From 966fed1829e6ad021ff409d8bf665ab1d6ea0023 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 1 Oct 2026 15:58:05 +0200 Subject: [PATCH 1/4] The vault claims mesh-vault, and each uplink holder declares the manager it speaks for (hq ADR 0161) The vault's claim makes a second provider of secret a second claimant, refused by name. The three uplink definitions declare uplink-networkmanager, uplink-systemd-networkd and uplink-dhcpcd, which the host reports for the manager it finds active, so the holder for a manager the machine does not run is refused the way any missing capability is. Merges after the controller holds the seat and the host reports the capability. --- modules/dhcpcd/module.json | 3 ++- modules/mesh-vault/module.json | 8 +++++++- modules/networkmanager/module.json | 3 ++- modules/systemd-networkd/module.json | 3 ++- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/modules/dhcpcd/module.json b/modules/dhcpcd/module.json index 89ffe07..23c658e 100644 --- a/modules/dhcpcd/module.json +++ b/modules/dhcpcd/module.json @@ -3,7 +3,8 @@ "version": "1", "capabilities": [ "package-manager", - "service-manager" + "service-manager", + "uplink-dhcpcd" ], "claims": [ { diff --git a/modules/mesh-vault/module.json b/modules/mesh-vault/module.json index 991e237..8b51fca 100644 --- a/modules/mesh-vault/module.json +++ b/modules/mesh-vault/module.json @@ -98,5 +98,11 @@ "from": "Dockerfile" } ] - } + }, + "claims": [ + { + "name": "mesh-vault", + "scope": "mesh" + } + ] } diff --git a/modules/networkmanager/module.json b/modules/networkmanager/module.json index 5aaa8f6..37c2ba7 100644 --- a/modules/networkmanager/module.json +++ b/modules/networkmanager/module.json @@ -3,7 +3,8 @@ "version": "1", "capabilities": [ "package-manager", - "service-manager" + "service-manager", + "uplink-networkmanager" ], "claims": [ { diff --git a/modules/systemd-networkd/module.json b/modules/systemd-networkd/module.json index 040b67e..370cf1d 100644 --- a/modules/systemd-networkd/module.json +++ b/modules/systemd-networkd/module.json @@ -3,7 +3,8 @@ "version": "1", "capabilities": [ "package-manager", - "service-manager" + "service-manager", + "uplink-systemd-networkd" ], "claims": [ { -- 2.54.0 From 83686977444e27972b1a79752f0cebba3c6fc5b9 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 1 Oct 2026 16:50:56 +0200 Subject: [PATCH 2/4] The vault's events are its own: provisioned, rotated, deprovisioned A module publishes under its own name only; secret.provisioned read as another module's event and the builder refused the vault's definition today, so the seat claim could not be built. The three events lose the prefix; nothing outside the vault listens for the old names. --- modules/mesh-vault/index.ts | 12 ++++++------ modules/mesh-vault/module.json | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/modules/mesh-vault/index.ts b/modules/mesh-vault/index.ts index 540a780..80f74f3 100644 --- a/modules/mesh-vault/index.ts +++ b/modules/mesh-vault/index.ts @@ -1,9 +1,9 @@ // mesh-vault's events entrypoint, loaded by the per-node tool host (the provisioner runs in the same // process — ADR 0052). The lifecycle events are EMITTED from the provisioner, where custody // actually changes (novox/hq ADR 0041/0042): -// module.mesh-vault.secret.provisioned — a consumer was granted a secret -// module.mesh-vault.secret.rotated — that consumer's value changed (`rotate secret`) -// module.mesh-vault.secret.deprovisioned — the consumer went away and its secret was withdrawn +// mesh-vault.provisioned — a consumer was granted a secret +// mesh-vault.rotated — that consumer's value changed (`rotate secret`) +// mesh-vault.deprovisioned — the consumer went away and its secret was withdrawn // Here the vault reacts to them, keeping a lightweight audit line of who holds what and when it // moved — the audit an owner of secrets is best placed to log. Fingerprints, never values. @@ -16,15 +16,15 @@ interface SecretEvent { rotations?: number; } -await on("secret.provisioned", async (e) => { +await on("provisioned", async (e) => { console.log(`[mesh-vault] secret provisioned for ${e.body.as} on ${e.body.consumer} (${e.body.fingerprint})`); }); -await on("secret.rotated", async (e) => { +await on("rotated", async (e) => { console.log(`[mesh-vault] secret rotated for ${e.body.as} — rotation ${e.body.rotations} (${e.body.fingerprint})`); }); -await on("secret.deprovisioned", async (e) => { +await on("deprovisioned", async (e) => { console.log(`[mesh-vault] secret withdrawn from ${e.body.as}`); }); diff --git a/modules/mesh-vault/module.json b/modules/mesh-vault/module.json index 8b51fca..29e17a3 100644 --- a/modules/mesh-vault/module.json +++ b/modules/mesh-vault/module.json @@ -11,14 +11,14 @@ "container-runtime" ], "emits": [ - "secret.provisioned", - "secret.rotated", - "secret.deprovisioned" + "provisioned", + "rotated", + "deprovisioned" ], "consumes": [ - "mesh-vault.secret.provisioned", - "mesh-vault.secret.rotated", - "mesh-vault.secret.deprovisioned" + "mesh-vault.provisioned", + "mesh-vault.rotated", + "mesh-vault.deprovisioned" ], "receives": { "secret": "${dir:grants}/mesh.json" -- 2.54.0 From 6ba61a8b4b9fac40fb9d9752ac6a9b238c9271d0 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 1 Oct 2026 16:51:13 +0200 Subject: [PATCH 3/4] The provisioner announces the vault's events by their new names --- modules/mesh-vault/provisioner/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/mesh-vault/provisioner/index.ts b/modules/mesh-vault/provisioner/index.ts index ad0872c..37808a1 100644 --- a/modules/mesh-vault/provisioner/index.ts +++ b/modules/mesh-vault/provisioner/index.ts @@ -43,6 +43,6 @@ runProvisioner("secret", { async remove(p: { as: string }): Promise { if (!ledger.withdraw(p.as)) return; console.log(`[mesh-vault] withdrawn: ${p.as}`); - await announce("secret.deprovisioned", { as: p.as }); + await announce("deprovisioned", { as: p.as }); }, }); -- 2.54.0 From 932efb51864edc20d88b53622209cf2046a6cf18 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 1 Oct 2026 16:52:46 +0200 Subject: [PATCH 4/4] This branch carries the vault's claim alone; the uplink capabilities wait for every machine to report its profile --- modules/dhcpcd/module.json | 3 +-- modules/networkmanager/module.json | 3 +-- modules/systemd-networkd/module.json | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/modules/dhcpcd/module.json b/modules/dhcpcd/module.json index 23c658e..89ffe07 100644 --- a/modules/dhcpcd/module.json +++ b/modules/dhcpcd/module.json @@ -3,8 +3,7 @@ "version": "1", "capabilities": [ "package-manager", - "service-manager", - "uplink-dhcpcd" + "service-manager" ], "claims": [ { diff --git a/modules/networkmanager/module.json b/modules/networkmanager/module.json index 37c2ba7..5aaa8f6 100644 --- a/modules/networkmanager/module.json +++ b/modules/networkmanager/module.json @@ -3,8 +3,7 @@ "version": "1", "capabilities": [ "package-manager", - "service-manager", - "uplink-networkmanager" + "service-manager" ], "claims": [ { diff --git a/modules/systemd-networkd/module.json b/modules/systemd-networkd/module.json index 370cf1d..040b67e 100644 --- a/modules/systemd-networkd/module.json +++ b/modules/systemd-networkd/module.json @@ -3,8 +3,7 @@ "version": "1", "capabilities": [ "package-manager", - "service-manager", - "uplink-systemd-networkd" + "service-manager" ], "claims": [ { -- 2.54.0