Skip to content

Commit e73978f

Browse files
committed
feat(cmd): Test --verbose and --verbose-sensitive-output
Signed-off-by: Oliver Gondža <[email protected]>
1 parent 427d4df commit e73978f

File tree

5 files changed

+90
-25
lines changed

5 files changed

+90
-25
lines changed

cmd/generate.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import (
2020
func NewGenerateCommand() *cobra.Command {
2121
const StdIn = "-"
2222
var configPath, secretName string
23-
var verboseOutput bool
24-
var verboseUnsafe bool
23+
var verboseSafe bool
24+
var verboseSensitive bool
2525
var disableCache bool
2626

2727
var command = &cobra.Command{
@@ -64,9 +64,12 @@ func NewGenerateCommand() *cobra.Command {
6464
}
6565

6666
v := viper.New()
67-
viper.Set("verboseOutput", verboseOutput)
68-
viper.Set("verboseUnsafe", verboseUnsafe)
67+
viper.Set("verbose", verboseSafe || verboseSensitive)
68+
viper.Set("verboseRedact", verboseSafe && !verboseSensitive)
6969
viper.Set("disableCache", disableCache)
70+
if verboseSensitive {
71+
utils.VerboseToStdErr("Running with --verbose-sensitive-output. Sensitive information will be printed to standard error!")
72+
}
7073
cmdConfig, err := config.New(v, &config.Options{
7174
SecretName: secretName,
7275
ConfigPath: configPath,
@@ -119,8 +122,8 @@ func NewGenerateCommand() *cobra.Command {
119122

120123
command.Flags().StringVarP(&configPath, "config-path", "c", "", "path to a file containing Vault configuration (YAML, JSON, envfile) to use")
121124
command.Flags().StringVarP(&secretName, "secret-name", "s", "", "name of a Kubernetes Secret in the argocd namespace containing Vault configuration data in the argocd namespace of your ArgoCD host (Only available when used in ArgoCD). The namespace can be overridden by using the format <namespace>:<name>")
122-
command.Flags().BoolVar(&verboseOutput, "verboseOutput", false, "enable verboseOutput mode for detailed info to help with debugging. Omits sensitive data (credentials), logged to stderr")
123-
command.Flags().BoolVar(&verboseUnsafe, "verboseOutput-sensitive-output", false, "enable verboseOutput mode for detailed info to help with debugging. Includes sensitive data (credentials), logged to stderr")
125+
command.Flags().BoolVar(&verboseSafe, "verbose", false, "enable verbose mode for detailed info to help with debugging. Omits sensitive data (credentials), logged to stderr")
126+
command.Flags().BoolVar(&verboseSensitive, "verbose-sensitive-output", false, "enable verbose mode for detailed info to help with debugging. Includes sensitive data (credentials), logged to stderr")
124127
command.Flags().BoolVar(&disableCache, "disable-token-cache", false, "disable the automatic token cache feature that store tokens locally")
125128
return command
126129
}

cmd/generate_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cmd
33
import (
44
"bytes"
55
"fmt"
6+
"github.com/stretchr/testify/assert"
67
"io"
78
"os"
89
"strings"
@@ -308,3 +309,60 @@ func TestMain(t *testing.T) {
308309
os.Unsetenv("VAULT_SKIP_VERIFY")
309310
os.Unsetenv("AVP_PATH_VALIDATION")
310311
}
312+
313+
func TestVerboseness(t *testing.T) {
314+
cluster, roleid, secretid = helpers.CreateTestAppRoleVault(t)
315+
os.Setenv("AVP_TYPE", "vault")
316+
os.Setenv("VAULT_ADDR", cluster.Cores[0].Client.Address())
317+
os.Setenv("AVP_AUTH_TYPE", "approle")
318+
os.Setenv("AVP_SECRET_ID", "broken_but_secret")
319+
os.Setenv("AVP_ROLE_ID", "broken_but_secret")
320+
os.Setenv("VAULT_SKIP_VERIFY", "true")
321+
322+
t.Run("Quiet", func(t *testing.T) {
323+
cmd := NewGenerateCommand()
324+
cmd.SetArgs([]string{"../fixtures/input/nonempty/secret_path.yaml"})
325+
cmd.SetOut(bytes.NewBufferString(""))
326+
cmd.SetErr(bytes.NewBufferString(""))
327+
logOut := helpers.CaptureOutput(func() {
328+
cmd.Execute()
329+
})
330+
331+
assert.Equal(t, "", logOut)
332+
})
333+
334+
t.Run("Safe verbose", func(t *testing.T) {
335+
cmd := NewGenerateCommand()
336+
cmd.SetArgs([]string{"../fixtures/input/nonempty/secret_path.yaml", "--verbose"})
337+
cmd.SetOut(bytes.NewBufferString(""))
338+
cmd.SetErr(bytes.NewBufferString(""))
339+
logOut := helpers.CaptureOutput(func() {
340+
cmd.Execute()
341+
})
342+
343+
assert.Contains(t, logOut, "Hashicorp Vault authenticating with role ID ***REDACTED(17 characters)*** and secret ID ***REDACTED(17 characters)*** at path auth/approle")
344+
assert.NotContains(t, logOut, "broken_but_secret")
345+
})
346+
347+
t.Run("Sensitive verbose", func(t *testing.T) {
348+
cmd := NewGenerateCommand()
349+
cmd.SetArgs([]string{"../fixtures/input/nonempty/secret_path.yaml", "--verbose-sensitive-output"})
350+
cmd.SetOut(bytes.NewBufferString(""))
351+
cmd.SetErr(bytes.NewBufferString(""))
352+
logOut := helpers.CaptureOutput(func() {
353+
cmd.Execute()
354+
})
355+
356+
assert.Contains(t, logOut, "Running with --verbose-sensitive-output. Sensitive information will be printed to standard error!")
357+
assert.Contains(t, logOut, "Hashicorp Vault authenticating with role ID broken_but_secret and secret ID broken_but_secret at path auth/approle")
358+
assert.NotContains(t, logOut, "***REDACTED")
359+
})
360+
361+
os.Unsetenv("AVP_TYPE")
362+
os.Unsetenv("VAULT_ADDR")
363+
os.Unsetenv("AVP_AUTH_TYPE")
364+
os.Unsetenv("AVP_SECRET_ID")
365+
os.Unsetenv("AVP_ROLE_ID")
366+
os.Unsetenv("VAULT_SKIP_VERIFY")
367+
os.Unsetenv("AVP_PATH_VALIDATION")
368+
}

pkg/config/config_test.go

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
package config_test
22

33
import (
4-
"bytes"
54
"fmt"
6-
"log"
75
"os"
86
"strings"
97
"testing"
108

119
"github.com/argoproj-labs/argocd-vault-plugin/pkg/config"
10+
"github.com/argoproj-labs/argocd-vault-plugin/pkg/helpers"
1211
"github.com/spf13/viper"
1312
)
1413

@@ -267,19 +266,6 @@ func TestNewConfigNoAuthType(t *testing.T) {
267266
os.Unsetenv("AVP_TYPE")
268267
}
269268

270-
// Helper function that captures log output from a function call into a string
271-
// Adapted from https://stackoverflow.com/a/26806093/170154
272-
func captureOutput(f func()) string {
273-
var buf bytes.Buffer
274-
flags := log.Flags()
275-
log.SetOutput(&buf)
276-
log.SetFlags(0) // don't include any date or time in the logging messages
277-
f()
278-
log.SetOutput(os.Stderr)
279-
log.SetFlags(flags)
280-
return buf.String()
281-
}
282-
283269
func TestNewConfigAwsRegionWarning(t *testing.T) {
284270
testCases := []struct {
285271
environment map[string]interface{}
@@ -314,7 +300,7 @@ func TestNewConfigAwsRegionWarning(t *testing.T) {
314300
viper.Set("verboseOutput", true)
315301

316302
v := viper.New()
317-
output := captureOutput(func() {
303+
output := helpers.CaptureOutput(func() {
318304
config, err := config.New(v, &config.Options{})
319305
if err != nil {
320306
t.Error(err)

pkg/helpers/test_helpers.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package helpers
22

33
import (
4+
"bytes"
45
"fmt"
6+
"log"
57
"net"
8+
"os"
69
"strconv"
710
"testing"
811

@@ -543,3 +546,16 @@ func (v *MockVault) GetIndividualSecret(path, secret, version string, annotation
543546
num, _ := strconv.ParseInt(version, 10, 0)
544547
return v.Data[num-1][secret], nil
545548
}
549+
550+
// Helper function that captures log output from a function call into a string
551+
// Adapted from https://stackoverflow.com/a/26806093/170154
552+
func CaptureOutput(f func()) string {
553+
var buf bytes.Buffer
554+
flags := log.Flags()
555+
log.SetOutput(&buf)
556+
log.SetFlags(0) // don't include any date or time in the logging messages
557+
f()
558+
log.SetOutput(os.Stderr)
559+
log.SetFlags(flags)
560+
return buf.String()
561+
}

pkg/utils/util.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,15 +142,17 @@ func DefaultHttpClient() *http.Client {
142142
return httpClient
143143
}
144144

145+
// VerboseToStdErr formatand prints message to stderr, if either `--verbose` or `--verbose-sensitive-output` were passed.
146+
// It is a responsibility of the user to call SanitizeUnsafe on all arguments that can contain sensitive data.
145147
func VerboseToStdErr(format string, message ...interface{}) {
146-
if viper.GetBool("verboseOutput") {
148+
if viper.GetBool("verbose") {
147149
log.Printf(fmt.Sprintf("%s\n", format), message...)
148150
}
149151
}
150152

151-
// SanitizeUnsafe replaces the message data with redacted literal unless `--verbose-sensitive-output` was passed
153+
// SanitizeUnsafe replaces the message data with redacted literal unless `--verbose-sensitive-output` was passed.
152154
func SanitizeUnsafe(message interface{}) interface{} {
153-
if viper.GetBool("verboseOutput") && !viper.GetBool("verboseUnsafe") {
155+
if viper.GetBool("verboseRedact") {
154156
messageLen := len(fmt.Sprintf("%s", message))
155157
return fmt.Sprintf("***REDACTED(%v characters)***", messageLen)
156158
} else {

0 commit comments

Comments
 (0)