From dd39d4ace74b6a592cfbc726db297e2b7bf42d37 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 13 Oct 2026 14:51:18 +0200 Subject: [PATCH] lab: name the bound credential in the tools bundle's env, and skip the locked-tree test as root (hq issue 624, reviews 198, 199) The lab's tools read their bound npm-package-registry credential, root's at 0600 on the machine. The controller gives the runtime's account exactly the files a tools bundle names in its env (ADR 0192), as gitea and umami are given theirs, so the bundle now names the credential and its binding there, and no other credential changes hands. The merge check runs as root, where no directory mode stops a removal: the test that makes an unremovable tree now skips there before it makes anything, and a second test clears leftovers whoever runs it. --- modules/lab/module.json | 4 +++- modules/lab/test/runs.test.ts | 35 ++++++++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/modules/lab/module.json b/modules/lab/module.json index 5406579d..c9c14770 100644 --- a/modules/lab/module.json +++ b/modules/lab/module.json @@ -104,7 +104,9 @@ ], "env": { "MESH_LAB_WORK": "${dir:work}", - "MESH_LAB_ENV_FILE": "${dir:state}/lab.env" + "MESH_LAB_ENV_FILE": "${dir:state}/lab.env", + "MESH_LAB_FORGE_BINDING": "${dir:state}/package-registry.json", + "MESH_LAB_FORGE_SECRET": "${dir:state}/package-registry.secret" } } ] diff --git a/modules/lab/test/runs.test.ts b/modules/lab/test/runs.test.ts index 441af105..f87bf3d2 100644 --- a/modules/lab/test/runs.test.ts +++ b/modules/lab/test/runs.test.ts @@ -209,7 +209,11 @@ test("each check gets a fresh directory of its own", () => { rmSync(work, { recursive: true, force: true }); }); -test("what earlier checks left is cleared, and what cannot be is named rather than tripped over", () => { +// 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. @@ -220,9 +224,30 @@ test("what earlier checks left is cleared, and what cannot be is named rather th 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"))); - if (process.getuid?.() !== 0) { - assert.equal(said.length, 1); - assert.match(said[0] as string, /check-stuck, left by an earlier check, could not be removed/); - } + 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"]); +});