import { test } from "node:test"; import assert from "node:assert/strict"; import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { spawnSync } from "node:child_process"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { installPlan, installStep, NPM_REPOSITORIES, outcomeOf, readStatus, REPOSITORIES, script } from "../tools/runs.ts"; // Defends novox/hq issue 624: lab_run ran `npm ci` at the root of every checkout it installs, and // mesh-tools keeps its package in node-tools/ with no lock file at its root, so every run failed at its // setup, in 9 seconds, before anything was built. function aCheckout(files: Record): string { const root = mkdtempSync(join(tmpdir(), "lab-checkout-")); for (const [path, content] of Object.entries(files)) { mkdirSync(join(root, path, ".."), { recursive: true }); writeFileSync(join(root, path), content); } return root; } test("a checkout with a lock file at its root is installed there", () => { const root = aCheckout({ "package.json": "{}", "package-lock.json": "{}", "node-tools/package.json": "{}" }); assert.deepEqual(installPlan(root), { install: [root], unlocked: [] }); rmSync(root, { recursive: true, force: true }); }); test("a checkout whose package lives one directory down is installed there, as mesh-tools' node-tools", () => { const root = aCheckout({ "node-tools/package.json": "{}", "node-tools/package-lock.json": "{}", "Dockerfile": "" }); assert.deepEqual(installPlan(root), { install: [join(root, "node-tools")], unlocked: [] }); rmSync(root, { recursive: true, force: true }); }); test("a package.json with no lock file is named, never installed", () => { const root = aCheckout({ "package.json": "{}" }); assert.deepEqual(installPlan(root), { install: [], unlocked: [root] }); rmSync(root, { recursive: true, force: true }); }); // The shell a run executes follows the same rule: npm is asked where installPlan says, and a checkout // with nothing installable fails the run loudly, naming it. function runStep(root: string, build: boolean): { ok: boolean; said: string; asked: string[] } { const bin = mkdtempSync(join(tmpdir(), "lab-npm-")); const record = join(bin, "asked"); writeFileSync(join(bin, "npm"), `#!/bin/sh\necho "$(pwd) $*" >> ${JSON.stringify(record)}\n`); chmodSync(join(bin, "npm"), 0o755); const ran = spawnSync("bash", ["-c", `set -euo pipefail\n${installStep(root, build)}`], { encoding: "utf8", env: { ...process.env, PATH: `${bin}:${process.env.PATH}` }, }); let asked: string[] = []; try { asked = readFileSync(record, "utf8").trim().split("\n").filter(Boolean); } catch { /* nothing asked */ } rmSync(bin, { recursive: true, force: true }); return { ok: ran.status === 0, said: `${ran.stdout}${ran.stderr}`, asked }; } test("a run installs and builds mesh-tools in node-tools, where its lock file is", () => { const root = aCheckout({ "node-tools/package.json": "{}", "node-tools/package-lock.json": "{}" }); const r = runStep(root, true); assert.ok(r.ok, r.said); assert.deepEqual(r.asked, [ `${join(root, "node-tools")} ci --no-audit --no-fund --loglevel=error`, `${join(root, "node-tools")} run build --if-present`, ]); rmSync(root, { recursive: true, force: true }); }); test("a run installs a checkout with its lock file at the root there, and builds only when asked", () => { const root = aCheckout({ "package.json": "{}", "package-lock.json": "{}" }); const r = runStep(root, false); assert.ok(r.ok, r.said); assert.deepEqual(r.asked, [`${root} ci --no-audit --no-fund --loglevel=error`]); rmSync(root, { recursive: true, force: true }); }); test("a run fails at its setup, naming the checkout, when nothing of it can be installed", () => { const layouts: Record[] = [{ "package.json": "{}" }, { "Dockerfile": "" }, { "sub/package.json": "{}" }]; for (const files of layouts) { const root = aCheckout(files); const r = runStep(root, false); assert.equal(r.ok, false, `installed ${JSON.stringify(files)}`); assert.match(r.said, /issue 624/); assert.deepEqual(r.asked, []); rmSync(root, { recursive: true, force: true }); } }); // A run checks out mesh-tools-go too (novox/hq issue 616): genesis builds the Go toolchain from the // repository beside mesh-tools, and a bed that raises genesis serves it. And it tells the beds where the // checkouts are. test("a run checks out mesh-tools-go and says where its checkouts are", () => { assert.ok(REPOSITORIES.includes("mesh-tools-go")); const s = script("/work", "run-x", "http://forge", ["test/integration/genesis-keeps-its-bus.test.ts"], {}); assert.match(s, /novox\/mesh-tools-go\.git' '\/work\/run-x\/mesh-tools-go'/); assert.match(s, /export MESH_LAB_REPOS='\/work\/run-x'/); assert.doesNotMatch(s, /cd '\/work\/run-x'\/\$repo && npm ci/); for (const repo of NPM_REPOSITORIES) assert.ok(s.includes(`'/work/run-x/${repo}'/package-lock.json`), repo); }); // Defends novox/hq issue 624, its second half: mesh-tools-go is private, and the lab cloned over HTTP with // no credential ("could not read Username"). A run clones with the forge credential the mesh binds and // seals to the lab, through git's credential store, and the secret is in no script, URL or argument. import { credentialArgs, credentialPath, forgeCredential } from "../tools/runs.ts"; function aBinding(as: string, secret: string): { binding: string; secret: string } { const dir = mkdtempSync(join(tmpdir(), "lab-binding-")); writeFileSync(join(dir, "package-registry.json"), JSON.stringify({ provision: "npm-package-registry", at: "10.42.0.1", as, serves: { scheme: "http", port: 3000 } })); writeFileSync(join(dir, "package-registry.secret"), `${secret}\n`); return { binding: join(dir, "package-registry.json"), secret: join(dir, "package-registry.secret") }; } test("the forge credential is the bound account and its sealed secret, for the forge's own origin", () => { const b = aBinding("lab-shanks", "s3cret-of-forty-characters"); assert.equal(forgeCredential("http://novox.internal:20000", b.binding, b.secret), "http://lab-shanks:s3cret-of-forty-characters@novox.internal:20000"); assert.equal(forgeCredential("http://novox.internal:20000/", b.binding, ""), undefined); assert.equal(forgeCredential("", b.binding, b.secret), undefined); assert.equal(forgeCredential("http://novox.internal:20000", "/nowhere", b.secret), undefined); }); test("a run clones through git's credential store, and its script carries no secret", () => { const b = aBinding("lab-shanks", "s3cret-of-forty-characters"); const credential = forgeCredential("http://novox.internal:20000", b.binding, b.secret); const path = credentialPath("/work", "run-x"); const s = script("/work", "run-x", "http://novox.internal:20000", ["t.test.ts"], {}, path); assert.ok(credential); assert.doesNotMatch(s, /s3cret/); assert.match(s, /git -c credential\.helper= -c 'credential\.helper=store --file=\/work\/\.run-x\.git-credentials' clone --quiet --depth 50 --branch 'main' 'http:\/\/novox\.internal:20000\/novox\/mesh-tools-go\.git'/); assert.match(s, /export GIT_TERMINAL_PROMPT=0/); assert.equal(path.startsWith("/work/run-x/"), false, "the credential is kept out of the run's own directory"); assert.equal(credentialArgs(undefined), ""); }); // Held against git itself: the credential in the store is offered to the forge's origin when it asks, and // a clone without it fails at once rather than prompting. test("git presents the stored credential to the forge, and only when one is given", () => { const dir = mkdtempSync(join(tmpdir(), "lab-git-")); const store = join(dir, "git-credentials"); writeFileSync(store, "http://lab-shanks:pw@forge.invalid:20000\n", { mode: 0o600 }); const fill = spawnSync("sh", ["-c", `printf 'protocol=http\\nhost=forge.invalid:20000\\n\\n' | git ${credentialArgs(store)}credential fill`], { encoding: "utf8", env: { ...process.env, GIT_TERMINAL_PROMPT: "0" } }); assert.match(fill.stdout, /username=lab-shanks/); assert.match(fill.stdout, /password=pw/); const other = spawnSync("sh", ["-c", `printf 'protocol=http\\nhost=elsewhere.invalid\\n\\n' | git ${credentialArgs(store)}credential fill`], { encoding: "utf8", env: { ...process.env, GIT_TERMINAL_PROMPT: "0" } }); assert.doesNotMatch(other.stdout, /password=pw/); rmSync(dir, { recursive: true, force: true }); }); // Review 196 on mesh-catalog #272: the credential file outlived a stop, because SIGTERM to the run's // process group killed the wrapper before its cleanup. It is now removed right after the clones, on // every way the script ends, and at the next run's start and in lab_check for what a crash left. import { cleanCredentials, credentialGuard } from "../tools/runs.ts"; test("a stopped script removes the credential, whatever ends it", () => { for (const signal of ["SIGTERM", "SIGINT", "SIGHUP"] as const) { const dir = mkdtempSync(join(tmpdir(), "lab-guard-")); const file = join(dir, ".run-x.git-credentials"); writeFileSync(file, "http://u:p@h\n", { mode: 0o600 }); const ran = spawnSync("bash", ["-c", `${credentialGuard(file)}\nkill -${signal.slice(3)} $$\nsleep 5`], { encoding: "utf8", timeout: 10_000 }); assert.notEqual(ran.status, 0, `${signal}: the script was not stopped`); assert.equal(existsSync(file), false, `${signal} left the credential on disk`); rmSync(dir, { recursive: true, force: true }); } }); test("the script removes the credential as soon as its clones are done", () => { const s = script("/work", "run-x", "http://forge", ["t.test.ts"], {}, "/work/.run-x.git-credentials"); const lastClone = s.lastIndexOf("clone --quiet"); const removed = s.indexOf("rm -f '/work/.run-x.git-credentials'", lastClone); const building = s.indexOf("npm ci"); assert.ok(lastClone > 0 && removed > lastClone && removed < building, "not removed between the clones and the build"); assert.match(s, /trap 'rm -f '\\''\/work\/\.run-x\.git-credentials'\\''' EXIT/); }); test("credentials a crashed run left are removed, but not the running one's", () => { const work = mkdtempSync(join(tmpdir(), "lab-work-")); for (const n of [".run-a.git-credentials", ".run-b.git-credentials", "run-a", "other"]) writeFileSync(join(work, n), "x"); const removed = cleanCredentials(work, join(work, ".run-b.git-credentials")); assert.deepEqual(removed, [join(work, ".run-a.git-credentials")]); assert.ok(existsSync(join(work, ".run-b.git-credentials")) && existsSync(join(work, "run-a")) && existsSync(join(work, "other"))); rmSync(work, { recursive: true, force: true }); }); // The lab asks the forge for read only (review 196): its credential is for clones of branches nobody has // reviewed yet, and must not be able to publish the mesh's packages. test("the lab asks the package registry for read only", () => { const m = JSON.parse(readFileSync(join(import.meta.dirname, "..", "module.json"), "utf8")) as { requires: unknown[]; contributes?: Record>; }; assert.ok(m.requires.includes("npm-package-registry")); assert.equal(m.contributes?.["npm-package-registry"]?.access, "read"); }); // lab_check failed for ever on "destination path '/check' already exists": it cloned into one fixed // path and ignored whether removing the last one worked (novox/hq issue 624). Each check now works in a // fresh directory, and what earlier checks left is cleared or named. import { checkDir, clearChecks } from "../tools/runs.ts"; test("each check gets a fresh directory of its own", () => { const work = mkdtempSync(join(tmpdir(), "lab-work-")); const a = checkDir(work); const b = checkDir(work); assert.notEqual(a, b); assert.ok(a.startsWith(join(work, "check-")) && existsSync(a) && existsSync(b)); rmSync(work, { recursive: true, force: true }); }); // As root nothing is locked against removal, so the unremovable tree cannot be made: skipped there, before // it makes anything (the merge check runs as root). test("what earlier checks left is cleared, and what cannot be is named rather than tripped over", { skip: process.getuid?.() === 0 ? "running as root, which no directory mode stops from removing anything" : false, }, () => { const work = mkdtempSync(join(tmpdir(), "lab-work-")); for (const d of ["check/src", "check-setup/mesh-lab", "check-abc", "run-x", "keep"]) mkdirSync(join(work, d), { recursive: true }); // A tree this account cannot empty: a directory it may not write, with something in it. mkdirSync(join(work, "check-stuck", "locked"), { recursive: true }); writeFileSync(join(work, "check-stuck", "locked", "file"), "x"); chmodSync(join(work, "check-stuck", "locked"), 0o555); const said = clearChecks(work); chmodSync(join(work, "check-stuck", "locked"), 0o755); for (const gone of ["check", "check-setup", "check-abc"]) assert.equal(existsSync(join(work, gone)), false, gone); assert.ok(existsSync(join(work, "run-x")) && existsSync(join(work, "keep"))); assert.equal(said.length, 1); assert.match(said[0] as string, /check-stuck, left by an earlier check, could not be removed/); rmSync(work, { recursive: true, force: true }); }); // And as root too: what earlier checks left is cleared. test("leftover checks are cleared, whoever runs the check", () => { const work = mkdtempSync(join(tmpdir(), "lab-work-")); for (const d of ["check/src", "check-setup/mesh-lab", "check-abc", "run-x"]) mkdirSync(join(work, d), { recursive: true }); assert.deepEqual(clearChecks(work), []); for (const gone of ["check", "check-setup", "check-abc"]) assert.equal(existsSync(join(work, gone)), false, gone); assert.ok(existsSync(join(work, "run-x"))); rmSync(work, { recursive: true, force: true }); }); // The lab's tools read the bound credential, so the runtime is given that file by the tools bundle's env // (ADR 0192), as gitea and umami are given theirs: the runtime's account may then read exactly it, and no // other credential changes hands (issue 624). test("the lab's tools bundle names its bound credential and binding in its env", () => { const m = JSON.parse(readFileSync(join(import.meta.dirname, "..", "module.json"), "utf8")) as { secrets: Record; binds: Record; build: { artifacts: { name: string; env?: Record }[] }; }; const env = m.build.artifacts.find((a) => a.name === "code")?.env ?? {}; assert.equal(env.MESH_LAB_FORGE_SECRET, m.secrets["npm-package-registry"]); assert.equal(env.MESH_LAB_FORGE_BINDING, m.binds["npm-package-registry"]); }); // The next setup failure of novox/hq issue 624 (run-2026-10-13T13-15-26-634Z on shanks): npm 12 refused // mesh-tools' locked @novox/mesh-sdk with EALLOWREMOTE. The lab named the registry by its forge setting's // address (http://novox.internal:20000/…), the lock file holds the address the forge writes every tarball // URL at (https://git.novox.be/…), and npm 12 installs a locked tarball only from its configured registry. // A run names the registry by the address the registry names itself by. import { npmRegistry } from "../tools/runs.ts"; function aRegistry(answer: () => Response | Promise): { get: typeof fetch; asked: string[] } { const asked: string[] = []; const get = (async (url: string | URL | Request) => { asked.push(String(url)); return answer(); }) as typeof fetch; return { get, asked }; } const packument = (tarball: string) => new Response(JSON.stringify({ name: "@novox/mesh-sdk", "dist-tags": { latest: "0.1.14" }, versions: { "0.1.1": { dist: { tarball: "http://old.example/api/packages/novox/npm/x.tgz" } }, "0.1.14": { dist: { tarball } } }, }), { status: 200, headers: { "content-type": "application/json" } }); test("a run names the package registry by the address the registry gives its tarballs", async () => { const r = aRegistry(() => packument("https://forge.example.org/api/packages/novox/npm/%40novox%2Fmesh-sdk/-/0.1.14/mesh-sdk-0.1.14.tgz")); const got = await npmRegistry("http://forge.example.org:3000/", r.get, "https://forge.example.org/api/packages/novox/npm/"); assert.deepEqual(got, { registry: "https://forge.example.org/api/packages/novox/npm/" }); assert.deepEqual(r.asked, ["http://forge.example.org:3000/api/packages/novox/npm/@novox%2fmesh-sdk"]); // The forge's own scheme is taken too, with its port. const plain = await npmRegistry("http://forge.example.org:3000", aRegistry(() => packument("http://forge.example.org:3000/api/packages/novox/npm/%40novox%2Fmesh-sdk/-/0.1.14/mesh-sdk-0.1.14.tgz")).get); assert.deepEqual(plain, { registry: "http://forge.example.org:3000/api/packages/novox/npm/" }); }); // What the registry answers may come over plain HTTP, so it never decides where packages come from: only // the forge's public root or its own address, scheme, host and port, under the npm path, with nothing after // it (review of mesh-catalog #275, ADR 0346). test("a registry that does not give an address the lab takes leaves the forge's, and the reason is said", async () => { const sdk = "/api/packages/novox/npm/%40novox%2Fmesh-sdk/-/0.1.14/mesh-sdk-0.1.14.tgz"; for (const [answer, why] of [ [() => new Response("not found", { status: 404 }), /it answered 404/], [() => new Response("{}", { status: 200 }), /no tarball/], [() => { throw new Error("connect ECONNREFUSED"); }, /ECONNREFUSED/], [() => packument(`https://forge.example.org/elsewhere/mesh-sdk-0.1.14.tgz`), /not under \/api\/packages\/novox\/npm\//], [() => packument(`https://attacker.example.net${sdk}`), /at https:\/\/attacker\.example\.net, which is neither the forge's public root nor its own address/], [() => packument(`https://attacker.example.net/x?u=https://novox.internal${sdk}`), /query or a fragment/], [() => packument(`https://novox.internal${sdk}?x=1`), /query or a fragment/], [() => packument(`https://novox.internal${sdk}#frag`), /query or a fragment/], [() => packument(`https://attacker.example.net/#https://novox.internal${sdk}`), /query or a fragment/], [() => packument(`ftp://novox.internal${sdk}`), /at ftp:\/\/novox\.internal, which is neither/], [() => packument(`file:///api/packages/novox/npm/x.tgz`), /which is neither/], [() => packument(`https://novox.internal/api/packages/novox/npm/\nregistry=https://attacker.example.net/\nallow-remote=all`), /whitespace or a control character/], [() => packument(`https://user:pw@novox.internal${sdk}`), /user or password/], ] as [() => Response, RegExp][]) { const got = await npmRegistry("http://novox.internal:20000", aRegistry(answer).get); assert.equal(got.registry, "http://novox.internal:20000/api/packages/novox/npm/", String(why)); assert.match(got.problem ?? "", /did not give an address the lab takes/); assert.match(got.problem ?? "", why); } }); test("a run's npm configuration names the registry it was given, and the forge's own address only without one", () => { const given = script("/work", "run-x", "http://novox.internal:20000", ["t.test.ts"], {}, undefined, "https://forge.example.org/api/packages/novox/npm/"); assert.match(given, / '@novox:registry=https:\/\/forge\.example\.org\/api\/packages\/novox\/npm\/' > '\/work\/run-x\/\.npmrc'\n/); assert.doesNotMatch(given, /@novox:registry=http:\/\/novox\.internal/); const none = script("/work", "run-x", "http://novox.internal:20000", ["t.test.ts"], {}); assert.match(none, /'@novox:registry=http:\/\/novox\.internal:20000\/api\/packages\/novox\/npm\/'/); }); // The public root the forge serves in the lab's binding (novox/hq ADR 0346) is the one other origin a // tarball may come from, by scheme, host and port: the review of #275 found the port ignored. import { publicRootOf } from "../tools/runs.ts"; test("a tarball is taken at the forge's public root, and at no other port or scheme of its host", async () => { const sdk = "/api/packages/novox/npm/%40novox%2Fmesh-sdk/-/0.1.14/mesh-sdk-0.1.14.tgz"; const root = "https://git.example.org/api/packages/novox/npm/"; const at = (tarball: string, publicRoot?: string) => npmRegistry("http://novox.internal:20000", aRegistry(() => packument(tarball)).get, publicRoot); assert.deepEqual(await at(`https://git.example.org${sdk}`, root), { registry: root }); for (const tarball of [`https://git.example.org:8443${sdk}`, `http://git.example.org${sdk}`, `https://example.org${sdk}`]) { const got = await at(tarball, root); assert.equal(got.registry, "http://novox.internal:20000/api/packages/novox/npm/", tarball); assert.match(got.problem ?? "", /neither the forge's public root nor its own address/, tarball); } // Without a public root, the forge's public name is not trusted on its own word. assert.match((await at(`https://git.example.org${sdk}`)).problem ?? "", /neither/); // And the forge's own address only at its own port. assert.match((await at(`http://novox.internal${sdk}`, root)).problem ?? "", /neither/); }); test("the public root is read from the binding, and only an https root at the npm path is taken", () => { const dir = mkdtempSync(join(tmpdir(), "lab-root-")); const binding = (root: unknown) => { const f = join(dir, `b-${Math.random()}.json`); writeFileSync(f, JSON.stringify({ provision: "npm-package-registry", at: "home", serves: { scheme: "http", port: 3000, "npm-path": "/api/packages/novox/npm/", ...(root === undefined ? {} : { "public-root": root }) } })); return f; }; assert.deepEqual(publicRootOf(binding("https://git.example.org/api/packages/novox/npm/")), { root: "https://git.example.org/api/packages/novox/npm/" }); assert.deepEqual(publicRootOf(binding("https://git.example.org:8443/api/packages/novox/npm/")), { root: "https://git.example.org:8443/api/packages/novox/npm/" }); for (const [root, why] of [ [undefined, /serves no public-root/], ["http://git.example.org/api/packages/novox/npm/", /is not https:\/\//], ["https://git.example.org/elsewhere/", /is not https:\/\//], ["https://git.example.org/api/packages/novox/npm/?x=1", /is not https:\/\//], ["https://u:p@git.example.org/api/packages/novox/npm/", /is not https:\/\//], ["https://git.example.org/api/packages/novox/npm/\nallow-remote=all", /whitespace or a control character/], ["https://${bound:route:name-web}/api/packages/novox/npm/", /not a URL|is not https/], ] as [unknown, RegExp][]) { const got = publicRootOf(binding(root)); assert.equal(got.root, undefined, String(root)); assert.match(got.problem ?? "", why, String(root)); } assert.match(publicRootOf(join(dir, "none.json")).problem ?? "", /could not be read/); assert.match(publicRootOf(undefined).problem ?? "", /no npm-package-registry binding/); rmSync(dir, { recursive: true, force: true }); }); // A forge setting that is not http(s) is never a trusted origin (review of #280): a `file:` tarball's origin // is "null", as is a `file:` forge's, and the two must not match. test("a forge setting that is not http(s) trusts no origin of its own", async () => { const got = await npmRegistry("file:///srv/forge", aRegistry(() => packument("file:///api/packages/novox/npm/x.tgz")).get); assert.match(got.problem ?? "", /neither the forge's public root nor its own address/); const root = "https://git.example.org/api/packages/novox/npm/"; const viaRoot = await npmRegistry("ftp://novox.internal", aRegistry(() => packument("ftp://novox.internal/api/packages/novox/npm/x.tgz")).get, root); assert.match(viaRoot.problem ?? "", /neither/); }); // Defends novox/hq issue 693: a run whose only test skipped as NOT REACHED read "0 passed, 0 failed", exit 0, // and lab_status said passed. The log's tail, as run-2026-10-14T00-21-44-014Z on shanks wrote it. const oldLog = [ "STOPPED at step 16 of 24, base: \t\t\t\tMake sure you have all the referenced content and try again.", "\ufe63 genesis adopts its bus as the nats module in place: one bus, its streams kept, the node connected (588152.016874ms) # ADR 0333 §5 NOT REACHED: the first run stopped at step 16 of 24, base, before the broker step:", " \t\t\t\tMake sure you have all the referenced content and try again.", "NotFound: content digest sha256:e2de96513ba9: not found", "ℹ tests 1", "ℹ suites 0", "ℹ pass 0", "ℹ fail 0", "ℹ cancelled 0", "ℹ skipped 1", "ℹ todo 0", "ℹ duration_ms 590254.163993", "", "recorded: test/integration/genesis-keeps-its-bus.test.ts — 0 passed, 0 failed, against mesh-lab 7ed7da1", ].join("\n"); // The same run, as the lab's suite says it once it names its skips (mesh-lab, issue 693). const newLog = [ "ℹ tests 1", "ℹ pass 0", "ℹ fail 0", "ℹ skipped 1", "", "recorded: test/integration/genesis-keeps-its-bus.test.ts — 0 passed, 0 failed, 1 skipped, against mesh-lab 7ed7da1", "NOT PASSED: no test passed: 1 skipped, 1 of them as NOT REACHED", "skipped: genesis adopts its bus — one bus (test/integration/genesis-keeps-its-bus.test.ts) # ADR 0333 §5 NOT REACHED: the first run stopped at step 16 of 24, base: NotFound: content digest", ].join("\n"); function anEndedRun(log: string, state: "passed" | "failed", exit: number): { work: string; id: string } { const work = mkdtempSync(join(tmpdir(), "lab-runs-")); const id = "run-2026-10-14T00-21-44-014Z"; mkdirSync(join(work, id)); writeFileSync(join(work, id, "run.log"), log); writeFileSync(join(work, id, "status.json"), JSON.stringify({ id, state, exit, started: "2026-10-14T00:21:44.014Z", ended: "2026-10-14T00:33:11.179Z", tests: ["test/integration/genesis-keeps-its-bus.test.ts"], refs: {}, })); return { work, id }; } test("a run whose only test skipped as NOT REACHED, from a lab of before, reads as failed with the reason", () => { const { work, id } = anEndedRun(oldLog, "passed", 0); const s = readStatus(work, id); assert.equal(s?.state, "failed", JSON.stringify(s)); assert.equal(s?.exit, 0); assert.equal(s?.outcome?.passed, 0); assert.equal(s?.outcome?.skipped, 1); assert.equal(s?.outcome?.notPassed, "no test passed: 1 skipped, 1 of them as NOT REACHED"); assert.match(s?.outcome?.skips[0]?.reason ?? "", /^ADR 0333 §5 NOT REACHED: the first run stopped at step 16 of 24, base, before the broker step:$/); // Kept in the run's record, not only answered. const kept = JSON.parse(readFileSync(join(work, id, "status.json"), "utf8")); assert.equal(kept.state, "failed"); assert.equal(kept.outcome.notPassed, "no test passed: 1 skipped, 1 of them as NOT REACHED"); rmSync(work, { recursive: true, force: true }); }); test("the lab's own NOT PASSED and skipped lines are read, a test name's punctuation and all", () => { const { work, id } = anEndedRun(newLog, "failed", 1); const s = readStatus(work, id); assert.equal(s?.state, "failed"); assert.equal(s?.outcome?.notPassed, "no test passed: 1 skipped, 1 of them as NOT REACHED"); assert.deepEqual(s?.outcome?.skips, [{ file: "test/integration/genesis-keeps-its-bus.test.ts", test: "genesis adopts its bus — one bus", reason: "ADR 0333 §5 NOT REACHED: the first run stopped at step 16 of 24, base: NotFound: content digest", }]); rmSync(work, { recursive: true, force: true }); }); test("a run that passed tests and skipped one for a declared reason stays passed, its skip listed", () => { const log = [ "✔ a module lands (12ms)", "﹣ a builder builds (0.1ms) # set MESH_LAB_BUILDER to a built mesh-builder", "ℹ tests 2", "ℹ pass 1", "ℹ fail 0", "ℹ skipped 1", ].join("\n"); const { work, id } = anEndedRun(log, "passed", 0); const s = readStatus(work, id); assert.equal(s?.state, "passed"); assert.equal(s?.outcome?.notPassed, undefined); assert.equal(s?.outcome?.skips[0]?.reason, "set MESH_LAB_BUILDER to a built mesh-builder"); rmSync(work, { recursive: true, force: true }); }); test("a run that ran no test at all is not passed", () => { assert.equal(outcomeOf("ℹ tests 0\nℹ pass 0\nℹ fail 0\nℹ skipped 0\n").notPassed, "no test passed: none ran"); }); // Review 254 on issue 693: a test's own output, printed before the suite reports, is not the suite's verdict. test("a line a test printed that looks like the suite's is not read as the suite's", () => { const log = [ "NOT PASSED: a test printed this", "skipped: a forged skip (test/integration/x.test.ts) # FORGED NOT REACHED", "✔ a module lands (12ms)", "ℹ tests 1", "ℹ pass 1", "ℹ fail 0", "ℹ skipped 0", "", "recorded: test/integration/x.test.ts — 1 passed, 0 failed, 0 skipped, against mesh-lab 7ed7da1", ].join("\n"); const o = outcomeOf(log); assert.equal(o.notPassed, undefined, JSON.stringify(o)); assert.deepEqual(o.skips, []); }); test("not reached is matched in any case", () => { const log = [ "✔ a module lands (12ms)", "﹣ the broker step (0.1ms) # the broker step was not reached", "ℹ tests 2", "ℹ pass 1", "ℹ fail 0", "ℹ skipped 1", ].join("\n"); assert.equal(outcomeOf(log).notPassed, "1 test(s) skipped as NOT REACHED: their subject was not reached"); });