fix: clarify pr preflight auth scopes

This commit is contained in:
Codex
2026-05-22 17:59:03 +00:00
parent 05b77151b8
commit b8b38bd44f
4 changed files with 172 additions and 12 deletions
+118 -10
View File
@@ -2897,25 +2897,74 @@ function activeRunnerDevContainerCapability(): Record<string, unknown> {
function prPreflightScopeBoundary(tokenCoverage: Record<string, unknown> | null): Record<string, unknown> {
const schedulerScope = typeof tokenCoverage?.scope === "string" ? tokenCoverage.scope : "scheduler-runner-env";
return {
headline: "scheduler-runner-env auth-missing is not active runner/dev container PR incapability",
schedulerPreflightScope: schedulerScope,
activeRunnerDevContainerScope: "current-cli-process",
scopesAreIndependent: true,
schedulerAuthMissingDoesNotMeanActiveRunnerCannotCreatePr: true,
authMissingInterpretation: "auth-missing from codex pr-preflight --remote is scoped to the scheduler/runtime preflight surface; do not simplify it to 'the active runner cannot create PRs'",
currentRunnerCheck: "use activeRunnerDevContainer plus bun scripts/cli.ts gh auth status --repo pikasTech/unidesk for the current dev container",
currentRunnerCheck: "use activeRunnerDevContainer plus bun scripts/cli.ts gh auth status --repo pikasTech/unidesk and gh pr create --dry-run for the current dev container",
valuesPrinted: false,
};
}
function prPreflightRecommendedActions(tokenCoverage: Record<string, unknown> | null): Record<string, unknown>[] {
const schedulerReady = tokenCoverage?.ok === true;
return [
{
scope: "active-runner-dev-container",
priority: "first",
action: "verify-current-runner-auth",
command: "bun scripts/cli.ts gh auth status --repo pikasTech/unidesk",
writesRemote: false,
},
{
scope: "active-runner-dev-container",
priority: "first",
action: "verify-current-runner-pr-create-plan",
command: "bun scripts/cli.ts gh pr create --repo pikasTech/unidesk --title <title> --body-file <file> --base master --head <head> --dry-run",
writesRemote: false,
},
{
scope: "scheduler-runtime",
priority: schedulerReady ? "long-term" : "required-for-scheduler-preflight",
action: "configure-scheduler-auth-source",
command: "configure auth-broker or inject GH_TOKEN/GITHUB_TOKEN via the scheduler runtime secret",
writesRemote: false,
},
];
}
function prPreflightAuthScopeSummary(tokenCoverage: Record<string, unknown> | null, activeRunnerDevContainer: Record<string, unknown>): Record<string, unknown> {
const schedulerReady = tokenCoverage?.ok === true;
return {
schedulerPreflightScope: typeof tokenCoverage?.scope === "string" ? tokenCoverage.scope : "scheduler-runner-env",
schedulerAuthReady: schedulerReady,
schedulerAuthSource: tokenCoverage?.source ?? null,
schedulerAuthMissingIsScoped: !schedulerReady,
activeRunnerDevContainerScope: activeRunnerDevContainer.scope ?? "current-cli-process",
activeRunnerTokenCandidatePresent: activeRunnerDevContainer.ok === true,
interpretation: schedulerReady
? "scheduler preflight has GitHub auth coverage; active runner PR creation still needs repo-native dry-run verification before real writes"
: "scheduler-runner-env auth-missing does not prove the active runner/dev container lacks PR create/comment capability",
valuesPrinted: false,
};
}
function decoratePrPreflightScopeBoundary(record: Record<string, unknown>): Record<string, unknown> {
const preflight = asRecord(record.preflight);
const tokenCoverage = asRecord(preflight?.tokenCoverage ?? record.tokenCoverage);
const tokenCoverage = asRecord(record.tokenCoverage) ?? asRecord(preflight?.tokenCoverage);
const scopeBoundary = prPreflightScopeBoundary(tokenCoverage);
const activeRunnerDevContainer = activeRunnerDevContainerCapability();
const authScopeSummary = prPreflightAuthScopeSummary(tokenCoverage, activeRunnerDevContainer);
const recommendedActions = prPreflightRecommendedActions(tokenCoverage);
return {
...record,
authScopeSummary,
scopeBoundary,
activeRunnerDevContainer,
...(preflight === null ? {} : { preflight: { ...preflight, scopeBoundary } }),
recommendedActions,
...(preflight === null ? {} : { preflight: { ...preflight, authScopeSummary, scopeBoundary, recommendedActions } }),
};
}
@@ -2943,6 +2992,53 @@ function prPreflightObservationGap(kind: Exclude<CodeQueueObservationGapKind, nu
};
}
function prPreflightObservationSummary(record: Record<string, unknown> | null): Record<string, unknown> | null {
if (record === null) return null;
const preflight = asRecord(record.preflight);
const tokenCoverage = asRecord(record.tokenCoverage) ?? asRecord(preflight?.tokenCoverage);
const controlPlane = asRecord(record.controlPlane);
const targetStack = asRecord(record.targetStack);
return {
ok: record.ok ?? null,
runnerDisposition: record.runnerDisposition ?? null,
failureKind: record.failureKind ?? null,
degradedReason: record.degradedReason ?? null,
controlPlane: controlPlane === null ? null : {
mode: controlPlane.mode ?? null,
localBackendCoreMissing: controlPlane.localBackendCoreMissing ?? null,
remoteFallbackUsed: controlPlane.remoteFallbackUsed ?? null,
},
targetStack: targetStack === null ? null : {
missingContainers: Array.isArray(targetStack.missingContainers) ? targetStack.missingContainers.map(String) : [],
verifyOnlyObserved: targetStack.verifyOnlyObserved ?? false,
},
tokenCoverage: tokenCoverage === null ? null : {
ok: tokenCoverage.ok ?? null,
source: tokenCoverage.source ?? null,
credentialSource: tokenCoverage.credentialSource ?? null,
scope: tokenCoverage.scope ?? null,
missing: Array.isArray(tokenCoverage.missing) ? tokenCoverage.missing.map(String) : [],
},
};
}
function maybeFullPrPreflightObservations(options: CodexPrPreflightOptions, localRecord: Record<string, unknown>, remoteRecord: Record<string, unknown>): Record<string, unknown> {
if (options.full) {
return {
localObservation: localRecord,
remoteObservation: remoteRecord,
};
}
return {
localObservationSummary: prPreflightObservationSummary(localRecord),
remoteObservationSummary: prPreflightObservationSummary(remoteRecord),
disclosure: {
fullObservationsOmitted: true,
expandWith: "bun scripts/cli.ts codex pr-preflight --remote --full",
},
};
}
function compactPrRuntimePreflight(preflight: Record<string, unknown>, options: CodexPrPreflightOptions): Record<string, unknown> {
const pull = asRecord(preflight.pullRequestDelivery) ?? {};
const tools = asRecord(pull.tools) ?? {};
@@ -2978,6 +3074,10 @@ function compactPrRuntimePreflight(preflight: Record<string, unknown>, options:
const pushDryRunRef = options.pushDryRunRef ?? defaultPushDryRunRef;
const targetBranch = "master";
const expectedHeadBranch = options.prCreateDryRunHead ?? (typeof git.branch === "string" && git.branch.length > 0 ? git.branch : "<head-branch>");
const scopeBoundary = prPreflightScopeBoundary(tokenCoverage);
const activeRunnerDevContainer = activeRunnerDevContainerCapability();
const authScopeSummary = prPreflightAuthScopeSummary(tokenCoverage, activeRunnerDevContainer);
const recommendedActions = prPreflightRecommendedActions(tokenCoverage);
const result: Record<string, unknown> = {
ok,
failureKind,
@@ -2992,7 +3092,9 @@ function compactPrRuntimePreflight(preflight: Record<string, unknown>, options:
},
tokenCoverage,
authBroker: authBrokerNeededStatus(tokenCoverage, authBrokerRuntime, systemGhBinary, unideskGhCli),
scopeBoundary: prPreflightScopeBoundary(tokenCoverage),
authScopeSummary,
scopeBoundary,
recommendedActions,
prCapabilityContract: {
targetBranch,
tokenSource: tokenCoverage.source,
@@ -3089,12 +3191,12 @@ function compactPrRuntimePreflight(preflight: Record<string, unknown>, options:
limitations,
risks,
runnerDisposition: ok ? "ready" : "infra-blocked",
activeRunnerDevContainer: activeRunnerDevContainerCapability(),
activeRunnerDevContainer,
recoveryHint: ok
? 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."
: "Scheduler preflight lacks GitHub auth coverage. Configure auth-broker or inject GH_TOKEN/GITHUB_TOKEN into the scheduler runtime secret for scheduler-scoped admission; separately check activeRunnerDevContainer and gh auth status before declaring the current runner unable to create/comment PRs.",
: "Scheduler preflight lacks GitHub auth coverage for scheduler-scoped admission only. First verify the active task with repo-native gh auth status and PR create dry-run; long-term configure auth-broker or inject GH_TOKEN/GITHUB_TOKEN into the scheduler runtime secret.",
commands: {
local: "bun scripts/cli.ts gh auth status --repo pikasTech/unidesk",
runner: "bun scripts/cli.ts codex pr-preflight --remote",
@@ -3230,8 +3332,7 @@ function codeQueuePrPreflight(optionArgs: string[] = [], transport: CodeQueuePrP
localBackendCoreMissing: true,
remoteFallbackUsed: true,
},
localObservation: localRecord,
remoteObservation: remoteRecord,
...maybeFullPrPreflightObservations(options, localRecord, remoteRecord),
});
}
return decoratePrPreflightScopeBoundary({
@@ -3250,8 +3351,7 @@ function codeQueuePrPreflight(optionArgs: string[] = [], transport: CodeQueuePrP
localBackendCoreMissing: true,
remoteFallbackUsed: true,
},
localObservation: localRecord,
remoteObservation: remoteRecord,
...maybeFullPrPreflightObservations(options, localRecord, remoteRecord),
});
}
}
@@ -3347,6 +3447,10 @@ function codeQueuePrPreflight(optionArgs: string[] = [], transport: CodeQueuePrP
runnerDisposition: compact.runnerDisposition,
failureKind: compact.failureKind ?? null,
degradedReason: compact.degradedReason ?? null,
authScopeSummary: compact.authScopeSummary,
scopeBoundary: compact.scopeBoundary,
activeRunnerDevContainer: compact.activeRunnerDevContainer,
recommendedActions: compact.recommendedActions,
upstream: { ok: response.ok, status: response.status },
controlPlane: {
mode: "local-backend-core",
@@ -3399,6 +3503,10 @@ export async function codexPrPreflightQueryAsync(optionArgs: string[], fetcher:
runnerDisposition: compact.runnerDisposition,
failureKind: compact.failureKind ?? null,
degradedReason: compact.degradedReason ?? null,
authScopeSummary: compact.authScopeSummary,
scopeBoundary: compact.scopeBoundary,
activeRunnerDevContainer: compact.activeRunnerDevContainer,
recommendedActions: compact.recommendedActions,
upstream: { ok: response.ok, status: response.status },
controlPlane: {
mode: "remote-frontend",