Three failures, all mine, all worth having

**A password beginning with a dash broke the search for it.** The
credential test greps the machine's own files for the delivered
password; this run's password started `-S`, so grep read it as an option
and refused the whole invocation. The test compared the usage message
against "0" and reported the password as leaked. That is the worst way
for a search to fail — it says it found something. Fixed with `-e` and
`--`, which is what those exist for.

**The planning test could not redirect what the scenario does not
serve.** Rewriting an image reference only works for repositories the
scenario's registry actually holds, and the object store's provisioner
was not stocked — so that module kept its placeholder and the refusal
fired, correctly. It is stocked now, so all five are planned again. The
skip path stays for anything genuinely unserved, and says which module
and why: a planning test quietly covering four instead of five is the
false coverage this suite exists to prevent.

**The forge failed because of the one above it.** The planning test
threw before its cleanup could run, leaving a module assigned that
refused the next push, so no database container was ever created.
Yesterday's fix moved that cleanup where a failure cannot skip it — but
`after` still only unassigns what was assigned, so it now tracks what
actually got added rather than what was intended.
This commit is contained in:
2026-09-01 16:16:57 +02:00
parent 2c7e69f4db
commit 44d3e53bcb
2 changed files with 22 additions and 3 deletions
+19 -3
View File
@@ -321,7 +321,12 @@ test("a credential reaches both ends and the mesh holds neither", { skip, timeou
["laptop", "/var/lib/mesh-host/state.json"],
["anchor", "/var/lib/mesh-host/declared.json"],
] as const) {
const { out } = await on(machine, `grep -c ${quote(onConsumer)} ${where}`);
// **`--` first, or the password is read as options.** A generated credential is random, so
// one of them eventually begins with a dash — this one started `-S` and grep refused the
// whole invocation. The test then compared an error message against "0" and reported the
// password as leaked, which is the worst way for a search to fail: it says it found
// something.
const { out } = await on(machine, `grep -c -e ${quote(onConsumer)} -- ${where}`);
assert.equal(out.trim(), "0", `the password is in ${where} on ${machine}`);
}
const inTheMesh = await must("anchor",
@@ -1712,6 +1717,7 @@ test("the real modules resolve together, and compose a declaration a host accept
skip, timeout: 300_000,
}, async (t) => {
const modules = ["postgres", "keycloak", "gitea", "minio", "mailu"];
const planned: string[] = [];
for (const name of modules) {
const raw = readFileSync(
`${process.env["MESH_LAB_MODULES"]}/${name}.json`, "utf8");
@@ -1722,6 +1728,16 @@ test("the real modules resolve together, and compose a declaration a host accept
// declaration from it is refused (novox/hq 04-ISSUES/025). Planning what could never run is
// what this test used to do.
const pinned = pinnedInto(raw, stocked);
// What this scenario does not serve cannot be redirected, and a module still naming a
// placeholder cannot be planned — the refusal is the point (novox/hq 04-ISSUES/025). Skipped
// and said, rather than silently dropped: a planning test quietly covering four modules
// instead of five is the false coverage this suite exists to prevent.
const left = stillUnpinned(pinned);
if (left.length > 0) {
console.log(`skipping ${name}: this scenario serves no ${left.join(", ")}`);
continue;
}
planned.push(name);
await must("anchor", `printf %s ${quote(pinned)} > /${name}.json`);
await must("anchor", `docker cp /${name}.json mesh-control:/${name}.json`);
await mesh(`module add /${name}.json`);
@@ -1732,12 +1748,12 @@ test("the real modules resolve together, and compose a declaration a host accept
// the first time this test failed — and the next test's push was refused by a module this one
// had left behind, which reads as a fault in the test that was actually working.
t.after(async () => {
for (const name of modules) await mesh(`unassign anchor ${name}`).catch(() => {});
for (const name of planned) await mesh(`unassign anchor ${name}`).catch(() => {});
});
// Assigned one at a time, because assignment resolves the whole set and says so immediately.
// A refusal here is the graph rejecting something, which is the point of asking.
for (const name of modules) {
for (const name of planned) {
await mesh(`assign anchor ${name}`);
}