swarm: put the matrix registration token where the reader is granted

`swarm-bao-matrix-token` reads `secret/swarm/matrix/registration-token`
and is refused with `Code: 403 — permission denied`, measured on this
host at 16:17:49Z after a successful cert login.

path.rs makes every swarm path `swarm/<kind>/<name>/…` where Kind is a
closed set of four: agents, hives, services, controller. `matrix` sits
where a kind belongs, so policy.rs's read document — which emits exactly
`swarm/agents/*` and `swarm/hives/<hive>/*` — cannot cover it. The
module's own doc predicted this: "a misspelled kind is a 403 at provision
time rather than anything a compiler sees".

Moves the token to `swarm/hives/<hive>/matrix/registration-token`, built
through principal_prefix(Kind::Hive, …) like its per-hive sibling
queue::agent_client_path. The policy is untouched: render already grants
that prefix. mara chose this over widening the namespace.

The nix reader interpolates hyperhiveCfg.hiveName, with the no-fallback
reasoning glue-bao-tls.nix already gives at its own use of it.

path.rs's MOUNT doc justified itself by citing the old literal, which
this commit deletes; rewritten to cite the nix reader instead.

Scope: this makes the read reachable, not the value present. Nothing
writes that path yet, and a 403 says nothing about presence — the two
are separate findings and only the first is fixed here. No migration:
nothing ever wrote the old path and no read ever succeeded.

Gate: cargo fmt 0, cargo test -p swarm-secret-client 0 — 32 passed
against a 29-passed baseline with the change stashed, so the three new
tests are accounted for rather than assumed.

Refs #4308
This commit is contained in:
atlas 2026-09-12 19:46:04 +02:00
commit 14305255f0
4 changed files with 70 additions and 4 deletions

View file

@ -10,9 +10,9 @@ use crate::Error;
/// The KV v2 mount every swarm secret lives under.
///
/// A literal because the store's existing reader already hardcodes the same
/// one (`secret/swarm/matrix/registration-token`); an option nobody sets would
/// be two ways to say one thing.
/// A literal because the nix-side reader spells the same one in
/// `glue-matrix-bao-token.nix`; an option nobody sets would be two ways to say
/// one thing.
pub const MOUNT: &str = "secret";
/// The root under [`MOUNT`] that every swarm secret lives beneath.