Skip to content

feat(policy): dynamic attribute value entitlement mappings#3568

Merged
alkalescent merged 16 commits into
mainfrom
DSPX-2754-dynamic-attribute-values-impl
Jul 17, 2026
Merged

feat(policy): dynamic attribute value entitlement mappings#3568
alkalescent merged 16 commits into
mainfrom
DSPX-2754-dynamic-attribute-values-impl

Conversation

@alkalescent

@alkalescent alkalescent commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Proposed Changes

Implements the DynamicValueMapping policy primitive end to end (the model chosen by the spike / ADR 0005). It raises entitlement authority from a concrete AttributeValue to the AttributeDefinition: a single mapping entitles dynamically-requested values by comparing the requested resource value segment against the entity representation at decision time, instead of pre-provisioning a value + subject mapping per discrete ID (MRNs, account IDs, etc.).

Design highlights:

  • Operator model: DynamicValueResolver reuses SubjectMappingOperatorEnum (IN = the resource segment equals any resolved entity value; IN_CONTAINS = substring). NOT_IN is rejected because dynamic resolution is existential over the resolved values. This keeps the resolver and subject-mapping vocabularies aligned and avoids a parallel operator enum. Follows the operator revert in feat(policy)!: undo subject mapping operator decomposition #3685; the earlier decomposed comparison/quantifier/case_insensitive model was undone.
  • Optional static SubjectConditionSet pre-gate (normal static semantics, no field overload) to support compound "entity attribute AND resource value" conditions.
  • No-coexistence enforced both directions between value-level subject mappings and dynamic mappings on the same definition (attribute values may still exist, e.g. for obligation triggers).
  • HIERARCHY rejected; matching is exact and case-sensitive.
  • Experimental, off by default behind the allow_dynamic_value_mappings config; dynamic mappings are loaded (including in the authz cache), evaluated in decisioning, and gated in the cache refresh only when enabled.
  • Dynamic values are first-class in decisioning: they flow into the same entitlements map and ANY_OF / ALL_OF rule layer as static values (manifest stays a list of attribute FQNs).

Wiring: proto + generated code + SDK client; DB migration + sqlc + CRUD; dedicated DynamicValueMappingService; decision-time evaluator; PDP load/merge with synthetic-value support; and authz cache. Replaces the throwaway spike package and ports its tests. GetEntitlements intentionally does not enumerate dynamic values (high-cardinality, resource-scoped).

Checklist

  • I have added or updated unit tests
  • I have added or updated integration tests (if appropriate)
  • I have added or updated documentation

Testing Instructions

  • cd service && go build ./...
  • cd service && go test ./internal/subjectmappingbuiltin/... ./internal/access/v2/... ./authorization/v2/...
  • cd service && golangci-lint run ./internal/subjectmappingbuiltin/... ./internal/access/v2/ ./authorization/v2/ ./policy/db/ ./policy/dynamicvaluemapping/
  • DB-layer CRUD and end-to-end GetDecision verification require a live Postgres/platform.

Related

Summary by CodeRabbit

  • New Features
    • Added definition-scoped dynamic value mappings with full CRUD and end-to-end authorization support (create/list/get/update/delete).
    • Introduced allow_dynamic_value_mappings flag to enable/disable dynamic mapping evaluation and related direct entitlement synthesis.
    • Extended entitlement cache to expose listing of all cached dynamic value mappings.
  • Bug Fixes
    • Improved entitlement cache refresh correctness to avoid marking the cache “ready” after partial failures.
    • Added validation and enforcement for dynamic mappings, including rejecting unsupported resolver operators and preventing conflicting coexistence/rule updates.
  • Tests
    • Added integration and unit test coverage for dynamic mapping evaluation, pagination, updates/deletes, and safety restrictions.
  • Documentation
    • Added ADR/spike and schema/migration docs for dynamic value mappings.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 04a1b0c2-bdac-4fe2-9864-bd6075ce2295

📥 Commits

Reviewing files that changed from the base of the PR and between 8432ce6 and e6c6bf6.

📒 Files selected for processing (6)
  • service/integration/dynamic_value_mappings_test.go
  • service/policy/db/dynamic_value_mappings.go
  • service/policy/db/dynamic_value_mappings.sql.go
  • service/policy/db/migrations/20260618000000_add_dynamic_value_mappings.md
  • service/policy/db/queries/dynamic_value_mappings.sql
  • service/policy/db/schema_erd.md

