From cf763da178936330ce75daf905185df57077a49a Mon Sep 17 00:00:00 2001 From: atlas Date: Mon, 12 Oct 2026 23:50:48 +0200 Subject: [PATCH] hive-github-notify: pick up a rotated PAT without a restart The poller read `/github-token` once at start, so after a PAT rotation it kept polling with the revoked token until the unit restarted. It now re-reads the file on every tick, as `hive-forge-notify` does: a different non-empty value rebuilds the GitHub source, clears the own-login cache, and logs one info line. A missing or empty file keeps the token in use. A 401 from the notifications endpoint is now logged at warn, once per token value; other non-2xx statuses stay at debug. Part of #5017 (slice G). --- docs/integrations/github.md | 3 +- docs/swarm/credentials.md | 2 +- .../src/bin/hive-github-notify/main.rs | 204 +++++++++++++++++- .../src/bin/hive-github-notify/source.rs | 34 ++- nix/agent-modules/github-token.nix | 3 +- 5 files changed, 230 insertions(+), 16 deletions(-) diff --git a/docs/integrations/github.md b/docs/integrations/github.md index 7dfb7a51..a63ef0cd 100644 --- a/docs/integrations/github.md +++ b/docs/integrations/github.md @@ -110,7 +110,8 @@ crate its build cache. At runtime the poller needs the PAT above. No PAT, no polling: the unit logs why and exits 0, which is why it's `Restart = on-failure` and never `always` — a clean exit on a PAT-less agent must not become a -restart loop. +restart loop. Once polling, it re-reads `/github-token` on every +tick, so it picks up a rotated PAT on the next tick without a restart. Forgejo models its notifications API on GitHub's, so one tolerant parse serves both: `id`, `repository.full_name`, diff --git a/docs/swarm/credentials.md b/docs/swarm/credentials.md index f9c24a2f..f1125789 100644 --- a/docs/swarm/credentials.md +++ b/docs/swarm/credentials.md @@ -66,7 +66,7 @@ of the cell says how. | `swarm/agents//queue` | `swarm-controller`, at agent creation | `hive-agent` in the agent container, under the agent's own certificate, held in memory — the identity it presents to the swarm queue, naming that one agent rather than its hive | ✅ `swarm-controller`'s five-minute pass re-mints a live agent's secret once it's 45 days old by `minted_at` on the stored object; a secret with no `minted_at` gets one stamped, value unchanged. The pass skips agents declared `Destroyed` — declaring an agent destroyed deletes every version of the path instead, the undo of the mint rather than another one | ✅ `hive-agent` reads the path before its first connect and again on every reconnect attempt, so a reconnect after a re-mint presents the new secret. An open connection keeps the secret it connected with; after a revocation the agent keeps retrying under the queue client's backoff | | `swarm/agents//forge-token` | `swarm-controller`, at agent creation and in a pass every 5 minutes over every agent with a store identity | the agent container itself, under its own certificate, fetched to `/run/hive-agent-forge-token/token` | ✅ the controller re-mints when the stored token is missing or no longer matches the forge (last eight characters and scopes) | ✅ the agent re-fetches on a 10-minute timer | | `swarm/agents//forge/