hive-matrix: load the swarm's appservice and promote its sender

The matrix container renders the swarm registration before tuwunel starts
(`requiredBy` it, no network), tuwunel loads it as a second `.yaml`
credential, and a publish unit hands its token to the store. tuwunel 1.9.1
refuses only a duplicate id or as_token, not overlapping non-exclusive
namespaces, so it sits beside the hive's `hyperhive` registration.

`admin_execute` promotes exactly `@swarm` at boot. The module-eval pin
narrows from "no account" to that one list, compared whole so a second
entry fails; `admin_execute_errors_ignore` is pinned too. matrix-ctl may
write the swarm token's leaf, and the controller may only read it.

Everything is gated on matrix-ctl's store identity: with nobody to publish
the token, the registration would be an admin credential nobody reads.
This commit is contained in:
atlas 2026-09-24 23:57:05 +02:00 • committed by mara
commit 9308752a09
4 changed files with 194 additions and 25 deletions

View file

@ -334,12 +334,18 @@ let
# are what keep it from drifting back — neither the `services/*` tree nor
# a `hives/*` wildcard may appear, since either one hands matrix-ctl (or
# a hive) reach beyond the single leaf it owns.
name = "matrix-ctl's grant is one hive's sender token path and nothing else";
#
# The one other leaf is the swarm appservice token, which matrix-ctl
# mints and publishes for the controller. Counted, so a third stanza
# fails rather than riding along beside two correct ones.
name = "matrix-ctl's grant is one hive's sender token and the swarm appservice token, nothing else";
ok =
let
s = baoGrantHere.systemd.services.swarm-bao-matrix-ctl-policy.script;
in
lib.hasInfix "path \"secret/data/swarm/hives/h1/matrix/sender-token\" {" s
&& lib.hasInfix "path \"secret/data/swarm/controller/swarm-controller/matrix/appservice-token\" {\n capabilities = [\"create\", \"update\", \"read\"]\n}" s
&& lib.length (lib.splitString "path \"" s) == 3
&& !(lib.hasInfix "secret/data/swarm/services" s)
&& !(lib.hasInfix "secret/data/swarm/agents" s)
&& !(lib.hasInfix "secret/data/swarm/hives/*" s)
@ -747,6 +753,14 @@ let
in
lib.hasInfix "path \"secret/data/swarm/agents/*\" {\n capabilities = [\"create\", \"read\", \"update\"]" s;
}
{
# The swarm appservice token is a homeserver-admin credential. The
# controller mints agents' accounts with it and has no business replacing
# it: matrix-ctl is its one writer. Pinned as the whole stanza, so an
# added capability fails.
name = "the controller reads the swarm appservice token and cannot write it";
ok = lib.hasInfix "path \"secret/data/swarm/controller/swarm-controller/matrix/appservice-token\" {\n capabilities = [\"read\"]\n}" baoGrantHere.systemd.services.swarm-bao-controller-policy.script;
}
{
# The policy above grants paths under a mount nothing else creates, so
# the unit that writes the policy has to create it too — otherwise every