openclaw/scripts/resolve-frozen-codex-live-suite.mjs
Vincent Koc 3c4981a51e
fix(ci): validate frozen targets without executing candidate code (#144023)
* fix(ci): run frozen bundle clients from their shipped layout

Resolve only the selected bundle contract with local committed-object reads and trusted syntax parsing. Preserve each legacy client's manifest, helper, import depth and bytes before Docker staging, and reject unknown or unreadable contracts.

* fix(ci): preserve frozen source read failures

Distinguish committed absence from missing, corrupt, or wrong-kind Git objects before selecting frozen compatibility. Share bounded local-only source reads across the shell and bundle resolver, and preserve errors through conditional callers before gateway Docker work. This is the source-read stage only; aggregate frozen admission remains separate.

* fix(ci): isolate frozen consumer contracts

* fix(ci): add inert frozen target admission

* fix(ci): validate Docker lane alias contracts
2026-09-10 22:51:05 +08:00

140 lines
4.7 KiB
JavaScript

#!/usr/bin/env node
import { appendFileSync, existsSync, readFileSync, realpathSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const CODEX_SUITE_PREFIX = "live-codex-harness";
const GENERIC_CODEX_SUITE = "live-codex-harness-docker";
const GPT_56_SUITE_PREFIX = "live-codex-harness-gpt56-";
function requireEnv(name) {
const value = process.env[name]?.trim();
if (!value) {
throw new Error(`${name} is required`);
}
return value;
}
function appendLine(file, line) {
appendFileSync(file, `${line}\n`, "utf8");
}
function readTargetModelIds(readSource) {
const catalogPath = "extensions/codex/provider-catalog.ts";
const catalog = readSource(catalogPath);
if (catalog === null) {
const harnessPath = "scripts/test-live-codex-harness-docker.sh";
const source = readSource(harnessPath);
if (source === null) {
throw new Error(`missing frozen Codex harness: ${harnessPath}`);
}
const defaults = new Set(
[...source.matchAll(/\$\{OPENCLAW_LIVE_CODEX_HARNESS_MODEL:-[^/}]+\/([^}\s]+)\}/gu)].map(
(match) => match[1],
),
);
if (defaults.size !== 1) {
throw new Error(`cannot read one frozen Codex harness default from ${harnessPath}`);
}
// The harness default proves only the generic lane's model. Specialized
// lanes need the explicit cohort declaration from the historical catalog.
return { modelIds: new Set(defaults), supportsGpt56Cohort: false };
}
const source = catalog;
const start = source.indexOf("export const FALLBACK_CODEX_MODELS = [");
const end = source.indexOf("] satisfies", start);
if (start < 0 || end < 0) {
throw new Error(`cannot read the frozen Codex fallback catalog from ${catalogPath}`);
}
const modelIds = new Set(
[...source.slice(start, end).matchAll(/\bid:\s*["']([^"']+)["']/gu)].map((match) => match[1]),
);
const hasSol = modelIds.has("gpt-5.6-sol");
const hasLuna = modelIds.has("gpt-5.6-luna");
if (hasSol !== hasLuna) {
throw new Error("frozen Codex GPT-5.6 capability marker is incomplete; refusing to guess");
}
return { modelIds, supportsGpt56Cohort: hasSol && hasLuna };
}
export function resolveFrozenCodexCompatibility({ suiteId, readSource }) {
const { modelIds, supportsGpt56Cohort } = readTargetModelIds(readSource);
if (suiteId === GENERIC_CODEX_SUITE) {
const model = modelIds.has("gpt-5.6-luna")
? "openai/gpt-5.6-luna"
: modelIds.has("gpt-5.5")
? "openai/gpt-5.5"
: modelIds.has("gpt-5.4-mini")
? "openai/gpt-5.4-mini"
: undefined;
if (!model) {
throw new Error("frozen Codex catalog has no supported generic live-harness model");
}
return { model, runLane: true };
}
if (suiteId.startsWith(GPT_56_SUITE_PREFIX)) {
return { runLane: supportsGpt56Cohort };
}
return { runLane: true };
}
function main() {
const outputFile = requireEnv("GITHUB_OUTPUT");
const suiteId = requireEnv("OPENCLAW_FROZEN_CODEX_SUITE_ID");
const selectedSha = requireEnv("OPENCLAW_SELECTED_SHA");
const workflowSha = requireEnv("OPENCLAW_WORKFLOW_SHA");
const isFrozenTarget = selectedSha !== workflowSha;
const omissionsAllowed = process.env.OPENCLAW_ALLOW_FROZEN_TARGET_SCENARIO_OMISSIONS === "1";
if (!suiteId.startsWith(CODEX_SUITE_PREFIX) || !isFrozenTarget || !omissionsAllowed) {
appendLine(outputFile, "run_lane=true");
return;
}
const targetRoot = requireEnv("OPENCLAW_FROZEN_TARGET_ROOT");
const result = resolveFrozenCodexCompatibility({
suiteId,
readSource: (relativePath) => {
const file = path.join(targetRoot, relativePath);
return existsSync(file) ? readFileSync(file, "utf8") : null;
},
});
appendLine(outputFile, `run_lane=${result.runLane}`);
const summaryFile = requireEnv("GITHUB_STEP_SUMMARY");
if (result.model) {
appendLine(requireEnv("GITHUB_ENV"), `OPENCLAW_LIVE_CODEX_HARNESS_MODEL=${result.model}`);
appendLine(
summaryFile,
`Frozen Codex target \`${selectedSha}\`: \`${suiteId}\` uses \`${result.model}\`.`,
);
} else if (!result.runLane) {
appendLine(
summaryFile,
`Frozen Codex target \`${selectedSha}\`: omitted unsupported current-only suite \`${suiteId}\`.`,
);
console.log(`::notice::Omitting unsupported frozen-target Codex suite ${suiteId}`);
}
}
let invokedAsMain = false;
if (process.argv[1]) {
try {
invokedAsMain =
realpathSync.native(fileURLToPath(import.meta.url)) === realpathSync.native(process.argv[1]);
} catch {
// Inline and stdin importers need not have a filesystem entrypoint.
}
}
if (invokedAsMain) {
try {
main();
} catch (error) {
console.error(error instanceof Error ? error.message : String(error));
process.exitCode = 1;
}
}