// PB-26-003: verify the committed Noise WASM still matches crypto-core source. // Rebuilds via npm run build:noise-core and fails if any shipped artifact // drifts, so "reviewed source → shipped binary" is machine-enforced. import { spawnSync } from "node:child_process"; import { createHash } from "node:crypto"; import { readFileSync } from "node:fs"; import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; const root = resolve(dirname(fileURLToPath(import.meta.url)), ".."); const dest = resolve(root, "src/shared/noise-core-wasm"); const files = [ "peach_noise_core.js", "peach_noise_core.d.ts", "peach_noise_core_bg.wasm", "peach_noise_core_bg.wasm.d.ts", "peach_noise_core_bytes.ts", ]; function hashTree() { return Object.fromEntries( files.map((f) => [ f, createHash("sha256").update(readFileSync(resolve(dest, f))).digest("hex"), ]), ); } const testConstructorPattern = /(?:WithEphemeralForTest|with_ephemeral_for_test)/; function assertProductionExports(files) { const leaked = files.filter((f) => testConstructorPattern.test(readFileSync(resolve(dest, f), "utf8"))); if (leaked.length > 0) { console.error(`production Noise WASM exports test-only constructors: ${leaked.join(", ")}`); process.exit(1); } } assertProductionExports(["peach_noise_core.js", "peach_noise_core.d.ts", "peach_noise_core_bg.wasm.d.ts"]); const before = hashTree(); const build = spawnSync("npm", ["run", "build:noise-core"], { stdio: "inherit" }); if (build.status !== 0) { console.error( "noise-core rebuild failed — committed WASM provenance cannot be verified (PB-26-003)", ); process.exit(build.status ?? 1); } const after = hashTree(); const drifted = files.filter((f) => before[f] !== after[f]); if (drifted.length > 0) { console.error( `committed Noise WASM does not match crypto-core/src/lib.rs — drifted: ${drifted.join(", ")}\n` + "run `npm run build:noise-core` and commit the regenerated files", ); process.exit(1); } console.log("committed Noise WASM matches crypto-core source");