Skip to content
Open
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
7 changes: 5 additions & 2 deletions age/keysource.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ import (
"filippo.io/age/agessh"
"filippo.io/age/armor"
"filippo.io/age/plugin"
"github.com/kballard/go-shellquote"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"

"github.com/getsops/sops/v3/logging"
"github.com/google/shlex"
)

const (
Expand Down Expand Up @@ -300,10 +300,13 @@ func (key *MasterKey) TypeToIdentifier() string {
func getOutputFromCmd(cmdString string, envVars []string) ([]byte, error) {
var out []byte

args, err := shlex.Split(cmdString)
args, err := shellquote.Split(cmdString)
if err != nil {
return nil, fmt.Errorf("failed to parse command %s: %w", cmdString, err)
}
if len(args) == 0 {
return nil, errors.New("failed to parse command: command is empty")
}
cmd := exec.Command(args[0], args[1:]...)
if envVars != nil {
cmd.Env = append(os.Environ(), envVars[0:]...)
Expand Down
44 changes: 44 additions & 0 deletions age/keysource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,50 @@ func TestMasterKey_loadIdentities(t *testing.T) {
assert.Nil(t, got)
assert.Len(t, unusedLocations, 7)
})

t.Run("empty cmd", func(t *testing.T) {
tmpDir := t.TempDir()
// Overwrite to ensure local config is not picked up by tests
overwriteUserConfigDir(t, tmpDir)

t.Setenv(SopsAgeKeyCmdEnv, "")

key := &MasterKey{}
got, unusedLocations, errs := key.loadIdentities()
assert.Len(t, errs, 1)
assert.Error(t, errs[0])
assert.ErrorContains(t, errs[0], "command is empty")
assert.Nil(t, got)
assert.Len(t, unusedLocations, 7)
})
}

func TestGetOutputFromCmd(t *testing.T) {
t.Run("backslashes in double quotes", func(t *testing.T) {
out, err := getOutputFromCmd(`printf %s "C:\Users\sops\keys.txt"`, nil)
assert.NoError(t, err)
assert.Equal(t, `C:\Users\sops\keys.txt`, string(out))
})

t.Run("env vars", func(t *testing.T) {
out, err := getOutputFromCmd(`sh -c 'printf %s "$FOO"'`, []string{"FOO=bar baz"})
assert.NoError(t, err)
assert.Equal(t, "bar baz", string(out))
})

t.Run("unterminated quote", func(t *testing.T) {
out, err := getOutputFromCmd(`printf %s 'foo`, nil)
assert.ErrorContains(t, err, "failed to parse command")
assert.Nil(t, out)
})

for _, cmdString := range []string{"", " "} {
t.Run(fmt.Sprintf("empty %q", cmdString), func(t *testing.T) {
out, err := getOutputFromCmd(cmdString, nil)
assert.ErrorContains(t, err, "command is empty")
assert.Nil(t, out)
})
}
}

// overwriteUserConfigDir sets the user config directory and the user home directory
Expand Down
4 changes: 2 additions & 2 deletions cmd/sops/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
"github.com/getsops/sops/v3/cmd/sops/common"
"github.com/getsops/sops/v3/keyservice"
"github.com/getsops/sops/v3/version"
"github.com/google/shlex"
"github.com/kballard/go-shellquote"
exec "golang.org/x/sys/execabs"
)

Expand Down Expand Up @@ -327,7 +327,7 @@ func runEditor(path string) error {
}
cmd = exec.Command(editor, path)
} else {
parts, err := shlex.Split(editor)
parts, err := shellquote.Split(editor)
if err != nil {
return fmt.Errorf("invalid $%s: %s", envVar, editor)
}
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ require (
github.com/getsops/gopgagent v0.0.0-20241224165529-7044f28e491e
github.com/go-viper/mapstructure/v2 v2.5.0
github.com/google/go-cmp v0.7.0
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/goware/prefixer v0.0.0-20160118172347-395022866408
github.com/hashicorp/go-cleanhttp v0.5.2
github.com/hashicorp/vault/api v1.23.0
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.213
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/lib/pq v1.12.3
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/go-wordwrap v1.0.1
Expand Down Expand Up @@ -103,6 +103,7 @@ require (
github.com/goccy/go-yaml v1.19.2 // indirect
github.com/golang-jwt/jwt/v5 v5.3.1 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.20 // indirect
github.com/googleapis/gax-go/v2 v2.24.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.213 h1:uKt4C7kPCCDk47+VLTPLUY/
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.213/go.mod h1:M+yna96Fx9o5GbIUnF3OvVvQGjgfVSyeJbV9Yb1z/wI=
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 h1:9Nu54bhS/H/Kgo2/7xNSUuC5G28VR8ljfrLKU2G4IjU=
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12/go.mod h1:TBzl5BIHNXfS9+C35ZyJaklL7mLDbgUkcgXzSLa8Tk0=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
Expand Down