Files
james.maesandClaude Sonnet 5.5 33e75b6d45
maven / build (push) Failing after 1m43s
build / maven (push) Failing after 1m43s
test(policy): golden vectors, Deny properties, consumer tests; blueprint, changelog, upgrade notes
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-08 18:09:24 -06:00

7.3 KiB

Upgrading qbit-authentik

Policy format 1.1.0 (unreleased)

  1. The default PolicyVersion is 1.1.0. Documents stored as 1.0.0 stop parsing (they grant nothing, and one invalid document voids ALL of a user's policies). Either rewrite the stored documents and the claim expression to 1.1.0, or keep policyVersion("1.0.0") in the config and the claim expression.
  2. The example claim blueprint now emits a document the qbit rejects when any of a user's documents under your spec is unparsable, has another version or has a non-array Statement. Update the blueprint copy in your identity repository, and run src/test/resources/policy-vectors-1.1.0.json against any claim validator you own.
  3. Code that read PolicyParser.parse/parseStrict(...).permissions() or GroupGraph.Node.policyPermissions() must move to PolicyRules (resolve(universe), hasFullAccess(), denyLabels()); there is deliberately no plain-name view of a Deny.
  4. Hosts that keep custom or service permission names (email.send, echo.use) declare them with PolicyPermissions.registerHostPermissions(qInstance -> names); no Authentik runtime is needed. They are granted only through Permission: [...].
  5. The Next UI policy editor payloads gain denied (policy editor widget) and policyFullAccess, policyDeny, policyInvalid (access editor widget); policyPermissions is now the resolved list (Allow minus Deny), never the internal full-access marker.

Table help bundle (unreleased)

Nothing to do. The qbit now applies help/qbit-authentik.yaml to the Identity app and its tables at the end of produce(), filling only help slots the host has not set. There is no schema change and nothing to seed or include in a Liquibase changelog: the API-backed tables are live Authentik data, and the four local tables fill as people use the actions.

QQQ 4.1.0-RC.6 baseline (#20 / F19)

Hosts should align their QQQ dependencies with the released qqq-bom-pom:4.1.0-RC.6 and use Java 21. The historical qqq-snapshot profile and qqq.snapshot.version property names remain, but the imported core version is a release, not a SNAPSHOT. Core actions now enforce permissions and field security locks for non-HTTP callers (QRun-IO/qqq#1061, #1062); callers must supply an appropriately authorized session. The qbit keeps its guards, scope checks and sensitive-field stripping because they also protect direct backend calls and implement Authentik-specific rules. No qbit configuration, stored policy format or schema changes are introduced.

The build adopts qbit-build-parent:2.1.0 with qbit.guardrails.enforce=true. The expired #1136 test stand-in is removed: tests now register features through TableFeaturePermissionsMetaData and discover them through the real PermissionsHelper.getAllAvailablePermissions, as production hosts do. The unused explicit permission-source overload in PolicyCatalog is removed. Duplicate shared-base entries, replacement registrations and malformed suffixes remain covered. Hosts should register feature suffixes, labels and table applicability through the core metadata API; no synthetic catalog is needed. Client-channel attribution and identity/credential channel restrictions remain separate follow-up work.

Permissions renamed identity.* → authentik.* (unreleased → first release)

The qbit's permissions follow the same owner naming rule (2026-10-12) and now carry the qbit's name. The suffixes are unchanged:

Before After
identity.* authentik.*
identity.users.read authentik.users.read
identity.users.manage authentik.users.manage
identity.groups.manage authentik.groups.manage
identity.memberships.manage authentik.memberships.manage
identity.permissions.manage authentik.permissions.manage
identity.roles.manage authentik.roles.manage
identity.credentials.reset authentik.credentials.reset
identity.sessions.revoke authentik.sessions.revoke
identity.audit.read authentik.audit.read
identity.approve authentik.approve
identity.admin authentik.admin

The QQQ session form is the new name plus .hasAccess (authentik.users.read.hasAccess).

Legacy names are not granted. The resolver lists an old identity.* name among a group's unknown permissions, so it grants nothing and fails closed. Update every stored grant before you deploy, or the admins lose the Identity app until you do:

  • Authentik group attributes: edit qqq.io/permissions on each group, for example identity-admins, in the Authentik UI (Directory → Groups → Attributes) or in its blueprint. Replace identity. with authentik.:

    attributes:
      qqq.io/permissions:
        - authentik.*            # was identity.*
    

    To find the groups that still carry old names, run the drift report. Its "group attributes" check warns about each identity.* entry ("grants nothing in this app").

  • QQQ-side grants: these are static fallbacks in AuthentikGroupPermissionMapper, host permission lists and role tables. If a host stores permission names in a table:

    -- example only: use your host's table and column names
    UPDATE role_permission
       SET permission_name = REPLACE(permission_name, 'identity.', 'authentik.')
     WHERE permission_name LIKE 'identity.%';
    

    The qbit itself stores no grants in a database. qqq_user_session rows hold resolved permissions, so sign users out (or let their sessions expire) after the change.

  • Code that names identity.* strings. Use IdentityPermission instead. IdentityPermission.LEGACY_PREFIX, LEGACY_WILDCARD and getLegacyShortName() (all deprecated) give the old names for upgrade scripts.

The identity-admins group name and the "Identity" app label are unchanged.

Snake_case table names (unreleased → first release)

Table names now follow the owner naming rule (2026-10-12): lowercase snake_case, prefixed with the qbit's name and _.

Before After
authentikUser authentik_user
authentikGroup authentik_group
authentikGroupMember authentik_group_member
authentikSession authentik_session
authentikEvent authentik_event

With a custom tableNamePrefix the prefix is snake-cased too: myAuth gives my_auth_user. App, widget, backend and process names keep camelCase (authentikAdmin, authentikDriftReport, authentikApi).

The tables are API-backed, so there is no database DDL. Hosts that ran a pre-release snapshot should update anything that stores a table name:

  • Permissions: grants or role definitions that name a table (for example table-level permission names derived from the table name) and any host code calling qInstance.getTable("authentikUser").
  • Saved views and reports: rows whose table name is an old name, for example UPDATE saved_view SET table_name = 'authentik_user' WHERE table_name = 'authentikUser'; (and the same for saved reports and any shared/favorite records).
  • Audit: audit_table.name rows for the old names, if the host audits these tables (rename them, or leave history under the old name).
  • Frontend links and bookmarks of the form /…/authentikUser/….

AuthentikTables.LEGACY_*_TABLE_NAME hold the old names (deprecated) so upgrade scripts can find them.