Skip to content

Commit

Permalink
Add paths to rotate
Browse files Browse the repository at this point in the history
  • Loading branch information
seanyeh committed Jan 29, 2025
1 parent d038e93 commit 210b26d
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 8 deletions.
1 change: 1 addition & 0 deletions cmd/esc/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,7 @@ func (c *testPulumiClient) RotateEnvironment(
projectName string,
envName string,
duration time.Duration,
rotationPaths []string,
) (string, []client.EnvironmentDiagnostic, error) {
return c.OpenEnvironment(ctx, orgName, projectName, envName, "", duration)
}
Expand Down
11 changes: 10 additions & 1 deletion cmd/esc/cli/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ type Client interface {
) (string, []EnvironmentDiagnostic, error)

// RotateEnvironment will rotate credentials in an environment.
// If rotationPaths is non-empty, will only rotate credentials at those paths.
// It also evaluates the environment projectName/envName in org orgName and returns the ID of the opened
// environment. The opened environment will be available for the indicated duration, after which it
// will expire.
Expand All @@ -167,6 +168,7 @@ type Client interface {
projectName string,
envName string,
duration time.Duration,
rotationPaths []string,
) (string, []EnvironmentDiagnostic, error)

// CheckYAMLEnvironment checks the given environment YAML for errors within the context of org orgName.
Expand Down Expand Up @@ -636,9 +638,16 @@ func (pc *client) RotateEnvironment(
projectName string,
envName string,
duration time.Duration,
rotationPaths []string,
) (string, []EnvironmentDiagnostic, error) {
path := fmt.Sprintf("/api/esc/environments/%v/%v/%v/rotate", orgName, projectName, envName)

reqObj := struct {
Paths []string `url:"paths"`
}{
Paths: rotationPaths,
}

queryObj := struct {
Duration string `url:"duration"`
}{
Expand All @@ -648,7 +657,7 @@ func (pc *client) RotateEnvironment(
ID string `json:"id"`
}
var errResp EnvironmentErrorResponse
err := pc.restCallWithOptions(ctx, http.MethodPost, path, queryObj, nil, &resp, httpCallOptions{
err := pc.restCallWithOptions(ctx, http.MethodPost, path, queryObj, reqObj, &resp, httpCallOptions{
ErrorResponse: &errResp,
})
if err != nil {
Expand Down
14 changes: 10 additions & 4 deletions cmd/esc/cli/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -505,18 +505,24 @@ func TestOpenEnvironment(t *testing.T) {
}

func TestRotateEnvironment(t *testing.T) {
rotationPaths := []string{"a.b", "c"}
t.Run("OK", func(t *testing.T) {
const expectedID = "open-id"
duration := 2 * time.Hour
expectedBody := "{\"Paths\":[\"a.b\",\"c\"]}"

client := newTestClient(t, http.MethodPost, "/api/esc/environments/test-org/test-project/test-env/rotate", func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, duration.String(), r.URL.Query().Get("duration"))

err := json.NewEncoder(w).Encode(map[string]any{"id": expectedID})
body, err := io.ReadAll(r.Body)
require.NoError(t, err)
assert.Equal(t, expectedBody, string(body))

err = json.NewEncoder(w).Encode(map[string]any{"id": expectedID})
require.NoError(t, err)
})

id, diags, err := client.RotateEnvironment(context.Background(), "test-org", "test-project", "test-env", duration)
id, diags, err := client.RotateEnvironment(context.Background(), "test-org", "test-project", "test-env", duration, rotationPaths)
require.NoError(t, err)
assert.Equal(t, expectedID, id)
assert.Empty(t, diags)
Expand Down Expand Up @@ -553,7 +559,7 @@ func TestRotateEnvironment(t *testing.T) {
require.NoError(t, err)
})

_, diags, err := client.RotateEnvironment(context.Background(), "test-org", "test-project", "test-env", 2*time.Hour)
_, diags, err := client.RotateEnvironment(context.Background(), "test-org", "test-project", "test-env", 2*time.Hour, rotationPaths)
require.NoError(t, err)
assert.Equal(t, expected, diags)
})
Expand All @@ -569,7 +575,7 @@ func TestRotateEnvironment(t *testing.T) {
require.NoError(t, err)
})

_, _, err := client.RotateEnvironment(context.Background(), "test-org", "test-project", "test-env", 2*time.Hour)
_, _, err := client.RotateEnvironment(context.Background(), "test-org", "test-project", "test-env", 2*time.Hour, rotationPaths)
assert.ErrorContains(t, err, "not found")
})
}
Expand Down
18 changes: 15 additions & 3 deletions cmd/esc/cli/env_rotate.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ func newEnvRotateCmd(envcmd *envCommand) *cobra.Command {
var format string

cmd := &cobra.Command{
Use: "rotate [<org-name>/][<project-name>/]<environment-name>",
Use: "rotate [<org-name>/][<project-name>/]<environment-name> [path(s) to rotate]",
Short: "Rotate secrets and open the environment",
Long: "Rotate secrets and open the environment\n" +
"\n" +
"Optionally accepts any number of Property Paths as additional arguments. If given any paths, will only rotate secrets at those paths.\n" +
"\n" +
"This command opens the environment with the given name. The result is written to\n" +
"stdout as JSON.\n",
Expand All @@ -42,14 +44,23 @@ func newEnvRotateCmd(envcmd *envCommand) *cobra.Command {
return fmt.Errorf("the rotate command does not accept environments at specific versions")
}

rotationPaths := []string{}
for _, arg := range args[1:] {
_, err := resource.ParsePropertyPath(arg)
if err != nil {
return fmt.Errorf("invalid path: %w", err)
}
rotationPaths = append(rotationPaths, arg)
}

switch format {
case "detailed", "json", "yaml", "string", "dotenv", "shell":
// OK
default:
return fmt.Errorf("unknown output format %q", format)
}

env, diags, err := envcmd.rotateEnvironment(ctx, ref, duration)
env, diags, err := envcmd.rotateEnvironment(ctx, ref, duration, rotationPaths)
if err != nil {
return err
}
Expand All @@ -75,8 +86,9 @@ func (env *envCommand) rotateEnvironment(
ctx context.Context,
ref environmentRef,
duration time.Duration,
rotationPaths []string,
) (*esc.Environment, []client.EnvironmentDiagnostic, error) {
envID, diags, err := env.esc.client.RotateEnvironment(ctx, ref.orgName, ref.projectName, ref.envName, duration)
envID, diags, err := env.esc.client.RotateEnvironment(ctx, ref.orgName, ref.projectName, ref.envName, duration, rotationPaths)
if err != nil {
return nil, nil, err
}
Expand Down

0 comments on commit 210b26d

Please sign in to comment.