swarm-controller: sweep agents' legacy hyperhive-* forge tokens at start
Before b5d07d4d, hive-c0re minted a new `hyperhive-<unix-seconds>` token
for an agent on every spawn and rebuild and never revoked one, so every
live agent's forge user carries a pile of write-scoped tokens nothing
holds. Nothing in the tree lists or deletes them.
On each start, swarm-controller now walks the store's hive-agent-*
roster (the one the swarm-agent mint pass walks), and for every agent
whose swarm-agent token that pass would keep, deletes each token named
exactly `hyperhive-<digits>`. It logs the count per agent and a total.
- `core` is refused by name in both the roster filter and the per-user
delete: hive-c0re still names core's live admin token
`hyperhive-<unix-seconds>`.
- An agent whose swarm-agent token is not current is skipped, because
consumers fall back to `<state>/forge-token`, the last hyperhive-*
token, until the swarm token is fetched.
- A failed list or delete is logged and skipped; the sweep does not
retry and never blocks startup. A second start deletes nothing.
Tokens on forge users of agents no longer on the store roster (already
destroyed) are not reached.
Closes #4644
This commit is contained in:
parent
41d66e2e05
commit
23e0c313b8
4 changed files with 368 additions and 5 deletions
|
|
@ -27,7 +27,7 @@ use super::Client;
|
|||
/// The forge's name for every agent token this module mints.
|
||||
///
|
||||
/// Deliberately not `hyperhive-…`: that prefix is what `hive-c0re` named each
|
||||
/// of its re-mints, and a later sweep of those must never match this one.
|
||||
/// of its re-mints, and [`super::legacy_tokens`] deletes those.
|
||||
pub const AGENT_TOKEN_NAME: &str = "swarm-agent";
|
||||
|
||||
/// The scopes an agent token carries. Byte-identical to the `TOKEN_SCOPES`
|
||||
|
|
@ -167,7 +167,7 @@ pub(super) fn is_not_found(e: &ForgejoError) -> bool {
|
|||
impl Client {
|
||||
/// Every access token the forge lists for `agent`, or `None` when the
|
||||
/// forge has no such user.
|
||||
async fn list_agent_tokens(&self, agent: &str) -> Result<Option<Vec<AccessToken>>> {
|
||||
pub(super) async fn list_agent_tokens(&self, agent: &str) -> Result<Option<Vec<AccessToken>>> {
|
||||
match self.api.admin_list_user_access_tokens(agent).all().await {
|
||||
Ok(tokens) => Ok(Some(tokens)),
|
||||
Err(e) if is_not_found(&e) => Ok(None),
|
||||
|
|
@ -270,7 +270,7 @@ impl Client {
|
|||
}
|
||||
|
||||
/// What the forge and the store say about `agent`'s token.
|
||||
async fn observe_agent(
|
||||
pub(super) async fn observe_agent(
|
||||
&self,
|
||||
store: &swarm_secret_client::SecretStore,
|
||||
agent: &str,
|
||||
|
|
|
|||
Loading…
Reference in a new issue