mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-17 12:22:34 +03:00
Adds a shadow release-acceptance report alongside release-green: an inventory/reduce/oracle pipeline under `scripts/quality/release-acceptance/` with a JSON schema, fixtures and a workflow that uploads the report as an artifact. Contained by design, which is why it merges as-is: it runs only on push to `release/v*` and on manual dispatch (never on pull requests), the step is `continue-on-error`, `permissions: contents: read`, `persist-credentials: false`, and it consumes no secrets. Nothing in the product changes; the report is advisory until we decide to promote it. Validated as a combined board first (this PR merged with the 11 siblings of the same batch on the release tip): eslint on every changed file with the suppressions file, typecheck:core, check:open-sse-typecheck, complexity, cognitive-complexity, changelog-integrity, i18n new-key coverage, docs-sync, migration-numbering, provider-consistency and a duplicate-identifier audit all green, plus 275 passing / 0 failing focused node:test cases across the 28 test files the batch touches. Then re-validated alone on the fresh tip before this merge: conflicts re-resolved, file sizes rebaselined for this PR's own growth, eslint and this PR's focused tests re-run. Thanks @HouMinXi!
175 lines
4.9 KiB
TypeScript
175 lines
4.9 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { mkdtempSync, mkdirSync, writeFileSync, readFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import {
|
|
exitFor,
|
|
reduceManifests,
|
|
main,
|
|
} from "../../scripts/quality/validate-release-acceptance.mjs";
|
|
|
|
const SHA = "30b5bf18fbe827a0283ce17e91bda22cc8b4c13e";
|
|
function key(id) {
|
|
return { gate_id: id, suite_id: null, shard_index: null, shard_total: null };
|
|
}
|
|
function gate(id, status) {
|
|
return {
|
|
gate_id: id,
|
|
suite_id: null,
|
|
shard_index: null,
|
|
shard_total: null,
|
|
tested_sha: SHA,
|
|
run_id: "1",
|
|
run_attempt: 1,
|
|
command_id: id,
|
|
gate_type: "static",
|
|
status,
|
|
cause: null,
|
|
exit_code: status === "PASS" ? 0 : 1,
|
|
duration_ms: 1,
|
|
evidence: [
|
|
{
|
|
artifact_id: "logs",
|
|
member: "lint.log",
|
|
algorithm: "sha256",
|
|
digest: "7f227db1653b6b723b07c8f2f6eb488f1f09e2f083ca7a3f5e02bbb274f5ff2e",
|
|
},
|
|
],
|
|
};
|
|
}
|
|
|
|
test("exit mapping", () => {
|
|
assert.equal(exitFor("VERIFIED"), 0);
|
|
assert.equal(exitFor("FAILED"), 1);
|
|
assert.equal(exitFor("UNVERIFIED"), 2);
|
|
});
|
|
|
|
test("three PASS manifests yield VERIFIED", () => {
|
|
const plan = {
|
|
required_gates: [key("a"), key("b"), key("c")],
|
|
identity: { tested_sha: SHA, run_id: "1", run_attempt: 1 },
|
|
};
|
|
const out = reduceManifests(plan, [
|
|
{ gates: [gate("a", "PASS")] },
|
|
{ gates: [gate("b", "PASS")] },
|
|
{ gates: [gate("c", "PASS")] },
|
|
]);
|
|
assert.equal(out.verdict, "VERIFIED");
|
|
assert.equal(exitFor(out.verdict), 0);
|
|
});
|
|
|
|
test("one FAIL yields FAILED", () => {
|
|
const plan = {
|
|
required_gates: [key("a")],
|
|
identity: { tested_sha: SHA, run_id: "1", run_attempt: 1 },
|
|
};
|
|
const out = reduceManifests(plan, [{ gates: [gate("a", "FAIL")] }]);
|
|
assert.equal(out.verdict, "FAILED");
|
|
assert.equal(exitFor(out.verdict), 1);
|
|
});
|
|
|
|
test("required missing yields UNVERIFIED", () => {
|
|
const plan = {
|
|
required_gates: [key("a"), key("b")],
|
|
identity: { tested_sha: SHA, run_id: "1", run_attempt: 1 },
|
|
};
|
|
const out = reduceManifests(plan, [{ gates: [gate("a", "PASS")] }]);
|
|
assert.equal(out.verdict, "UNVERIFIED");
|
|
assert.equal(exitFor(out.verdict), 2);
|
|
});
|
|
|
|
test("workflow source-guard", () => {
|
|
const text = readFileSync(".github/workflows/release-acceptance.yml", "utf8");
|
|
assert.match(text, /name: Release acceptance/);
|
|
assert.match(text, /cancel-in-progress: false/);
|
|
assert.equal(text.includes("gh issue close"), false);
|
|
assert.match(text, /if: github.event_name != 'pull_request'/);
|
|
});
|
|
|
|
test("schema_invalid does not throw when required_gates is missing", async () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "acc-"));
|
|
writeFileSync(
|
|
join(dir, "plan.json"),
|
|
JSON.stringify({
|
|
identity: {
|
|
repository: "diegosouzapw/OmniRoute",
|
|
run_id: "1",
|
|
run_attempt: 1,
|
|
workflow: "release-acceptance.yml",
|
|
trigger: "push",
|
|
scope: "release",
|
|
requested_ref: "refs/heads/release/v3.8.51",
|
|
base_sha: SHA,
|
|
candidate_sha: SHA,
|
|
tested_sha: SHA,
|
|
},
|
|
artifact: null,
|
|
})
|
|
);
|
|
const man = join(dir, "m");
|
|
mkdirSync(man);
|
|
writeFileSync(join(man, "a.json"), JSON.stringify({ gates: [gate("a", "PASS")] }));
|
|
const out = join(dir, "report.json");
|
|
const code = await main([
|
|
"node",
|
|
"cli",
|
|
"--plan",
|
|
join(dir, "plan.json"),
|
|
"--manifests",
|
|
man,
|
|
"--out",
|
|
out,
|
|
]);
|
|
assert.equal(code, 2);
|
|
const report = JSON.parse(readFileSync(out, "utf8"));
|
|
assert.equal(report.verdict, "UNVERIFIED");
|
|
assert.ok(Array.isArray(report.required_gates));
|
|
assert.ok(report.evidence_errors.some((e) => e.code === "empty_required_set"));
|
|
assert.equal(
|
|
report.evidence_errors.some((e) => e.code === "schema_invalid"),
|
|
false
|
|
);
|
|
});
|
|
|
|
test("schema_invalid keeps FAILED when reduce already failed", async () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "acc-fail-"));
|
|
const plan = {
|
|
required_gates: [key("a")],
|
|
identity: {
|
|
repository: "diegosouzapw/OmniRoute",
|
|
run_id: "1",
|
|
run_attempt: 1,
|
|
workflow: "release-acceptance.yml",
|
|
trigger: "push",
|
|
scope: "release",
|
|
requested_ref: "refs/heads/release/v3.8.51",
|
|
base_sha: SHA,
|
|
candidate_sha: SHA,
|
|
tested_sha: SHA,
|
|
},
|
|
artifact: null,
|
|
};
|
|
writeFileSync(join(dir, "plan.json"), JSON.stringify(plan));
|
|
const man = join(dir, "m");
|
|
mkdirSync(man);
|
|
const g = gate("a", "FAIL");
|
|
g.unexpected = true;
|
|
writeFileSync(join(man, "a.json"), JSON.stringify({ gates: [g] }));
|
|
const out = join(dir, "report.json");
|
|
const code = await main([
|
|
"node",
|
|
"cli",
|
|
"--plan",
|
|
join(dir, "plan.json"),
|
|
"--manifests",
|
|
man,
|
|
"--out",
|
|
out,
|
|
]);
|
|
assert.equal(code, 1);
|
|
const report = JSON.parse(readFileSync(out, "utf8"));
|
|
assert.equal(report.verdict, "FAILED");
|
|
assert.ok(report.evidence_errors.some((e) => e.code === "schema_invalid"));
|
|
});
|