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

@ -34,10 +34,12 @@ pub fn account_path(agent: &str, account: &str) -> Result<String, Error> {
/// "only once" without a lock.
pub const HOMESERVER_SERVICE: &str = "matrix";
/// The path holding the `@hive:` account's homeserver access token.
/// The path holding the matrix appservice sender account's homeserver
/// access token.
///
/// Keyed per **homeserver**, not per hive and not per agent: a homeserver has one
/// `@hive:` account (hive-c0re's `matrix::HIVE_LOCALPART`), so a
/// appservice registration and so one sender account (`@hive:<server_name>`,
/// hive-c0re's `matrix::HIVE_LOCALPART`), so a
/// per-hive copy would be several names for one secret. That is also why this
/// takes no argument and cannot fail — there is no caller-supplied segment in
/// it to reject.
@ -45,9 +47,9 @@ pub const HOMESERVER_SERVICE: &str = "matrix";
/// Reachable by every hive without a new grant: [`crate::policy::render`]
/// already grants a hive read on the whole [`Kind::Service`] tree.
#[must_use]
pub fn hive_token_path() -> String {
pub fn sender_token_path() -> String {
format!(
"{ROOT}/{}/{HOMESERVER_SERVICE}/hive-access-token",
"{ROOT}/{}/{HOMESERVER_SERVICE}/sender-token",
<&str>::from(Kind::Service)
)
}
@ -121,7 +123,7 @@ mod tests {
// segment is PLURAL; `Kind::label` renders the singular and is for
// error text only, so reading it as the path segment produces a
// 403 the store explains as "permission denied" and nothing else.
assert_eq!(hive_token_path(), "swarm/services/matrix/hive-access-token");
assert_eq!(sender_token_path(), "swarm/services/matrix/sender-token");
}
#[test]
@ -131,7 +133,7 @@ mod tests {
// neighbouring tree instead of this one.
let prefix =
principal_prefix(Kind::Service, HOMESERVER_SERVICE).expect("a plain name is legal");
assert_eq!(hive_token_path(), format!("{prefix}/hive-access-token"));
assert_eq!(sender_token_path(), format!("{prefix}/sender-token"));
}
#[test]