Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion docs/grpc/index.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion docs/openapi/policy/objects.openapi.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion docs/openapi/policy/unsafe/unsafe.openapi.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions otdfctl/pkg/handlers/kas-keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
220 changes: 113 additions & 107 deletions protocol/go/policy/kasregistry/key_access_server_registry.pb.go

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion protocol/go/policy/objects.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 66 additions & 0 deletions service/integration/kas_registry_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2501,6 +2501,48 @@ 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])
}

func (s *KasRegistryKeySuite) Test_ListKeys_SortByKeyStatus_ASC() {
Comment thread
c-r33d marked this conversation as resolved.
// 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)
})

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 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() {
// 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)
})

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 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() {
kasReq := kasregistry.CreateKeyAccessServerRequest{
Name: "tiebreaker-kk-kas-" + uuid.NewString(),
Expand Down Expand Up @@ -3143,6 +3185,30 @@ 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{
// 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("rot-priv-%d", ts),
WrappedKey: keyCtx,
},
})
s.Require().NoError(err)
s.NotNil(rotated)

return rotated.GetKasKey().GetKey().GetId()
}

func (s *KasRegistryKeySuite) createListKeysSearchTestKeys(kids []string) (string, map[string]string) {
kasUUID := uuid.NewString()
kasReq := kasregistry.CreateKeyAccessServerRequest{
Expand Down
14 changes: 14 additions & 0 deletions service/policy/db/key_access_server_registry.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions service/policy/db/queries/key_access_server_registry.sql
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +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 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_;
Expand Down
3 changes: 3 additions & 0 deletions service/policy/db/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const (
sortFieldFQN = "fqn"
sortFieldURI = "uri"
sortFieldKeyID = "key_id"
sortFieldKeyStatus = "key_status"
)

// Gathers request pagination limit/offset or configured default
Expand Down Expand Up @@ -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:
Expand Down
16 changes: 16 additions & 0 deletions service/policy/db/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
2 changes: 2 additions & 0 deletions service/policy/kasregistry/key_access_server_registry.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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 alphabetically by policy.KeyStatus name.
SORT_KAS_KEYS_TYPE_KEY_STATUS = 4;
}

message KasKeysSort {
Expand Down
4 changes: 3 additions & 1 deletion service/policy/objects.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading