Skip to content

feat(client): add OpenFGA policy store client support - #944

Open
robertswork23-crypto wants to merge 3 commits into
permitio:masterfrom
robertswork23-crypto:feat/openfga-policy-store
Open

feat(client): add OpenFGA policy store client support#944
robertswork23-crypto wants to merge 3 commits into
permitio:masterfrom
robertswork23-crypto:feat/openfga-policy-store

Conversation

@robertswork23-crypto

Copy link
Copy Markdown

Adds OpenFGA support per #661.

Design

OpenFGA's data model doesn't map onto OPA/Cedar's "named policy files" shape — OpenFGA has one immutable, versioned authorization model per store rather than independently-addressable policy files. So set_policies(bundle) compiles every module in the bundle into a single authorization model and writes it once, instead of looping a per-module set_policy() call. set_policy/get_policy/delete_policy/get_policy_module_ids are left unimplemented (inheriting NotImplementedError), same as Cedar leaves several methods unimplemented — there's no per-file operation to perform. set_policy_data/delete_policy_data/get_data map onto OpenFGA relationship tuples via the real /write and /read endpoints.

Endpoint paths and payload shapes were verified against OpenFGA's own OpenAPI spec (github.com/openfga/api), not guessed.

Testing

  • Unit/liveness tests: openfga_client_liveness_test.py, mirroring the existing Cedar suite. Full opal-client suite passes (37/37; two unrelated pre-existing test files don't collect on Windows due to a POSIX-only fcntl import in opal_common, confirmed via git stash to predate this change).
  • Verified against a real, containerized OpenFGA instance (docker run openfga/openfga run) — not mocked: set_policies (real model write), set_policy_data/get_data (real tuple write/read round-trip), delete_policy_data, the liveness probe against GET /stores, the transaction-context path (is_ready/is_healthy via real log_transaction calls), and full_export/full_import round-trip. This caught and fixed a real bug: full_export was writing /read's raw response shape into the export instead of the flat shape /write expects.

Known scope limits (flagged, not hidden)

  • OAuth isn't supported (matches Cedar's stance); OpenFGA does support OIDC in some deployments but that's separate work.
  • store_id is read from POLICY_STORE_OPENFGA_STORE_ID directly rather than wired into config.py's confi system — a pragmatic MVP choice, real config wiring is a natural follow-up.
  • No OpenFGA DSL → JSON transpile; policy modules are expected to already contain JSON-encoded type_definitions.
  • authorization_model_id pinning on writes isn't implemented; writes target the latest model implicitly.
  • The "inline runner" (OPAL spawning the engine itself, like it does for OPA/Cedar) isn't included — OpenFGA normally runs as its own service with its own datastore, so that felt like separately-scoped work rather than a mechanical port.

Caught via real integration testing against a containerized OpenFGA
instance: full_export wrote /read's raw {"key": {...}, "timestamp": ...}
tuple shape into the export file, which full_import then fed unmodified
to set_policy_data. /write rejected it ("the 'user' field is malformed")
since it isn't the flat {user, relation, object} shape /write expects.
Shared the reshape logic with delete_policy_data, which already did this
correctly, via a new _to_write_tuple_keys() helper.
@netlify

netlify Bot commented Aug 18, 2026

Copy link
Copy Markdown

Deploy Preview for opal-docs ready!

Name Link
🔨 Latest commit a4f00b9
🔍 Latest deploy log https://app.netlify.com/projects/opal-docs/deploys/6a84b4118dad2e00088ab854
😎 Deploy Preview https://deploy-preview-944--opal-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@robertswork23-crypto

Copy link
Copy Markdown
Author

awaiting review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant