import assert from "node:assert/strict"; import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; export const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); export const ledgerPath = path.join(root, "docs/status/parity-ledger.json"); export const packagePath = path.join(root, "web/package.json"); export const evidencePath = path.join(root, "docs/status/v1-acceptance-evidence.json"); export const toolRelativePaths = [ "tools/web/v1-acceptance-lib.mjs", "tools/web/check-v1-acceptance-coverage.mjs", "tools/web/run-v1-acceptance.mjs", "tools/web/check-v1-acceptance-evidence.mjs", ]; export function sha256(value) { return crypto.createHash("sha256").update(value).digest("hex"); } export function readAcceptanceInputs() { const ledgerBytes = fs.readFileSync(ledgerPath); const packageBytes = fs.readFileSync(packagePath); return { ledgerBytes, packageBytes, ledger: JSON.parse(ledgerBytes), packageManifest: JSON.parse(packageBytes), }; } function resolveAcceptance(token, scripts) { assert.equal(typeof token, "string", "acceptance token must be a string"); if (token.startsWith("web:e2e:")) { const pattern = token.slice("web:e2e:".length); assert.ok(pattern.trim().length > 0, `${token}: E2E pattern must not be empty`); assert.equal(typeof scripts["test:e2e"], "string", `${token}: web test:e2e script is missing`); return { token, kind: "e2e", script: "test:e2e", args: ["--", "--workers=1", "-g", pattern], command: `npm --prefix web run test:e2e -- --workers=1 -g ${JSON.stringify(pattern)}`, }; } const match = /^web:(test|release):(.+)$/.exec(token); assert.ok(match, `${token}: unsupported acceptance namespace`); const script = `${match[1]}:${match[2]}`; assert.equal(typeof scripts[script], "string", `${token}: web package script ${script} is missing`); return { token, kind: "script", script, args: [], command: `npm --prefix web run ${script}`, }; } export function buildAcceptancePlan(ledger, packageManifest) { assert.equal(ledger.schemaVersion, 2, "unsupported parity ledger schema"); assert.ok(Array.isArray(ledger.families), "parity ledger families must be an array"); assert.equal(ledger.families.length, 12, "V1 acceptance expects N-015 through N-026"); assert.ok(packageManifest.scripts && typeof packageManifest.scripts === "object", "web package scripts are missing"); const byToken = new Map(); let declarationCount = 0; for (const family of ledger.families) { assert.match(family.id, /^N-0(?:1[5-9]|2[0-6])$/, `${family.id}: unexpected family id`); assert.ok(Array.isArray(family.acceptance) && family.acceptance.length > 0, `${family.id}: acceptance is empty`); assert.equal(new Set(family.acceptance).size, family.acceptance.length, `${family.id}: duplicate acceptance token`); for (const token of family.acceptance) { declarationCount += 1; const existing = byToken.get(token); if (existing) { existing.familyIds.push(family.id); continue; } byToken.set(token, { ...resolveAcceptance(token, packageManifest.scripts), familyIds: [family.id] }); } } const entries = [...byToken.values()]; return { familyCount: ledger.families.length, declarationCount, uniqueCount: entries.length, scriptCount: entries.filter((entry) => entry.kind === "script").length, e2eCount: entries.filter((entry) => entry.kind === "e2e").length, reusedCount: entries.filter((entry) => entry.familyIds.length > 1).length, entries, }; } export function expectedEvidenceIdentity() { const inputs = readAcceptanceInputs(); return { ...inputs, plan: buildAcceptancePlan(inputs.ledger, inputs.packageManifest), ledgerSha256: sha256(inputs.ledgerBytes), packageSha256: sha256(inputs.packageBytes), toolSourceSha256: Object.fromEntries( toolRelativePaths.map((relativePath) => [relativePath, sha256(fs.readFileSync(path.join(root, relativePath)))]), ), }; }