matrix, docs: drop the last admin framing, fix tense and prose lint

Three leftovers from the rename, plus the gating prose job.

`nix/packages/default.nix` still described the minter as the "matrix
admin credential's minter", and shipped that claim in the package's
`meta.description` — a PR-visible string.

`promote_user_to_admin`'s doc comment pointed at the `admin_execute`
entry in `hive-matrix.nix` as the thing that bootstraps the first
admin. That entry is gone, so the comment referenced nothing. It now
records that the account is ordinary, that the call therefore has no
working sender, and that rehoming at swarm level is the fix rather than
re-granting. `reset_user_password` gained the matching warning; it had
none.

The prose fixes clear all 8 `CI / prose lint (vale, errors)` failures,
all of which were in docs this branch touches. No vale config change,
no exception, no carve-out: contractions, one recast sentence, one
de-hyphenation and one dropped "simply".

Tense: four docs described system behaviour in the future ("will
refuse", "will fetch and trust"). Reference docs get read from the
other side of the change, so they say what the system does.
This commit is contained in:
atlas 2026-09-20 05:17:23 +02:00 committed by mara
commit bbb4e471ea
5 changed files with 27 additions and 19 deletions

View file

@ -181,7 +181,7 @@ which. A hive that does **not** deploy the store names the reader's three
itself: the operator issues that leaf out of band, and it's the one credential itself: the operator issues that leaf out of band, and it's the one credential
the store can't hand you, being what opens it. ⚠️ Not the gateway's HTTPS certificates and not the hive CA — this is the store can't hand you, being what opens it. ⚠️ Not the gateway's HTTPS certificates and not the hive CA — this is
**mTLS between services and the store**, a separate trust domain, because a **mTLS between services and the store**, a separate trust domain, because a
store that took its identity from an authority it will itself distribute could store that took its identity from an authority it itself distributes could
never come up before that authority. never come up before that authority.
### 4 · Swarm SSO (only when `deploy.authelia`) ### 4 · Swarm SSO (only when `deploy.authelia`)
@ -203,8 +203,8 @@ surfaces (the swarm UI below) gate on that group, and an account
without it authenticates successfully and is then refused — which reads without it authenticates successfully and is then refused — which reads
like a broken login rather than a missing group. like a broken login rather than a missing group.
If an account already exists without it, `user add` will refuse rather If an account already exists without it, `user add` refuses rather
than amend — adding the group afterwards is `swarmctl user update mara than amends — adding the group afterwards is `swarmctl user update mara
--add-group admins`. --add-group admins`.
Detail, including what the password is and why this stays manual: Detail, including what the password is and why this stays manual:

View file

@ -147,20 +147,20 @@ a token.
(`hive-matrix-daemon.path` watching for `matrix-token` appearance) (`hive-matrix-daemon.path` watching for `matrix-token` appearance)
brings the daemon up on the same boot cycle anyway. brings the daemon up on the same boot cycle anyway.
### The `@hive:` account, and why it is not an admin ### The `@hive:` account, and why it isn't an admin
`@hive:<server_name>` is the appservice's own `sender_localpart`, which `@hive:<server_name>` is the appservice's own `sender_localpart`, which
the homeserver creates itself when it loads the registration — on a the homeserver creates itself when it loads the registration — on a
zero-user database, inside startup, before the HTTP listener accepts zero-user database, inside startup, before the HTTP listener accepts
anything. It is an **ordinary account**: nothing promotes it, and the anything. It's an **ordinary account**: nothing promotes it, and the
homeserver runs no `admin_execute` for it. homeserver runs no `admin_execute` for it.
It needs no promotion for what the hive does with it. Creating the hive 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 Space and the chat room, writing their hierarchy and join rules, and
inviting agents into them are all ordinary client calls that ride on inviting agents into them are all ordinary client calls that ride on
being the rooms' own creator at power level 100 — there is no homeserver being the rooms' own creator at power level 100 — there is no homeserver
admin in any of it. (There is no Synapse admin API here either; tuwunel admin in any of it, and no Synapse admin API to reach for either, since
has none.) tuwunel has none.
Two operations do need an admin **sender**, and neither works today: Two operations do need an admin **sender**, and neither works today:
`hivectl matrix promote-user` and `hivectl matrix reset-password`. Both `hivectl matrix promote-user` and `hivectl matrix reset-password`. Both
@ -169,8 +169,8 @@ treats a message as a command when its sender is already an admin. They
are swarm-level operations and are being rehomed as such; until then are swarm-level operations and are being rehomed as such; until then
they fail with the admin room's refusal rather than being served by an they fail with the admin room's refusal rather than being served by an
over-privileged credential that every other call site would also carry. over-privileged credential that every other call site would also carry.
The one hive-side path that depends on them is the password-reset The one hive-side path that depends on them is the automatic password
auto-recovery for an agent whose stored password is gone — the ordinary recovery for an agent whose stored password is gone — the ordinary
appservice re-login above is unaffected. appservice re-login above is unaffected.
<details><summary>Upgrading a hive that used the registration token</summary> <details><summary>Upgrading a hive that used the registration token</summary>
@ -189,7 +189,7 @@ restarts, so the first boot after the switch already has both halves.
and displaces no session. and displaces no session.
- **`@hive:` may already be an admin** on such a hive (it won the - **`@hive:` 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 first-user grant when the hive was new). Nothing here demotes it; the
homeserver simply no longer promotes it, so a hive built fresh has an homeserver no longer promotes it, so a hive built fresh has an
ordinary account and an older one keeps whatever standing it acquired. ordinary account and an older one keeps whatever standing it acquired.
- **`/var/lib/hyperhive/matrix-register-token` stays on disk**, read by - **`/var/lib/hyperhive/matrix-register-token` stays on disk**, read by
nothing. Delete it or leave it; neither does any harm. nothing. Delete it or leave it; neither does any harm.
@ -278,7 +278,7 @@ services.hyperhive.swarm.matrix = {
``` ```
**`trustedServers`** (default `[]`) — list of peer homeserver names **`trustedServers`** (default `[]`) — list of peer homeserver names
whose signing keys tuwunel will fetch and trust. tuwunel enables federation whose signing keys tuwunel fetches and trusts. Federation is enabled
at the protocol level from first boot (`allow_federation = true`) but at the protocol level from first boot (`allow_federation = true`) but
trusts no remote homeserver until you list it here. For a closed trusts no remote homeserver until you list it here. For a closed
single-hive deployment the default empty list is correct — add peer single-hive deployment the default empty list is correct — add peer

View file

@ -79,11 +79,11 @@ hivectl matrix invite @mara:server --room '#hive-chat:server' # ...or to a spec
access token path. Safe to run again — idempotent. access token path. Safe to run again — idempotent.
- `promote-user`: promotes an already-registered user to homeserver - `promote-user`: promotes an already-registered user to homeserver
admin by an `!admin` command in `#admins`. ⚠️ Needs an admin **sender**, admin by an `!admin` command in `#admins`. ⚠️ Needs an admin **sender**,
which `@hive:` is not — this operation is being rehomed at swarm level which `@hive:` isn't — this operation is being rehomed at swarm level
and does not work from the hive today. and doesn't work from the hive today.
- `reset-password`: asks the admin room to set a new random - `reset-password`: asks the admin room to set a new random
password and prints it to stdout. ⚠️ Needs an admin **sender** too, so password and prints it to stdout. ⚠️ Needs an admin **sender** too, so
it does not work from the hive today either. Useful if an agent or human lost it doesn't work from the hive today either. Useful if an agent or human lost
credentials. credentials.
- `invite`: invites a matrix user (full `@user:server` or a bare - `invite`: invites a matrix user (full `@user:server` or a bare
localpart, qualified with the homeserver's `server_name`) to the hive localpart, qualified with the homeserver's `server_name`) to the hive
@ -227,7 +227,7 @@ granting that group the one action `machinectl shell` needs); `choom`
checks this itself and refuses up front with a message naming the checks this itself and refuses up front with a message naming the
requirement rather than letting systemd reject the exec later with an requirement rather than letting systemd reject the exec later with an
opaque polkit prompt. Same caveat as the socket grant: a shell opened opaque polkit prompt. Same caveat as the socket grant: a shell opened
before the operator added you to `hive-admin` won't see it until you log before the operator added you to `hive-admin` doesn't see it until you log
back in — secondary group membership applies at login. back in — secondary group membership applies at login.
It also needs the daemon socket, unlike the other exec-into-a-container It also needs the daemon socket, unlike the other exec-into-a-container

View file

@ -1103,8 +1103,12 @@ mod is_make_admin_success_tests {
/// ///
/// ⚠️ Requires the **sender** to be an admin already — tuwunel only /// ⚠️ Requires the **sender** to be an admin already — tuwunel only
/// treats a message as a command when its sender is in the admin room. /// treats a message as a command when its sender is in the admin room.
/// So this promotes a *second* user; it cannot bootstrap the first one. /// `@hive:` is an ordinary account (`hive-matrix.nix` grants it no
/// That is what the `admin_execute` entry in `hive-matrix.nix` is for. /// `admin_execute` promotion), so this call has no working sender from
/// the hive and fails with the admin room's refusal. Promotion is a
/// swarm-level operation and is being rehomed as such; this stays here,
/// failing loudly, rather than justifying an over-privileged token that
/// all 13 ordinary call sites would also carry.
/// ///
/// Goes through the admin room rather than a direct HTTP call because /// Goes through the admin room rather than a direct HTTP call because
/// tuwunel implements parts of the Synapse admin API but not user /// tuwunel implements parts of the Synapse admin API but not user
@ -1144,6 +1148,10 @@ pub async fn promote_user_to_admin(
/// it to the non-purgeable creds path so [`ensure_user_for`] can re-login /// it to the non-purgeable creds path so [`ensure_user_for`] can re-login
/// on the next provisioning sweep. /// on the next provisioning sweep.
/// ///
/// ⚠️ Same admin-**sender** requirement as [`promote_user_to_admin`], and
/// the same consequence: `@hive:` is an ordinary account, so this fails
/// from the hive until the operation is rehomed at swarm level.
///
/// Returns the new password for use in subsequent `login_user` calls. /// Returns the new password for use in subsequent `login_user` calls.
pub async fn reset_user_password( pub async fn reset_user_password(
client: &reqwest::Client, client: &reqwest::Client,

View file

@ -163,12 +163,12 @@ in
# rather than every hive's. # rather than every hive's.
swarm-nats-auth = mkBinPackage "swarm-nats-auth" "hyperhive swarm queue auth-callout responder"; swarm-nats-auth = mkBinPackage "swarm-nats-auth" "hyperhive swarm queue auth-callout responder";
# The matrix admin credential's minter. Out of `daemonBins` for the same # The `@hive:` access token's minter. Out of `daemonBins` for the same
# "runs *inside* a container, not on the host" reason as the responder # "runs *inside* a container, not on the host" reason as the responder
# above, and with a second one: putting it in the core bundle would place # above, and with a second one: putting it in the core bundle would place
# the binary that reads the appservice token on every hive's filesystem, # the binary that reads the appservice token on every hive's filesystem,
# which is the arrangement it exists to end. # which is the arrangement it exists to end.
swarm-matrix-minter = mkBinPackage "swarm-matrix-minter" "hyperhive matrix admin-credential minter"; swarm-matrix-minter = mkBinPackage "swarm-matrix-minter" "hyperhive matrix @hive: access-token minter";
# The only process allowed to write swarm-authelia's users database — # The only process allowed to write swarm-authelia's users database —
# same "runs *inside* a container, not on the host" placement as # same "runs *inside* a container, not on the host" placement as