Skip to content

feat(policy): Add the ability to do substring search - #3551

Merged
c-r33d merged 13 commits into
mainfrom
search-term-impl
Jun 16, 2026
Merged

feat(policy): Add the ability to do substring search#3551
c-r33d merged 13 commits into
mainfrom
search-term-impl

Conversation

@c-r33d

@c-r33d c-r33d commented May 29, 2026

Copy link
Copy Markdown
Contributor

General goal

Search for policy objects with a List req by specifying a Search term. The search term is simply that, a word or phrase. We do this by using the LIKE or ILIKE command depending on the specific RPC.

The following sanitization is done for each query:

  • Whitespace is removed from the beginning and end of the term
  • Characters that are used by LIKE\ILIKE such as % and _ are escaped before being queried.

Note

Currently there is no goal to optimize this strategy, this is to serve as a starting point. In the case optimizations are needed
we can look into adding GIN indexes and pg_trgm for better fuzziness matching.

Implementations

RPC Searchable fields
ListNamespaces Namespace FQN (attribute_fqns.fqn)
ListAttributes Attribute FQN (attribute_fqns.fqn)
ListKeyAccessServers KAS name (key_access_servers.name), KAS URI (key_access_servers.uri)
ListKeys Key ID (kas_keys.key_id)
ListObligations Obligation FQN (<namespace fqn>/obl/<obligation name>)
ListRegisteredResources Registered resource name (registered_resources.name)
ListSubjectMappings Attribute value FQN (attribute_fqns.fqn), metadata label values (metadata.labels.*)
ListSubjectConditionSets Metadata label values (metadata.labels.*)

Summary by CodeRabbit

  • New Features

    • Added search functionality to list operations for attributes, namespaces, obligations, registered resources, and key access servers, with minimum search term length of 1 character enforced.
  • Documentation

    • Updated OpenAPI specifications to reflect search parameter additions and validation constraints across policy services.
  • Tests

    • Added comprehensive integration test coverage for search behavior, including wildcard escaping, filtering combinations, and pagination.

@coderabbitai

coderabbitai Bot commented May 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds server-side substring search filtering to eight policy list RPCs (attributes, namespaces, KAS registry, KAS keys, obligations, registered resources, subject mappings, subject condition sets). Enforces min_len: 1 on Search.term and removes search fields from ListObligationTriggersRequest and ListRegisteredResourceValuesRequest. Bumps sqlc to v1.31.1 and ships validator unit tests plus integration tests for all new search paths.

Changes

Policy List Search + sqlc v1.31.1

