diff --git a/nix/host-modules/hive-forge/default.nix b/nix/host-modules/hive-forge/default.nix index 4367fd28..acc40610 100644 --- a/nix/host-modules/hive-forge/default.nix +++ b/nix/host-modules/hive-forge/default.nix @@ -1092,10 +1092,22 @@ in # re-mint instead of being silently masked by a stamp that # outlived what it claims exists. if [ ! -s "$token_path" ]; then + # `write:admin` added for `swarm-controller::forge::Client:: + # ensure_agent_user` (the `CreateForgeUser` jobq node) — + # Forgejo's `admin_create_user` HTTP endpoint refused every + # call with "token does not have at least one of required + # scope(s): [write:admin]" without it, an already-deployed + # swarm hitting this the moment that node shipped. A host + # whose token was minted before this scope was added won't + # pick it up automatically — the `[ ! -s "$token_path" ]` + # guard above only mints when the file is absent, by design + # (see its own comment) — so an existing deployment needs + # its token file deleted to force a re-mint with the new + # scope. out=$(forgejo admin user generate-access-token \ --username ${lib.escapeShellArg swarmControllerForgeUser} \ --token-name swarm-controller-boot \ - --scopes "write:repository,write:organization,write:issue,read:user") + --scopes "write:repository,write:organization,write:issue,read:user,write:admin") token=$(printf '%s' "$out" | grep -oE '[0-9a-f]{32,}' | head -n1) if [ -z "$token" ]; then echo "no token-shaped word in forgejo's generate-access-token output" >&2