mirror of
https://github.com/hashicorp/vault.git
synced 2025-08-07 23:27:01 +02:00
Removing the timeout logic from raw-response functions and adding documentation comments. The following functions are affected: - `ReadRaw` - `ReadRawWithContext` (newly added) - `ReadRawWithData` - `ReadRawWithDataWithContext` The previous logic of using `ctx, _ = c.c.withConfiguredTimeout(ctx)` could cause a potential [context leak](https://pkg.go.dev/context): > Failing to call the CancelFunc leaks the child and its children until the parent is canceled or the timer fires. The go vet tool checks that CancelFuncs are used on all control-flow paths. Cancelling the context would have caused more issues since the context would be cancelled before the request body is closed. Resolves: #18658
136 lines
2.9 KiB
Go
136 lines
2.9 KiB
Go
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)
|
|
}
|