返回 DeepSeek-Reasonix
resolve-release-candidate.test.mjs
根目录 / scripts / resolve-release-candidate.test.mjs
1 import assert from "node:assert/strict";
2 import { spawnSync } from "node:child_process";
3 import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
4 import { tmpdir } from "node:os";
5 import path from "node:path";
6 import { fileURLToPath } from "node:url";
7 import test from "node:test";
8 import { inspectRecord, requireNotRevoked, selectRecordArtifact, validateCandidateRun } from "./resolve-release-candidate.mjs";
9
10 const id = `v1.2.3-${"a".repeat(12)}-${"b".repeat(12)}`;
11 const artifact = { id: 22, name: `release-candidate-record-${id}`, expired: false, workflow_run: { id: 11 } };
12 const run = { id: 11, run_attempt: 2, repository: { full_name: "esengine/DeepSeek-Reasonix" }, path: ".github/workflows/release-candidate.yml", head_branch: "main-v2", head_sha: "c".repeat(40), event: "workflow_dispatch", status: "completed", conclusion: "success" };
13 const record = { candidateId: id, version: "1.2.3", sourceSHA: "a".repeat(40), control: { buildSHA: run.head_sha }, signing: { desktopFingerprint: "v1:example" }, validity: { createdAt: "2026-01-01T00:00:00Z", expiresAt: "2027-01-01T00:00:00Z", revoked: false }, source: { runId: "11", runAttempt: "2", desktopPrefix: "desktop-11-2-preflight", payloadArtifactId: "33", payloadArtifactName: `release-candidate-payload-${id}`, evidenceArtifactId: "34", evidenceArtifactName: `release-candidate-evidence-${id}` } };
14
15 for (const purpose of ["release", "rehearsal"]) {
16 test(`${purpose} CLI writes the exact workflow output contract`, t => {
17 const root = mkdtempSync(path.join(tmpdir(), "reasonix-candidate-outputs-"));
18 t.after(() => rmSync(root, { recursive: true, force: true }));
19 const namespace = purpose === "release" ? "release-candidate" : "release-candidate-rehearsal";
20 const payloadName = `${namespace}-payload-${id}`;
21 const evidenceName = `${namespace}-evidence-${id}`;
22 const sealed = { ...record, purpose,
23 validity: { ...record.validity, expiresAt: "2099-01-01T00:00:00Z" },
24 source: { ...record.source, payloadArtifactName: payloadName, evidenceArtifactName: evidenceName },
25 };
26 const inputs = [sealed, { ...artifact, name: `${namespace}-record-${id}` }, run].map((value, index) => {
27 const file = path.join(root, `${index}.json`);
28 writeFileSync(file, JSON.stringify(value));
29 return file;
30 });
31 const output = path.join(root, "outputs");
32 const result = spawnSync(process.execPath, [fileURLToPath(new URL("./resolve-release-candidate.mjs", import.meta.url)),
33 purpose === "release" ? "inspect" : "inspect-rehearsal", id, ...inputs],
34 { encoding: "utf8", env: { ...process.env, GITHUB_OUTPUT: output } });
35 assert.equal(result.status, 0, result.stderr);
36 const values = Object.fromEntries(readFileSync(output, "utf8").trim().split("\n").map(line => {
37 const separator = line.indexOf("=");
38 return [line.slice(0, separator), line.slice(separator + 1)];
39 }));
40 assert.deepEqual(values, {
41 candidate_id: id, version: "1.2.3", source_sha: record.sourceSHA,
42 candidate_control_sha: run.head_sha, signing_fingerprint: "v1:example",
43 producer_run_id: "11", producer_run_attempt: "2", desktop_prefix: "desktop-11-2-preflight",
44 payload_artifact_id: "33", payload_artifact_name: payloadName,
45 evidence_artifact_id: "34", evidence_artifact_name: evidenceName,
46 });
47 });
48 }
49
50 test("rejects missing or malformed source/control identities before emitting outputs", () => {
51 for (const sourceSHA of [undefined, "", "main-v2"]) {
52 assert.throws(() => inspectRecord({ ...record, sourceSHA }, id, artifact, run), /source SHA/);
53 }
54 for (const buildSHA of [undefined, "", "main-v2"]) {
55 assert.throws(() => inspectRecord({ ...record, control: { buildSHA } }, id, artifact, run), /control SHA/);
56 }
57 });
58
59 test("selects the newest active exact-name record", () => {
60 assert.equal(selectRecordArtifact([{ ...artifact, id: 20 }, artifact, { ...artifact, id: 30, expired: true }], id).id, 22);
61 assert.equal(selectRecordArtifact([], id, false), null);
62 assert.throws(() => selectRecordArtifact([], id), /not found/);
63 });
64
65 test("accepts a successful protected producer and exact record", () => {
66 assert.doesNotThrow(() => validateCandidateRun(run, artifact, "esengine/DeepSeek-Reasonix"));
67 const inspected = inspectRecord(record, id, artifact, run);
68 assert.equal(inspected.payloadArtifactId, "33");
69 assert.equal(inspected.evidenceArtifactId, "34");
70 });
71
72 test("rehearsal records cannot be selected or inspected for publication", () => {
73 const rehearsalArtifact = { ...artifact, name: `release-candidate-rehearsal-record-${id}` };
74 const rehearsalRecord = {
75 ...record, purpose: "rehearsal",
76 source: {
77 ...record.source,
78 payloadArtifactName: `release-candidate-rehearsal-payload-${id}`,
79 evidenceArtifactName: `release-candidate-rehearsal-evidence-${id}`,
80 },
81 };
82 assert.equal(selectRecordArtifact([rehearsalArtifact], id, false), null);
83 assert.equal(selectRecordArtifact([rehearsalArtifact], id, true, "rehearsal"), rehearsalArtifact);
84 assert.throws(() => inspectRecord(rehearsalRecord, id, rehearsalArtifact, run), /purpose mismatch/);
85 assert.throws(() => inspectRecord(rehearsalRecord, id, artifact, run, new Date(), "rehearsal"), /artifact identity/);
86 assert.equal(inspectRecord(rehearsalRecord, id, rehearsalArtifact, run, new Date(), "rehearsal").payloadArtifactId, "33");
87 });
88
89 test("accepts automatic preparation after the reviewed Notes PR merges", () => {
90 assert.doesNotThrow(() => validateCandidateRun({ ...run, event: "push" }, artifact, "esengine/DeepSeek-Reasonix"));
91 });
92
93 for (const change of [
94 { path: ".github/workflows/other.yml" }, { head_branch: "topic" }, { event: "pull_request" },
95 { conclusion: "failure" }, { repository: { full_name: "fork/Reasonix" } },
96 ]) {
97 test(`rejects untrusted producer ${JSON.stringify(change)}`, () => {
98 assert.throws(() => validateCandidateRun({ ...run, ...change }, artifact, "esengine/DeepSeek-Reasonix"));
99 });
100 }
101
102 test("rejects a payload artifact substituted after sealing", () => {
103 assert.throws(() => inspectRecord({ ...record, source: { ...record.source, payloadArtifactId: "" } }, id, artifact, run));
104 });
105
106 test("rejects expired or record-revoked candidates before payload reuse", () => {
107 assert.throws(() => inspectRecord(record, id, artifact, run, new Date("2027-01-02T00:00:00Z")), /expired/);
108 assert.throws(() => inspectRecord({ ...record, validity: { ...record.validity, revoked: true } }, id, artifact, run,
109 new Date("2026-01-02T00:00:00Z")), /revoked/);
110 });
111
112 test("rejects a candidate on the repository revocation list", () => {
113 assert.throws(() => requireNotRevoked(id, `v9.9.9-${"c".repeat(12)}-${"d".repeat(12)}, ${id}`), /is revoked/);
114 assert.doesNotThrow(() => requireNotRevoked(id, ""));
115 });
116
116 lines Plain Text