Rebuild local Blender WASM environment and recovery evidence
This commit is contained in:
108
tools/web/intake-m12-immutable-snapshot.mjs
Normal file
108
tools/web/intake-m12-immutable-snapshot.mjs
Normal file
@@ -0,0 +1,108 @@
|
||||
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";
|
||||
|
||||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
const outputPath = path.join(root, "tests/golden/corrective/rehydration/M12-provenance-intake.json");
|
||||
const driftPath = path.join(root, "tests/golden/corrective/rehydration/M12-manifest-sha-drift.json");
|
||||
const snapshotArgument = process.argv.indexOf("--snapshot");
|
||||
const requestedSnapshot = snapshotArgument >= 0 ? process.argv[snapshotArgument + 1] : null;
|
||||
const write = process.argv.includes("--write");
|
||||
|
||||
const relative = (file) => path.relative(root, file).replaceAll(path.sep, "/");
|
||||
const sha256 = (file) => crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex");
|
||||
const readJson = (file) => JSON.parse(fs.readFileSync(file, "utf8"));
|
||||
const drift = readJson(driftPath);
|
||||
|
||||
function emptyReport(reason) {
|
||||
return {
|
||||
schemaVersion: 1,
|
||||
operation: "M12_IMMUTABLE_SNAPSHOT_PROVENANCE_INTAKE",
|
||||
historicalEvidencePreserved: true,
|
||||
immutableSourceSnapshotAvailable: false,
|
||||
provenanceState: "BLOCKED_SOURCE_LOST",
|
||||
sourceSnapshot: null,
|
||||
sourceSnapshotManifestSha256: null,
|
||||
driftEntries: drift.entries.length,
|
||||
restoredEntries: 0,
|
||||
remainingEntries: drift.entries.length,
|
||||
reason,
|
||||
entries: drift.entries.map((entry) => ({ ...entry, provenanceState: "BLOCKED_SOURCE_LOST" })),
|
||||
};
|
||||
}
|
||||
|
||||
function resolveSnapshot(value) {
|
||||
if (!value) return null;
|
||||
const candidate = path.resolve(root, value);
|
||||
if (!fs.existsSync(candidate)) return null;
|
||||
const manifestPath = fs.statSync(candidate).isDirectory() ? path.join(candidate, "snapshot-manifest.json") : candidate;
|
||||
if (!fs.existsSync(manifestPath)) return null;
|
||||
const manifest = readJson(manifestPath);
|
||||
assert.equal(manifest.schemaVersion, 1, "snapshot manifest schema must be 1");
|
||||
assert.ok(["IMMUTABLE_ARCHIVE", "IMMUTABLE_REPOSITORY", "SIGNED_ARTIFACT"].includes(manifest.mode), "snapshot mode is not immutable");
|
||||
assert.equal(manifest.authorized, true, "snapshot must be authorized");
|
||||
assert.ok(Array.isArray(manifest.files), "snapshot manifest files are missing");
|
||||
const rootPath = path.dirname(manifestPath);
|
||||
const files = new Map();
|
||||
for (const entry of manifest.files) {
|
||||
assert.equal(typeof entry.path, "string");
|
||||
assert.match(entry.sha256 ?? "", /^[a-f0-9]{64}$/u);
|
||||
const sourcePath = path.resolve(rootPath, entry.snapshotPath ?? entry.path);
|
||||
assert.ok(sourcePath === rootPath || sourcePath.startsWith(`${rootPath}${path.sep}`), `snapshot path escapes root: ${entry.path}`);
|
||||
assert.ok(fs.existsSync(sourcePath), `snapshot file is missing: ${entry.path}`);
|
||||
assert.equal(sha256(sourcePath), entry.sha256, `snapshot hash drift: ${entry.path}`);
|
||||
if (entry.bytes !== undefined) assert.equal(fs.statSync(sourcePath).size, entry.bytes, `snapshot byte drift: ${entry.path}`);
|
||||
const key = `${entry.path}\0${entry.sha256}`;
|
||||
if (files.has(key)) throw new Error(`duplicate snapshot path/SHA pair: ${entry.path}`);
|
||||
files.set(key, { ...entry, sourcePath });
|
||||
}
|
||||
return { rootPath, manifestPath, manifest, files };
|
||||
}
|
||||
|
||||
let report;
|
||||
if (!requestedSnapshot) {
|
||||
report = emptyReport("immutable snapshot was not supplied; no historical source may be inferred from the current worktree");
|
||||
} else {
|
||||
const snapshot = resolveSnapshot(requestedSnapshot);
|
||||
if (!snapshot) {
|
||||
report = emptyReport(`immutable snapshot is unavailable or invalid: ${requestedSnapshot}`);
|
||||
} else {
|
||||
const restored = [];
|
||||
const remaining = [];
|
||||
for (const entry of drift.entries) {
|
||||
const source = snapshot.files.get(`${entry.path}\0${entry.originalSha256}`);
|
||||
if (source) {
|
||||
restored.push({ ...entry, snapshotPath: relative(source.sourcePath), provenanceState: "PROVENANCE_RESTORED" });
|
||||
} else {
|
||||
remaining.push({ ...entry, snapshotPath: source ? relative(source.sourcePath) : null, provenanceState: "BLOCKED_SOURCE_LOST" });
|
||||
}
|
||||
}
|
||||
report = {
|
||||
schemaVersion: 1,
|
||||
operation: "M12_IMMUTABLE_SNAPSHOT_PROVENANCE_INTAKE",
|
||||
historicalEvidencePreserved: true,
|
||||
immutableSourceSnapshotAvailable: true,
|
||||
provenanceState: remaining.length === 0 ? "PROVENANCE_RESTORED" : "BLOCKED_SOURCE_LOST",
|
||||
sourceSnapshot: relative(snapshot.rootPath),
|
||||
sourceSnapshotManifestSha256: sha256(snapshot.manifestPath),
|
||||
snapshotMode: snapshot.manifest.mode,
|
||||
driftEntries: drift.entries.length,
|
||||
restoredEntries: restored.length,
|
||||
remainingEntries: remaining.length,
|
||||
reason: remaining.length === 0 ? "all observed M12 drift entries match the immutable source snapshot" : "snapshot supplied but some historical hashes remain unresolved",
|
||||
entries: [...restored, ...remaining].sort((a, b) => `${a.task}:${a.artifact}:${a.path}`.localeCompare(`${b.task}:${b.artifact}:${b.path}`)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (write) {
|
||||
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
||||
fs.writeFileSync(outputPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
|
||||
} else {
|
||||
assert.ok(fs.existsSync(outputPath), "provenance intake report is missing; run with --write");
|
||||
assert.deepEqual(readJson(outputPath), report, "provenance intake report is stale or source changed");
|
||||
}
|
||||
|
||||
process.stdout.write(`m12-provenance-intake-ok state=${report.provenanceState} drift=${report.driftEntries} restored=${report.restoredEntries} remaining=${report.remainingEntries} snapshot=${report.immutableSourceSnapshotAvailable} write=${write}\n`);
|
||||
Reference in New Issue
Block a user