Layer / File(s) Summary
Proto and OpenAPI contract changes
service/policy/selectors.proto, service/policy/obligations/obligations.proto, service/policy/registeredresources/registered_resources.proto, docs/openapi/policy/.../*.openapi.yaml, docs/grpc/index.html, protocol/go/CHANGELOG.md, .github/release-please/release-please-manifest.json
Search.term gains min_len: 1; ListObligationTriggersRequest drops its search field; ListRegisteredResourceValuesRequest replaces search with pagination; all downstream OpenAPI/gRPC docs and the protocol changelog are updated to 0.33.0.
sqlc v1.31.1 toolchain bump
Makefile, .github/workflows/checks.yaml, service/policy/db/actions.sql.go, service/policy/db/attribute_fqn.sql.go, service/policy/db/attribute_values.sql.go, service/policy/db/copyfrom.go, service/policy/db/db.go, service/policy/db/key_management.sql.go, service/policy/db/models.go, service/policy/db/resource_mapping.sql.go
SQLC version requirement and install step bumped from 1.31.0 to 1.31.1; all regenerated file headers updated accordingly.
DB search pattern helper
service/policy/db/utils.go, service/policy/db/utils_test.go
Introduces pgtypeSubstringSearchPattern and escapeLikePattern to produce a lowercased, trimmed, LIKE-wildcard-escaped %…% pgtype.Text; table-driven tests verify empty/whitespace invalidity, escaping, and literal SQL input preservation.
SQL query search filter extensions
service/policy/db/queries/attributes.sql, service/policy/db/queries/namespaces.sql, service/policy/db/queries/key_access_server_registry.sql, service/policy/db/queries/obligations.sql, service/policy/db/queries/registered_resources.sql, service/policy/db/queries/subject_mappings.sql
Raw SQL queries gain optional @search LIKE/ILIKE predicates; obligations and registered_resources migrate total counting from a counted CTE to COUNT(*) OVER(); subject_mappings introduces a filtered_subject_mappings CTE; KAS registry adds a filtered CTE.
Generated sqlc Go search wiring
service/policy/db/attributes.sql.go, service/policy/db/namespaces.sql.go, service/policy/db/key_access_server_registry.sql.go, service/policy/db/obligations.sql.go, service/policy/db/registered_resources.sql.go, service/policy/db/subject_mappings.sql.go
All affected sqlc-generated files are regenerated: param structs gain Search pgtype.Text, SQL placeholder indices are renumbered, and query invocation argument lists include arg.Search.
DB Go method search wiring
service/policy/db/attributes.go, service/policy/db/namespaces.go, service/policy/db/key_access_server_registry.go, service/policy/db/obligations.go, service/policy/db/registered_resources.go, service/policy/db/subject_mappings.go
Each list method derives a pgtypeSubstringSearchPattern from r.GetSearch().GetTerm() and passes it into the corresponding query params struct.
Validator unit tests for Search
service/policy/attributes/attributes_test.go, service/policy/namespaces/namespaces_test.go, service/policy/kasregistry/key_access_server_registry_test.go, service/policy/kasregistry/key_access_server_registry_keys_test.go, service/policy/obligations/obligations_test.go, service/policy/registeredresources/registered_resources_test.go, service/policy/subjectmapping/subject_condition_set_test.go, service/policy/subjectmapping/subject_mapping_test.go
Unit tests confirm that a non-empty Search.Term passes validation, an absent Search passes, and an empty Search{} fails with a string.min_len error.
Integration tests for list search
service/integration/attributes_test.go, service/integration/namespaces_test.go, service/integration/kas_registry_test.go, service/integration/kas_registry_key_test.go, service/integration/obligations_test.go, service/integration/registered_resources_test.go, service/integration/subject_mappings_test.go, service/integration/utils.go
Integration tests for all eight list RPCs cover FQN/name/URI search, wildcard-literal escaping, search combined with state/namespace filters, empty/whitespace equivalence, and pagination-after-filtering; sort-test cleanup helpers are renamed; KAS key tests migrate to s.T().Cleanup; deleteNamespaces utility is added.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • opentdf/platform#3552: Implements the same ListNamespaces substring search with identical DB query changes and accompanying tests.
  • opentdf/platform#3554: Directly overlaps with this PR's ListAttributes search wiring in service/policy/db/attributes.go and the fqns.fqn LIKE … ESCAPE filter in attributes.sql.go.
  • opentdf/platform#3604: Introduces the same min_len: 1 tightening on policy.Search.term and the corresponding removal of search from obligations/registered resources request schemas.

Suggested labels

comp:db, size/xl

Suggested reviewers

  • elizabethhealy
  • jakedoublev

Poem

🐇 Hop, hop, the search is live!
No empty terms shall survive —
LIKE patterns trim and escape with care,
Eight list endpoints freshly bare.
The rabbit finds what's sought with glee,
Wildcard-safe and paginated, free! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.00% 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 'feat(policy): Add the ability to do substring search' accurately summarizes the main change: adding substring search functionality to policy object listing operations across multiple RPCs.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

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

@github-actions github-actions Bot added comp:policy Policy Configuration ( attributes, subject mappings, resource mappings, kas registry) docs Documentation labels May 29, 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 standardized substring search mechanism across the policy service API. By adding a reusable Search message type to various List request objects, it enables clients to filter resources using a search term. The implementation includes necessary protocol buffer updates, documentation adjustments, and validation logic to ensure search terms are handled correctly.

Highlights

  • New Search Capability: Introduced a new Search message type in the policy selectors, allowing for substring-based searching with a defined term.
  • API Integration: Updated multiple List request messages across various policy services (Attributes, KeyAccessServers, Namespaces, Obligations, RegisteredResources, and SubjectMappings) to include the optional Search field.
  • Validation: Added strict validation for the search term length (max 253 characters) using buf.validate and included a corresponding Go unit test.
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/**/* (20)
    • 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/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/**/* (7)
    • protocol/go/policy/attributes/attributes.pb.go
    • protocol/go/policy/kasregistry/key_access_server_registry.pb.go
    • protocol/go/policy/namespaces/namespaces.pb.go
    • protocol/go/policy/obligations/obligations.pb.go
    • protocol/go/policy/registeredresources/registered_resources.pb.go
    • protocol/go/policy/selectors.pb.go
    • protocol/go/policy/subjectmapping/subject_mapping.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.


