Skip to content

Commit

Permalink
stores: test for duplicate keys, reseve keyword (yaml only now)
Browse files Browse the repository at this point in the history
Signed-off-by: Martin Holst Swende <martin@swende.se>
  • Loading branch information
holiman committed Sep 21, 2023
1 parent b7da2fc commit 4bad36e
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 1 deletion.
4 changes: 3 additions & 1 deletion stores/json/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,9 @@ func (store Store) jsonFromTreeBranch(branch sops.TreeBranch) ([]byte, error) {

func (store Store) treeBranchFromJSON(in []byte) (sops.TreeBranch, error) {
dec := json.NewDecoder(bytes.NewReader(in))
dec.Token()
if _, err := dec.Token(); err != nil {
return nil, err
}
return store.treeBranchFromJSONDecoder(dec)
}

Expand Down
23 changes: 23 additions & 0 deletions stores/json/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,3 +394,26 @@ func TestEmitValueString(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, []byte("\"hello\""), bytes)
}

func TestConflictingAttributes(t *testing.T) {
// See https://stackoverflow.com/a/23195243
// Duplicate keys in json is technically valid, but discouraged.
// Implementations may handle them differently. ECMA-262 says
//
// > In the case where there are duplicate name Strings within an object,
// > lexically preceding values for the same key shall be overwritten.

data := `
{
"hello": "Sops config file",
"hello": "Doubles are ok",
"hello": ["repeatedly"],
"hello": 3.14
}
`
s := new(Store)
_, err := s.LoadPlainFile([]byte(data))
if err != nil {
t.Errorf("did not expect error, got %v", err)
}
}
13 changes: 13 additions & 0 deletions stores/yaml/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,13 @@ func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
// sops.Tree runtime object
func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
var branches sops.TreeBranches
{
// This is needed to make the yaml-decoder check for uniqueness of keys
// Can probably be removed when https://github.com/go-yaml/yaml/issues/814 is merged.
if err := yaml.NewDecoder(bytes.NewReader(in)).Decode(make(map[string]interface{})); err != nil {
return nil, err
}
}
d := yaml.NewDecoder(bytes.NewReader(in))
for {
var data yaml.Node
Expand All @@ -309,6 +316,12 @@ func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
if err != nil {
return nil, fmt.Errorf("Error unmarshaling input YAML: %s", err)
}
// Prevent use of reserved keywords
for _, item := range branch {
if item.Key == "sops" {
return nil, fmt.Errorf("YAML doc used reserved word '%v'", item.Key)
}
}
branches = append(branches, branch)
}
return branches, nil
Expand Down
39 changes: 39 additions & 0 deletions stores/yaml/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,3 +281,42 @@ func TestComment7(t *testing.T) {
assert.Equal(t, string(COMMENT_7_OUT), string(bytes))
assert.Equal(t, COMMENT_7_OUT, bytes)
}
func TestDuplicateAttributes(t *testing.T) {
// Duplicate keys are _not_ valid yaml.
//
// See https://yaml.org/spec/1.2.2/
// > The content of a mapping node is an unordered set of key/value node pairs,
// > with the restriction that each of the keys is unique.
//
data := `
hello: Sops config file
hello: Duplicates are not ok
rootunique:
key2: "value"
key2: "foo"
`
s := new(Store)
_, err := s.LoadPlainFile([]byte(data))
if err == nil {
t.Errorf("Expected error")
}
if have, want := err.Error(), `yaml: unmarshal errors:
line 3: mapping key "hello" already defined at line 2`; have != want {
t.Errorf("have '%v', want '%v'", have, want)
}
}

func TestReservedAttributes(t *testing.T) {
data := `
hello: Sops config file
sops: The attribute 'sops' must be rejected, otherwise the file cannot be opened later on
`
s := new(Store)
_, err := s.LoadPlainFile([]byte(data))
if err == nil {
t.Errorf("Expected error")
}
if have, want := err.Error(), `YAML doc used reserved word 'sops'`; have != want {
t.Errorf("have '%v', want '%v'", have, want)
}
}

0 comments on commit 4bad36e

Please sign in to comment.