Skip to content

refactor(authz): OpenFGA parser, profile validator, and compiler - #720

Merged
adlerhurst merged 8 commits into
mainfrom
421-openfga-parser-compiler
Aug 5, 2026
Merged

refactor(authz): OpenFGA parser, profile validator, and compiler#720
adlerhurst merged 8 commits into
mainfrom
421-openfga-parser-compiler

Conversation

@livio-a

@livio-a livio-a commented Aug 3, 2026

Copy link
Copy Markdown
Member

Summary

  • Implements OpenFGA Parser, IR & Profile Compiler #421: OpenFGA DSL/JSON → portable authz IR (internal/authz/openfga), MVP profile validation with structured diagnostics (internal/authz/profile), and compilation to storage-neutral catalog mutations + query-plan metadata (internal/authz/compiler).
  • Uses upstream github.com/openfga/language/pkg/go for parsing; Zitadel owns profile enforcement and plan output. Persistence/SQL mapping stays with Relational Schema & Migrations for Authorization #422.

Validation

  • go test ./internal/authz/...

Release notes / changeset

  • Changeset: .changeset/openfga-authz-compiler.md — OpenFGA authz parser/profile/compiler foundation (@zitadel/server minor)

Notes

livio-a and others added 4 commits August 3, 2026 09:25
The permission compiler needs a policy shape that profile validation,
closure computation, and SQL planning can consume without depending on
OpenFGA protobufs, so parsing stays with the upstream language package
while Zitadel owns the intermediate representation.

Refs #421

Co-authored-by: Cursor <cursoragent@cursor.com>
Schema uploads must fail fast on constructs that cannot be planned on
PostgreSQL and Spanner, with stable detail codes that can later wrap into
a domain error at the API boundary.

Refs #421

