Skip to content

feat(policy): DSPX-2541 add GetEntitleableAttributesByFqns API#3633

Closed
alkalescent wants to merge 3 commits into
DSPX-2541-key-mappings-apifrom
DSPX-2541-entitleable-attributes-api-v2
Closed

feat(policy): DSPX-2541 add GetEntitleableAttributesByFqns API#3633
alkalescent wants to merge 3 commits into
DSPX-2541-key-mappings-apifrom
DSPX-2541-entitleable-attributes-api-v2

Conversation

@alkalescent

@alkalescent alkalescent commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Proposed Changes

  • Add GetEntitleableAttributesByFqns, a narrow server-side decisioning read API on the attributes service: proto, regenerated protocol/go, handler, DB method, lean SQL, and tests, all in one PR (per repo convention for adding an RPC).
  • Per requested attribute value FQN it returns the attribute rule, the value id, the definition's ordered value FQNs (for hierarchy rule logic), and the value-level subject mappings. Subject mappings are fetched via a new getSubjectMappingsByValueFqns query in a single roundtrip, instead of the full ListAllSubjectMappings load the entitlement path uses today.

Stacked on #3632 (base DSPX-2541-key-mappings-api). Migrating the v1/v2 decisioning + PDP consumers onto this API and adding namespace-scoped fetch is a separate PR (it depends on the still-open tenancy model under epic DSPX-2184).

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

  • go test ./service/integration/ -run TestAttributesSuite/Test_GetEntitleableAttributesByFqns
  • golangci-lint run ./policy/db/... ./policy/attributes/... — 0 issues.

Related

Add a narrow server-side decisioning read API to the attributes service: proto, regenerated protocol/go, handler, DB method, lean SQL, and tests in one PR. Per requested attribute value FQN it returns the attribute rule, value id, the definition's ordered value FQNs (for hierarchy rule logic), and value-level subject mappings, fetched via a new getSubjectMappingsByValueFqns query in a single roundtrip instead of the full-policy load. Stacked on the GetKeyMappingsByFqns PR.

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

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1acfa36a-58af-4c52-a347-fcbc1f685175

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch DSPX-2541-entitleable-attributes-api-v2

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 and usage tips.

@github-actions github-actions Bot added comp:db DB component comp:policy Policy Configuration ( attributes, subject mappings, resource mappings, kas registry) docs Documentation labels Jun 17, 2026
@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 introduces a new read-only API endpoint, GetEntitleableAttributesByFqns, designed to streamline server-side decisioning. By optimizing the retrieval of subject mappings through a targeted SQL query, the change significantly reduces data transfer overhead compared to previous methods, improving the efficiency of the entitlement resolution path.

Highlights

  • New API Endpoint: Added the GetEntitleableAttributesByFqns API to the attributes service to support server-side decisioning and entitlement resolution.
  • Performance Optimization: Implemented a new SQL query, getSubjectMappingsByValueFqns, to fetch subject mappings in a single roundtrip, replacing the previous full-policy load.
  • Testing: Added comprehensive unit and integration tests to verify the new API functionality and ensure correct data retrieval.
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/**/* (1)
    • docs/openapi/policy/attributes/attributes.openapi.yaml
  • Ignored by pattern: protocol/**/* (3)
    • protocol/go/policy/attributes/attributes.pb.go
    • protocol/go/policy/attributes/attributes_grpc.pb.go
    • protocol/go/policy/attributes/attributesconnect/attributes.connect.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.