A search term added to the list, To find the data that we missed. With LIKE or ILIKE in the base, We find the items in their place.

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 Search message containing a term field and integrates it as an optional search parameter across multiple list request protobuf definitions in the policy service. It also includes updated documentation and a unit test for search term validation. The reviewer recommends enforcing a minimum length of 1 character on the search term to prevent inefficient database queries with empty strings, along with adding a corresponding test case to verify this validation.

Comment thread service/policy/selectors.proto Outdated
Comment thread service/policy/selectors_test.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 193.762597ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 436.257597ms
Throughput 229.22 requests/second

TDF3 Benchmark Results:

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

@github-actions

github-actions Bot commented Jun 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 138.459268ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 345.389784ms
Throughput 289.53 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 33.995128928s
Average Latency 338.569152ms
Throughput 147.08 requests/second

@github-actions

github-actions Bot commented Jun 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 152.654762ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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.721055ms
Throughput 242.88 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 43.221880474s
Average Latency 429.755265ms
Throughput 115.68 requests/second

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

X-Test Failure Report

@github-actions

github-actions Bot commented Jun 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 162.143515ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 351.017662ms
Throughput 284.89 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 33.582497649s
Average Latency 334.238148ms
Throughput 148.89 requests/second

@github-actions

github-actions Bot commented Jun 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 175.503321ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 696.517827ms
Throughput 143.57 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 43.558439679s
Average Latency 433.163115ms
Throughput 114.79 requests/second

@github-actions

github-actions Bot commented Jun 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 169.07553ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 471.79831ms
Throughput 211.95 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 45.129210758s
Average Latency 449.703704ms
Throughput 110.79 requests/second

@github-actions

github-actions Bot commented Jun 3, 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 189.972798ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 448.027521ms
Throughput 223.20 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 45.529077403s
Average Latency 453.865093ms
Throughput 109.82 requests/second

@github-actions

github-actions Bot commented Jun 3, 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 268.430484ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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.747948ms
Throughput 226.89 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 44.533754526s
Average Latency 443.74433ms
Throughput 112.27 requests/second

@github-actions

github-actions Bot commented Jun 3, 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.104836ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 441.708301ms
Throughput 226.39 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 46.121442304s
Average Latency 459.492499ms
Throughput 108.41 requests/second

c-r33d and others added 6 commits June 12, 2026 14:39
### Proposed Changes

1.) Add substring searching to ListNamespaces, `fqn` field.
2.) Escape characters used by `LIKE\ILIKE` from incoming input
3.) Specify `\` as the escape character

### 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



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added search functionality to namespace listing with support for name
and FQN matching
  * Search is case-insensitive and supports prefix matching
  * Search integrates with namespace state filtering (ACTIVE/INACTIVE)
* Special wildcard characters are properly escaped to prevent unexpected
matches

* **Tests**
* Added comprehensive test coverage for search functionality,
pagination, and edge cases

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
- Adds ListAttributes RPC search support by wiring request search into
the policy DB list query.
- Applies escaped, case-insensitive matching in the attributes SQL path
and adds integration coverage for search behavior, wildcard literals,
empty search, and pagination after filtering.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added search functionality for attributes, including filtering by
fully qualified name with wildcard escaping and combined namespace/state
filters.

* **Tests**
* Added comprehensive integration tests for attribute search operations,
including pagination and filter combinations.

* **Chores**
  * Updated sqlc tool to version 1.31.1.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Chris Reed <creed@virtru.com>
## Summary
- Adds ListRegisteredResources RPC search support by wiring request
search into the policy DB list query.
- Applies escaped, case-insensitive matching in the registered resources
SQL path and adds integration coverage for search behavior, wildcard
literals, namespace filters, empty/whitespace search, and pagination
after filtering.

---------

Signed-off-by: Chris Reed <creed@virtru.com>
## Summary
- Adds ListKeyAccessServers RPC search support by wiring request search
into the policy DB list query.
- Applies escaped, case-insensitive matching in the KAS registry SQL
path and adds integration coverage for search behavior, wildcard
literals, empty search, and pagination after filtering.

---------

Signed-off-by: Chris Reed <creed@virtru.com>
c-r33d and others added 2 commits June 12, 2026 14:39
## Summary
- Adds ListKeys RPC search support by wiring request search into the
policy DB list query.
- Applies escaped, case-insensitive matching in the KAS key SQL path and
adds integration coverage for search behavior, wildcard literals, empty
search, whitespace handling, and pagination after filtering.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
  * Search capability for KAS registry keys by key ID.
  * Search input automatically trims leading and trailing whitespace.
  * Wildcard characters in search queries are properly escaped.
  * Search results work seamlessly with existing filters and pagination.

* **Tests**
  * Added comprehensive test coverage for search functionality.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Chris Reed <creed@virtru.com>
@c-r33d
c-r33d marked this pull request as ready for review June 15, 2026 14:08
@c-r33d
c-r33d requested review from a team as code owners June 15, 2026 14:08
@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 154.655094ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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.441616ms
Throughput 243.05 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 41.453253308s
Average Latency 412.759953ms
Throughput 120.62 requests/second

@c-r33d
c-r33d force-pushed the search-term-impl branch from f9b004c to 132a9b8 Compare June 15, 2026 14:18
@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 186.968162ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 424.398551ms
Throughput 235.63 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 43.294514808s
Average Latency 431.100288ms
Throughput 115.49 requests/second

## Summary

Adds proto validation coverage for `policy.Search` on each List RPC that
supports search.

  ## Changes

- Added validation tests confirming search can be provided with a
non-empty term.
  - Added validation tests confirming search can be omitted.
- Added validation tests confirming present-but-empty search fails
validation.
- Updated existing `ListNamespacesRequest` search validation to include
the empty-search failure case.

---------

Signed-off-by: Chris Reed <creed@virtru.com>
Co-authored-by: opentdf-automation[bot] <149537512+opentdf-automation[bot]@users.noreply.github.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 194.884776ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 439.339133ms
Throughput 227.61 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 45.825586143s
Average Latency 455.611686ms
Throughput 109.11 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: 8

Caution

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

⚠️ Outside diff range comments (1)
service/policy/db/queries/key_access_server_registry.sql (1)

97-117: ⚠️ Potential issue | 🟡 Minor

Resolve duplicate kas alias to avoid SQLFluff AL04 failures.

The kas alias is used twice in the same query: for the outer FROM filtered AS kas (line 97) and for the inner INNER JOIN key_access_servers kas (line 115). While SQL scoping prevents runtime issues, duplicate aliases violate SQLFluff's AL04 rule and reduce code clarity. Renaming the inner alias keeps semantics intact.

Suggested fix
-        INNER JOIN key_access_servers kas ON kask.key_access_server_id = kas.id
+        INNER JOIN key_access_servers kas_keys_src ON kask.key_access_server_id = kas_keys_src.id
...
-                    'kas_uri', kas.uri,
-                    'kas_id', kas.id,
+                    'kas_uri', kas_keys_src.uri,
+                    'kas_id', kas_keys_src.id,
🤖 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/policy/db/queries/key_access_server_registry.sql` around lines 97 -
117, The query uses the `kas` alias twice: once for the outer FROM clause
referencing filtered table and again in the inner subquery for the INNER JOIN
with key_access_servers table. This duplicate alias violates SQLFluff's AL04
rule and reduces clarity. Rename the inner `key_access_servers kas` alias (in
the subquery starting at line 115) to a different name (e.g., kas_server or ks)
and update the corresponding reference in the ON clause condition that
references this inner table alias to maintain correct join semantics.

Source: Linters/SAST tools

🤖 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 `@protocol/go/CHANGELOG.md`:
- Around line 6-20: The CHANGELOG.md file is missing documentation of
client-facing breaking changes for version 0.33.0. Add two breaking changes to
the BREAKING CHANGES section: first, document that Search.term now enforces a
minimum length of 1 character and will reject empty strings, and second,
document that the search field has been removed from multiple request schemas.
These changes impact the client contract and should be clearly listed in the
breaking changes section alongside the existing policy namespace fields change.

In `@service/integration/namespaces_test.go`:
- Around line 702-720: In the Test_ListNamespaces_SearchEmptyQuery_Succeeds
function, add a third ListNamespaces call with a whitespace-only search term (a
string containing only spaces, such as "   ") in addition to the existing
noSearch and emptySearch calls. Then add an assertion that the pagination total
from this whitespace-only search matches the same total as the noSearch and
emptySearch results, validating that whitespace-only search terms are properly
trimmed to empty and behave identically to both no search and empty string
search scenarios.

