Skip to content

fix(ers): fix direct entitlements silently dropped on token-identifier decisions - #3908

Merged
elizabethhealy merged 5 commits into
mainfrom
fix/dspx-4452-fix-direct-entitlement-token-path
Aug 27, 2026
Merged

fix(ers): fix direct entitlements silently dropped on token-identifier decisions#3908
elizabethhealy merged 5 commits into
mainfrom
fix/dspx-4452-fix-direct-entitlement-token-path

Conversation

@elizabethhealy

@elizabethhealy elizabethhealy commented Aug 20, 2026

Copy link
Copy Markdown
Member

Proposed Changes

Fixes a regression in the access decision flow where direct entitlements present on JWT claims were silently dropped when decisions were made via token identifiers (token → entity chain shortcut path), and adds regression coverage across unit + BDD tests.

Changes:

  • Force ERS hydration when resolved token-chain claims include direct-entitlements claim keys so entitlements are preserved on entity representations.
  • Add unit tests to verify hydration is triggered and that both direct_entitlements and directEntitlements claim keys are handled.
  • Add BDD scenarios + step support to mint JWTs with direct entitlements and exercise the token-identifier decision path.

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

Summary by CodeRabbit

  • Bug Fixes
    • Direct entitlements are now preserved when resolving permissions through token identifiers.
    • Supports both direct_entitlements and directEntitlements claim formats.
    • Prevents direct entitlements from being omitted during token-chain processing.
  • Tests
    • Added regression coverage confirming matching actions return PERMIT and mismatched actions return DENY.

@coderabbitai

coderabbitai Bot commented Aug 20, 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 Plus

Run ID: c87687d2-4553-45be-9ea6-f915d6ec9451

📥 Commits

Reviewing files that changed from the base of the PR and between 98f4ec6 and f265ee4.

📒 Files selected for processing (6)
  • service/entityresolution/claims/v2/entity_resolution.go
  • service/internal/access/v2/just_in_time_pdp.go
  • service/internal/access/v2/just_in_time_pdp_test.go
  • tests-bdd/cukes/steps_directentitlements.go
  • tests-bdd/features/direct-entitlements.feature
  • tests-bdd/go.mod

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Changes

The change centralizes supported direct-entitlement claim keys. Token-chain processing now requires ERS hydration when these claims are present. Unit and BDD tests cover entitlement preservation and permit or deny decisions.

Direct entitlement hydration

Layer / File(s) Summary
Centralize direct-entitlement claim parsing
service/entityresolution/claims/v2/entity_resolution.go
The parser exposes snake_case and camelCase claim keys and iterates the shared list when extracting direct entitlements.
Require ERS hydration for token chains
service/internal/access/v2/just_in_time_pdp.go, service/internal/access/v2/just_in_time_pdp_test.go
Resolved chains containing direct-entitlement claims now use ERS hydration. Unit tests cover both claim key variants and verify preserved entitlements.
Exercise token-based entitlement decisions
tests-bdd/cukes/steps_directentitlements.go, tests-bdd/features/direct-entitlements.feature, tests-bdd/go.mod
BDD steps mint signed subject tokens with direct entitlements. Scenarios verify PERMIT for matching actions and DENY for mismatched actions.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to f265e

The PR makes a localized correction to direct entitlement handling on token-identifier decisions with corresponding test updates; no actionable merge-blocking risk remains beyond normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant JustInTimePDP
  participant ERS
  Client->>JustInTimePDP: submit token chain
  JustInTimePDP->>JustInTimePDP: detect direct-entitlement claim
  JustInTimePDP->>ERS: hydrate resolved chain
  ERS-->>JustInTimePDP: return representation with entitlements
  JustInTimePDP-->>Client: evaluate action as PERMIT or DENY
Loading

Suggested reviewers: alkalescent

Poem

