fides-pbac standalone CLI and demo fixtures (reference, not for merge)#7941
Draft
fides-pbac standalone CLI and demo fixtures (reference, not for merge)#7941
Conversation
Go library implementing the PBAC purpose-overlap evaluation algorithm and fideslang policy rule evaluation. Provides two packages: - pkg/pbac: Purpose evaluation (set intersection of consumer vs dataset purposes) - pkg/fideslang: Fideslang policy rule evaluation (taxonomy hierarchy matching) - cmd/fides-evaluate: CLI binary for stdin/file-based evaluation The library is designed to be imported by the fidesplus sidecar for high-throughput HTTP evaluation (~13x faster than Python).
The fideslang package implemented the old policy rule evaluation (taxonomy hierarchy matching against privacy declarations). This is replaced by the Access Policy v2 system which will be added to pkg/pbac/ as the next step in the PBAC pipeline.
Implements the policy evaluation algorithm from IMPLEMENTATION_GUIDE.md as step 7 of the PBAC pipeline — filtering violations through access policies created via the UI. Features: - Priority-ordered, first-decisive-match-wins evaluation - Match blocks with any/all operators and taxonomy hierarchy matching - Unless conditions: consent, geo_location, data_flow (AND logic) - ALLOW + unless triggered = DENY (decisive) - DENY + unless triggered = SUPPRESSED (continues to next policy) - Audit trail of evaluated policies 25 tests covering priority ordering, match modes, all three unless condition types, multi-constraint AND logic, and taxonomy matching.
Library tests (pkg/pbac/): - edge_cases_test.go: empty datasets, nil collections, multiple collections counted separately, duplicate purpose keys, sorted output, non-nil slices for JSON, EffectivePurposes inheritance, policy catch-all, match all/any combined, unless without context, deny action only on deny, context field resolution (nested, missing, non-string) CLI integration tests (cmd/fides-evaluate/): - Builds the binary once, exercises both purpose and policies commands via stdin and file input - Purpose: compliant, violation, gap, collections, multiple datasets - Policies: allow, deny, no-decision, unless-inverts, priority ordering - Error handling: no args, unknown command, invalid JSON, missing file, empty input, output is valid JSON Also adds 'policies' subcommand to the CLI. 63 tests total, all passing.
Drops the standalone Go binary (cmd/fides-evaluate/) and adds PBAC evaluation to the existing fides CLI: fides pbac evaluate-purpose — purpose overlap check (stdin/file) fides pbac evaluate-policies — access policy evaluation (stdin/file) The CLI calls the Python evaluation engine directly. Performance is not the concern here — the Go sidecar handles API throughput. The CLI is for local testing and debugging. Adds: - src/fides/cli/commands/pbac.py — Click command group - src/fides/service/pbac/policies/evaluate.py — Python policy v2 engine (mirrors Go implementation in policy-engine/pkg/pbac/) - tests for both the evaluation engine and CLI passthrough
Go library (50 tests) — adds: - data_subject match dimension - three-dimension match (use + category + subject) - consent not_opt_in / not_opt_out requirements - data_flow none_of operator Python evaluation (42 tests) — adds: - data_subject match + three-dimension match - match any+all combined across dimensions - consent not_opt_in / not_opt_out - geo not_in operator - data_flow none_of operator - nested context field resolution 92 automated tests total across Go and Python, covering every rule, match mode, unless condition type, and operator.
Runs go build, go vet, and go test on pull_request/push when policy-engine/ files change. Uses setup-go with module caching.
…verage
CI blockers:
- Fix mypy: click.utils.LazyFile → typing.TextIO in pbac.py
- Run ruff format on all Python files
Logic fixes:
- Deterministic output: sort dataset keys before iterating Go map
- Stable sort: sort.Slice → sort.SliceStable for policy priority ties
- Enabled default: *bool pointer so nil (omitted) defaults to true,
matching Python's p.get("enabled", True)
- Complete audit trail: decisive policy now included in EvaluatedPolicies
for both ALLOW-inverted-to-DENY and normal decisive paths
- Empty taxonomy guard: taxonomyMatch("", x) returns false in both Go
and Python to prevent accidental catch-all
Code smells:
- Replace interface{} return from checkAccess with typed accessCheckResult
- Remove unused GapUnconfiguredConsumer from Go (service-layer concern)
- Document Constraint.Operator field: which operators apply to which types
Missing tests (Go + Python):
- MatchDimension with both Any and All on same dimension
- Duplicate Unless constraints (AND of identical = no-op)
- Empty taxonomy match key never matches
- Enabled defaults to true when omitted
54 Go tests + 48 Python tests, all passing.
Critical fixes: - evaluate.py now uses typed dataclasses (ParsedPolicy, AccessEvaluationRequest, PolicyEvaluationResult) instead of raw dicts - InProcessAccessPolicyEvaluator conforms to the existing AccessPolicyEvaluator Protocol from interface.py - JSON conversion (parsed_policy_from_dict, request_from_dict, result_to_dict) pushed to CLI boundary, not inside the service - CLI evaluate-policies now constructs typed objects from JSON, matching the pattern used by evaluate-purpose - Lazy import removed — all imports at module level Significant fixes: - CI: add go mod tidy verification step - Go: document EvaluatePoliciesRequest/EvaluatePurposeRequest as sidecar types (used by fidesplus companion PR) - Go + Python: add priority tie-breaking test (stable sort preserves insertion order) 55 Go tests + 51 Python tests, all passing.
- Go CI: remove go.sum from git diff check (no external deps, file doesn't exist) - Ruff: fix import block formatting (extra blank line) - ParsedPolicy.decision: change from str to PolicyDecision enum so invalid values fail at construction time rather than evaluation time - .gitignore: add test_report.xml (pytest junitxml artifact)
Tests were constructing ParsedPolicy with decision="ALLOW"/"DENY" strings, but the field is now PolicyDecision. This caused 'str' object has no attribute 'value' in evaluate_policies.
- CI: add gofmt check and include go.sum in module verification diff - Fix gofmt alignment drift in Constraint and EvaluatedPolicyInfo structs - parsed_policy_from_dict: raise InvalidPolicyError with friendly message on bad decision values (instead of raw ValueError) - CLI: catch InvalidPolicyError for clean error output on bad JSON - result_to_dict: omit null action (matches Go omitempty behavior)
Reference-only bundle showing how a single Go binary can evaluate SQL queries against a YAML PBAC config directory with no dependency on the fides Python stack. Adds: - policy-engine/cmd/fides-pbac/ — the CLI (flag parsing, statement splitter, output shape matching EvaluationRecord) - policy-engine/pkg/sqlextract/ — regex-based table extractor plus StripComments helper (31 subtests) - policy-engine/pkg/fixtures/ — YAML loaders for consumers, purposes, datasets, policies; builds the collection-name -> dataset_key index - policy-engine/README.md — module-level docs - pbac/ — demo fixture directory used by the CLI Extends pbac types minimally to support the CLI: - yaml tags on pbac.AccessPolicy and its nested types (non-breaking) - PurposeViolation.SuppressedByPolicy / SuppressedByAction so suppressions are auditable inline instead of being filtered out Removes an unused asdict import from src/fides/cli/commands/pbac.py. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
Codecov Report✅ All modified and coverable lines are covered by tests. ❌ Your project check has failed because the head coverage (83.41%) is below the target coverage (85.00%). You can increase the head coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## policy-engine-go-library #7941 +/- ##
============================================================
- Coverage 85.09% 83.41% -1.69%
============================================================
Files 631 631
Lines 41053 41052 -1
Branches 4781 4781
============================================================
- Hits 34933 34242 -691
- Misses 5040 5627 +587
- Partials 1080 1183 +103 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
thabofletcher
added a commit
that referenced
this pull request
Apr 15, 2026
Mirrors the POC fides-pbac CLI (#7941) but with the CLI staying in Python and the SQL parsing staying in Python. The Go library gets a new pipeline package that can drive the same flow over HTTP or in-process — useful when we want to move the hot path off of Python later without rewriting the CLI UX. Go additions (policy-engine/): - pkg/fixtures — YAML loaders for consumers/, purposes/, datasets/, policies/ matching the POC's config dir layout - pkg/pipeline — identity resolution + dataset resolution + purpose eval + gap reclassification + policy filtering, returning one EvaluationRecord per statement. 8 tests against the pbac/ fixtures. - pkg/pbac/types.go — SuppressedByPolicy + SuppressedByAction on PurposeViolation so suppressed violations stay in the record for audit instead of being dropped. GapUnconfiguredConsumer restored (the pipeline needs it; the engine still doesn't produce it). - pkg/pbac/policy_types.go — yaml: tags alongside json: on the policy types so YAML-loaded policies round-trip through the same struct. New Identity field on AccessEvaluationRequest carries the caller identity through the engine so identity-aware policies become an additive change rather than a request-shape break. Python additions (src/fides/): - service/pbac/fixtures.py — Python mirror of the Go fixture loaders - service/pbac/pipeline.py — Python mirror of the Go pipeline; reuses the existing sql_parser (sqlglot), evaluate_purpose, and evaluate_policies primitives - service/pbac/policies/interface.py — Identity field on AccessEvaluationRequest to match the Go side - cli/commands/pbac.py — new `fides pbac evaluate --config DIR --identity EMAIL [SQL_FILE]` command. Existing evaluate-purpose and evaluate-policies commands stay as lower-level JSON primitives. Fixtures (pbac/): - Ported verbatim from the POC to serve as both demo data and the test fixture set for the pipeline tests.
thabofletcher
added a commit
that referenced
this pull request
Apr 16, 2026
Mirrors the POC fides-pbac CLI (#7941) but with the CLI staying in Python and the SQL parsing staying in Python. The Go library gets a new pipeline package that can drive the same flow over HTTP or in-process — useful when we want to move the hot path off of Python later without rewriting the CLI UX. Go additions (policy-engine/): - pkg/fixtures — YAML loaders for consumers/, purposes/, datasets/, policies/ matching the POC's config dir layout - pkg/pipeline — identity resolution + dataset resolution + purpose eval + gap reclassification + policy filtering, returning one EvaluationRecord per statement. 8 tests against the pbac/ fixtures. - pkg/pbac/types.go — SuppressedByPolicy + SuppressedByAction on PurposeViolation so suppressed violations stay in the record for audit instead of being dropped. GapUnconfiguredConsumer restored (the pipeline needs it; the engine still doesn't produce it). - pkg/pbac/policy_types.go — yaml: tags alongside json: on the policy types so YAML-loaded policies round-trip through the same struct. New Identity field on AccessEvaluationRequest carries the caller identity through the engine so identity-aware policies become an additive change rather than a request-shape break. Python additions (src/fides/): - service/pbac/fixtures.py — Python mirror of the Go fixture loaders - service/pbac/pipeline.py — Python mirror of the Go pipeline; reuses the existing sql_parser (sqlglot), evaluate_purpose, and evaluate_policies primitives - service/pbac/policies/interface.py — Identity field on AccessEvaluationRequest to match the Go side - cli/commands/pbac.py — new `fides pbac evaluate --config DIR --identity EMAIL [SQL_FILE]` command. Existing evaluate-purpose and evaluate-policies commands stay as lower-level JSON primitives. Fixtures (pbac/): - Ported verbatim from the POC to serve as both demo data and the test fixture set for the pipeline tests.
thabofletcher
added a commit
that referenced
this pull request
Apr 16, 2026
Mirrors the POC fides-pbac CLI (#7941) but with the CLI staying in Python and the SQL parsing staying in Python. The Go library gets a new pipeline package that can drive the same flow over HTTP or in-process — useful when we want to move the hot path off of Python later without rewriting the CLI UX. Go additions (policy-engine/): - pkg/fixtures — YAML loaders for consumers/, purposes/, datasets/, policies/ matching the POC's config dir layout - pkg/pipeline — identity resolution + dataset resolution + purpose eval + gap reclassification + policy filtering, returning one EvaluationRecord per statement. 8 tests against the pbac/ fixtures. - pkg/pbac/types.go — SuppressedByPolicy + SuppressedByAction on PurposeViolation so suppressed violations stay in the record for audit instead of being dropped. GapUnconfiguredConsumer restored (the pipeline needs it; the engine still doesn't produce it). - pkg/pbac/policy_types.go — yaml: tags alongside json: on the policy types so YAML-loaded policies round-trip through the same struct. New Identity field on AccessEvaluationRequest carries the caller identity through the engine so identity-aware policies become an additive change rather than a request-shape break. Python additions (src/fides/): - service/pbac/fixtures.py — Python mirror of the Go fixture loaders - service/pbac/pipeline.py — Python mirror of the Go pipeline; reuses the existing sql_parser (sqlglot), evaluate_purpose, and evaluate_policies primitives - service/pbac/policies/interface.py — Identity field on AccessEvaluationRequest to match the Go side - cli/commands/pbac.py — new `fides pbac evaluate --config DIR --identity EMAIL [SQL_FILE]` command. Existing evaluate-purpose and evaluate-policies commands stay as lower-level JSON primitives. Fixtures (pbac/): - Ported verbatim from the POC to serve as both demo data and the test fixture set for the pipeline tests.
thabofletcher
added a commit
that referenced
this pull request
Apr 17, 2026
Mirrors the POC fides-pbac CLI (#7941) but with the CLI staying in Python and the SQL parsing staying in Python. The Go library gets a new pipeline package that can drive the same flow over HTTP or in-process — useful when we want to move the hot path off of Python later without rewriting the CLI UX. Go additions (policy-engine/): - pkg/fixtures — YAML loaders for consumers/, purposes/, datasets/, policies/ matching the POC's config dir layout - pkg/pipeline — identity resolution + dataset resolution + purpose eval + gap reclassification + policy filtering, returning one EvaluationRecord per statement. 8 tests against the pbac/ fixtures. - pkg/pbac/types.go — SuppressedByPolicy + SuppressedByAction on PurposeViolation so suppressed violations stay in the record for audit instead of being dropped. GapUnconfiguredConsumer restored (the pipeline needs it; the engine still doesn't produce it). - pkg/pbac/policy_types.go — yaml: tags alongside json: on the policy types so YAML-loaded policies round-trip through the same struct. New Identity field on AccessEvaluationRequest carries the caller identity through the engine so identity-aware policies become an additive change rather than a request-shape break. Python additions (src/fides/): - service/pbac/fixtures.py — Python mirror of the Go fixture loaders - service/pbac/pipeline.py — Python mirror of the Go pipeline; reuses the existing sql_parser (sqlglot), evaluate_purpose, and evaluate_policies primitives - service/pbac/policies/interface.py — Identity field on AccessEvaluationRequest to match the Go side - cli/commands/pbac.py — new `fides pbac evaluate --config DIR --identity EMAIL [SQL_FILE]` command. Existing evaluate-purpose and evaluate-policies commands stay as lower-level JSON primitives. Fixtures (pbac/): - Ported verbatim from the POC to serve as both demo data and the test fixture set for the pipeline tests.
thabofletcher
added a commit
that referenced
this pull request
Apr 17, 2026
Mirrors the POC fides-pbac CLI (#7941) but with the CLI staying in Python and the SQL parsing staying in Python. The Go library gets a new pipeline package that can drive the same flow over HTTP or in-process — useful when we want to move the hot path off of Python later without rewriting the CLI UX. Go additions (policy-engine/): - pkg/fixtures — YAML loaders for consumers/, purposes/, datasets/, policies/ matching the POC's config dir layout - pkg/pipeline — identity resolution + dataset resolution + purpose eval + gap reclassification + policy filtering, returning one EvaluationRecord per statement. 8 tests against the pbac/ fixtures. - pkg/pbac/types.go — SuppressedByPolicy + SuppressedByAction on PurposeViolation so suppressed violations stay in the record for audit instead of being dropped. GapUnconfiguredConsumer restored (the pipeline needs it; the engine still doesn't produce it). - pkg/pbac/policy_types.go — yaml: tags alongside json: on the policy types so YAML-loaded policies round-trip through the same struct. New Identity field on AccessEvaluationRequest carries the caller identity through the engine so identity-aware policies become an additive change rather than a request-shape break. Python additions (src/fides/): - service/pbac/fixtures.py — Python mirror of the Go fixture loaders - service/pbac/pipeline.py — Python mirror of the Go pipeline; reuses the existing sql_parser (sqlglot), evaluate_purpose, and evaluate_policies primitives - service/pbac/policies/interface.py — Identity field on AccessEvaluationRequest to match the Go side - cli/commands/pbac.py — new `fides pbac evaluate --config DIR --identity EMAIL [SQL_FILE]` command. Existing evaluate-purpose and evaluate-policies commands stay as lower-level JSON primitives. Fixtures (pbac/): - Ported verbatim from the POC to serve as both demo data and the test fixture set for the pipeline tests.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
A single Go binary (
fides-pbac) that:consumers/,purposes/,datasets/,policies/)EvaluationRecordfromsrc/fides/service/pbac/types.pyNo Python runtime, no server, no Redis, no database. ~3 ms median startup+config-load. 3.5 MB static binary.
Static fixture files (
pbac/at the repo root)Fixture schema conventions
Consumer — four fields:
name,description,members(list of emails),purposes. Identity resolution is "does--identityappear in some consumer'smemberslist."Purpose — mirrors
fidesplus/seed/pbac/data.py::PURPOSES:fides_key,name,data_use, optionaldata_subject,data_categories,description.Dataset — standard fideslang.
data_purposescan be declared at the dataset, collection, and field levels; effective purposes for a query on<dataset>.<collection>stack additively:sales.invoicesis the live demonstration: dataset isbilling, collection addsanalytics, so analytics-team queries againstinvoicespass the purpose check directly without a policy override.Policy — matches
pbac.AccessPolicy. Disabled policies (enabled: false) are filtered out at load time.Dataset resolution
Collection names are assumed globally unique across datasets, so queries resolve by bare table name regardless of catalog/schema prefix.
SELECT FROM ordersandSELECT FROM archive.legacy_sales.ordersboth resolve to the dataset that declares anorderscollection. Unknown tables fall through to their qualified name as the identifier on the resultingUNCONFIGURED_DATASETgap.fides-pbacCLI options--config DIRconsumers/,purposes/,datasets/,policies/YAML subdirectories--identity EMAILFILE(positional)-to read from stdinStatements are split on top-level
;(respecting single-quoted strings,--line comments, and/* */block comments). Each statement becomes one record in the output.Evaluation pipeline (per statement)
pkg/sqlextractpulls 1-3 part qualified identifiers from the SQL.--identitylooked up againstconsumers/by member email.collections[].name. Unknown tables fall through to their qualified name.PurposeViolation, missing configuration is anEvaluationGap.UNRESOLVED_IDENTITYbecomesUNCONFIGURED_CONSUMERwhen the consumer exists but declares no purposes.data_usestrings (viapurposes/), then evaluated againstpolicies/. AnALLOWsetssuppressed_by_policy(andsuppressed_by_actionwhen the policy has anaction.message) on the violation in place.Gaps do not flow through policy filtering. A record is compliant when every violation is suppressed and no gaps were recorded.
Output
JSON on stdout. One
recordsarray with:query_id,identity,consumer,dataset_keysis_compliantviolations— eachPurposeViolationwithconsumer_id/name,dataset_key,collection,consumer_purposes,dataset_purposes,reason, and the optionalsuppressed_by_policy/suppressed_by_actioninline when anALLOWpolicy matchedgaps,total_accesses,query_textMirrors
EvaluationRecordfromsrc/fides/service/pbac/types.pywith three deliberate deltas: simplifiedconsumer(name string instead of full entity), notimestamp(not available in SQL text), and the inlinesuppressed_by_policy/suppressed_by_actionfields onPurposeViolation.Install (local checkout)
cd policy-engine go install ./cmd/fides-pbacExpected outcomes from the fixture set
fides-pbac --config pbac/ --identity alice@demo.example pbac/entries/alice.txtfides-pbac --config pbac/ --identity bob@demo.example pbac/entries/bob.txtunconfigured_datasetidentified ascold_storagefides-pbac --config pbac/ --identity carol@demo.example pbac/entries/carol.txtunresolved_identityfides-pbac --config pbac/ --identity dave@demo.example pbac/entries/dave.txtunconfigured_consumerPackage additions under
policy-engine/cmd/fides-pbac/— CLI entrypointpkg/sqlextract/— regex-based SQL table extractor +StripCommentshelper, 31 subtestspkg/fixtures/— YAML loaders returning typed structs consumable bypkg/pbacMinimal changes to
pkg/pbacyaml:tags added alongside existingjson:tags onAccessPolicyand its nested types. Non-breaking.PurposeViolation.SuppressedByPolicyandSuppressedByActionadded next to the existing service-enriched fields (DataUse,Control). Optional; absent when the violation wasn't suppressed.