Files
workinf_Blender_Wasm/tools/web/check-io-format-receipt-freshness.mjs
mes123456 380cbed4ff
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled
Checkpoint web parity through Chromium input tasks
2026-08-19 10:39:03 -04:00

88 lines
5.5 KiB
JavaScript

import assert from "node:assert/strict";
import crypto from "node:crypto";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { execFileSync } from "node:child_process";
import { fileURLToPath, pathToFileURL } from "node:url";
import ts from "../../web/node_modules/typescript/lib/typescript.js";
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
const parentPath = path.join(repoRoot, "tests/golden/M12-05E/bound-runtime-receipts.json");
const freshPath = path.join(repoRoot, "tests/golden/M12-05F/fresh-runtime-receipts.json");
const appFreshPath = path.join(repoRoot, "web/app/src/capabilities/io-format-runtime-receipts-freshness.json");
const appExpectedPath = path.join(repoRoot, "web/app/src/capabilities/io-format-runtime-receipts-freshness-expected.json");
const appPath = path.join(repoRoot, "web/app/src/app/App.tsx");
const protocolPath = path.join(repoRoot, "web/protocol/io-format-receipt-freshness.ts");
const temporary = fs.mkdtempSync(path.join(os.tmpdir(), "io-format-receipt-freshness-"));
const sha256 = (bytes) => crypto.createHash("sha256").update(bytes).digest("hex");
const stableValue = (value) => Array.isArray(value) ? value.map(stableValue) : value && typeof value === "object" ? Object.fromEntries(Object.keys(value).sort().map((key) => [key, stableValue(value[key])])) : value;
const stableSha256 = (value) => sha256(JSON.stringify(stableValue(value)));
function transpile(sourcePath, outputName, replacements = []) {
const transpiled = ts.transpileModule(fs.readFileSync(sourcePath, "utf8"), { compilerOptions: { module: ts.ModuleKind.ES2022, target: ts.ScriptTarget.ES2022 }, fileName: sourcePath, reportDiagnostics: true });
assert.deepEqual(transpiled.diagnostics, []);
let output = transpiled.outputText;
for (const [from, to] of replacements) output = output.replaceAll(from, to);
const outputPath = path.join(temporary, outputName);
fs.writeFileSync(outputPath, output);
return outputPath;
}
try {
const parentBytes = fs.readFileSync(parentPath);
const bound = JSON.parse(parentBytes);
const freshBytes = fs.readFileSync(freshPath);
const fresh = JSON.parse(freshBytes);
assert.deepEqual(fs.readFileSync(appFreshPath), freshBytes, "App freshness receipt drifted from golden");
const appExpected = JSON.parse(fs.readFileSync(appExpectedPath));
const runtimeModule = transpile(path.join(repoRoot, "web/protocol/io-format-runtime-receipt.ts"), "io-format-runtime-receipt.mjs");
const bindingModule = transpile(path.join(repoRoot, "web/protocol/io-format-receipt-binding.ts"), "io-format-receipt-binding.mjs");
const protocolModule = transpile(protocolPath, "io-format-receipt-freshness.mjs", [["./io-format-receipt-binding\"", "./io-format-receipt-binding.mjs\""], ["./io-format-runtime-receipt\"", "./io-format-runtime-receipt.mjs\""]]);
const protocol = await import(pathToFileURL(protocolModule));
const expected = {
parentBindingSha256: sha256(parentBytes),
parentReceiptSetSha256: bound.parentReceiptSetSha256,
inventorySha256: bound.inventorySha256,
boundReceiptSetSha256: stableSha256(bound),
runtimeSha256: stableSha256(bound.runtime),
runtime: bound.runtime,
receiptIdentities: bound.receipts,
};
assert.equal(fresh.parentBindingSha256, expected.parentBindingSha256);
assert.equal(fresh.boundReceiptSetSha256, expected.boundReceiptSetSha256);
assert.equal(fresh.runtimeSha256, expected.runtimeSha256);
assert.deepEqual(appExpected, {
parentBindingSha256: expected.parentBindingSha256,
parentReceiptSetSha256: expected.parentReceiptSetSha256,
inventorySha256: expected.inventorySha256,
boundReceiptSetSha256: expected.boundReceiptSetSha256,
runtimeSha256: expected.runtimeSha256,
runtime: expected.runtime,
receiptIdentities: expected.receiptIdentities,
});
const appSource = fs.readFileSync(appPath, "utf8");
assert.match(appSource, /resolveFreshIOFormatRuntimeRoute\(IO_FORMAT_RUNTIME_RECEIPTS, IO_FORMAT_RUNTIME_RECEIPT_EXPECTED/);
await protocol.verifyIOFormatReceiptFreshness(fresh, expected);
assert.equal(protocol.resolveFreshIOFormatRuntimeRoute(fresh, expected, { format: "GLB", operation: "EXPORT" }).status, "READY");
assert.equal(protocol.resolveFreshIOFormatRuntimeRoute(fresh, expected, { format: "USD", operation: "EXPORT" }).status, "BLOCKED");
const forged = structuredClone(fresh);
forged.bound.receipts[0].operator = "forged.operator";
await assert.rejects(() => protocol.verifyIOFormatReceiptFreshness(forged, expected), (error) => error.reason === "RECEIPT_FORGED");
const stale = structuredClone(fresh);
stale.bound.inventorySha256 = "a".repeat(64);
assert.equal(protocol.resolveFreshIOFormatRuntimeRoute(stale, expected, { format: "GLB", operation: "EXPORT" }).reason, "RECEIPT_STALE");
const crossVersion = structuredClone(fresh);
crossVersion.bound.runtime.versionTuple = [5, 3, 0];
assert.equal(protocol.resolveFreshIOFormatRuntimeRoute(crossVersion, expected, { format: "GLB", operation: "EXPORT" }).reason, "RECEIPT_CROSS_VERSION");
const regenerated = path.join(temporary, "fresh-runtime-receipts.json");
execFileSync(process.execPath, [path.join(repoRoot, "tools/web/generate-io-format-receipt-freshness.mjs"), "--output", regenerated], { cwd: repoRoot });
assert.deepEqual(fs.readFileSync(regenerated), freshBytes, "freshness receipt is not deterministic");
process.stdout.write("io-format-receipt-freshness-ok receipts=14 forged=BLOCKED stale=BLOCKED cross-version=BLOCKED deterministic=true\n");
}
finally {
fs.rmSync(temporary, { recursive: true, force: true });
}