Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make check whether file contains invalid keys for encryption dependent on output store #1393

Merged
merged 1 commit into from
Dec 29, 2023
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
9 changes: 4 additions & 5 deletions cmd/sops/encrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ func (err *fileAlreadyEncryptedError) Error() string {

func (err *fileAlreadyEncryptedError) UserError() string {
message := "The file you have provided contains a top-level entry called " +
"'sops'. This is generally due to the file already being encrypted. " +
"'sops', or for flat file formats top-level entries starting with " +
"'sops_'. This is generally due to the file already being encrypted. " +
"SOPS uses a top-level entry called 'sops' to store the metadata " +
"required to decrypt the file. For this reason, SOPS can not " +
"encrypt files that already contain such an entry.\n\n" +
Expand All @@ -47,10 +48,8 @@ func (err *fileAlreadyEncryptedError) UserError() string {
}

func ensureNoMetadata(opts encryptOpts, branch sops.TreeBranch) error {
for _, b := range branch {
if b.Key == "sops" {
return &fileAlreadyEncryptedError{}
}
if opts.OutputStore.HasSopsTopLevelKey(branch) {
return &fileAlreadyEncryptedError{}
}
return nil
}
Expand Down
7 changes: 7 additions & 0 deletions sops.go
Original file line number Diff line number Diff line change
Expand Up @@ -567,13 +567,20 @@ type ValueEmitter interface {
EmitValue(interface{}) ([]byte, error)
}

// CheckEncryped is the interface for testing whether a branch contains sops
// metadata. This is used to check whether a file is already encrypted or not.
type CheckEncryped interface {
HasSopsTopLevelKey(TreeBranch) bool
}

// Store is used to interact with files, both encrypted and unencrypted.
type Store interface {
EncryptedFileLoader
PlainFileLoader
EncryptedFileEmitter
PlainFileEmitter
ValueEmitter
CheckEncryped
}

// MasterKeyCount returns the number of master keys available
Expand Down
12 changes: 12 additions & 0 deletions stores/dotenv/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,15 @@ func isComplexValue(v interface{}) bool {
}
return false
}

// HasSopsTopLevelKey checks whether a top-level "sops" key exists.
func (store *Store) HasSopsTopLevelKey(branch sops.TreeBranch) bool {
for _, b := range branch {
if key, ok := b.Key.(string); ok {
if strings.HasPrefix(key, SopsPrefix) {
return true
}
}
}
return false
}
17 changes: 17 additions & 0 deletions stores/dotenv/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,20 @@ func TestEmitEncryptedFileStability(t *testing.T) {
previous = bytes
}
}

func TestHasSopsTopLevelKey(t *testing.T) {
ok := (&Store{}).HasSopsTopLevelKey(sops.TreeBranch{
sops.TreeItem{
Key: "sops",
Value: "value",
},
})
assert.Equal(t, ok, false)
ok = (&Store{}).HasSopsTopLevelKey(sops.TreeBranch{
sops.TreeItem{
Key: "sops_",
Value: "value",
},
})
assert.Equal(t, ok, true)
}
5 changes: 5 additions & 0 deletions stores/ini/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,8 @@ func (store *Store) EmitExample() []byte {
}
return bytes
}

// HasSopsTopLevelKey checks whether a top-level "sops" key exists.
func (store *Store) HasSopsTopLevelKey(branch sops.TreeBranch) bool {
return stores.HasSopsTopLevelKey(branch)
}
10 changes: 10 additions & 0 deletions stores/json/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,3 +357,13 @@ func (store *Store) EmitExample() []byte {
}
return bytes
}

// HasSopsTopLevelKey checks whether a top-level "sops" key exists.
func (store *Store) HasSopsTopLevelKey(branch sops.TreeBranch) bool {
return stores.HasSopsTopLevelKey(branch)
}

// HasSopsTopLevelKey checks whether a top-level "sops" key exists.
func (store *BinaryStore) HasSopsTopLevelKey(branch sops.TreeBranch) bool {
return stores.HasSopsTopLevelKey(branch)
}
10 changes: 10 additions & 0 deletions stores/stores.go
Original file line number Diff line number Diff line change
Expand Up @@ -506,3 +506,13 @@ var ExampleFlatTree = sops.Tree{
},
},
}

// HasSopsTopLevelKey returns true if the given branch has a top-level key called "sops".
func HasSopsTopLevelKey(branch sops.TreeBranch) bool {
for _, b := range branch {
if b.Key == "sops" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not worth it for this PR, but thoughts on adding a constant for "sops"?

https://github.com/search?q=repo:getsops/sops+sops%22+language:Go&type=code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that would be a very good idea!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return true
}
}
return false
}
5 changes: 5 additions & 0 deletions stores/yaml/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,3 +417,8 @@ func (store *Store) EmitExample() []byte {
}
return bytes
}

// HasSopsTopLevelKey checks whether a top-level "sops" key exists.
func (store *Store) HasSopsTopLevelKey(branch sops.TreeBranch) bool {
return stores.HasSopsTopLevelKey(branch)
}
19 changes: 18 additions & 1 deletion stores/yaml/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,4 +380,21 @@ func TestIndent1(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, string(INDENT_1_OUT), string(bytes))
assert.Equal(t, INDENT_1_OUT, bytes)
}
}

func TestHasSopsTopLevelKey(t *testing.T) {
ok := (&Store{}).HasSopsTopLevelKey(sops.TreeBranch{
sops.TreeItem{
Key: "sops",
Value: "value",
},
})
assert.Equal(t, ok, true)
ok = (&Store{}).HasSopsTopLevelKey(sops.TreeBranch{
sops.TreeItem{
Key: "sops_",
Value: "value",
},
})
assert.Equal(t, ok, false)
}
Loading