feat: v1 - full user lifecycle and group/permission management (phases 2-3) #12

Merged
KofTwentyTwo merged 5 commits from feature/v1-lifecycle into develop 2026-10-12 23:18:35 +00:00
KofTwentyTwo commented 2026-10-12 21:59:03 +00:00 (Migrated from github.com)

Moves the Authentik qbit to its v1: the full user lifecycle and management of groups and permissions, inside QQQ (spec QRun-IO/qqq#1065, revision 4; owner decisions of 2026-10-12: all recommendations accepted). Builds on the merged rename PR #6.

What is built

  • Writes through the Authentik API (never its DB), behind the features USERS, GROUPS, MEMBERSHIP, CREDENTIALS, SESSIONS. Read-only stays the default; readOnly is a hard kill switch.
  • Actions as standard streamed-ETL table and record actions (Review = dry run, then Result), never in the nav: Create User, Invite User, Edit User, Deactivate/Reactivate User, Add To Group, Remove From Group, Send Password Reset Email, Reset MFA, Revoke App Passwords, Revoke Sessions, Create Group, Edit Group, Edit Permissions And App Access, Add/Remove Members, Cancel Invitation, Approve And Apply, Reject.
  • Safety (spec 5.4), checked at Review and again at execute, against live Authentik data and the operator's live groups (not the session claim): subset (no escalation) rule, protected accounts and superuser groups, no self-edits, last-administrator protection, reasons, typed confirmations (and a typed count above 25), a 100-target cap, stale checks by fingerprint, attribute edits that merge only the qqq.io/* keys into the current attributes, and two-person approval for granting authentik.*.
  • Audit: authentik_admin_action row written before the call (no row, no call), plus an Authentik custom_qqq_admin_action event naming the human operator. authentik_approval_request for second-person requests. DDL in docs/schema.sql.
  • Screens: the authentikHome dashboard (needs attention, people, groups and permissions, recent changes, connection), the main tables in the nav, and sessions, tokens (never a key), events, bindings, roles, blueprints, memberships as child lists on their parents. New read tables: application, policy_binding, blueprint, role, token, invitation.
  • Only AuthentikAdmin can change Authentik: AuthentikActionUtil.write needs a WriteAuthorization that only AuthentikGuard.authorize can mint (an architecture test pins the call sites).

Fixes found on the way

  • A client count returned no distinct count, so process Reviews showed no total; group lists now carry member pks.
  • Contract tests showed: recovery_email needs the brand to have a recovery flow, plus the role's add_user (DRF maps POST to add), reset_user_password and view_emailstage; MFA devices come back as a bare array. All documented in the README and the owner checklist (new item 12).

Not in this PR (listed in docs/STATUS.md)

The Authentik webhook/ESB trigger/inbox, the local mirror tables and reconcile, the access-matrix and group-tree widgets (need Next UI widgets), snapshot export, RBAC (phase 4), the Alerts producer integration (QRun-IO/qqq#1090). Users and groups are API-backed, so Quick Search is the table's own live search.

Tests

CI=true ./mvnw verify: 128 unit tests (rules on an in-memory Authentik, processes through RunProcessAction, app and home) and 40 contract tests on Authentik 2026.8.3 (9 new write tests: user create with the recovery email arriving in Mailpit, memberships, permission-attribute merge, group create/edit, deactivate with app-password revocation that spares API tokens, edit user, password reset, invite/cancel, MFA reset), all green; checkstyle and the JaCoCo gate pass.

🤖 Generated with Claude Code

Moves the Authentik qbit to its v1: the full user lifecycle and management of groups and permissions, inside QQQ (spec QRun-IO/qqq#1065, revision 4; owner decisions of 2026-10-12: all recommendations accepted). Builds on the merged rename PR #6. ## What is built - **Writes through the Authentik API** (never its DB), behind the features `USERS`, `GROUPS`, `MEMBERSHIP`, `CREDENTIALS`, `SESSIONS`. Read-only stays the default; `readOnly` is a hard kill switch. - **Actions** as standard streamed-ETL table and record actions (Review = dry run, then Result), never in the nav: Create User, Invite User, Edit User, Deactivate/Reactivate User, Add To Group, Remove From Group, Send Password Reset Email, Reset MFA, Revoke App Passwords, Revoke Sessions, Create Group, Edit Group, Edit Permissions And App Access, Add/Remove Members, Cancel Invitation, Approve And Apply, Reject. - **Safety** (spec 5.4), checked at Review and again at execute, against live Authentik data and the operator's live groups (not the session claim): subset (no escalation) rule, protected accounts and superuser groups, no self-edits, last-administrator protection, reasons, typed confirmations (and a typed count above 25), a 100-target cap, stale checks by fingerprint, attribute edits that merge only the `qqq.io/*` keys into the current attributes, and two-person approval for granting `authentik.*`. - **Audit**: `authentik_admin_action` row written before the call (no row, no call), plus an Authentik `custom_qqq_admin_action` event naming the human operator. `authentik_approval_request` for second-person requests. DDL in `docs/schema.sql`. - **Screens**: the `authentikHome` dashboard (needs attention, people, groups and permissions, recent changes, connection), the main tables in the nav, and sessions, tokens (never a key), events, bindings, roles, blueprints, memberships as child lists on their parents. New read tables: application, policy_binding, blueprint, role, token, invitation. - Only `AuthentikAdmin` can change Authentik: `AuthentikActionUtil.write` needs a `WriteAuthorization` that only `AuthentikGuard.authorize` can mint (an architecture test pins the call sites). ## Fixes found on the way - A client count returned no distinct count, so process Reviews showed no total; group lists now carry member pks. - Contract tests showed: `recovery_email` needs the brand to have a recovery flow, plus the role's `add_user` (DRF maps POST to add), `reset_user_password` and `view_emailstage`; MFA devices come back as a bare array. All documented in the README and the owner checklist (new item 12). ## Not in this PR (listed in docs/STATUS.md) The Authentik webhook/ESB trigger/inbox, the local mirror tables and reconcile, the access-matrix and group-tree widgets (need Next UI widgets), snapshot export, RBAC (phase 4), the Alerts producer integration (QRun-IO/qqq#1090). Users and groups are API-backed, so Quick Search is the table's own live search. ## Tests `CI=true ./mvnw verify`: 128 unit tests (rules on an in-memory Authentik, processes through `RunProcessAction`, app and home) and 40 contract tests on Authentik 2026.8.3 (9 new write tests: user create with the recovery email arriving in Mailpit, memberships, permission-attribute merge, group create/edit, deactivate with app-password revocation that spares API tokens, edit user, password reset, invite/cancel, MFA reset), all green; checkstyle and the JaCoCo gate pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.