Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions plugins/pass/commands/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,17 @@ func Test_SetCommand(t *testing.T) {
_, err := execute(t, mustSetCommand(t), mock, "foo=bar", "--metadata", "invalid")
assert.ErrorContains(t, err, "invalid metadata pair (expected key=value): invalid")
})
t.Run("rejects an empty inline value", func(t *testing.T) {
mock := teststore.NewMockStore(teststore.WithStoreSaveErr(errors.New("save should not be called for an empty value")))
out, err := execute(t, mustSetCommand(t), mock, "foo=")
assert.ErrorIs(t, err, store.ErrEmptySecret)
assert.Equal(t, "Error: "+store.ErrEmptySecret.Error()+"\n", out)
})
t.Run("rejects empty STDIN", func(t *testing.T) {
mock := teststore.NewMockStore(teststore.WithStoreSaveErr(errors.New("save should not be called for an empty value")))
_, err := executeWithStdin(t, mustSetCommand(t), mock, "", "foo")
assert.ErrorIs(t, err, store.ErrEmptySecret)
})
t.Run("store error", func(t *testing.T) {
errSave := errors.New("save error")
mock := teststore.NewMockStore(teststore.WithStoreSaveErr(errSave))
Expand Down Expand Up @@ -170,6 +181,16 @@ func Test_SetCommand(t *testing.T) {
assert.ErrorContains(t, err, "invalid metadata pair (expected key=value): invalid")
assert.NotErrorIs(t, err, client.ErrSecretsEngineNotRunning)
})
t.Run("--force rejects an empty value before asking the engine", func(t *testing.T) {
mock := teststore.NewMockStore(teststore.WithStore(map[store.ID]store.Secret{
store.MustParseID("foo"): pass.NewPassValue([]byte("old")),
}))
cmd := mustSetCommand(t, WithTimeout(time.Second), WithSocketPath(deadSocket(t)))
_, err := execute(t, cmd, mock, "foo=", "--force")
assert.ErrorIs(t, err, store.ErrEmptySecret)
assert.NotErrorIs(t, err, client.ErrSecretsEngineNotRunning)
assertStoredValue(t, mock, "old")
})
t.Run("--force surfaces upsert error", func(t *testing.T) {
errUpsert := errors.New("upsert error")
mock := teststore.NewMockStore(teststore.WithStoreUpsertErr(errUpsert))
Expand Down
34 changes: 23 additions & 11 deletions plugins/pass/commands/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,17 +71,7 @@ func SetCommand(options ...ClientOption) (*cobra.Command, error) {
return err
}

var s *setPayload
switch in, isFile := prompt.UnwrapFile(cmd.InOrStdin()); {
case isNotImplicitReadFromStdinSyntax(args):
s = &setPayload{val: value}
case isFile && term.IsTerminal(in.Fd()):
var val string
val, err = prompt.ReadMasked(cmd.Context(), in, cmd.ErrOrStderr(), id)
s = &setPayload{val: val}
default:
s, err = secretMappingFromSTDIN(cmd.Context(), cmd.InOrStdin())
}
s, err := readSecret(cmd, args, value, id)
if err != nil {
return err
}
Expand Down Expand Up @@ -131,6 +121,28 @@ func parseMetadataFlags(raw []string) (map[string]string, error) {
return m, nil
}

func readSecret(cmd *cobra.Command, args []string, value string, id secrets.ID) (*setPayload, error) {
var s *setPayload
var err error
switch in, isFile := prompt.UnwrapFile(cmd.InOrStdin()); {
case isNotImplicitReadFromStdinSyntax(args):
s = &setPayload{val: value}
case isFile && term.IsTerminal(in.Fd()):
var val string
val, err = prompt.ReadMasked(cmd.Context(), in, cmd.ErrOrStderr(), id)
s = &setPayload{val: val}
default:
s, err = secretMappingFromSTDIN(cmd.Context(), cmd.InOrStdin())
}
if err != nil {
return nil, err
}
if s.val == "" {
return nil, secrets.ErrEmptySecret
}
return s, nil
}

func isNotImplicitReadFromStdinSyntax(args []string) bool {
return strings.Contains(args[0], "=") || len(args) > 1
}
Expand Down
Loading