test(07-04): RED — the CLI vectors: per-gate evidence lines, the free-tier comparison table, CLEAN exit 0, --live contract, environment-drift exit 2

This commit is contained in:
araharah-executor
2026-10-25 05:03:00 +08:00
parent 9efb6e2832
commit 8378337578
+53 -2
View File
@@ -148,7 +148,8 @@ await test("BA2 a missing web/dist is notRun — NEVER a pass (exit-2 class)", a
}); });
await test("BA3 a fixture dist over the app-bundle ceiling FAILS the gate with the overage", async () => { await test("BA3 a fixture dist over the app-bundle ceiling FAILS the gate with the overage", async () => {
const fix = makeFixtureRoot("ba3-dist", { "assets/huge.js": "x".repeat(600000) }); const { randomBytes } = await import("node:crypto");
const fix = makeFixtureRoot("ba3-dist", { "assets/huge.js": randomBytes(600000).toString("base64") });
try { try {
const m = await import(gatesUrl); const m = await import(gatesUrl);
const r = await m.runBundleBudgetGate({ distDir: fix.dir }); const r = await m.runBundleBudgetGate({ distDir: fix.dir });
@@ -260,8 +261,58 @@ await test("GC2 a failing corpus FAILS the gate carrying that child's own output
assert.match(r.evidence, /CORPUS GATE FAIL: synthetic/, "the child's own failure output must be carried verbatim"); assert.match(r.evidence, /CORPUS GATE FAIL: synthetic/, "the child's own failure output must be carried verbatim");
}); });
/* ————— summary ————— */ /* ————— AU — the CLI ————— */
const cliPath = path.join(ROOT, "scripts", "budget-audit.mjs");
function runCli(args, env = {}) {
return spawnSync(process.execPath, [cliPath, ...args], {
cwd: ROOT,
encoding: "utf8",
timeout: 300000,
env: { ...process.env, ...env },
maxBuffer: 1 << 26,
});
}
await test("AU1 without --live: every required gate prints its evidence line, the free-tier comparison table is printed, and the audit is CLEAN with exit 0", () => {
assert.ok(existsSync(cliPath), "scripts/budget-audit.mjs must exist");
const r = runCli([]);
assert.equal(r.status, 0, `exit 0 expected on the current tree (stdout: ${r.stdout?.slice(-400)})`);
const out = r.stdout ?? "";
for (const id of ["route-cpu", "bundle-budget", "kv-writes", "subrequests", "golden-corpus"]) {
assert.match(out, new RegExp(`${id}: (PASS|FAIL|NOT RUN) — `), `${id} must print its one-line evidence`);
}
assert.match(out, /BUDGET AUDIT CLEAN/, "the CLEAN summary must print");
assert.match(out, /50\/request/, "the subrequest ceiling must appear in the comparison table");
assert.match(out, /10 ms\/invocation/, "the CPU ceiling must appear in the comparison table");
assert.match(out, /not measured/, "unmeasured ceilings must read `not measured` — never 0");
assert.match(out, /cache-headers: NOT RUN \(pass --live\)/, "the flag-skipped live gate is visible and honest");
});
await test("AU2 with --live: the live header probe runs and the exit contract holds — a NOT RUN cache-header gate NEVER coexists with exit 0", () => {
const r = runCli(["--live"]);
const out = r.stdout ?? "";
assert.ok([0, 1, 2].includes(r.status), `exit must be 0/1/2 (got ${r.status})`);
assert.match(out, /cache-headers: /, "the cache-header gate must print with --live");
if (out.includes("cache-headers: NOT RUN")) {
assert.equal(r.status, 2, "a NOT RUN gate must map to exit 2 (environment drift) — never a silent pass");
assert.match(out, /BUDGET AUDIT NOT RUN/, "the NOT RUN summary must print");
}
});
await test("AU3 environment drift (a root with no builds/graph) maps to exit 2 — BUDGET AUDIT NOT RUN, never a pass (T-07-22)", () => {
const empty = mkdtempSync(path.join(tmpdir(), "budget-empty-"));
try {
const r = runCli([], { PRIVACY_AUDIT_ROOT: empty });
assert.equal(r.status, 2, `a root without the measured surfaces must be exit 2 (stdout: ${r.stdout?.slice(-300)})`);
assert.match(r.stdout ?? "", /BUDGET AUDIT NOT RUN/, "the NOT RUN summary must print");
} finally {
rmSync(empty, { recursive: true, force: true });
}
});
/* ————— summary ————— */
if (failures.length > 0) { if (failures.length > 0) {
console.error(`\n${failures.length}/${ran} vector(s) FAILED:`); console.error(`\n${failures.length}/${ran} vector(s) FAILED:`);
for (const f of failures) console.error(` - ${f.name}`); for (const f of failures) console.error(` - ${f.name}`);