// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package command import ( "context" "fmt" "io" "os" "strings" "github.com/mitchellh/cli" "github.com/posener/complete" ) var ( _ cli.Command = (*ReadCommand)(nil) _ cli.CommandAutocomplete = (*ReadCommand)(nil) ) type ReadCommand struct { *BaseCommand testStdin io.Reader // for tests } func (c *ReadCommand) Synopsis() string { return "Read data and retrieves secrets" } func (c *ReadCommand) Help() string { helpText := ` Usage: vault read [options] PATH Reads data from Vault at the given path. This can be used to read secrets, generate dynamic credentials, get configuration details, and more. Read a secret from the static secrets engine: $ vault read secret/my-secret For a full list of examples and paths, please see the documentation that corresponds to the secrets engine in use. ` + c.Flags().Help() return strings.TrimSpace(helpText) } func (c *ReadCommand) Flags() *FlagSets { return c.flagSet(FlagSetHTTP | FlagSetOutputField | FlagSetOutputFormat) } func (c *ReadCommand) AutocompleteArgs() complete.Predictor { return c.PredictVaultFiles() } func (c *ReadCommand) AutocompleteFlags() complete.Flags { return c.Flags().Completions() } func (c *ReadCommand) Run(args []string) int { f := c.Flags() if err := f.Parse(args, ParseOptionAllowRawFormat(true)); err != nil { c.UI.Error(err.Error()) return 1 } args = f.Args() switch { case len(args) < 1: c.UI.Error(fmt.Sprintf("Not enough arguments (expected 1, got %d)", len(args))) return 1 } client, err := c.Client() if err != nil { c.UI.Error(err.Error()) return 2 } // client.ReadRaw* methods require a manual timeout override ctx, cancel := context.WithTimeout(context.Background(), client.ClientTimeout()) defer cancel() // Pull our fake stdin if needed stdin := (io.Reader)(os.Stdin) if c.testStdin != nil { stdin = c.testStdin } path := sanitizePath(args[0]) data, err := parseArgsDataStringLists(stdin, args[1:]) if err != nil { c.UI.Error(fmt.Sprintf("Failed to parse K=V data: %s", err)) return 1 } if Format(c.UI) != "raw" { secret, err := client.Logical().ReadWithDataWithContext(ctx, path, data) if err != nil { c.UI.Error(fmt.Sprintf("Error reading %s: %s", path, err)) return 2 } if secret == nil { c.UI.Error(fmt.Sprintf("No value found at %s", path)) return 2 } if c.flagField != "" { return PrintRawField(c.UI, secret, c.flagField) } return OutputSecret(c.UI, secret) } resp, err := client.Logical().ReadRawWithDataWithContext(ctx, path, data) if err != nil { c.UI.Error(fmt.Sprintf("Error reading: %s: %s", path, err)) return 2 } if resp == nil || resp.Body == nil { c.UI.Error(fmt.Sprintf("No value found at %s", path)) return 2 } defer resp.Body.Close() contents, err := io.ReadAll(resp.Body) if err != nil { c.UI.Error(fmt.Sprintf("Error reading: %s: %s", path, err)) return 2 } return OutputData(c.UI, contents) }