gateway: user revocation as the third kill switch (UserDetail + People) - #1694
Merged
Merged
Conversation
The dashboard already has per-run and per-agent kill switches; this adds the user axis on top of the existing revoke_user_before cutoff. Backend - /_plugin/revoke/user/:id (PUT/GET/DELETE) moves from bearer-only to cookie-or-bearer with CSRF on cookie mutations, the same posture as the kill routes. /_plugin/revoke/nonce/* stays bearer-only; server.go splits the prefix. - New GET /_plugin/revoke/users lists every cutoff on the swarm, newest first, from a revoke_users ZSET index that SetUserRevokeCutoff / ClearUserRevokeCutoff maintain. The per-user string key stays authoritative: the list re-reads it and prunes index members whose key is gone, so direct Redis DELs self-heal. - user_id is validated like the kill ids (no whitespace or '/'). UI - UserDetail: header badge, Authorization card (cutoff + effect), and a Revoke user / Clear revoke switch with typed confirmation. The modal spells out the blast radius from /users/:id/quota's in-flight list while open. - People: a Revoked column from one /revoke/users read. - KillConfirmModal grows a "user" target; apiFetch accepts PUT. Tests: cookie+CSRF accepted on user routes, 403 without CSRF, nonce routes still 401 on a cookie, list ordering, method guard, index self-heal (adminapi + auth packages). Docs: phase-6 schema/status, phase-9 users views + endpoint table, ui/AGENTS.md.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds the user axis to the dashboard's kill switches, next to run and agent, on top of the existing phase-6
revoke_user_before:<user_id>cutoff.Setting the cutoff makes the hot path reject every macaroon whose user authorization was issued before it: all of the user's in-flight runs, whatever agent carries them, and every new spawn under the current authorization, until Hive issues a fresh one. Per swarm, no TTL,
DELETEclears.Backend
PUT|GET|DELETE /_plugin/revoke/user/:idmove from bearer-only to cookie-or-bearer (CSRF header on cookie mutations), the same posture as the kill routes./_plugin/revoke/nonce/*stays bearer-only;server.gosplits the prefix.GET /_plugin/revoke/users: every cutoff on the swarm, newest first, from abifrost:revoke_usersZSET index maintained bySetUserRevokeCutoff/ClearUserRevokeCutoff. The per-user string key stays authoritative: the list re-reads it and prunes index members whose key is gone (direct Redis DELs self-heal). Hive's reconcile sweep can read this per swarm.user_idis validated like the kill ids.UI
/users/:id/quota's in-flight list, fetched only while open. Copy says "authorizations issued before the cutoff are rejected" rather than "revoked", because after Hive re-issues the cutoff is still set and still true./revoke/usersread.KillConfirmModalgrows ausertarget;apiFetchacceptsPUT.Docs
phase-6 schema + status note, phase-9 users views + endpoint table,
ui/AGENTS.md.Tests
go test ./internal/...green;make tygoregeneratedtypes.ts;npm run typecheck+npm run buildclean.Verified in the browser
Against a Node mock of the routes the two pages touch (same recipe as #1685): People renders the column, UserDetail opens the typed modal with the blast-radius line, revoke flips badge/card/button and the People badge, clear flips them back. Not yet run against a real gateway + Redis.
Caveats
enforce_macaroonsis on; shadow mode logs.