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
@@ -66,6 +66,7 @@ export interface PullRequestDeliveryPreflight {
checkedAt: string;
tools: Record<string, RuntimeToolStatus>;
unideskGhCli: UniDeskGhCliStatus;
authBroker: RuntimeAuthBrokerStatus;
credentials: {
ghTokenPresent: boolean;
githubTokenPresent: boolean;
@@ -129,6 +130,32 @@ export interface PullRequestDeliveryPreflight {
risks: string[];
}
export interface RuntimeAuthBrokerStatus {
ok: boolean;
configured: boolean;
source: "auth-broker" | "broker/auth-broker-needed";
endpointEnvKey: string | null;
runnerEnvTokenRequired: boolean;
credentialSource: string | null;
failureKind: "auth-missing" | null;
degradedReason: "auth-broker-needed" | null;
capability: {
source: "broker-issued-token" | "missing-token";
githubRestAuth: boolean;
operations: string[];
systemGhBinaryRequiredForWrites: false;
preflightWritesRemote: false;
preflightCreatesPr: false;
preflightMergesPr: false;
realPrCreateRequiresCommanderAuthorization: true;
valuesPrinted: false;
};
nextAction: "use-auth-broker" | "configure-auth-broker-or-env-token";
next: string[];
valuesRead: false;
valuesPrinted: false;
}
export interface RuntimeToolStatus {
name: string;
ok: boolean;
@@ -137,6 +164,9 @@ export interface RuntimeToolStatus {
probe: RuntimeCommandProbe;
}
const AUTH_BROKER_ENV_KEYS = ["UNIDESK_AUTH_BROKER_URL", "AUTH_BROKER_URL"] as const;
const AUTH_BROKER_OPERATIONS = ["github.auth.status", "github.issue.read", "github.pr.read", "github.pr.create"] as const;
function redactSensitive(value: string): string {
return value
.replace(/gh[pousr]_[A-Za-z0-9_]{20,}/gu, "***")
@@ -238,6 +268,48 @@ function boolEnv(name: string): boolean {
return value !== undefined && value.trim().length > 0;
}
function authBrokerEndpointEnvKey(): string | null {
for (const key of AUTH_BROKER_ENV_KEYS) {
if (boolEnv(key)) return key;
}
return null;
}
function authBrokerStatus(): RuntimeAuthBrokerStatus {
const endpointEnvKey = authBrokerEndpointEnvKey();
const configured = endpointEnvKey !== null;
return {
ok: configured,
configured,
source: configured ? "auth-broker" : "broker/auth-broker-needed",
endpointEnvKey,
runnerEnvTokenRequired: false,
credentialSource: configured ? "broker-held-github-credential" : null,
failureKind: configured ? null : "auth-missing",
degradedReason: configured ? null : "auth-broker-needed",
capability: {
source: configured ? "broker-issued-token" : "missing-token",
githubRestAuth: configured,
operations: [...AUTH_BROKER_OPERATIONS],
systemGhBinaryRequiredForWrites: false,
preflightWritesRemote: false,
preflightCreatesPr: false,
preflightMergesPr: false,
realPrCreateRequiresCommanderAuthorization: true,
valuesPrinted: false,
},
nextAction: configured ? "use-auth-broker" : "configure-auth-broker-or-env-token",
next: 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 fileExistsProbe(path: string): boolean {
return shellProbe(`test -s ${shellQuote(path)}`, 2000).ok;
}
@@ -420,6 +492,7 @@ function collectPullRequestDeliveryPreflight(options: RuntimePreflightOptions, c
ghHostsConfigPresent: fileExistsProbe(`${home ?? "/root"}/.config/gh/hosts.yml`),
gitCredentialsPresent: fileExistsProbe(`${home ?? "/root"}/.git-credentials`),
};
const authBroker = authBrokerStatus();
const egressProxy = proxySummary();
const issueUrl = issueApiUrl(githubApiBaseUrl, githubRepo, issueProbeNumber);
const egress = {
@@ -467,33 +540,48 @@ function collectPullRequestDeliveryPreflight(options: RuntimePreflightOptions, c
const risks: string[] = [];
if (!tools.git.ok) limitations.push("missing git CLI");
if (!tools.jq.ok) limitations.push("missing jq CLI");
if (!tools.gh.ok) risks.push("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 are available");
if (!tools.gh.ok) risks.push("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");
if (!unideskGhCli.ok) limitations.push("UniDesk gh CLI is missing at scripts/cli.ts; runner cannot use the repo-native REST PR create/comment path");
if (!credentials.ghTokenPresent && !credentials.githubTokenPresent) limitations.push("GH_TOKEN/GITHUB_TOKEN is not present; gh cannot create PRs unless another gh credential store is mounted");
if (!credentials.ghHostsConfigPresent && !credentials.gitCredentialsPresent && !credentials.ghTokenPresent && !credentials.githubTokenPresent) limitations.push("no gh hosts config, git credentials file, GH_TOKEN, or GITHUB_TOKEN is visible for GitHub API/issue/PR access");
if (!credentials.ghTokenPresent && !credentials.githubTokenPresent && !authBroker.ok) limitations.push("GH_TOKEN/GITHUB_TOKEN is not present and auth-broker is not configured; PR create requires broker, env token, or another gh credential store");
if (!credentials.ghHostsConfigPresent && !credentials.gitCredentialsPresent && !credentials.ghTokenPresent && !credentials.githubTokenPresent && !authBroker.ok) limitations.push("no auth-broker, gh hosts config, git credentials file, GH_TOKEN, or GITHUB_TOKEN is visible for GitHub API/issue/PR access");
if (!gitInfo.insideWorktree) limitations.push("current directory is not a Git worktree");
if (gitInfo.remoteOrigin === null) limitations.push("git remote origin is not configured");
if (githubRepo === null) limitations.push("cannot infer GitHub owner/repo from GH_REPO or git remote origin");
if (!gitInfo.homeWritable) limitations.push("HOME is not writable");
if (!gitInfo.knownHostsPresent) risks.push("GitHub known_hosts is not pre-seeded; first SSH use may need accept-new behavior");
if (!gitInfo.privateKeyPresent && !credentials.sshAuthSockPresent && !credentials.ghTokenPresent && !credentials.githubTokenPresent) limitations.push("no SSH key, SSH agent, or GitHub token credential is visible");
if (!gitInfo.privateKeyPresent && !credentials.sshAuthSockPresent && !credentials.ghTokenPresent && !credentials.githubTokenPresent && !authBroker.ok) limitations.push("no SSH key, SSH agent, GitHub token credential, or auth-broker credential is visible");
if (egress.proxy.selectedProxyHost !== null && egress.proxy.selectedProxyHostResolvable === false) limitations.push(`configured GitHub egress proxy host is not resolvable: ${egress.proxy.selectedProxyHost}`);
if (options.includeRemote === true && !egress.githubDefault.ok) limitations.push("GitHub HTTPS probe failed with the default environment/proxy");
if (options.includeRemote === true && !egress.apiDefault.ok) limitations.push("GitHub API probe failed with the default environment/proxy");
if (options.includeRemote === true && egress.issueApi !== null && !egress.issueApi.ok) limitations.push(`GitHub issue API probe for #${issueProbeNumber} failed; private repo access likely lacks token or egress`);
if (options.includeRemote === true && egress.issueApi !== null && !egress.issueApi.ok) {
if (authBroker.ok) risks.push(`direct GitHub issue API probe for #${issueProbeNumber} failed without runner env token; auth-broker is the intended REST auth source`);
else limitations.push(`GitHub issue API probe for #${issueProbeNumber} failed; private repo access likely lacks token or egress`);
}
if (remote !== undefined) {
if (!remote.gitLsRemote.ok) limitations.push("git ls-remote origin master failed");
if (remote.gitHttpsLsRemote !== null && !remote.gitHttpsLsRemote.ok) limitations.push("anonymous HTTPS git ls-remote failed; HTTPS Git access likely needs token credentials");
if (!remote.githubSshAuthenticated) limitations.push("GitHub SSH auth probe did not authenticate");
if (remote.ghAuthStatus !== null && !remote.ghAuthStatus.ok) limitations.push("gh auth status failed");
if (tools.gh.ok && remote.ghRepoView !== null && !remote.ghRepoView.ok) limitations.push("gh repo view failed");
if (tools.gh.ok && remote.ghIssueView !== null && !remote.ghIssueView.ok) limitations.push(`gh issue read|view #${issueProbeNumber} failed`);
if (tools.gh.ok && remote.ghPrReadOnly !== null && !remote.ghPrReadOnly.ok) limitations.push("gh pr read-only probe failed");
if (remote.ghAuthStatus !== null && !remote.ghAuthStatus.ok) {
if (authBroker.ok) risks.push("system gh auth status failed; broker-backed UniDesk REST path remains the intended PR preflight auth source");
else limitations.push("gh auth status failed");
}
if (tools.gh.ok && remote.ghRepoView !== null && !remote.ghRepoView.ok) {
if (authBroker.ok) risks.push("system gh repo view failed; broker-backed UniDesk REST path remains the intended repo read path");
else limitations.push("gh repo view failed");
}
if (tools.gh.ok && remote.ghIssueView !== null && !remote.ghIssueView.ok) {
if (authBroker.ok) risks.push(`system gh issue read|view #${issueProbeNumber} failed; broker-backed UniDesk REST path remains the intended issue read path`);
else limitations.push(`gh issue read|view #${issueProbeNumber} failed`);
}
if (tools.gh.ok && remote.ghPrReadOnly !== null && !remote.ghPrReadOnly.ok) {
if (authBroker.ok) risks.push("system gh pr read-only probe failed; broker-backed UniDesk REST path remains the intended PR read path");
else limitations.push("gh pr read-only probe failed");
}
}
if (pushDryRun !== undefined && !pushDryRun.ok) limitations.push("git push --dry-run failed for probe branch");
if (prCreateDryRun !== undefined && !prCreateDryRun.ok) limitations.push("PR create dry-run body/command guard failed");
const prCliReady = unideskGhCli.ok;
const tokenOrGhStore = credentials.ghTokenPresent || credentials.githubTokenPresent || credentials.ghHostsConfigPresent || (remote?.ghAuthStatus?.ok === true);
const tokenOrGhStore = authBroker.ok || credentials.ghTokenPresent || credentials.githubTokenPresent || credentials.ghHostsConfigPresent || (remote?.ghAuthStatus?.ok === true);
const remoteReady = remote === undefined || (egress.githubDefault.ok && egress.apiDefault.ok && remote.gitLsRemote.ok && remote.githubSshAuthenticated);
const pushReady = pushDryRun === undefined || pushDryRun.ok;
const prCreateDryRunReady = prCreateDryRun === undefined || prCreateDryRun.ok;
@@ -502,6 +590,7 @@ function collectPullRequestDeliveryPreflight(options: RuntimePreflightOptions, c
checkedAt,
tools,
unideskGhCli,
authBroker,
credentials,
githubContext: {
host: githubHost,