hives read the forge through their own swarm-minted read account
swarm-controller now gives every hive in its directory a forge account, `hive-<hive>`, in a new `hives` team of `agent-configs` (read on `repo.code` + `repo.pulls`, every repo including later ones), and mints one `read:repository` token named `swarm-hive` into the store at `swarm/hives/<hive>/forge/token`. A five-minute pass queues a `MintHiveForgeToken` node for a hive whose token is missing or no longer matches the forge, whose account is missing, or whose team membership or team settings drifted. A hive whose store or forge read failed is never queued, so an outage cannot rotate every hive's token. The token decision reuses `agent_token`'s classifier and replace step, now parameterised by name and scopes. An agent may be called `hive-<x>`. The hive account is created with `hive-<hive>@hives.hyperhive.local` and the job refuses an account by that name with any other email before it locks it down, adds it to the team or mints for it; agent creation already refuses the hive's account by the same email check. The controller's bao policy gains the `swarm/hives/+/forge/token` leaf (create/read/update), pinned by the bao-grants module-eval assertion. The hive's own policy already reads `swarm/hives/<hive>/*`. hive-c0re reads that token through `forge::reader_token()`, falling back to the core token file when the store holds none, and uses it for: fetching a merged config rev (swarm deploy, `hivectl forge reconcile-config`), reseeding a purged `applied`, the meta-update cascade's fast-forward, seeding `proposed` on first deploy, and finding the PR that merged a refused rev. Those reads no longer require a local `hive-forge` container. The `/knowledge` clone moves from the forge host's boot sweep into the knowledge pull, so every hive clones it. Posting the deploy-failure comment on that PR stays on the core token. Refs #4851
This commit is contained in:
parent
c8472966e9
commit
21e3f626f4
17 changed files with 1222 additions and 138 deletions
|
|
@ -429,6 +429,10 @@ let
|
|||
capabilities = ["create", "read", "update"]
|
||||
}
|
||||
|
||||
path "${credentialMountPath}/data/swarm/hives/+/forge/token" {
|
||||
capabilities = ["create", "read", "update"]
|
||||
}
|
||||
|
||||
path "${credentialMountPath}/data/${ciRunnerTokenLeaf}" {
|
||||
capabilities = ["create", "update"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1299,17 +1299,19 @@ let
|
|||
lib.hasInfix "path \"secret/data/swarm/agents/*\" {\n capabilities = [\"create\", \"read\", \"update\"]" s;
|
||||
}
|
||||
{
|
||||
# `matrix_account::hive_sender` writes every hive's sender token, and
|
||||
# nothing else under `hives/`, where each hive's queue credential also
|
||||
# lives. `+` is one segment, which keeps this to the one leaf; a `*` is a
|
||||
# glob only at the end of a path. Pinned as the whole stanza, so an
|
||||
# added capability fails.
|
||||
name = "the controller writes each hive's sender token and nothing else under hives";
|
||||
# `matrix_account::hive_sender` writes every hive's sender token and
|
||||
# `forge::hive_token` every hive's forge token, and nothing else under
|
||||
# `hives/`, where each hive's queue credential also lives. `+` is one
|
||||
# segment, which keeps each stanza to its one leaf; a `*` is a glob only
|
||||
# at the end of a path. Pinned as whole stanzas, so an added capability
|
||||
# fails.
|
||||
name = "the controller writes each hive's sender and forge tokens and nothing else under hives";
|
||||
ok =
|
||||
let
|
||||
s = baoGrantHere.systemd.services.swarm-bao-controller-policy.script;
|
||||
in
|
||||
lib.hasInfix "path \"secret/data/swarm/hives/+/matrix/sender-token\" {\n capabilities = [\"create\", \"read\", \"update\"]\n}" s
|
||||
&& lib.hasInfix "path \"secret/data/swarm/hives/+/forge/token\" {\n capabilities = [\"create\", \"read\", \"update\"]\n}" s
|
||||
&& !(lib.hasInfix "secret/data/swarm/hives/*" s)
|
||||
&& !(lib.hasInfix "secret/metadata/swarm/hives" s);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue