diff --git a/command/base_predict.go b/command/base_predict.go index f8fee0ae1ec3..c7b306118a3f 100644 --- a/command/base_predict.go +++ b/command/base_predict.go @@ -233,8 +233,18 @@ func (p *Predict) vaultPaths(includeFiles bool) complete.PredictFunc { path := args.Last + // Trim path with potential mount + var relativePath string + for _, mount := range p.mounts() { + if strings.HasPrefix(path, mount) { + relativePath = strings.TrimPrefix(path, mount+"/") + break + } + } + + // Predict path or mount depending on path separator var predictions []string - if strings.Contains(path, "/") { + if strings.Contains(relativePath, "/") { predictions = p.paths(path, includeFiles) } else { predictions = p.filter(p.mounts(), path) diff --git a/command/base_predict_test.go b/command/base_predict_test.go index 9523dc938d6a..2e06b6f5ec93 100644 --- a/command/base_predict_test.go +++ b/command/base_predict_test.go @@ -31,6 +31,12 @@ func TestPredictVaultPaths(t *testing.T) { if _, err := client.Logical().Write("secret/zip/twoot", data); err != nil { t.Fatal(err) } + if err := client.Sys().Mount("level1a/level2a/level3a", &api.MountInput{Type: "kv"}); err != nil { + t.Fatal(err) + } + if err := client.Sys().Mount("level1a/level2a/level3b", &api.MountInput{Type: "kv"}); err != nil { + t.Fatal(err) + } cases := []struct { name string @@ -182,6 +188,18 @@ func TestPredictVaultPaths(t *testing.T) { false, []string{"secret/zip/t"}, }, + { + "multi_nested", + complete.Args{ + All: []string{"read", "level1a/level2a"}, + Last: "level1a/level2a", + }, + false, + []string{ + "level1a/level2a/level3a/", + "level1a/level2a/level3b/", + }, + }, } t.Run("group", func(t *testing.T) {