Co-authored-by: Cursor <cursoragent@cursor.com>
Expand same-object computed usersets into a relation closure and emit
storage-neutral catalog mutations plus query-plan terms for direct,
computed, and TTU leaves (#421).

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI review requested due to automatic review settings August 3, 2026 07:25
@vercel

vercel Bot commented Aug 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nextgen Ready Ready Preview Aug 5, 2026 7:44am
nextgen-docs Ready Ready Preview Aug 5, 2026 7:44am
nextgen-mock-zitadel Ready Ready Preview Aug 5, 2026 7:44am

Request Review

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

🦋 Changeset detected

Latest commit: abfeed1

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements the first stage of the ADR-032 OpenFGA→catalog pipeline by introducing a storage-neutral authz intermediate representation, an OpenFGA DSL/JSON parser adapter, a bounded-profile validator with structured diagnostics, and a compiler that emits catalog mutations plus query-plan metadata (leaving persistence/SQL mapping to #422).

Changes:

  • Add internal/authz/openfga to parse OpenFGA DSL/JSON via github.com/openfga/language/pkg/go and normalize into a deterministic internal/authz IR.
  • Add internal/authz/profile validator to enforce the MVP “portable/bounded” profile and return structured Diagnostics.
  • Add internal/authz/compiler to compile a profile-valid model into storage-neutral catalog mutations, flattened query terms, and same-object computed-userset closure metadata.

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
internal/authz/profile/profile.go Implements profile validation (schema version, unsupported constructs, TTU bounding).
internal/authz/profile/profile_test.go Unit tests for accepted profile, rejection diagnostics, and configurability.
internal/authz/profile/index.go Adds deterministic model index + reference graph traversal for recursion detection.
internal/authz/profile/diagnostic.go Defines stable diagnostic codes + Diagnostics error semantics (Unwrap for errors.Is).
internal/authz/openfga/parse.go Adapts upstream OpenFGA parser/transformer to normalized Zitadel IR.
internal/authz/openfga/parse_test.go Tests DSL/JSON parsing, normalization ordering, and condition preservation.
internal/authz/model.go Introduces the shared storage-independent authz IR types.
internal/authz/compiler/output.go Defines storage-neutral catalog mutation records and query-plan term structures.
internal/authz/compiler/compiler.go Validates then compiles IR into catalog mutations, query plans, and implication graph inputs.
internal/authz/compiler/compiler_test.go Tests compilation output, closure properties, TTU handling, and diagnostics passthrough.
internal/authz/compiler/closure.go Computes shortest-depth reflexive transitive closure for computed-userset implications.
go.mod Adds OpenFGA language + proto dependencies.
go.sum Adds checksums for new dependencies (including indirects).
.changeset/openfga-authz-compiler.md Declares @zitadel/server minor release note for the new authz foundation.

Comment thread internal/authz/openfga/parse.go Outdated
Comment thread internal/authz/openfga/parse.go

@fforootd fforootd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid implementation — this tracks ADR 032 §2 closely: the package boundary is verbatim from the ADR table, the hierarchy edges and unsupported-construct set match, and the output types stay clean of catalog IDs/SQL so #422 keeps full freedom on the relational shape.

What I did beyond reading: checked out the branch, ran go vet + go test ./internal/authz/... (green, matching CI), hand-checked the closure BFS and its deterministic catalog-order emission against the test expectations, and threw four adversarial models at it. Recursion detection held up well — a self-type TTU through a valid hierarchy edge (define parent: [project] + define viewer: [user] or viewer from parent) is rejected as unbounded_recursion, and a cross-type team↔project TTU cycle rejects both participants with stable diagnostics. The two shapes that slipped through are both crafted-JSON-only and deny-safe; repros are in the inline comments.

Things I want to call out as particularly good:

  • The diagnostics design: comparable Diagnostic + Diagnostics.Unwrap() []error makes a single violation errors.Is-matchable without scanning, and reusing OpenFGA's own error vocabulary (with the documented rationale for not reusing 2002) is exactly the right customer-empathy call.
  • Determinism is handled at every layer (sorted normalization, positions, catalog-order closure rows) — the future catalog-diff story will lean on this.
  • The oneof-discriminator switch in normalizeRewrite instead of the unreliable GetThis() is a subtle trap avoided, and the comment explains it for the next reader.
  • The closure/plan split (computed usersets → closure; TTU and userset refs → plan terms) is the correct reading of ADR 032 §3's write-cheap model, and there's a test pinning that TTU is not treated as a global implication.

Two notes that don't belong on any one line:

  • Upload-path bounds: recursion checking is O(V·E) per relation, the closure is O(V²) rows worst case, and ANTLR parses untrusted tenant input. All fine at schema scale, but #422's upload API should cap input size and type/relation counts — worth carrying over as a note on that issue so it doesn't get lost.
  • ADR bookkeeping: ADR 032 is still marked Proposed and its follow-up item 4 is exactly this PR — worth ticking off (or revisiting the status) when this lands.

The one thing I'd change before merge is the changeset/title pairing — see the comment on the changeset file.

Comment thread .changeset/openfga-authz-compiler.md Outdated
Comment thread internal/authz/profile/profile.go
Comment thread internal/authz/compiler/compiler.go
Comment thread internal/authz/profile/profile.go
Comment thread internal/authz/profile/profile.go
Comment thread internal/authz/profile/profile.go Outdated
cursor Bot pushed a commit that referenced this pull request Aug 3, 2026
Keep table-shaped statement APIs; document dual-write vs grants vs
resolver callers in comments. Extend permission-storage.md with domain
roles, compiler/storage layer split, and one-SQL get/list check guidance.

Co-authored-by: Silvan <adlerhurst@users.noreply.github.com>
@IAM-marco
IAM-marco requested a review from adlerhurst August 3, 2026 09:27

@adlerhurst adlerhurst left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No additional comments to ffo's review.

Reject empty unions, dedupe identical flatten terms, distinguish nil vs
empty HierarchyTypes, tighten diagnostics/tests, and switch to an empty
changeset until something imports the package.

Co-authored-by: Cursor <cursoragent@cursor.com>
@livio-a livio-a changed the title feat(authz): OpenFGA parser, profile validator, and compiler refactor(authz): OpenFGA parser, profile validator, and compiler Aug 4, 2026
@livio-a
livio-a requested review from adlerhurst and fforootd August 4, 2026 13:15
Comment thread internal/authz/compiler/closure.go Outdated
Comment thread internal/authz/compiler/output.go Outdated
cursor Bot pushed a commit that referenced this pull request Aug 5, 2026
Bring internal/authz compiler so catalog DDL can align and
PersistCatalogVersion can be implemented against CatalogMutations.

Co-authored-by: Silvan <adlerhurst@users.noreply.github.com>
cursor Bot pushed a commit that referenced this pull request Aug 5, 2026
Reshape authz relations to (object_type, relation), add expression edges and
relation references, persist CatalogMutations via PersistCatalogVersion, and
renumber migrations after main merge collisions.

Co-authored-by: Silvan <adlerhurst@users.noreply.github.com>
Move compiler package documentation to doc.go (include SQLite with
PostgreSQL and Spanner) and replace manual queue dequeue with an
index-based BFS walk.

Co-authored-by: Cursor <cursoragent@cursor.com>
@adlerhurst
adlerhurst enabled auto-merge (squash) August 5, 2026 07:43
@adlerhurst
adlerhurst merged commit b7b4c25 into main Aug 5, 2026
14 checks passed
@adlerhurst
adlerhurst deleted the 421-openfga-parser-compiler branch August 5, 2026 07:53
@github-project-automation github-project-automation Bot moved this from Inbox to Done in Engineering Kanban Aug 5, 2026
cursor Bot pushed a commit that referenced this pull request Aug 5, 2026
Take main's #720 compiler sources after it landed on main.

Co-authored-by: Silvan <adlerhurst@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

OpenFGA Parser, IR & Profile Compiler

4 participants