2016-09-01 14:16:41 -07:00
|
|
|
package json
|
|
|
|
|
|
|
|
|
|
import (
|
2017-10-03 14:35:28 -07:00
|
|
|
"testing"
|
|
|
|
|
|
2023-07-11 21:09:23 +02:00
|
|
|
"github.com/getsops/sops/v3"
|
2023-09-14 08:41:23 +02:00
|
|
|
"github.com/getsops/sops/v3/config"
|
2023-09-16 15:03:46 +02:00
|
|
|
"github.com/stretchr/testify/assert"
|
2016-09-01 14:16:41 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func TestDecodeJSON(t *testing.T) {
|
|
|
|
|
in := `
|
|
|
|
|
{
|
|
|
|
|
"glossary":{
|
|
|
|
|
"title":"example glossary",
|
|
|
|
|
"GlossDiv":{
|
|
|
|
|
"title":"S",
|
|
|
|
|
"GlossList":{
|
|
|
|
|
"GlossEntry":{
|
|
|
|
|
"ID":"SGML",
|
|
|
|
|
"SortAs":"SGML",
|
|
|
|
|
"GlossTerm":"Standard Generalized Markup Language",
|
|
|
|
|
"Acronym":"SGML",
|
|
|
|
|
"Abbrev":"ISO 8879:1986",
|
|
|
|
|
"GlossDef":{
|
|
|
|
|
"para":"A meta-markup language, used to create markup languages such as DocBook.",
|
|
|
|
|
"GlossSeeAlso":[
|
|
|
|
|
"GML",
|
|
|
|
|
"XML"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
"GlossSee":"markup"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-03-31 17:18:05 +02:00
|
|
|
}
|
|
|
|
|
`
|
2016-09-01 14:16:41 -07:00
|
|
|
expected := sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "glossary",
|
|
|
|
|
Value: sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "title",
|
|
|
|
|
Value: "example glossary",
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "GlossDiv",
|
|
|
|
|
Value: sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "title",
|
|
|
|
|
Value: "S",
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "GlossList",
|
|
|
|
|
Value: sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "GlossEntry",
|
|
|
|
|
Value: sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "ID",
|
|
|
|
|
Value: "SGML",
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "SortAs",
|
|
|
|
|
Value: "SGML",
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "GlossTerm",
|
|
|
|
|
Value: "Standard Generalized Markup Language",
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "Acronym",
|
|
|
|
|
Value: "SGML",
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "Abbrev",
|
|
|
|
|
Value: "ISO 8879:1986",
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "GlossDef",
|
|
|
|
|
Value: sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "para",
|
|
|
|
|
Value: "A meta-markup language, used to create markup languages such as DocBook.",
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "GlossSeeAlso",
|
|
|
|
|
Value: []interface{}{
|
|
|
|
|
"GML",
|
|
|
|
|
"XML",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "GlossSee",
|
|
|
|
|
Value: "markup",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
branch, err := Store{}.treeBranchFromJSON([]byte(in))
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.Equal(t, expected, branch)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDecodeSimpleJSONObject(t *testing.T) {
|
|
|
|
|
in := `{"foo": "bar", "baz": 2}`
|
|
|
|
|
expected := sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: "bar",
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "baz",
|
|
|
|
|
Value: 2.0,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
branch, err := Store{}.treeBranchFromJSON([]byte(in))
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.Equal(t, expected, branch)
|
|
|
|
|
}
|
|
|
|
|
|
Don't consider io.EOF returned by Decoder.Token as error
[`Decoder.Token`](https://golang.org/pkg/encoding/json/#Decoder.Token)
returns nil, io.EOF at the input stream.
This caused the output json to have no "data" key for an input
containing a number:
```
{
"sops": {
"kms": null,
"gcp_kms": null,
"lastmodified": "2018-01-14T14:51:51Z",
"mac": "ENC[AES256_GCM,data:miI91EH0VGqTY9DuJweV61++dq1LmdBwbU/tkaznCeVo2H7z0vws0FdDJiKUiyCwd+PYkpklinVyGWzxDjgR1yWch+9uU4zFkwSiNwLTdQRitYE9Kwxd37E7+AFmJtZIfIdUZsx/gFP4YZ4Pn2cgVK6n9sNRyaGhR4PyCp7TXT4=,iv:XnyghTNLba1edrVYk8sum38pe736T3L5yGJMmBocDyE=,tag:b3z730u8+hPiNxmg8REFHg==,type:str]",
"pgp": [
{
"created_at": "2018-01-14T14:51:51Z",
"enc": "-----BEGIN PGP MESSAGE-----\n\nwcFMA90gOM45xlRNARAAj8AtDWZakRBpMmqRH3z6F+hIkyt2xpP911MAHpU1e4ma\nNZfUcKJybg2XFbAj40uDSEE1o1+hebU18nzYVwVUiDKBGN5f3rSgAIgtcK8u9JT2\nhRPndP7wkFK1t1+n3ne40ZotdqYefCLjHUalmS8Ka5wYDXGD9fOR3zBoaJ1VFWYu\nZyOltpqK76AFZ8dJkBBXcZCKfmZ2h2C9/tfSq5Hjibzddd/zit09zXsyHE6McFJU\n3YPGmGQ/kE+/1vkELIF3suGy7yB3Um0cRCEVnHoZJkE+lRZtxKKJ91oKLOfwJkoT\nOAHmeRJxDE45eae/wbWS4KHUFJ2IvfnUuaNCVrnYyzRP05wFxAuZI7XcV3ckVfaM\nBW2GkAUESfY9zYkTm/lOpUhAjEpqzjG+lSCt9VdHMMqOl8N4z6U5qzznm1ZL4Wf9\nbEV0zRc5XECmM6yjx7KHA8ivjdgxpKY9HgBI5ZkfjgoORfOaZaiVdteRmEOQM3yS\nWN+QTt4dkcfsqdpmYyHbCatgV9rsZdcIHS1kZ4EK7HMKzwR9+caRFA+o3NOm0hyx\nbNnMldVFr771KFoneau13A5HdZGdZRO7qMfpVZjdDQ8dFR1xtAimeoSGqIv5rcT3\n8UzrnNuSkHlPZHNgBloV5DoFLtWzd9VZCOl1KyLQLsSqQgbi1mbZlAQWfdWbwqHS\n4AHk3ef1I8MjQxVJFD4jSgC80OHzIeBK4C/heu/gfuKjuYWI4MLlPiuN6e+yoFT+\nR75GX1GgqTWP52gwxstEibTQ7n9zl6/gUeQ1/T+QOFDfajpawb8+xxyx4kjOzPnh\nU4MA\n=VSfw\n-----END PGP MESSAGE-----",
"fp": "C8F69F5F7059C32B3328DFE48BE9D15D0B0D06EB"
}
],
"unencrypted_suffix": "_unencrypted",
"version": "3.0.0"
}
}
```
After the change:
```
{
"data": "ENC[AES256_GCM,data:PVw=,iv:cCDbWu1jdYkCIUcF/BtZGBs6mSWtdTI5ZF/A/i7RxIY=,tag:sFtal0nSo2koPDxnaKxLgA==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
"lastmodified": "2018-01-14T14:52:38Z",
"mac": "ENC[AES256_GCM,data:BOyvRlaMKIGRcNOnmBGnN/Qz7i/l6Lhl5lx1OJ1VMb6nhuKkhCySktGVYOElUTgLc3CDKLfELNKiID2i6HKAkSAWQyYC1tIPAQTcBtnVd2Pt7Adzz8i8JFzWT+sc5rKLCOljnXwcXsxbmhrWwfQFj57wVWkvZTRNLfNZkcMnykw=,iv:JxCILR1qxAk391tTmLf/hXlr1L/JQWqhLbFHYR04HjI=,tag:0LSWWPWEBeK1Gm2mi4UBNA==,type:str]",
"pgp": [
{
"created_at": "2018-01-14T14:52:38Z",
"enc": "-----BEGIN PGP MESSAGE-----\n\nwcFMA90gOM45xlRNARAAR+FmJBwY4gnpUUZSwWRrwJ+PLhBzVXoIfZ2zqhk+gkvl\nGZyi62mCM5ZVoVPf8Pw+a9cQi+IzJHgKEOT/6PIp1chw7DhnoGbFJExcE3inniou\nlLo2pFTRH5jTvCE3yIIR/l1b9VMrtnOcZuYx9SobLjIv4wKtY1gMkbmrG2IDLmMT\n9QYM/MT/aCcUA/u6bYz8+ZjAS7NUEifji/SkZkYlL1tdCEdiHU/Cl4gScOhqcIsK\nGWGa+1jnxnYOmYq3FDMb90RSPgU8xkzl9EQIInF2t4K3Zj7E+9J93Y7N2udpNGah\nebPwxS4VTCLl1p69q9+nhO8rn9ySjeTjIoJwPoNDzWVowQEmUPZCTz+A28RKi02l\nGsuYxCzD5aF8cRhZbLk882fCAo77U9TiYYa00cq8kTqnCpZmtp3BevrdWTswJwin\n/TID0DOflahzj7iUP8MAVI2nzGosmCWEFiVONWq2l2z7ND78Y65G/d5hM3zv71U/\n1z0B8zzxZSbFFTV2YjADwWdizpeXJFJuVdynCQdPxt8qfNZVXcQfIHmYwh4M3k3U\nv5yV491mwCPNAJAoBaNJoKLnXx3ae4Aic4s2sF3V+AKK6rNiWtuAWsyjuwzmTse2\ntQisNTez5m+6r5seC7YvC2i9Vb2DNzqYn4M/13tHjxpPrNxdCGNneM1FKG8a03nS\n4AHk5BBSjhL9oc/o7zf8AsoFdeE2A+BR4KnhNXbg2eJlJCnO4IvlzVv3wYVwmh5W\nfyHqIQAX3ICb43o6Vo2/AGANvM5BdA3gX+ToyYFHsSMttWLz4zAUJWe04pRx0/rh\n73EA\n=0ON2\n-----END PGP MESSAGE-----",
"fp": "C8F69F5F7059C32B3328DFE48BE9D15D0B0D06EB"
}
],
"unencrypted_suffix": "_unencrypted",
"version": "3.0.0"
}
}
```
Fixes #235
2018-01-14 20:41:37 +05:30
|
|
|
func TestDecodeNumber(t *testing.T) {
|
|
|
|
|
in := `42`
|
|
|
|
|
_, err := Store{}.treeBranchFromJSON([]byte(in))
|
|
|
|
|
assert.NotNil(t, err)
|
2023-09-28 22:15:30 +02:00
|
|
|
assert.Equal(t, "Expected JSON object start, got 42 of type float64 instead", err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDecodeArray(t *testing.T) {
|
|
|
|
|
in := ` [42] `
|
|
|
|
|
_, err := Store{}.treeBranchFromJSON([]byte(in))
|
|
|
|
|
assert.NotNil(t, err)
|
|
|
|
|
assert.Equal(t, "Expected JSON object start, got delimiter [ instead", err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDecodeEmpty(t *testing.T) {
|
|
|
|
|
in := ``
|
|
|
|
|
_, err := Store{}.treeBranchFromJSON([]byte(in))
|
|
|
|
|
assert.NotNil(t, err)
|
|
|
|
|
assert.Equal(t, "EOF", err.Error())
|
Don't consider io.EOF returned by Decoder.Token as error
[`Decoder.Token`](https://golang.org/pkg/encoding/json/#Decoder.Token)
returns nil, io.EOF at the input stream.
This caused the output json to have no "data" key for an input
containing a number:
```
{
"sops": {
"kms": null,
"gcp_kms": null,
"lastmodified": "2018-01-14T14:51:51Z",
"mac": "ENC[AES256_GCM,data:miI91EH0VGqTY9DuJweV61++dq1LmdBwbU/tkaznCeVo2H7z0vws0FdDJiKUiyCwd+PYkpklinVyGWzxDjgR1yWch+9uU4zFkwSiNwLTdQRitYE9Kwxd37E7+AFmJtZIfIdUZsx/gFP4YZ4Pn2cgVK6n9sNRyaGhR4PyCp7TXT4=,iv:XnyghTNLba1edrVYk8sum38pe736T3L5yGJMmBocDyE=,tag:b3z730u8+hPiNxmg8REFHg==,type:str]",
"pgp": [
{
"created_at": "2018-01-14T14:51:51Z",
"enc": "-----BEGIN PGP MESSAGE-----\n\nwcFMA90gOM45xlRNARAAj8AtDWZakRBpMmqRH3z6F+hIkyt2xpP911MAHpU1e4ma\nNZfUcKJybg2XFbAj40uDSEE1o1+hebU18nzYVwVUiDKBGN5f3rSgAIgtcK8u9JT2\nhRPndP7wkFK1t1+n3ne40ZotdqYefCLjHUalmS8Ka5wYDXGD9fOR3zBoaJ1VFWYu\nZyOltpqK76AFZ8dJkBBXcZCKfmZ2h2C9/tfSq5Hjibzddd/zit09zXsyHE6McFJU\n3YPGmGQ/kE+/1vkELIF3suGy7yB3Um0cRCEVnHoZJkE+lRZtxKKJ91oKLOfwJkoT\nOAHmeRJxDE45eae/wbWS4KHUFJ2IvfnUuaNCVrnYyzRP05wFxAuZI7XcV3ckVfaM\nBW2GkAUESfY9zYkTm/lOpUhAjEpqzjG+lSCt9VdHMMqOl8N4z6U5qzznm1ZL4Wf9\nbEV0zRc5XECmM6yjx7KHA8ivjdgxpKY9HgBI5ZkfjgoORfOaZaiVdteRmEOQM3yS\nWN+QTt4dkcfsqdpmYyHbCatgV9rsZdcIHS1kZ4EK7HMKzwR9+caRFA+o3NOm0hyx\nbNnMldVFr771KFoneau13A5HdZGdZRO7qMfpVZjdDQ8dFR1xtAimeoSGqIv5rcT3\n8UzrnNuSkHlPZHNgBloV5DoFLtWzd9VZCOl1KyLQLsSqQgbi1mbZlAQWfdWbwqHS\n4AHk3ef1I8MjQxVJFD4jSgC80OHzIeBK4C/heu/gfuKjuYWI4MLlPiuN6e+yoFT+\nR75GX1GgqTWP52gwxstEibTQ7n9zl6/gUeQ1/T+QOFDfajpawb8+xxyx4kjOzPnh\nU4MA\n=VSfw\n-----END PGP MESSAGE-----",
"fp": "C8F69F5F7059C32B3328DFE48BE9D15D0B0D06EB"
}
],
"unencrypted_suffix": "_unencrypted",
"version": "3.0.0"
}
}
```
After the change:
```
{
"data": "ENC[AES256_GCM,data:PVw=,iv:cCDbWu1jdYkCIUcF/BtZGBs6mSWtdTI5ZF/A/i7RxIY=,tag:sFtal0nSo2koPDxnaKxLgA==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
"lastmodified": "2018-01-14T14:52:38Z",
"mac": "ENC[AES256_GCM,data:BOyvRlaMKIGRcNOnmBGnN/Qz7i/l6Lhl5lx1OJ1VMb6nhuKkhCySktGVYOElUTgLc3CDKLfELNKiID2i6HKAkSAWQyYC1tIPAQTcBtnVd2Pt7Adzz8i8JFzWT+sc5rKLCOljnXwcXsxbmhrWwfQFj57wVWkvZTRNLfNZkcMnykw=,iv:JxCILR1qxAk391tTmLf/hXlr1L/JQWqhLbFHYR04HjI=,tag:0LSWWPWEBeK1Gm2mi4UBNA==,type:str]",
"pgp": [
{
"created_at": "2018-01-14T14:52:38Z",
"enc": "-----BEGIN PGP MESSAGE-----\n\nwcFMA90gOM45xlRNARAAR+FmJBwY4gnpUUZSwWRrwJ+PLhBzVXoIfZ2zqhk+gkvl\nGZyi62mCM5ZVoVPf8Pw+a9cQi+IzJHgKEOT/6PIp1chw7DhnoGbFJExcE3inniou\nlLo2pFTRH5jTvCE3yIIR/l1b9VMrtnOcZuYx9SobLjIv4wKtY1gMkbmrG2IDLmMT\n9QYM/MT/aCcUA/u6bYz8+ZjAS7NUEifji/SkZkYlL1tdCEdiHU/Cl4gScOhqcIsK\nGWGa+1jnxnYOmYq3FDMb90RSPgU8xkzl9EQIInF2t4K3Zj7E+9J93Y7N2udpNGah\nebPwxS4VTCLl1p69q9+nhO8rn9ySjeTjIoJwPoNDzWVowQEmUPZCTz+A28RKi02l\nGsuYxCzD5aF8cRhZbLk882fCAo77U9TiYYa00cq8kTqnCpZmtp3BevrdWTswJwin\n/TID0DOflahzj7iUP8MAVI2nzGosmCWEFiVONWq2l2z7ND78Y65G/d5hM3zv71U/\n1z0B8zzxZSbFFTV2YjADwWdizpeXJFJuVdynCQdPxt8qfNZVXcQfIHmYwh4M3k3U\nv5yV491mwCPNAJAoBaNJoKLnXx3ae4Aic4s2sF3V+AKK6rNiWtuAWsyjuwzmTse2\ntQisNTez5m+6r5seC7YvC2i9Vb2DNzqYn4M/13tHjxpPrNxdCGNneM1FKG8a03nS\n4AHk5BBSjhL9oc/o7zf8AsoFdeE2A+BR4KnhNXbg2eJlJCnO4IvlzVv3wYVwmh5W\nfyHqIQAX3ICb43o6Vo2/AGANvM5BdA3gX+ToyYFHsSMttWLz4zAUJWe04pRx0/rh\n73EA\n=0ON2\n-----END PGP MESSAGE-----",
"fp": "C8F69F5F7059C32B3328DFE48BE9D15D0B0D06EB"
}
],
"unencrypted_suffix": "_unencrypted",
"version": "3.0.0"
}
}
```
Fixes #235
2018-01-14 20:41:37 +05:30
|
|
|
}
|
|
|
|
|
|
2016-09-01 14:16:41 -07:00
|
|
|
func TestDecodeNestedJSONObject(t *testing.T) {
|
|
|
|
|
in := `{"foo": {"foo": "bar"}}`
|
|
|
|
|
expected := sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: "bar",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
branch, err := Store{}.treeBranchFromJSON([]byte(in))
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.Equal(t, expected, branch)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDecodeJSONWithArray(t *testing.T) {
|
|
|
|
|
in := `{"foo": {"foo": [1, 2, 3]}, "bar": "baz"}`
|
|
|
|
|
expected := sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: []interface{}{1.0, 2.0, 3.0},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "bar",
|
|
|
|
|
Value: "baz",
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
branch, err := Store{}.treeBranchFromJSON([]byte(in))
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.Equal(t, expected, branch)
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-08 13:21:32 -07:00
|
|
|
func TestDecodeJSONArrayOfObjects(t *testing.T) {
|
|
|
|
|
in := `{"foo": [{"bar": "foo"}, {"foo": "bar"}]}`
|
|
|
|
|
expected := sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: []interface{}{
|
|
|
|
|
sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "bar",
|
|
|
|
|
Value: "foo",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: "bar",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
branch, err := Store{}.treeBranchFromJSON([]byte(in))
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.Equal(t, expected, branch)
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-20 21:53:37 +00:00
|
|
|
func TestDecodeJSONArrayOfArrays(t *testing.T) {
|
|
|
|
|
in := `{"foo": [[["foo", {"bar": "foo"}]]]}`
|
|
|
|
|
expected := sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: []interface{}{
|
|
|
|
|
[]interface{}{
|
|
|
|
|
[]interface{}{
|
|
|
|
|
"foo",
|
|
|
|
|
sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "bar",
|
|
|
|
|
Value: "foo",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
branch, err := Store{}.treeBranchFromJSON([]byte(in))
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.Equal(t, expected, branch)
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-01 14:16:41 -07:00
|
|
|
func TestEncodeSimpleJSON(t *testing.T) {
|
|
|
|
|
branch := sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: "bar",
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: 3.0,
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "bar",
|
|
|
|
|
Value: false,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
out, err := Store{}.jsonFromTreeBranch(branch)
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
expected, _ := Store{}.treeBranchFromJSON(out)
|
|
|
|
|
assert.Equal(t, expected, branch)
|
|
|
|
|
}
|
2016-11-09 17:56:35 +01:00
|
|
|
|
2018-06-01 12:47:27 -07:00
|
|
|
func TestEncodeJSONWithEscaping(t *testing.T) {
|
|
|
|
|
branch := sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo\\bar",
|
|
|
|
|
Value: "value",
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "a_key_with\"quotes\"",
|
|
|
|
|
Value: 4.0,
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "baz\\\\foo",
|
|
|
|
|
Value: 2.0,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
out, err := Store{}.jsonFromTreeBranch(branch)
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
expected, _ := Store{}.treeBranchFromJSON(out)
|
|
|
|
|
assert.Equal(t, expected, branch)
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-09 17:56:35 +01:00
|
|
|
func TestEncodeJSONArrayOfObjects(t *testing.T) {
|
2018-09-20 11:18:34 -06:00
|
|
|
tree := sops.Tree{
|
|
|
|
|
Branches: sops.TreeBranches{
|
|
|
|
|
sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: []interface{}{
|
|
|
|
|
sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: 3,
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "bar",
|
|
|
|
|
Value: false,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
2,
|
2016-11-09 17:56:35 +01:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
expected := `{
|
|
|
|
|
"foo": [
|
|
|
|
|
{
|
|
|
|
|
"foo": 3,
|
|
|
|
|
"bar": false
|
|
|
|
|
},
|
|
|
|
|
2
|
|
|
|
|
]
|
2024-03-31 17:18:05 +02:00
|
|
|
}
|
|
|
|
|
`
|
2023-09-14 20:41:56 +02:00
|
|
|
store := Store{
|
|
|
|
|
config: config.JSONStoreConfig{
|
|
|
|
|
Indent: -1,
|
|
|
|
|
},
|
|
|
|
|
}
|
2018-09-20 11:18:34 -06:00
|
|
|
out, err := store.EmitPlainFile(tree.Branches)
|
2016-11-09 17:56:35 +01:00
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.Equal(t, expected, string(out))
|
|
|
|
|
}
|
2017-10-03 14:35:28 -07:00
|
|
|
|
|
|
|
|
func TestUnmarshalMetadataFromNonSOPSFile(t *testing.T) {
|
|
|
|
|
data := []byte(`{"hello": 2}`)
|
2018-04-20 10:13:46 +02:00
|
|
|
store := Store{}
|
|
|
|
|
_, err := store.LoadEncryptedFile(data)
|
2017-10-03 14:35:28 -07:00
|
|
|
assert.Equal(t, sops.MetadataNotFound, err)
|
|
|
|
|
}
|
2018-04-20 10:13:46 +02:00
|
|
|
|
|
|
|
|
func TestLoadJSONFormattedBinaryFile(t *testing.T) {
|
|
|
|
|
// This is JSON data, but we want SOPS to interpret it as binary,
|
|
|
|
|
// e.g. because the --input-type binary flag was provided.
|
|
|
|
|
data := []byte(`{"hello": 2}`)
|
|
|
|
|
store := BinaryStore{}
|
2018-09-20 11:18:34 -06:00
|
|
|
branches, err := store.LoadPlainFile(data)
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.Equal(t, "data", branches[0][0].Key)
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-16 15:03:46 +02:00
|
|
|
func TestEmitBinaryFile(t *testing.T) {
|
|
|
|
|
store := BinaryStore{}
|
|
|
|
|
data, err := store.EmitPlainFile(sops.TreeBranches{
|
|
|
|
|
sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "data",
|
|
|
|
|
Value: "foo",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.Equal(t, []byte("foo"), data)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestEmitBinaryFileWrongBranches(t *testing.T) {
|
|
|
|
|
store := BinaryStore{}
|
|
|
|
|
data, err := store.EmitPlainFile(sops.TreeBranches{
|
|
|
|
|
sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "data",
|
|
|
|
|
Value: "bar",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "data",
|
|
|
|
|
Value: "bar",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
assert.Nil(t, data)
|
|
|
|
|
assert.Contains(t, err.Error(), "there must be exactly one tree branch")
|
|
|
|
|
|
|
|
|
|
data, err = store.EmitPlainFile(sops.TreeBranches{})
|
|
|
|
|
assert.Nil(t, data)
|
|
|
|
|
assert.Contains(t, err.Error(), "there must be exactly one tree branch")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestEmitBinaryFileNoData(t *testing.T) {
|
|
|
|
|
store := BinaryStore{}
|
|
|
|
|
data, err := store.EmitPlainFile(sops.TreeBranches{
|
|
|
|
|
sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: "bar",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
assert.Nil(t, data)
|
|
|
|
|
assert.Contains(t, err.Error(), "no binary data found in tree")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestEmitBinaryFileWrongDataType(t *testing.T) {
|
|
|
|
|
store := BinaryStore{}
|
|
|
|
|
data, err := store.EmitPlainFile(sops.TreeBranches{
|
|
|
|
|
sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "data",
|
|
|
|
|
Value: sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: "bar",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
assert.Nil(t, data)
|
|
|
|
|
assert.Contains(t, err.Error(), "'data' key in tree does not have a string value")
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-20 11:18:34 -06:00
|
|
|
func TestEmitValueString(t *testing.T) {
|
|
|
|
|
bytes, err := (&Store{}).EmitValue("hello")
|
2018-04-20 10:13:46 +02:00
|
|
|
assert.Nil(t, err)
|
2018-09-20 11:18:34 -06:00
|
|
|
assert.Equal(t, []byte("\"hello\""), bytes)
|
2018-04-20 10:13:46 +02:00
|
|
|
}
|
2023-09-14 08:41:23 +02:00
|
|
|
|
|
|
|
|
func TestIndentTwoSpaces(t *testing.T) {
|
|
|
|
|
tree := sops.Tree{
|
|
|
|
|
Branches: sops.TreeBranches{
|
|
|
|
|
sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: []interface{}{
|
|
|
|
|
sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: 3,
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "bar",
|
|
|
|
|
Value: false,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
2,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
expected := `{
|
|
|
|
|
"foo": [
|
|
|
|
|
{
|
|
|
|
|
"foo": 3,
|
|
|
|
|
"bar": false
|
|
|
|
|
},
|
|
|
|
|
2
|
|
|
|
|
]
|
2024-03-31 17:18:05 +02:00
|
|
|
}
|
|
|
|
|
`
|
2023-09-14 08:41:23 +02:00
|
|
|
store := Store{
|
|
|
|
|
config: config.JSONStoreConfig{
|
|
|
|
|
Indent: 2,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
out, err := store.EmitPlainFile(tree.Branches)
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.Equal(t, expected, string(out))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestIndentDefault(t *testing.T) {
|
|
|
|
|
tree := sops.Tree{
|
|
|
|
|
Branches: sops.TreeBranches{
|
|
|
|
|
sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: []interface{}{
|
|
|
|
|
sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: 3,
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "bar",
|
|
|
|
|
Value: false,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
2,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
expected := `{
|
|
|
|
|
"foo": [
|
|
|
|
|
{
|
|
|
|
|
"foo": 3,
|
|
|
|
|
"bar": false
|
|
|
|
|
},
|
|
|
|
|
2
|
|
|
|
|
]
|
2024-03-31 17:18:05 +02:00
|
|
|
}
|
|
|
|
|
`
|
2023-09-14 20:41:56 +02:00
|
|
|
store := Store{
|
|
|
|
|
config: config.JSONStoreConfig{
|
|
|
|
|
Indent: -1,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
out, err := store.EmitPlainFile(tree.Branches)
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.Equal(t, expected, string(out))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestNoIndent(t *testing.T) {
|
|
|
|
|
tree := sops.Tree{
|
|
|
|
|
Branches: sops.TreeBranches{
|
|
|
|
|
sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: []interface{}{
|
|
|
|
|
sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: 3,
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "bar",
|
|
|
|
|
Value: false,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
2,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
expected := `{
|
|
|
|
|
"foo": [
|
|
|
|
|
{
|
|
|
|
|
"foo": 3,
|
|
|
|
|
"bar": false
|
|
|
|
|
},
|
|
|
|
|
2
|
|
|
|
|
]
|
2024-03-31 17:18:05 +02:00
|
|
|
}
|
|
|
|
|
`
|
2023-09-14 20:41:56 +02:00
|
|
|
store := Store{
|
|
|
|
|
config: config.JSONStoreConfig{
|
|
|
|
|
Indent: 0,
|
|
|
|
|
},
|
|
|
|
|
}
|
2023-09-14 08:41:23 +02:00
|
|
|
out, err := store.EmitPlainFile(tree.Branches)
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.Equal(t, expected, string(out))
|
2023-04-21 10:17:24 +02:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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))
|
|
|
|
|
assert.Nil(t, err)
|
2023-09-14 08:41:23 +02:00
|
|
|
}
|
2024-10-09 21:41:42 +02:00
|
|
|
|
|
|
|
|
func TestComments(t *testing.T) {
|
|
|
|
|
tree := sops.Tree{
|
|
|
|
|
Branches: sops.TreeBranches{
|
|
|
|
|
sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: []interface{}{
|
|
|
|
|
sops.Comment{Value: " comment 0"},
|
|
|
|
|
sops.TreeBranch{
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: sops.Comment{Value: " comment 1"},
|
|
|
|
|
Value: nil,
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "foo",
|
|
|
|
|
Value: 3,
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: sops.Comment{Value: " comment 2"},
|
|
|
|
|
Value: nil,
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: sops.Comment{Value: " comment 3"},
|
|
|
|
|
Value: nil,
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: "bar",
|
|
|
|
|
Value: false,
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: sops.Comment{Value: " comment 4"},
|
|
|
|
|
Value: nil,
|
|
|
|
|
},
|
|
|
|
|
sops.TreeItem{
|
|
|
|
|
Key: sops.Comment{Value: " comment 5"},
|
|
|
|
|
Value: nil,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
sops.Comment{Value: " comment 6"},
|
|
|
|
|
sops.Comment{Value: " comment 7"},
|
|
|
|
|
2,
|
|
|
|
|
sops.Comment{Value: " comment 8"},
|
|
|
|
|
sops.Comment{Value: " comment 9"},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
expected := `{
|
|
|
|
|
"foo": [
|
|
|
|
|
{
|
|
|
|
|
"foo": 3,
|
|
|
|
|
"bar": false
|
|
|
|
|
},
|
|
|
|
|
2
|
|
|
|
|
]
|
2025-02-15 14:25:29 +01:00
|
|
|
}
|
|
|
|
|
`
|
2024-10-09 21:41:42 +02:00
|
|
|
store := Store{
|
|
|
|
|
config: config.JSONStoreConfig{
|
|
|
|
|
Indent: 2,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
out, err := store.EmitPlainFile(tree.Branches)
|
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
assert.Equal(t, expected, string(out))
|
|
|
|
|
}
|