import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); const parentPath = path.join(repoRoot, "tests/golden/M12-05E/bound-runtime-receipts.json"); const outputArgument = process.argv.indexOf("--output"); const outputPath = outputArgument === -1 ? path.join(repoRoot, "tests/golden/M12-05F/fresh-runtime-receipts.json") : path.resolve(process.argv[outputArgument + 1] ?? ""); const expectedArgument = process.argv.indexOf("--expected-output"); const expectedOutputPath = expectedArgument === -1 ? null : path.resolve(process.argv[expectedArgument + 1] ?? ""); if (!outputPath) throw new Error("--output requires a file"); function stableValue(value) { if (Array.isArray(value)) return value.map(stableValue); if (value && typeof value === "object") return Object.fromEntries(Object.keys(value).sort().map((key) => [key, stableValue(value[key])])); return value; } function sha256(value) { return crypto.createHash("sha256").update(value).digest("hex"); } const parentBytes = fs.readFileSync(parentPath); const bound = JSON.parse(parentBytes); if (bound.schemaVersion !== 1 || bound.task !== "M12-05E") throw new Error("M12-05E bound receipt header is invalid"); const output = { schemaVersion: 1, task: "M12-05F", parentBindingSha256: sha256(parentBytes), boundReceiptSetSha256: sha256(JSON.stringify(stableValue(bound))), runtimeSha256: sha256(JSON.stringify(stableValue(bound.runtime))), bound, }; fs.mkdirSync(path.dirname(outputPath), { recursive: true }); fs.writeFileSync(outputPath, `${JSON.stringify(output, null, 2)}\n`); if (expectedOutputPath) { fs.mkdirSync(path.dirname(expectedOutputPath), { recursive: true }); fs.writeFileSync(expectedOutputPath, `${JSON.stringify({ parentBindingSha256: output.parentBindingSha256, parentReceiptSetSha256: bound.parentReceiptSetSha256, inventorySha256: bound.inventorySha256, boundReceiptSetSha256: output.boundReceiptSetSha256, runtimeSha256: output.runtimeSha256, runtime: bound.runtime, receiptIdentities: bound.receipts, }, null, 2)}\n`); } process.stdout.write(`io-format-receipt-freshness-generated receipts=${bound.receipts.length} output=${path.relative(repoRoot, outputPath)}\n`);