Public: anyone can read this; the crew can change it.
A test fails when the forge gains a runtime dependency or bun.lock is out of step with package.json #3032
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/3026-a-test-fails-when-the-forge-gains-a-runt → main 1 commit fork
2 files
changed +37
−2
docs/THREATS.md +2 −2
| @@ -52,8 +52,8 @@ Wants: to run its code on the forge or in an app through something the forge | ||
| 52 | 52 | trusts: a package, a model provider, a hosting provider, an origin it syncs from. |
| 53 | 53 | |
| 54 | 54 | - The forge has no runtime dependencies, so there is no package to poison in the |
| 55 | forge itself. Nothing checks that this stays true. | |
| 56 | Test: none yet | |
| 55 | forge itself. | |
| 56 | Test: `test/deps.test.ts` | |
| 57 | 57 | - An app's code runs in a cell: read-only machine, empty data directory and |
| 58 | 58 | home, own pid and network namespaces, memory, CPU and disk watched. A |
| 59 | 59 | dependency an app pulls in gets no more than the app does. |
test/deps.test.ts added +35
| @@ -0,0 +1,35 @@ | ||
| 1 | import { expect, test } from "bun:test"; | |
| 2 | import { readFileSync } from "node:fs"; | |
| 3 | import { join } from "node:path"; | |
| 4 | ||
| 5 | const root = join(import.meta.dir, ".."); | |
| 6 | type Deps = Record<string, string>; | |
| 7 | type Manifest = Partial<Record<(typeof kinds)[number], Deps>>; | |
| 8 | const kinds = ["dependencies", "optionalDependencies", "peerDependencies", "devDependencies"] as const; | |
| 9 | ||
| 10 | const pkg: Manifest = JSON.parse(readFileSync(join(root, "package.json"), "utf8")); | |
| 11 | // bun.lock is JSONC: plain JSON plus trailing commas. | |
| 12 | const lock = JSON.parse( | |
| 13 | readFileSync(join(root, "bun.lock"), "utf8").replace(/,(\s*[}\]])/g, "$1"), | |
| 14 | ) as { workspaces: Record<string, Manifest> }; | |
| 15 | const locked = lock.workspaces[""] ?? {}; | |
| 16 | ||
| 17 | test("the forge has no runtime dependencies", () => { | |
| 18 | for (const kind of ["dependencies", "optionalDependencies", "peerDependencies"] as const) { | |
| 19 | const names = Object.keys(pkg[kind] ?? {}); | |
| 20 | expect(names.length === 0 ? "" : `${kind}: ${names.join(", ")}`).toBe(""); | |
| 21 | } | |
| 22 | }); | |
| 23 | ||
| 24 | test("bun.lock names the same packages as package.json", () => { | |
| 25 | for (const kind of kinds) { | |
| 26 | const want = pkg[kind] ?? {}; | |
| 27 | const have = locked[kind] ?? {}; | |
| 28 | for (const name of Object.keys(want)) | |
| 29 | expect(name in have ? "" : `${kind}: ${name} is in package.json but not bun.lock`).toBe(""); | |
| 30 | for (const name of Object.keys(have)) | |
| 31 | expect(name in want ? "" : `${kind}: ${name} is in bun.lock but not package.json`).toBe(""); | |
| 32 | for (const [name, range] of Object.entries(want)) | |
| 33 | expect(have[name]).toBe(range); | |
| 34 | } | |
| 35 | }); |
new above
offline