Skip to content

feat(sdk): DSPX-2418 add attribute discovery methods#3082

Merged
marythought merged 9 commits into
mainfrom
feat/dspx-2418-discovery-methods
Feb 27, 2026
Merged

feat(sdk): DSPX-2418 add attribute discovery methods#3082
marythought merged 9 commits into
mainfrom
feat/dspx-2418-discovery-methods

Conversation

@marythought

@marythought marythought commented Feb 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds five convenience discovery methods to the Go SDK's SDK struct, addressing GitHub Discussions #947 and #1204 where developers had no ergonomic way to discover attributes or validate them before encryption.

  • ListAttributes(ctx, namespace...) — returns all active attributes, auto-paginates
  • ValidateAttributes(ctx, fqns) — fail-fast batch check that value FQNs exist before CreateTDF; returns ErrAttributeNotFound naming which FQNs are missing
  • AttributeExists(ctx, fqn) — checks that an attribute exists with any amount of values, bool return
  • AttributeValueExists(ctx, attributeFqn, value) — checks that an attribute / value combination exists -- bool return; addresses #2930
  • GetEntityAttributes(ctx, entity) — returns attribute FQNs assigned to a PE/NPE via GetEntitlements
  • Adds ErrAttributeNotFound sentinel to sdk.go

Security hardening applied during implementation

  • Pagination loop in ListAttributes capped at 1000 pages to prevent unbounded memory growth from a misbehaving server
  • ValidateAttributes enforces the server's 250-FQN limit client-side for a clear local error
  • GetEntityAttributes matches response entitlements against the requested entity ID rather than blindly returning index 0

Checklist

Testing Instructions

  • 21 unit tests in sdk/discovery_test.go covering all methods, edge cases (empty input, pagination overflow, ID mismatch, service errors, invalid FQN format)
  • go test ./sdk/... passes (pre-existing auth/oauth failure is unrelated)
  • golangci-lint run ./sdk/... — no new issues introduced
  • Docs updated in companion PR against opentdf/docs

@marythought
marythought requested review from a team as code owners February 17, 2026 21:00
@github-actions github-actions Bot added the comp:sdk A software development kit, including library, for client applications and inter-service communicati label Feb 17, 2026
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @marythought, 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 significantly enhances the Go SDK by providing a set of new methods for attribute discovery and validation. These additions aim to streamline the developer workflow by offering ergonomic ways to interact with attributes, ensuring their existence and proper assignment before critical operations like TDF creation. The changes improve the SDK's robustness and developer experience by preventing common pitfalls related to attribute management.

Highlights

  • Attribute Discovery Methods: Added four convenience discovery methods to the Go SDK's SDK struct, addressing issues where developers lacked ergonomic ways to discover or validate attributes before encryption.
  • ListAttributes Function: Introduced ListAttributes(ctx, namespace...) to return all active attributes, with automatic pagination and an optional namespace filter.
  • Attribute Validation: Implemented ValidateAttributes(ctx, fqns) for fail-fast checking that attribute FQNs exist, returning ErrAttributeNotFound for missing FQNs, and ValidateAttributeValue(ctx, fqn) as a single-FQN wrapper.
  • Entity Attribute Retrieval: Added GetEntityAttributes(ctx, entity) to retrieve attribute FQNs assigned to a given entity (PE/NPE) via GetEntitlements.
  • New Error Type: Added ErrAttributeNotFound sentinel error to sdk.go for clearer error handling.

🧠 New Feature in Public Preview: You can now enable Memory 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.

Changelog
  • sdk/discovery.go
    • Added ListAttributes function to retrieve all active attributes with pagination.
    • Added ValidateAttributes function to check for the existence of multiple attribute FQNs.
    • Added GetEntityAttributes function to fetch attributes assigned to an entity.
    • Added ValidateAttributeValue function as a wrapper for single attribute FQN validation.
    • Defined maxListAttributesPages and maxValidateFQNs constants for safety limits.
  • sdk/discovery_test.go
    • Added comprehensive unit tests for ListAttributes, covering empty results, single/multi-page responses, namespace filtering, page limit exceeding, and service errors.
    • Added comprehensive unit tests for ValidateAttributes, covering empty input, all found, some missing, all missing, too many FQNs, invalid FQN format, and service errors.
    • Added comprehensive unit tests for GetEntityAttributes, covering nil entity, found entitlements, no entitlements, ID mismatch, and service errors.
    • Added comprehensive unit tests for ValidateAttributeValue, covering valid/existing, valid/missing, and invalid format.
    • Introduced mock clients (mockDiscoveryAttributesClient, mockDiscoveryAuthzClient) and helper functions (newDiscoverySDK, makeAttr, fqnMap) for testing.
  • sdk/sdk.go
    • Added ErrAttributeNotFound sentinel error.
