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

@ -1,7 +1,7 @@
# swarm-matrix-minter
A boot-time oneshot that runs **inside `containers.hive-matrix`**, beside the
homeserver, and puts the `@hive:` account's access token into the swarm's secret
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
@ -21,7 +21,7 @@ is a property of the thing being minted.
## Idempotency
The **store** is the key, not the homeserver. A run reads
`swarm/services/matrix/hive-access-token` first and returns without touching the
`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:

View file

@ -4,7 +4,7 @@
//! its `errcode`, never its body.** A successful `/register` or `/login` body
//! *is* an access token, and an error body is one malformed response away from
//! being the same bytes — so a `body: {json}` in a message here would put the
//! `@hive:` credential in the journal.
//! sender token in the journal.
use anyhow::{Context, Result, bail};

View file

@ -1,4 +1,4 @@
//! Mint the `@hive:` account's homeserver access token, once, and publish it to the
//! Mint the matrix appservice sender account's homeserver access token, once, and publish it to the
//! swarm's secret store.
//!
//! A oneshot inside `containers.hive-matrix`, not a daemon and not part of the
@ -137,9 +137,9 @@ async fn main() -> Result<()> {
)
})?;
let path = matrix::hive_token_path();
let path = matrix::sender_token_path();
if already_published(&store, &path).await {
tracing::info!(%path, "the @hive: credential is already published; not minting");
tracing::info!(%path, "the sender token is already published; not minting");
return Ok(());
}
@ -167,8 +167,8 @@ async fn main() -> Result<()> {
},
)
.await
.with_context(|| format!("writing the @hive: credential to {path}"))?;
tracing::info!(%path, "published the @hive: credential");
.with_context(|| format!("writing the sender token to {path}"))?;
tracing::info!(%path, "published the sender token");
Ok(())
}
@ -242,8 +242,8 @@ mod tests {
// and names the literal so a move of the path is a deliberate edit on
// both sides rather than a silent 404 on the reading one.
assert_eq!(
matrix::hive_token_path(),
"swarm/services/matrix/hive-access-token"
matrix::sender_token_path(),
"swarm/services/matrix/sender-token"
);
}
}