matrix: name the credential after the account it authenticates as

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.
This commit is contained in:
atlas 2026-09-20 13:28:01 +02:00 committed by mara
commit fb9c6122df
18 changed files with 177 additions and 150 deletions

View file

@ -229,7 +229,7 @@ control: [`swarm/ui.md`](../swarm/ui.md).
### 6 · Matrix
```bash
# Ensure the hive's own `@hive:` account exists first
# Ensure the appservice's sender account exists first
hivectl matrix sync-admin
# Provision ruth's own matrix account — same bootstrap-bypass reasoning
@ -293,7 +293,7 @@ See [`tools/hivectl.md`](../tools/hivectl.md) for every `hivectl` verb.
- **No forge admin token is stored in any agent state dir.** Agents
hold a regular agent token in their `forge-token` file; sensitive
creds (the core token, the `@hive:` matrix access token) live on the host.
creds (the core token, the matrix sender token) live on the host.
- All config changes (forge PRs on `agent-configs/<name>`) go through
operator approval — agents can't unilaterally rebuild containers, by design.
See [`boundary.md`](../trust-boundary/boundary.md) and [`security.md`](../trust-boundary/security.md).

View file

@ -147,7 +147,7 @@ a token.
(`hive-matrix-daemon.path` watching for `matrix-token` appearance)
brings the daemon up on the same boot cycle anyway.
### The `@hive:` account, and why it isn't an admin
### The appservice's sender account, and why it isn't an admin
`@hive:<server_name>` is the appservice's own `sender_localpart`, which
the homeserver creates itself when it loads the registration — on a
@ -155,6 +155,14 @@ zero-user database, inside startup, before the HTTP listener accepts
anything. It's an **ordinary account**: nothing promotes it, and the
homeserver runs no `admin_execute` for it.
Its access token is the **sender token**, and it's the credential
hive-c0re presents for every homeserver call it makes on the hive's
behalf. `swarm-matrix-minter` mints it inside the `hive-matrix`
container and publishes it to `swarm/services/matrix/sender-token`; the
hive reads it from there. The name says what it authenticates as — an
account the appservice registration brings into being — rather than any
privilege level, because it carries none.
It needs no promotion for what the hive does with it. Creating the hive
Space and the chat room, writing their hierarchy and join rules, and
inviting agents into them are all ordinary client calls that ride on
@ -187,7 +195,7 @@ restarts, so the first boot after the switch already has both halves.
- **The per-agent sweep honours existing token files.** It skips any
agent that already has a `matrix-token`, so it re-registers no account
and displaces no session.
- **`@hive:` may already be an admin** on such a hive (it won the
- **The sender account may already be an admin** on such a hive (it won the
first-user grant when the hive was new). Nothing here demotes it; the
homeserver no longer promotes it, so a hive built fresh has an
ordinary account and an older one keeps whatever standing it acquired.

View file

@ -54,15 +54,15 @@ strategy for every credential, including the mTLS leaf.
<!-- vale write-good.Passive = NO -->
| store path | minter | reader — pulls at runtime, holds in memory | renewal |
| -------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| `swarm/agents/<agent>/matrix/<account>` | `swarm-controller` | the agent container itself, under the certificate its hive passed in | must be stated |
| `swarm/agents/<agent>/bao-mtls` | `swarm-controller`, at agent creation | `hive-c0re`, under the hive's own certificate, when it writes the agent's container config | must be stated |
| `swarm/hives/<hive>/matrix/appservice-token` | one minter, on the authelia host | the hive process that presents the token to its homeserver, under the hive's own certificate | must be stated |
| `swarm/hives/<hive>/queue/agent` | authelia | the agent container presenting the OIDC client to the swarm queue, under its own certificate | must be stated |
| `swarm/services/<clientId>/oidc/client` | authelia | the service process that presents the client secret, under the certificate of the host it runs on | must be stated |
| `swarm/services/matrix/hive-access-token` | `swarm-matrix-minter`, in the `hive-matrix` container | `swarm-matrix-minter` itself, under its own certificate, before it decides whether to mint, and hive-c0re's `stored_hive_token()`, under the hive's own certificate | must be stated |
| _(not in the store)_ a hive's mTLS leaf | the store's own PKI, or an operator placing it by hand | its own client, off disk — the exception above, because it's what makes every other row's pull possible | must be stated |
| store path | minter | reader — pulls at runtime, holds in memory | renewal |
| -------------------------------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| `swarm/agents/<agent>/matrix/<account>` | `swarm-controller` | the agent container itself, under the certificate its hive passed in | must be stated |
| `swarm/agents/<agent>/bao-mtls` | `swarm-controller`, at agent creation | `hive-c0re`, under the hive's own certificate, when it writes the agent's container config | must be stated |
| `swarm/hives/<hive>/matrix/appservice-token` | one minter, on the authelia host | the hive process that presents the token to its homeserver, under the hive's own certificate | must be stated |
| `swarm/hives/<hive>/queue/agent` | authelia | the agent container presenting the OIDC client to the swarm queue, under its own certificate | must be stated |
| `swarm/services/<clientId>/oidc/client` | authelia | the service process that presents the client secret, under the certificate of the host it runs on | must be stated |
| `swarm/services/matrix/sender-token` | `swarm-matrix-minter`, in the `hive-matrix` container | `swarm-matrix-minter` itself, under its own certificate, before it decides whether to mint, and hive-c0re's `stored_sender_token()`, under the hive's own certificate | must be stated |
| _(not in the store)_ a hive's mTLS leaf | the store's own PKI, or an operator placing it by hand | its own client, off disk — the exception above, because it's what makes every other row's pull possible | must be stated |
<!-- vale write-good.Passive = YES -->

View file

@ -165,7 +165,7 @@ Manual entry point to the same idempotent provisioning c0re runs at boot — for
###### **Subcommands:**
* `create-user` — Create or refresh the matrix account + access token for `<name>`
* `sync-admin` — Provision (or re-provision) the hive system admin matrix account
* `sync-admin` — Provision (or re-provision) the matrix appservice's sender account
* `promote-user` — Promote a matrix user to homeserver admin
* `reset-password` — Reset a matrix user's password via the admin API
* `invite` — Invite a matrix user to the hive Space, or a specific room with `--room`. Idempotent
@ -193,7 +193,7 @@ For an existing agent, persists the token to its state dir; for a human/other ac
## `hivectl matrix sync-admin`
Provision (or re-provision) the hive's own `@hive:` matrix account.
Provision (or re-provision) the matrix appservice's sender account.
Runs automatically on startup; run manually to recover a missing access token.

View file

@ -64,7 +64,7 @@ running (`services.hyperhive.deploy.matrix.enable = true`).
hivectl matrix create-user iris # provision (or re-provision) matrix account for agent `iris`
hivectl matrix create-user mara # create matrix account for a human; prints access_token to stdout
hivectl matrix create-user mara --password hunter2 # set a client-login password
hivectl matrix sync-admin # provision / refresh the hive's own `@hive:` account
hivectl matrix sync-admin # provision / refresh the appservice's sender account
hivectl matrix promote-user mara # promote an existing matrix user to homeserver admin
hivectl matrix reset-password iris # generate and set a new random password for `iris`; prints it
hivectl matrix invite mara # invite a user to the hive Space
@ -74,7 +74,7 @@ hivectl matrix invite @mara:server --room '#hive-chat:server' # ...or to a spec
- `create-user`: for agents, persists the `access_token` to
`<state>/matrix-token`. Skips registration when the file already
exists — delete it first to force re-registration.
- `sync-admin`: ensures the hive's own `@hive:` matrix user exists
- `sync-admin`: ensures the appservice's sender account (`@hive:<server_name>`) exists
(the account `hive-c0re` provisions rooms with). Token persisted to the
access token path. Safe to run again — idempotent.
- `promote-user`: promotes an already-registered user to homeserver
@ -87,7 +87,7 @@ hivectl matrix invite @mara:server --room '#hive-chat:server' # ...or to a spec
credentials.
- `invite`: invites a matrix user (full `@user:server` or a bare
localpart, qualified with the homeserver's `server_name`) to the hive
Space by default, or to a `--room` id / `#alias`. Uses the `@hive:`
Space by default, or to a `--room` id / `#alias`. Uses the sender
token; the account must be a member of the target room with
invite power (it owns the hive Space, so that case always works).
Idempotent — already-member / already-invited is a no-op.