codex: expose auth broker pr preflight contract

This commit is contained in:
Codex
2026-05-21 14:04:33 +00:00
parent 7d80e2c259
commit dff355c5a4
6 changed files with 474 additions and 34 deletions
@@ -189,6 +189,101 @@ function remoteControlPlaneResult(overrides: Partial<JsonRecord> = {}): JsonReco
};
}
function rawRuntimePreflightFixture(overrides: Partial<JsonRecord> = {}): JsonRecord {
return {
ok: true,
checkedAt: "2026-05-20T00:00:00.000Z",
cwd: "/workspace/unidesk",
pid: 123,
pullRequestDelivery: {
ok: true,
checkedAt: "2026-05-20T00:00:00.000Z",
tools: {
git: { ok: true, path: "/usr/bin/git", version: "git version 2.43.0" },
gh: { ok: false, path: null, version: null },
hub: { ok: false, path: null, version: null },
jq: { ok: true, path: "/usr/bin/jq", version: "jq-1.7" },
ssh: { ok: true, path: "/usr/bin/ssh", version: "OpenSSH_9.6" },
curl: { ok: true, path: "/usr/bin/curl", version: "curl 8.5.0" },
},
unideskGhCli: { ok: true, path: "/workspace/unidesk/scripts/cli.ts", present: true },
credentials: {
ghTokenPresent: false,
githubTokenPresent: false,
ghHostsConfigPresent: false,
gitCredentialsPresent: false,
},
authBroker: {
ok: false,
configured: false,
source: "broker/auth-broker-needed",
endpointEnvKey: null,
runnerEnvTokenRequired: false,
credentialSource: null,
failureKind: "auth-missing",
degradedReason: "auth-broker-needed",
capability: {
source: "missing-token",
githubRestAuth: false,
operations: ["github.auth.status", "github.issue.read", "github.pr.read", "github.pr.create"],
systemGhBinaryRequiredForWrites: false,
preflightWritesRemote: false,
preflightCreatesPr: false,
preflightMergesPr: false,
realPrCreateRequiresCommanderAuthorization: true,
valuesPrinted: false,
},
nextAction: "configure-auth-broker-or-env-token",
next: ["configure UNIDESK_AUTH_BROKER_URL or AUTH_BROKER_URL for broker-backed runner auth"],
valuesRead: false,
valuesPrinted: false,
},
git: {
insideWorktree: true,
branch: "code-queue/issue-35-pr-dry-run-probe",
head: "abc1234",
originMaster: "def5678",
remoteOrigin: "git@github.com:pikasTech/unidesk.git",
home: "/root",
homeWritable: true,
knownHostsPresent: true,
privateKeyPresent: true,
},
githubContext: {
host: "github.com",
apiBaseUrl: "https://api.github.com",
repo: "pikasTech/unidesk",
issueProbeNumber: 20,
},
egress: {
proxy: {
selectedProxyHost: "d601-provider-egress-proxy.unidesk.svc.cluster.local",
selectedProxyPort: "18789",
selectedProxyHostResolvable: true,
},
githubDefault: { command: "curl", args: ["-IsS", "https://github.com"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
apiDefault: { command: "curl", args: ["-IsS", "https://api.github.com"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
issueApi: null,
},
remote: {
gitLsRemote: { command: "git", args: ["ls-remote", "--heads", "origin", "master"], ok: true, exitCode: 0, signal: null, error: null, stdout: "abc1234\trefs/heads/master\n", stderr: "" },
gitHttpsLsRemote: null,
githubSshAuthenticated: true,
ghAuthStatus: null,
ghRepoView: null,
ghIssueView: null,
ghPrReadOnly: null,
},
limitations: [],
risks: [
"system gh binary is missing; UniDesk REST gh CLI remains the supported PR create/comment path when scripts/cli.ts and GH_TOKEN/GITHUB_TOKEN or auth-broker are available",
],
},
ports: {},
...overrides,
};
}
async function main(): Promise<void> {
let observedLocalPath = "";
const remoteFallback = await codexPrPreflightQueryForTest(["--remote", "--issue", "35"], {
@@ -493,6 +588,137 @@ async function main(): Promise<void> {
assertCondition(asRecord(dryRunPrContract.prCreateDryRun).writesRemote === false, "PR create dry-run must be marked non-writing", dryRunPrContract);
assertCondition(asRecord(dryRunPrContract.prCreateDryRun).headBranch === "code-queue/issue-35-pr-dry-run-probe", "PR dry-run head should come from the option", dryRunPrContract);
const brokerIssuedContract = await codexPrPreflightQueryForTest(["--remote"], {
config: null,
coreFetch: () => ({
ok: true,
status: 200,
body: {
runtimePreflight: rawRuntimePreflightFixture({
pullRequestDelivery: {
...asRecord(rawRuntimePreflightFixture().pullRequestDelivery),
ok: true,
authBroker: {
ok: true,
configured: true,
source: "auth-broker",
endpointEnvKey: "UNIDESK_AUTH_BROKER_URL",
runnerEnvTokenRequired: false,
credentialSource: "broker-held-github-credential",
failureKind: null,
degradedReason: null,
capability: {
source: "broker-issued-token",
githubRestAuth: true,
operations: ["github.auth.status", "github.issue.read", "github.pr.read", "github.pr.create"],
systemGhBinaryRequiredForWrites: false,
preflightWritesRemote: false,
preflightCreatesPr: false,
preflightMergesPr: false,
realPrCreateRequiresCommanderAuthorization: true,
valuesPrinted: false,
},
nextAction: "use-auth-broker",
next: ["keep PR preflight read-only; create a real PR only after commander authorization"],
valuesRead: false,
valuesPrinted: false,
},
},
}),
},
}),
});
const brokerIssuedRecord = asRecord(brokerIssuedContract);
assertCondition(brokerIssuedRecord.ok === true, "broker-issued token branch should be ready", brokerIssuedRecord);
const brokerIssuedPreflight = asRecord(brokerIssuedRecord.preflight);
const brokerIssuedTokenCoverage = asRecord(brokerIssuedPreflight.tokenCoverage);
const brokerIssuedAuthBroker = asRecord(brokerIssuedPreflight.authBroker);
const brokerIssuedCapability = asRecord(brokerIssuedAuthBroker.capability);
const brokerIssuedPrContract = asRecord(brokerIssuedPreflight.prCapabilityContract);
assertCondition(brokerIssuedTokenCoverage.source === "auth-broker", "broker-issued branch should use auth-broker token coverage", brokerIssuedTokenCoverage);
assertCondition(brokerIssuedTokenCoverage.credentialSource === "broker-issued-token", "broker-issued branch should expose broker-issued-token capability", brokerIssuedTokenCoverage);
assertCondition(brokerIssuedAuthBroker.source === "auth-broker", "broker-issued branch should expose authBroker.source", brokerIssuedAuthBroker);
assertCondition(brokerIssuedAuthBroker.nextAction === "use-auth-broker", "broker-issued branch should expose nextAction", brokerIssuedAuthBroker);
assertCondition(brokerIssuedCapability.systemGhBinaryRequiredForWrites === false, "broker-issued branch should not require system gh binary", brokerIssuedCapability);
assertCondition(brokerIssuedCapability.realPrCreateRequiresCommanderAuthorization === true, "real PR creation should still require commander authorization", brokerIssuedCapability);
assertCondition(asRecord(brokerIssuedPrContract.authBroker).source === "auth-broker", "PR capability should include broker source", brokerIssuedPrContract);
const envTokenContract = await codexPrPreflightQueryForTest(["--remote"], {
config: null,
coreFetch: () => ({
ok: true,
status: 200,
body: {
runtimePreflight: rawRuntimePreflightFixture({
pullRequestDelivery: {
...asRecord(rawRuntimePreflightFixture().pullRequestDelivery),
ok: true,
credentials: {
ghTokenPresent: true,
githubTokenPresent: false,
ghHostsConfigPresent: false,
gitCredentialsPresent: false,
},
authBroker: {
ok: false,
configured: false,
source: "broker/auth-broker-needed",
endpointEnvKey: null,
runnerEnvTokenRequired: false,
credentialSource: null,
failureKind: "auth-missing",
degradedReason: "auth-broker-needed",
capability: {
source: "missing-token",
githubRestAuth: false,
operations: ["github.auth.status", "github.issue.read", "github.pr.read", "github.pr.create"],
systemGhBinaryRequiredForWrites: false,
preflightWritesRemote: false,
preflightCreatesPr: false,
preflightMergesPr: false,
realPrCreateRequiresCommanderAuthorization: true,
valuesPrinted: false,
},
nextAction: "configure-auth-broker-or-env-token",
next: ["configure UNIDESK_AUTH_BROKER_URL or AUTH_BROKER_URL for broker-backed runner auth"],
valuesRead: false,
valuesPrinted: false,
},
},
}),
},
}),
});
const envTokenRecord = asRecord(envTokenContract);
assertCondition(envTokenRecord.ok === true, "env token branch should be ready", envTokenRecord);
const envTokenPreflight = asRecord(envTokenRecord.preflight);
const envTokenCoverage = asRecord(envTokenPreflight.tokenCoverage);
const envTokenAuthBroker = asRecord(envTokenPreflight.authBroker);
assertCondition(envTokenCoverage.source === "GH_TOKEN", "env token branch should expose GH_TOKEN source", envTokenCoverage);
assertCondition(envTokenCoverage.credentialSource === "env-token", "env token branch should expose env-token capability", envTokenCoverage);
assertCondition(envTokenAuthBroker.source === "GH_TOKEN", "env token branch should not pretend broker is configured", envTokenAuthBroker);
assertCondition(envTokenAuthBroker.nextAction === "use-env-token-until-auth-broker-live", "env token branch should still point at broker migration", envTokenAuthBroker);
const missingTokenContract = await codexPrPreflightQueryForTest(["--remote"], {
config: null,
coreFetch: () => ({
ok: true,
status: 200,
body: { runtimePreflight: rawRuntimePreflightFixture() },
}),
});
const missingTokenRecord = asRecord(missingTokenContract);
assertCondition(missingTokenRecord.ok === false, "missing-token branch should fail", missingTokenRecord);
assertCondition(missingTokenRecord.failureKind === "auth-missing", "missing-token branch should classify auth-missing", missingTokenRecord);
assertCondition(missingTokenRecord.degradedReason === "auth-broker-needed", "missing-token branch should expose broker-needed degraded reason", missingTokenRecord);
const missingTokenPreflight = asRecord(missingTokenRecord.preflight);
const missingTokenAuthBroker = asRecord(missingTokenPreflight.authBroker);
const missingTokenCapability = asRecord(missingTokenAuthBroker.capability);
assertCondition(missingTokenAuthBroker.source === "broker/auth-broker-needed", "missing-token branch should expose broker/auth-broker-needed", missingTokenAuthBroker);
assertCondition(missingTokenAuthBroker.nextAction === "configure-auth-broker-or-env-token", "missing-token branch should expose nextAction", missingTokenAuthBroker);
assertCondition(missingTokenCapability.source === "missing-token", "missing-token branch should expose missing-token capability", missingTokenCapability);
assertCondition(missingTokenCapability.systemGhBinaryRequiredForWrites === false, "missing-token branch should still not require system gh binary for UniDesk gh CLI", missingTokenCapability);
process.stdout.write(`${JSON.stringify({
ok: true,
checks: [
@@ -503,6 +729,7 @@ async function main(): Promise<void> {
"proxy failures return proxy-gap",
"git remote failures return git-remote-gap",
"combined push/PR create dry-run contract stays read-only and separates system gh from UniDesk gh CLI",
"broker-issued token, env-token, and missing-token branches expose authBroker source/capability/nextAction",
],
observedLocalPath,
observedDryRunPath,