Merge develop into release/0.1 (policy format 1.1.0, RC.10) #70

Merged
james.maes merged 17 commits from merge/develop-into-release-0-1-rc10 into release/0.1 2026-11-09 03:31:24 +00:00
Owner

Brings develop (policy format 1.1.0 with Deny, prefix wildcards, named permissions; PR 69, four independent fail-open reviews, Gitea CI green) into release/0.1. The committed revision is already 0.1.0-RC.10, so merging this publishes 0.1.0-RC.10.

Note for hosts: documents stored as 1.0.0 stop parsing (see UPGRADE.md); the typed PolicyResult API replaces the Set-returning fromClaims for session assembly.

🤖 Generated with Claude Code

Brings develop (policy format 1.1.0 with Deny, prefix wildcards, named permissions; PR 69, four independent fail-open reviews, Gitea CI green) into release/0.1. The committed revision is already 0.1.0-RC.10, so merging this publishes 0.1.0-RC.10. Note for hosts: documents stored as 1.0.0 stop parsing (see UPGRADE.md); the typed PolicyResult API replaces the Set-returning fromClaims for session assembly. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
james.maes added 16 commits 2026-11-09 03:01:52 +00:00
docs(policy): specify format 1.1.0 (Deny, prefix wildcards, named permissions)
maven / build (push) Failing after 45s
build / maven (push) Failing after 45s
6f9ec41f35
Spec and shared golden vectors only; no parser change yet.

- Effect Allow|Deny; result = union(Allow) minus union(Deny) across all of
  a user's groups, Deny wins, no ordering, expanded against the live
  instance so a Deny also covers future resources.
- Prefix resources (utils_*): at least two characters, literal part ends in
  an underscore, wildcard last. Deny with Action * means every action
  including features; Allow with Action * stays the five standard actions.
- Permission[] key for exact dotted/host permission names under Allow and
  Deny, so Deny can remove what full access includes.
- Zero-match prefix, feature or named permission is rejected at save for
  both effects. Unknown statement keys (Condition) reject the document.
- One invalid document among a user's groups voids all of them: dropping a
  bad group could drop a Deny and escalate access.
- Canonicalization never drops a Deny.
- policy-vectors-1.1.0.json: 27 vectors over a 16-name universe, to be run
  by this parser, the authentik-cd claim validator and Forge's tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Permission names are dot-separated segments of [A-Za-z0-9_-] (bare names
