From 6b03363eb831d3e212b65b168f93cd6cf541d30d Mon Sep 17 00:00:00 2001 From: Johan Brandhorst-Satzkorn Date: Fri, 1 Dec 2023 16:16:19 -0800 Subject: [PATCH] internal/handlers: add credential library pagination --- internal/daemon/controller/handler.go | 7 +- .../credentiallibrary_service.go | 225 +++++-- .../credentiallibrary_service_test.go | 617 ++++++++++++++---- .../targets/tcp/target_service_test.go | 10 +- internal/gen/controller.swagger.json | 46 +- .../services/credential_library_service.pb.go | 344 ++++++---- .../v1/credential_library_service.proto | 30 + 7 files changed, 958 insertions(+), 321 deletions(-) diff --git a/internal/daemon/controller/handler.go b/internal/daemon/controller/handler.go index 6f83c9d07..de5b8437e 100644 --- a/internal/daemon/controller/handler.go +++ b/internal/daemon/controller/handler.go @@ -273,7 +273,12 @@ func (c *Controller) registerGrpcServices(s *grpc.Server) error { services.RegisterCredentialStoreServiceServer(s, cs) } if _, ok := currentServices[services.CredentialLibraryService_ServiceDesc.ServiceName]; !ok { - cl, err := credentiallibraries.NewService(c.baseContext, c.VaultCredentialRepoFn, c.IamRepoFn) + cl, err := credentiallibraries.NewService( + c.baseContext, + c.IamRepoFn, + c.VaultCredentialRepoFn, + c.conf.RawConfig.Controller.MaxPageSize, + ) if err != nil { return fmt.Errorf("failed to create credential library handler service: %w", err) } diff --git a/internal/daemon/controller/handlers/credentiallibraries/credentiallibrary_service.go b/internal/daemon/controller/handlers/credentiallibraries/credentiallibrary_service.go index f58d69ab2..c84182a37 100644 --- a/internal/daemon/controller/handlers/credentiallibraries/credentiallibrary_service.go +++ b/internal/daemon/controller/handlers/credentiallibraries/credentiallibrary_service.go @@ -18,6 +18,8 @@ import ( "github.com/hashicorp/boundary/internal/daemon/controller/handlers" "github.com/hashicorp/boundary/internal/errors" pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services" + "github.com/hashicorp/boundary/internal/listtoken" + "github.com/hashicorp/boundary/internal/pagination" "github.com/hashicorp/boundary/internal/perms" "github.com/hashicorp/boundary/internal/requests" "github.com/hashicorp/boundary/internal/types/action" @@ -112,83 +114,164 @@ func init() { type Service struct { pbs.UnsafeCredentialLibraryServiceServer - iamRepoFn common.IamRepoFactory - repoFn common.VaultCredentialRepoFactory + iamRepoFn common.IamRepoFactory + repoFn common.VaultCredentialRepoFactory + maxPageSize uint } var _ pbs.CredentialLibraryServiceServer = (*Service)(nil) // NewService returns a credential library service which handles credential library related requests to boundary. -func NewService(ctx context.Context, repo common.VaultCredentialRepoFactory, iamRepo common.IamRepoFactory) (Service, error) { +func NewService( + ctx context.Context, + iamRepoFn common.IamRepoFactory, + repoFn common.VaultCredentialRepoFactory, + maxPageSize uint, +) (Service, error) { const op = "credentiallibraries.NewService" - if iamRepo == nil { + if iamRepoFn == nil { return Service{}, errors.New(ctx, errors.InvalidParameter, op, "missing iam repository") } - if repo == nil { + if repoFn == nil { return Service{}, errors.New(ctx, errors.InvalidParameter, op, "missing vault credential repository") } - return Service{iamRepoFn: iamRepo, repoFn: repo}, nil + if maxPageSize == 0 { + maxPageSize = uint(globals.DefaultMaxPageSize) + } + return Service{ + iamRepoFn: iamRepoFn, + repoFn: repoFn, + maxPageSize: maxPageSize, + }, nil } // ListCredentialLibraries implements the interface pbs.CredentialLibraryServiceServer func (s Service) ListCredentialLibraries(ctx context.Context, req *pbs.ListCredentialLibrariesRequest) (*pbs.ListCredentialLibrariesResponse, error) { + const op = "credentiallibraries.(Service).ListCredentialLibraries" if err := validateListRequest(ctx, req); err != nil { - return nil, err + return nil, errors.Wrap(ctx, err, op) } authResults := s.authResult(ctx, req.GetCredentialStoreId(), action.List) if authResults.Error != nil { return nil, authResults.Error } - csl, err := s.listFromRepo(ctx, req.GetCredentialStoreId()) - if err != nil { - return nil, err + pageSize := int(s.maxPageSize) + // Use the requested page size only if it is smaller than + // the configured max. + if req.GetPageSize() != 0 && uint(req.GetPageSize()) < s.maxPageSize { + pageSize = int(req.GetPageSize()) } - if len(csl) == 0 { - return &pbs.ListCredentialLibrariesResponse{}, nil + var filterItemFn func(ctx context.Context, item credential.Library) (bool, error) + switch { + case req.GetFilter() != "": + // Only use a filter if we need to + filter, err := handlers.NewFilter(ctx, req.GetFilter()) + if err != nil { + return nil, err + } + // TODO: replace the need for this function with some way to convert the `filter` + // to a domain type. This would allow filtering to happen in the domain, and we could + // remove this callback altogether. + filterItemFn = func(ctx context.Context, item credential.Library) (bool, error) { + outputOpts, ok := newOutputOpts(ctx, item, req.GetCredentialStoreId(), authResults) + if !ok { + return ok, nil + } + pbItem, err := toProto(ctx, item, outputOpts...) + if err != nil { + return false, err + } + + filterable, err := subtypes.Filterable(ctx, pbItem) + if err != nil { + return false, err + } + return filter.Match(filterable), nil + } + default: + filterItemFn = func(ctx context.Context, item credential.Library) (bool, error) { + return true, nil + } + } + repo, err := s.repoFn() + if err != nil { + return nil, errors.Wrap(ctx, err, op) + } + grantsHash, err := authResults.GrantsHash(ctx) + if err != nil { + return nil, errors.Wrap(ctx, err, op) } - filter, err := handlers.NewFilter(ctx, req.GetFilter()) - if err != nil { - return nil, err + var listResp *pagination.ListResponse[credential.Library] + var sortBy string + if req.GetListToken() == "" { + sortBy = "created_time" + listResp, err = credential.ListLibraries(ctx, grantsHash, pageSize, filterItemFn, repo, req.GetCredentialStoreId()) + if err != nil { + return nil, err + } + } else { + listToken, err := handlers.ParseListToken(ctx, req.GetListToken(), resource.CredentialLibrary, grantsHash) + if err != nil { + return nil, err + } + switch st := listToken.Subtype.(type) { + case *listtoken.PaginationToken: + sortBy = "created_time" + listResp, err = credential.ListLibrariesPage(ctx, grantsHash, pageSize, filterItemFn, listToken, repo, req.GetCredentialStoreId()) + if err != nil { + return nil, err + } + case *listtoken.StartRefreshToken: + sortBy = "updated_time" + listResp, err = credential.ListLibrariesRefresh(ctx, grantsHash, pageSize, filterItemFn, listToken, repo, req.GetCredentialStoreId()) + if err != nil { + return nil, err + } + case *listtoken.RefreshToken: + sortBy = "updated_time" + listResp, err = credential.ListLibrariesRefreshPage(ctx, grantsHash, pageSize, filterItemFn, listToken, repo, req.GetCredentialStoreId()) + if err != nil { + return nil, err + } + default: + return nil, handlers.ApiErrorWithCodeAndMessage(codes.InvalidArgument, "unexpected list token subtype: %T", st) + } } - finalItems := make([]*pb.CredentialLibrary, 0, len(csl)) - res := perms.Resource{ - ScopeId: authResults.Scope.Id, - Type: resource.CredentialLibrary, - Pin: req.GetCredentialStoreId(), - } - for _, item := range csl { - res.Id = item.GetPublicId() - authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions, auth.WithResource(&res)).Strings() - if len(authorizedActions) == 0 { + finalItems := make([]*pb.CredentialLibrary, 0, len(listResp.Items)) + for _, item := range listResp.Items { + outputOpts, ok := newOutputOpts(ctx, item, req.GetCredentialStoreId(), authResults) + if !ok { continue } - - outputFields := authResults.FetchOutputFields(res, action.List).SelfOrDefaults(authResults.UserId) - outputOpts := make([]handlers.Option, 0, 3) - outputOpts = append(outputOpts, handlers.WithOutputFields(outputFields)) - if outputFields.Has(globals.ScopeField) { - outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) - } - if outputFields.Has(globals.AuthorizedActionsField) { - outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authorizedActions)) + pbItem, err := toProto(ctx, item, outputOpts...) + if err != nil { + return nil, errors.Wrap(ctx, err, op) } + finalItems = append(finalItems, pbItem) + } + respType := "delta" + if listResp.CompleteListing { + respType = "complete" + } + resp := &pbs.ListCredentialLibrariesResponse{ + Items: finalItems, + EstItemCount: uint32(listResp.EstimatedItemCount), + RemovedIds: listResp.DeletedIds, + ResponseType: respType, + SortBy: sortBy, + SortDir: "desc", + } - item, err := toProto(ctx, item, outputOpts...) + if listResp.ListToken != nil { + resp.ListToken, err = handlers.MarshalListToken(ctx, listResp.ListToken, pbs.ResourceType_RESOURCE_TYPE_CREDENTIAL_LIBRARY) if err != nil { return nil, err } - - filterable, err := subtypes.Filterable(ctx, item) - if err != nil { - return nil, err - } - if filter.Match(filterable) { - finalItems = append(finalItems, item) - } } - return &pbs.ListCredentialLibrariesResponse{Items: finalItems}, nil + + return resp, nil } // GetCredentialLibrary implements the interface pbs.CredentialLibraryServiceServer. @@ -346,31 +429,6 @@ func (s Service) DeleteCredentialLibrary(ctx context.Context, req *pbs.DeleteCre return nil, nil } -func (s Service) listFromRepo(ctx context.Context, storeId string) ([]credential.Library, error) { - const op = "credentiallibraries.(Service).listFromRepo" - repo, err := s.repoFn() - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - genCsl, err := repo.ListCredentialLibraries(ctx, storeId) - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - certCsl, err := repo.ListSSHCertificateCredentialLibraries(ctx, storeId) - if err != nil { - return nil, errors.Wrap(ctx, err, op) - } - - csl := make([]credential.Library, 0, len(genCsl)+len(certCsl)) - for _, s := range genCsl { - csl = append(csl, s) - } - for _, s := range certCsl { - csl = append(csl, s) - } - return csl, nil -} - func (s Service) getFromRepo(ctx context.Context, id string) (credential.Library, error) { const op = "credentiallibraries.(Service).getFromRepo" repo, err := s.repoFn() @@ -613,6 +671,35 @@ func (s Service) authResult(ctx context.Context, id string, a action.Type) auth. return auth.Verify(ctx, opts...) } +func newOutputOpts( + ctx context.Context, + item credential.Library, + credentialStoreId string, + authResults auth.VerifyResults, +) ([]handlers.Option, bool) { + res := perms.Resource{ + ScopeId: authResults.Scope.Id, + Type: resource.CredentialLibrary, + Pin: credentialStoreId, + Id: item.GetPublicId(), + } + authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions, auth.WithResource(&res)).Strings() + if len(authorizedActions) == 0 { + return nil, false + } + + outputFields := authResults.FetchOutputFields(res, action.List).SelfOrDefaults(authResults.UserId) + outputOpts := make([]handlers.Option, 0, 3) + outputOpts = append(outputOpts, handlers.WithOutputFields(outputFields)) + if outputFields.Has(globals.ScopeField) { + outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) + } + if outputFields.Has(globals.AuthorizedActionsField) { + outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authorizedActions)) + } + return outputOpts, true +} + func toProto(ctx context.Context, in credential.Library, opt ...handlers.Option) (*pb.CredentialLibrary, error) { const op = "credentiallibraries.toProto" diff --git a/internal/daemon/controller/handlers/credentiallibraries/credentiallibrary_service_test.go b/internal/daemon/controller/handlers/credentiallibraries/credentiallibrary_service_test.go index 4f93068fe..0d4187cd7 100644 --- a/internal/daemon/controller/handlers/credentiallibraries/credentiallibrary_service_test.go +++ b/internal/daemon/controller/handlers/credentiallibraries/credentiallibrary_service_test.go @@ -7,6 +7,7 @@ import ( "context" "encoding/json" "fmt" + "slices" "sort" "strings" "testing" @@ -14,15 +15,21 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/hashicorp/boundary/globals" + "github.com/hashicorp/boundary/internal/auth/password" + "github.com/hashicorp/boundary/internal/authtoken" "github.com/hashicorp/boundary/internal/credential/vault" + "github.com/hashicorp/boundary/internal/credential/vault/store" "github.com/hashicorp/boundary/internal/daemon/controller/auth" "github.com/hashicorp/boundary/internal/daemon/controller/handlers" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/errors" pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services" + authpb "github.com/hashicorp/boundary/internal/gen/controller/auth" "github.com/hashicorp/boundary/internal/iam" "github.com/hashicorp/boundary/internal/kms" + "github.com/hashicorp/boundary/internal/requests" "github.com/hashicorp/boundary/internal/scheduler" + "github.com/hashicorp/boundary/internal/server" "github.com/hashicorp/boundary/internal/types/scope" pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/credentiallibraries" scopepb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes" @@ -39,6 +46,46 @@ import ( var testAuthorizedActions = []string{"no-op", "read", "update", "delete"} +func vaultCredentialLibraryToProto(credLib *vault.CredentialLibrary, project *iam.Scope) *pb.CredentialLibrary { + return &pb.CredentialLibrary{ + Id: credLib.GetPublicId(), + CredentialStoreId: credLib.GetStoreId(), + Scope: &scopepb.ScopeInfo{Id: project.GetPublicId(), Type: scope.Project.String(), ParentScopeId: project.GetParentId()}, + CreatedTime: credLib.GetCreateTime().GetTimestamp(), + UpdatedTime: credLib.GetUpdateTime().GetTimestamp(), + Version: credLib.GetVersion(), + Type: vault.GenericLibrarySubtype.String(), + AuthorizedActions: testAuthorizedActions, + Attrs: &pb.CredentialLibrary_VaultGenericCredentialLibraryAttributes{ + VaultGenericCredentialLibraryAttributes: &pb.VaultCredentialLibraryAttributes{ + Path: wrapperspb.String(credLib.GetVaultPath()), + HttpMethod: wrapperspb.String(credLib.GetHttpMethod()), + }, + }, + } +} + +func sshCredentialLibraryToProto(credLib *vault.SSHCertificateCredentialLibrary, project *iam.Scope) *pb.CredentialLibrary { + return &pb.CredentialLibrary{ + Id: credLib.GetPublicId(), + CredentialStoreId: credLib.GetStoreId(), + CredentialType: credLib.GetCredentialType(), + Scope: &scopepb.ScopeInfo{Id: project.GetPublicId(), Type: scope.Project.String(), ParentScopeId: project.GetParentId()}, + CreatedTime: credLib.GetCreateTime().GetTimestamp(), + UpdatedTime: credLib.GetUpdateTime().GetTimestamp(), + Version: credLib.GetVersion(), + Type: vault.SSHCertificateLibrarySubtype.String(), + AuthorizedActions: testAuthorizedActions, + Attrs: &pb.CredentialLibrary_VaultSshCertificateCredentialLibraryAttributes{ + VaultSshCertificateCredentialLibraryAttributes: &pb.VaultSSHCertificateCredentialLibraryAttributes{ + KeyType: wrapperspb.String(credLib.GetKeyType()), + Path: wrapperspb.String(credLib.GetVaultPath()), + Username: wrapperspb.String(credLib.GetUsername()), + }, + }, + } +} + func TestList(t *testing.T) { ctx := context.Background() conn, _ := db.TestSetup(t, "postgres") @@ -62,43 +109,12 @@ func TestList(t *testing.T) { store := vault.TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 1)[0] var wantLibraries []*pb.CredentialLibrary for _, l := range vault.TestCredentialLibraries(t, conn, wrapper, store.GetPublicId(), 10) { - wantLibraries = append(wantLibraries, &pb.CredentialLibrary{ - Id: l.GetPublicId(), - CredentialStoreId: l.GetStoreId(), - Scope: &scopepb.ScopeInfo{Id: prj.GetPublicId(), Type: scope.Project.String(), ParentScopeId: prj.GetParentId()}, - CreatedTime: l.GetCreateTime().GetTimestamp(), - UpdatedTime: l.GetUpdateTime().GetTimestamp(), - Version: l.GetVersion(), - Type: vault.GenericLibrarySubtype.String(), - AuthorizedActions: testAuthorizedActions, - Attrs: &pb.CredentialLibrary_VaultGenericCredentialLibraryAttributes{ - VaultGenericCredentialLibraryAttributes: &pb.VaultCredentialLibraryAttributes{ - Path: wrapperspb.String(l.GetVaultPath()), - HttpMethod: wrapperspb.String(l.GetHttpMethod()), - }, - }, - }) + wantLibraries = append(wantLibraries, vaultCredentialLibraryToProto(l, prj)) } for _, l := range vault.TestSSHCertificateCredentialLibraries(t, conn, wrapper, store.GetPublicId(), 10) { - wantLibraries = append(wantLibraries, &pb.CredentialLibrary{ - Id: l.GetPublicId(), - CredentialStoreId: l.GetStoreId(), - CredentialType: l.GetCredentialType(), - Scope: &scopepb.ScopeInfo{Id: prj.GetPublicId(), Type: scope.Project.String(), ParentScopeId: prj.GetParentId()}, - CreatedTime: l.GetCreateTime().GetTimestamp(), - UpdatedTime: l.GetUpdateTime().GetTimestamp(), - Version: l.GetVersion(), - Type: vault.SSHCertificateLibrarySubtype.String(), - AuthorizedActions: testAuthorizedActions, - Attrs: &pb.CredentialLibrary_VaultSshCertificateCredentialLibraryAttributes{ - VaultSshCertificateCredentialLibraryAttributes: &pb.VaultSSHCertificateCredentialLibraryAttributes{ - KeyType: wrapperspb.String(l.GetKeyType()), - Path: wrapperspb.String(l.GetVaultPath()), - Username: wrapperspb.String(l.GetUsername()), - }, - }, - }) + wantLibraries = append(wantLibraries, sshCredentialLibraryToProto(l, prj)) } + cases := []struct { name string req *pbs.ListCredentialLibrariesRequest @@ -107,28 +123,76 @@ func TestList(t *testing.T) { err error }{ { - name: "List Many Libraries", - req: &pbs.ListCredentialLibrariesRequest{CredentialStoreId: store.GetPublicId()}, - res: &pbs.ListCredentialLibrariesResponse{Items: wantLibraries}, - anonRes: &pbs.ListCredentialLibrariesResponse{Items: wantLibraries}, + name: "List Many Libraries", + req: &pbs.ListCredentialLibrariesRequest{CredentialStoreId: store.GetPublicId()}, + res: &pbs.ListCredentialLibrariesResponse{ + Items: wantLibraries, + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + EstItemCount: 20, + }, + anonRes: &pbs.ListCredentialLibrariesResponse{ + Items: wantLibraries, + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + EstItemCount: 20, + }, }, { - name: "List No Libraries", - req: &pbs.ListCredentialLibrariesRequest{CredentialStoreId: storeNoLibs.GetPublicId()}, - res: &pbs.ListCredentialLibrariesResponse{}, - anonRes: &pbs.ListCredentialLibrariesResponse{}, + name: "List No Libraries", + req: &pbs.ListCredentialLibrariesRequest{CredentialStoreId: storeNoLibs.GetPublicId()}, + res: &pbs.ListCredentialLibrariesResponse{ + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + }, + anonRes: &pbs.ListCredentialLibrariesResponse{ + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + }, }, { - name: "Filter to One Libraries", - req: &pbs.ListCredentialLibrariesRequest{CredentialStoreId: store.GetPublicId(), Filter: fmt.Sprintf(`"/item/id"==%q`, wantLibraries[1].GetId())}, - res: &pbs.ListCredentialLibrariesResponse{Items: wantLibraries[1:2]}, - anonRes: &pbs.ListCredentialLibrariesResponse{Items: wantLibraries[1:2]}, + name: "Filter to One Library", + req: &pbs.ListCredentialLibrariesRequest{CredentialStoreId: store.GetPublicId(), Filter: fmt.Sprintf(`"/item/id"==%q`, wantLibraries[1].GetId())}, + res: &pbs.ListCredentialLibrariesResponse{ + Items: wantLibraries[1:2], + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + EstItemCount: 1, + }, + anonRes: &pbs.ListCredentialLibrariesResponse{ + Items: wantLibraries[1:2], + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + EstItemCount: 1, + }, }, { - name: "Filter to No Libraries", - req: &pbs.ListCredentialLibrariesRequest{CredentialStoreId: store.GetPublicId(), Filter: `"/item/id"=="doesnt match"`}, - res: &pbs.ListCredentialLibrariesResponse{}, - anonRes: &pbs.ListCredentialLibrariesResponse{}, + name: "Filter to No Libraries", + req: &pbs.ListCredentialLibrariesRequest{CredentialStoreId: store.GetPublicId(), Filter: `"/item/id"=="doesnt match"`}, + res: &pbs.ListCredentialLibrariesResponse{ + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + }, + anonRes: &pbs.ListCredentialLibrariesResponse{ + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + }, }, { name: "Filter Bad Format", @@ -138,9 +202,8 @@ func TestList(t *testing.T) { } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - s, err := NewService(ctx, repoFn, iamRepoFn) - require.NoError(t, err, "Couldn't create new host set service.") - + s, err := NewService(ctx, iamRepoFn, repoFn, 1000) + require.NoError(t, err) // Test non-anonymous listing got, gErr := s.ListCredentialLibraries(auth.DisabledAuthTestContext(iamRepoFn, prj.GetPublicId()), tc.req) if tc.err != nil { @@ -156,14 +219,19 @@ func TestList(t *testing.T) { sort.Slice(want.Items, func(i, j int) bool { return want.Items[i].GetId() < want.Items[j].GetId() }) - assert.Empty(t, cmp.Diff( - got, - want, - protocmp.Transform(), - cmpopts.SortSlices(func(a, b string) bool { - return a < b - }), - )) + // Compare without comparing the list token + assert.Empty( + t, + cmp.Diff( + got, + want, + protocmp.Transform(), + cmpopts.SortSlices(func(a, b string) bool { + return a < b + }), + protocmp.IgnoreFields(&pbs.ListCredentialLibrariesResponse{}, "list_token"), + ), + ) // Test anonymous listing got, gErr = s.ListCredentialLibraries(auth.DisabledAuthTestContext(iamRepoFn, prj.GetPublicId(), auth.WithUserId(globals.AnonymousUserId)), tc.req) @@ -193,6 +261,7 @@ func TestList_Attributes(t *testing.T) { repoFn := func() (*vault.Repository, error) { return vault.NewRepository(ctx, rw, rw, kms, sche) } + _, prj := iam.TestScopes(t, iamRepo) ts := vault.TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 2) @@ -200,43 +269,12 @@ func TestList_Attributes(t *testing.T) { var wantLibrariesGeneric []*pb.CredentialLibrary var wantLibrariesSSHCertificate []*pb.CredentialLibrary for _, l := range vault.TestCredentialLibraries(t, conn, wrapper, storeGeneric.GetPublicId(), 5) { - wantLibrariesGeneric = append(wantLibrariesGeneric, &pb.CredentialLibrary{ - Id: l.GetPublicId(), - CredentialStoreId: l.GetStoreId(), - Scope: &scopepb.ScopeInfo{Id: prj.GetPublicId(), Type: scope.Project.String(), ParentScopeId: prj.GetParentId()}, - CreatedTime: l.GetCreateTime().GetTimestamp(), - UpdatedTime: l.GetUpdateTime().GetTimestamp(), - Version: l.GetVersion(), - Type: vault.GenericLibrarySubtype.String(), - AuthorizedActions: testAuthorizedActions, - Attrs: &pb.CredentialLibrary_VaultGenericCredentialLibraryAttributes{ - VaultGenericCredentialLibraryAttributes: &pb.VaultCredentialLibraryAttributes{ - Path: wrapperspb.String(l.GetVaultPath()), - HttpMethod: wrapperspb.String(l.GetHttpMethod()), - }, - }, - }) + wantLibrariesGeneric = append(wantLibrariesGeneric, vaultCredentialLibraryToProto(l, prj)) } for _, l := range vault.TestSSHCertificateCredentialLibraries(t, conn, wrapper, storeSSHCertificate.GetPublicId(), 10) { - wantLibrariesSSHCertificate = append(wantLibrariesSSHCertificate, &pb.CredentialLibrary{ - Id: l.GetPublicId(), - CredentialStoreId: l.GetStoreId(), - CredentialType: l.GetCredentialType(), - Scope: &scopepb.ScopeInfo{Id: prj.GetPublicId(), Type: scope.Project.String(), ParentScopeId: prj.GetParentId()}, - CreatedTime: l.GetCreateTime().GetTimestamp(), - UpdatedTime: l.GetUpdateTime().GetTimestamp(), - Version: l.GetVersion(), - Type: vault.SSHCertificateLibrarySubtype.String(), - AuthorizedActions: testAuthorizedActions, - Attrs: &pb.CredentialLibrary_VaultSshCertificateCredentialLibraryAttributes{ - VaultSshCertificateCredentialLibraryAttributes: &pb.VaultSSHCertificateCredentialLibraryAttributes{ - KeyType: wrapperspb.String(l.GetKeyType()), - Path: wrapperspb.String(l.GetVaultPath()), - Username: wrapperspb.String(l.GetUsername()), - }, - }, - }) + wantLibrariesSSHCertificate = append(wantLibrariesSSHCertificate, sshCredentialLibraryToProto(l, prj)) } + cases := []struct { name string req *pbs.ListCredentialLibrariesRequest @@ -245,23 +283,46 @@ func TestList_Attributes(t *testing.T) { err error }{ { - name: "Filter on Attribute Generic Library", - req: &pbs.ListCredentialLibrariesRequest{CredentialStoreId: storeGeneric.GetPublicId(), Filter: fmt.Sprintf(`"/item/attributes/path"==%q`, wantLibrariesGeneric[2].GetVaultGenericCredentialLibraryAttributes().GetPath().Value)}, - res: &pbs.ListCredentialLibrariesResponse{Items: wantLibrariesGeneric[2:3]}, - anonRes: &pbs.ListCredentialLibrariesResponse{}, // anonymous user does not have access to attributes + name: "Filter on Attribute Generic Library", + req: &pbs.ListCredentialLibrariesRequest{CredentialStoreId: storeGeneric.GetPublicId(), Filter: fmt.Sprintf(`"/item/attributes/path"==%q`, wantLibrariesGeneric[2].GetVaultGenericCredentialLibraryAttributes().GetPath().Value)}, + res: &pbs.ListCredentialLibrariesResponse{ + Items: wantLibrariesGeneric[2:3], + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + EstItemCount: 1, + }, + anonRes: &pbs.ListCredentialLibrariesResponse{ + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + }, // anonymous user does not have access to attributes }, { - name: "Filter on Attribute SSH Certificate Library", - req: &pbs.ListCredentialLibrariesRequest{CredentialStoreId: storeSSHCertificate.GetPublicId(), Filter: fmt.Sprintf(`"/item/attributes/path"==%q`, wantLibrariesSSHCertificate[2].GetVaultSshCertificateCredentialLibraryAttributes().GetPath().Value)}, - res: &pbs.ListCredentialLibrariesResponse{Items: wantLibrariesSSHCertificate[2:3]}, - anonRes: &pbs.ListCredentialLibrariesResponse{}, // anonymous user does not have access to attributes + name: "Filter on Attribute SSH Certificate Library", + req: &pbs.ListCredentialLibrariesRequest{CredentialStoreId: storeSSHCertificate.GetPublicId(), Filter: fmt.Sprintf(`"/item/attributes/path"==%q`, wantLibrariesSSHCertificate[2].GetVaultSshCertificateCredentialLibraryAttributes().GetPath().Value)}, + res: &pbs.ListCredentialLibrariesResponse{ + Items: wantLibrariesSSHCertificate[2:3], + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + EstItemCount: 1, + }, + anonRes: &pbs.ListCredentialLibrariesResponse{ + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + }, // anonymous user does not have access to attributes }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - s, err := NewService(ctx, repoFn, iamRepoFn) - require.NoError(t, err, "Couldn't create new host set service.") - + s, err := NewService(ctx, iamRepoFn, repoFn, 1000) + require.NoError(t, err) // Test non-anonymous listing got, gErr := s.ListCredentialLibraries(auth.DisabledAuthTestContext(iamRepoFn, prj.GetPublicId()), tc.req) if tc.err != nil { @@ -284,17 +345,21 @@ func TestList_Attributes(t *testing.T) { cmpopts.SortSlices(func(a, b string) bool { return a < b }), + protocmp.IgnoreFields(&pbs.ListCredentialLibrariesResponse{}, "list_token"), )) // Test anonymous listing got, gErr = s.ListCredentialLibraries(auth.DisabledAuthTestContext(iamRepoFn, prj.GetPublicId(), auth.WithUserId(globals.AnonymousUserId)), tc.req) require.NoError(t, gErr) - assert.Len(t, got.Items, len(tc.anonRes.Items)) - for _, item := range got.GetItems() { - require.Nil(t, item.CreatedTime) - require.Nil(t, item.UpdatedTime) - require.Zero(t, item.Version) - } + assert.Empty( + t, + cmp.Diff( + got, + tc.anonRes, + protocmp.Transform(), + protocmp.IgnoreFields(&pbs.ListCredentialLibrariesResponse{}, "list_token"), + ), + ) }) } } @@ -828,9 +893,8 @@ func TestCreate(t *testing.T) { t.Run(tc.name, func(t *testing.T) { assert, require := assert.New(t), require.New(t) - s, err := NewService(ctx, repoFn, iamRepoFn) - require.NoError(err, "Error when getting new credential store service.") - + s, err := NewService(ctx, iamRepoFn, repoFn, 1000) + require.NoError(err) got, gErr := s.CreateCredentialLibrary(auth.DisabledAuthTestContext(iamRepoFn, prj.GetPublicId()), tc.req) if tc.wantErr || tc.err != nil { require.Error(gErr) @@ -891,9 +955,8 @@ func TestGet(t *testing.T) { store := vault.TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 1)[0] unspecifiedLib := vault.TestCredentialLibraries(t, conn, wrapper, store.GetPublicId(), 1)[0] - s, err := NewService(ctx, repoFn, iamRepoFn) + s, err := NewService(ctx, iamRepoFn, repoFn, 1000) require.NoError(t, err) - repo, err := repoFn() require.NoError(t, err) @@ -1104,9 +1167,8 @@ func TestDelete(t *testing.T) { store := vault.TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 1)[0] vl := vault.TestCredentialLibraries(t, conn, wrapper, store.GetPublicId(), 1)[0] vl2 := vault.TestSSHCertificateCredentialLibraries(t, conn, wrapper, store.GetPublicId(), 1)[0] - s, err := NewService(ctx, repoFn, iamRepoFn) + s, err := NewService(ctx, iamRepoFn, repoFn, 1000) require.NoError(t, err) - cases := []struct { name string id string @@ -1168,7 +1230,7 @@ func TestUpdate(t *testing.T) { _, prj := iam.TestScopes(t, iamRepo) ctx := auth.DisabledAuthTestContext(iamRepoFn, prj.GetPublicId()) - s, err := NewService(testCtx, repoFn, iamRepoFn) + s, err := NewService(testCtx, iamRepoFn, repoFn, 1000) require.NoError(t, err) cs := vault.TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 2) store, diffStore := cs[0], cs[1] @@ -2217,9 +2279,8 @@ func TestCreate_SSHCertificateCredentialLibrary(t *testing.T) { t.Run(tc.name, func(t *testing.T) { assert, require := assert.New(t), require.New(t) - s, err := NewService(ctx, repoFn, iamRepoFn) - require.NoError(err, "Error when getting new credential store service.") - + s, err := NewService(ctx, iamRepoFn, repoFn, 1000) + require.NoError(err) got, gErr := s.CreateCredentialLibrary(auth.DisabledAuthTestContext(iamRepoFn, prj.GetPublicId()), tc.req) if tc.wantErr || tc.err != nil { require.Error(gErr) @@ -2279,7 +2340,7 @@ func TestUpdate_SSHCertificateCredentialLibrary(t *testing.T) { _, prj := iam.TestScopes(t, iamRepo) ctx := auth.DisabledAuthTestContext(iamRepoFn, prj.GetPublicId()) - s, err := NewService(testCtx, repoFn, iamRepoFn) + s, err := NewService(testCtx, iamRepoFn, repoFn, 1000) require.NoError(t, err) cs := vault.TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 2) store, diffStore := cs[0], cs[1] @@ -2649,3 +2710,311 @@ func TestUpdate_SSHCertificateCredentialLibrary(t *testing.T) { }) } } + +func TestListPagination(t *testing.T) { + // Set database read timeout to avoid duplicates in response + oldReadTimeout := globals.RefreshReadLookbackDuration + globals.RefreshReadLookbackDuration = 0 + t.Cleanup(func() { + globals.RefreshReadLookbackDuration = oldReadTimeout + }) + assert, require := assert.New(t), require.New(t) + ctx := context.Background() + conn, _ := db.TestSetup(t, "postgres") + sqlDB, err := conn.SqlDB(ctx) + require.NoError(err) + wrapper := db.TestWrapper(t) + kms := kms.TestKms(t, conn, wrapper) + sche := scheduler.TestScheduler(t, conn, wrapper) + rw := db.New(conn) + + iamRepo := iam.TestRepo(t, conn, wrapper) + iamRepoFn := func() (*iam.Repository, error) { + return iamRepo, nil + } + repoFn := func() (*vault.Repository, error) { + return vault.NewRepository(ctx, rw, rw, kms, sche) + } + tokenRepoFn := func() (*authtoken.Repository, error) { + return authtoken.NewRepository(ctx, rw, rw, kms) + } + serversRepoFn := func() (*server.Repository, error) { + return server.NewRepository(ctx, rw, rw, kms) + } + + vaultRepo, err := repoFn() + require.NoError(err) + tokenRepo, err := tokenRepoFn() + require.NoError(err) + + _, prjNoLibs := iam.TestScopes(t, iamRepo) + storeNoLibs := vault.TestCredentialStores(t, conn, wrapper, prjNoLibs.GetPublicId(), 1)[0] + o, prj := iam.TestScopes(t, iamRepo) + + credStore := vault.TestCredentialStores(t, conn, wrapper, prj.GetPublicId(), 1)[0] + var allCredentialLibraries []*pb.CredentialLibrary + for _, l := range vault.TestCredentialLibraries(t, conn, wrapper, credStore.GetPublicId(), 5) { + allCredentialLibraries = append(allCredentialLibraries, vaultCredentialLibraryToProto(l, prj)) + } + for _, l := range vault.TestSSHCertificateCredentialLibraries(t, conn, wrapper, credStore.GetPublicId(), 5) { + allCredentialLibraries = append(allCredentialLibraries, sshCredentialLibraryToProto(l, prj)) + } + + // Reverse as we return items sorted by create_time desceding (newest first) + slices.Reverse(allCredentialLibraries) + + // Run analyze to update postgres meta tables + _, err = sqlDB.ExecContext(ctx, "analyze") + require.NoError(err) + + authMethod := password.TestAuthMethods(t, conn, o.GetPublicId(), 1)[0] + // auth account is only used to join auth method to user. + // We don't do anything else with the auth account in the test setup. + acct := password.TestAccount(t, conn, authMethod.GetPublicId(), "test_user") + u := iam.TestUser(t, iamRepo, o.GetPublicId(), iam.WithAccountIds(acct.PublicId)) + role1 := iam.TestRole(t, conn, prj.GetPublicId()) + iam.TestRoleGrant(t, conn, role1.GetPublicId(), "id=*;type=*;actions=*") + iam.TestUserRole(t, conn, role1.GetPublicId(), u.GetPublicId()) + role2 := iam.TestRole(t, conn, prjNoLibs.GetPublicId()) + iam.TestRoleGrant(t, conn, role2.GetPublicId(), "id=*;type=*;actions=*") + iam.TestUserRole(t, conn, role2.GetPublicId(), u.GetPublicId()) + at, err := tokenRepo.CreateAuthToken(ctx, u, acct.GetPublicId()) + require.NoError(err) + + // Test without anon user + requestInfo := authpb.RequestInfo{ + TokenFormat: uint32(auth.AuthTokenTypeBearer), + PublicId: at.GetPublicId(), + Token: at.GetToken(), + } + requestContext := context.WithValue(context.Background(), requests.ContextRequestInformationKey, &requests.RequestContext{}) + ctx = auth.NewVerifierContext(requestContext, iamRepoFn, tokenRepoFn, serversRepoFn, kms, &requestInfo) + + s, err := NewService(ctx, iamRepoFn, repoFn, 1000) + require.NoError(err) + // Start paginating, recursively + req := &pbs.ListCredentialLibrariesRequest{ + CredentialStoreId: credStore.PublicId, // Use store with libraries first + Filter: "", + ListToken: "", + PageSize: 2, + } + got, err := s.ListCredentialLibraries(ctx, req) + require.NoError(err) + require.Len(got.GetItems(), 2) + // Compare without comparing the list token + assert.Empty( + cmp.Diff( + got, + &pbs.ListCredentialLibrariesResponse{ + Items: allCredentialLibraries[0:2], + ResponseType: "delta", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + EstItemCount: 10, + }, + protocmp.Transform(), + protocmp.IgnoreFields(&pbs.ListCredentialLibrariesResponse{}, "list_token"), + ), + ) + + // Request second page + req.ListToken = got.ListToken + got, err = s.ListCredentialLibraries(ctx, req) + require.NoError(err) + require.Len(got.GetItems(), 2) + // Compare without comparing the list token + assert.Empty( + cmp.Diff( + got, + &pbs.ListCredentialLibrariesResponse{ + Items: allCredentialLibraries[2:4], + ResponseType: "delta", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + EstItemCount: 10, + }, + protocmp.Transform(), + protocmp.IgnoreFields(&pbs.ListCredentialLibrariesResponse{}, "list_token"), + ), + ) + + // Request rest of results + req.ListToken = got.ListToken + req.PageSize = 10 + got, err = s.ListCredentialLibraries(ctx, req) + require.NoError(err) + require.Len(got.GetItems(), 6) + // Compare without comparing the list token + assert.Empty( + cmp.Diff( + got, + &pbs.ListCredentialLibrariesResponse{ + Items: allCredentialLibraries[4:], + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + EstItemCount: 10, + }, + protocmp.Transform(), + protocmp.IgnoreFields(&pbs.ListCredentialLibrariesResponse{}, "list_token"), + ), + ) + + // Create another credential library + newCredLib := vault.TestCredentialLibraries(t, conn, wrapper, credStore.GetPublicId(), 1)[0] + pbNewCredLib := vaultCredentialLibraryToProto(newCredLib, prj) + // Prepend since this is the newest library + allCredentialLibraries = append([]*pb.CredentialLibrary{pbNewCredLib}, allCredentialLibraries...) + + // Delete one of the other credential libraries + _, err = vaultRepo.DeleteCredentialLibrary(ctx, prj.PublicId, allCredentialLibraries[len(allCredentialLibraries)-1].Id) + require.NoError(err) + deletedCredLib := allCredentialLibraries[len(allCredentialLibraries)-1] + allCredentialLibraries = allCredentialLibraries[:len(allCredentialLibraries)-1] + + // Update one of the other stores + allCredentialLibraries[1].Name = wrapperspb.String("new-name") + allCredentialLibraries[1].Version = 2 + updatedLibrary := &vault.SSHCertificateCredentialLibrary{ + SSHCertificateCredentialLibrary: &store.SSHCertificateCredentialLibrary{ + PublicId: allCredentialLibraries[1].GetId(), + StoreId: allCredentialLibraries[1].GetCredentialStoreId(), + Name: allCredentialLibraries[1].Name.Value, + }, + } + cred, _, err := vaultRepo.UpdateSSHCertificateCredentialLibrary(ctx, prj.PublicId, updatedLibrary, 1, []string{"name"}) + require.NoError(err) + allCredentialLibraries[1].UpdatedTime = cred.UpdateTime.GetTimestamp() + allCredentialLibraries[1].Version = cred.Version + // Add to the front since it's most recently updated + allCredentialLibraries = append( + []*pb.CredentialLibrary{allCredentialLibraries[1]}, + append( + []*pb.CredentialLibrary{allCredentialLibraries[0]}, + allCredentialLibraries[2:]..., + )..., + ) + + // Run analyze to update postgres meta tables + _, err = sqlDB.ExecContext(ctx, "analyze") + require.NoError(err) + + // Request updated results + req.ListToken = got.ListToken + req.PageSize = 1 + got, err = s.ListCredentialLibraries(ctx, req) + require.NoError(err) + require.Len(got.GetItems(), 1) + // Compare without comparing the list token + assert.Empty( + cmp.Diff( + got, + &pbs.ListCredentialLibrariesResponse{ + Items: []*pb.CredentialLibrary{allCredentialLibraries[0]}, + ResponseType: "delta", + SortBy: "updated_time", + SortDir: "desc", + // Should contain the deleted library + RemovedIds: []string{deletedCredLib.Id}, + EstItemCount: 10, + }, + protocmp.Transform(), + protocmp.IgnoreFields(&pbs.ListCredentialLibrariesResponse{}, "list_token"), + ), + ) + + // Get next page + req.ListToken = got.ListToken + got, err = s.ListCredentialLibraries(ctx, req) + require.NoError(err) + require.Len(got.GetItems(), 1) + // Compare without comparing the list token + assert.Empty( + cmp.Diff( + got, + &pbs.ListCredentialLibrariesResponse{ + Items: []*pb.CredentialLibrary{allCredentialLibraries[1]}, + ResponseType: "complete", + SortBy: "updated_time", + SortDir: "desc", + RemovedIds: nil, + EstItemCount: 10, + }, + protocmp.Transform(), + protocmp.IgnoreFields(&pbs.ListCredentialLibrariesResponse{}, "list_token"), + ), + ) + + // Request new page with filter requiring looping + // to fill the page. + req.ListToken = "" + req.PageSize = 1 + req.Filter = fmt.Sprintf(`"/item/id"==%q or "/item/id"==%q`, allCredentialLibraries[len(allCredentialLibraries)-2].Id, allCredentialLibraries[len(allCredentialLibraries)-1].Id) + got, err = s.ListCredentialLibraries(ctx, req) + require.NoError(err) + require.Len(got.GetItems(), 1) + assert.Empty( + cmp.Diff( + got, + &pbs.ListCredentialLibrariesResponse{ + Items: []*pb.CredentialLibrary{allCredentialLibraries[len(allCredentialLibraries)-2]}, + ResponseType: "delta", + SortBy: "created_time", + SortDir: "desc", + // Should be empty again + RemovedIds: nil, + EstItemCount: 10, + }, + protocmp.Transform(), + protocmp.IgnoreFields(&pbs.ListCredentialLibrariesResponse{}, "list_token"), + ), + ) + req.ListToken = got.ListToken + // Get the second page + got, err = s.ListCredentialLibraries(ctx, req) + require.NoError(err) + require.Len(got.GetItems(), 1) + assert.Empty( + cmp.Diff( + got, + &pbs.ListCredentialLibrariesResponse{ + Items: []*pb.CredentialLibrary{allCredentialLibraries[len(allCredentialLibraries)-1]}, + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + EstItemCount: 10, + }, + protocmp.Transform(), + protocmp.IgnoreFields(&pbs.ListCredentialLibrariesResponse{}, "list_token"), + ), + ) + req.ListToken = got.ListToken + + // List items in the empty store + req = &pbs.ListCredentialLibrariesRequest{ + CredentialStoreId: storeNoLibs.PublicId, + Filter: "", + ListToken: "", + PageSize: 2, + } + got, err = s.ListCredentialLibraries(ctx, req) + require.NoError(err) + require.Len(got.GetItems(), 0) + assert.Empty( + cmp.Diff( + got, + &pbs.ListCredentialLibrariesResponse{ + ResponseType: "complete", + ListToken: "", // Should return no token + SortBy: "created_time", + SortDir: "desc", + }, + protocmp.Transform(), + ), + ) +} diff --git a/internal/daemon/controller/handlers/targets/tcp/target_service_test.go b/internal/daemon/controller/handlers/targets/tcp/target_service_test.go index ede145b7b..906391c4d 100644 --- a/internal/daemon/controller/handlers/targets/tcp/target_service_test.go +++ b/internal/daemon/controller/handlers/targets/tcp/target_service_test.go @@ -2910,7 +2910,7 @@ func TestAuthorizeSession(t *testing.T) { sec, tok := v.CreateToken(t, vault.WithPolicies([]string{"default", "boundary-controller", "pki"})) vaultStore := vault.TestCredentialStore(t, conn, wrapper, proj.GetPublicId(), v.Addr, tok, sec.Auth.Accessor) - credService, err := credentiallibraries.NewService(ctx, vaultCredRepoFn, iamRepoFn) + credService, err := credentiallibraries.NewService(ctx, iamRepoFn, vaultCredRepoFn, 1000) require.NoError(t, err) clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credlibpb.CredentialLibrary{ CredentialStoreId: vaultStore.GetPublicId(), @@ -3167,7 +3167,7 @@ func TestAuthorizeSessionTypedCredentials(t *testing.T) { sec, tok := v.CreateToken(t, vault.WithPolicies([]string{"default", "boundary-controller", "secret"})) vaultStore := vault.TestCredentialStore(t, conn, wrapper, proj.GetPublicId(), v.Addr, tok, sec.Auth.Accessor) - credLibService, err := credentiallibraries.NewService(ctx, vaultCredRepoFn, iamRepoFn) + credLibService, err := credentiallibraries.NewService(ctx, iamRepoFn, vaultCredRepoFn, 1000) require.NoError(t, err) // Create secret in vault with default username and password fields @@ -3824,7 +3824,7 @@ func TestAuthorizeSession_Errors(t *testing.T) { } libraryExists := func(tar target.Target) (version uint32) { - credService, err := credentiallibraries.NewService(ctx, vaultCredRepoFn, iamRepoFn) + credService, err := credentiallibraries.NewService(ctx, iamRepoFn, vaultCredRepoFn, 1000) require.NoError(t, err) clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credlibpb.CredentialLibrary{ CredentialStoreId: store.GetPublicId(), @@ -3849,7 +3849,7 @@ func TestAuthorizeSession_Errors(t *testing.T) { } misConfiguredlibraryExists := func(tar target.Target) (version uint32) { - credService, err := credentiallibraries.NewService(ctx, vaultCredRepoFn, iamRepoFn) + credService, err := credentiallibraries.NewService(ctx, iamRepoFn, vaultCredRepoFn, 1000) require.NoError(t, err) clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credlibpb.CredentialLibrary{ CredentialStoreId: store.GetPublicId(), @@ -3874,7 +3874,7 @@ func TestAuthorizeSession_Errors(t *testing.T) { } expiredTokenLibrary := func(tar target.Target) (version uint32) { - credService, err := credentiallibraries.NewService(ctx, vaultCredRepoFn, iamRepoFn) + credService, err := credentiallibraries.NewService(ctx, iamRepoFn, vaultCredRepoFn, 1000) require.NoError(t, err) clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credlibpb.CredentialLibrary{ CredentialStoreId: expiredStore.GetPublicId(), diff --git a/internal/gen/controller.swagger.json b/internal/gen/controller.swagger.json index f7efc2365..8d44f06e1 100644 --- a/internal/gen/controller.swagger.json +++ b/internal/gen/controller.swagger.json @@ -668,6 +668,21 @@ "in": "query", "required": false, "type": "string" + }, + { + "name": "list_token", + "description": "An opaque token used to continue an existing iteration or\nrequest updated items. If not specified, pagination\nwill start from the beginning.", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "page_size", + "description": "The maximum size of a page in this iteration.\nIf unset, the default page size configured will be used.\nIf the page_size is greater than the max page size configured,\nthe page size will be truncated to this number.", + "in": "query", + "required": false, + "type": "integer", + "format": "int64" } ], "tags": [ @@ -7547,7 +7562,36 @@ "items": { "type": "object", "$ref": "#/definitions/controller.api.resources.credentiallibraries.v1.CredentialLibrary" - } + }, + "description": "The items returned in this page." + }, + "response_type": { + "type": "string", + "description": "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page." + }, + "list_token": { + "type": "string", + "description": "An opaque token used to continue an existing pagination or\nrequest updated items. Use this token in the next list request\nto request the next page." + }, + "sort_by": { + "type": "string", + "description": "The name of the field which the items are sorted by." + }, + "sort_dir": { + "type": "string", + "description": "The direction of the sort, either \"asc\" or \"desc\"." + }, + "removed_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings." + }, + "est_item_count": { + "type": "integer", + "format": "int64", + "description": "An estimate at the total items available. This may change during pagination." } } }, diff --git a/internal/gen/controller/api/services/credential_library_service.pb.go b/internal/gen/controller/api/services/credential_library_service.pb.go index b55af79f6..e5d886698 100644 --- a/internal/gen/controller/api/services/credential_library_service.pb.go +++ b/internal/gen/controller/api/services/credential_library_service.pb.go @@ -129,6 +129,15 @@ type ListCredentialLibrariesRequest struct { CredentialStoreId string `protobuf:"bytes,1,opt,name=credential_store_id,json=scope_id,proto3" json:"credential_store_id,omitempty" class:"public"` // @gotags: `class:"public"` Filter string `protobuf:"bytes,30,opt,name=filter,proto3" json:"filter,omitempty" class:"public"` // @gotags: `class:"public"` + // An opaque token used to continue an existing iteration or + // request updated items. If not specified, pagination + // will start from the beginning. + ListToken string `protobuf:"bytes,40,opt,name=list_token,proto3" json:"list_token,omitempty" class:"public"` // @gotags: `class:"public"` + // The maximum size of a page in this iteration. + // If unset, the default page size configured will be used. + // If the page_size is greater than the max page size configured, + // the page size will be truncated to this number. + PageSize uint32 `protobuf:"varint,50,opt,name=page_size,proto3" json:"page_size,omitempty" class:"public"` // @gotags: `class:"public"` } func (x *ListCredentialLibrariesRequest) Reset() { @@ -177,12 +186,47 @@ func (x *ListCredentialLibrariesRequest) GetFilter() string { return "" } +func (x *ListCredentialLibrariesRequest) GetListToken() string { + if x != nil { + return x.ListToken + } + return "" +} + +func (x *ListCredentialLibrariesRequest) GetPageSize() uint32 { + if x != nil { + return x.PageSize + } + return 0 +} + type ListCredentialLibrariesResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // The items returned in this page. Items []*credentiallibraries.CredentialLibrary `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` + // The type of response, either "delta" or "complete". + // Delta signifies that this is part of a paginated result + // or an update to a previously completed pagination. + // Complete signifies that it is the last page. + ResponseType string `protobuf:"bytes,2,opt,name=response_type,proto3" json:"response_type,omitempty" class:"public"` // @gotags: `class:"public"` + // An opaque token used to continue an existing pagination or + // request updated items. Use this token in the next list request + // to request the next page. + ListToken string `protobuf:"bytes,3,opt,name=list_token,proto3" json:"list_token,omitempty" class:"public"` // @gotags: `class:"public"` + // The name of the field which the items are sorted by. + SortBy string `protobuf:"bytes,4,opt,name=sort_by,proto3" json:"sort_by,omitempty" class:"public"` // @gotags: `class:"public"` + // The direction of the sort, either "asc" or "desc". + SortDir string `protobuf:"bytes,5,opt,name=sort_dir,proto3" json:"sort_dir,omitempty" class:"public"` // @gotags: `class:"public"` + // A list of item IDs that have been removed since they were returned + // as part of a pagination. They should be dropped from any client cache. + // This may contain items that are not known to the cache, if they were + // created and deleted between listings. + RemovedIds []string `protobuf:"bytes,6,rep,name=removed_ids,proto3" json:"removed_ids,omitempty" class:"public"` // @gotags: `class:"public"` + // An estimate at the total items available. This may change during pagination. + EstItemCount uint32 `protobuf:"varint,7,opt,name=est_item_count,proto3" json:"est_item_count,omitempty" class:"public"` // @gotags: `class:"public"` } func (x *ListCredentialLibrariesResponse) Reset() { @@ -224,6 +268,48 @@ func (x *ListCredentialLibrariesResponse) GetItems() []*credentiallibraries.Cred return nil } +func (x *ListCredentialLibrariesResponse) GetResponseType() string { + if x != nil { + return x.ResponseType + } + return "" +} + +func (x *ListCredentialLibrariesResponse) GetListToken() string { + if x != nil { + return x.ListToken + } + return "" +} + +func (x *ListCredentialLibrariesResponse) GetSortBy() string { + if x != nil { + return x.SortBy + } + return "" +} + +func (x *ListCredentialLibrariesResponse) GetSortDir() string { + if x != nil { + return x.SortDir + } + return "" +} + +func (x *ListCredentialLibrariesResponse) GetRemovedIds() []string { + if x != nil { + return x.RemovedIds + } + return nil +} + +func (x *ListCredentialLibrariesResponse) GetEstItemCount() uint32 { + if x != nil { + return x.EstItemCount + } + return 0 +} + type CreateCredentialLibraryRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -554,13 +640,17 @@ var file_controller_api_services_v1_credential_library_service_proto_rawDesc = [ 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, - 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x5f, 0x0a, 0x1e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x13, 0x63, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x12, - 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x7b, 0x0a, 0x1f, 0x4c, 0x69, 0x73, 0x74, 0x43, + 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x9d, 0x01, 0x0a, 0x1e, 0x4c, 0x69, 0x73, 0x74, 0x43, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x13, 0x63, 0x72, 0x65, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, + 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x69, 0x73, 0x74, + 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x69, + 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, + 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x70, 0x61, 0x67, + 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x22, 0xc1, 0x02, 0x0a, 0x1f, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x63, 0x6f, 0x6e, 0x74, @@ -568,128 +658,140 @@ var file_controller_api_services_v1_credential_library_service_proto_rawDesc = [ 0x72, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x05, 0x69, - 0x74, 0x65, 0x6d, 0x73, 0x22, 0x78, 0x0a, 0x1e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x56, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, - 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, - 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, - 0x69, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x8b, - 0x01, 0x0a, 0x1f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x75, 0x72, 0x69, 0x12, 0x56, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, - 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xc6, 0x01, 0x0a, - 0x1e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x56, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x42, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x61, 0x6c, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, - 0x79, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x3c, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, - 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x22, 0x79, 0x0a, 0x1f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, + 0x74, 0x65, 0x6d, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x69, + 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x6f, + 0x72, 0x74, 0x5f, 0x62, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x6f, 0x72, + 0x74, 0x5f, 0x62, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x64, 0x69, 0x72, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x64, 0x69, 0x72, + 0x12, 0x20, 0x0a, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x5f, 0x69, 0x64, 0x73, 0x18, + 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x5f, 0x69, + 0x64, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x65, 0x73, 0x74, 0x5f, + 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x78, 0x0a, 0x1e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, + 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x56, 0x0a, 0x04, + 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x04, + 0x69, 0x74, 0x65, 0x6d, 0x22, 0x8b, 0x01, 0x0a, 0x1f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x73, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x69, 0x62, 0x72, - 0x61, 0x72, 0x69, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, - 0x22, 0x30, 0x0a, 0x1e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, - 0x69, 0x64, 0x22, 0x21, 0x0a, 0x1f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x85, 0x09, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x12, 0xdc, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x12, 0x37, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, - 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, - 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x51, - 0x92, 0x41, 0x23, 0x12, 0x21, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, - 0x6c, 0x65, 0x20, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x4c, 0x69, - 0x62, 0x72, 0x61, 0x72, 0x79, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x62, 0x04, 0x69, 0x74, - 0x65, 0x6d, 0x12, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x2d, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x64, - 0x7d, 0x12, 0xd6, 0x01, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x3a, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, - 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x42, 0x92, 0x41, 0x1f, 0x12, 0x1d, 0x4c, 0x69, 0x73, - 0x74, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x20, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, - 0x12, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, - 0x2d, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0xe9, 0x01, 0x0a, 0x17, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, - 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x12, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, - 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x55, 0x92, 0x41, 0x26, 0x12, 0x24, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, - 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x20, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, - 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x18, 0x2f, 0x76, - 0x31, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x6c, 0x69, 0x62, - 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0xe7, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, - 0x72, 0x79, 0x12, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, - 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, - 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x56, 0x0a, 0x04, 0x69, 0x74, + 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x69, + 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x04, 0x69, 0x74, + 0x65, 0x6d, 0x22, 0xc6, 0x01, 0x0a, 0x1e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x56, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x63, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, + 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x3c, 0x0a, + 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0b, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x22, 0x79, 0x0a, 0x1f, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, + 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, + 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, + 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x30, 0x0a, 0x1e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x21, 0x0a, 0x1f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, - 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x53, 0x92, 0x41, 0x1f, - 0x12, 0x1d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x43, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x2e, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, - 0x6d, 0x32, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x2d, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, - 0x12, 0xda, 0x01, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, + 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x85, 0x09, 0x0a, 0x18, + 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, + 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xdc, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, + 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, + 0x79, 0x12, 0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, + 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, + 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x51, 0x92, 0x41, 0x23, 0x12, 0x21, 0x47, 0x65, 0x74, 0x73, 0x20, + 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x20, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x2e, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x25, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x72, + 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, + 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0xd6, 0x01, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, + 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, + 0x69, 0x65, 0x73, 0x12, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, + 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, + 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x42, 0x92, 0x41, + 0x1f, 0x12, 0x1d, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x43, 0x72, 0x65, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x2e, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, + 0x12, 0xe9, 0x01, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x12, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, + 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x46, 0x92, 0x41, 0x1e, 0x12, 0x1c, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, - 0x20, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x2a, 0x1d, - 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x6c, - 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x42, 0x5b, 0xa2, - 0xe3, 0x29, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5a, 0x4b, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, - 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, - 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x55, 0x92, 0x41, 0x26, 0x12, 0x24, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x43, 0x72, 0x65, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x2e, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, + 0x65, 0x6d, 0x22, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x2d, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0xe7, 0x01, 0x0a, + 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, + 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x12, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, + 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x53, 0x92, 0x41, 0x1f, 0x12, 0x1d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x20, + 0x61, 0x20, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x4c, 0x69, 0x62, + 0x72, 0x61, 0x72, 0x79, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x3a, 0x04, 0x69, 0x74, 0x65, + 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x32, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x72, 0x65, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, + 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0xda, 0x01, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, 0x61, + 0x72, 0x79, 0x12, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x69, 0x62, 0x72, + 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x46, 0x92, 0x41, 0x1e, + 0x12, 0x1c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x43, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x1f, 0x2a, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x2d, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x2f, 0x7b, + 0x69, 0x64, 0x7d, 0x42, 0x5b, 0xa2, 0xe3, 0x29, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x5a, 0x4b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, + 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/internal/proto/controller/api/services/v1/credential_library_service.proto b/internal/proto/controller/api/services/v1/credential_library_service.proto index da8ec3439..b14ef1bc0 100644 --- a/internal/proto/controller/api/services/v1/credential_library_service.proto +++ b/internal/proto/controller/api/services/v1/credential_library_service.proto @@ -84,10 +84,40 @@ message GetCredentialLibraryResponse { message ListCredentialLibrariesRequest { string credential_store_id = 1 [json_name = "scope_id"]; // @gotags: `class:"public"` string filter = 30 [json_name = "filter"]; // @gotags: `class:"public"` + // An opaque token used to continue an existing iteration or + // request updated items. If not specified, pagination + // will start from the beginning. + string list_token = 40 [json_name = "list_token"]; // @gotags: `class:"public"` + // The maximum size of a page in this iteration. + // If unset, the default page size configured will be used. + // If the page_size is greater than the max page size configured, + // the page size will be truncated to this number. + uint32 page_size = 50 [json_name = "page_size"]; // @gotags: `class:"public"` } message ListCredentialLibrariesResponse { + // The items returned in this page. repeated resources.credentiallibraries.v1.CredentialLibrary items = 1; + // The type of response, either "delta" or "complete". + // Delta signifies that this is part of a paginated result + // or an update to a previously completed pagination. + // Complete signifies that it is the last page. + string response_type = 2 [json_name = "response_type"]; // @gotags: `class:"public"` + // An opaque token used to continue an existing pagination or + // request updated items. Use this token in the next list request + // to request the next page. + string list_token = 3 [json_name = "list_token"]; // @gotags: `class:"public"` + // The name of the field which the items are sorted by. + string sort_by = 4 [json_name = "sort_by"]; // @gotags: `class:"public"` + // The direction of the sort, either "asc" or "desc". + string sort_dir = 5 [json_name = "sort_dir"]; // @gotags: `class:"public"` + // A list of item IDs that have been removed since they were returned + // as part of a pagination. They should be dropped from any client cache. + // This may contain items that are not known to the cache, if they were + // created and deleted between listings. + repeated string removed_ids = 6 [json_name = "removed_ids"]; // @gotags: `class:"public"` + // An estimate at the total items available. This may change during pagination. + uint32 est_item_count = 7 [json_name = "est_item_count"]; // @gotags: `class:"public"` } message CreateCredentialLibraryRequest {