fix: harden Base manifest recovery

This commit is contained in:
golem
2026-08-21 16:16:12 -06:00
parent 90b0a11b8a
commit 6dee960d15
7 changed files with 119 additions and 32 deletions
+58 -6
View File
@@ -106,7 +106,8 @@ import { pathToFileURL } from "node:url";
const repositoryRoot = process.argv[2];
const { archiveManifest, selectManifest } = await import(pathToFileURL(join(repositoryRoot, "tools/select-manifest.mjs")));
const { publishManifest } = await import(pathToFileURL(join(repositoryRoot, "tools/publish-web-manifest.mjs")));
const { validateManifest } = await import(pathToFileURL(join(repositoryRoot, "tools/finalize-manifest.mjs")));
const { publishManifest, validatePublicManifest } = await import(pathToFileURL(join(repositoryRoot, "tools/publish-web-manifest.mjs")));
const root = await mkdtemp(join(tmpdir(), "uups-base-config-"));
const deployments = join(root, "deployments");
const webManifest = join(root, "web/public/deployment.json");
@@ -157,14 +158,29 @@ try {
assert.equal(published.rpcUrl, "https://public.invalid/rpc");
assert.equal(published.explorerBaseUrl, "https://sepolia.basescan.org");
assert.equal((await readFile(webManifest, "utf8")).includes("terminal.invalid"), false);
for (const invalid of [
{ ...base, rpcUrl: "http://public.invalid/rpc" },
{ ...base, explorerBaseUrl: "https://example.invalid" },
]) {
const without = (field) => {
const manifest = { ...base };
delete manifest[field];
return manifest;
};
const invalidCases = [
["missing rpcUrl", without("rpcUrl"), /rpcUrl/],
["missing explorerBaseUrl", without("explorerBaseUrl"), /explorerBaseUrl/],
["wrong actor count", { ...base, actors: [base.actors[0]] }, /exactly Presenter and Recipient|actor configuration/],
["wrong actor labels", { ...base, actors: [{ ...base.actors[0], label: "Owner" }, base.actors[1]] }, /Presenter and Recipient|actor configuration/],
["owner is not Presenter", { ...base, owner: recipient }, /owner.*Presenter|first actor/],
["HTTP public RPC", { ...base, rpcUrl: "http://public.invalid/rpc" }, /HTTPS/],
["credential-bearing public RPC", { ...base, rpcUrl: "https://user@public.invalid/rpc" }, /credentials|prohibited secret/],
["wrong BaseScan root", { ...base, explorerBaseUrl: "https://example.invalid" }, /BaseScan/],
];
for (const [label, invalid, rejection] of invalidCases) {
assert.throws(() => validateManifest(invalid), rejection, `confirmation accepted ${label}`);
assert.throws(() => validatePublicManifest(invalid), rejection, `publication validation accepted ${label}`);
await writeFile(join(deployments, "active.json"), `${JSON.stringify(invalid)}\n`);
await assert.rejects(
() => publishManifest({ activePath: join(deployments, "active.json"), outputPath: webManifest }),
/HTTPS|BaseScan/,
rejection,
`publication accepted ${label}`,
);
}
await writeFile(join(deployments, "active.json"), activeBefore);
@@ -179,6 +195,42 @@ try {
await assert.rejects(() => access(join(deployments, "base-sepolia.json")));
assert.deepEqual(await readFile(join(deployments, "active.json")), activeBefore);
assert.deepEqual(await readFile(join(deployments, "anvil.json")), anvilBefore);
const canonicalPath = join(deployments, "base-sepolia.json");
const canonicalBytes = Buffer.from(`${JSON.stringify(base)}\n`);
const existingBytes = Buffer.from("existing archive bytes\n");
const collisionDate = new Date("2026-08-21T12:35:56.789Z");
const collisionPath = join(deployments, "base-sepolia.20260821T123556789Z.json");
await writeFile(canonicalPath, canonicalBytes);
await writeFile(collisionPath, existingBytes);
await assert.rejects(
() => archiveManifest({ root, network: "baseSepolia", now: collisionDate }),
/existing Base Sepolia archive/,
);
assert.deepEqual(await readFile(canonicalPath), canonicalBytes);
assert.deepEqual(await readFile(collisionPath), existingBytes);
const boundaryDate = new Date("2026-08-21T12:36:56.789Z");
const boundaryPath = join(deployments, "base-sepolia.20260821T123656789Z.json");
const boundaryBytes = Buffer.from("archive created by racing process\n");
await assert.rejects(
() => archiveManifest({
root,
network: "baseSepolia",
now: boundaryDate,
io: {
link: async (_source, target) => {
await writeFile(target, boundaryBytes);
const error = new Error("collision at link boundary");
error.code = "EEXIST";
throw error;
},
},
}),
/existing Base Sepolia archive/,
);
assert.deepEqual(await readFile(canonicalPath), canonicalBytes);
assert.deepEqual(await readFile(boundaryPath), boundaryBytes);
await assert.rejects(() => archiveManifest({ root, network: "anvil" }), /baseSepolia/);
} finally {
await rm(root, { recursive: true, force: true });