📝 Walkthrough

Walkthrough

Introduces definition-scoped dynamic value mappings across policy storage, CRUD APIs, authorization decisioning, caching, configuration, consistency enforcement, and test/documentation coverage.

Changes

Dynamic value mapping rollout

Layer / File(s) Summary
Schema and query surface
service/policy/db/migrations/*, service/policy/db/models.go, service/policy/db/queries/*, service/policy/db/dynamic_value_mappings.sql.go, service/policy/db/utils.go
Adds dynamic mapping tables, models, CRUD/count/list queries, generated wrappers, pagination, sorting, and ERD relationships.
DB client and consistency guards
service/policy/db/dynamic_value_mappings.go, service/policy/db/attributes.go, service/policy/db/subject_mappings.go, service/policy/db/registered_resources.go
Implements CRUD hydration, resolver/rule validation, namespace and subject-condition handling, coexistence restrictions, and hierarchy-transition checks.
Service registration and RPC handlers
service/policy/dynamicvaluemapping/*, service/logger/audit/constants.go, service/policy/policy.go, service/pkg/server/services_test.go
Adds the Connect CRUD service, audit object type, config hot-reload wiring, registration, and service-count coverage.
Condition and mapping evaluation
service/internal/access/v2/validators.go, service/internal/subjectmappingbuiltin/*
Validates mappings and evaluates selector-based IN/IN_CONTAINS matches with optional static subject-condition gates.
PDP and access flow
service/internal/access/v2/{policy_store.go,helpers.go,just_in_time_pdp.go,pdp.go,evaluate.go}, pdp_dynamic_test.go
Loads and indexes mappings, allows mapped values during decisionable-attribute construction, and merges dynamic actions into decisions.
Authorization config and cache
service/authorization/v2/*
Adds the feature flag, propagates it through authorization handlers, and caches/retrieves dynamic mappings with entitlement policy data.
Integration tests and ADR
service/integration/dynamic_value_mappings_test.go, service/policy/adr/0005-dynamic-attribute-value-entitlements-spike.md
Covers CRUD, validation, restrictions, updates, deletes, pagination, decision semantics, and the selected dynamic entitlement model.

Estimated code review effort: 4 (Complex) | ~75 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant AuthorizationService
  participant EntitlementPolicyCache
  participant JustInTimePDP
  participant PolicyDecisionPoint
  participant EvaluateDynamicValueMappingsWithActions

  Client->>AuthorizationService: GetDecision request
  AuthorizationService->>EntitlementPolicyCache: retrieve dynamic mappings
  AuthorizationService->>JustInTimePDP: construct with feature flag
  JustInTimePDP->>PolicyDecisionPoint: WithDynamicValueMappings
  PolicyDecisionPoint->>PolicyDecisionPoint: build decisionable attributes
  PolicyDecisionPoint->>EvaluateDynamicValueMappingsWithActions: evaluate entity and resource values
  EvaluateDynamicValueMappingsWithActions-->>PolicyDecisionPoint: entitled actions by value FQN
  PolicyDecisionPoint-->>AuthorizationService: decision and entitlements
  AuthorizationService-->>Client: response
Loading

Possibly related PRs

Poem

A rabbit maps values in rows,
Through PDP paths the access flows.
IN hops left, contains hops right,
Cache and checks keep burrows tight.
Dynamic carrots bloom anew! 🐰

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.94% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding dynamic attribute value entitlement mappings to policy.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch DSPX-2754-dynamic-attribute-values-impl

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added comp:db DB component comp:policy Policy Configuration ( attributes, subject mappings, resource mappings, kas registry) comp:sdk A software development kit, including library, for client applications and inter-service communicati comp:authorization docs Documentation size/xl labels Jun 4, 2026
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 179.705299ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 99.507736ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 405.58654ms
Throughput 246.56 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 46.591212655s
Average Latency 463.808555ms
Throughput 107.32 requests/second

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request implements a new policy primitive, DefinitionValueEntitlementMapping, which enables dynamic entitlement mappings at the attribute definition level. This allows for more flexible and scalable authorization by comparing resource values against entity attributes at decision time, rather than relying on pre-provisioned static mappings. The change includes a full end-to-end implementation, including protocol definitions, service logic, database persistence, and integration into the existing policy decision point.

Highlights

  • New Policy Primitive: Introduced the DefinitionValueEntitlementMapping primitive to support dynamic attribute value entitlement at the definition level.
  • Dynamic Evaluation Logic: Added DynamicValueOperatorEnum and DefinitionValueResolver to allow for dynamic comparison of resource values against entity attributes at decision time.
  • Service and Persistence: Implemented a dedicated CRUD service, database migrations, and SQLC queries to manage the new entitlement mappings.
  • PDP Integration: Integrated dynamic mapping evaluation into the Policy Decision Point (PDP) and added caching to maintain performance.
  • Validation and Safety: Enforced no-coexistence rules to prevent conflicts between static value-level subject mappings and new dynamic mappings on the same definition.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Ignored Files
  • Ignored by pattern: docs/openapi/**/* (21)
    • docs/openapi/authorization/authorization.openapi.yaml
    • docs/openapi/authorization/v2/authorization.openapi.yaml
    • docs/openapi/common/common.openapi.yaml
    • docs/openapi/entity/entity.openapi.yaml
    • docs/openapi/entityresolution/entity_resolution.openapi.yaml
    • docs/openapi/entityresolution/v2/entity_resolution.openapi.yaml
    • docs/openapi/kas/kas.openapi.yaml
    • docs/openapi/policy/actions/actions.openapi.yaml
    • docs/openapi/policy/attributes/attributes.openapi.yaml
    • docs/openapi/policy/definitionvalueentitlement/definition_value_entitlement.openapi.yaml
    • docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml
    • docs/openapi/policy/keymanagement/key_management.openapi.yaml
    • docs/openapi/policy/namespaces/namespaces.openapi.yaml
    • docs/openapi/policy/objects.openapi.yaml
    • docs/openapi/policy/obligations/obligations.openapi.yaml
    • docs/openapi/policy/registeredresources/registered_resources.openapi.yaml
    • docs/openapi/policy/resourcemapping/resource_mapping.openapi.yaml
    • docs/openapi/policy/selectors.openapi.yaml
    • docs/openapi/policy/subjectmapping/subject_mapping.openapi.yaml
    • docs/openapi/policy/unsafe/unsafe.openapi.yaml
    • docs/openapi/wellknownconfiguration/wellknown_configuration.openapi.yaml
  • Ignored by pattern: protocol/**/* (4)
    • protocol/go/policy/definitionvalueentitlement/definition_value_entitlement.pb.go
    • protocol/go/policy/definitionvalueentitlement/definition_value_entitlement_grpc.pb.go
    • protocol/go/policy/definitionvalueentitlement/definitionvalueentitlementconnect/definition_value_entitlement.connect.go
    • protocol/go/policy/objects.pb.go
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.


