fix(admin): queue two-person approval when Create Group grants authentik.* #63

Merged
james.maes merged 1 commits from fix/create-time-approval-20261106 into develop 2026-11-06 15:31:56 +00:00
Owner

What GG Forge observed

Running the published qbit-authentik 0.1.0-RC.8 with twoPersonApproval=true, the native Create Group action persisted a new group carrying authentik.users.read immediately, without queuing an authentik_approval_request. Edit Group already routed the same grant to a second person. Forge's live identity browser check now detects this, and Forge has been running a patched build to stay safe.

What the fix does

AuthentikAdmin.planCreateGroup now applies the existing identity-permission expansion and second-person condition (the same twoPersonApproval && !approved && addsIdentityPermission(...) gate and message as Edit Group). A creation whose permissions expand to any authentik.* permission becomes NEEDS_APPROVAL: nothing is written until a distinct operator holding authentik.approve approves it. Stored approvals keep the native requester/approver and live revalidation checks (approve re-plans against live data under the approver's own permissions). No pom version change; CHANGELOG [Unreleased] entry added.

Test evidence

  • New AuthentikAdminTest.creatingGroupWithIdentityPermissionsNeedsASecondPerson: queued result with no writes, exactly one approval request, self-approval refused (still no writes), second operator with approve + groups.manage succeeds, persisted group carries exactly authentik.users.read, request status APPROVED, repeat approval refused.
  • ./mvnw verify -DskipITs on this branch: 464 unit tests, 0 failures/errors/skips, JaCoCo coverage checks met, BUILD SUCCESS (AuthentikAdminTest: 39 tests). Contract ITs not run locally.
  • Checkstyle (repository checkstyle/config.xml, run explicitly since the pom does not bind it): 176 violations, all pre-existing; none in the changed lines.
  • Forge's own evidence against RC.8: the regression fails on original RC.8 and passes patched; full patched unit suite and the 55-test Docker integration suite passed there.

Carried locally by GG Forge as qbit-authentik-rc8-create-approval.patch since RC.8; merging this lets Forge drop the patched build at the next RC.

🤖 Generated with Claude Code

## What GG Forge observed Running the published `qbit-authentik` 0.1.0-RC.8 with `twoPersonApproval=true`, the native **Create Group** action persisted a new group carrying `authentik.users.read` immediately, without queuing an `authentik_approval_request`. **Edit Group** already routed the same grant to a second person. Forge's live identity browser check now detects this, and Forge has been running a patched build to stay safe. ## What the fix does `AuthentikAdmin.planCreateGroup` now applies the existing identity-permission expansion and second-person condition (the same `twoPersonApproval && !approved && addsIdentityPermission(...)` gate and message as Edit Group). A creation whose permissions expand to any `authentik.*` permission becomes `NEEDS_APPROVAL`: nothing is written until a distinct operator holding `authentik.approve` approves it. Stored approvals keep the native requester/approver and live revalidation checks (`approve` re-plans against live data under the approver's own permissions). No pom version change; CHANGELOG `[Unreleased]` entry added. ## Test evidence - New `AuthentikAdminTest.creatingGroupWithIdentityPermissionsNeedsASecondPerson`: queued result with no writes, exactly one approval request, self-approval refused (still no writes), second operator with `approve` + `groups.manage` succeeds, persisted group carries exactly `authentik.users.read`, request status `APPROVED`, repeat approval refused. - `./mvnw verify -DskipITs` on this branch: 464 unit tests, 0 failures/errors/skips, JaCoCo coverage checks met, BUILD SUCCESS (AuthentikAdminTest: 39 tests). Contract ITs not run locally. - Checkstyle (repository `checkstyle/config.xml`, run explicitly since the pom does not bind it): 176 violations, all pre-existing; none in the changed lines. - Forge's own evidence against RC.8: the regression fails on original RC.8 and passes patched; full patched unit suite and the 55-test Docker integration suite passed there. Carried locally by GG Forge as `qbit-authentik-rc8-create-approval.patch` since RC.8; merging this lets Forge drop the patched build at the next RC. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
james.maes added 1 commit 2026-11-06 14:40:41 +00:00
fix(admin): queue two-person approval when Create Group grants authentik.*
QRun-IO/ci-policy: ci / fork-guard (pull_request) Skipped
QRun-IO/ci-policy: native / fork-deny (pull_request) Skipped
QRun-IO/ci-policy: native / dotnet-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / Scoped workflow [workflow 1e25bb5a243dfdcd95d4b9a4f780200ff8c8778a] (pull_request) Successful in 6s
QRun-IO/ci-policy: ci / head-profile (pull_request) Skipped
QRun-IO/ci-policy: ci / repository-policy (pull_request) Skipped
QRun-IO/ci-policy: ci / application-template-0 (pull_request) Skipped
QRun-IO/ci-policy: native / native-result (pull_request) Successful in 5s
QRun-IO/ci-policy: ci / gradle-1 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-core-2-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-3 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-3-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-4 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-frontend-browser-5 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-6 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-6-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-7 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-7-head (pull_request) Skipped
QRun-IO/ci-policy: ci / node-8 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-9 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-10 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-playwright-11 (pull_request) Skipped
QRun-IO/ci-policy: ci / repository-policy-12 (pull_request) Skipped
QRun-IO/ci-policy: ci / source-config-13 (pull_request) Skipped
QRun-IO/ci-policy: ci / source-config-14 (pull_request) Skipped
QRun-IO/ci-policy: ci / android-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / original-business (pull_request) Skipped
QRun-IO/ci-policy: ci / original-mcp (pull_request) Skipped
QRun-IO/ci-policy: ci / original-voyage (pull_request) Skipped
QRun-IO/ci-policy: ci / original-cli (pull_request) Skipped
QRun-IO/ci-policy: ci / not-enrolled (pull_request) Skipped
QRun-IO/ci-policy: ci / shared-pipeline (pull_request) Skipped
QRun-IO/ci-policy: ci / ci-result (pull_request) Successful in 5s
maven / build (push) Failing after 31m34s
build / maven (push) Failing after 31m34s
53bc414490
With twoPersonApproval=true, the native Create Group action persisted a
new group carrying authentik.* permissions (for example
authentik.users.read) immediately, while Edit Group queued an
authentik_approval_request for a second person. Apply the same
identity-permission expansion and second-person condition at creation
time: the plan becomes NEEDS_APPROVAL and nothing is written until a
distinct operator holding authentik.approve approves it; the stored
request keeps the native requester/approver and live revalidation
checks.

Regression test: creating a group with authentik.users.read queues one
approval request and writes nothing, self-approval is refused, a second
operator with approve + groups.manage completes the creation, the
persisted group carries exactly the requested permission, the request is
APPROVED, and a repeat approval is refused.

Carried locally by GG Forge as qbit-authentik-rc8-create-approval.patch
since 0.1.0-RC.8.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
james.maes merged commit 4d45796651 into develop 2026-11-06 15:31:56 +00:00
Sign in to join this conversation.