A new API for us to call, / To make the policy stand tall. / With mappings fetched in one quick trip, / We've optimized the entitlement ship.

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 introduces a new GetEntitleableAttributesByFqns endpoint to the AttributesService and database layer to fetch only entitlement-relevant information for requested attribute value FQNs, optimizing server-side decisioning. Feedback focuses on improving performance and type safety by explicitly casting COALESCE aggregate expressions to ::jsonb in the SQL query. This allows sqlc to generate these fields as []byte instead of interface{}, eliminating the CPU and memory overhead of double-serialization in the Go hydration logic.

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 on lines +213 to +228
COALESCE(
JSONB_AGG(JSONB_BUILD_OBJECT('id', a.id, 'name', a.name,
'namespace', CASE WHEN a.namespace_id IS NULL THEN NULL
ELSE JSONB_BUILD_OBJECT('id', ans.id, 'name', ans.name, 'fqn', ans_fqns.fqn)
END
)) FILTER (WHERE a.is_standard = TRUE),
'[]'::JSONB
) AS standard_actions,
COALESCE(
JSONB_AGG(JSONB_BUILD_OBJECT('id', a.id, 'name', a.name,
'namespace', CASE WHEN a.namespace_id IS NULL THEN NULL
ELSE JSONB_BUILD_OBJECT('id', ans.id, 'name', ans.name, 'fqn', ans_fqns.fqn)
END
)) FILTER (WHERE a.is_standard = FALSE),
'[]'::JSONB
) AS custom_actions

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.

medium

By default, sqlc infers the type of COALESCE on aggregate functions inside a CTE as interface{}, which forces pgx to parse the JSONB data into Go maps/slices. Explicitly casting these expressions to ::jsonb ensures sqlc generates them as []byte (or json.RawMessage). This avoids the overhead of parsing and re-marshalling the JSON in Go, allowing you to pass the raw bytes directly to unmarshalAllActionsProto in hydrateSubjectMappingForEntitlement.

        COALESCE(
            JSONB_AGG(JSONB_BUILD_OBJECT('id', a.id, 'name', a.name,
                'namespace', CASE WHEN a.namespace_id IS NULL THEN NULL
                    ELSE JSONB_BUILD_OBJECT('id', ans.id, 'name', ans.name, 'fqn', ans_fqns.fqn)
                END
            )) FILTER (WHERE a.is_standard = TRUE),
            '[]'::JSONB
        )::jsonb AS standard_actions,
        COALESCE(
            JSONB_AGG(JSONB_BUILD_OBJECT('id', a.id, 'name', a.name,
                'namespace', CASE WHEN a.namespace_id IS NULL THEN NULL
                    ELSE JSONB_BUILD_OBJECT('id', ans.id, 'name', ans.name, 'fqn', ans_fqns.fqn)
                END
            )) FILTER (WHERE a.is_standard = FALSE),
            '[]'::JSONB
        )::jsonb AS custom_actions

Comment on lines +308 to +315
stdActionsBytes, err := json.Marshal(row.StandardActions)
if err != nil {
return nil, fmt.Errorf("failed to marshal standard actions: %w", err)
}
customActionsBytes, err := json.Marshal(row.CustomActions)
if err != nil {
return nil, fmt.Errorf("failed to marshal custom actions: %w", err)
}

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.

medium

The StandardActions and CustomActions fields are currently marshalled back to JSON bytes using json.Marshal because they are typed as interface{} in the generated sqlc struct. This introduces unnecessary CPU and memory overhead due to double-serialization (parsing JSON in pgx -> marshalling back to JSON in Go -> unmarshalling to Proto).\n\nBy explicitly casting these fields to ::jsonb in the SQL query (see the suggestion in subject_mappings.sql), sqlc will generate them as []byte (or json.RawMessage), allowing you to pass them directly to unmarshalAllActionsProto without the json.Marshal step.

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

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 427.419286ms
Throughput 233.96 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 43.946915499s
Average Latency 437.989214ms
Throughput 113.77 requests/second

…ableAttributesByFqns

Adds the entitleable RPC wrapper method so CI's generated-code freshness check (make connect-wrapper-generate) passes.

Signed-off-by: Krish Suchak <suchak.krish@gmail.com>
@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.

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

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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.893285ms
Throughput 238.72 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 45.784757698s
Average Latency 456.209466ms
Throughput 109.21 requests/second

@alkalescent

Copy link
Copy Markdown
Contributor Author

Combined into a single PR #3634 (both narrow attribute read APIs), per discussion: they edit the same files, match the repo convention of bundling related RPCs (4c3d53d), and release as one protocol/go version.

@alkalescent alkalescent deleted the DSPX-2541-entitleable-attributes-api-v2 branch June 17, 2026 19:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp:db DB component comp:policy Policy Configuration ( attributes, subject mappings, resource mappings, kas registry) docs Documentation size/m

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant