fix: harden upgrade publication and refresh
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
||||
import { mkdtemp, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { basename, dirname, join } from "node:path";
|
||||
import { extractAbi, renderContractsModule, syncArtifacts } from "./sync-web-artifacts.mjs";
|
||||
import { publishManifest } from "./publish-web-manifest.mjs";
|
||||
|
||||
@@ -89,9 +89,44 @@ await withFixture(async (root) => {
|
||||
const outputPath = join(root, "deployment.json");
|
||||
await writeFile(activePath, JSON.stringify(manifest));
|
||||
|
||||
// Catches a publisher that copies pending, secret-bearing, or malformed live state into the browser bundle.
|
||||
await publishManifest({ activePath, outputPath });
|
||||
// Catches a publisher that writes the browser destination directly instead of replacing a complete same-directory file.
|
||||
const operations = [];
|
||||
await publishManifest({
|
||||
activePath,
|
||||
outputPath,
|
||||
io: {
|
||||
writeFile: async (...args) => { operations.push(["write", args[0]]); await writeFile(...args); },
|
||||
rename: async (...args) => { operations.push(["rename", ...args]); await rename(...args); },
|
||||
rm,
|
||||
},
|
||||
});
|
||||
assert.deepEqual(JSON.parse(await readFile(outputPath, "utf8")), manifest);
|
||||
assert.equal(operations.length, 2);
|
||||
assert.equal(operations[0][0], "write");
|
||||
assert.equal(dirname(operations[0][1]), dirname(outputPath));
|
||||
assert.notEqual(operations[0][1], outputPath);
|
||||
assert.deepEqual(operations[1], ["rename", operations[0][1], outputPath]);
|
||||
|
||||
// Catches a failed replacement truncating the published manifest or leaking its staging file.
|
||||
const preserved = Buffer.from("preserved browser manifest\n");
|
||||
await writeFile(outputPath, preserved);
|
||||
let failedStage;
|
||||
await assert.rejects(
|
||||
() => publishManifest({
|
||||
activePath,
|
||||
outputPath,
|
||||
io: {
|
||||
writeFile: async (...args) => { failedStage = args[0]; await writeFile(...args); },
|
||||
rename: async () => { throw new Error("injected browser replacement failure"); },
|
||||
rm,
|
||||
},
|
||||
}),
|
||||
/injected browser replacement failure/,
|
||||
);
|
||||
assert.deepEqual(await readFile(outputPath), preserved);
|
||||
assert.equal((await readdir(root)).includes(basename(failedStage)), false);
|
||||
|
||||
// Catches a publisher that copies pending, secret-bearing, or malformed live state into the browser bundle.
|
||||
for (const invalid of [
|
||||
{ ...manifest, deploymentBlock: 0 },
|
||||
{ ...manifest, rpcUrl: "https://token@example.test" },
|
||||
|
||||
Reference in New Issue
Block a user