A rabbit found claims in a token so bright
It sent them to ERS for a careful rewrite
The keys hopped in both snake and camel attire
Tests checked each action by permit’s warm fire
Mismatches were denied, and the burrow slept tight

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 10 functions across 4 files. (2 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main fix: preventing direct entitlements from being silently dropped during token-identifier decisions.
Full details: Docstring Coverage

Explanation

Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 10 functions across 4 files. (2 skipped: 2 unsupported.)

✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/dspx-4452-fix-direct-entitlement-token-path

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

Copy link
Copy Markdown
Contributor

@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 215.855821ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 453.481911ms
Throughput 220.52 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 44.146741015s
Average Latency 440.597796ms
Throughput 113.26 requests/second

@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 223.662489ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 443.531916ms
Throughput 225.46 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 42.006164249s
Average Latency 419.077907ms
Throughput 119.03 requests/second

@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 168.491088ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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.71408ms
Throughput 282.71 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 33.259315629s
Average Latency 332.065646ms
Throughput 150.33 requests/second

Comment thread service/internal/access/v2/just_in_time_pdp.go Outdated
@elizabethhealy
elizabethhealy marked this pull request as ready for review August 25, 2026 17:00
@elizabethhealy
elizabethhealy requested review from a team as code owners August 25, 2026 17:00
@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 227.902988ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 431.378416ms
Throughput 231.82 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 43.961409591s
Average Latency 438.634995ms
Throughput 113.74 requests/second

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

Fixes a regression in the access decision flow where direct entitlements present on JWT claims were silently dropped when decisions were made via token identifiers (token → entity chain shortcut path), and adds regression coverage across unit + BDD tests.

Changes:

  • Force ERS hydration when resolved token-chain claims include direct-entitlements claim keys so entitlements are preserved on entity representations.
  • Add unit tests to verify hydration is triggered and that both direct_entitlements and directEntitlements claim keys are handled.
  • Add BDD scenarios + step support to mint JWTs with direct entitlements and exercise the token-identifier decision path.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests-bdd/go.mod Adds a direct dependency on lestrrat-go/jwx/v2 for JWT minting in BDD steps.
tests-bdd/features/direct-entitlements.feature Adds BDD regression scenarios for token-based direct-entitlement permit/deny behavior.
tests-bdd/cukes/steps_directentitlements.go Implements a new step to mint/store JWTs with direct entitlements for token-identifier decisioning.
service/internal/access/v2/just_in_time_pdp.go Detects direct-entitlement claim keys on resolved token-chain claims and forces ERS hydration to avoid dropping entitlements.
service/internal/access/v2/just_in_time_pdp_test.go Adds unit regression tests asserting hydration is required/preserved for both claim-key variants.
service/entityresolution/claims/v2/entity_resolution.go Centralizes the supported direct-entitlements claim keys and uses them during parsing.
Suppressed comments (1)

service/internal/access/v2/just_in_time_pdp.go:445

  • Hydration is forced whenever the direct-entitlements claim key exists, even if direct entitlements are disabled (or the claim is present but empty). That can introduce an extra ERS ResolveEntities call for tokens that won’t use direct entitlements. Consider gating this on the PDP’s allowDirectEntitlements flag (and possibly checking for a non-empty list) to avoid unnecessary RPCs.
		// Direct entitlements are carried inline on the claims. Taking the no-rehydrate
		// shortcut here would silently drop them, so defer to ERS whenever the claim is present.
		if key, ok := directEntitlementClaimKey(&claimsStruct); ok {
			return nil, fmt.Errorf("%w: entity %s carries %q claims", errResolvedTokenChainRequiresHydration, chained.GetEphemeralId(), key)
		}

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread service/entityresolution/claims/v2/entity_resolution.go Outdated
Comment thread service/internal/access/v2/just_in_time_pdp.go
Comment thread tests-bdd/cukes/steps_directentitlements.go
@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 226.577199ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 440.810816ms
Throughput 226.85 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 43.765776514s
Average Latency 436.914795ms
Throughput 114.24 requests/second

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Govulncheck found vulnerabilities ⚠️

The following modules have known vulnerabilities:

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

See the workflow run for details.

@elizabethhealy
elizabethhealy added this pull request to the merge queue Aug 27, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 27, 2026
@elizabethhealy
elizabethhealy added this pull request to the merge queue Aug 27, 2026
Merged via the queue into main with commit ec88620 Aug 27, 2026
46 checks passed
@elizabethhealy
elizabethhealy deleted the fix/dspx-4452-fix-direct-entitlement-token-path branch August 27, 2026 20:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants