The admin-room command stays in #admins' history, so a grant tuwunel
ignores must not be re-sent every five minutes. The controller now
sends `make-user-admin` at most once per operator per process; an
operator still missing from the room on a later pass is logged as
"make-user-admin for an operator failed to take" and left alone until
the controller restarts. The cap lives in the pure `plan()`.
swarm-matrix-client's `user_exists` and `joined_members` read their
responses through pure `profile_verdict` / `joined_verdict`, the shape
`whoami` / `whoami_verdict` already has, with every branch tested: only
M_NOT_FOUND is "no account", and a 403 or a list without `joined` is an
error rather than an answer.
The bridge's handling after authentication moves into `respond()`,
which takes the config and write lock instead of the whole AppState, so
a test can drive ListOperators through the real request path and see
the 403 without an HTTP client or an authelia.
docs/integrations/matrix.md no longer says @swarm is the only homeserver
admin.
swarm-authelia-bridge gains ListOperators, the usernames in authelia's
operator group (`operatorGroup = "admins"`, passed in from
swarm-authelia.nix). Unlike the two agent verbs, which admit any active
token, it answers only the client named by
SWARM_AUTHELIA_BRIDGE_OPERATOR_READER_CLIENT_ID (swarm-controller's
queueClientId) and returns 403 to every other active token: authelia
issues machine tokens to every hive and its agents as well. The bridge's
introspection now models `client_id` to make that check, the same way
swarm-nats-auth's does.
swarm-controller runs a grant-only pass at start and every five minutes:
read the group, map each username to the account an SSO login lands on
(tuwunel lowercases `preferred_username`), skip anyone already joined to
`#admins:<server>` (tuwunel's definition of admin) or without a matrix
account, and send `!admin users make-user-admin <user>` there as @swarm
with the swarm appservice token. Nothing is ever revoked: tuwunel has no
command for it (#4799).
The admin-room calls (alias, joined members, profile, send) go into
swarm-matrix-client next to whoami, keeping its no-body-in-errors rule.
Closes#4585
The swarm gets an appservice identity of its own, separate from each hive's
`hyperhive` registration. `swarm-matrix-ctl appservice render` mints its
tokens inside the matrix container when they are absent and renders the
registration tuwunel loads; `appservice publish` writes its as_token to
`swarm/controller/swarm-controller/matrix/appservice-token`, the one kind no
hive's policy grants.
The homeserver calls move out of swarm-matrix-ctl into swarm-matrix-client,
with a `whoami`, so swarm-controller can mint agents' accounts through the
same pinned device id instead of a copy of them.