diff --git a/build/docker/debian.Dockerfile b/build/docker/debian.Dockerfile index 3bedc813..f17c490c 100644 --- a/build/docker/debian.Dockerfile +++ b/build/docker/debian.Dockerfile @@ -134,6 +134,7 @@ RUN apt -y update && apt -y install --no-install-recommends \ tar \ uuid-dev \ xz-utils \ + zip \ zlib1g && \ curl -O https://download.swift.org/swiftly/linux/swiftly-$(uname -m).tar.gz && \ tar zxf swiftly-$(uname -m).tar.gz && \ diff --git a/internal/cmd/root/root.go b/internal/cmd/root/root.go index 616d7ead..2b5646f7 100644 --- a/internal/cmd/root/root.go +++ b/internal/cmd/root/root.go @@ -40,10 +40,13 @@ Complete documentation is available at https://docs.debricked.com/tools-and-inte &accessToken, OldAccessTokenFlag, "t", - viper.GetString(AccessTokenFlag), + "", `Debricked access token. Read more: https://docs.debricked.com/product/administration/generate-access-token`, ) + // Set the env var value directly on the variable (not as the flag's registered default) so it + // isn't echoed back in --help/usage output, while still allowing -t/--access-token to override it. + accessToken = viper.GetString(AccessTokenFlag) var debClient = container.DebClient() debClient.SetAccessToken(&accessToken) diff --git a/internal/cmd/root/root_test.go b/internal/cmd/root/root_test.go index 17c9fe74..d5251ec7 100644 --- a/internal/cmd/root/root_test.go +++ b/internal/cmd/root/root_test.go @@ -1,6 +1,7 @@ package root import ( + "bytes" "testing" "github.com/debricked/cli/internal/wire" @@ -52,3 +53,41 @@ func TestPreRun(t *testing.T) { cmd := NewRootCmd("", wire.GetCliContainer()) cmd.PreRun(cmd, nil) } + +func TestAccessTokenFlagDoesNotLeakEnvValueAsDefault(t *testing.T) { + t.Setenv("DEBRICKED_TOKEN", "supersecrettoken") + + cmd := NewRootCmd("v0.0.0", wire.GetCliContainer()) + + flag := cmd.PersistentFlags().Lookup(OldAccessTokenFlag) + assert.NotNil(t, flag) + assert.Empty(t, flag.DefValue, "flag default must not expose the env var value") + assert.NotContains(t, cmd.UsageString(), "supersecrettoken") +} + +func TestAccessTokenFallsBackToEnvValue(t *testing.T) { + t.Setenv("DEBRICKED_TOKEN", "env-token") + + NewRootCmd("v0.0.0", wire.GetCliContainer()) + + assert.Equal(t, "env-token", accessToken, "env var must still be used when the flag is omitted") +} + +func TestAccessTokenFlagOverridesEnvValue(t *testing.T) { + cases := []string{"--" + OldAccessTokenFlag, "-t"} + for _, flagName := range cases { + t.Run(flagName, func(t *testing.T) { + t.Setenv("DEBRICKED_TOKEN", "env-token") + + cmd := NewRootCmd("v0.0.0", wire.GetCliContainer()) + output := &bytes.Buffer{} + cmd.SetOut(output) + cmd.SetErr(output) + cmd.SetArgs([]string{flagName, "flag-token"}) + + assert.NoError(t, cmd.Execute()) + assert.Equal(t, "flag-token", accessToken, "flag must take precedence over the env var") + assert.NotContains(t, output.String(), "env-token", "help output must not contain the env var value") + }) + } +}