codex: expose auth broker pr preflight contract
This commit is contained in:
@@ -203,6 +203,10 @@ async function main(): Promise<void> {
|
||||
assertCondition(noTokenData.failureKind === "auth-missing", "missing token should classify as auth-missing", noTokenData);
|
||||
assertCondition(noTokenData.degradedReason === "broker-needed", "missing token should classify as broker-needed", noTokenData);
|
||||
assertCondition(noTokenData.brokerNeeded === true, "missing token should set brokerNeeded", noTokenData);
|
||||
const noTokenAuthBroker = noTokenData.authBroker as Record<string, unknown>;
|
||||
assertCondition(noTokenAuthBroker.source === "broker/auth-broker-needed", "missing broker endpoint should expose broker-needed auth source", noTokenAuthBroker);
|
||||
assertCondition(noTokenAuthBroker.capability === "missing-token", "missing broker endpoint should expose missing-token capability", noTokenAuthBroker);
|
||||
assertCondition(noTokenAuthBroker.nextAction === "configure-auth-broker", "missing broker endpoint should expose next action", noTokenAuthBroker);
|
||||
assertCondition(!noToken.stdout.includes("contract-secret-marker"), "missing-token response must not leak secret marker strings", noToken.stdout);
|
||||
|
||||
const brokerReady = await runCli([
|
||||
@@ -225,13 +229,19 @@ async function main(): Promise<void> {
|
||||
const readyData = dataOf(brokerReady.json ?? {});
|
||||
const tokenCoverage = readyData.tokenCoverage as Record<string, unknown>;
|
||||
const brokerCoverage = readyData.brokerCoverage as Record<string, unknown>;
|
||||
const readyAuthBroker = readyData.authBroker as Record<string, unknown>;
|
||||
const prCapability = readyData.prCapabilityContract as Record<string, unknown>;
|
||||
const brokerProxy = prCapability.brokerProxy as Record<string, unknown>;
|
||||
assertCondition(readyAuthBroker.source === "auth-broker", "ready auth broker source should be auth-broker", readyAuthBroker);
|
||||
assertCondition(readyAuthBroker.capability === "broker-issued-token", "ready auth broker capability should be broker-issued-token", readyAuthBroker);
|
||||
assertCondition(readyAuthBroker.nextAction === "use-auth-broker", "ready auth broker next action should use broker", readyAuthBroker);
|
||||
assertCondition(tokenCoverage.source === "auth-broker", "ready token coverage should come from broker", tokenCoverage);
|
||||
assertCondition(tokenCoverage.runnerEnvTokenRequired === false, "ready token coverage should not require runner env token", tokenCoverage);
|
||||
assertCondition(tokenCoverage.valuesPrinted === false, "ready token coverage must not print values", tokenCoverage);
|
||||
assertCondition(String(brokerCoverage.endpoint).includes("http://***:***@127.0.0.1:4291/?..."), "endpoint should be sanitized", brokerCoverage);
|
||||
assertCondition(prCapability.targetBranch === "master", "P0 capability should preserve target branch", prCapability);
|
||||
assertCondition(prCapability.authSource === "broker-issued-token", "P0 capability should expose broker-issued-token auth source", prCapability);
|
||||
assertCondition(prCapability.realPrCreateRequiresCommanderAuthorization === true, "real PR create should require commander authorization", prCapability);
|
||||
assertCondition(prCapability.preflightCreatesPr === false && prCapability.preflightMergesPr === false, "P0 PR preflight must not write or merge", prCapability);
|
||||
assertCondition(brokerProxy.writesRemote === false, "P0 broker proxy should not write remote", brokerProxy);
|
||||
assertCondition(Array.isArray(brokerProxy.operations) && brokerProxy.operations.includes("github.pr.create"), "P0 broker proxy should include PR create dry-run operation", brokerProxy);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -124,6 +124,17 @@ function brokerNeededResult(options: BrokerAdapterOptions): Record<string, unkno
|
||||
message: "No auth broker endpoint is configured for this dry-run contract; runner env token coverage is reported only for migration diagnostics.",
|
||||
tokenCoverage: runnerEnvTokenCoverage(),
|
||||
brokerCoverage: brokerCoverage(options.endpoint),
|
||||
authBroker: {
|
||||
ok: false,
|
||||
source: "broker/auth-broker-needed",
|
||||
capability: "missing-token",
|
||||
nextAction: "configure-auth-broker",
|
||||
runnerEnvTokenRequired: false,
|
||||
brokerIssuedTokenAvailable: false,
|
||||
valuesRead: false,
|
||||
valuesPrinted: false,
|
||||
realPrCreateRequiresCommanderAuthorization: true,
|
||||
},
|
||||
next: [
|
||||
"configure UNIDESK_AUTH_BROKER_URL or AUTH_BROKER_URL for broker-backed runner auth",
|
||||
"keep GH_TOKEN/GITHUB_TOKEN out of ordinary runner env once broker mode is enabled",
|
||||
@@ -185,6 +196,17 @@ function readyContract(options: BrokerAdapterOptions): Record<string, unknown> {
|
||||
dryRun: true,
|
||||
mutation: false,
|
||||
capabilities: [...DEFAULT_CAPABILITIES],
|
||||
authBroker: {
|
||||
ok: true,
|
||||
source: "auth-broker",
|
||||
capability: "broker-issued-token",
|
||||
nextAction: "use-auth-broker",
|
||||
runnerEnvTokenRequired: false,
|
||||
brokerIssuedTokenAvailable: true,
|
||||
valuesRead: false,
|
||||
valuesPrinted: false,
|
||||
realPrCreateRequiresCommanderAuthorization: true,
|
||||
},
|
||||
tokenCoverage: {
|
||||
ok: true,
|
||||
source: "auth-broker",
|
||||
@@ -199,9 +221,11 @@ function readyContract(options: BrokerAdapterOptions): Record<string, unknown> {
|
||||
prCapabilityContract: {
|
||||
targetBranch: options.base,
|
||||
headBranch: options.head,
|
||||
authSource: "broker-issued-token",
|
||||
systemGhBinaryRequiredForWrites: false,
|
||||
preflightCreatesPr: false,
|
||||
preflightMergesPr: false,
|
||||
realPrCreateRequiresCommanderAuthorization: true,
|
||||
brokerProxy: {
|
||||
ok: true,
|
||||
operations: ["github.auth.status", "github.issue.read", "github.pr.read", "github.pr.create"],
|
||||
|
||||
+113
-23
@@ -2418,6 +2418,51 @@ function compactUniDeskGhCliStatus(value: unknown): Record<string, unknown> {
|
||||
};
|
||||
}
|
||||
|
||||
function compactAuthBrokerRuntimeStatus(value: unknown): Record<string, unknown> {
|
||||
const broker = asRecord(value);
|
||||
const observed = broker !== null;
|
||||
const capability = asRecord(broker?.capability);
|
||||
const configured = broker?.configured === true || broker?.ok === true && broker?.source === "auth-broker";
|
||||
const operations = Array.isArray(capability?.operations)
|
||||
? capability.operations.map(String)
|
||||
: ["github.auth.status", "github.issue.read", "github.pr.read", "github.pr.create"];
|
||||
return {
|
||||
ok: configured,
|
||||
observed,
|
||||
configured,
|
||||
source: typeof broker?.source === "string" ? broker.source : configured ? "auth-broker" : "broker/auth-broker-needed",
|
||||
endpointEnvKey: typeof broker?.endpointEnvKey === "string" ? broker.endpointEnvKey : null,
|
||||
runnerEnvTokenRequired: broker?.runnerEnvTokenRequired === true,
|
||||
credentialSource: typeof broker?.credentialSource === "string" ? broker.credentialSource : configured ? "broker-held-github-credential" : null,
|
||||
failureKind: configured ? null : broker?.failureKind ?? "auth-missing",
|
||||
degradedReason: configured ? null : broker?.degradedReason ?? "auth-broker-needed",
|
||||
capability: {
|
||||
source: typeof capability?.source === "string" ? capability.source : configured ? "broker-issued-token" : "missing-token",
|
||||
githubRestAuth: capability?.githubRestAuth === true || configured,
|
||||
operations,
|
||||
systemGhBinaryRequiredForWrites: false,
|
||||
preflightWritesRemote: false,
|
||||
preflightCreatesPr: false,
|
||||
preflightMergesPr: false,
|
||||
realPrCreateRequiresCommanderAuthorization: true,
|
||||
valuesPrinted: false,
|
||||
},
|
||||
nextAction: typeof broker?.nextAction === "string"
|
||||
? broker.nextAction
|
||||
: configured
|
||||
? "use-auth-broker"
|
||||
: "configure-auth-broker-or-env-token",
|
||||
next: Array.isArray(broker?.next) ? broker.next.map(String) : configured
|
||||
? ["keep PR preflight read-only; create a real PR only after commander authorization"]
|
||||
: [
|
||||
"configure UNIDESK_AUTH_BROKER_URL or AUTH_BROKER_URL for broker-backed runner auth",
|
||||
"or inject GH_TOKEN/GITHUB_TOKEN into the Code Queue scheduler runtime secret until broker mode is live",
|
||||
],
|
||||
valuesRead: false,
|
||||
valuesPrinted: false,
|
||||
};
|
||||
}
|
||||
|
||||
function compactAgentPortStatus(value: unknown): Record<string, unknown> {
|
||||
const port = asRecord(value) ?? {};
|
||||
return {
|
||||
@@ -2428,43 +2473,80 @@ function compactAgentPortStatus(value: unknown): Record<string, unknown> {
|
||||
};
|
||||
}
|
||||
|
||||
function tokenCoverageStatus(credentials: Record<string, unknown>): Record<string, unknown> {
|
||||
function tokenCoverageStatus(credentials: Record<string, unknown>, authBroker: Record<string, unknown>): Record<string, unknown> {
|
||||
const ghTokenPresent = credentials.ghTokenPresent === true;
|
||||
const githubTokenPresent = credentials.githubTokenPresent === true;
|
||||
const anyEnvToken = ghTokenPresent || githubTokenPresent;
|
||||
const anyGhCredentialStore = credentials.ghHostsConfigPresent === true || credentials.gitCredentialsPresent === true;
|
||||
const authBrokerOk = authBroker.ok === true;
|
||||
const effective = authBrokerOk || anyEnvToken;
|
||||
const envSource = ghTokenPresent ? "GH_TOKEN" : githubTokenPresent ? "GITHUB_TOKEN" : null;
|
||||
return {
|
||||
ok: anyEnvToken,
|
||||
source: ghTokenPresent ? "GH_TOKEN" : githubTokenPresent ? "GITHUB_TOKEN" : null,
|
||||
ok: effective,
|
||||
source: authBrokerOk ? "auth-broker" : envSource,
|
||||
credentialSource: authBrokerOk ? "broker-issued-token" : anyEnvToken ? "env-token" : null,
|
||||
ghTokenPresent,
|
||||
githubTokenPresent,
|
||||
ghCredentialStorePresent: anyGhCredentialStore,
|
||||
runnerDisposition: anyEnvToken ? "ready" : "infra-blocked",
|
||||
missing: anyEnvToken ? [] : ["GH_TOKEN", "GITHUB_TOKEN"],
|
||||
scope: "scheduler-runner-env",
|
||||
note: anyEnvToken
|
||||
authBrokerPresent: authBrokerOk,
|
||||
authBrokerSource: authBroker.source ?? null,
|
||||
runnerEnvTokenRequired: !authBrokerOk,
|
||||
runnerDisposition: effective ? "ready" : "infra-blocked",
|
||||
missing: effective ? [] : ["GH_TOKEN", "GITHUB_TOKEN"],
|
||||
envMissing: anyEnvToken ? [] : ["GH_TOKEN", "GITHUB_TOKEN"],
|
||||
scope: authBrokerOk ? "broker-held-github-credential" : "scheduler-runner-env",
|
||||
note: authBrokerOk
|
||||
? "scheduler can use auth-broker for GitHub REST PR preflight without exposing GH_TOKEN/GITHUB_TOKEN to runner env"
|
||||
: anyEnvToken
|
||||
? "scheduler has a GitHub env token that can be forwarded to provider dev containers through CODE_QUEUE_REMOTE_CODEX_ENV_KEYS"
|
||||
: "scheduler is missing GH_TOKEN/GITHUB_TOKEN; provider dev containers cannot receive a GitHub token even though CODE_QUEUE_REMOTE_CODEX_ENV_KEYS includes those keys",
|
||||
: "scheduler is missing GH_TOKEN/GITHUB_TOKEN and auth-broker is not configured; provider dev containers cannot receive a GitHub token even though CODE_QUEUE_REMOTE_CODEX_ENV_KEYS includes those keys",
|
||||
};
|
||||
}
|
||||
|
||||
function authBrokerNeededStatus(tokenCoverage: Record<string, unknown>, systemGhBinary: Record<string, unknown>, unideskGhCli: Record<string, unknown>): Record<string, unknown> {
|
||||
function authBrokerNeededStatus(tokenCoverage: Record<string, unknown>, runtimeAuthBroker: Record<string, unknown>, systemGhBinary: Record<string, unknown>, unideskGhCli: Record<string, unknown>): Record<string, unknown> {
|
||||
const missing = Array.isArray(tokenCoverage.missing) ? tokenCoverage.missing.map(String) : [];
|
||||
const needed = tokenCoverage.ok !== true;
|
||||
const ready = tokenCoverage.ok === true;
|
||||
const authBrokerReady = tokenCoverage.source === "auth-broker";
|
||||
const needed = !ready;
|
||||
const capability = asRecord(runtimeAuthBroker.capability) ?? {};
|
||||
const capabilitySource = tokenCoverage.credentialSource ?? "missing-token";
|
||||
const nextAction = authBrokerReady
|
||||
? "use-auth-broker"
|
||||
: ready
|
||||
? "use-env-token-until-auth-broker-live"
|
||||
: "configure-auth-broker-or-env-token";
|
||||
return {
|
||||
ok: !needed,
|
||||
source: needed ? "broker/auth-broker-needed" : tokenCoverage.source ?? "runner-env-token",
|
||||
ok: ready,
|
||||
source: authBrokerReady ? "auth-broker" : needed ? "broker/auth-broker-needed" : tokenCoverage.source ?? "runner-env-token",
|
||||
needed,
|
||||
configured: false,
|
||||
configured: runtimeAuthBroker.configured === true,
|
||||
runnerDisposition: needed ? "infra-blocked" : "ready",
|
||||
failureKind: needed ? "auth-missing" : null,
|
||||
degradedReason: needed ? "auth-broker-needed" : null,
|
||||
runnerEnvTokenRequiredWithoutBroker: true,
|
||||
brokerCredentialSource: null,
|
||||
runnerEnvTokenRequiredWithoutBroker: !authBrokerReady,
|
||||
brokerCredentialSource: authBrokerReady ? runtimeAuthBroker.credentialSource ?? "broker-held-github-credential" : null,
|
||||
capability: {
|
||||
source: capabilitySource,
|
||||
githubRestAuth: ready,
|
||||
operations: Array.isArray(capability.operations)
|
||||
? capability.operations.map(String)
|
||||
: ["github.auth.status", "github.issue.read", "github.pr.read", "github.pr.create"],
|
||||
systemGhBinaryRequiredForWrites: false,
|
||||
unideskGhCliRequired: true,
|
||||
preflightWritesRemote: false,
|
||||
preflightCreatesPr: false,
|
||||
preflightMergesPr: false,
|
||||
realPrCreateRequiresCommanderAuthorization: true,
|
||||
valuesPrinted: false,
|
||||
},
|
||||
nextAction,
|
||||
valuesPrinted: false,
|
||||
evidence: {
|
||||
envTokenMissing: needed,
|
||||
missing,
|
||||
authBrokerObserved: runtimeAuthBroker.observed ?? false,
|
||||
authBrokerConfigured: runtimeAuthBroker.configured ?? false,
|
||||
authBrokerSource: runtimeAuthBroker.source ?? null,
|
||||
systemGhBinaryOk: systemGhBinary.ok === true,
|
||||
systemGhBinaryRequiredForWrites: false,
|
||||
unideskGhCliObserved: unideskGhCli.observed ?? false,
|
||||
@@ -2474,10 +2556,12 @@ function authBrokerNeededStatus(tokenCoverage: Record<string, unknown>, systemGh
|
||||
},
|
||||
next: needed
|
||||
? [
|
||||
"inject GH_TOKEN or GITHUB_TOKEN into the Code Queue scheduler runtime secret",
|
||||
"or configure the planned auth-broker so PR preflight can use a broker-held GitHub credential without exposing runner env tokens",
|
||||
"configure UNIDESK_AUTH_BROKER_URL or AUTH_BROKER_URL so PR preflight can use a broker-held GitHub credential without exposing runner env tokens",
|
||||
"or inject GH_TOKEN/GITHUB_TOKEN into the Code Queue scheduler runtime secret until broker mode is live",
|
||||
]
|
||||
: [],
|
||||
: authBrokerReady
|
||||
? ["keep PR preflight read-only; create a real PR only after commander authorization"]
|
||||
: ["env token path is ready; Auth Broker is still needed before removing runner env GitHub credentials"],
|
||||
reference: "docs/reference/auth-broker.md#post-v1githubpr-preflight",
|
||||
};
|
||||
}
|
||||
@@ -2486,6 +2570,7 @@ function compactPrRuntimePreflight(preflight: Record<string, unknown>, options:
|
||||
const pull = asRecord(preflight.pullRequestDelivery) ?? {};
|
||||
const tools = asRecord(pull.tools) ?? {};
|
||||
const unideskGhCli = compactUniDeskGhCliStatus(pull.unideskGhCli);
|
||||
const authBrokerRuntime = compactAuthBrokerRuntimeStatus(pull.authBroker);
|
||||
const systemGhBinary = compactToolStatus(tools.gh);
|
||||
const credentials = asRecord(pull.credentials) ?? {};
|
||||
const git = asRecord(pull.git) ?? {};
|
||||
@@ -2494,7 +2579,7 @@ function compactPrRuntimePreflight(preflight: Record<string, unknown>, options:
|
||||
const proxy = asRecord(egress.proxy) ?? {};
|
||||
const remote = asRecord(pull.remote);
|
||||
const ports = asRecord(preflight.ports) ?? {};
|
||||
const tokenCoverage = tokenCoverageStatus(credentials);
|
||||
const tokenCoverage = tokenCoverageStatus(credentials, authBrokerRuntime);
|
||||
const limitations = Array.isArray(pull.limitations) ? pull.limitations.map(String) : [];
|
||||
const risks = Array.isArray(pull.risks) ? pull.risks.map(String) : [];
|
||||
const ok = preflight.ok === true && tokenCoverage.ok === true;
|
||||
@@ -2506,7 +2591,7 @@ function compactPrRuntimePreflight(preflight: Record<string, unknown>, options:
|
||||
? "proxy-gap"
|
||||
: null;
|
||||
const degradedReason = failureKind === "auth-missing"
|
||||
? "GH_TOKEN/GITHUB_TOKEN missing"
|
||||
? "auth-broker-needed"
|
||||
: failureKind === "git-remote-gap"
|
||||
? "git remote probe failed"
|
||||
: failureKind === "proxy-gap"
|
||||
@@ -2529,12 +2614,15 @@ function compactPrRuntimePreflight(preflight: Record<string, unknown>, options:
|
||||
pid: preflight.pid ?? null,
|
||||
},
|
||||
tokenCoverage,
|
||||
authBroker: authBrokerNeededStatus(tokenCoverage, systemGhBinary, unideskGhCli),
|
||||
authBroker: authBrokerNeededStatus(tokenCoverage, authBrokerRuntime, systemGhBinary, unideskGhCli),
|
||||
prCapabilityContract: {
|
||||
targetBranch,
|
||||
tokenSource: tokenCoverage.source,
|
||||
authSource: tokenCoverage.credentialSource,
|
||||
realPrCreateRequiresCommanderAuthorization: true,
|
||||
systemGhBinaryRequiredForWrites: false,
|
||||
unideskGhCli,
|
||||
authBroker: authBrokerRuntime,
|
||||
pushDryRun: {
|
||||
requested: options.pushDryRun,
|
||||
ref: pushDryRunRef,
|
||||
@@ -2624,8 +2712,10 @@ function compactPrRuntimePreflight(preflight: Record<string, unknown>, options:
|
||||
risks,
|
||||
runnerDisposition: ok ? "ready" : "infra-blocked",
|
||||
recoveryHint: ok
|
||||
? "Runner PR workflow has env-token coverage for the scheduler."
|
||||
: "Inject GH_TOKEN or GITHUB_TOKEN into the Code Queue scheduler runtime secret for the target queue, then rerun this preflight before creating a PR.",
|
||||
? tokenCoverage.source === "auth-broker"
|
||||
? "Runner PR workflow has auth-broker coverage for GitHub REST preflight; real PR creation still requires commander authorization."
|
||||
: "Runner PR workflow has env-token coverage for the scheduler."
|
||||
: "Configure auth-broker or inject GH_TOKEN/GITHUB_TOKEN into the Code Queue scheduler runtime secret for the target queue, then rerun this preflight before creating a PR.",
|
||||
commands: {
|
||||
local: "bun scripts/cli.ts gh auth status --repo pikasTech/unidesk",
|
||||
runner: "bun scripts/cli.ts codex pr-preflight --remote",
|
||||
|
||||
Reference in New Issue
Block a user