A grant file and a provisioned login name the module too

novox/hq 04-ISSUES/022: a consumer is a module on a machine, not a
machine. The mesh now writes <node>.<module>.secret and the provisioners
name the role and the access key after both.

The fixtures here write what the mesh writes, so they move with it —
that is the whole point of them, and a fixture that kept the old shape
would agree with the bug rather than catch it.

The object-store assertions are the ones that mattered most: one store
holds every bucket behind one endpoint, so isolation is a policy rather
than a property. One access key per machine meant every module on a node
shared it, and the policy confining each consumer to its own bucket
confined none of them.
This commit is contained in:
2026-09-01 02:45:40 +02:00
parent 0ffb24ff5d
commit e7f4a49e40
3 changed files with 27 additions and 27 deletions
+13 -13
View File
@@ -80,7 +80,7 @@ async function meshWrote(
given: consumers.map((c) => ({
from: c.module,
node: c.node,
secret: `${GRANTS}/${c.node}.secret`,
secret: `${GRANTS}/${c.node}.${c.module}.secret`,
values: { name: c.name },
})),
};
@@ -90,8 +90,8 @@ async function meshWrote(
// make the revocation test pass for a reason that is not the one being tested.
await must(`find ${GRANTS} -name '*.secret' -delete`);
for (const c of consumers) {
await must(`printf %s ${shellQuote(c.password)} > ${GRANTS}/${c.node}.secret`);
await must(`chmod 600 ${GRANTS}/${c.node}.secret`);
await must(`printf %s ${shellQuote(c.password)} > ${GRANTS}/${c.node}.${c.module}.secret`);
await must(`chmod 600 ${GRANTS}/${c.node}.${c.module}.secret`);
}
}
@@ -178,9 +178,9 @@ test("a password the mesh generated becomes a login that works", { skip, timeout
const { out, ok } = await provision();
assert.ok(ok, out);
assert.equal(await sql(`select rolcanlogin from pg_roles where rolname = 'mesh_workstation'`), "t");
assert.equal(await sql(`select rolcanlogin from pg_roles where rolname = 'mesh_workstation_meshboard'`), "t");
assert.equal(await sql(`select 1 from pg_database where datname = 'meshboard'`), "1");
const attempt = await tryLogIn("mesh_workstation", "first-password-aaa", "meshboard");
const attempt = await tryLogIn("mesh_workstation_meshboard", "first-password-aaa", "meshboard");
assert.ok(attempt.ok, `the consumer cannot log in with the password the mesh gave it:\n${attempt.out}`);
});
@@ -190,7 +190,7 @@ test("running it again reaches the same state and says nothing", { skip, timeout
const { out, ok } = await provision();
assert.ok(ok, out);
assert.equal(out.trim(), "", `it did work on a second run: ${out}`);
assert.ok(await canLogIn("mesh_workstation", "first-password-aaa", "meshboard"));
assert.ok(await canLogIn("mesh_workstation_meshboard", "first-password-aaa", "meshboard"));
});
test("rotating the password makes the new one work and the old one stop", { skip, timeout: 300_000 }, async () => {
@@ -203,11 +203,11 @@ test("rotating the password makes the new one work and the old one stop", { skip
assert.ok(ok, out);
assert.ok(
await canLogIn("mesh_workstation", "second-password-bbb", "meshboard"),
await canLogIn("mesh_workstation_meshboard", "second-password-bbb", "meshboard"),
"the rotated password does not work",
);
assert.equal(
await canLogIn("mesh_workstation", "first-password-aaa", "meshboard"),
await canLogIn("mesh_workstation_meshboard", "first-password-aaa", "meshboard"),
false,
"the old password still works, so the rotation changed nothing",
);
@@ -220,11 +220,11 @@ test("a consumer that goes away loses its login", { skip, timeout: 300_000 }, as
await meshWrote([]);
const { out, ok } = await provision();
assert.ok(ok, out);
assert.match(out, /revoked mesh_workstation/);
assert.match(out, /revoked mesh_workstation_meshboard/);
assert.equal(await sql(`select rolcanlogin from pg_roles where rolname = 'mesh_workstation'`), "f");
assert.equal(await sql(`select rolcanlogin from pg_roles where rolname = 'mesh_workstation_meshboard'`), "f");
assert.equal(
await canLogIn("mesh_workstation", "second-password-bbb", "meshboard"),
await canLogIn("mesh_workstation_meshboard", "second-password-bbb", "meshboard"),
false,
"a consumer nobody asks for any more can still log in",
);
@@ -248,11 +248,11 @@ test("a manifest naming a credential that was never written is refused", { skip,
await meshWrote([]);
await must(
`printf %s '{"contributions":1,"requirement":"postgres-database","given":[` +
`{"from":"meshboard","node":"ghost","secret":"${GRANTS}/ghost.secret","values":{"name":"ghost"}}` +
`{"from":"meshboard","node":"ghost","secret":"${GRANTS}/ghost.meshboard.secret","values":{"name":"ghost"}}` +
`]}' > ${GRANTS}/mesh.json`,
);
const { out, ok } = await provision();
assert.equal(ok, false, "it carried on past a missing credential");
assert.match(out, /should be at .*ghost\.secret/);
assert.equal(await sql(`select count(*) from pg_roles where rolname = 'mesh_ghost'`), "0");
assert.equal(await sql(`select count(*) from pg_roles where rolname = 'mesh_ghost_meshboard'`), "0");
});