The two-node bed places the bus's users as genesis must

This bed raises genesis by hand, so it places the composed user list
after each token and each enrolment, as the trust bed does (novox/hq
issue 146); without it the first join was refused.
This commit is contained in:
2026-10-02 16:29:21 +02:00
parent 1a4f570e54
commit 91ba825975
+17
View File
@@ -193,6 +193,20 @@ function bundleFor(images: HeldImage[]): string {
return foundationBundle(bundle, images);
}
/**
* Put the mesh's composed user list where the anchor's bus reads it, and make it re-read.
*
* **Genesis's step, done by hand because this bed raises genesis by hand** (novox/hq 04-ISSUES/146).
* The bus here is the bundle's, not a module the mesh delivers, so an account the mesh composes —
* the enrolment when a token is issued, the node's own when it enrols — reaches it only if whoever
* raised it places it. Without this the first join is refused with an authorisation violation.
*/
async function composeTheBusUsers(): Promise<void> {
await must("anchor",
`docker exec mesh-controller /mesh-controller broker accounts > /var/lib/mesh-bus-conf/accounts.conf && ` +
`docker kill -s HUP mesh-broker >/dev/null`);
}
/** Take a token out of what `token issue` printed. It is the one base64url blob on its own line. */
function tokenFrom(said: string): string {
const found = said.split("\n").map((l) => l.trim()).find((l) => l.length > 100 && !l.includes(" "));
@@ -311,9 +325,11 @@ test("both machines join it, and the token is all they need", { skip, timeout: 9
for (const [machine, node] of [["anchor", "anchor"], ["laptop", "laptop"]] as const) {
await mesh(`node add ${node}`);
const token = tokenFrom(await mesh(`token issue --node ${node}`));
await composeTheBusUsers();
// No --name. The token says what the mesh calls the machine, which is the fault this walk
// found the first time it was run.
const said = await must(machine, `${HOST_PATH} enrol --token ${quote(token)}`);
await composeTheBusUsers();
assert.match(said, new RegExp(`enrolled as ${node}`), said);
assert.match(said, /sealing key/, "no sealing key was generated");
}
@@ -1678,6 +1694,7 @@ test("a machine joins through the tunnel, with the bus closed to it", { skip, ti
assert.equal((await must("joiner", `${HOST_PATH} key 2>/dev/null`)).trim(), key);
const token = tokenFrom(await mesh(`token issue --new joiner --overlay-key ${key}`));
await composeTheBusUsers();
const said = await must("joiner", `${HOST_PATH} enrol --token ${quote(token)}`);
assert.match(said, /the tunnel to the hub is up/, said);
assert.match(said, /enrolled as joiner/, said);