Skip to content

Commit

Permalink
Merge pull request #147 from hashicorp/hvs-paginate-run
Browse files Browse the repository at this point in the history
[HVS] Support Pagination in run Command
  • Loading branch information
VinnyHC authored Aug 30, 2024
2 parents 773914b + 526b17d commit 98da946
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 31 deletions.
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

0 comments on commit 98da946

Please sign in to comment.