| Filename | Latest commit message | Latest commit date |
|---|---|---|
The store path and every identifier around it called this an admin token. It is not one: of ~15 hive-c0re call sites only two need homeserver admin, and the homeserver no longer promotes the account at boot, so the name overstated both what the credential is and what it may do. Renaming it to the account was not enough either. "The `@hive:` token" reads as the token of a hive user, and no such user is provisioned — `@hive:<server_name>` is the appservice registration's own `sender_localpart`, an account the homeserver creates for itself when it loads the registration. So it is the **sender token**: the matrix appservice sender account's access token, at `swarm/services/matrix/sender-token`. The name says what it authenticates as rather than what it may do, which is the part that was wrong. The path has one constructor, and the bao grant, the grant assertion and three unit tests pin its literal independently — so a half-finished rename fails a check rather than leaving the minter and its readers disagreeing at runtime. `tracing` messages are renamed with the code, so the journal reads the way the source does. The host-side file keeps its name (`matrix/access-token`): it carried no admin framing, and renaming it would orphan the file on every deployed hive for nothing. `docs/tools/hivectl-cli.md` is regenerated from the clap tree. |
||
| .. | ||
| src | ||
| Cargo.toml | ||
| README.md | ||
swarm-matrix-minter
A boot-time oneshot that runs inside containers.hive-matrix, beside the
homeserver, and puts the appservice sender account's access token into the swarm's secret
store under an identity of its own.
Why it lives in the matrix container
The credential it mints is authorised by the appservice as_token, and the
container already holds that: nix/host-modules/hive-matrix.nix bind-mounts the
rendered appservice registration into it read-only, because that is how tuwunel
itself is handed the registration. Minting anywhere else would mean copying the
as_token to a second holder — and the point of this component is that the hive
stops being one.
It is not the swarm controller for the same reason, plus a structural one: a
homeserver has exactly one @hive: account and a swarm runs one
homeserver, so "mint it once" needs no lock, no lease and no trigger surface — it
is a property of the thing being minted.
Idempotency
The store is the key, not the homeserver. A run reads
swarm/services/matrix/sender-token first and returns without touching the
homeserver when something is already there. Only an empty path reaches the mint
ladder:
POST /_matrix/client/v3/registerwith"type": "m.login.application_service"— one round trip, no UIAA.M_USER_IN_USE(the expected arm on a homeserver that has already loaded the registration, since the account is the appservice's ownsender_localpart) →POST /_matrix/client/v3/loginas the appservice, same pinneddevice_id, so the old device is replaced rather than duplicated.- Write the result to the store.
A crash between the homeserver call and the store write is recoverable: the next run takes arm 2.
🩸 A secret is a path, never a value
Nothing here logs, prints or interpolates a token. The mint ladder's errors are
built from the homeserver's status and its errcode, never its body, because a
/login response body is an access token. The one identifier this binary logs is
the store path it wrote.