diff --git a/changelog/20488.txt b/changelog/20488.txt new file mode 100644 index 000000000..5ea0f78b3 --- /dev/null +++ b/changelog/20488.txt @@ -0,0 +1,3 @@ +```release-note:improvement +cli: Improve addPrefixToKVPath helper +``` diff --git a/command/kv_delete.go b/command/kv_delete.go index d10c9ebc3..a365c8916 100644 --- a/command/kv_delete.go +++ b/command/kv_delete.go @@ -156,7 +156,7 @@ func (c *KVDeleteCommand) Run(args []string) int { var fullPath string if v2 { secret, err = c.deleteV2(partialPath, mountPath, client) - fullPath = addPrefixToKVPath(partialPath, mountPath, "data") + fullPath = addPrefixToKVPath(partialPath, mountPath, "data", false) } else { // v1 if mountFlagSyntax { @@ -195,13 +195,13 @@ func (c *KVDeleteCommand) deleteV2(path, mountPath string, client *api.Client) ( var secret *api.Secret switch { case len(c.flagVersions) > 0: - path = addPrefixToKVPath(path, mountPath, "delete") + path = addPrefixToKVPath(path, mountPath, "delete", false) data := map[string]interface{}{ "versions": kvParseVersionsFlags(c.flagVersions), } secret, err = client.Logical().Write(path, data) default: - path = addPrefixToKVPath(path, mountPath, "data") + path = addPrefixToKVPath(path, mountPath, "data", false) secret, err = client.Logical().Delete(path) } diff --git a/command/kv_destroy.go b/command/kv_destroy.go index 2ac115cd2..1167ec814 100644 --- a/command/kv_destroy.go +++ b/command/kv_destroy.go @@ -155,7 +155,7 @@ func (c *KVDestroyCommand) Run(args []string) int { c.UI.Error("Destroy not supported on KV Version 1") return 1 } - destroyPath := addPrefixToKVPath(partialPath, mountPath, "destroy") + destroyPath := addPrefixToKVPath(partialPath, mountPath, "destroy", false) if err != nil { c.UI.Error(err.Error()) return 2 diff --git a/command/kv_get.go b/command/kv_get.go index c5c93fc96..1d0e330e7 100644 --- a/command/kv_get.go +++ b/command/kv_get.go @@ -152,7 +152,7 @@ func (c *KVGetCommand) Run(args []string) int { var fullPath string // Add /data to v2 paths only if v2 { - fullPath = addPrefixToKVPath(partialPath, mountPath, "data") + fullPath = addPrefixToKVPath(partialPath, mountPath, "data", false) if c.flagVersion > 0 { versionParam = map[string]string{ diff --git a/command/kv_helpers.go b/command/kv_helpers.go index 878e25282..adf2ec3fd 100644 --- a/command/kv_helpers.go +++ b/command/kv_helpers.go @@ -128,15 +128,15 @@ func isKVv2(path string, client *api.Client) (string, bool, error) { return mountPath, version == 2, nil } -func addPrefixToKVPath(p, mountPath, apiPrefix string) string { - if p == mountPath || p == strings.TrimSuffix(mountPath, "/") { +func addPrefixToKVPath(path, mountPath, apiPrefix string, skipIfExists bool) string { + if path == mountPath || path == strings.TrimSuffix(mountPath, "/") { return paths.Join(mountPath, apiPrefix) } - tp := strings.TrimPrefix(p, mountPath) + pathSuffix := strings.TrimPrefix(path, mountPath) for { // If the entire mountPath is included in the path, we are done - if tp != p { + if pathSuffix != path { break } // Trim the parts of the mountPath that are not included in the @@ -147,10 +147,16 @@ func addPrefixToKVPath(p, mountPath, apiPrefix string) string { break } mountPath = strings.TrimSuffix(partialMountPath[1], "/") - tp = strings.TrimPrefix(tp, mountPath) + pathSuffix = strings.TrimPrefix(pathSuffix, mountPath) } - return paths.Join(mountPath, apiPrefix, tp) + if skipIfExists { + if strings.HasPrefix(pathSuffix, apiPrefix) || strings.HasPrefix(pathSuffix, "/"+apiPrefix) { + return paths.Join(mountPath, pathSuffix) + } + } + + return paths.Join(mountPath, apiPrefix, pathSuffix) } func getHeaderForMap(header string, data map[string]interface{}) string { diff --git a/command/kv_helpers_test.go b/command/kv_helpers_test.go new file mode 100644 index 000000000..5ab1f6e39 --- /dev/null +++ b/command/kv_helpers_test.go @@ -0,0 +1,78 @@ +package command + +import "testing" + +// TestAddPrefixToKVPath tests the addPrefixToKVPath helper function +func TestAddPrefixToKVPath(t *testing.T) { + cases := map[string]struct { + path string + mountPath string + apiPrefix string + skipIfExists bool + expected string + }{ + "simple": { + path: "kv-v2/foo", + mountPath: "kv-v2/", + apiPrefix: "data", + skipIfExists: false, + expected: "kv-v2/data/foo", + }, + + "multi-part": { + path: "my/kv-v2/mount/path/foo/bar/baz", + mountPath: "my/kv-v2/mount/path", + apiPrefix: "metadata", + skipIfExists: false, + expected: "my/kv-v2/mount/path/metadata/foo/bar/baz", + }, + + "with-namespace": { + path: "my/kv-v2/mount/path/foo/bar/baz", + mountPath: "my/ns1/my/kv-v2/mount/path", + apiPrefix: "metadata", + skipIfExists: false, + expected: "my/kv-v2/mount/path/metadata/foo/bar/baz", + }, + + "skip-if-exists-true": { + path: "kv-v2/data/foo", + mountPath: "kv-v2/", + apiPrefix: "data", + skipIfExists: true, + expected: "kv-v2/data/foo", + }, + + "skip-if-exists-false": { + path: "kv-v2/data/foo", + mountPath: "kv-v2", + apiPrefix: "data", + skipIfExists: false, + expected: "kv-v2/data/data/foo", + }, + + "skip-if-exists-with-namespace": { + path: "my/kv-v2/mount/path/metadata/foo/bar/baz", + mountPath: "my/ns1/my/kv-v2/mount/path", + apiPrefix: "metadata", + skipIfExists: true, + expected: "my/kv-v2/mount/path/metadata/foo/bar/baz", + }, + } + + for name, tc := range cases { + name, tc := name, tc + t.Run(name, func(t *testing.T) { + actual := addPrefixToKVPath( + tc.path, + tc.mountPath, + tc.apiPrefix, + tc.skipIfExists, + ) + + if tc.expected != actual { + t.Fatalf("unexpected output; want: %v, got: %v", tc.expected, actual) + } + }) + } +} diff --git a/command/kv_list.go b/command/kv_list.go index 5b74edcc1..25ad4d2a7 100644 --- a/command/kv_list.go +++ b/command/kv_list.go @@ -136,7 +136,7 @@ func (c *KVListCommand) Run(args []string) int { // Add /metadata to v2 paths only var fullPath string if v2 { - fullPath = addPrefixToKVPath(partialPath, mountPath, "metadata") + fullPath = addPrefixToKVPath(partialPath, mountPath, "metadata", false) } else { // v1 if mountFlagSyntax { diff --git a/command/kv_metadata_delete.go b/command/kv_metadata_delete.go index 5cb97b0ed..6217506f2 100644 --- a/command/kv_metadata_delete.go +++ b/command/kv_metadata_delete.go @@ -138,7 +138,7 @@ func (c *KVMetadataDeleteCommand) Run(args []string) int { return 1 } - fullPath := addPrefixToKVPath(partialPath, mountPath, "metadata") + fullPath := addPrefixToKVPath(partialPath, mountPath, "metadata", false) if secret, err := client.Logical().Delete(fullPath); err != nil { c.UI.Error(fmt.Sprintf("Error deleting %s: %s", fullPath, err)) if secret != nil { diff --git a/command/kv_metadata_get.go b/command/kv_metadata_get.go index db5e3f25a..8d1721074 100644 --- a/command/kv_metadata_get.go +++ b/command/kv_metadata_get.go @@ -140,7 +140,7 @@ func (c *KVMetadataGetCommand) Run(args []string) int { return 1 } - fullPath := addPrefixToKVPath(partialPath, mountPath, "metadata") + fullPath := addPrefixToKVPath(partialPath, mountPath, "metadata", false) secret, err := client.Logical().Read(fullPath) if err != nil { c.UI.Error(fmt.Sprintf("Error reading %s: %s", fullPath, err)) diff --git a/command/kv_metadata_patch.go b/command/kv_metadata_patch.go index 3de4881ff..60d1a3e8b 100644 --- a/command/kv_metadata_patch.go +++ b/command/kv_metadata_patch.go @@ -211,7 +211,7 @@ func (c *KVMetadataPatchCommand) Run(args []string) int { return 1 } - fullPath := addPrefixToKVPath(partialPath, mountPath, "metadata") + fullPath := addPrefixToKVPath(partialPath, mountPath, "metadata", false) data := make(map[string]interface{}, 0) diff --git a/command/kv_metadata_put.go b/command/kv_metadata_put.go index 5acea825a..9ec43e0ba 100644 --- a/command/kv_metadata_put.go +++ b/command/kv_metadata_put.go @@ -199,7 +199,7 @@ func (c *KVMetadataPutCommand) Run(args []string) int { return 1 } - fullPath := addPrefixToKVPath(partialPath, mountPath, "metadata") + fullPath := addPrefixToKVPath(partialPath, mountPath, "metadata", false) data := map[string]interface{}{} if c.flagMaxVersions >= 0 { diff --git a/command/kv_patch.go b/command/kv_patch.go index e6fad922b..3f5080d4d 100644 --- a/command/kv_patch.go +++ b/command/kv_patch.go @@ -220,7 +220,7 @@ func (c *KVPatchCommand) Run(args []string) int { return 2 } - fullPath := addPrefixToKVPath(partialPath, mountPath, "data") + fullPath := addPrefixToKVPath(partialPath, mountPath, "data", false) if err != nil { c.UI.Error(err.Error()) return 2 diff --git a/command/kv_put.go b/command/kv_put.go index bdbd34b0f..77c0c6a11 100644 --- a/command/kv_put.go +++ b/command/kv_put.go @@ -181,7 +181,7 @@ func (c *KVPutCommand) Run(args []string) int { // Add /data to v2 paths only var fullPath string if v2 { - fullPath = addPrefixToKVPath(partialPath, mountPath, "data") + fullPath = addPrefixToKVPath(partialPath, mountPath, "data", false) data = map[string]interface{}{ "data": data, "options": map[string]interface{}{}, diff --git a/command/kv_rollback.go b/command/kv_rollback.go index a0aec415f..c54d7bc2f 100644 --- a/command/kv_rollback.go +++ b/command/kv_rollback.go @@ -164,7 +164,7 @@ func (c *KVRollbackCommand) Run(args []string) int { return 2 } - fullPath := addPrefixToKVPath(partialPath, mountPath, "data") + fullPath := addPrefixToKVPath(partialPath, mountPath, "data", false) if err != nil { c.UI.Error(err.Error()) return 2 diff --git a/command/kv_undelete.go b/command/kv_undelete.go index 8b8eab569..25de58835 100644 --- a/command/kv_undelete.go +++ b/command/kv_undelete.go @@ -150,7 +150,7 @@ func (c *KVUndeleteCommand) Run(args []string) int { return 1 } - undeletePath := addPrefixToKVPath(partialPath, mountPath, "undelete") + undeletePath := addPrefixToKVPath(partialPath, mountPath, "undelete", false) data := map[string]interface{}{ "versions": kvParseVersionsFlags(c.flagVersions), }