feat(mcp): admin account-lifecycle UI, instances unreadable #125

Merged
Claude-Run merged 1 commit from feat/YT-71-admin-account-lifecycle into main 2026-07-17 18:27:44 +02:00
Member

Rebuild the admin surface around the local-account lifecycle (YT-69 dropped the Hub allowlist this replaces). GET /admin and GET /admin/accounts render one account-lifecycle view listing every account with email, status, admin flag, TOTP state, created-at, and a connected boolean. Per-account actions are ban, unban, force-logout, reset second factor, and delete; every route is gated on is_admin and rejects a banned admin through the existing require_admin gate.

The product boundary is that an administrator must not see which YouTrack instance a user has configured. This is enforced at the query layer, not in a handler or template filter: the admin list is built by list_admin_account_rows, whose SELECT computes only EXISTS(youtrack_instances) as a boolean and never projects base_url or token_enc. A column that is never selected cannot leak into a view. A regression test drives an account that has both a base URL and a token configured and asserts no admin response contains either, while the connected column still reads yes.

Force-logout revokes the account's app-issued access and refresh tokens and invalidates its browser session without banning it. The browser session is a stateless signed cookie with no server-side row, so it is revoked by advancing a new session_epoch on the account (migration 0005): the session stamps the epoch it was minted at, and current_account accepts it only while the two still match. force_logout_account bumps the epoch and revokes both token kinds in one transaction; the account stays active and signs back in to mint a fresh session at the new epoch.

An admin cannot ban or delete their own account, so a deployment cannot be left with no administrator and no recovery short of database surgery. Reset second factor clears the TOTP secret, enrolment, spent-step marker, and recovery codes so a user who lost their authenticator can sign in with the password alone and re-enrol.

#YT-71

Rebuild the admin surface around the local-account lifecycle (YT-69 dropped the Hub allowlist this replaces). `GET /admin` and `GET /admin/accounts` render one account-lifecycle view listing every account with email, status, admin flag, TOTP state, created-at, and a connected boolean. Per-account actions are ban, unban, force-logout, reset second factor, and delete; every route is gated on `is_admin` and rejects a banned admin through the existing `require_admin` gate. The product boundary is that an administrator must not see which YouTrack instance a user has configured. This is enforced at the query layer, not in a handler or template filter: the admin list is built by `list_admin_account_rows`, whose SELECT computes only `EXISTS(youtrack_instances)` as a boolean and never projects `base_url` or `token_enc`. A column that is never selected cannot leak into a view. A regression test drives an account that has both a base URL and a token configured and asserts no admin response contains either, while the connected column still reads yes. Force-logout revokes the account's app-issued access and refresh tokens and invalidates its browser session without banning it. The browser session is a stateless signed cookie with no server-side row, so it is revoked by advancing a new `session_epoch` on the account (migration 0005): the session stamps the epoch it was minted at, and `current_account` accepts it only while the two still match. `force_logout_account` bumps the epoch and revokes both token kinds in one transaction; the account stays active and signs back in to mint a fresh session at the new epoch. An admin cannot ban or delete their own account, so a deployment cannot be left with no administrator and no recovery short of database surgery. Reset second factor clears the TOTP secret, enrolment, spent-step marker, and recovery codes so a user who lost their authenticator can sign in with the password alone and re-enrol. #YT-71
feat(mcp): admin account-lifecycle UI, instances unreadable
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 1m13s
Create release / Create release from merged PR (pull_request) Has been skipped
c09e026fdb
Rebuild the admin surface around the local-account lifecycle (YT-69 dropped the Hub allowlist this replaces). `GET /admin` and `GET /admin/accounts` render one account-lifecycle view listing every account with email, status, admin flag, TOTP state, created-at, and a connected boolean. Per-account actions are ban, unban, force-logout, reset second factor, and delete; every route is gated on `is_admin` and rejects a banned admin through the existing `require_admin` gate.

The product boundary is that an administrator must not see which YouTrack instance a user has configured. This is enforced at the query layer, not in a handler or template filter: the admin list is built by `list_admin_account_rows`, whose SELECT computes only `EXISTS(youtrack_instances)` as a boolean and never projects `base_url` or `token_enc`. A column that is never selected cannot leak into a view. A regression test drives an account that has both a base URL and a token configured and asserts no admin response contains either, while the connected column still reads yes.

Force-logout revokes the account's app-issued access and refresh tokens and invalidates its browser session without banning it. The browser session is a stateless signed cookie with no server-side row, so it is revoked by advancing a new `session_epoch` on the account (migration 0005): the session stamps the epoch it was minted at, and `current_account` accepts it only while the two still match. `force_logout_account` bumps the epoch and revokes both token kinds in one transaction; the account stays active and signs back in to mint a fresh session at the new epoch.

An admin cannot ban or delete their own account, so a deployment cannot be left with no administrator and no recovery short of database surgery. Reset second factor clears the TOTP secret, enrolment, spent-step marker, and recovery codes so a user who lost their authenticator can sign in with the password alone and re-enrol.

#YT-71
Claude-Run deleted branch feat/YT-71-admin-account-lifecycle 2026-07-17 18:27:44 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
pandoras-box/youtrack-cli!125
No description provided.