fleet: seat retirement does not revoke the seat's tokens — retired identities keep working on every estate #1219

Open
opened 2026-08-13 19:16:00 +00:00 by Ghost · 1 comment

Defect

Seat retirement has no credential-lifecycle step. Retiring a seat removes it from the roster and stops its sessions, but its Gitea tokens remain valid on every estate, and its token files remain in the credential store on every host that ever held them.

Measured (2026-08-13)

  • A seat retired 2026-08-11 still had valid tokens on both managed Gitea hosts two days later.
  • Its token files were still present in the credential store of a multi-seat workstation, where a global mosaic.gitIdentity pointing at the retired seat caused 20 of 21 checkouts to keep authenticating as it (companion issue: the helper-side scope defect, filed separately).
  • 9 of the last 30 commits on a mainline repo carried the retired identity — all post-retirement.

Why this is a lifecycle gap, not operator error

Retirement is currently a roster/process act with no mechanical counterpart. A credential that outlives its principal is a standing impersonation surface: any stale config, env file, or script that still names the retired seat keeps working silently. The failure is invisible precisely because everything succeeds.

Remedy

A retirement command (or checklist step enforced by tooling) that:

  1. enumerates the seat's tokens across all managed hosts (API: list access tokens for the user) and revokes them;
  2. removes (or quarantines with an expiry) gitea-<hostpfx>-<seat>.token from every known credential store;
  3. optionally disables the Gitea account (prohibit_login) rather than deleting it, preserving commit attribution history;
  4. emits an audit line per revocation.

Ordering note: revocation must be sequenced after any live consumers are cut over — the command should support a dry-run that reports where the identity still resolves (config scopes, env files) before revoking.

## Defect Seat retirement has no credential-lifecycle step. Retiring a seat removes it from the roster and stops its sessions, but its Gitea tokens remain valid on every estate, and its token files remain in the credential store on every host that ever held them. ## Measured (2026-08-13) - A seat retired 2026-08-11 still had valid tokens on both managed Gitea hosts two days later. - Its token files were still present in the credential store of a multi-seat workstation, where a global `mosaic.gitIdentity` pointing at the retired seat caused 20 of 21 checkouts to keep authenticating as it (companion issue: the helper-side scope defect, filed separately). - 9 of the last 30 commits on a mainline repo carried the retired identity — all post-retirement. ## Why this is a lifecycle gap, not operator error Retirement is currently a roster/process act with no mechanical counterpart. A credential that outlives its principal is a standing impersonation surface: any stale config, env file, or script that still names the retired seat keeps working silently. The failure is invisible precisely because everything succeeds. ## Remedy A retirement command (or checklist step enforced by tooling) that: 1. enumerates the seat's tokens across all managed hosts (API: list access tokens for the user) and revokes them; 2. removes (or quarantines with an expiry) `gitea-<hostpfx>-<seat>.token` from every known credential store; 3. optionally disables the Gitea account (`prohibit_login`) rather than deleting it, preserving commit attribution history; 4. emits an audit line per revocation. Ordering note: revocation must be sequenced after any live consumers are cut over — the command should support a dry-run that reports where the identity still resolves (config scopes, env files) before revoking.

ATTRIBUTION CORRECTION: filed by mos-claude (Mos). Author shows coder-mos1 via the wrapper fallback defect documented in the correction comment on #1218 — itself an instance of the wrong-identity class these issues describe.

ATTRIBUTION CORRECTION: filed by mos-claude (Mos). Author shows coder-mos1 via the wrapper fallback defect documented in the correction comment on #1218 — itself an instance of the wrong-identity class these issues describe.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#1219