Files
pikasTech-unidesk/scripts/code-queue-pr-preflight-contract-test.ts
T
2026-05-21 10:19:08 +00:00

296 lines
15 KiB
TypeScript

import { codexPrPreflightQueryForTest } from "./src/code-queue";
type JsonRecord = Record<string, unknown>;
function assertCondition(condition: unknown, message: string, detail: unknown = {}): void {
if (!condition) throw new Error(`${message}: ${JSON.stringify(detail)}`);
}
function asRecord(value: unknown): JsonRecord {
assertCondition(typeof value === "object" && value !== null && !Array.isArray(value), "expected JSON object", { value });
return value as JsonRecord;
}
function localBackendCoreMissingFixture(): JsonRecord {
return {
ok: false,
failureKind: "target-stack-not-running",
degradedReason: "backend-core-container-missing",
runnerDisposition: "infra-blocked",
message: "backend-core/database target containers are not running; only verify-only containers were observed.",
targetStack: {
expectedContainers: ["unidesk-backend-core", "unidesk-database", "baidu-netdisk-backend"],
missingContainers: ["unidesk-backend-core", "unidesk-database", "baidu-netdisk-backend"],
verifyOnlyObserved: true,
},
readOnlyCommands: [
"bun scripts/cli.ts server status",
"bun scripts/cli.ts schedule list",
"bun scripts/cli.ts schedule runs --limit 20",
],
authorizationRequiredForRecovery: ["restore runtime secret coverage", "start the target stack"],
};
}
function remoteControlPlaneResult(overrides: Partial<JsonRecord> = {}): JsonRecord {
return {
ok: true,
runnerDisposition: "ready",
failureKind: null,
degradedReason: null,
upstream: { ok: true, status: 200 },
controlPlane: {
mode: "remote-frontend",
host: "74.48.78.17",
frontendUrl: "http://74.48.78.17:18081",
localBackendCoreMissing: true,
remoteFallbackUsed: true,
},
preflight: {
ok: true,
runnerDisposition: "ready",
failureKind: null,
degradedReason: null,
checkedAt: "2026-05-20T00:00:00.000Z",
runner: {
serviceId: "code-queue",
plane: "D601 k3s scheduler/runner",
queueScope: "all queues executed by the scheduler, including default",
cwd: "/workspace/unidesk",
pid: 123,
},
tokenCoverage: {
ok: true,
source: "GH_TOKEN",
ghTokenPresent: true,
githubTokenPresent: false,
ghCredentialStorePresent: false,
runnerDisposition: "ready",
missing: [],
scope: "scheduler-runner-env",
},
prCapabilityContract: {
targetBranch: "master",
tokenSource: "GH_TOKEN",
systemGhBinaryRequiredForWrites: false,
unideskGhCli: { ok: true, path: "/workspace/unidesk/scripts/cli.ts", present: true, role: "repo-native REST GitHub CLI used by bun scripts/cli.ts gh", requiresSystemGhBinary: false },
pushDryRun: { requested: false, ref: "refs/heads/probe/code-queue-pr-capability-dryrun", writesRemote: false, commandShape: "git push --dry-run origin HEAD:refs/heads/probe/code-queue-pr-capability-dryrun" },
prCreateDryRun: { requested: false, headBranch: "feature/code-queue-pr-preflight", writesRemote: false, commandShape: "bun scripts/cli.ts gh pr create --repo pikasTech/unidesk --base master --head feature/code-queue-pr-preflight --dry-run" },
expectedPrHandoff: {
sourceBranch: "feature/code-queue-pr-preflight",
targetBranch: "master",
runnerCreatesPrAfterAuthorization: true,
commanderReviewsAndMerges: true,
preflightCreatesPr: false,
preflightMergesPr: false,
},
unsupportedMergeBoundary: {
supported: false,
command: "bun scripts/cli.ts gh pr merge <number> --repo pikasTech/unidesk",
degradedReason: "unsupported-command",
runnerDisposition: "business-failed",
note: "UniDesk CLI intentionally does not merge PRs in this phase; runner handoff stops at PR creation and evidence.",
},
},
controlPlane: {
mode: "local-backend-core",
localBackendCoreMissing: false,
remoteFallbackUsed: false,
},
tools: {
git: { ok: true, path: "/usr/bin/git", version: "git version 2.43.0" },
gh: { ok: true, path: "/usr/bin/gh", version: "gh version 2.45.0" },
systemGhBinary: { ok: true, path: "/usr/bin/gh", version: "gh version 2.45.0" },
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, role: "repo-native REST GitHub CLI used by bun scripts/cli.ts gh", requiresSystemGhBinary: false },
},
agentPorts: {
codex: { ok: true, commandPath: "/usr/local/bin/codex", version: "codex 0.128.0", errors: [] },
opencode: { ok: true, commandPath: "/usr/local/bin/opencode", version: "opencode 1.14.48", errors: [] },
},
git: {
insideWorktree: true,
branch: "feature/code-queue-pr-preflight",
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: 35,
},
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: { command: "gh", args: ["auth", "status"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
ghRepoView: { command: "gh", args: ["repo", "view", "pikasTech/unidesk"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
ghIssueView: { command: "gh", args: ["issue", "view", "35"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
ghPrReadOnly: { command: "gh", args: ["pr", "list"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
},
pushDryRun: null,
prCreateDryRun: null,
limitations: [],
risks: [],
runnerDisposition: "ready",
recoveryHint: "Runner PR workflow has env-token coverage for the scheduler.",
commands: {
local: "bun scripts/cli.ts gh auth status --repo pikasTech/unidesk",
runner: "bun scripts/cli.ts codex pr-preflight --remote",
runnerPushDryRun: "bun scripts/cli.ts codex pr-preflight --remote --push-dry-run --push-dry-run-ref refs/heads/probe/code-queue-pr-capability",
runnerPrCreateDryRun: "bun scripts/cli.ts codex pr-preflight --remote --pr-create-dry-run --pr-create-dry-run-head <head-branch>",
rawProxy: "bun scripts/cli.ts microservice proxy code-queue /api/runtime-preflight?remote=1 --raw",
},
},
...overrides,
};
}
async function main(): Promise<void> {
let observedLocalPath = "";
const remoteFallback = await codexPrPreflightQueryForTest(["--remote", "--issue", "35"], {
config: {
project: { name: "unidesk", timezone: "Etc/UTC" },
runtime: { typescript: "bun", bunVersion: "1.3.13" },
network: {
host: "0.0.0.0",
publicHost: "74.48.78.17",
core: { port: 18080, containerPort: 8080 },
frontend: { port: 18081, containerPort: 8080 },
devFrontend: { port: 18083, containerPort: 8080 },
database: { port: 15432, containerPort: 5432 },
providerIngress: { port: 18082, containerPort: 8081 },
},
database: { user: "unidesk", password: "unidesk_dev_password", name: "unidesk", volume: "unidesk_pgdata_10gb", volumeSize: "15GB" },
providerGateway: {
id: "main-server",
name: "Main Server Provider",
token: "unidesk-dev-token-change-me",
labels: { host: "main-server", role: "self-provider", docker: true },
heartbeatIntervalMs: 15000,
reconnectBaseMs: 1000,
reconnectMaxMs: 30000,
metrics: { diskPath: "/" },
upgrade: { hostProjectRoot: "/root/unidesk", workspacePath: "/workspace", composeFile: "docker-compose.yml", composeEnvFile: ".state/docker-compose.env", composeProject: "unidesk", service: "provider-gateway", runnerImage: "unidesk_provider-gateway" },
},
docker: { composeFile: "docker-compose.yml", projectName: "unidesk" },
microservices: [],
paths: { stateDir: ".state", logsDir: "logs", docsReferenceDir: "docs/reference" },
sshForwarding: { mode: "ws", keyDir: "/root/.ssh", host: "main-server", port: 22, user: "root" },
auth: { username: "admin", password: "Liang6516.", sessionSecret: "secret", sessionTtlSeconds: 86400 },
},
coreFetch: (path) => {
observedLocalPath = path;
return localBackendCoreMissingFixture();
},
remoteMainServerPrPreflight: () => remoteControlPlaneResult({
controlPlane: {
mode: "remote-frontend",
host: "74.48.78.17",
frontendUrl: "http://74.48.78.17:18081",
localBackendCoreMissing: true,
remoteFallbackUsed: true,
},
failureKind: null,
degradedReason: null,
}),
});
assertCondition(observedLocalPath === "/api/microservices/code-queue/proxy/api/runtime-preflight?remote=1&issue=35", "runner-like local path should stay on the stable proxy", { observedLocalPath });
const fallback = asRecord(remoteFallback);
assertCondition(fallback.ok === true, "remote fallback should succeed", fallback);
assertCondition(fallback.runnerDisposition === "ready", "remote fallback should stay ready", fallback);
assertCondition(fallback.controlPlane && asRecord(fallback.controlPlane).remoteFallbackUsed === true, "remote fallback should be marked", fallback.controlPlane);
assertCondition(fallback.failureKind === null, "remote fallback should not invent a failure kind when remote control plane is healthy", fallback);
const fallbackPreflight = asRecord(fallback.preflight);
assertCondition(fallbackPreflight.ok === true, "remote fallback preflight should stay ready", fallbackPreflight);
assertCondition(asRecord(fallbackPreflight.tokenCoverage).source === "GH_TOKEN", "token source should be GH_TOKEN", fallbackPreflight.tokenCoverage);
assertCondition(asRecord(fallbackPreflight.prCapabilityContract).targetBranch === "master", "target branch should stay master", fallbackPreflight.prCapabilityContract);
const authMissing = await codexPrPreflightQueryForTest(["--remote"], {
config: null,
coreFetch: () => localBackendCoreMissingFixture(),
});
const remoteControlPlaneMissingRecord = asRecord(authMissing);
assertCondition(remoteControlPlaneMissingRecord.ok === false, "missing control plane should fail", remoteControlPlaneMissingRecord);
assertCondition(remoteControlPlaneMissingRecord.failureKind === "proxy-gap", "missing control plane should classify as proxy-gap", remoteControlPlaneMissingRecord);
assertCondition(remoteControlPlaneMissingRecord.degradedReason === "remote-control-plane-unreachable", "missing control plane should classify as remote-control-plane-unreachable", remoteControlPlaneMissingRecord);
assertCondition(asRecord(remoteControlPlaneMissingRecord.controlPlane).localBackendCoreMissing === true, "local backend-core absence should remain evidence only", remoteControlPlaneMissingRecord.controlPlane);
const directAuthMissing = remoteControlPlaneResult({
ok: false,
failureKind: "auth-missing",
degradedReason: "GH_TOKEN/GITHUB_TOKEN missing",
runnerDisposition: "infra-blocked",
message: "GH_TOKEN/GITHUB_TOKEN missing in remote control plane",
tokenCoverage: {
ok: false,
source: null,
ghTokenPresent: false,
githubTokenPresent: false,
ghCredentialStorePresent: false,
runnerDisposition: "infra-blocked",
missing: ["GH_TOKEN", "GITHUB_TOKEN"],
scope: "scheduler-runner-env",
},
prCapabilityContract: {
targetBranch: "master",
tokenSource: null,
systemGhBinaryRequiredForWrites: false,
unideskGhCli: { ok: true, path: "/workspace/unidesk/scripts/cli.ts", present: true, role: "repo-native REST GitHub CLI used by bun scripts/cli.ts gh", requiresSystemGhBinary: false },
pushDryRun: { requested: false, ref: "refs/heads/probe/code-queue-pr-capability-dryrun", writesRemote: false, commandShape: "git push --dry-run origin HEAD:refs/heads/probe/code-queue-pr-capability-dryrun" },
prCreateDryRun: { requested: false, headBranch: "feature/code-queue-pr-preflight", writesRemote: false, commandShape: "bun scripts/cli.ts gh pr create --repo pikasTech/unidesk --base master --head feature/code-queue-pr-preflight --dry-run" },
expectedPrHandoff: { sourceBranch: "feature/code-queue-pr-preflight", targetBranch: "master", runnerCreatesPrAfterAuthorization: true, commanderReviewsAndMerges: true, preflightCreatesPr: false, preflightMergesPr: false },
unsupportedMergeBoundary: { supported: false, command: "bun scripts/cli.ts gh pr merge <number> --repo pikasTech/unidesk", degradedReason: "unsupported-command", runnerDisposition: "business-failed", note: "UniDesk CLI intentionally does not merge PRs in this phase; runner handoff stops at PR creation and evidence." },
},
});
const directAuthMissingRecord = asRecord(directAuthMissing);
assertCondition(directAuthMissingRecord.ok === false, "auth-missing remote result should fail", directAuthMissingRecord);
assertCondition(directAuthMissingRecord.failureKind === "auth-missing", "missing token should classify as auth-missing", directAuthMissingRecord);
assertCondition(directAuthMissingRecord.degradedReason === "GH_TOKEN/GITHUB_TOKEN missing", "auth missing should state token gap", directAuthMissingRecord);
const gitRemoteGap = remoteControlPlaneResult({
ok: false,
failureKind: "git-remote-gap",
degradedReason: "git remote probe failed",
runnerDisposition: "infra-blocked",
message: "git ls-remote probe failed",
});
const gitRemoteGapRecord = asRecord(gitRemoteGap);
assertCondition(gitRemoteGapRecord.failureKind === "git-remote-gap", "git probe failures should stay structured", gitRemoteGapRecord);
process.stdout.write(`${JSON.stringify({
ok: true,
checks: [
"runner-like local target-stack absence does not block remote fallback",
"remote control plane fallback preserves ready preflight",
"missing remote control plane returns proxy-gap",
"auth missing returns auth-missing",
"git remote failures return git-remote-gap",
],
observedLocalPath,
}, null, 2)}\n`);
}
if (import.meta.main) {
await main();
}