Activity
  • Added 21 new unit tests in sdk/discovery_test.go covering all new methods and edge cases.
  • Confirmed go test ./sdk/... passes.
  • Confirmed golangci-lint run ./sdk/... introduces no new issues.
  • Updated documentation in a companion pull request against opentdf/docs.
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 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 counter productive. 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.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.


Attributes now found, SDK guides the true path, Data flows secure.

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 several useful attribute discovery methods to the Go SDK, which will improve the developer experience for discovering and validating attributes. The implementation is well-structured and includes comprehensive unit tests. I've identified one high-severity issue in GetEntityAttributes that could lead to incorrect data being returned, and a medium-severity suggestion to improve performance in ListAttributes.

Comment thread sdk/discovery.go Outdated
Comment thread sdk/discovery.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 203.155993ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 361.121093ms
Throughput 276.92 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 39.150052759s
Average Latency 390.119879ms
Throughput 127.71 requests/second

@github-actions

Copy link
Copy Markdown
Contributor

Prefer nil over []string{} as the zero value for a slice return
when no entitlements match the requested entity ID.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mary Dickson <mary.dickson@virtru.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 161.384817ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 362.795749ms
Throughput 275.64 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 39.05372406s
Average Latency 388.400342ms
Throughput 128.03 requests/second

@github-actions

Copy link
Copy Markdown
Contributor

- Pre-allocate the result slice in ListAttributes using PageResponse.Total
  on the first page, reducing allocations when paginating large lists.
- Remove the entityID == "" short-circuit in GetEntityAttributes that
  caused the first entitlement in the response to be returned regardless
  of its entity ID when the caller passed an entity with no ID.
- Add TestGetEntityAttributes_EmptyEntityID to cover the fixed case.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mary Dickson <mary.dickson@virtru.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 190.180451ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 367.43287ms
Throughput 272.16 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 41.46831481s
Average Latency 413.071717ms
Throughput 120.57 requests/second

@github-actions

Copy link
Copy Markdown
Contributor

marythought and others added 2 commits February 17, 2026 16:36
…dd new ValidateAttributeValue

The old ValidateAttributeValue(fqn) only checked if a complete value FQN
was pre-registered on the platform. This gave false negatives for dynamic
(non-enumerated) attributes where any string value is valid.

- Rename ValidateAttributeValue(ctx, fqn) → ValidateAttributeExists(ctx, fqn)
  to make it clear the method checks pre-registered FQN existence.
- Add ValidateAttributeValue(ctx, attributeFqn, value) which fetches the
  attribute definition via GetAttribute:
  - Enumerated attribute (values non-empty): value must match case-insensitively.
  - Dynamic attribute (values empty): any string is accepted.
- Add GetAttribute to mockDiscoveryAttributesClient in tests.
- Add 6 new tests covering enumerated match, case-insensitivity, not-found,
  dynamic pass-through, attribute-not-found, and invalid FQN.
- Rename existing 3 ValidateAttributeValue tests to ValidateAttributeExists.

Fixes: orgs/opentdf/discussions/2930

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread sdk/discovery.go
Comment thread sdk/discovery.go Outdated
Comment thread sdk/discovery.go
Comment thread sdk/discovery_test.go Outdated
marythought and others added 2 commits February 19, 2026 08:46
- ListAttributes: add guard for multiple namespace args (varargs already)
- ValidateAttributes: change fqns param to variadic (...string) for cleaner call sites
- ValidateAttributeExists: update call site to use variadic form
- GetEntityAttributes: add comment explaining entity ID filter rationale
- discovery_test.go: replace context.Background() with t.Context() throughout,
  update ValidateAttributes call sites for variadic signature change