Dynamic rules now take the stage, No longer static on the page. From definition, values flow, To let the right permissions grow.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request implements Definition Value Entitlement Mappings (DSPX-2754), which move entitlement authority from concrete attribute values to the attribute definition level. The changes span SDK client generation, caching, PDP evaluation, database storage, and a new gRPC service. The review feedback is highly constructive and identifies several critical issues that should be addressed: a potential data race hazard in the gRPC service, possible nil pointer dereferences in both the PDP evaluator and the database client, a bug in error handling that could return nil values, incorrect type formatting in cache errors, and a redundant database index in the migration script.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread service/policy/definitionvalueentitlement/definition_value_entitlement.go Outdated
Comment thread service/authorization/v2/cache.go Outdated
Comment thread service/internal/access/v2/helpers.go Outdated
Comment thread service/internal/subjectmappingbuiltin/dynamic_value_mapping_builtin.go Outdated
Comment thread service/policy/db/definition_value_entitlement_mappings.go Outdated
Comment thread service/policy/db/definition_value_entitlement_mappings.go Outdated
@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 185.014087ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 118.099251ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 429.531288ms
Throughput 232.81 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 44.331230891s
Average Latency 441.164371ms
Throughput 112.79 requests/second

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 193.209357ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 99.253148ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 452.432409ms
Throughput 221.03 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 47.779208084s
Average Latency 475.780561ms
Throughput 104.65 requests/second

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 153.929845ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 78.781532ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 411.672475ms
Throughput 242.91 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 43.358428704s
Average Latency 431.654544ms
Throughput 115.32 requests/second

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 186.551087ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 99.790406ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 444.671341ms
Throughput 224.89 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 45.347542117s
Average Latency 451.731513ms
Throughput 110.26 requests/second

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 179.271779ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 94.536026ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 449.588328ms
Throughput 222.43 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 47.609789466s
Average Latency 474.175763ms
Throughput 105.02 requests/second

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 305.274891ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 107.714912ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 560.889955ms
Throughput 178.29 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 44.183073863s
Average Latency 439.810332ms
Throughput 113.17 requests/second

alkalescent added a commit that referenced this pull request Jun 9, 2026
Protocol-first half of the dynamic attribute value entitlement work: adds the
DynamicValueMapping / DynamicValueResolver messages and DynamicValueOperatorEnum to
objects.proto, and a dedicated DynamicValueMappingService
(policy.dynamicvaluemapping), plus regenerated protocol/go and OpenAPI/gRPC docs.

No service implementation here. This lands and releases protocol/go first so the
consumer PR (#3568) can require the new version and pass per-module 'go mod tidy'.

Refs: DSPX-2754, DSPX-3498
Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
alkalescent added a commit that referenced this pull request Jun 10, 2026
Protocol-first half of the dynamic attribute value entitlement work: adds the
DynamicValueMapping / DynamicValueResolver messages and DynamicValueOperatorEnum to
objects.proto, and a dedicated DynamicValueMappingService
(policy.dynamicvaluemapping), plus regenerated protocol/go and OpenAPI/gRPC docs.

No service implementation here. This lands and releases protocol/go first so the
consumer PR (#3568) can require the new version and pass per-module 'go mod tidy'.

Refs: DSPX-2754, DSPX-3498
Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
alkalescent added a commit that referenced this pull request Jun 11, 2026
Protocol-first half of the dynamic attribute value entitlement work: adds the
DynamicValueMapping / DynamicValueResolver messages and DynamicValueOperatorEnum to
objects.proto, and a dedicated DynamicValueMappingService
(policy.dynamicvaluemapping), plus regenerated protocol/go and OpenAPI/gRPC docs.

No service implementation here. This lands and releases protocol/go first so the
consumer PR (#3568) can require the new version and pass per-module 'go mod tidy'.

Refs: DSPX-2754, DSPX-3498
Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
alkalescent added a commit that referenced this pull request Jun 11, 2026
Adds the DynamicValueMapping / DynamicValueResolver messages and
DynamicValueOperatorEnum to objects.proto, and a dedicated
DynamicValueMappingService (policy.dynamicvaluemapping), with regenerated
protocol/go and OpenAPI/gRPC docs. Protocol-first half of DSPX-2754; the consumer
implementation (service/sdk/db/PDP) is PR #3568.

Includes review fixes: namespace oneof + min_len:1/uri + direct validation rules on
CreateDynamicValueMappingRequest; per-field List filter comments; and a
namespace_fqn filter (namespace_id|namespace_fqn oneof) on ListDynamicValueMappingsRequest.

Refs: DSPX-2754, DSPX-3498
Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
alkalescent added a commit that referenced this pull request Jun 15, 2026
Protocol-first half of the dynamic attribute value entitlement work: adds the
DynamicValueMapping / DynamicValueResolver messages and DynamicValueOperatorEnum to
objects.proto, and a dedicated DynamicValueMappingService
(policy.dynamicvaluemapping), plus regenerated protocol/go and OpenAPI/gRPC docs.

No service implementation here. This lands and releases protocol/go first so the
consumer PR (#3568) can require the new version and pass per-module 'go mod tidy'.

Refs: DSPX-2754, DSPX-3498
Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
alkalescent added a commit that referenced this pull request Jun 15, 2026
Adds the DynamicValueMapping / DynamicValueResolver messages and
DynamicValueOperatorEnum to objects.proto, and a dedicated
DynamicValueMappingService (policy.dynamicvaluemapping), with regenerated
protocol/go and OpenAPI/gRPC docs. Protocol-first half of DSPX-2754; the consumer
implementation (service/sdk/db/PDP) is PR #3568.

Includes review fixes: namespace oneof + min_len:1/uri + direct validation rules on
CreateDynamicValueMappingRequest; per-field List filter comments; and a
namespace_fqn filter (namespace_id|namespace_fqn oneof) on ListDynamicValueMappingsRequest.

Refs: DSPX-2754, DSPX-3498
Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
The dynamic value mapping indexing loop skipped mappings whose attribute
definition was absent from the entitleable set. The DVM table has a foreign key
to attribute_definitions (ON DELETE CASCADE), so a mapping cannot reference a
missing definition; the guard is unreachable. Remove it and read the HIERARCHY
defense-in-depth rule directly from the canonical map (nil-safe on a miss).

Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 199.992525ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 104.116187ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 683.414973ms
Throughput 146.32 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 45.490049659s
Average Latency 452.135984ms
Throughput 109.91 requests/second

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 159.567849ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 80.43147ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 353.301281ms
Throughput 283.04 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 34.415605272s
Average Latency 342.878736ms
Throughput 145.28 requests/second

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
service/internal/access/v2/helpers_test.go (1)

1131-1207: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding a case for the new hasDynamicMapping branch.

None of the three subtests exercise dynamicMappingsByDefinitionFQN populated with allowDirectEntitlements=false — the new branch added in helpers.go (lines 258-280) that admits synthetic values purely via a dynamic mapping. Integration coverage exists via pdp_dynamic_test.go, but a focused unit case here would pin down the new admission logic directly.

✅ Suggested additional subtest
t.Run("dynamic mapping present, direct entitlements disabled, synthetic value admitted", func(t *testing.T) {
	resources := []*authz.Resource{
		{
			Resource: &authz.Resource_AttributeValues_{
				AttributeValues: &authz.Resource_AttributeValues{
					Fqns: []string{attrSyntheticValueFQN},
				},
			},
		},
	}
	dynamicMappings := subjectmappingbuiltin.DynamicValueMappingsByDefinitionFQN{
		attrFQN: {{AttributeDefinition: attr}},
	}

	decisionableAttrs, err := getResourceDecisionableAttributes(ctx, logger,
		nil,
		nil,
		entitleableAttributesByDefinitionFQN,
		dynamicMappings,
		resources,
		false, // direct entitlements disabled
	)
	require.NoError(t, err)
	require.Contains(t, decisionableAttrs, attrSyntheticValueFQN)
})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@service/internal/access/v2/helpers_test.go` around lines 1131 - 1207, The
unit tests in getResourceDecisionableAttributes are missing coverage for the new
hasDynamicMapping path. Add a focused subtest in helpers_test.go that passes
dynamicMappingsByDefinitionFQN with a matching definition FQN, uses
allowDirectEntitlements=false, and verifies the synthetic value is accepted
without error. Use getResourceDecisionableAttributes,
entitleableAttributesByDefinitionFQN, and
subjectmappingbuiltin.DynamicValueMappingsByDefinitionFQN to locate the branch
and assert the returned decisionableAttrs contains the synthetic FQN.

Source: Path instructions

service/authorization/v2/cache.go (1)

238-244: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Refresh log omits dynamic value mappings count.

The debug log after a successful refresh reports counts for attributes, subject mappings, registered resources, and obligations, but not for the newly-added dynamic value mappings, making it harder to observe this experimental feature's cache state.

🔧 Proposed fix
 	c.logger.DebugContext(ctx,
 		"refreshed EntitlementPolicyCache",
 		slog.Int("attributes_count", len(attributes)),
 		slog.Int("subject_mappings_count", len(subjectMappings)),
+		slog.Int("dynamic_value_mappings_count", len(dynamicValueMappings)),
 		slog.Int("registered_resources_count", len(registeredResources)),
 		slog.Int("obligations_count", len(obligations)),
 	)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@service/authorization/v2/cache.go` around lines 238 - 244, The refresh debug
log in EntitlementPolicyCache is missing the new dynamic value mappings count.
Update the c.logger.DebugContext call in the refresh path to include a count
field for dynamic value mappings alongside attributes, subject mappings,
registered resources, and obligations, using the same local variable that holds
the dynamic mappings so the cache state is fully observable.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@service/authorization/v2/cache_test.go`:
- Line 24: The tests for NewEntitlementPolicyCache only cover the
allowDynamicValueMappings=false path, so add a case that creates the cache with
true and exercises the dynamic mapping branch. Update cache_test.go to hit the
ListAllDynamicValueMappings accessor and verify both the cache miss and cache
hit behavior for the dynamic-value-mapping path.

In `@service/integration/dynamic_value_mappings_test.go`:
- Around line 86-95: Add a sibling test alongside TestRejectsHierarchyDefinition
to cover validateDynamicValueResolverOperator rejecting
SUBJECT_MAPPING_OPERATOR_ENUM_NOT_IN. Use DynamicValueMappingsSuite,
createDefinition, s.resolver, and CreateDynamicValueMapping to construct a
request with an ANY_OF attribute and assert db.ErrEnumValueInvalid, matching the
existing hierarchy rejection style.
- Around line 175-180: The delete verification in the dynamic value mappings
test only checks for any error, which can hide regressions in
GetDynamicValueMapping. Update the assertion after DeleteDynamicValueMapping in
dynamic_value_mappings_test.go to require the specific db.ErrNotFound sentinel,
matching the stricter pattern already used in this test file for other policy
errors. Keep the check tied to the existing
s.db.PolicyClient.GetDynamicValueMapping call so it verifies the mapping is
truly gone.

In `@service/internal/subjectmappingbuiltin/dynamic_value_mapping_builtin.go`:
- Around line 29-79: EvaluateDynamicValueMappingsWithActions currently appends
the same mapping actions once per matching entity in
entityRepresentation.GetAdditionalProps(), which can duplicate actions for a
single valueFQN when multiple entities satisfy the same mapping. Update the
logic so each mapping/valueFQN contributes actions at most once across all
entities, using an existential check/break after the first match rather than
appending per entity. While refactoring, keep the work centered in
EvaluateDynamicValueMappingsWithActions and avoid recomputing
resourceValueSegment inside the per-entity loop since it depends only on the
valueFQN and attribute value.

---

Outside diff comments:
In `@service/authorization/v2/cache.go`:
- Around line 238-244: The refresh debug log in EntitlementPolicyCache is
missing the new dynamic value mappings count. Update the c.logger.DebugContext
call in the refresh path to include a count field for dynamic value mappings
alongside attributes, subject mappings, registered resources, and obligations,
using the same local variable that holds the dynamic mappings so the cache state
is fully observable.

In `@service/internal/access/v2/helpers_test.go`:
- Around line 1131-1207: The unit tests in getResourceDecisionableAttributes are
missing coverage for the new hasDynamicMapping path. Add a focused subtest in
helpers_test.go that passes dynamicMappingsByDefinitionFQN with a matching
definition FQN, uses allowDirectEntitlements=false, and verifies the synthetic
value is accepted without error. Use getResourceDecisionableAttributes,
entitleableAttributesByDefinitionFQN, and
subjectmappingbuiltin.DynamicValueMappingsByDefinitionFQN to locate the branch
and assert the returned decisionableAttrs contains the synthetic FQN.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8a4b35fb-436d-41a5-b2b2-d8e6df7510cf

📥 Commits

Reviewing files that changed from the base of the PR and between b3aa840 and f70b321.

📒 Files selected for processing (28)
  • service/authorization/v2/authorization.go
  • service/authorization/v2/cache.go
  • service/authorization/v2/cache_test.go
  • service/authorization/v2/config.go
  • service/integration/dynamic_value_mappings_test.go
  • service/internal/access/v2/evaluate.go
  • service/internal/access/v2/helpers.go
  • service/internal/access/v2/helpers_test.go
  • service/internal/access/v2/just_in_time_pdp.go
  • service/internal/access/v2/pdp.go
  • service/internal/access/v2/pdp_dynamic_test.go
  • service/internal/access/v2/policy_store.go
  • service/internal/access/v2/validators.go
  • service/internal/subjectmappingbuiltin/dynamic_value_mapping_builtin.go
  • service/internal/subjectmappingbuiltin/dynamic_value_mapping_builtin_test.go
  • service/logger/audit/constants.go
  • service/pkg/server/services_test.go
  • service/policy/adr/0005-dynamic-attribute-value-entitlements-spike.md
  • service/policy/db/attributes.go
  • service/policy/db/dynamic_value_mappings.go
  • service/policy/db/dynamic_value_mappings.sql.go
  • service/policy/db/migrations/20260618000000_add_dynamic_value_mappings.sql
  • service/policy/db/models.go
  • service/policy/db/queries/dynamic_value_mappings.sql
  • service/policy/db/subject_mappings.go
  • service/policy/db/utils.go
  • service/policy/dynamicvaluemapping/dynamic_value_mapping.go
  • service/policy/policy.go
💤 Files with no reviewable changes (12)
  • service/policy/db/attributes.go
  • service/pkg/server/services_test.go
  • service/policy/db/subject_mappings.go
  • service/policy/db/utils.go
  • service/policy/policy.go
  • service/policy/db/dynamic_value_mappings.sql.go
  • service/policy/adr/0005-dynamic-attribute-value-entitlements-spike.md
  • service/policy/db/models.go
  • service/policy/dynamicvaluemapping/dynamic_value_mapping.go
  • service/policy/db/dynamic_value_mappings.go
  • service/policy/db/migrations/20260618000000_add_dynamic_value_mappings.sql
  • service/policy/db/queries/dynamic_value_mappings.sql

Comment thread service/authorization/v2/cache_test.go
Comment thread service/integration/dynamic_value_mappings_test.go
Comment thread service/integration/dynamic_value_mappings_test.go
- EvaluateDynamicValueMappingsWithActions now flattens entities once and matches
  each mapping existentially across all entities, appending its actions at most
  once per value FQN. Previously multiple matching entities (e.g. person +
  client) duplicated the entitlement, and the resource value segment was
  recomputed per entity.
- Add integration coverage for NOT_IN operator rejection (ErrEnumValueInvalid).
- Assert ErrNotFound after dynamic value mapping delete.
- Add authz cache coverage for the enabled dynamic-value-mappings path.

Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 186.925403ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 90.291417ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 415.398046ms
Throughput 240.73 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 42.220140486s
Average Latency 419.830339ms
Throughput 118.43 requests/second

@alkalescent
alkalescent enabled auto-merge July 6, 2026 14:35
Comment thread service/policy/db/dynamic_value_mappings.go Outdated
Comment thread service/internal/subjectmappingbuiltin/dynamic_value_mapping_builtin.go Outdated
Comment thread service/policy/dynamicvaluemapping/dynamic_value_mapping.go Outdated
Comment thread service/policy/db/subject_mappings.go
Comment thread service/internal/subjectmappingbuiltin/dynamic_value_mapping_builtin.go Outdated
Comment thread service/internal/access/v2/pdp.go
Comment thread service/authorization/v2/cache.go Outdated
- Forbid attribute values under a definition with a dynamic value mapping from
  being added to a registered resource's action attribute values, mirroring the
  value-level subject-mapping coexistence rule (shared definitionHasDynamicValueMapping
  helper; enforced in createRegisteredResourceActionAttributeValues).
- Name the dynamic value resolver operator errors so the PDP/authz layer can
  errors.Is them and log malformed policy.
- Remove dead not-found check in GetDynamicValueMapping (:one already returns it).
- Gate the authz cache Set on allow_dynamic_value_mappings so a disabled feature
  does not cache an empty slice.
- Use slog.Any for error logging in the DVM service.
- Document subject-set AND / mapping OR semantics and the IN_CONTAINS substring
  over-match caution in ADR 0005 and code comments.
- Add integration coverage for the registered-resource coexistence guard.

Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 195.751991ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 112.818639ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 451.828386ms
Throughput 221.32 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 44.175845206s
Average Latency 439.899641ms
Throughput 113.18 requests/second

Comment thread service/integration/dynamic_value_mappings_test.go
…tion doc, ERD)

Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 173.441835ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 74.97682ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 418.321443ms
Throughput 239.05 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 29.944184973s
Average Latency 298.480671ms
Throughput 166.98 requests/second

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Govulncheck found vulnerabilities ⚠️

The following modules have known vulnerabilities:

  • examples
  • otdfctl
  • sdk
  • service
  • lib/fixtures
  • tests-bdd

See the workflow run for details.

@alkalescent
alkalescent added this pull request to the merge queue Jul 17, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jul 17, 2026
@alkalescent
alkalescent added this pull request to the merge queue Jul 17, 2026
Merged via the queue into main with commit 21e95e0 Jul 17, 2026
46 checks passed
@alkalescent
alkalescent deleted the DSPX-2754-dynamic-attribute-values-impl branch July 17, 2026 04:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp:authorization comp:db DB component comp:policy Policy Configuration ( attributes, subject mappings, resource mappings, kas registry) comp:sdk A software development kit, including library, for client applications and inter-service communicati docs Documentation size/xl

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants