From 13104ac9d11bbeab389268a5a7caf329e5c5d098 Mon Sep 17 00:00:00 2001 From: Elizabeth Healy Date: Thu, 6 Aug 2026 16:32:02 -0400 Subject: [PATCH 1/7] key sort on status --- docs/grpc/index.html | 6 + .../key_access_server_registry.openapi.yaml | 1 + otdfctl/pkg/handlers/kas-keys.go | 1 + .../key_access_server_registry.pb.go | 220 +++++++++--------- service/integration/kas_registry_key_test.go | 85 +++++++ .../db/key_access_server_registry.sql.go | 4 + .../db/queries/key_access_server_registry.sql | 2 + service/policy/db/utils.go | 3 + service/policy/db/utils_test.go | 16 ++ .../key_access_server_registry.proto | 2 + 10 files changed, 233 insertions(+), 107 deletions(-) diff --git a/docs/grpc/index.html b/docs/grpc/index.html index cfc09a5f05..76c6b5d5ff 100644 --- a/docs/grpc/index.html +++ b/docs/grpc/index.html @@ -13933,6 +13933,12 @@

SortKasKeysType

+ + SORT_KAS_KEYS_TYPE_KEY_STATUS + 4 +

Orders by policy.KeyStatus numeric value, not status name.

+ + diff --git a/docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml b/docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml index b8c7b84cad..096641f6e5 100644 --- a/docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml +++ b/docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml @@ -593,6 +593,7 @@ components: - SORT_KAS_KEYS_TYPE_KEY_ID - SORT_KAS_KEYS_TYPE_CREATED_AT - SORT_KAS_KEYS_TYPE_UPDATED_AT + - SORT_KAS_KEYS_TYPE_KEY_STATUS policy.kasregistry.SortKeyAccessServersType: type: string title: SortKeyAccessServersType diff --git a/otdfctl/pkg/handlers/kas-keys.go b/otdfctl/pkg/handlers/kas-keys.go index 6fa1f9d8dc..a216840b96 100644 --- a/otdfctl/pkg/handlers/kas-keys.go +++ b/otdfctl/pkg/handlers/kas-keys.go @@ -138,6 +138,7 @@ func (h Handler) ListKasKeys( "key_id": kasregistry.SortKasKeysType_SORT_KAS_KEYS_TYPE_KEY_ID, "created_at": kasregistry.SortKasKeysType_SORT_KAS_KEYS_TYPE_CREATED_AT, "updated_at": kasregistry.SortKasKeysType_SORT_KAS_KEYS_TYPE_UPDATED_AT, + "key_status": kasregistry.SortKasKeysType_SORT_KAS_KEYS_TYPE_KEY_STATUS, } field, err := sortField("KAS keys", sort, allowedFields) if err != nil { diff --git a/protocol/go/policy/kasregistry/key_access_server_registry.pb.go b/protocol/go/policy/kasregistry/key_access_server_registry.pb.go index 61fe847fae..3c7a12471e 100644 --- a/protocol/go/policy/kasregistry/key_access_server_registry.pb.go +++ b/protocol/go/policy/kasregistry/key_access_server_registry.pb.go @@ -85,6 +85,8 @@ const ( SortKasKeysType_SORT_KAS_KEYS_TYPE_KEY_ID SortKasKeysType = 1 SortKasKeysType_SORT_KAS_KEYS_TYPE_CREATED_AT SortKasKeysType = 2 SortKasKeysType_SORT_KAS_KEYS_TYPE_UPDATED_AT SortKasKeysType = 3 + // Orders by policy.KeyStatus numeric value, not status name. + SortKasKeysType_SORT_KAS_KEYS_TYPE_KEY_STATUS SortKasKeysType = 4 ) // Enum value maps for SortKasKeysType. @@ -94,12 +96,14 @@ var ( 1: "SORT_KAS_KEYS_TYPE_KEY_ID", 2: "SORT_KAS_KEYS_TYPE_CREATED_AT", 3: "SORT_KAS_KEYS_TYPE_UPDATED_AT", + 4: "SORT_KAS_KEYS_TYPE_KEY_STATUS", } SortKasKeysType_value = map[string]int32{ "SORT_KAS_KEYS_TYPE_UNSPECIFIED": 0, "SORT_KAS_KEYS_TYPE_KEY_ID": 1, "SORT_KAS_KEYS_TYPE_CREATED_AT": 2, "SORT_KAS_KEYS_TYPE_UPDATED_AT": 3, + "SORT_KAS_KEYS_TYPE_KEY_STATUS": 4, } ) @@ -4730,7 +4734,7 @@ var file_policy_kasregistry_key_access_server_registry_proto_rawDesc = []byte{ 0x45, 0x44, 0x5f, 0x41, 0x54, 0x10, 0x03, 0x12, 0x2b, 0x0a, 0x27, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x44, 0x5f, - 0x41, 0x54, 0x10, 0x04, 0x2a, 0x9a, 0x01, 0x0a, 0x0f, 0x53, 0x6f, 0x72, 0x74, 0x4b, 0x61, 0x73, + 0x41, 0x54, 0x10, 0x04, 0x2a, 0xbd, 0x01, 0x0a, 0x0f, 0x53, 0x6f, 0x72, 0x74, 0x4b, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x1e, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x4b, 0x41, 0x53, 0x5f, 0x4b, 0x45, 0x59, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, @@ -4740,119 +4744,121 @@ var file_policy_kasregistry_key_access_server_registry_proto_rawDesc = []byte{ 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x41, 0x54, 0x10, 0x02, 0x12, 0x21, 0x0a, 0x1d, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x4b, 0x41, 0x53, 0x5f, 0x4b, 0x45, 0x59, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x41, 0x54, 0x10, - 0x03, 0x32, 0x99, 0x0c, 0x0a, 0x1e, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x7e, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x41, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x2f, 0x2e, 0x70, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, + 0x03, 0x12, 0x21, 0x0a, 0x1d, 0x53, 0x4f, 0x52, 0x54, 0x5f, 0x4b, 0x41, 0x53, 0x5f, 0x4b, 0x45, + 0x59, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, + 0x55, 0x53, 0x10, 0x04, 0x32, 0x99, 0x0c, 0x0a, 0x1e, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x7e, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x4b, + 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, + 0x2f, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x30, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x78, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4b, 0x65, + 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x2d, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x03, 0x90, 0x02, 0x01, 0x12, 0x78, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x2d, 0x2e, 0x70, 0x6f, 0x6c, + 0x72, 0x79, 0x2e, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x70, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x79, 0x2e, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, + 0x01, 0x12, 0x7e, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x30, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, - 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x47, - 0x65, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x7e, - 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x30, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7e, - 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x30, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7e, - 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x30, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x90, - 0x01, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x34, 0x2e, 0x70, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x41, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0x88, 0x02, 0x01, 0x90, 0x02, - 0x01, 0x12, 0x5a, 0x0a, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x24, - 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x72, 0x79, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, - 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, - 0x06, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x47, 0x65, 0x74, - 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x70, 0x6f, 0x6c, + 0x79, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x7e, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x30, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, - 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x57, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x23, 0x2e, 0x70, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x09, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, - 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, + 0x79, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x7e, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x30, 0x2e, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x79, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x09, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x4b, - 0x65, 0x79, 0x12, 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x4b, 0x65, - 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x52, 0x6f, - 0x74, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x5d, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x12, + 0x79, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x90, 0x01, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x12, + 0x34, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, + 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, + 0x65, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x47, 0x72, + 0x61, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0x88, 0x02, + 0x01, 0x90, 0x02, 0x01, 0x12, 0x5a, 0x0a, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, + 0x79, 0x12, 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x51, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x2e, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, + 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x79, 0x2e, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x57, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x12, + 0x23, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, + 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, + 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x09, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, - 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x74, 0x42, - 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x5d, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x25, - 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x72, 0x79, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, - 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, - 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x6c, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, - 0x67, 0x73, 0x12, 0x2a, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x4d, - 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, - 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x4d, 0x61, 0x70, 0x70, 0x69, - 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0xdb, 0x01, - 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, - 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x42, 0x1c, 0x4b, 0x65, 0x79, 0x41, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x64, 0x66, 0x2f, 0x70, 0x6c, 0x61, - 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x67, - 0x6f, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2f, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x79, 0xa2, 0x02, 0x03, 0x50, 0x4b, 0x58, 0xaa, 0x02, 0x12, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0xca, - 0x02, 0x12, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5c, 0x4b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x79, 0xe2, 0x02, 0x1e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5c, 0x4b, 0x61, - 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x13, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x3a, 0x3a, - 0x4b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x73, 0x74, 0x72, 0x79, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x09, 0x52, 0x6f, 0x74, 0x61, + 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, + 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, + 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, + 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, + 0x65, 0x79, 0x12, 0x25, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, + 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x53, + 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, + 0x79, 0x12, 0x25, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x47, 0x65, + 0x74, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x6c, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x4d, 0x61, 0x70, + 0x70, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x2a, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, + 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, + 0x65, 0x79, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2b, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x6b, 0x61, 0x73, 0x72, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x4d, 0x61, + 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x42, 0xdb, 0x01, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, + 0x6b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x42, 0x1c, 0x4b, 0x65, 0x79, + 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3a, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x64, 0x66, 0x2f, + 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2f, 0x6b, 0x61, 0x73, 0x72, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0xa2, 0x02, 0x03, 0x50, 0x4b, 0x58, 0xaa, 0x02, 0x12, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x4b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x79, 0xca, 0x02, 0x12, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5c, 0x4b, 0x61, 0x73, 0x72, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0xe2, 0x02, 0x1e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x5c, 0x4b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x5c, 0x47, 0x50, 0x42, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x13, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x3a, 0x3a, 0x4b, 0x61, 0x73, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/service/integration/kas_registry_key_test.go b/service/integration/kas_registry_key_test.go index a8435ce3b3..83b037016c 100644 --- a/service/integration/kas_registry_key_test.go +++ b/service/integration/kas_registry_key_test.go @@ -2501,6 +2501,91 @@ func (s *KasRegistryKeySuite) Test_ListKeys_SortByUpdatedAt_ASC() { assertIDsInOrder(s.T(), list.GetKasKeys(), func(k *policy.KasKey) string { return k.GetKey().GetId() }, ids[0], ids[1], ids[2]) } +// rotateOneSortTestKey rotates the key at keyIDs[idx] so it becomes ROTATED, +// returning the ID of the newly created ACTIVE key. +func (s *KasRegistryKeySuite) rotateOneSortTestKey(keyIDs []string, idx int) string { + activeKey, err := s.db.PolicyClient.GetKey(s.ctx, &kasregistry.GetKeyRequest_Id{Id: keyIDs[idx]}) + s.Require().NoError(err) + + ts := time.Now().UnixNano() + rotated, err := s.db.PolicyClient.RotateKey(s.ctx, activeKey, &kasregistry.RotateKeyRequest_NewKey{ + KeyId: fmt.Sprintf("statussort-rotated-%d", ts), + Algorithm: policy.Algorithm_ALGORITHM_RSA_2048, + KeyMode: policy.KeyMode_KEY_MODE_CONFIG_ROOT_KEY, + PublicKeyCtx: &policy.PublicKeyCtx{Pem: keyCtx}, + PrivateKeyCtx: &policy.PrivateKeyCtx{ + KeyId: fmt.Sprintf("statussort-rotated-priv-%d", ts), + WrappedKey: keyCtx, + }, + }) + s.Require().NoError(err) + s.NotNil(rotated) + + return rotated.GetKasKey().GetKey().GetId() +} + +// assertKeyStatusesOrdered asserts the listed statuses are sorted by their +// numeric enum value in the given direction. +func (s *KasRegistryKeySuite) assertKeyStatusesOrdered(keys []*policy.KasKey, ascending bool) { + s.Require().GreaterOrEqual(len(keys), 2, "need at least two keys to assert ordering") + + statuses := make([]policy.KeyStatus, 0, len(keys)) + for _, k := range keys { + statuses = append(statuses, k.GetKey().GetKeyStatus()) + } + + for i := 1; i < len(statuses); i++ { + if ascending { + s.LessOrEqual(statuses[i-1], statuses[i], "statuses not ascending: %v", statuses) + } else { + s.GreaterOrEqual(statuses[i-1], statuses[i], "statuses not descending: %v", statuses) + } + } + + // Guard against a vacuous pass if every key shares one status. + s.NotEqual(statuses[0], statuses[len(statuses)-1], "expected mixed statuses: %v", statuses) +} + +func (s *KasRegistryKeySuite) Test_ListKeys_SortByKeyStatus_ASC() { + ids, kasID := s.createSortTestKasKeys([]string{"statusasc-kk-0", "statusasc-kk-1"}) + ids = append(ids, s.rotateOneSortTestKey(ids, 0)) + s.T().Cleanup(func() { + s.deleteSortTestKasKeys(ids, kasID) + }) + + list, err := s.db.PolicyClient.ListKeys(s.ctx, &kasregistry.ListKeysRequest{ + KasFilter: &kasregistry.ListKeysRequest_KasId{KasId: kasID}, + Sort: []*kasregistry.KasKeysSort{ + {Field: kasregistry.SortKasKeysType_SORT_KAS_KEYS_TYPE_KEY_STATUS, Direction: policy.SortDirection_SORT_DIRECTION_ASC}, + }, + }) + s.Require().NoError(err) + s.NotNil(list) + + // ACTIVE (1) before ROTATED (2) + s.assertKeyStatusesOrdered(list.GetKasKeys(), true) +} + +func (s *KasRegistryKeySuite) Test_ListKeys_SortByKeyStatus_DESC() { + ids, kasID := s.createSortTestKasKeys([]string{"statusdesc-kk-0", "statusdesc-kk-1"}) + ids = append(ids, s.rotateOneSortTestKey(ids, 0)) + s.T().Cleanup(func() { + s.deleteSortTestKasKeys(ids, kasID) + }) + + list, err := s.db.PolicyClient.ListKeys(s.ctx, &kasregistry.ListKeysRequest{ + KasFilter: &kasregistry.ListKeysRequest_KasId{KasId: kasID}, + Sort: []*kasregistry.KasKeysSort{ + {Field: kasregistry.SortKasKeysType_SORT_KAS_KEYS_TYPE_KEY_STATUS, Direction: policy.SortDirection_SORT_DIRECTION_DESC}, + }, + }) + s.Require().NoError(err) + s.NotNil(list) + + // ROTATED (2) before ACTIVE (1) + s.assertKeyStatusesOrdered(list.GetKasKeys(), false) +} + func (s *KasRegistryKeySuite) Test_ListKeys_SortTieBreaker_CreatedAtWithIDFallback() { kasReq := kasregistry.CreateKeyAccessServerRequest{ Name: "tiebreaker-kk-kas-" + uuid.NewString(), diff --git a/service/policy/db/key_access_server_registry.sql.go b/service/policy/db/key_access_server_registry.sql.go index 90d53a88b4..375f8f29d0 100644 --- a/service/policy/db/key_access_server_registry.sql.go +++ b/service/policy/db/key_access_server_registry.sql.go @@ -1139,6 +1139,8 @@ ORDER BY CASE WHEN p.resolved_field = 'created_at' AND p.resolved_direction = 'DESC' THEN kask.created_at END DESC, CASE WHEN p.resolved_field = 'updated_at' AND p.resolved_direction = 'ASC' THEN kask.updated_at END ASC, CASE WHEN p.resolved_field = 'updated_at' AND p.resolved_direction = 'DESC' THEN kask.updated_at END DESC, + CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'ASC' THEN kask.key_status END ASC, + CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'DESC' THEN kask.key_status END DESC, kask.id ASC LIMIT $5 OFFSET $4 @@ -1235,6 +1237,8 @@ type listKeysRow struct { // CASE WHEN p.resolved_field = 'created_at' AND p.resolved_direction = 'DESC' THEN kask.created_at END DESC, // CASE WHEN p.resolved_field = 'updated_at' AND p.resolved_direction = 'ASC' THEN kask.updated_at END ASC, // CASE WHEN p.resolved_field = 'updated_at' AND p.resolved_direction = 'DESC' THEN kask.updated_at END DESC, +// CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'ASC' THEN kask.key_status END ASC, +// CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'DESC' THEN kask.key_status END DESC, // kask.id ASC // LIMIT $5 // OFFSET $4 diff --git a/service/policy/db/queries/key_access_server_registry.sql b/service/policy/db/queries/key_access_server_registry.sql index 160e877c27..4dc2751463 100644 --- a/service/policy/db/queries/key_access_server_registry.sql +++ b/service/policy/db/queries/key_access_server_registry.sql @@ -425,6 +425,8 @@ ORDER BY CASE WHEN p.resolved_field = 'created_at' AND p.resolved_direction = 'DESC' THEN kask.created_at END DESC, CASE WHEN p.resolved_field = 'updated_at' AND p.resolved_direction = 'ASC' THEN kask.updated_at END ASC, CASE WHEN p.resolved_field = 'updated_at' AND p.resolved_direction = 'DESC' THEN kask.updated_at END DESC, + CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'ASC' THEN kask.key_status END ASC, + CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'DESC' THEN kask.key_status END DESC, kask.id ASC LIMIT @limit_ OFFSET @offset_; diff --git a/service/policy/db/utils.go b/service/policy/db/utils.go index b7d3745725..f7321299c8 100644 --- a/service/policy/db/utils.go +++ b/service/policy/db/utils.go @@ -29,6 +29,7 @@ const ( sortFieldFQN = "fqn" sortFieldURI = "uri" sortFieldKeyID = "key_id" + sortFieldKeyStatus = "key_status" ) // Gathers request pagination limit/offset or configured default @@ -517,6 +518,8 @@ func getKasKeysSortField(field kasregistry.SortKasKeysType) string { return sortFieldCreatedAt case kasregistry.SortKasKeysType_SORT_KAS_KEYS_TYPE_UPDATED_AT: return sortFieldUpdatedAt + case kasregistry.SortKasKeysType_SORT_KAS_KEYS_TYPE_KEY_STATUS: + return sortFieldKeyStatus case kasregistry.SortKasKeysType_SORT_KAS_KEYS_TYPE_UNSPECIFIED: fallthrough default: diff --git a/service/policy/db/utils_test.go b/service/policy/db/utils_test.go index a325ddcf06..e7e5f32f2e 100644 --- a/service/policy/db/utils_test.go +++ b/service/policy/db/utils_test.go @@ -1195,6 +1195,22 @@ func Test_GetKasKeysSortParams(t *testing.T) { expectedField: "updated_at", expectedDirection: "DESC", }, + { + name: "KEY_STATUS with ASC", + sort: []*kasregistry.KasKeysSort{ + {Field: kasregistry.SortKasKeysType_SORT_KAS_KEYS_TYPE_KEY_STATUS, Direction: policy.SortDirection_SORT_DIRECTION_ASC}, + }, + expectedField: "key_status", + expectedDirection: "ASC", + }, + { + name: "KEY_STATUS with DESC", + sort: []*kasregistry.KasKeysSort{ + {Field: kasregistry.SortKasKeysType_SORT_KAS_KEYS_TYPE_KEY_STATUS, Direction: policy.SortDirection_SORT_DIRECTION_DESC}, + }, + expectedField: "key_status", + expectedDirection: "DESC", + }, { name: "UNSPECIFIED direction returns empty direction", sort: []*kasregistry.KasKeysSort{ diff --git a/service/policy/kasregistry/key_access_server_registry.proto b/service/policy/kasregistry/key_access_server_registry.proto index 4b40df67cf..281ccbe864 100644 --- a/service/policy/kasregistry/key_access_server_registry.proto +++ b/service/policy/kasregistry/key_access_server_registry.proto @@ -79,6 +79,8 @@ enum SortKasKeysType { SORT_KAS_KEYS_TYPE_KEY_ID = 1; SORT_KAS_KEYS_TYPE_CREATED_AT = 2; SORT_KAS_KEYS_TYPE_UPDATED_AT = 3; + // Orders by policy.KeyStatus numeric value, not status name. + SORT_KAS_KEYS_TYPE_KEY_STATUS = 4; } message KasKeysSort { From 99f490ac43505674e998fe55f7e231687e81012b Mon Sep 17 00:00:00 2001 From: Elizabeth Healy Date: Fri, 7 Aug 2026 09:58:13 -0400 Subject: [PATCH 2/7] trigger ci From ad5780bf0fabbbc2efeb94c78de9fd7d2c690488 Mon Sep 17 00:00:00 2001 From: Elizabeth Healy Date: Fri, 7 Aug 2026 10:09:36 -0400 Subject: [PATCH 3/7] lint --- service/integration/kas_registry_key_test.go | 90 ++++++++++---------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/service/integration/kas_registry_key_test.go b/service/integration/kas_registry_key_test.go index 83b037016c..22b8059aec 100644 --- a/service/integration/kas_registry_key_test.go +++ b/service/integration/kas_registry_key_test.go @@ -2501,51 +2501,6 @@ func (s *KasRegistryKeySuite) Test_ListKeys_SortByUpdatedAt_ASC() { assertIDsInOrder(s.T(), list.GetKasKeys(), func(k *policy.KasKey) string { return k.GetKey().GetId() }, ids[0], ids[1], ids[2]) } -// rotateOneSortTestKey rotates the key at keyIDs[idx] so it becomes ROTATED, -// returning the ID of the newly created ACTIVE key. -func (s *KasRegistryKeySuite) rotateOneSortTestKey(keyIDs []string, idx int) string { - activeKey, err := s.db.PolicyClient.GetKey(s.ctx, &kasregistry.GetKeyRequest_Id{Id: keyIDs[idx]}) - s.Require().NoError(err) - - ts := time.Now().UnixNano() - rotated, err := s.db.PolicyClient.RotateKey(s.ctx, activeKey, &kasregistry.RotateKeyRequest_NewKey{ - KeyId: fmt.Sprintf("statussort-rotated-%d", ts), - Algorithm: policy.Algorithm_ALGORITHM_RSA_2048, - KeyMode: policy.KeyMode_KEY_MODE_CONFIG_ROOT_KEY, - PublicKeyCtx: &policy.PublicKeyCtx{Pem: keyCtx}, - PrivateKeyCtx: &policy.PrivateKeyCtx{ - KeyId: fmt.Sprintf("statussort-rotated-priv-%d", ts), - WrappedKey: keyCtx, - }, - }) - s.Require().NoError(err) - s.NotNil(rotated) - - return rotated.GetKasKey().GetKey().GetId() -} - -// assertKeyStatusesOrdered asserts the listed statuses are sorted by their -// numeric enum value in the given direction. -func (s *KasRegistryKeySuite) assertKeyStatusesOrdered(keys []*policy.KasKey, ascending bool) { - s.Require().GreaterOrEqual(len(keys), 2, "need at least two keys to assert ordering") - - statuses := make([]policy.KeyStatus, 0, len(keys)) - for _, k := range keys { - statuses = append(statuses, k.GetKey().GetKeyStatus()) - } - - for i := 1; i < len(statuses); i++ { - if ascending { - s.LessOrEqual(statuses[i-1], statuses[i], "statuses not ascending: %v", statuses) - } else { - s.GreaterOrEqual(statuses[i-1], statuses[i], "statuses not descending: %v", statuses) - } - } - - // Guard against a vacuous pass if every key shares one status. - s.NotEqual(statuses[0], statuses[len(statuses)-1], "expected mixed statuses: %v", statuses) -} - func (s *KasRegistryKeySuite) Test_ListKeys_SortByKeyStatus_ASC() { ids, kasID := s.createSortTestKasKeys([]string{"statusasc-kk-0", "statusasc-kk-1"}) ids = append(ids, s.rotateOneSortTestKey(ids, 0)) @@ -3228,6 +3183,51 @@ func (s *KasRegistryKeySuite) deleteSortTestKasKeys(keyIDs []string, kasID strin s.cleanupKeys(keyIDs, []string{kasID}) } +// rotateOneSortTestKey rotates the key at keyIDs[idx] so it becomes ROTATED, +// returning the ID of the newly created ACTIVE key. +func (s *KasRegistryKeySuite) rotateOneSortTestKey(keyIDs []string, idx int) string { + activeKey, err := s.db.PolicyClient.GetKey(s.ctx, &kasregistry.GetKeyRequest_Id{Id: keyIDs[idx]}) + s.Require().NoError(err) + + ts := time.Now().UnixNano() + rotated, err := s.db.PolicyClient.RotateKey(s.ctx, activeKey, &kasregistry.RotateKeyRequest_NewKey{ + KeyId: fmt.Sprintf("statussort-rotated-%d", ts), + Algorithm: policy.Algorithm_ALGORITHM_RSA_2048, + KeyMode: policy.KeyMode_KEY_MODE_CONFIG_ROOT_KEY, + PublicKeyCtx: &policy.PublicKeyCtx{Pem: keyCtx}, + PrivateKeyCtx: &policy.PrivateKeyCtx{ + KeyId: fmt.Sprintf("statussort-rotated-priv-%d", ts), + WrappedKey: keyCtx, + }, + }) + s.Require().NoError(err) + s.NotNil(rotated) + + return rotated.GetKasKey().GetKey().GetId() +} + +// assertKeyStatusesOrdered asserts the listed statuses are sorted by their +// numeric enum value in the given direction. +func (s *KasRegistryKeySuite) assertKeyStatusesOrdered(keys []*policy.KasKey, ascending bool) { + s.Require().GreaterOrEqual(len(keys), 2, "need at least two keys to assert ordering") + + statuses := make([]policy.KeyStatus, 0, len(keys)) + for _, k := range keys { + statuses = append(statuses, k.GetKey().GetKeyStatus()) + } + + for i := 1; i < len(statuses); i++ { + if ascending { + s.LessOrEqual(statuses[i-1], statuses[i], "statuses not ascending: %v", statuses) + } else { + s.GreaterOrEqual(statuses[i-1], statuses[i], "statuses not descending: %v", statuses) + } + } + + // Guard against a vacuous pass if every key shares one status. + s.NotEqual(statuses[0], statuses[len(statuses)-1], "expected mixed statuses: %v", statuses) +} + func (s *KasRegistryKeySuite) createListKeysSearchTestKeys(kids []string) (string, map[string]string) { kasUUID := uuid.NewString() kasReq := kasregistry.CreateKeyAccessServerRequest{ From 2bbc5d40613562c5f3c52f899aaf559315c6285d Mon Sep 17 00:00:00 2001 From: Elizabeth Healy Date: Fri, 7 Aug 2026 10:25:19 -0400 Subject: [PATCH 4/7] fix test --- service/integration/kas_registry_key_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/service/integration/kas_registry_key_test.go b/service/integration/kas_registry_key_test.go index 22b8059aec..fee031d432 100644 --- a/service/integration/kas_registry_key_test.go +++ b/service/integration/kas_registry_key_test.go @@ -3191,12 +3191,13 @@ func (s *KasRegistryKeySuite) rotateOneSortTestKey(keyIDs []string, idx int) str ts := time.Now().UnixNano() rotated, err := s.db.PolicyClient.RotateKey(s.ctx, activeKey, &kasregistry.RotateKeyRequest_NewKey{ - KeyId: fmt.Sprintf("statussort-rotated-%d", ts), + // key_id is varchar(36), so keep the generated IDs short + KeyId: fmt.Sprintf("rot-%d", ts), Algorithm: policy.Algorithm_ALGORITHM_RSA_2048, KeyMode: policy.KeyMode_KEY_MODE_CONFIG_ROOT_KEY, PublicKeyCtx: &policy.PublicKeyCtx{Pem: keyCtx}, PrivateKeyCtx: &policy.PrivateKeyCtx{ - KeyId: fmt.Sprintf("statussort-rotated-priv-%d", ts), + KeyId: fmt.Sprintf("rot-priv-%d", ts), WrappedKey: keyCtx, }, }) From 2fca8893ef5d77c6cd9315fc944101b56b677782 Mon Sep 17 00:00:00 2001 From: Elizabeth Healy Date: Fri, 7 Aug 2026 11:45:34 -0400 Subject: [PATCH 5/7] order after migration --- docs/grpc/index.html | 2 +- protocol/go/policy/kasregistry/key_access_server_registry.pb.go | 2 +- service/policy/db/queries/key_access_server_registry.sql | 1 + service/policy/kasregistry/key_access_server_registry.proto | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/grpc/index.html b/docs/grpc/index.html index 76c6b5d5ff..8aeeeb7908 100644 --- a/docs/grpc/index.html +++ b/docs/grpc/index.html @@ -13936,7 +13936,7 @@

SortKasKeysType

SORT_KAS_KEYS_TYPE_KEY_STATUS 4 -

Orders by policy.KeyStatus numeric value, not status name.

+

Orders alphabetically by policy.KeyStatus name.

diff --git a/protocol/go/policy/kasregistry/key_access_server_registry.pb.go b/protocol/go/policy/kasregistry/key_access_server_registry.pb.go index 3c7a12471e..b388e1dc15 100644 --- a/protocol/go/policy/kasregistry/key_access_server_registry.pb.go +++ b/protocol/go/policy/kasregistry/key_access_server_registry.pb.go @@ -85,7 +85,7 @@ const ( SortKasKeysType_SORT_KAS_KEYS_TYPE_KEY_ID SortKasKeysType = 1 SortKasKeysType_SORT_KAS_KEYS_TYPE_CREATED_AT SortKasKeysType = 2 SortKasKeysType_SORT_KAS_KEYS_TYPE_UPDATED_AT SortKasKeysType = 3 - // Orders by policy.KeyStatus numeric value, not status name. + // Orders alphabetically by policy.KeyStatus name. SortKasKeysType_SORT_KAS_KEYS_TYPE_KEY_STATUS SortKasKeysType = 4 ) diff --git a/service/policy/db/queries/key_access_server_registry.sql b/service/policy/db/queries/key_access_server_registry.sql index 4dc2751463..8d1a9d9cc0 100644 --- a/service/policy/db/queries/key_access_server_registry.sql +++ b/service/policy/db/queries/key_access_server_registry.sql @@ -425,6 +425,7 @@ ORDER BY CASE WHEN p.resolved_field = 'created_at' AND p.resolved_direction = 'DESC' THEN kask.created_at END DESC, CASE WHEN p.resolved_field = 'updated_at' AND p.resolved_direction = 'ASC' THEN kask.updated_at END ASC, CASE WHEN p.resolved_field = 'updated_at' AND p.resolved_direction = 'DESC' THEN kask.updated_at END DESC, + -- key_status stores the KeyStatus enum name, so this sorts alphabetically CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'ASC' THEN kask.key_status END ASC, CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'DESC' THEN kask.key_status END DESC, kask.id ASC diff --git a/service/policy/kasregistry/key_access_server_registry.proto b/service/policy/kasregistry/key_access_server_registry.proto index 281ccbe864..6b51cbfa5f 100644 --- a/service/policy/kasregistry/key_access_server_registry.proto +++ b/service/policy/kasregistry/key_access_server_registry.proto @@ -79,7 +79,7 @@ enum SortKasKeysType { SORT_KAS_KEYS_TYPE_KEY_ID = 1; SORT_KAS_KEYS_TYPE_CREATED_AT = 2; SORT_KAS_KEYS_TYPE_UPDATED_AT = 3; - // Orders by policy.KeyStatus numeric value, not status name. + // Orders alphabetically by policy.KeyStatus name. SORT_KAS_KEYS_TYPE_KEY_STATUS = 4; } From 6072327a528b02aef87eaca6f33ca6a3be9790d7 Mon Sep 17 00:00:00 2001 From: Elizabeth Healy Date: Fri, 7 Aug 2026 12:56:54 -0400 Subject: [PATCH 6/7] handle in sql case --- docs/grpc/index.html | 2 +- .../key_access_server_registry.openapi.yaml | 5 ++++- docs/openapi/policy/objects.openapi.yaml | 5 ++++- docs/openapi/policy/unsafe/unsafe.openapi.yaml | 5 ++++- protocol/go/policy/objects.pb.go | 4 +++- .../db/key_access_server_registry.sql.go | 18 ++++++++++++++---- .../db/queries/key_access_server_registry.sql | 10 +++++++--- service/policy/objects.proto | 4 +++- 8 files changed, 40 insertions(+), 13 deletions(-) diff --git a/docs/grpc/index.html b/docs/grpc/index.html index 8aeeeb7908..e1000f9556 100644 --- a/docs/grpc/index.html +++ b/docs/grpc/index.html @@ -4588,7 +4588,7 @@

KeyMode

KeyStatus

-

The status of the key

+

The status of the key.

Adding a value here requires updating the key_status mapping in the listKeys

query so SORT_KAS_KEYS_TYPE_KEY_STATUS keeps sorting alphabetically.

diff --git a/docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml b/docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml index 096641f6e5..9a28e2a5ea 100644 --- a/docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml +++ b/docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml @@ -561,7 +561,10 @@ components: - KEY_STATUS_UNSPECIFIED - KEY_STATUS_ACTIVE - KEY_STATUS_ROTATED - description: The status of the key + description: |- + The status of the key. + Adding a value here requires updating the key_status mapping in the listKeys + query so SORT_KAS_KEYS_TYPE_KEY_STATUS keeps sorting alphabetically. policy.SortDirection: type: string title: SortDirection diff --git a/docs/openapi/policy/objects.openapi.yaml b/docs/openapi/policy/objects.openapi.yaml index 1b3a8729bd..301971bcec 100644 --- a/docs/openapi/policy/objects.openapi.yaml +++ b/docs/openapi/policy/objects.openapi.yaml @@ -74,7 +74,10 @@ components: - KEY_STATUS_UNSPECIFIED - KEY_STATUS_ACTIVE - KEY_STATUS_ROTATED - description: The status of the key + description: |- + The status of the key. + Adding a value here requires updating the key_status mapping in the listKeys + query so SORT_KAS_KEYS_TYPE_KEY_STATUS keeps sorting alphabetically. policy.SourceType: type: string title: SourceType diff --git a/docs/openapi/policy/unsafe/unsafe.openapi.yaml b/docs/openapi/policy/unsafe/unsafe.openapi.yaml index 383144f97c..c01ae4c28e 100644 --- a/docs/openapi/policy/unsafe/unsafe.openapi.yaml +++ b/docs/openapi/policy/unsafe/unsafe.openapi.yaml @@ -475,7 +475,10 @@ components: - KEY_STATUS_UNSPECIFIED - KEY_STATUS_ACTIVE - KEY_STATUS_ROTATED - description: The status of the key + description: |- + The status of the key. + Adding a value here requires updating the key_status mapping in the listKeys + query so SORT_KAS_KEYS_TYPE_KEY_STATUS keeps sorting alphabetically. policy.SourceType: type: string title: SourceType diff --git a/protocol/go/policy/objects.pb.go b/protocol/go/policy/objects.pb.go index 87ff221319..94d0f9dd05 100644 --- a/protocol/go/policy/objects.pb.go +++ b/protocol/go/policy/objects.pb.go @@ -381,7 +381,9 @@ func (Algorithm) EnumDescriptor() ([]byte, []int) { return file_policy_objects_proto_rawDescGZIP(), []int{5} } -// The status of the key +// The status of the key. +// Adding a value here requires updating the key_status mapping in the listKeys +// query so SORT_KAS_KEYS_TYPE_KEY_STATUS keeps sorting alphabetically. type KeyStatus int32 const ( diff --git a/service/policy/db/key_access_server_registry.sql.go b/service/policy/db/key_access_server_registry.sql.go index 375f8f29d0..2cda098299 100644 --- a/service/policy/db/key_access_server_registry.sql.go +++ b/service/policy/db/key_access_server_registry.sql.go @@ -1139,8 +1139,13 @@ ORDER BY CASE WHEN p.resolved_field = 'created_at' AND p.resolved_direction = 'DESC' THEN kask.created_at END DESC, CASE WHEN p.resolved_field = 'updated_at' AND p.resolved_direction = 'ASC' THEN kask.updated_at END ASC, CASE WHEN p.resolved_field = 'updated_at' AND p.resolved_direction = 'DESC' THEN kask.updated_at END DESC, - CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'ASC' THEN kask.key_status END ASC, - CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'DESC' THEN kask.key_status END DESC, + -- key_status is stored as an enum ordinal, so map it to a name to sort alphabetically + CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'ASC' THEN + CASE kask.key_status WHEN 1 THEN 'ACTIVE' WHEN 2 THEN 'ROTATED' ELSE 'UNSPECIFIED' END + END ASC, + CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'DESC' THEN + CASE kask.key_status WHEN 1 THEN 'ACTIVE' WHEN 2 THEN 'ROTATED' ELSE 'UNSPECIFIED' END + END DESC, kask.id ASC LIMIT $5 OFFSET $4 @@ -1237,8 +1242,13 @@ type listKeysRow struct { // CASE WHEN p.resolved_field = 'created_at' AND p.resolved_direction = 'DESC' THEN kask.created_at END DESC, // CASE WHEN p.resolved_field = 'updated_at' AND p.resolved_direction = 'ASC' THEN kask.updated_at END ASC, // CASE WHEN p.resolved_field = 'updated_at' AND p.resolved_direction = 'DESC' THEN kask.updated_at END DESC, -// CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'ASC' THEN kask.key_status END ASC, -// CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'DESC' THEN kask.key_status END DESC, +// -- key_status is stored as an enum ordinal, so map it to a name to sort alphabetically +// CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'ASC' THEN +// CASE kask.key_status WHEN 1 THEN 'ACTIVE' WHEN 2 THEN 'ROTATED' ELSE 'UNSPECIFIED' END +// END ASC, +// CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'DESC' THEN +// CASE kask.key_status WHEN 1 THEN 'ACTIVE' WHEN 2 THEN 'ROTATED' ELSE 'UNSPECIFIED' END +// END DESC, // kask.id ASC // LIMIT $5 // OFFSET $4 diff --git a/service/policy/db/queries/key_access_server_registry.sql b/service/policy/db/queries/key_access_server_registry.sql index 8d1a9d9cc0..4270962ed9 100644 --- a/service/policy/db/queries/key_access_server_registry.sql +++ b/service/policy/db/queries/key_access_server_registry.sql @@ -425,9 +425,13 @@ ORDER BY CASE WHEN p.resolved_field = 'created_at' AND p.resolved_direction = 'DESC' THEN kask.created_at END DESC, CASE WHEN p.resolved_field = 'updated_at' AND p.resolved_direction = 'ASC' THEN kask.updated_at END ASC, CASE WHEN p.resolved_field = 'updated_at' AND p.resolved_direction = 'DESC' THEN kask.updated_at END DESC, - -- key_status stores the KeyStatus enum name, so this sorts alphabetically - CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'ASC' THEN kask.key_status END ASC, - CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'DESC' THEN kask.key_status END DESC, + -- key_status is stored as an enum ordinal, so map it to a name to sort alphabetically + CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'ASC' THEN + CASE kask.key_status WHEN 1 THEN 'ACTIVE' WHEN 2 THEN 'ROTATED' ELSE 'UNSPECIFIED' END + END ASC, + CASE WHEN p.resolved_field = 'key_status' AND p.resolved_direction = 'DESC' THEN + CASE kask.key_status WHEN 1 THEN 'ACTIVE' WHEN 2 THEN 'ROTATED' ELSE 'UNSPECIFIED' END + END DESC, kask.id ASC LIMIT @limit_ OFFSET @offset_; diff --git a/service/policy/objects.proto b/service/policy/objects.proto index c1dbb71e85..8dc0df77a3 100644 --- a/service/policy/objects.proto +++ b/service/policy/objects.proto @@ -642,7 +642,9 @@ enum Algorithm { ALGORITHM_MLKEM_1024 = 21; } -// The status of the key +// The status of the key. +// Adding a value here requires updating the key_status mapping in the listKeys +// query so SORT_KAS_KEYS_TYPE_KEY_STATUS keeps sorting alphabetically. enum KeyStatus { KEY_STATUS_UNSPECIFIED = 0; KEY_STATUS_ACTIVE = 1; From a817b593e18fb1d5cf150bf7794522e43bf441d1 Mon Sep 17 00:00:00 2001 From: Elizabeth Healy Date: Mon, 10 Aug 2026 10:32:52 -0400 Subject: [PATCH 7/7] remove helper --- service/integration/kas_registry_key_test.go | 36 +++++--------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/service/integration/kas_registry_key_test.go b/service/integration/kas_registry_key_test.go index fee031d432..657cfc3c28 100644 --- a/service/integration/kas_registry_key_test.go +++ b/service/integration/kas_registry_key_test.go @@ -2502,7 +2502,8 @@ func (s *KasRegistryKeySuite) Test_ListKeys_SortByUpdatedAt_ASC() { } func (s *KasRegistryKeySuite) Test_ListKeys_SortByKeyStatus_ASC() { - ids, kasID := s.createSortTestKasKeys([]string{"statusasc-kk-0", "statusasc-kk-1"}) + // Rotating leaves ids[0] ROTATED and adds an ACTIVE key, one key per status. + ids, kasID := s.createSortTestKasKeys([]string{"statusasc-kk-0"}) ids = append(ids, s.rotateOneSortTestKey(ids, 0)) s.T().Cleanup(func() { s.deleteSortTestKasKeys(ids, kasID) @@ -2517,12 +2518,13 @@ func (s *KasRegistryKeySuite) Test_ListKeys_SortByKeyStatus_ASC() { s.Require().NoError(err) s.NotNil(list) - // ACTIVE (1) before ROTATED (2) - s.assertKeyStatusesOrdered(list.GetKasKeys(), true) + // ACTIVE before ROTATED + assertIDsInOrder(s.T(), list.GetKasKeys(), func(k *policy.KasKey) string { return k.GetKey().GetId() }, ids[1], ids[0]) } func (s *KasRegistryKeySuite) Test_ListKeys_SortByKeyStatus_DESC() { - ids, kasID := s.createSortTestKasKeys([]string{"statusdesc-kk-0", "statusdesc-kk-1"}) + // Rotating leaves ids[0] ROTATED and adds an ACTIVE key, one key per status. + ids, kasID := s.createSortTestKasKeys([]string{"statusdesc-kk-0"}) ids = append(ids, s.rotateOneSortTestKey(ids, 0)) s.T().Cleanup(func() { s.deleteSortTestKasKeys(ids, kasID) @@ -2537,8 +2539,8 @@ func (s *KasRegistryKeySuite) Test_ListKeys_SortByKeyStatus_DESC() { s.Require().NoError(err) s.NotNil(list) - // ROTATED (2) before ACTIVE (1) - s.assertKeyStatusesOrdered(list.GetKasKeys(), false) + // ROTATED before ACTIVE + assertIDsInOrder(s.T(), list.GetKasKeys(), func(k *policy.KasKey) string { return k.GetKey().GetId() }, ids[0], ids[1]) } func (s *KasRegistryKeySuite) Test_ListKeys_SortTieBreaker_CreatedAtWithIDFallback() { @@ -3207,28 +3209,6 @@ func (s *KasRegistryKeySuite) rotateOneSortTestKey(keyIDs []string, idx int) str return rotated.GetKasKey().GetKey().GetId() } -// assertKeyStatusesOrdered asserts the listed statuses are sorted by their -// numeric enum value in the given direction. -func (s *KasRegistryKeySuite) assertKeyStatusesOrdered(keys []*policy.KasKey, ascending bool) { - s.Require().GreaterOrEqual(len(keys), 2, "need at least two keys to assert ordering") - - statuses := make([]policy.KeyStatus, 0, len(keys)) - for _, k := range keys { - statuses = append(statuses, k.GetKey().GetKeyStatus()) - } - - for i := 1; i < len(statuses); i++ { - if ascending { - s.LessOrEqual(statuses[i-1], statuses[i], "statuses not ascending: %v", statuses) - } else { - s.GreaterOrEqual(statuses[i-1], statuses[i], "statuses not descending: %v", statuses) - } - } - - // Guard against a vacuous pass if every key shares one status. - s.NotEqual(statuses[0], statuses[len(statuses)-1], "expected mixed statuses: %v", statuses) -} - func (s *KasRegistryKeySuite) createListKeysSearchTestKeys(kids []string) (string, map[string]string) { kasUUID := uuid.NewString() kasReq := kasregistry.CreateKeyAccessServerRequest{
NameNumberDescription