diff --git a/internal/control/access_key_collection.go b/internal/control/access_key_collection.go index bd15c0fa..23364c8f 100644 --- a/internal/control/access_key_collection.go +++ b/internal/control/access_key_collection.go @@ -49,14 +49,24 @@ func (s *Service) ListAccessKeyCollection( ctx context.Context, query AccessKeyCollectionQuery, ) (AccessKeyCollectionResponse, error) { + records, err := s.captureAccessKeyCollectionRecords(ctx) + if err != nil { + return AccessKeyCollectionResponse{}, err + } + return queryAccessKeyCollectionRecords(records, normalizeAccessKeyCollectionQuery(query)), nil +} + +func (s *Service) captureAccessKeyCollectionRecords( + ctx context.Context, +) ([]accessKeyCollectionRecord, error) { if ctx == nil { ctx = context.Background() } if err := ctx.Err(); err != nil { - return AccessKeyCollectionResponse{}, err + return nil, err } if s == nil || s.db == nil { - return AccessKeyCollectionResponse{}, fmt.Errorf( + return nil, fmt.Errorf( "list access key collection: dependencies unavailable: %w", app_errors.ErrInternalServer, ) @@ -69,19 +79,20 @@ func (s *Service) ListAccessKeyCollection( "id", "name", "key_suffix", "status", "filters", "rpm_limit", "created_at_ms", "updated_at_ms", ). + Order("id ASC"). Scan(&rows).Error }); err != nil { if parentErr := ctx.Err(); parentErr != nil { - return AccessKeyCollectionResponse{}, parentErr + return nil, parentErr } - return AccessKeyCollectionResponse{}, app_errors.ParseDBError(err) + return nil, app_errors.ParseDBError(err) } records := make([]accessKeyCollectionRecord, 0, len(rows)) for _, row := range rows { metadata, err := mapAccessKeyMetadataRow(row) if err != nil { - return AccessKeyCollectionResponse{}, err + return nil, err } records = append(records, accessKeyCollectionRecord{ AccessKeyCollectionItem: AccessKeyCollectionItem{ @@ -90,7 +101,7 @@ func (s *Service) ListAccessKeyCollection( }, }) } - return queryAccessKeyCollectionRecords(records, normalizeAccessKeyCollectionQuery(query)), nil + return records, nil } func accessKeyCollectionScope(filters AccessKeyFilters) AccessKeyCollectionScope { diff --git a/internal/control/access_keys.go b/internal/control/access_keys.go index 0dd91a83..513951b2 100644 --- a/internal/control/access_keys.go +++ b/internal/control/access_keys.go @@ -176,13 +176,13 @@ func (s *Service) CreateAccessKey( } func (s *Service) ListAccessKeys(ctx context.Context) ([]AccessKeyMetadata, error) { - collection, err := s.ListAccessKeyCollection(ctx, AccessKeyCollectionQuery{}) + records, err := s.captureAccessKeyCollectionRecords(ctx) if err != nil { return nil, err } - result := make([]AccessKeyMetadata, len(collection.Items)) - for index := range collection.Items { - result[index] = collection.Items[index].AccessKeyMetadata + result := make([]AccessKeyMetadata, len(records)) + for index := range records { + result[index] = records[index].AccessKeyMetadata } return result, nil } diff --git a/internal/control/access_keys_test.go b/internal/control/access_keys_test.go index 0f93ef2a..378bd895 100644 --- a/internal/control/access_keys_test.go +++ b/internal/control/access_keys_test.go @@ -266,6 +266,37 @@ func TestListAccessKeyCollectionReturnsMaskedMetadataWithoutDecrypting(t *testin } } +func TestListAccessKeysReturnsCompleteArrayBeyondCollectionDefaultPageSize(t *testing.T) { + fixture := newServiceFixture(t) + rows := make([]models.AccessKey, 21) + for index := range rows { + rows[index] = models.AccessKey{ + Name: fmt.Sprintf("legacy-%02d", index), + KeyValue: "ciphertext", + KeyHash: fmt.Sprintf("legacy-key-hash-%02d", index), + KeySuffix: fmt.Sprintf("%04x", index), + Status: string(state.AccessKeyStatusActive), + Filters: models.JSON(`{}`), + } + } + if err := fixture.db.Create(&rows).Error; err != nil { + t.Fatalf("create access keys: %v", err) + } + + listed, err := fixture.service.ListAccessKeys(t.Context()) + if err != nil { + t.Fatalf("ListAccessKeys() error = %v", err) + } + if len(listed) != len(rows) { + t.Fatalf("ListAccessKeys() count = %d, want %d", len(listed), len(rows)) + } + for index := range rows { + if listed[index].ID != rows[index].ID { + t.Fatalf("ListAccessKeys()[%d].ID = %d, want %d", index, listed[index].ID, rows[index].ID) + } + } +} + func TestUpdateAccessKeyPreservesCredentialAcrossPointerPatches(t *testing.T) { fixture := newServiceFixture(t) group := validControlGroup("access-key-update")