allowed); Resource stays [A-Za-z0-9_]+ and utils_* prefixes. Every Allow
expands against one universe, host names are not features, a standard action
a resource lacks is dropped, and the claim is one merged document.
New vectors: hyphenated and bare Permission names, invalid names, hyphenated
Resource, host name as Action, dropped action, not-in-universe name.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
PolicyParser returns typed PolicyRules (Allow and Deny terms, or void) instead
of permission names, so a Deny or prefix cannot be read as a grant. Result =
union(Allow) minus union(Deny) across all of a user's groups; one invalid
policy voids every group of the user. Allow expands against one live universe;
Deny is a predicate. Canonicalization never drops a Deny. Editor: save-time
zero-match checks, effective-permission subset rule, release of Deny on
removal, last-admin check. Host names register without an Authentik runtime;
PolicyCatalog is cached per QInstance. Default PolicyVersion is 1.1.0.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
test(policy): golden vectors, Deny properties, consumer tests; blueprint, changelog, upgrade notes
maven / build (push) Failing after 1m43s
build / maven (push) Failing after 1m43s
33e75b6d45
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Deny of a prefix or named resource covers its dotted host names; empty
Resource/Action/Permission arrays reject; the blueprint voids on any document
under the attribute that is not exactly our spec (skipping other specs is an
opt-in) and on duplicate keys. Spec: what a Deny subtracts, void is not empty,
operators, host customizer API, blueprint known differences.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
fix(policy): close fail-open edges found in review
maven / build (push) Failing after 1m26s
build / maven (push) Failing after 1m25s
a6ac960f3a
Operator credit never includes a name their own policies deny; the configured
policy attribute is reserved against attribute edits; un-voiding an invalid
policy is a release; a deliberate Deny no longer trips the cut-over guard and
void is shown; a group missing from the graph voids; PolicyResult typed API
with apply(); Deny of a prefix covers dotted host names; empty arrays and bad
host names reject; Save Policy requires expectedFingerprint; the catalog cache
key covers all rule sources and the runtime shares the cached catalog.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Documents with an unknown top-level key or no Statement are rejected (new
rawDocuments vectors); a Deny subtracts static and host floors, also while the
guard blocks; unreadable and void states; fingerprint covers the policy attribute.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
fix(policy): guard-blocked and floor Deny, unavailable state, strict documents
maven / build (push) Failing after 1m32s
build / maven (push) Failing after 1m32s
bad06d806a
The cut-over guard's blocked branch applies valid Deny rules (claim and graph) to
floor, host source and existing permissions; a guard error keeps the last known
state. Static and host floors are subject to Deny everywhere (bootstrap exempt),
including the refreshing mapper, which now reads Deny rules from the mirror
without an API call. PolicyResult gains UNAVAILABLE; a failed graph read with no
claim voids earlier permissions; resolveResult reports the full rules. Missing
parents void. Documents with unknown top-level keys or no Statement are
rejected. The group fingerprint covers the configured policy attribute. Stronger
tests for release, grandparent Deny, and the blueprint (fails without python).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
fix(policy): one shared session-permission rule; Deny beats the mirror; void/unavailable
maven / build (push) Failing after 1m29s
build / maven (push) Failing after 1m29s
cd1ebc0f73
SessionPermissionRules.compute serves sign-in, automated sessions and the
refreshing mapper: void leaves break-glass only even while the guard blocks;
unavailable leaves only configured outage fallbacks; known applies every Deny to
policy grants, mirror permissions, static and host floors and earlier session
permissions. The refreshing mapper reads Deny rules from the mirrored group rows
on the same connection (checkpoint-consistent, bounded). Automated sessions void
on an unknown group pk and no longer keep earlier permissions when unresolved.
The guard keeps only a real last state (never OFF, original time, 15 min bound).
The mirror stores the policy document unredacted. Blueprint rejects extra
top-level keys and a missing Statement.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
fix(policy): break-glass operators keep identity permissions; absent groups claim is unavailable
maven / build (push) Failing after 1m29s
build / maven (push) Failing after 1m29s
49905f8e86
Bootstrap identity permissions are added to an operator after the Deny filter, so
a void or denying group cannot lock them out of repairing policies. A token with
no groups claim and no policy claim is unavailable (an empty array stays known).
The mirror restores a policy attribute verbatim only when it parses. Docs mark the
resolve/resolveResult/apply helpers as not for sign-in assembly. More mapper tests
(void claim alone, bootstrap under void, guard error at sign-in, specific
QAuthenticationException on refused mirror snapshots).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
test(policy): skip the python blueprint run when the CI image has no python
maven / build (push) Failing after 1m43s
build / maven (push) Failing after 1m43s
e2a3cd3021
The shared CI runner image has no python3, so the 'fail without python' rule made
every build red at the unit stage. The python run now skips unless
BLUEPRINT_PYTHON_REQUIRED=true; a pure-Java test keeps the blueprint's safety
shape checked everywhere.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
ci: re-run (the previous run hit a runner Docker port-binding error in Testcontainers)
maven / build (push) Successful in 11m49s
build / maven (push) Successful in 11m49s
2c5baa336d
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Merge develop into release/0.1 (policy format 1.1.0, RC.10)
maven / build (push) Failing after 1m56s
build / maven (push) Failing after 1m56s
ce9cf33fd4
james.maes added 1 commit 2026-11-09 03:05:10 +00:00
ci: re-run (previous run hit a runner Docker port-binding error in Testcontainers; unit tests passed)
maven / build (push) Successful in 11m18s
build / maven (push) Successful in 11m18s
a058403857
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
james.maes merged commit 7e579cc1cd into release/0.1 2026-11-09 03:31:24 +00:00
Sign in to join this conversation.