From cdc019e670caf1adc7be82c237dbeaf0fa25334a Mon Sep 17 00:00:00 2001 From: Valerie Conklin Date: Fri, 25 Feb 2022 10:51:49 -0800 Subject: [PATCH 01/10] Full secret path in table output of get and put --- command/kv_get.go | 2 ++ command/kv_helpers.go | 30 +++++++++++++++++++++--------- command/kv_put.go | 12 +++++++++++- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/command/kv_get.go b/command/kv_get.go index 3a7130626e29..c3365985847d 100644 --- a/command/kv_get.go +++ b/command/kv_get.go @@ -158,6 +158,8 @@ func (c *KVGetCommand) Run(args []string) int { tf.printWarnings(c.UI, secret) } + outputSecretPath(c.UI, path) + if metadata, ok := secret.Data["metadata"]; ok && metadata != nil { c.UI.Info(getHeaderForMap("Metadata", metadata.(map[string]interface{}))) OutputData(c.UI, metadata) diff --git a/command/kv_helpers.go b/command/kv_helpers.go index 1442be6ed762..f1d05c1601c7 100644 --- a/command/kv_helpers.go +++ b/command/kv_helpers.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/go-secure-stdlib/strutil" "github.com/hashicorp/vault/api" + "github.com/mitchellh/cli" ) func kvReadRequest(client *api.Client, path string, params map[string]string) (*api.Secret, error) { @@ -141,6 +142,26 @@ func getHeaderForMap(header string, data map[string]interface{}) string { // 4 for the column spaces and 5 for the len("value") totalLen := maxKey + 4 + 5 + return addEqualSigns(header, totalLen) +} + +func kvParseVersionsFlags(versions []string) []string { + versionsOut := make([]string, 0, len(versions)) + for _, v := range versions { + versionsOut = append(versionsOut, strutil.ParseStringSlice(v, ",")...) + } + + return versionsOut +} + +func outputSecretPath(ui cli.Ui, path string) { + ui.Info(addEqualSigns("Secret Path", len(path))) + ui.Info(path) + ui.Info("") +} + +// Pad the table header with equal signs on each side +func addEqualSigns(header string, totalLen int) string { equalSigns := totalLen - (len(header) + 2) // If we have zero or fewer equal signs bump it back up to two on either @@ -156,12 +177,3 @@ func getHeaderForMap(header string, data map[string]interface{}) string { return fmt.Sprintf("%s %s %s", strings.Repeat("=", equalSigns/2), header, strings.Repeat("=", equalSigns/2)) } - -func kvParseVersionsFlags(versions []string) []string { - versionsOut := make([]string, 0, len(versions)) - for _, v := range versions { - versionsOut = append(versionsOut, strutil.ParseStringSlice(v, ",")...) - } - - return versionsOut -} diff --git a/command/kv_put.go b/command/kv_put.go index 90349f6f34fd..1527672bc620 100644 --- a/command/kv_put.go +++ b/command/kv_put.go @@ -161,5 +161,15 @@ func (c *KVPutCommand) Run(args []string) int { return PrintRawField(c.UI, secret, c.flagField) } - return OutputSecret(c.UI, secret) + if Format(c.UI) != "table" { + return OutputSecret(c.UI, secret) + } + + outputSecretPath(c.UI, path) + + metadata := secret.Data + c.UI.Info(getHeaderForMap("Metadata", metadata)) + OutputData(c.UI, metadata) + + return 0 } From 5aab198db61f3f350893ad9d0e62dde94eb32b7c Mon Sep 17 00:00:00 2001 From: Valerie Conklin Date: Mon, 28 Feb 2022 08:32:03 -0800 Subject: [PATCH 02/10] Add path output to KV patch and metadata get --- command/kv_get.go | 2 +- command/kv_helpers.go | 8 ++++++-- command/kv_metadata_get.go | 2 ++ command/kv_patch.go | 12 +++++++++++- command/kv_put.go | 2 +- 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/command/kv_get.go b/command/kv_get.go index c3365985847d..88ee42065efd 100644 --- a/command/kv_get.go +++ b/command/kv_get.go @@ -158,7 +158,7 @@ func (c *KVGetCommand) Run(args []string) int { tf.printWarnings(c.UI, secret) } - outputSecretPath(c.UI, path) + outputPath(c.UI, path, false) if metadata, ok := secret.Data["metadata"]; ok && metadata != nil { c.UI.Info(getHeaderForMap("Metadata", metadata.(map[string]interface{}))) diff --git a/command/kv_helpers.go b/command/kv_helpers.go index f1d05c1601c7..d730c0a8d466 100644 --- a/command/kv_helpers.go +++ b/command/kv_helpers.go @@ -154,8 +154,12 @@ func kvParseVersionsFlags(versions []string) []string { return versionsOut } -func outputSecretPath(ui cli.Ui, path string) { - ui.Info(addEqualSigns("Secret Path", len(path))) +func outputPath(ui cli.Ui, path string, isMetadataPath bool) { + header := "Secret Path" + if isMetadataPath { + header = "Metadata Path" + } + ui.Info(addEqualSigns(header, len(path))) ui.Info(path) ui.Info("") } diff --git a/command/kv_metadata_get.go b/command/kv_metadata_get.go index c37e0db65327..cdcea6b012e9 100644 --- a/command/kv_metadata_get.go +++ b/command/kv_metadata_get.go @@ -117,6 +117,8 @@ func (c *KVMetadataGetCommand) Run(args []string) int { delete(secret.Data, "versions") + outputPath(c.UI, path, true) + c.UI.Info(getHeaderForMap("Metadata", secret.Data)) OutputSecret(c.UI, secret) diff --git a/command/kv_patch.go b/command/kv_patch.go index 7b54fb64fdfd..b143076d591d 100644 --- a/command/kv_patch.go +++ b/command/kv_patch.go @@ -185,7 +185,17 @@ func (c *KVPatchCommand) Run(args []string) int { return code } - return OutputSecret(c.UI, secret) + if Format(c.UI) != "table" { + return OutputSecret(c.UI, secret) + } + + outputPath(c.UI, path, false) + + metadata := secret.Data + c.UI.Info(getHeaderForMap("Metadata", metadata)) + OutputData(c.UI, metadata) + + return 0 } func (c *KVPatchCommand) readThenWrite(client *api.Client, path string, newData map[string]interface{}) (*api.Secret, int) { diff --git a/command/kv_put.go b/command/kv_put.go index 1527672bc620..d16f5e8c38f7 100644 --- a/command/kv_put.go +++ b/command/kv_put.go @@ -165,7 +165,7 @@ func (c *KVPutCommand) Run(args []string) int { return OutputSecret(c.UI, secret) } - outputSecretPath(c.UI, path) + outputPath(c.UI, path, false) metadata := secret.Data c.UI.Info(getHeaderForMap("Metadata", metadata)) From fe8b11141bd63abd13d308ae935dac50fa123b0c Mon Sep 17 00:00:00 2001 From: Valerie Conklin Date: Mon, 28 Feb 2022 09:42:32 -0800 Subject: [PATCH 03/10] Add changelog --- changelog/14301.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelog/14301.txt diff --git a/changelog/14301.txt b/changelog/14301.txt new file mode 100644 index 000000000000..9f5e4ba1c9d2 --- /dev/null +++ b/changelog/14301.txt @@ -0,0 +1,3 @@ +```release-note:improvement +secrets/kv: add full secret path output to table-formatted responses +``` From a0832fbee9ec8039d569b5baca8396a6a5008c10 Mon Sep 17 00:00:00 2001 From: Valerie Conklin Date: Mon, 28 Feb 2022 09:54:29 -0800 Subject: [PATCH 04/10] Don't print secret path for kv-v1 --- command/kv_get.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/command/kv_get.go b/command/kv_get.go index 88ee42065efd..6543f90c8380 100644 --- a/command/kv_get.go +++ b/command/kv_get.go @@ -158,7 +158,9 @@ func (c *KVGetCommand) Run(args []string) int { tf.printWarnings(c.UI, secret) } - outputPath(c.UI, path, false) + if v2 { + outputPath(c.UI, path, false) + } if metadata, ok := secret.Data["metadata"]; ok && metadata != nil { c.UI.Info(getHeaderForMap("Metadata", metadata.(map[string]interface{}))) From 6e23ed40d1409cdcfeea2695ec6ba3aea2fe1c32 Mon Sep 17 00:00:00 2001 From: Valerie Conklin Date: Thu, 3 Mar 2022 09:13:23 -0800 Subject: [PATCH 05/10] Make more readable --- command/kv_get.go | 2 +- command/kv_helpers.go | 12 ++++-------- command/kv_metadata_get.go | 2 +- command/kv_patch.go | 2 +- command/kv_put.go | 2 +- 5 files changed, 8 insertions(+), 12 deletions(-) diff --git a/command/kv_get.go b/command/kv_get.go index 6543f90c8380..14202d76449b 100644 --- a/command/kv_get.go +++ b/command/kv_get.go @@ -159,7 +159,7 @@ func (c *KVGetCommand) Run(args []string) int { } if v2 { - outputPath(c.UI, path, false) + outputPath(c.UI, path, "Secret Path") } if metadata, ok := secret.Data["metadata"]; ok && metadata != nil { diff --git a/command/kv_helpers.go b/command/kv_helpers.go index d730c0a8d466..7a2bf9f8d962 100644 --- a/command/kv_helpers.go +++ b/command/kv_helpers.go @@ -142,7 +142,7 @@ func getHeaderForMap(header string, data map[string]interface{}) string { // 4 for the column spaces and 5 for the len("value") totalLen := maxKey + 4 + 5 - return addEqualSigns(header, totalLen) + return padEqualSigns(header, totalLen) } func kvParseVersionsFlags(versions []string) []string { @@ -154,18 +154,14 @@ func kvParseVersionsFlags(versions []string) []string { return versionsOut } -func outputPath(ui cli.Ui, path string, isMetadataPath bool) { - header := "Secret Path" - if isMetadataPath { - header = "Metadata Path" - } - ui.Info(addEqualSigns(header, len(path))) +func outputPath(ui cli.Ui, path string, title string) { + ui.Info(padEqualSigns(title, len(path))) ui.Info(path) ui.Info("") } // Pad the table header with equal signs on each side -func addEqualSigns(header string, totalLen int) string { +func padEqualSigns(header string, totalLen int) string { equalSigns := totalLen - (len(header) + 2) // If we have zero or fewer equal signs bump it back up to two on either diff --git a/command/kv_metadata_get.go b/command/kv_metadata_get.go index cdcea6b012e9..61abf3a57c9b 100644 --- a/command/kv_metadata_get.go +++ b/command/kv_metadata_get.go @@ -117,7 +117,7 @@ func (c *KVMetadataGetCommand) Run(args []string) int { delete(secret.Data, "versions") - outputPath(c.UI, path, true) + outputPath(c.UI, path, "Metadata Path") c.UI.Info(getHeaderForMap("Metadata", secret.Data)) OutputSecret(c.UI, secret) diff --git a/command/kv_patch.go b/command/kv_patch.go index b143076d591d..5d0a5d965ec9 100644 --- a/command/kv_patch.go +++ b/command/kv_patch.go @@ -189,7 +189,7 @@ func (c *KVPatchCommand) Run(args []string) int { return OutputSecret(c.UI, secret) } - outputPath(c.UI, path, false) + outputPath(c.UI, path, "Secret Path") metadata := secret.Data c.UI.Info(getHeaderForMap("Metadata", metadata)) diff --git a/command/kv_put.go b/command/kv_put.go index d16f5e8c38f7..b462871259a6 100644 --- a/command/kv_put.go +++ b/command/kv_put.go @@ -165,7 +165,7 @@ func (c *KVPutCommand) Run(args []string) int { return OutputSecret(c.UI, secret) } - outputPath(c.UI, path, false) + outputPath(c.UI, path, "Secret Path") metadata := secret.Data c.UI.Info(getHeaderForMap("Metadata", metadata)) From ce1a6640ee2146d47955d6b5d50dfb2035b194e9 Mon Sep 17 00:00:00 2001 From: Valerie Conklin Date: Thu, 3 Mar 2022 10:03:54 -0800 Subject: [PATCH 06/10] Switch around logic to not swallow error --- command/kv_patch.go | 15 ++++++--------- command/kv_put.go | 25 +++++++++++++++++-------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/command/kv_patch.go b/command/kv_patch.go index 5d0a5d965ec9..334ba6f463ac 100644 --- a/command/kv_patch.go +++ b/command/kv_patch.go @@ -185,17 +185,14 @@ func (c *KVPatchCommand) Run(args []string) int { return code } - if Format(c.UI) != "table" { - return OutputSecret(c.UI, secret) + if Format(c.UI) == "table" { + outputPath(c.UI, path, "Secret Path") + metadata := secret.Data + c.UI.Info(getHeaderForMap("Metadata", metadata)) + return OutputData(c.UI, metadata) } - outputPath(c.UI, path, "Secret Path") - - metadata := secret.Data - c.UI.Info(getHeaderForMap("Metadata", metadata)) - OutputData(c.UI, metadata) - - return 0 + return OutputSecret(c.UI, secret) } func (c *KVPatchCommand) readThenWrite(client *api.Client, path string, newData map[string]interface{}) (*api.Secret, int) { diff --git a/command/kv_put.go b/command/kv_put.go index b462871259a6..eba8cff04819 100644 --- a/command/kv_put.go +++ b/command/kv_put.go @@ -161,15 +161,24 @@ func (c *KVPutCommand) Run(args []string) int { return PrintRawField(c.UI, secret, c.flagField) } - if Format(c.UI) != "table" { - return OutputSecret(c.UI, secret) - } + // if Format(c.UI) != "table" { + // return OutputSecret(c.UI, secret) + // } + + // outputPath(c.UI, path, "Secret Path") - outputPath(c.UI, path, "Secret Path") + // metadata := secret.Data + // c.UI.Info(getHeaderForMap("Metadata", metadata)) + // OutputData(c.UI, metadata) - metadata := secret.Data - c.UI.Info(getHeaderForMap("Metadata", metadata)) - OutputData(c.UI, metadata) + // return 0 + + if Format(c.UI) == "table" { + outputPath(c.UI, path, "Secret Path") + metadata := secret.Data + c.UI.Info(getHeaderForMap("Metadata", metadata)) + return OutputData(c.UI, metadata) + } - return 0 + return OutputSecret(c.UI, secret) } From dffb01e1f7fa6e1d29f713cfe3666fc55478cdaa Mon Sep 17 00:00:00 2001 From: Valerie Conklin Date: Thu, 3 Mar 2022 15:14:10 -0800 Subject: [PATCH 07/10] Add test for secret path --- command/kv_test.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/command/kv_test.go b/command/kv_test.go index 41a6e68e20dd..aca1fb3632ce 100644 --- a/command/kv_test.go +++ b/command/kv_test.go @@ -134,6 +134,12 @@ func TestKVPutCommand(t *testing.T) { v2ExpectedFields, 0, }, + { + "v2_secret_path", + []string{"kv/write/foo", "foo=bar"}, + []string{"== Secret Path ==", "kv/data/write/foo"}, + 0, + }, } for _, tc := range cases { @@ -441,6 +447,12 @@ func TestKVGetCommand(t *testing.T) { append(baseV2ExpectedFields, "foo"), 0, }, + { + "v2_secret_path", + []string{"kv/read/foo"}, + []string{"== Secret Path ==", "kv/data/read/foo"}, + 0, + }, } t.Run("validations", func(t *testing.T) { @@ -560,6 +572,12 @@ func TestKVMetadataGetCommand(t *testing.T) { append(expectedTopLevelFields, expectedVersionFields[:]...), 0, }, + { + "path_exists", + []string{"kv/foo"}, + []string{"=== Metadata Path ===", "kv/metadata/write/foo"}, + 0, + }, } t.Run("validations", func(t *testing.T) { @@ -872,6 +890,13 @@ func TestKVPatchCommand_RWMethodSucceeds(t *testing.T) { } } + // Test that full path was output + for _, str := range []string{"== Secret Path ==", "kv/data/patch/foo"} { + if !strings.Contains(combined, str) { + t.Errorf("expected %q to contain %q", combined, str) + } + } + // Test multi value args = []string{"-method", "rw", "kv/patch/foo", "foo=aaa", "bar=bbb"} code, combined = kvPatchWithRetry(t, client, args, nil) From 76a970dd1105c83b8756b7724b2e15bcc45d5031 Mon Sep 17 00:00:00 2001 From: Valerie Conklin Date: Thu, 3 Mar 2022 17:48:43 -0800 Subject: [PATCH 08/10] Fix metadata test --- command/kv_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/kv_test.go b/command/kv_test.go index aca1fb3632ce..ed91cd318a31 100644 --- a/command/kv_test.go +++ b/command/kv_test.go @@ -575,7 +575,7 @@ func TestKVMetadataGetCommand(t *testing.T) { { "path_exists", []string{"kv/foo"}, - []string{"=== Metadata Path ===", "kv/metadata/write/foo"}, + []string{"== Metadata Path ==", "kv/metadata/foo"}, 0, }, } From 8aebe13e6cac2dd3e23d2ef566ec97cf07f152e0 Mon Sep 17 00:00:00 2001 From: Valerie Conklin Date: Mon, 7 Mar 2022 11:25:06 -0800 Subject: [PATCH 09/10] Add unit test for padequalsigns --- command/kv_test.go | 92 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 70 insertions(+), 22 deletions(-) diff --git a/command/kv_test.go b/command/kv_test.go index ed91cd318a31..20c7afcf27b4 100644 --- a/command/kv_test.go +++ b/command/kv_test.go @@ -1131,28 +1131,6 @@ func TestKVPatchCommand_403Fallback(t *testing.T) { } } -func createTokenForPolicy(t *testing.T, client *api.Client, policy string) (*api.SecretAuth, error) { - t.Helper() - - if err := client.Sys().PutPolicy("policy", policy); err != nil { - return nil, err - } - - secret, err := client.Auth().Token().Create(&api.TokenCreateRequest{ - Policies: []string{"policy"}, - TTL: "30m", - }) - if err != nil { - return nil, err - } - - if secret == nil || secret.Auth == nil || secret.Auth.ClientToken == "" { - return nil, fmt.Errorf("missing auth data: %#v", secret) - } - - return secret.Auth, err -} - func TestKVPatchCommand_RWMethodPolicyVariations(t *testing.T) { cases := []struct { name string @@ -1230,3 +1208,73 @@ func TestKVPatchCommand_RWMethodPolicyVariations(t *testing.T) { }) } } + +func TestPadEqualSigns(t *testing.T) { + t.Parallel() + + header := "Test Header" + + cases := []struct { + name string + totalPathLen int + expectedCount int + }{ + { + name: "path with even length", + totalPathLen: 20, + expectedCount: 4, + }, + { + name: "path with odd length", + totalPathLen: 19, + expectedCount: 3, + }, + { + name: "smallest possible path", + totalPathLen: 8, + expectedCount: 2, + }, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + padded := padEqualSigns(header, tc.totalPathLen) + + signs := strings.Split(padded, fmt.Sprintf(" %s ", header)) + if len(signs[0]) != len(signs[1]) { + t.Fatalf("expected an equal number of equal signs on both sides") + } + for _, sign := range signs { + count := strings.Count(sign, "=") + if count != tc.expectedCount { + t.Fatalf("expected %d equal signs but there were %d", tc.expectedCount, count) + } + } + }) + } +} + +func createTokenForPolicy(t *testing.T, client *api.Client, policy string) (*api.SecretAuth, error) { + t.Helper() + + if err := client.Sys().PutPolicy("policy", policy); err != nil { + return nil, err + } + + secret, err := client.Auth().Token().Create(&api.TokenCreateRequest{ + Policies: []string{"policy"}, + TTL: "30m", + }) + if err != nil { + return nil, err + } + + if secret == nil || secret.Auth == nil || secret.Auth.ClientToken == "" { + return nil, fmt.Errorf("missing auth data: %#v", secret) + } + + return secret.Auth, err +} From 2711bedd84bce3cf0c7f12fefbb107fd088b8eaf Mon Sep 17 00:00:00 2001 From: Valerie Conklin Date: Tue, 8 Mar 2022 08:27:45 -0800 Subject: [PATCH 10/10] Remove wonky kv get tests --- command/kv_test.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/command/kv_test.go b/command/kv_test.go index 20c7afcf27b4..fd5303db01ba 100644 --- a/command/kv_test.go +++ b/command/kv_test.go @@ -447,12 +447,6 @@ func TestKVGetCommand(t *testing.T) { append(baseV2ExpectedFields, "foo"), 0, }, - { - "v2_secret_path", - []string{"kv/read/foo"}, - []string{"== Secret Path ==", "kv/data/read/foo"}, - 0, - }, } t.Run("validations", func(t *testing.T) { @@ -572,12 +566,6 @@ func TestKVMetadataGetCommand(t *testing.T) { append(expectedTopLevelFields, expectedVersionFields[:]...), 0, }, - { - "path_exists", - []string{"kv/foo"}, - []string{"== Metadata Path ==", "kv/metadata/foo"}, - 0, - }, } t.Run("validations", func(t *testing.T) {