feat(policy): Add sort support to ListNamespaces API#3192
Conversation
Summary of ChangesHello, 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 enhances the Highlights
🧠 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. Ignored Files
Using Gemini Code AssistThe 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
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 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. Data flows, a stream, Sort it, ASC or DESC, Order brings new gleam. Footnotes
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds request-level sorting for ListNamespaces: new proto enums/messages (SortDirection, SortNamespacesType, NamespacesSort), ListNamespacesRequest gains an optional repeated sort, helper maps proto sort to SQL, listNamespaces SQL ORDER BY made dynamic, and unit + integration tests added. Changes
Sequence DiagramsequenceDiagram
participant Client
participant Service
participant DB
Client->>Service: ListNamespacesRequest (optional sort)
Service->>Service: GetNamespacesSortParams(sort)
Service->>Service: Build listNamespaces params (active, offset, limit, sortField, sortDirection)
Service->>DB: listNamespaces(params)
DB->>DB: Apply ORDER BY CASE using sortField & sortDirection
DB-->>Service: Sorted namespace rows
Service-->>Client: ListNamespacesResponse
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Code Review
This pull request effectively introduces sorting capabilities to the ListNamespaces RPC. The implementation using CASE statements in the SQL query is a practical solution for dynamic sorting with sqlc, and the addition of comprehensive integration tests is a great step towards ensuring correctness. I have identified a critical issue that could lead to a panic, along with some opportunities to improve test correctness and reliability.
Benchmark results, click to expandBenchmark authorization.GetDecisions Results:
Benchmark authorization.v2.GetMultiResourceDecision Results:
Benchmark Statistics
Bulk Benchmark Results
TDF3 Benchmark Results:
|
Benchmark results, click to expandBenchmark authorization.GetDecisions Results:
Benchmark authorization.v2.GetMultiResourceDecision Results:
Benchmark Statistics
Bulk Benchmark Results
TDF3 Benchmark Results:
|
Benchmark results, click to expandBenchmark authorization.GetDecisions Results:
Benchmark authorization.v2.GetMultiResourceDecision Results:
Benchmark Statistics
Bulk Benchmark Results
TDF3 Benchmark Results:
|
Benchmark results, click to expandBenchmark authorization.GetDecisions Results:
Benchmark authorization.v2.GetMultiResourceDecision Results:
Benchmark Statistics
Bulk Benchmark Results
TDF3 Benchmark Results:
|
f6574f1 to
c8bb6d0
Compare
Benchmark results, click to expandBenchmark authorization.GetDecisions Results:
Benchmark authorization.v2.GetMultiResourceDecision Results:
Benchmark Statistics
Bulk Benchmark Results
TDF3 Benchmark Results:
|
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
docs/grpc/index.html (2)
12352-12484:⚠️ Potential issue | 🟡 MinorDocument the actual
ListNamespacesRequest.sortcontract.Because this field is
repeated, the currentOptionaldescription makes multi-key sorting look valid, andNamespacesSortitself does not explain the single-field/default behavior. Add those semantics in the source comments before regenerating the page.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/grpc/index.html` around lines 12352 - 12484, Update the source protobuf comments to clearly document the ListNamespacesRequest.sort contract: in the comment for the ListNamespacesRequest.sort field and on the NamespacesSort message, state that although the field is declared repeated it is optional and only the first element is applied (i.e., single-field sorting / default behavior), or define the explicit multi-key merge semantics if multi-key sorting is supported; mention the default sort if none provided and reference SortNamespacesType and SortDirection. After changing the comments on ListNamespacesRequest.sort and NamespacesSort, regenerate the HTML docs so the updated contract appears in the generated page.
7401-7482:⚠️ Potential issue | 🔴 CriticalThe HTML documentation at lines 7401-7482 incorrectly documents non-existent
PageRequest.sortandSortFieldtypes.The proto sources show
PageRequest(selectors.proto) contains onlylimitandoffsetfields. There is noSortFieldmessage, and sorting is not a shared PageRequest feature.ListNamespacesRequestdefines its ownrepeated NamespacesSort sortfield, which uses the sharedSortDirectionenum but is request-specific, not a PageRequest capability.Remove the incorrect
PageRequest.sort,SortFielddocumentation, and namespace-scoped references to them. The duplicatedSortDirectiondocumentation and TOC entries should also be deduplicated.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/grpc/index.html` around lines 7401 - 7482, The generated HTML incorrectly documents a non-existent PageRequest.sort and a global SortField message; remove the PageRequest.sort entry and the SortField section/toc entries, and instead ensure any sorting docs reference the request-scoped sort types (e.g., ListNamespacesRequest -> NamespacesSort) and the shared enum SortDirection only where actually used; update/remove duplicated SortDirection TOC/section so SortDirection appears once and is linked from request-specific sort fields rather than from PageRequest or a global SortField.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/grpc/index.html`:
- Around line 7518-7545: The docs contain a duplicated enum section for
SortDirection (h3 id="policy.SortDirection") causing a repeated TOC entry;
locate the generator/template or source that emits the policy.SortDirection enum
(search for "SortDirection" or the template that renders enums) and remove the
duplicate emission (remove the redundant template block or stop processing the
same proto/enum twice), then regenerate the docs so the SortDirection enum
appears only once.
In `@docs/openapi/policy/attributes/attributes.openapi.yaml`:
- Around line 1299-1307: The OpenAPI spec incorrectly exposes a generic
policy.PageRequest.sort and policy.SortField (used by ListAttributes clients)
but the shipped proto only defines limit/offset and sorting is
namespace-specific via NamespacesSort; remove the generic sort and SortField
entries from the non-namespace OpenAPI artifacts and regenerate the namespace
OpenAPI from the final proto so only ListNamespaces (and
namespaces.ListNamespacesRequest.Sort / NamespacesSort) exposes sorting; verify
and remove the same stale shared-schema expansion wherever policy.PageRequest or
policy.SortField were added (see service/policy/db/namespaces.go usage and
ListAttributes references) and re-run spec generation from the final proto
contract.
In `@docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml`:
- Around line 972-980: The shared schema documents a hardcoded fallback "Falls
back to created_at DESC" for the `sort` property which is too specific; remove
that resource-specific default from the common `sort` field (the
`policy.SortField`/`sort` schema) and instead document any concrete fallback
per-endpoint where applicable (move the "created_at DESC" text into the endpoint
operation descriptions that actually use that default). Ensure the `sort` schema
description stays generic (e.g., "Optional: sort results. Array for future
extensibility; max 1 via protovalidate for now.") and update endpoint docs to
state their specific fallback behavior.
- Around line 1088-1102: The SortField schema currently allows a free-form
string for the field property (policy.SortField.field); change this to use a
resource-specific enum reference instead of type: string — either (a) define
per-resource enum schemas (e.g., policy.UserSortFieldFields,
policy.ProjectSortFieldFields) and replace field's type with $ref to the
appropriate enum, or (b) replace policy.SortField with a oneOf/anyOf that
references resource-specific SortField schemas so each resource's sortable field
names are strictly typed; update any request/response schemas that reference
policy.SortField to use the correct resource-specific SortField schema.
In `@docs/openapi/policy/namespaces/namespaces.openapi.yaml`:
- Around line 695-703: Clarify in the ListNamespacesRequest OpenAPI description
which sort mechanism wins: update the documentation for the resource-specific
"sort" field (items $ref '#/components/schemas/policy.SortNamespacesType' or
mention SortNamespacesType enum) to state that it takes precedence over the
generic pagination.sort (policy.SortField) and recommend clients use the
strongly-typed "sort" for namespace results; additionally add a note suggesting
deprecating pagination.sort for this endpoint (or explicitly document both if
deprecation is deferred) so consumers are not confused about precedence between
ListNamespacesRequest.pagination.sort and the endpoint-level sort field.
In `@service/policy/db/namespaces.sql.go`:
- Around line 202-213: The ORDER BY ends with a non-unique tie-breaker
(ns.created_at DESC) causing unstable pagination; update the SQL in the ORDER BY
clause to append a unique deterministic tie-breaker such as ns.id (e.g., add ",
ns.id ASC" after ns.created_at DESC or otherwise ensure ns.id is the final
ordering key) so rows with identical sort keys are ordered consistently; apply
this change in the query that generates namespaces (modify the ORDER BY in the
namespaces SQL query) and then regenerate sqlc so the updated statement lands in
service/policy/db/namespaces.sql.go.
In `@service/policy/db/queries/namespaces.sql`:
- Around line 16-25: The ORDER BY clause must include a deterministic
tie-breaker to prevent duplicate/skip across pages when created_at/updated_at
collide; update the ORDER BY in the namespaces query to append ns.id as the
final sort key (after the existing conditional cases and fallback ns.created_at
DESC) so that every ordering is stable, ensuring you reference ns.id alongside
the existing `@sort_field/`@sort_direction logic in the ORDER BY expression.
---
Outside diff comments:
In `@docs/grpc/index.html`:
- Around line 12352-12484: Update the source protobuf comments to clearly
document the ListNamespacesRequest.sort contract: in the comment for the
ListNamespacesRequest.sort field and on the NamespacesSort message, state that
although the field is declared repeated it is optional and only the first
element is applied (i.e., single-field sorting / default behavior), or define
the explicit multi-key merge semantics if multi-key sorting is supported;
mention the default sort if none provided and reference SortNamespacesType and
SortDirection. After changing the comments on ListNamespacesRequest.sort and
NamespacesSort, regenerate the HTML docs so the updated contract appears in the
generated page.
- Around line 7401-7482: The generated HTML incorrectly documents a non-existent
PageRequest.sort and a global SortField message; remove the PageRequest.sort
entry and the SortField section/toc entries, and instead ensure any sorting docs
reference the request-scoped sort types (e.g., ListNamespacesRequest ->
NamespacesSort) and the shared enum SortDirection only where actually used;
update/remove duplicated SortDirection TOC/section so SortDirection appears once
and is linked from request-specific sort fields rather than from PageRequest or
a global SortField.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: af958750-fcd6-4d3a-b700-94e241bded6a
⛔ Files ignored due to path filters (2)
protocol/go/policy/namespaces/namespaces.pb.gois excluded by!**/*.pb.goprotocol/go/policy/selectors.pb.gois excluded by!**/*.pb.go
📒 Files selected for processing (19)
docs/grpc/index.htmldocs/openapi/policy/actions/actions.openapi.yamldocs/openapi/policy/attributes/attributes.openapi.yamldocs/openapi/policy/kasregistry/key_access_server_registry.openapi.yamldocs/openapi/policy/keymanagement/key_management.openapi.yamldocs/openapi/policy/namespaces/namespaces.openapi.yamldocs/openapi/policy/obligations/obligations.openapi.yamldocs/openapi/policy/registeredresources/registered_resources.openapi.yamldocs/openapi/policy/resourcemapping/resource_mapping.openapi.yamldocs/openapi/policy/selectors.openapi.yamldocs/openapi/policy/subjectmapping/subject_mapping.openapi.yamlservice/integration/namespaces_test.goservice/policy/db/namespaces.goservice/policy/db/namespaces.sql.goservice/policy/db/queries/namespaces.sqlservice/policy/db/utils.goservice/policy/db/utils_test.goservice/policy/namespaces/namespaces.protoservice/policy/selectors.proto
Benchmark results, click to expandBenchmark authorization.GetDecisions Results:
Benchmark authorization.v2.GetMultiResourceDecision Results:
Benchmark Statistics
Bulk Benchmark Results
TDF3 Benchmark Results:
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/grpc/index.html`:
- Around line 12275-12280: Update the documentation/source proto comments for
the Namespaces RPC so the repeated field "sort" (type
policy.namespaces.NamespacesSort) clearly documents that only a single sort
entry is honored and that if none is provided the server falls back to ordering
by created_at DESC; change the comment block for the "sort" field in the
relevant .proto or template to state "Only the first sort entry is used; if
omitted the server orders by created_at DESC" and then regenerate the HTML docs
so the change appears throughout the generated pages (including the other
referenced ranges).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 60e06a80-d6ad-4e67-8a23-b6d075bc7647
📒 Files selected for processing (3)
docs/grpc/index.htmldocs/openapi/policy/namespaces/namespaces.openapi.yamldocs/openapi/policy/selectors.openapi.yaml
Added default case (same functionality as current unspecified sort)
86a0e49 to
8700eb8
Compare
Benchmark results, click to expandBenchmark authorization.GetDecisions Results:
Benchmark authorization.v2.GetMultiResourceDecision Results:
Benchmark Statistics
Bulk Benchmark Results
TDF3 Benchmark Results:
|
🤖 I have created a release *beep* *boop* --- ## [0.22.0](protocol/go/v0.21.0...protocol/go/v0.22.0) (2026-04-01) ### Features * **policy:** Add sort support to ListNamespaces API ([#3192](#3192)) ([aac86cd](aac86cd)) * **policy:** add SortField proto and update PageRequest for sort support ([#3187](#3187)) ([6cf1862](6cf1862)) --- 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>
Resolves [DSPX-2682](https://virtru.atlassian.net/browse/DSPX-2682), depends on #3187 ## Proposed Changes - Adds strongly-typed sort support to `ListAttributes` RPC, following the pattern established in #3192 (ListNamespaces) - Sortable fields: `name`, `created_at`, `updated_at` (ASC/DESC), with backward-compatible fallback to `created_at DESC` - Includes CASE WHEN ordering in both `listAttributesDetail` and `listAttributesSummary` SQL queries ## Changes - **Proto**: `SortAttributesType` enum, `AttributesSort` message, `sort` field on `ListAttributesRequest` (max 1, buf.validate) - **SQL**: CASE WHEN sort blocks in `attributes.sql` for both detail and summary queries - **Go**: `GetAttributesSortParams()` helper in `utils.go`, wired into `ListAttributes()` in `attributes.go` - **Tests**: 9 unit tests for the helper, 5 integration tests covering each sort field + direction + fallback ### Checklist - [x] I have added or updated unit tests - [x] I have added or updated integration tests (if appropriate) - [x] I have added or updated documentation [DSPX-2682]: https://virtru.atlassian.net/browse/DSPX-2682?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **New Features** * Added sorting capability for attributes with options to sort by name, creation date, or last updated date in ascending or descending order. * **Documentation** * Updated API documentation with new sorting parameters and clarified timestamp parameter constraints. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Diego <74568547+dsm20@users.noreply.github.com>
Resolves [DSPX-2685](https://virtru.atlassian.net/browse/DSPX-2685) ## Proposed Changes - Adds strongly-typed sort support to `ListSubjectMappings` RPC, following the pattern established in #3223 (ListAttributes) and #3192 (ListNamespaces) - Sortable fields: `created_at`, `updated_at` (ASC/DESC), with backward-compatible fallback to `created_at DESC` ## Changes **Proto** — `service/policy/subjectmapping/subject_mapping.proto` - `SortSubjectMappingsType` enum (`UNSPECIFIED`, `CREATED_AT`, `UPDATED_AT`) - `SubjectMappingsSort` message (field + direction) - `repeated SubjectMappingsSort sort = 11` on `ListSubjectMappingsRequest` with `max_items = 1` constraint - Regenerated protos and docs **SQL** — `service/policy/db/queries/subject_mappings.sql` - CASE WHEN ORDER BY blocks for `created_at` and `updated_at` (ASC/DESC each) - Fallback `sm.created_at DESC` + tiebreaker `sm.id ASC` **Go** — `service/policy/db/utils.go` + `service/policy/db/subject_mappings.go` - `GetSubjectMappingsSortParams()`: maps enum to SQL-compatible field/direction strings - `ListSubjectMappings` handler wired to call mapper and pass params to sqlc query - Extracted `sortFieldCreatedAt`/`sortFieldUpdatedAt` constants in `utils.go` to resolve `goconst` lint across all sort helpers **_(slightly out of scope but necessary to avoid goconst errors)_** **Tests** - 9 unit tests for the enum mapper helper (nil, empty, unspecified, each field + direction) - 5 integration tests (created_at ASC/DESC, updated_at ASC/DESC, unspecified fallback) using `createSortTestSubjectMappings` suite helper - Protovalidate sort constraint test (`Test_ListSubjectMappingsRequest_Sort`) ## Notes - `name` sort is listed in the ticket but the `subject_mappings` table has no `name` column - `otdfctl --sort` flag deferred to a follow-up, consistent with #3192 and #3223 ### Checklist - [x] I have added or updated unit tests - [x] I have added or updated integration tests (if appropriate) - [x] I have added or updated documentation [DSPX-2685]: https://virtru.atlassian.net/browse/DSPX-2685?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added sorting to the subject mappings list: sort by created_at or updated_at, ASC/DESC, max one sort field per request. * **Documentation** * gRPC and OpenAPI docs updated to describe new sort enum, sort object, and request sort field. * **Tests** * Added unit and integration tests covering sort parameter validation and ordering behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Resolves [DSPX-2686](https://virtru.atlassian.net/browse/DSPX-2686) ## Proposed Changes - Adds strongly-typed sort support to `ListSubjectConditionSets` RPC, following the pattern established in #3223 (ListAttributes) and #3255 (ListSubjectMappings) - Sortable fields: `created_at`, `updated_at` (ASC/DESC), with backward-compatible fallback to `created_at DESC` ## Changes **Proto** — `service/policy/subjectmapping/subject_mapping.proto` - `SortSubjectConditionSetsType` enum (`UNSPECIFIED`, `CREATED_AT`, `UPDATED_AT`) - `SubjectConditionSetsSort` message (field + direction) - `repeated SubjectConditionSetsSort sort = 11` on `ListSubjectConditionSetsRequest` with `max_items = 1` constraint - Regenerated protos and docs **SQL** — `service/policy/db/queries/subject_mappings.sql` - CASE WHEN sort blocks in `listSubjectConditionSets` query - Fallback `scs.created_at DESC` + tiebreaker `scs.id ASC` **Go** — `service/policy/db/utils.go` + `service/policy/db/subject_mappings.go` - `GetSubjectConditionSetsSortParams()`: maps enum to SQL-compatible field/direction strings - `ListSubjectConditionSets` handler wired to call mapper and pass params to sqlc query **Tests** - 8 unit tests for the enum mapper helper (nil, empty, unspecified, each field + direction) - 5 integration tests (created_at ASC/DESC, updated_at ASC/DESC, unspecified fallback) using `createSortTestSubjectConditionSets` suite helper - Protovalidate sort constraint test (`Test_ListSubjectConditionSetsRequest_Sort`) ## Notes - `otdfctl --sort` flag deferred to a follow-up, consistent with #3192, #3223, and #3255 ### Checklist - [x] I have added or updated unit tests - [x] I have added or updated integration tests (if appropriate) - [x] I have added or updated documentation ### Testing Instructions [DSPX-2686]: https://virtru.atlassian.net/browse/DSPX-2686?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added sorting for Subject Condition Set listings by created_at or updated_at (ASC/DESC). Requests accept at most one sort entry; default ordering is created_at DESC with deterministic tie-breaker when omitted or unspecified. * **Documentation** * Clarified shared sort-direction semantics: unspecified direction → ASC when a sort field is provided; omitted/UNSPECIFIED sort fields defer to each List endpoint’s documented default ordering. * **Tests** * Added unit and integration tests covering sort parameter handling, ordering, and validation. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Resolves DSPX-2689 Proposed Changes - Adds strongly-typed sort support to ListKeyAccessServers RPC, following the pattern established in #3223 (ListAttributes), #3255 (ListSubjectMappings), and #3272 (ListSubjectConditionSets) - Sortable fields: name, uri, created_at, updated_at (ASC/DESC), with backward-compatible fallback to created_at DESC Changes Proto — service/policy/kasregistry/key_access_server_registry.proto - SortKeyAccessServersType enum (UNSPECIFIED, NAME, URI, CREATED_AT, UPDATED_AT) - KeyAccessServersSort message (field + direction) - repeated KeyAccessServersSort sort = 11 on ListKeyAccessServersRequest with max_items = 1 constraint - Regenerated protos and docs SQL — service/policy/db/queries/key_access_server_registry.sql - CASE WHEN sort blocks in listKeyAccessServers query for 4 fields (8 blocks total) - Fallback kas.created_at DESC + tiebreaker kas.id ASC Go — service/policy/db/utils.go + service/policy/db/key_access_server_registry.go - GetKeyAccessServersSortParams(): maps enum to SQL-compatible field/direction strings - ListKeyAccessServers handler wired to call mapper and pass params to sqlc query - Extracted sortFieldName constant in utils.go to resolve goconst lint across sort helpers (slightly out of scope but necessary to avoid goconst errors, same pattern as sortFieldCreatedAt/sortFieldUpdatedAt from #3255) Tests - 12 unit tests for the enum mapper helper (nil, empty, unspecified, each field + direction) - 9 integration tests (created_at ASC/DESC, updated_at ASC/DESC, name ASC/DESC, uri ASC/DESC, unspecified fallback) using createSortTestKeyAccessServers and createNamedSortTestKeyAccessServers suite helpers - Protovalidate sort constraint test (Test_ListKeyAccessServersRequest_Sort) Notes - otdfctl --sort flag deferred to a follow-up, consistent with #3192, #3223, #3255, and #3272 ### Checklist - [x] I have added or updated unit tests - [x] I have added or updated integration tests (if appropriate) - [x] 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 sorting for Key Access Servers list (name, URI, created_at, updated_at) with ASC/DESC; single sort directive accepted; default ordering is created_at DESC then id ASC. * **Documentation** * Protocol and API docs updated to describe new sort parameters, enums/schemas, and default ordering behavior. * **Tests** * Added unit and integration tests to validate sort mapping, behavior, and single-sort request validation. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
### Proposed Changes Resolves DSPX-2690 - Adds strongly-typed sort support to ListObligations RPC, following the pattern established in #3223 (ListAttributes), #3255 (ListSubjectMappings), #3272 (ListSubjectConditionSets), and the ListKeyAccessServers PR - Sortable fields: name, fqn, created_at, updated_at (ASC/DESC), with backward-compatible fallback to created_at DESC ### Changes **Proto** — `service/policy/obligations/obligations.proto` - `SortObligationsType` enum (UNSPECIFIED, NAME, FQN, CREATED_AT, UPDATED_AT) - `ObligationsSort` message (field + direction) - `repeated ObligationsSort sort = 11` on `ListObligationsRequest` with `max_items = 1` constraint - Regenerated protos and docs **SQL** — `service/policy/db/queries/obligations.sql` - CASE WHEN sort blocks in `listObligations` query for 4 fields (8 blocks total) - FQN sort uses constructed expression `fqns.fqn || '/obl/' || LOWER(od.name)` since obligation FQNs aren't stored in `attribute_fqns` - Fallback `od.created_at DESC` **Go** — `service/policy/db/utils.go` + `service/policy/db/obligations.go` - `GetObligationsSortParams()`: maps enum to SQL-compatible field/direction strings - `ListObligations` handler wired to call mapper and pass params to sqlc query - Added `sortFieldName` and `sortFieldFQN` constants in `utils.go` (same pattern as `sortFieldCreatedAt`/`sortFieldUpdatedAt` from #3255) **Tests** - 12 unit tests for the enum mapper helper (nil, empty, unspecified, each field + direction) - 9 integration tests (name ASC/DESC, fqn ASC/DESC, created_at ASC/DESC, updated_at ASC/DESC, unspecified fallback) using `createSortTestObligations` and `createNamedSortTestObligations` suite helpers - Protovalidate sort constraint test (`Test_ListObligationsRequest_Sort`) ### Notes - otdfctl `--sort` flag deferred to a follow-up, consistent with #3192, #3223, #3255, and #3272 - Tie-breaker (`od.id ASC`) deferred to a follow-up refactoring ticket ### Checklist - [x] I have added or updated unit tests - [x] I have added or updated integration tests (if appropriate) - [x] 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 sorting to the obligations list API (name, FQN, created_at, updated_at) with ASC/DESC, single-sort-item constraint, and default ordering created_at DESC (ties by id ASC). * **Tests** * Added unit and integration tests covering all sort fields, directions, multi-namespace FQN ordering, unspecified fallback, and request validation for max-items. * **Documentation** * Updated API docs and table of contents to document sorting and removed an obsolete request description. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Diego <74568547+dsm20@users.noreply.github.com>
### Proposed Changes Resolves DSPX-2691 - Adds strongly-typed sort support to ListRegisteredResources RPC, following the pattern established in #3223 (ListAttributes), #3255 (ListSubjectMappings), #3272 (ListSubjectConditionSets), #3300 (ListObligations), and the ListKeyAccessServers PR - Sortable fields: name, created_at, updated_at (ASC/DESC), with backward-compatible fallback to created_at DESC ### Changes **Proto** — `service/policy/registeredresources/registered_resources.proto` - `SortRegisteredResourcesType` enum (UNSPECIFIED, NAME, CREATED_AT, UPDATED_AT) - `RegisteredResourcesSort` message (field + direction) - `repeated RegisteredResourcesSort sort = 11` on `ListRegisteredResourcesRequest` with `max_items = 1` constraint - Regenerated protos and docs **SQL** — `service/policy/db/queries/registered_resources.sql` - CASE WHEN sort blocks in `listRegisteredResources` query for 3 fields (6 blocks total) - Fallback `r.created_at DESC` **Go** — `service/policy/db/utils.go` + `service/policy/db/registered_resources.go` - `GetRegisteredResourcesSortParams()`: maps enum to SQL-compatible field/direction strings - `ListRegisteredResources` handler wired to call mapper and pass params to sqlc query - No new constants needed — `sortFieldName`, `sortFieldCreatedAt`, `sortFieldUpdatedAt` already exist **Tests** - 11 unit tests for the enum mapper helper (nil, empty, unspecified, each field + direction, unspecified direction default) - 7 integration tests (name ASC/DESC, created_at ASC/DESC, updated_at ASC/DESC, unspecified fallback) using `createSortTestRegisteredResources` and `createNamedSortTestRegisteredResources` suite helpers - Protovalidate sort constraint test (`TestListRegisteredResourcesRequest_Sort`) ### Notes - otdfctl `--sort` flag deferred to a follow-up, consistent with #3192, #3223, #3255, #3272, and #3300 - Tie-breaker (`r.id ASC`) deferred to a follow-up refactoring ticket ### Checklist - [x] I have added or updated unit tests - [x] I have added or updated integration tests (if appropriate) - [x] I have added or updated documentation ### Testing Instructions <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **New Features** * Added sorting functionality to registered resources lists. Sort by name, creation date, or update date in ascending or descending order. Defaults to creation date (descending) when not specified. * **Documentation** * Updated API documentation with new sorting options and default ordering behavior. * **Tests** * Added integration and unit tests covering all sorting configurations. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
🤖 I have created a release *beep* *boop* --- ## [0.14.0](opentdf/platform@service/v0.13.0...service/v0.14.0) (2026-04-21) ### ⚠ BREAKING CHANGES * **sdk:** reclassify KAS 400 errors — distinguish tamper from misconfiguration ([opentdf#3166](opentdf#3166)) * **policy:** optional namespace for RRs ([opentdf#3165](opentdf#3165)) * **policy:** Namespace subject mappings and subject condition sets. ([opentdf#3143](opentdf#3143)) * **policy:** Optional namespace on actions protos, NamespacedPolicy feature flag ([opentdf#3155](opentdf#3155)) * **policy:** add namespaced actions schema and namespace-aware action queries ([opentdf#3154](opentdf#3154)) * **policy:** only require namespace on GetAction if no id provided ([opentdf#3144](opentdf#3144)) * **policy:** add namespace field to Actions proto ([opentdf#3130](opentdf#3130)) * **policy:** namespace Registered Resources ([opentdf#3111](opentdf#3111)) * **policy:** add namespace field to RegisteredResource proto ([opentdf#3110](opentdf#3110)) ### Features * **authz:** Namespaced policy in decisioning ([opentdf#3226](opentdf#3226)) ([0355934](opentdf@0355934)) * **cli:** migrate otdfctl into platform monorepo ([opentdf#3205](opentdf#3205)) ([5177bec](opentdf@5177bec)) * fix tracing ([opentdf#3242](opentdf#3242)) ([57e5680](opentdf@57e5680)) * **policy:** add GetObligationTrigger RPC ([opentdf#3318](opentdf#3318)) ([d68e39d](opentdf@d68e39d)) * **policy:** add namespace field to Actions proto ([opentdf#3130](opentdf#3130)) ([bedc9b3](opentdf@bedc9b3)) * **policy:** add namespace field to RegisteredResource proto ([opentdf#3110](opentdf#3110)) ([04fd85d](opentdf@04fd85d)) * **policy:** add namespaced actions schema and namespace-aware action queries ([opentdf#3154](opentdf#3154)) ([c0443f1](opentdf@c0443f1)) * **policy:** add sort ListSubjectMappings API ([opentdf#3255](opentdf#3255)) ([9d5d757](opentdf@9d5d757)) * **policy:** Add sort support listregisteredresources api ([opentdf#3312](opentdf#3312)) ([91a3ff3](opentdf@91a3ff3)) * **policy:** add sort support to ListAttributes API ([opentdf#3223](opentdf#3223)) ([ec3312f](opentdf@ec3312f)) * **policy:** add sort support to ListKeyAccessServer ([opentdf#3287](opentdf#3287)) ([7fae2d7](opentdf@7fae2d7)) * **policy:** Add sort support to ListNamespaces API ([opentdf#3192](opentdf#3192)) ([aac86cd](opentdf@aac86cd)) * **policy:** add sort support to listobligations api ([opentdf#3300](opentdf#3300)) ([9221cac](opentdf@9221cac)) * **policy:** add sort support to ListSubjectConditionSets API ([opentdf#3272](opentdf#3272)) ([9010f12](opentdf@9010f12)) * **policy:** add SortField proto and update PageRequest for sort support ([opentdf#3187](opentdf#3187)) ([6cf1862](opentdf@6cf1862)) * **policy:** Enforce same namespace when actions referenced downstream ([opentdf#3206](opentdf#3206)) ([4b5463a](opentdf@4b5463a)) * **policy:** namespace Registered Resources ([opentdf#3111](opentdf#3111)) ([6db1883](opentdf@6db1883)) * **policy:** Namespace subject mappings and condition sets ([opentdf#3172](opentdf#3172)) ([6deed50](opentdf@6deed50)) * **policy:** Namespace subject mappings and subject condition sets. ([opentdf#3143](opentdf#3143)) ([3006780](opentdf@3006780)) * **policy:** optional namespace for RRs ([opentdf#3165](opentdf#3165)) ([8948018](opentdf@8948018)) * **policy:** rollback migration strategy for namespaced actions ([opentdf#3235](opentdf#3235)) ([f7e5e01](opentdf@f7e5e01)) * **policy:** Seed existing namespaces with standard actions ([opentdf#3228](opentdf#3228)) ([12136b0](opentdf@12136b0)) * **policy:** Seed namespaces with standard actions on creation + namespaced actions for obligation triggers ([opentdf#3161](opentdf#3161)) ([984d76b](opentdf@984d76b)) ### Bug Fixes * **ci:** Upgrade toolchain version to 1.25.8 ([opentdf#3116](opentdf#3116)) ([e1b7882](opentdf@e1b7882)) * **core:** do not concat slashes directly in url/file paths ([opentdf#3290](opentdf#3290)) ([114c2a7](opentdf@114c2a7)) * **deps:** bump github.com/jackc/pgx/v5 from 5.7.5 to 5.9.0 in /service ([opentdf#3316](opentdf#3316)) ([017362e](opentdf@017362e)) * **deps:** bump github.com/opentdf/platform/lib/identifier from 0.2.0 to 0.3.0 in /service ([opentdf#3162](opentdf#3162)) ([8bc5dcd](opentdf@8bc5dcd)) * **deps:** bump github.com/opentdf/platform/protocol/go from 0.16.0 to 0.17.0 in /service ([opentdf#3125](opentdf#3125)) ([29fec61](opentdf@29fec61)) * **deps:** bump github.com/opentdf/platform/protocol/go from 0.17.0 to 0.21.0 in /service ([opentdf#3220](opentdf#3220)) ([e63add2](opentdf@e63add2)) * **deps:** bump github.com/opentdf/platform/protocol/go from 0.21.0 to 0.22.0 in /service ([opentdf#3248](opentdf#3248)) ([1ebce73](opentdf@1ebce73)) * **deps:** bump github.com/opentdf/platform/protocol/go from 0.22.0 to 0.23.0 in /service ([opentdf#3271](opentdf#3271)) ([3338b8e](opentdf@3338b8e)) * **deps:** bump github.com/opentdf/platform/protocol/go from 0.23.0 to 0.24.0 in /service ([opentdf#3321](opentdf#3321)) ([78e6022](opentdf@78e6022)) * **deps:** bump github.com/opentdf/platform/protocol/go from 0.24.0 to 0.25.0 in /service ([opentdf#3333](opentdf#3333)) ([3940bf8](opentdf@3940bf8)) * **deps:** bump github.com/opentdf/platform/sdk from 0.13.0 to 0.16.0 in /service ([opentdf#3356](opentdf#3356)) ([5617077](opentdf@5617077)) * **deps:** bump go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp from 1.42.0 to 1.43.0 in /service ([opentdf#3282](opentdf#3282)) ([046374a](opentdf@046374a)) * **deps:** bump go.opentelemetry.io/otel/sdk from 1.42.0 to 1.43.0 in /service ([opentdf#3281](opentdf#3281)) ([56b33f2](opentdf@56b33f2)) * **deps:** bump google.golang.org/grpc from 1.77.0 to 1.79.3 in /service ([opentdf#3176](opentdf#3176)) ([3289502](opentdf@3289502)) * **deps:** remove direct github.com/docker/docker dependency ([opentdf#3229](opentdf#3229)) ([2becb27](opentdf@2becb27)) * **deps:** upgrade testcontainers-go to resolve vulns ([opentdf#3299](opentdf#3299)) ([72c6f9b](opentdf@72c6f9b)) * **ers:** include standard JWT claims in claims mode entity resolution ([opentdf#3196](opentdf#3196)) ([6d50da1](opentdf@6d50da1)) * **ers:** ldap multi-strategy ers ([opentdf#3117](opentdf#3117)) ([d3aaf1a](opentdf@d3aaf1a)) * **policy:** deprecate ListAttributeValues in favor of existing GetAttribute ([opentdf#3108](opentdf#3108)) ([7e17c2d](opentdf@7e17c2d)) * **policy:** make obligation trigger uniqueness client-aware ([opentdf#3114](opentdf#3114)) ([9265bc3](opentdf@9265bc3)) * **policy:** omit empty attribute values from create responses ([opentdf#3193](opentdf#3193)) ([d298378](opentdf@d298378)) * **policy:** only require namespace on GetAction if no id provided ([opentdf#3144](opentdf#3144)) ([10d0c0f](opentdf@10d0c0f)) * **policy:** Optional namespace on actions protos, NamespacedPolicy feature flag ([opentdf#3155](opentdf#3155)) ([c20f039](opentdf@c20f039)) * **policy:** order List* results by created_at ([opentdf#3088](opentdf#3088)) ([ea90ac2](opentdf@ea90ac2)) * **sdk:** normalize issuer URL before OIDC discovery ([opentdf#3261](opentdf#3261)) ([61f98c9](opentdf@61f98c9)) * **sdk:** reclassify KAS 400 errors — distinguish tamper from misconfiguration ([opentdf#3166](opentdf#3166)) ([f04a385](opentdf@f04a385)) * **sdk:** remove testcontainers from consumer dependency graph ([opentdf#3129](opentdf#3129)) ([f17dcdd](opentdf@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>
Summary
Adds strongly-typed single-field sort capability to the
ListNamespacesRPC. Defines aSortNamespacesTypeenum andNamespacesSortmessage per the strongly-typed approachagreed on in DSPX-2680, then wires it through to CASE WHEN SQL ordering via sqlc.
Resolves DSPX-2681
Depends on DSPX-2680 (shared
SortDirectionenum inselectors.proto)Changes
Proto —
service/policy/namespaces/namespaces.protoSortNamespacesTypeenum (NAME, FQN, CREATED_AT, UPDATED_AT)NamespacesSortmessage (embeds enum +SortDirection)repeated NamespacesSort sorttoListNamespacesRequestwith max 1 protovalidateconstraint
SQL —
service/policy/db/queries/namespaces.sqlcreated_at DESCfallbackGo —
service/policy/db/utils.go+service/policy/db/namespaces.goGetNamespacesSortParams: maps enum → SQL-compatible field/direction stringsListNamespaceshandler calls it viar.GetSort()Tests
unspecified fallback)
Deferred
otdfctl --sortflag forpolicy namespaces list— will hit all CLI changes after finishing changes to API.Design Decisions
Strongly-typed sort enums — Per team discussion on DSPX-2680, each entity defines
its own sort enum rather than using a generic string field. Valid sort fields are
discoverable via IDE autocomplete and enforced at compile time.
CASE WHEN ORDER BY in sqlc — Each sortable field gets two CASE blocks (ASC + DESC),
grouped by column type. The enum mapper in Go converts the proto enum to strings that
match the SQL CASE conditions.
Silent fall-through for UNSPECIFIED —
SORT_NAMESPACES_TYPE_UNSPECIFIEDreturnsempty strings, causing all CASE branches to evaluate to NULL. The
created_at DESCtiebreaker takes over.
Integration tests over unit tests — Ticket AC says "unit tests" but sort behavior
requires a real DB. Written as integration tests following existing codebase precedent.
Unit tests cover the enum mapper separately.
Test Plan
golangci-lintpasses (0 issues)go test ./service/policy/db/...)go build ./service/integration/...)Checklist
Testing Instructions
Summary by CodeRabbit
New Features
Documentation
Tests