import assert from "node:assert/strict"; import { createHash } from "node:crypto"; import { readFile } from "node:fs/promises"; import { test } from "node:test"; import { unstable_dev } from "wrangler"; import { parse } from "jsonc-parser"; import { customerBindings } from "./fixtures/config.mjs"; import { loadArtifact, verifyUpgradeIdentity, } from "../control-plane/artifact.ts"; const readJson = async (path) => JSON.parse(await readFile(path, "utf8")); const digest = (bytes) => createHash("sha256").update(bytes).digest("hex"); test("release contains intact Worker, assets and a consistent SQLite lifecycle", async () => { const manifestBytes = await readFile("dist/release/manifest.json"); assert.equal( digest(manifestBytes), (await readFile("dist/release/manifest.sha256", "utf8")).trim(), ); const manifest = JSON.parse(manifestBytes); const config = await readJson("dist/release/deployment.json"); const source = parse(await readFile("wrangler.jsonc", "utf8"), [], { allowTrailingComma: true, }); assert.equal(manifest.schemaVersion, 1); assert.equal(manifest.release, (await readJson("package.json")).version); assert.equal( manifest.lockfileSha256, digest(await readFile("pnpm-lock.yaml")), ); assert.equal(config.no_bundle, true); assert.deepEqual(config.compatibility_flags, [ "nodejs_compat", "global_fetch_strictly_public", ]); assert.equal(config.name, undefined); assert.equal(config.account_id, undefined); assert.equal(config.vars, undefined); assert.equal(config.env, undefined); assert.equal(config.migrations, undefined); assert.deepEqual(config.exports, { PersonalAgent: { type: "durable-object", storage: "sqlite" }, Sandbox: { type: "durable-object", storage: "sqlite" }, }); assert.deepEqual(config.durable_objects, source.durable_objects); assert.deepEqual(config.containers, source.containers); assert.equal(config.containers[0].image, manifest.shell.image); assert.match(manifest.shell.image, /0\.12\.9@sha256:[0-9a-f]{64}$/); assert.equal(config.containers[0].class_name, manifest.shell.className); assert.equal(config.containers[0].max_instances, manifest.shell.maxInstances); assert.equal(config.containers[0].instance_type, manifest.shell.instanceType); assert.equal( config.durable_objects.bindings[0].class_name, manifest.identity.durableObjectClass, ); assert.equal( config.durable_objects.bindings[0].name, manifest.identity.durableObjectBinding, ); assert.deepEqual(config.ai, { binding: "AI" }); assert.equal(config.browser.binding, "BROWSER"); assert.deepEqual(config.worker_loaders, [{ binding: "LOADER" }]); assert.ok( manifest.files.some( ({ path }) => path === config.main.replace(/^\.\//, ""), ), ); assert.ok( manifest.files.some( ({ path }) => path.startsWith("assets/") && path.endsWith(".js"), ), ); for (const file of manifest.files) { assert.match(file.path, /^(worker\/|assets\/|deployment\.json$)/); assert.ok(!file.path.split("/").includes("..")); const bytes = await readFile(`dist/release/${file.path}`); assert.equal(bytes.length, file.size, file.path); assert.equal(digest(bytes), file.sha256, file.path); assert.ok( !bytes.includes(customerBindings.FLAREBOT_SESSION_SECRET), file.path, ); if (file.path.startsWith("assets/")) { assert.ok( !bytes.includes("FLAREBOT_SESSION_SECRET"), "server configuration must not enter browser assets", ); } if (file.path.startsWith("worker/")) { assert.ok( !bytes.includes("__golden__") && !bytes.includes("TEST_RUNNER_PORT"), "golden-path fixture routes and boundaries must not enter the release", ); assert.ok( !bytes.includes("fixtureEcho"), "test tools must not enter the release", ); assert.ok( !bytes.includes("MockLanguageModel"), "test model must not enter the release", ); assert.ok( !bytes.includes("react.production"), "React runtime must not enter the Worker", ); assert.ok( !bytes.includes("FLAREBOT_OAUTH_CLIENT_SECRET"), "control-plane secret loader must not enter customer Worker", ); } } }); test("public fetch release retains legacy artifacts and requires an explicit forward edge", async () => { const source = parse(await readFile("wrangler.jsonc", "utf8")); const publisher = parse( await readFile("wrangler.control-plane.jsonc", "utf8"), ); const contract = await readJson("deployment/manifest.json"); assert.deepEqual(source.compatibility_flags, [ "nodejs_compat", "global_fetch_strictly_public", ]); assert.deepEqual(publisher.compatibility_flags, source.compatibility_flags); assert.equal((await readJson("package.json")).version, "0.1.0-dev.13"); assert.ok( contract.compatibility.fromArtifacts.includes( "2306652b8f72ad772243e3a24ba1164a59e966539082c9eccdac4346cd74ec5d", ), ); assert.ok( contract.compatibility.fromArtifacts.includes( "cb19b72d84999e8e0a71f165c94715bb2a62a9254ce064ee0b291d123253e020", ), ); assert.ok( contract.compatibility.fromArtifacts.includes( "f978451c3c8e3ef1a62d0c558059426f78a09e4b608b5e1df25d9c6c7b8b2a4f", ), ); assert.ok( contract.compatibility.fromArtifacts.includes( "7b52b11b9b2ddb492309607664ca229433dfb28968391634b32cdced1f87b65c", ), ); assert.ok( contract.compatibility.fromArtifacts.includes( "d4e44b5430b871ced18c624901e09ea19d0ee67215aeed9f8c1beed25d860bc2", ), ); assert.ok( contract.compatibility.fromArtifacts.includes( "ecf047e0c3cec1fc92429c7589801c7a7d5660d9ff65e9884667c29fda2e0281", ), ); assert.ok( contract.compatibility.fromArtifacts.includes( "4c0e2ed811f0f254890af50c92c73bd6ea9e224ae77cbca066e285f29ddf92ca", ), ); assert.ok( contract.compatibility.fromArtifacts.includes( "0f54bfd186c7577b8cfb69f88ff9f2e8540abd344a09d198c97a7619c76da208", ), ); assert.ok( contract.compatibility.fromArtifacts.includes( "ca98843d197f6a4fbaf8e1039beede3db706336ca4610bd20e1f8a8c6feb6c73", ), ); assert.ok( contract.compatibility.fromArtifacts.includes( "b48bc5126a2b2a7ba34f94c73ed0b524d52fb1d11ee62bf5a995424028ac3366", ), ); assert.ok( contract.compatibility.fromArtifacts.includes( "362dcc03f0a80013b96a4972f9a7192469738716d92ee90f12041865b1520068", ), ); async function entry(flags, version, fromArtifacts = []) { const deployment = await readJson("dist/release/deployment.json"); deployment.compatibility_flags = flags; const bytes = Object.fromEntries( Object.entries({ "deployment.json": JSON.stringify(deployment), "worker/index.js": "export default {};", "assets/index.html": "