Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[HVS] Support Pagination in run Command #147

Merged
merged 3 commits into from
Aug 30, 2024
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
3 changes: 3 additions & 0 deletions .changelog/147.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
include all secrets from paginated respoonses when invoking `hcp vs run` command
```
34 changes: 27 additions & 7 deletions internal/commands/vaultsecrets/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,20 +139,15 @@ func runRun(opts *RunOpts) (err error) {
}

func getAllSecretsForEnv(opts *RunOpts) ([]string, error) {
params := preview_secret_service.NewOpenAppSecretsParamsWithContext(opts.Ctx)
params.OrganizationID = opts.Profile.OrganizationID
params.ProjectID = opts.Profile.ProjectID
params.AppName = opts.AppName

res, err := opts.PreviewClient.OpenAppSecrets(params, nil)
secs, err := fetchPaginatedSecrets(opts)
if err != nil {
return nil, err
}

result := os.Environ()
collisions := make(map[string][]*models.Secrets20231128OpenSecret, 0)

for _, secret := range res.Payload.Secrets {
for _, secret := range secs {
// we need to append results in case of duplicates we want secrets to override
switch {
case secret.RotatingVersion != nil:
Expand Down Expand Up @@ -224,3 +219,28 @@ func setupChildProcess(ctx context.Context, command []string, envVars []string)

return cmdCtx
}

func fetchPaginatedSecrets(opts *RunOpts) ([]*models.Secrets20231128OpenSecret, error) {
params := preview_secret_service.NewOpenAppSecretsParamsWithContext(opts.Ctx)
params.OrganizationID = opts.Profile.OrganizationID
params.ProjectID = opts.Profile.ProjectID
params.AppName = opts.AppName

var secrets []*models.Secrets20231128OpenSecret
for {
resp, err := opts.PreviewClient.OpenAppSecrets(params, nil)
if err != nil {
return nil, fmt.Errorf("failed to open app secrets: %w", err)
}

secrets = append(secrets, resp.Payload.Secrets...)
if resp.Payload.Pagination == nil || resp.Payload.Pagination.NextPageToken == "" {
break
}

next := resp.Payload.Pagination.NextPageToken
params.PaginationNextPageToken = &next
}

return secrets, nil
}
98 changes: 74 additions & 24 deletions internal/commands/vaultsecrets/run/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,19 +104,17 @@ func TestRunRun(t *testing.T) {
RespErr bool
ErrMsg string
IOErrorContains string
MockCalled bool
PaginatedResp bool
}{
{
Name: "Failed: Secret not found",
RespErr: true,
Secrets: nil,
ErrMsg: "[GET /secrets/2023-11-28/organizations/{organization_id}/projects/{project_id}/apps/{app_name}/secrets:open][403]",
MockCalled: true,
Name: "Failed: Secret not found",
RespErr: true,
Secrets: nil,
ErrMsg: "[GET /secrets/2023-11-28/organizations/{organization_id}/projects/{project_id}/apps/{app_name}/secrets:open][403]",
},
{
Name: "Success",
RespErr: false,
MockCalled: true,
Name: "Success",
RespErr: false,
Secrets: []*preview_models.Secrets20231128OpenSecret{
{
Name: "static",
Expand All @@ -139,7 +137,6 @@ func TestRunRun(t *testing.T) {
{
Name: "Collide",
RespErr: false,
MockCalled: true,
ErrMsg: "multiple secrets map to the same environment variable",
IOErrorContains: "ERROR: \"static_collision\" [static], \"static\" [rotating] map to the same environment variable \"STATIC_COLLISION\"",
Secrets: []*preview_models.Secrets20231128OpenSecret{
Expand All @@ -161,6 +158,29 @@ func TestRunRun(t *testing.T) {
},
},
},
{
Name: "Paginated",
PaginatedResp: true,
RespErr: false,
Secrets: []*preview_models.Secrets20231128OpenSecret{
{
Name: "static_1",
StaticVersion: &preview_models.Secrets20231128OpenSecretStaticVersion{},
},
{
Name: "static_2",
StaticVersion: &preview_models.Secrets20231128OpenSecretStaticVersion{},
},
{
Name: "static_3",
StaticVersion: &preview_models.Secrets20231128OpenSecretStaticVersion{},
},
{
Name: "static_4",
StaticVersion: &preview_models.Secrets20231128OpenSecretStaticVersion{},
},
},
},
}

for _, c := range cases {
Expand All @@ -182,21 +202,51 @@ func TestRunRun(t *testing.T) {
Command: []string{"echo \"Testing\""},
}

if c.MockCalled {
if c.RespErr {
vs.EXPECT().OpenAppSecrets(mock.Anything, mock.Anything).Return(nil, errors.New(c.ErrMsg)).Once()
} else {
vs.EXPECT().OpenAppSecrets(&preview_secret_service.OpenAppSecretsParams{
OrganizationID: testProfile(t).OrganizationID,
ProjectID: testProfile(t).ProjectID,
AppName: testProfile(t).VaultSecrets.AppName,
Context: opts.Ctx,
}, nil).Return(&preview_secret_service.OpenAppSecretsOK{
Payload: &preview_models.Secrets20231128OpenAppSecretsResponse{
Secrets: c.Secrets,
if c.RespErr {
vs.EXPECT().OpenAppSecrets(mock.Anything, mock.Anything).Return(nil, errors.New(c.ErrMsg)).Once()
} else if c.PaginatedResp {
paginationNextPageToken := "next_page_token"

// expect first request to be missing the page token
// provide half the secrets and a NextPageToken
vs.EXPECT().OpenAppSecrets(&preview_secret_service.OpenAppSecretsParams{
OrganizationID: testProfile(t).OrganizationID,
ProjectID: testProfile(t).ProjectID,
AppName: testProfile(t).VaultSecrets.AppName,
Context: opts.Ctx,
}, mock.Anything).Return(&preview_secret_service.OpenAppSecretsOK{
Payload: &preview_models.Secrets20231128OpenAppSecretsResponse{
Secrets: c.Secrets[:len(c.Secrets)/2],
Pagination: &preview_models.CommonPaginationResponse{
NextPageToken: paginationNextPageToken,
},
}, nil).Once()
}
},
}, nil).Once()

// expect second request to have a page token
// provide later half of the secrets
vs.EXPECT().OpenAppSecrets(&preview_secret_service.OpenAppSecretsParams{
OrganizationID: testProfile(t).OrganizationID,
ProjectID: testProfile(t).ProjectID,
AppName: testProfile(t).VaultSecrets.AppName,
Context: opts.Ctx,
PaginationNextPageToken: &paginationNextPageToken,
}, mock.Anything).Return(&preview_secret_service.OpenAppSecretsOK{
Payload: &preview_models.Secrets20231128OpenAppSecretsResponse{
Secrets: c.Secrets[len(c.Secrets)/2:],
},
}, nil).Once()
} else {
vs.EXPECT().OpenAppSecrets(&preview_secret_service.OpenAppSecretsParams{
OrganizationID: testProfile(t).OrganizationID,
ProjectID: testProfile(t).ProjectID,
AppName: testProfile(t).VaultSecrets.AppName,
Context: opts.Ctx,
}, nil).Return(&preview_secret_service.OpenAppSecretsOK{
Payload: &preview_models.Secrets20231128OpenAppSecretsResponse{
Secrets: c.Secrets,
},
}, nil).Once()
}

// Run the command
Expand Down
Loading