In `@service/integration/subject_mappings_test.go`:
- Around line 1238-1241: The tests at
service/integration/subject_mappings_test.go lines 1238-1241 and 1725-1727
create multiple rows in rapid succession and then assert strict created_at ASC
ordering. Without spacing between inserts, equal timestamps cause flaky test
ordering failures. Add small delays between the createSearchSubjectMapping calls
in both the loop at lines 1238-1241 and the sequential calls at lines 1725-1727
to ensure each row has a distinct timestamp, making the ordering deterministic
and preventing intermittent test failures.

In `@service/policy/db/key_access_server_registry.sql.go`:
- Around line 647-651: The kas.name search condition uses case-sensitive LIKE
matching while pgtypeSubstringSearchPattern lowercases the search input, causing
mixed-case KAS names to be missed; additionally, kas.uri in the same condition
correctly uses case-insensitive ILIKE, creating inconsistency. Update the source
SQL files (not the generated .sql.go files) to change kas.name LIKE to kas.name
ILIKE for case-insensitive matching, apply the same LIKE to ILIKE change in
registered_resources.sql, then regenerate the sqlc code to update all generated
Go files.

In `@service/policy/db/obligations.sql.go`:
- Around line 1746-1752: The SQL queries use case-sensitive LIKE operators
instead of case-insensitive ILIKE, causing searches to fail when FQN or value
casing differs from the search term. In service/policy/db/obligations.sql.go at
lines 1746-1752, replace LIKE with ILIKE in the expression CONCAT_WS('/',
fqns.fqn, 'obl', od.name) LIKE $3::text to enable case-insensitive matching for
the obligation name/FQN search. In service/policy/db/subject_mappings.sql.go at
lines 539-547, replace LIKE with ILIKE in the expression fqns.fqn LIKE $7::TEXT
to align with the case-insensitive label.value ILIKE in the parallel OR branch
of the same condition.

In `@service/policy/db/queries/attributes.sql`:
- Around line 47-52: The LIKE operator used in the attribute FQN search
condition is case-sensitive, but since stored FQN values may contain mixed case
while search input is lowercased, valid matches will be missed. Replace the LIKE
operator with ILIKE in the search condition on the fqns.fqn column to enable
case-insensitive pattern matching. Keep the ESCAPE clause as-is.

In `@service/policy/db/queries/obligations.sql`:
- Around line 201-204: The search predicate in the obligation query uses the
case-sensitive LIKE operator to match against the concatenated FQN path, but the
search input is already lowercased upstream via pgtypeSubstringSearchPattern().
Since FQNs can contain mixed-case components (e.g., https://Example.com), the
comparison will fail. Replace the LIKE operator with ILIKE (PostgreSQL's
case-insensitive variant) on the line that compares CONCAT_WS('/', fqns.fqn,
'obl', od.name) against the search parameter, or alternatively apply LOWER() to
the CONCAT_WS expression to match the lowercased search term.

In `@service/policy/db/queries/subject_mappings.sql`:
- Around line 133-136: The FQN search condition on line 135 uses the
case-sensitive LIKE operator, while line 139 uses the case-insensitive ILIKE
operator for the same search parameter when matching labels, creating an
inconsistency. Replace the LIKE operator with ILIKE in the condition that checks
fqns.fqn against the search parameter to ensure FQN matching is case-insensitive
and consistent with the label matching behavior below it, allowing searches to
correctly match FQN values regardless of casing differences.

---

Outside diff comments:
In `@service/policy/db/queries/key_access_server_registry.sql`:
- Around line 97-117: The query uses the `kas` alias twice: once for the outer
FROM clause referencing filtered table and again in the inner subquery for the
INNER JOIN with key_access_servers table. This duplicate alias violates
SQLFluff's AL04 rule and reduces clarity. Rename the inner `key_access_servers
kas` alias (in the subquery starting at line 115) to a different name (e.g.,
kas_server or ks) and update the corresponding reference in the ON clause
condition that references this inner table alias to maintain correct join
semantics.
🪄 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: cd7eb0be-5e0a-4bb9-b46d-5fa6cb6f0fab

📥 Commits

Reviewing files that changed from the base of the PR and between 40f35df and 12e8a22.

⛔ Files ignored due to path filters (3)
  • protocol/go/policy/obligations/obligations.pb.go is excluded by !**/*.pb.go
  • protocol/go/policy/registeredresources/registered_resources.pb.go is excluded by !**/*.pb.go
  • protocol/go/policy/selectors.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (59)
  • .github/release-please/release-please-manifest.json
  • .github/workflows/checks.yaml
  • Makefile
  • docs/grpc/index.html
  • docs/openapi/policy/attributes/attributes.openapi.yaml
  • docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml
  • docs/openapi/policy/namespaces/namespaces.openapi.yaml
  • docs/openapi/policy/obligations/obligations.openapi.yaml
  • docs/openapi/policy/registeredresources/registered_resources.openapi.yaml
  • docs/openapi/policy/selectors.openapi.yaml
  • docs/openapi/policy/subjectmapping/subject_mapping.openapi.yaml
  • protocol/go/CHANGELOG.md
  • service/integration/attributes_test.go
  • service/integration/kas_registry_key_test.go
  • service/integration/kas_registry_test.go
  • service/integration/namespaces_test.go
  • service/integration/obligations_test.go
  • service/integration/registered_resources_test.go
  • service/integration/subject_mappings_test.go
  • service/integration/utils.go
  • service/policy/attributes/attributes_test.go
  • service/policy/db/actions.sql.go
  • service/policy/db/attribute_fqn.sql.go
  • service/policy/db/attribute_values.sql.go
  • service/policy/db/attributes.go
  • service/policy/db/attributes.sql.go
  • service/policy/db/copyfrom.go
  • service/policy/db/db.go
  • service/policy/db/key_access_server_registry.go
  • service/policy/db/key_access_server_registry.sql.go
  • service/policy/db/key_management.sql.go
  • service/policy/db/models.go
  • service/policy/db/namespaces.go
  • service/policy/db/namespaces.sql.go
  • service/policy/db/obligations.go
  • service/policy/db/obligations.sql.go
  • service/policy/db/queries/attributes.sql
  • service/policy/db/queries/key_access_server_registry.sql
  • service/policy/db/queries/namespaces.sql
  • service/policy/db/queries/obligations.sql
  • service/policy/db/queries/registered_resources.sql
  • service/policy/db/queries/subject_mappings.sql
  • service/policy/db/registered_resources.go
  • service/policy/db/registered_resources.sql.go
  • service/policy/db/resource_mapping.sql.go
  • service/policy/db/subject_mappings.go
  • service/policy/db/subject_mappings.sql.go
  • service/policy/db/utils.go
  • service/policy/db/utils_test.go
  • service/policy/kasregistry/key_access_server_registry_keys_test.go
  • service/policy/kasregistry/key_access_server_registry_test.go
  • service/policy/namespaces/namespaces_test.go
  • service/policy/obligations/obligations.proto
  • service/policy/obligations/obligations_test.go
  • service/policy/registeredresources/registered_resources.proto
  • service/policy/registeredresources/registered_resources_test.go
  • service/policy/selectors.proto
  • service/policy/subjectmapping/subject_condition_set_test.go
  • service/policy/subjectmapping/subject_mapping_test.go
💤 Files with no reviewable changes (3)
  • service/policy/obligations/obligations.proto
  • service/policy/registeredresources/registered_resources.proto
  • docs/grpc/index.html

Comment thread protocol/go/CHANGELOG.md
Comment thread service/integration/namespaces_test.go
Comment thread service/integration/subject_mappings_test.go
Comment thread service/policy/db/key_access_server_registry.sql.go
Comment thread service/policy/db/obligations.sql.go
Comment thread service/policy/db/queries/attributes.sql
Comment thread service/policy/db/queries/obligations.sql
Comment thread service/policy/db/queries/subject_mappings.sql
@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 246.885233ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

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

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 539.081165ms
Throughput 185.50 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 43.56977122s
Average Latency 434.105627ms
Throughput 114.76 requests/second

@github-actions

Copy link
Copy Markdown
Contributor

@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.

@c-r33d
c-r33d added this pull request to the merge queue Jun 16, 2026
Merged via the queue into main with commit 33b6fd7 Jun 16, 2026
61 of 71 checks passed
@c-r33d
c-r33d deleted the search-term-impl branch June 16, 2026 17:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp:policy Policy Configuration ( attributes, subject mappings, resource mappings, kas registry) docs Documentation size/s

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants