Permalink
Cannot retrieve contributors at this time
730 lines (699 sloc)
13.9 KB
package sops | |
import ( | |
"bytes" | |
"fmt" | |
"reflect" | |
"testing" | |
"github.com/stretchr/testify/assert" | |
) | |
type reverseCipher struct{} | |
// reverse returns its argument string reversed rune-wise left to right. | |
func reverse(s string) string { | |
r := []rune(s) | |
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { | |
r[i], r[j] = r[j], r[i] | |
} | |
return string(r) | |
} | |
func (c reverseCipher) Encrypt(value interface{}, key []byte, path string) (string, error) { | |
b, err := ToBytes(value) | |
if err != nil { | |
return "", err | |
} | |
return reverse(string(b)), nil | |
} | |
func (c reverseCipher) Decrypt(value string, key []byte, path string) (plaintext interface{}, err error) { | |
if value == "error" { | |
return nil, fmt.Errorf("Error") | |
} | |
return reverse(value), nil | |
} | |
func TestUnencryptedSuffix(t *testing.T) { | |
branches := TreeBranches{ | |
TreeBranch{ | |
TreeItem{ | |
Key: "foo_unencrypted", | |
Value: "bar", | |
}, | |
TreeItem{ | |
Key: "bar_unencrypted", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: "bar", | |
}, | |
}, | |
}, | |
}, | |
} | |
tree := Tree{Branches: branches, Metadata: Metadata{UnencryptedSuffix: "_unencrypted"}} | |
expected := TreeBranch{ | |
TreeItem{ | |
Key: "foo_unencrypted", | |
Value: "bar", | |
}, | |
TreeItem{ | |
Key: "bar_unencrypted", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: "bar", | |
}, | |
}, | |
}, | |
} | |
cipher := reverseCipher{} | |
_, err := tree.Encrypt(bytes.Repeat([]byte("f"), 32), cipher) | |
if err != nil { | |
t.Errorf("Encrypting the tree failed: %s", err) | |
} | |
if !reflect.DeepEqual(tree.Branches[0], expected) { | |
t.Errorf("Trees don't match: \ngot \t\t%+v,\n expected \t\t%+v", tree.Branches[0], expected) | |
} | |
_, err = tree.Decrypt(bytes.Repeat([]byte("f"), 32), cipher) | |
if err != nil { | |
t.Errorf("Decrypting the tree failed: %s", err) | |
} | |
if !reflect.DeepEqual(tree.Branches[0], expected) { | |
t.Errorf("Trees don't match: \ngot\t\t\t%+v,\nexpected\t\t%+v", tree.Branches[0], expected) | |
} | |
} | |
func TestEncryptedSuffix(t *testing.T) { | |
branches := TreeBranches{ | |
TreeBranch{ | |
TreeItem{ | |
Key: "foo_encrypted", | |
Value: "bar", | |
}, | |
TreeItem{ | |
Key: "bar", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: "bar", | |
}, | |
}, | |
}, | |
}, | |
} | |
tree := Tree{Branches: branches, Metadata: Metadata{EncryptedSuffix: "_encrypted"}} | |
expected := TreeBranch{ | |
TreeItem{ | |
Key: "foo_encrypted", | |
Value: "rab", | |
}, | |
TreeItem{ | |
Key: "bar", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: "bar", | |
}, | |
}, | |
}, | |
} | |
cipher := reverseCipher{} | |
_, err := tree.Encrypt(bytes.Repeat([]byte("f"), 32), cipher) | |
if err != nil { | |
t.Errorf("Encrypting the tree failed: %s", err) | |
} | |
if !reflect.DeepEqual(tree.Branches[0], expected) { | |
t.Errorf("Trees don't match: \ngot \t\t%+v,\n expected \t\t%+v", tree.Branches[0], expected) | |
} | |
_, err = tree.Decrypt(bytes.Repeat([]byte("f"), 32), cipher) | |
if err != nil { | |
t.Errorf("Decrypting the tree failed: %s", err) | |
} | |
expected[0].Value = "bar" | |
if !reflect.DeepEqual(tree.Branches[0], expected) { | |
t.Errorf("Trees don't match: \ngot\t\t\t%+v,\nexpected\t\t%+v", tree.Branches[0], expected) | |
} | |
} | |
func TestEncryptedRegex(t *testing.T) { | |
branches := TreeBranches{ | |
TreeBranch{ | |
TreeItem{ | |
Key: "enc:foo", | |
Value: "bar", | |
}, | |
TreeItem{ | |
Key: "bar", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: "bar", | |
}, | |
}, | |
}, | |
}, | |
} | |
tree := Tree{Branches: branches, Metadata: Metadata{EncryptedRegex: "^enc:"}} | |
expected := TreeBranch{ | |
TreeItem{ | |
Key: "enc:foo", | |
Value: "rab", | |
}, | |
TreeItem{ | |
Key: "bar", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: "bar", | |
}, | |
}, | |
}, | |
} | |
cipher := reverseCipher{} | |
_, err := tree.Encrypt(bytes.Repeat([]byte("f"), 32), cipher) | |
if err != nil { | |
t.Errorf("Encrypting the tree failed: %s", err) | |
} | |
if !reflect.DeepEqual(tree.Branches[0], expected) { | |
t.Errorf("Trees don't match: \ngot \t\t%+v,\n expected \t\t%+v", tree.Branches[0], expected) | |
} | |
_, err = tree.Decrypt(bytes.Repeat([]byte("f"), 32), cipher) | |
if err != nil { | |
t.Errorf("Decrypting the tree failed: %s", err) | |
} | |
expected[0].Value = "bar" | |
if !reflect.DeepEqual(tree.Branches[0], expected) { | |
t.Errorf("Trees don't match: \ngot\t\t\t%+v,\nexpected\t\t%+v", tree.Branches[0], expected) | |
} | |
} | |
func TestUnencryptedRegex(t *testing.T) { | |
branches := TreeBranches{ | |
TreeBranch{ | |
TreeItem{ | |
Key: "dec:foo", | |
Value: "bar", | |
}, | |
TreeItem{ | |
Key: "dec:bar", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: "bar", | |
}, | |
}, | |
}, | |
}, | |
} | |
tree := Tree{Branches: branches, Metadata: Metadata{UnencryptedRegex: "^dec:"}} | |
expected := TreeBranch{ | |
TreeItem{ | |
Key: "dec:foo", | |
Value: "bar", | |
}, | |
TreeItem{ | |
Key: "dec:bar", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: "bar", | |
}, | |
}, | |
}, | |
} | |
cipher := reverseCipher{} | |
_, err := tree.Encrypt(bytes.Repeat([]byte("f"), 32), cipher) | |
if err != nil { | |
t.Errorf("Encrypting the tree failed: %s", err) | |
} | |
// expected[1].Value[] = "bar" | |
if !reflect.DeepEqual(tree.Branches[0], expected) { | |
t.Errorf("Trees don't match: \ngot \t\t%+v,\n expected \t\t%+v", tree.Branches[0], expected) | |
} | |
_, err = tree.Decrypt(bytes.Repeat([]byte("f"), 32), cipher) | |
if err != nil { | |
t.Errorf("Decrypting the tree failed: %s", err) | |
} | |
if !reflect.DeepEqual(tree.Branches[0], expected) { | |
t.Errorf("Trees don't match: \ngot\t\t\t%+v,\nexpected\t\t%+v", tree.Branches[0], expected) | |
} | |
} | |
type MockCipher struct{} | |
func (m MockCipher) Encrypt(value interface{}, key []byte, path string) (string, error) { | |
return "a", nil | |
} | |
func (m MockCipher) Decrypt(value string, key []byte, path string) (interface{}, error) { | |
return "a", nil | |
} | |
func TestEncrypt(t *testing.T) { | |
branches := TreeBranches{ | |
TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: "bar", | |
}, | |
TreeItem{ | |
Key: "baz", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "bar", | |
Value: 5, | |
}, | |
}, | |
}, | |
TreeItem{ | |
Key: "bar", | |
Value: false, | |
}, | |
TreeItem{ | |
Key: "foobar", | |
Value: 2.12, | |
}, | |
TreeItem{ | |
Key: "barfoo", | |
Value: nil, | |
}, | |
}, | |
TreeBranch{ | |
TreeItem{ | |
Key: "foo2", | |
Value: "bar", | |
}, | |
}, | |
TreeBranch{ | |
TreeItem{ | |
Key: "foo3", | |
Value: "bar", | |
}, | |
}, | |
} | |
expected := TreeBranches{ | |
TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: "a", | |
}, | |
TreeItem{ | |
Key: "baz", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "bar", | |
Value: "a", | |
}, | |
}, | |
}, | |
TreeItem{ | |
Key: "bar", | |
Value: "a", | |
}, | |
TreeItem{ | |
Key: "foobar", | |
Value: "a", | |
}, | |
TreeItem{ | |
Key: "barfoo", | |
Value: nil, | |
}, | |
}, | |
TreeBranch{ | |
TreeItem{ | |
Key: "foo2", | |
Value: "a", | |
}, | |
}, | |
TreeBranch{ | |
TreeItem{ | |
Key: "foo3", | |
Value: "a", | |
}, | |
}, | |
} | |
tree := Tree{Branches: branches, Metadata: Metadata{UnencryptedSuffix: DefaultUnencryptedSuffix}} | |
tree.Encrypt(bytes.Repeat([]byte{'f'}, 32), MockCipher{}) | |
if !reflect.DeepEqual(tree.Branches, expected) { | |
t.Errorf("%s does not equal expected tree: %s", tree.Branches, expected) | |
} | |
} | |
func TestDecrypt(t *testing.T) { | |
branches := TreeBranches{ | |
TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: "bar", | |
}, | |
TreeItem{ | |
Key: "baz", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "bar", | |
Value: "5", | |
}, | |
}, | |
}, | |
TreeItem{ | |
Key: "bar", | |
Value: "false", | |
}, | |
TreeItem{ | |
Key: "foobar", | |
Value: "2.12", | |
}, | |
TreeItem{ | |
Key: "barfoo", | |
Value: nil, | |
}, | |
}, | |
TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: "bar", | |
}, | |
TreeItem{ | |
Key: "baz", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "bar", | |
Value: "6", | |
}, | |
}, | |
}, | |
}, | |
TreeBranch{ | |
TreeItem{ | |
Key: "foo3", | |
Value: "bar", | |
}, | |
}, | |
} | |
expected := TreeBranches{ | |
TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: "a", | |
}, | |
TreeItem{ | |
Key: "baz", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "bar", | |
Value: "a", | |
}, | |
}, | |
}, | |
TreeItem{ | |
Key: "bar", | |
Value: "a", | |
}, | |
TreeItem{ | |
Key: "foobar", | |
Value: "a", | |
}, | |
TreeItem{ | |
Key: "barfoo", | |
Value: nil, | |
}, | |
}, | |
TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: "a", | |
}, | |
TreeItem{ | |
Key: "baz", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "bar", | |
Value: "a", | |
}, | |
}, | |
}, | |
}, | |
TreeBranch{ | |
TreeItem{ | |
Key: "foo3", | |
Value: "a", | |
}, | |
}, | |
} | |
tree := Tree{Branches: branches, Metadata: Metadata{UnencryptedSuffix: DefaultUnencryptedSuffix}} | |
tree.Decrypt(bytes.Repeat([]byte{'f'}, 32), MockCipher{}) | |
if !reflect.DeepEqual(tree.Branches, expected) { | |
t.Errorf("%s does not equal expected tree: %s", tree.Branches[0], expected) | |
} | |
} | |
func TestTruncateTree(t *testing.T) { | |
tree := TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: 2, | |
}, | |
TreeItem{ | |
Key: "bar", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "foobar", | |
Value: []int{ | |
1, | |
2, | |
3, | |
4, | |
}, | |
}, | |
}, | |
}, | |
} | |
expected := 3 | |
result, err := tree.Truncate([]interface{}{ | |
"bar", | |
"foobar", | |
2, | |
}) | |
assert.Equal(t, nil, err) | |
assert.Equal(t, expected, result) | |
} | |
func TestEncryptComments(t *testing.T) { | |
tree := Tree{ | |
Branches: TreeBranches{ | |
TreeBranch{ | |
TreeItem{ | |
Key: Comment{"foo"}, | |
Value: nil, | |
}, | |
TreeItem{ | |
Key: "list", | |
Value: []interface{}{ | |
"1", | |
Comment{"bar"}, | |
"2", | |
}, | |
}, | |
}, | |
}, | |
Metadata: Metadata{ | |
UnencryptedSuffix: DefaultUnencryptedSuffix, | |
}, | |
} | |
tree.Encrypt(bytes.Repeat([]byte{'f'}, 32), reverseCipher{}) | |
assert.Equal(t, "oof", tree.Branches[0][0].Key.(Comment).Value) | |
assert.Equal(t, "rab", tree.Branches[0][1].Value.([]interface{})[1]) | |
} | |
func TestDecryptComments(t *testing.T) { | |
tree := Tree{ | |
Branches: TreeBranches{ | |
TreeBranch{ | |
TreeItem{ | |
Key: Comment{"oof"}, | |
Value: nil, | |
}, | |
TreeItem{ | |
Key: "list", | |
Value: []interface{}{ | |
"1", | |
Comment{"rab"}, | |
"2", | |
}, | |
}, | |
TreeItem{ | |
Key: "list", | |
Value: nil, | |
}, | |
}, | |
}, | |
Metadata: Metadata{ | |
UnencryptedSuffix: DefaultUnencryptedSuffix, | |
}, | |
} | |
tree.Decrypt(bytes.Repeat([]byte{'f'}, 32), reverseCipher{}) | |
assert.Equal(t, "foo", tree.Branches[0][0].Key.(Comment).Value) | |
assert.Equal(t, "bar", tree.Branches[0][1].Value.([]interface{})[1]) | |
} | |
func TestDecryptUnencryptedComments(t *testing.T) { | |
tree := Tree{ | |
Branches: TreeBranches{ | |
TreeBranch{ | |
TreeItem{ | |
// We use `error` to simulate an error decrypting, the fake cipher will error in this case | |
Key: Comment{"error"}, | |
Value: nil, | |
}, | |
}, | |
}, | |
Metadata: Metadata{}, | |
} | |
tree.Decrypt(bytes.Repeat([]byte{'f'}, 32), reverseCipher{}) | |
assert.Equal(t, "error", tree.Branches[0][0].Key.(Comment).Value) | |
} | |
func TestSetNewKey(t *testing.T) { | |
branch := TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "bar", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "baz", | |
Value: "foobar", | |
}, | |
}, | |
}, | |
}, | |
}, | |
} | |
set := branch.Set([]interface{}{"foo", "bar", "foo"}, "hello") | |
assert.Equal(t, "hello", set[0].Value.(TreeBranch)[0].Value.(TreeBranch)[1].Value) | |
} | |
func TestSetArrayDeepNew(t *testing.T) { | |
branch := TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: []interface{}{ | |
"one", | |
"two", | |
}, | |
}, | |
} | |
set := branch.Set([]interface{}{"foo", 2, "bar"}, "hello") | |
assert.Equal(t, "hello", set[0].Value.([]interface{})[2].(TreeBranch)[0].Value) | |
} | |
func TestSetNewKeyDeep(t *testing.T) { | |
branch := TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: "bar", | |
}, | |
} | |
set := branch.Set([]interface{}{"foo", "bar", "baz"}, "hello") | |
assert.Equal(t, "hello", set[0].Value.(TreeBranch)[0].Value.(TreeBranch)[0].Value) | |
} | |
func TestSetNewKeyOnEmptyBranch(t *testing.T) { | |
branch := TreeBranch{} | |
set := branch.Set([]interface{}{"foo", "bar", "baz"}, "hello") | |
assert.Equal(t, "hello", set[0].Value.(TreeBranch)[0].Value.(TreeBranch)[0].Value) | |
} | |
func TestSetArray(t *testing.T) { | |
branch := TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: []interface{}{ | |
"one", | |
"two", | |
"three", | |
}, | |
}, | |
} | |
set := branch.Set([]interface{}{"foo", 0}, "uno") | |
assert.Equal(t, "uno", set[0].Value.([]interface{})[0]) | |
} | |
func TestSetArrayNew(t *testing.T) { | |
branch := TreeBranch{} | |
set := branch.Set([]interface{}{"foo", 0, 0}, "uno") | |
assert.Equal(t, "uno", set[0].Value.([]interface{})[0].([]interface{})[0]) | |
} | |
func TestSetExisting(t *testing.T) { | |
branch := TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: "foobar", | |
}, | |
} | |
set := branch.Set([]interface{}{"foo"}, "bar") | |
assert.Equal(t, "bar", set[0].Value) | |
} | |
func TestSetArrayLeafNewItem(t *testing.T) { | |
branch := TreeBranch{ | |
TreeItem{ | |
Key: "array", | |
Value: []interface{}{}, | |
}, | |
} | |
set := branch.Set([]interface{}{"array", 2}, "hello") | |
assert.Equal(t, TreeBranch{ | |
TreeItem{ | |
Key: "array", | |
Value: []interface{}{ | |
"hello", | |
}, | |
}, | |
}, set) | |
} | |
func TestSetArrayNonLeaf(t *testing.T) { | |
branch := TreeBranch{ | |
TreeItem{ | |
Key: "array", | |
Value: []interface{}{ | |
1, | |
}, | |
}, | |
} | |
set := branch.Set([]interface{}{"array", 0, "hello"}, "hello") | |
assert.Equal(t, TreeBranch{ | |
TreeItem{ | |
Key: "array", | |
Value: []interface{}{ | |
TreeBranch{ | |
TreeItem{ | |
Key: "hello", | |
Value: "hello", | |
}, | |
}, | |
}, | |
}, | |
}, set) | |
} | |
func TestEmitAsMap(t *testing.T) { | |
expected := map[string]interface{}{ | |
"foobar": "barfoo", | |
"number": 42, | |
"foo": map[string]interface{}{ | |
"bar": map[string]interface{}{ | |
"baz": "foobar", | |
}, | |
}, | |
} | |
branches := TreeBranches{ | |
TreeBranch{ | |
TreeItem{ | |
Key: "foobar", | |
Value: "barfoo", | |
}, | |
TreeItem{ | |
Key: "number", | |
Value: 42, | |
}, | |
}, | |
TreeBranch{ | |
TreeItem{ | |
Key: "foo", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "bar", | |
Value: TreeBranch{ | |
TreeItem{ | |
Key: "baz", | |
Value: "foobar", | |
}, | |
}, | |
}, | |
}, | |
}, | |
}, | |
} | |
data, err := EmitAsMap(branches) | |
if assert.NoError(t, err) { | |
assert.Equal(t, expected, data) | |
} | |
} |