From dbd07addf5f92a4650cce7c729d5f30e63a92c70 Mon Sep 17 00:00:00 2001 From: Seth Vargo Date: Thu, 7 Sep 2017 22:04:16 -0400 Subject: [PATCH] Update write command --- command/write.go | 28 ++++++++++++++-------------- command/write_test.go | 41 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 18 deletions(-) diff --git a/command/write.go b/command/write.go index 3046e2b38..ed25ba6ce 100644 --- a/command/write.go +++ b/command/write.go @@ -10,7 +10,6 @@ import ( "github.com/posener/complete" ) -// Ensure we are implementing the right interfaces. var _ cli.Command = (*WriteCommand)(nil) var _ cli.CommandAutocomplete = (*WriteCommand)(nil) @@ -24,7 +23,7 @@ type WriteCommand struct { } func (c *WriteCommand) Synopsis() string { - return "Writes data, configuration, and secrets" + return "Write data, configuration, and secrets" } func (c *WriteCommand) Help() string { @@ -33,17 +32,17 @@ Usage: vault write [options] PATH [DATA K=V...] Writes data to Vault at the given path. The data can be credentials, secrets, configuration, or arbitrary data. The specific behavior of this command is - determined at the backend mounted at the path. + determined at the thing mounted at the path. Data is specified as "key=value" pairs. If the value begins with an "@", then it is loaded from a file. If the value is "-", Vault will read the value from stdin. - Persist data in the static secret backend: + Persist data in the generic secrets engine: $ vault write secret/my-secret foo=bar - Create a new encryption key in the transit backend: + Create a new encryption key in the transit secrets engine: $ vault write -f transit/keys/my-key @@ -56,7 +55,7 @@ Usage: vault write [options] PATH [DATA K=V...] $ echo $MY_TOKEN | vault write consul/config/access token=- For a full list of examples and paths, please see the documentation that - corresponds to the secret backend in use. + corresponds to the secret engines in use. ` + c.Flags().Help() @@ -99,14 +98,13 @@ func (c *WriteCommand) Run(args []string) int { return 1 } - path, kvs, err := extractPath(f.Args()) - if err != nil { - c.UI.Error(err.Error()) + args = f.Args() + switch { + case len(args) < 1: + c.UI.Error(fmt.Sprintf("Not enough arguments (expected 1, got %d)", len(args))) return 1 - } - - if len(kvs) == 0 && !c.flagForce { - c.UI.Error("Missing DATA! Specify at least one K=V pair or use -force.") + case len(args) == 1 && !c.flagForce: + c.UI.Error("Must supply data or use -force") return 1 } @@ -116,7 +114,9 @@ func (c *WriteCommand) Run(args []string) int { stdin = c.testStdin } - data, err := parseArgsData(stdin, kvs) + path := sanitizePath(args[0]) + + data, err := parseArgsData(stdin, args[1:]) if err != nil { c.UI.Error(fmt.Sprintf("Failed to parse K=V data: %s", err)) return 1 diff --git a/command/write_test.go b/command/write_test.go index 7139e7a51..03aab4c79 100644 --- a/command/write_test.go +++ b/command/write_test.go @@ -5,6 +5,7 @@ import ( "strings" "testing" + "github.com/hashicorp/vault/api" "github.com/mitchellh/cli" ) @@ -29,15 +30,15 @@ func TestWriteCommand_Run(t *testing.T) { code int }{ { - "empty_path", - nil, - "Missing PATH!", + "not_enough_args", + []string{}, + "Not enough arguments", 1, }, { "empty_kvs", []string{"secret/write/foo"}, - "Missing DATA!", + "Must supply data or use -force", 1, }, { @@ -114,6 +115,38 @@ func TestWriteCommand_Run(t *testing.T) { }) } + t.Run("force", func(t *testing.T) { + t.Parallel() + + client, closer := testVaultServer(t) + defer closer() + + if err := client.Sys().Mount("transit/", &api.MountInput{ + Type: "transit", + }); err != nil { + t.Fatal(err) + } + + ui, cmd := testWriteCommand(t) + cmd.client = client + + code := cmd.Run([]string{ + "-force", + "transit/keys/my-key", + }) + if exp := 0; code != exp { + t.Fatalf("expected %d to be %d: %q", code, exp, ui.ErrorWriter.String()) + } + + secret, err := client.Logical().Read("transit/keys/my-key") + if err != nil { + t.Fatal(err) + } + if secret == nil || secret.Data == nil { + t.Fatal("expected secret to have data") + } + }) + t.Run("stdin_full", func(t *testing.T) { t.Parallel()