codex: expose auth broker pr preflight contract
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user