Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: getsops/sops
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 66963a4a2b156f6dfa2aa11ab5e5574ef8ee668e
Choose a base ref
..
head repository: getsops/sops
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: fad3c3386bbaa0f96e95469866aad6f1ccf71b1c
Choose a head ref
4 changes: 2 additions & 2 deletions .github/workflows/cli.yml
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ jobs:
id: go

- name: Check out code into the Go module directory
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v3.6.0
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0

- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
with:
@@ -89,7 +89,7 @@ jobs:
run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y --default-toolchain 1.70.0

- name: Check out code
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v3.6.0
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0

- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2
with:
2 changes: 1 addition & 1 deletion .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0

16 changes: 14 additions & 2 deletions age/keysource.go
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ import (
"io"
"os"
"path/filepath"
"runtime"
"strings"

"filippo.io/age"
@@ -23,8 +24,10 @@ const (
// age keys file.
SopsAgeKeyFileEnv = "SOPS_AGE_KEY_FILE"
// SopsAgeKeyUserConfigPath is the default age keys file path in
// os.UserConfigDir.
// getUserConfigDir().
SopsAgeKeyUserConfigPath = "sops/age/keys.txt"
// On macOS, os.UserConfigDir() ignores XDG_CONFIG_HOME. So we handle that manually.
xdgConfigHome = "XDG_CONFIG_HOME"
)

// log is the global logger for any age MasterKey.
@@ -222,6 +225,15 @@ func (key *MasterKey) ToMap() map[string]interface{} {
return out
}

func getUserConfigDir() (string, error) {
if runtime.GOOS == "darwin" {
if userConfigDir, ok := os.LookupEnv(xdgConfigHome); ok && userConfigDir != "" {
return userConfigDir, nil
}
}
return os.UserConfigDir()
}

// loadIdentities attempts to load the age identities based on runtime
// environment configurations (e.g. SopsAgeKeyEnv, SopsAgeKeyFileEnv,
// SopsAgeKeyUserConfigPath). It will load all found references, and expects
@@ -242,7 +254,7 @@ func (key *MasterKey) loadIdentities() (ParsedIdentities, error) {
readers[SopsAgeKeyFileEnv] = f
}

userConfigDir, err := os.UserConfigDir()
userConfigDir, err := getUserConfigDir()
if err != nil && len(readers) == 0 {
return nil, fmt.Errorf("user config directory could not be determined: %w", err)
}
16 changes: 14 additions & 2 deletions age/keysource_test.go
Original file line number Diff line number Diff line change
@@ -380,11 +380,23 @@ func overwriteUserConfigDir(t *testing.T, path string) {
switch runtime.GOOS {
case "windows":
t.Setenv("AppData", path)
case "darwin", "ios": // This adds "/Library/Application Support" as a suffix to $HOME
t.Setenv("HOME", path)
case "plan9": // This adds "/lib" as a suffix to $home
t.Setenv("home", path)
default: // Unix
t.Setenv("XDG_CONFIG_HOME", path)
}
}

// Make sure that on all supported platforms but Windows, XDG_CONFIG_HOME
// can be used to specify the user's home directory. For most platforms
// this is handled by Go's os.UserConfigDir(), but for Darwin our code
// in getUserConfigDir() handles this explicitly.
func TestUserConfigDir(t *testing.T) {
if runtime.GOOS != "windows" {
const dir = "/test/home/dir"
t.Setenv("XDG_CONFIG_HOME", dir)
home, err := getUserConfigDir()
assert.Nil(t, err)
assert.Equal(t, home, dir)
}
}
1 change: 1 addition & 0 deletions cmd/sops/codes/codes.go
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ const (
ConfigFileNotFound int = 61
KeyboardInterrupt int = 85
InvalidTreePathFormat int = 91
NeedAtLeastOneDocument int = 92
NoFileSpecified int = 100
CouldNotRetrieveKey int = 128
NoEncryptionKeyFound int = 111
11 changes: 11 additions & 0 deletions cmd/sops/decrypt.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package main

import (
"errors"
"fmt"

"github.com/getsops/sops/v3"
"github.com/getsops/sops/v3/cmd/sops/codes"
"github.com/getsops/sops/v3/cmd/sops/common"
"github.com/getsops/sops/v3/keyservice"
"github.com/getsops/sops/v3/stores/json"
)

const notBinaryHint = ("This is likely not an encrypted binary file?" +
" If not, use --output-type to select the correct output type.")

type decryptOpts struct {
Cipher sops.Cipher
InputStore sops.Store
@@ -45,6 +50,9 @@ func decrypt(opts decryptOpts) (decryptedFile []byte, err error) {
return extract(tree, opts.Extract, opts.OutputStore)
}
decryptedFile, err = opts.OutputStore.EmitPlainFile(tree.Branches)
if errors.Is(err, json.BinaryStoreEmitPlainError) {
err = fmt.Errorf("%s\n\n%s", err.Error(), notBinaryHint)
}
if err != nil {
return nil, common.NewExitError(fmt.Sprintf("Error dumping file: %s", err), codes.ErrorDumpingTree)
}
@@ -59,6 +67,9 @@ func extract(tree *sops.Tree, path []interface{}, outputStore sops.Store) (outpu
if newBranch, ok := v.(sops.TreeBranch); ok {
tree.Branches[0] = newBranch
decrypted, err := outputStore.EmitPlainFile(tree.Branches)
if errors.Is(err, json.BinaryStoreEmitPlainError) {
err = fmt.Errorf("%s\n\n%s", err.Error(), notBinaryHint)
}
if err != nil {
return nil, common.NewExitError(fmt.Sprintf("Error dumping file: %s", err), codes.ErrorDumpingTree)
}
3 changes: 3 additions & 0 deletions cmd/sops/encrypt.go
Original file line number Diff line number Diff line change
@@ -64,6 +64,9 @@ func encrypt(opts encryptOpts) (encryptedFile []byte, err error) {
if err != nil {
return nil, common.NewExitError(fmt.Sprintf("Error unmarshalling file: %s", err), codes.CouldNotReadInputFile)
}
if len(branches) < 1 {
return nil, common.NewExitError("File cannot be completely empty, it must contain at least one document", codes.NeedAtLeastOneDocument)
}
if err := ensureNoMetadata(opts, branches[0]); err != nil {
return nil, common.NewExitError(err, codes.FileAlreadyEncrypted)
}
4 changes: 2 additions & 2 deletions cmd/sops/main.go
Original file line number Diff line number Diff line change
@@ -678,11 +678,11 @@ func main() {
},
cli.StringFlag{
Name: "unencrypted-regex",
Usage: "set the unencrypted key suffix. When specified, only keys matching the regex will be left unencrypted.",
Usage: "set the unencrypted key regex. When specified, only keys matching the regex will be left unencrypted.",
},
cli.StringFlag{
Name: "encrypted-regex",
Usage: "set the encrypted key suffix. When specified, only keys matching the regex will be encrypted.",
Usage: "set the encrypted key regex. When specified, only keys matching the regex will be encrypted.",
},
cli.StringFlag{
Name: "config",
5 changes: 4 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
@@ -242,12 +242,15 @@ func configFromRule(rule *creationRule, kmsEncryptionContext map[string]*string)
if rule.EncryptedSuffix != "" {
cryptRuleCount++
}
if rule.UnencryptedRegex != "" {
cryptRuleCount++
}
if rule.EncryptedRegex != "" {
cryptRuleCount++
}

if cryptRuleCount > 1 {
return nil, fmt.Errorf("error loading config: cannot use more than one of encrypted_suffix, unencrypted_suffix, or encrypted_regex for the same rule")
return nil, fmt.Errorf("error loading config: cannot use more than one of encrypted_suffix, unencrypted_suffix, encrypted_regex, or unencrypted_regex for the same rule")
}

groups, err := getKeyGroupsFromCreationRule(rule, kmsEncryptionContext)
15 changes: 11 additions & 4 deletions config/config_test.go
Original file line number Diff line number Diff line change
@@ -140,12 +140,19 @@ creation_rules:
version: fooversion
`)

var sampleConfigWithRegexParameters = []byte(`
var sampleConfigWithEncryptedRegexParameters = []byte(`
creation_rules:
- path_regex: barbar*
kms: "1"
pgp: "2"
encrypted_regex: "^enc:"
`)

var sampleConfigWithUnencryptedRegexParameters = []byte(`
creation_rules:
- path_regex: barbar*
kms: "1"
pgp: "2"
unencrypted_regex: "^dec:"
`)

@@ -226,7 +233,7 @@ creation_rules:
var sampleConfigWithComplicatedRegexp = []byte(`
creation_rules:
- path_regex: "stage/dev/feature-.*"
kms: dev-feature
kms: dev-feature
- path_regex: "stage/dev/.*"
kms: dev
- path_regex: "stage/staging/.*"
@@ -396,13 +403,13 @@ func TestLoadConfigFileWithEncryptedSuffix(t *testing.T) {
}

func TestLoadConfigFileWithUnencryptedRegex(t *testing.T) {
conf, err := parseCreationRuleForFile(parseConfigFile(sampleConfigWithRegexParameters, t), "/conf/path", "barbar", nil)
conf, err := parseCreationRuleForFile(parseConfigFile(sampleConfigWithUnencryptedRegexParameters, t), "/conf/path", "barbar", nil)
assert.Equal(t, nil, err)
assert.Equal(t, "^dec:", conf.UnencryptedRegex)
}

func TestLoadConfigFileWithEncryptedRegex(t *testing.T) {
conf, err := parseCreationRuleForFile(parseConfigFile(sampleConfigWithRegexParameters, t), "/conf/path", "barbar", nil)
conf, err := parseCreationRuleForFile(parseConfigFile(sampleConfigWithEncryptedRegexParameters, t), "/conf/path", "barbar", nil)
assert.Equal(t, nil, err)
assert.Equal(t, "^enc:", conf.EncryptedRegex)
}
28 changes: 14 additions & 14 deletions go.mod
Original file line number Diff line number Diff line change
@@ -11,12 +11,12 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371
github.com/aws/aws-sdk-go-v2 v1.21.0
github.com/aws/aws-sdk-go-v2/config v1.18.39
github.com/aws/aws-sdk-go-v2/credentials v1.13.37
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.83
github.com/aws/aws-sdk-go-v2/config v1.18.42
github.com/aws/aws-sdk-go-v2/credentials v1.13.40
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.87
github.com/aws/aws-sdk-go-v2/service/kms v1.24.5
github.com/aws/aws-sdk-go-v2/service/s3 v1.38.5
github.com/aws/aws-sdk-go-v2/service/sts v1.21.5
github.com/aws/aws-sdk-go-v2/service/s3 v1.40.0
github.com/aws/aws-sdk-go-v2/service/sts v1.22.0
github.com/blang/semver v3.5.1+incompatible
github.com/fatih/color v1.15.0
github.com/getsops/gopgagent v0.0.0-20170926210634-4d7ea76ff71a
@@ -37,9 +37,9 @@ require (
golang.org/x/net v0.15.0
golang.org/x/sys v0.12.0
golang.org/x/term v0.12.0
google.golang.org/api v0.141.0
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb
google.golang.org/grpc v1.58.1
google.golang.org/api v0.143.0
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13
google.golang.org/grpc v1.58.2
google.golang.org/protobuf v1.31.0
gopkg.in/ini.v1 v1.67.0
gopkg.in/yaml.v3 v3.0.1
@@ -60,14 +60,14 @@ require (
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.43 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.36 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.13.6 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.14.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.1 // indirect
github.com/aws/smithy-go v1.14.2 // indirect
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
@@ -85,7 +85,7 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-hclog v1.2.1 // indirect
@@ -124,8 +124,8 @@ require (
golang.org/x/tools v0.7.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 // indirect
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
Loading