Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add -mount flag to kv list command #19378

Merged
merged 15 commits into from
Mar 20, 2023
77 changes: 63 additions & 14 deletions command/kv_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package command

import (
"fmt"
"path"
"strings"

"github.com/mitchellh/cli"
Expand All @@ -15,6 +16,7 @@ var (

type KVListCommand struct {
*BaseCommand
flagMount string
}

func (c *KVListCommand) Synopsis() string {
Expand All @@ -40,7 +42,23 @@ Usage: vault kv list [options] PATH
}

func (c *KVListCommand) Flags() *FlagSets {
return c.flagSet(FlagSetHTTP | FlagSetOutputFormat)
set := c.flagSet(FlagSetHTTP | FlagSetOutputFormat)

// Common Options
f := set.NewFlagSet("Common Options")

f.StringVar(&StringVar{
Name: "mount",
Target: &c.flagMount,
Default: "", // no default, because the handling of the next arg is determined by whether this flag has a value
Usage: `Specifies the path where the KV backend is mounted. If specified,
the next argument will be interpreted as the secret path. If this flag is
not specified, the next argument will be interpreted as the combined mount
path and secret path, with /data/ automatically appended between KV
v2 secrets.`,
Comment on lines +57 to +58
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
path and secret path, with /data/ automatically appended between KV
v2 secrets.`,
path and secret path, with /data/ automatically inserted between the two
paths for KV-v2 secrets.`,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is copied from kv get

vault/command/kv_get.go

Lines 72 to 76 in e4e9612

Usage: `Specifies the path where the KV backend is mounted. If specified,
the next argument will be interpreted as the secret path. If this flag is
not specified, the next argument will be interpreted as the combined mount
path and secret path, with /data/ automatically appended between KV
v2 secrets.`,

so going to leave for now

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps adjusting both descriptions for clarity would help.

})

return set
}

func (c *KVListCommand) AutocompleteArgs() complete.Predictor {
Expand Down Expand Up @@ -75,25 +93,56 @@ func (c *KVListCommand) Run(args []string) int {
return 2
}

// Sanitize path
path := sanitizePath(args[0])
mountPath, v2, err := isKVv2(path, client)
if err != nil {
c.UI.Error(err.Error())
return 2
}
// If true, we're working with "-mount=secret foo" syntax.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// If false, we're using "secret/foo" syntax.
mountFlagSyntax := c.flagMount != ""

var (
mountPath string
partialPath string
v2 bool
)

// Parse the paths and grab the KV version
if mountFlagSyntax {
// In this case, this arg is the secret path (e.g. "foo").
partialPath = sanitizePath(args[0])
mountPath, v2, err = isKVv2(sanitizePath(c.flagMount), client)
if err != nil {
c.UI.Error(err.Error())
return 2
}

if v2 {
path = addPrefixToKVPath(path, mountPath, "metadata")
if v2 {
partialPath = path.Join(mountPath, partialPath)
}
} else {
// In this case, this arg is a path-like combination of mountPath/secretPath.
// (e.g. "secret/foo")
partialPath = sanitizePath(args[0])
mountPath, v2, err = isKVv2(partialPath, client)
if err != nil {
c.UI.Error(err.Error())
return 2
}
}

secret, err := client.Logical().List(path)
// Add /data to v2 paths only
var fullPath string
if v2 {
fullPath = addPrefixToKVPath(partialPath, mountPath, "data")
} else {
// v1
if mountFlagSyntax {
fullPath = path.Join(mountPath, partialPath)
} else {
Comment on lines +138 to +141
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit hard to follow these if blocks, perhaps they can be rearranged a bit for clarity? In particular we are doing path.Join(...) for kv-v1 here yet for kv-v2 in the previous if block.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just copied the logic from kv put

each command in kv ... does this a little differently, going to look to consolidate the logic in a subsequent ticket

fullPath = partialPath
}
}

secret, err := client.Logical().List(fullPath)
if err != nil {
c.UI.Error(fmt.Sprintf("Error listing %s: %s", path, err))
c.UI.Error(fmt.Sprintf("Error listing %s: %s", fullPath, err))
return 2
}

Expand All @@ -111,12 +160,12 @@ func (c *KVListCommand) Run(args []string) int {
}

if secret == nil || secret.Data == nil {
c.UI.Error(fmt.Sprintf("No value found at %s", path))
c.UI.Error(fmt.Sprintf("No value found at %s", fullPath))
return 2
}

if !ok {
c.UI.Error(fmt.Sprintf("No entries found at %s", path))
c.UI.Error(fmt.Sprintf("No entries found at %s", fullPath))
return 2
}

Expand Down