Co-authored-by: dmihalcik-virtru <dmihalcik-virtru@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.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 193.997222ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 377.411694ms
Throughput 264.96 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 39.106774379s
Average Latency 389.997913ms
Throughput 127.86 requests/second

@github-actions

Copy link
Copy Markdown
Contributor

X-Test Failure Report

opentdfplatformSNDN4O.dockerbuild

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

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 368.052206ms
Throughput 271.70 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 38.708169591s
Average Latency 384.935932ms
Throughput 129.17 requests/second

@github-actions

Copy link
Copy Markdown
Contributor

An attribute with no registered values now returns ErrAttributeNotFound
instead of silently succeeding. Also aligns the empty-value error message
with the Java and TypeScript SDKs.

Co-authored-by: dmihalcik-virtru <dmihalcik-virtru@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.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 198.660946ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 359.024145ms
Throughput 278.53 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 39.789930214s
Average Latency 396.143914ms
Throughput 125.66 requests/second

@github-actions

Copy link
Copy Markdown
Contributor

…ibuteValue with AttributeExists/AttributeValueExists

Both methods now return (bool, error) instead of throwing on not-found,
aligning with idiomatic Go conventions for existence checks.
AttributeExists uses connect.CodeNotFound to distinguish not-found from
service errors; AttributeValueExists checks the FQN map from
GetAttributeValuesByFqns.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.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 197.61078ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 373.766436ms
Throughput 267.55 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 40.511310574s
Average Latency 403.250013ms
Throughput 123.42 requests/second

@github-actions

Copy link
Copy Markdown
Contributor

@marythought
marythought added this pull request to the merge queue Feb 19, 2026
marythought added a commit to opentdf/java-sdk that referenced this pull request Feb 19, 2026
## Summary

- Add five discovery methods directly on the `SDK` class:
`listAttributes()`,
  `validateAttributes()`, `attributeExists()`, `attributeValueExists()`,
  `getEntityAttributes()`
- Add `SDK.AttributeNotFoundException extends SDKException`, thrown when
FQNs or attribute
  values are not found on the platform
- Add 26 unit tests in `DiscoveryTest.java` covering all methods and
edge cases
- docs update: opentdf/docs#186

## Rationale

Addresses GitHub discussion developer feedback. Developers currently
work with verbose Connect RPC
request/response types through `sdk.getServices().attributes()`. These
methods provide ergonomic
wrappers that:

- Auto-paginate `listAttributes()` with a 1,000-page safety cap to
prevent unbounded memory
  growth from a misbehaving server
- Validate FQN format and existence before `createTDF()` so failures
happen at encryption time
with a clear message rather than at decryption time with a cryptic
"resource not found"
- Match entity ID in the `GetEntitlements` response to prevent silent
wrong-entity attribute
  returns
- Cap `validateAttributes()` at 250 FQNs client-side to match the server
limit

Matches the API shape and security properties of the Go SDK
implementation: opentdf/platform#3082.

## Test plan

- [ ] `mvn -pl sdk test -Dtest=DiscoveryTest` — all 26 tests pass
- [ ] `mvn -pl sdk test` — no regressions in existing test suite

---------

Signed-off-by: Mary Dickson <mary.dickson@virtru.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Feb 19, 2026
@marythought
marythought added this pull request to the merge queue Feb 27, 2026
Merged via the queue into main with commit aeeaadd Feb 27, 2026
39 checks passed
@marythought
marythought deleted the feat/dspx-2418-discovery-methods branch February 27, 2026 20:40
github-merge-queue Bot pushed a commit that referenced this pull request Mar 11, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.14.0](sdk/v0.13.0...sdk/v0.14.0)
(2026-03-11)


### Features

* **sdk:** DSPX-2418 add attribute discovery methods
([#3082](#3082))
([aeeaadd](aeeaadd))


### Bug Fixes

* **ci:** Upgrade toolchain version to 1.25.8
([#3116](#3116))
([e1b7882](e1b7882))
* **policy:** order List* results by created_at
([#3088](#3088))
([ea90ac2](ea90ac2))
* **sdk:** remove testcontainers from consumer dependency graph
([#3129](#3129))
([f17dcdd](f17dcdd))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: opentdf-automation[bot] <149537512+opentdf-automation[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp:sdk A software development kit, including library, for client applications and inter-service communicati size/m

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants