Skip to content

Commit 81857bb

Browse files
authored
feat: add 'UnmarshalJSON' transform. Closes #867 (#868)
1 parent d29454f commit 81857bb

File tree

2 files changed

+335
-0
lines changed

2 files changed

+335
-0
lines changed

plugin/transform/primitives.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package transform
33

44
import (
55
"context"
6+
"encoding/json"
67
"fmt"
78
"net/url"
89
"reflect"
@@ -246,6 +247,28 @@ func UnmarshalYAML(_ context.Context, d *TransformData) (interface{}, error) {
246247
return result, nil
247248
}
248249

250+
// UnmarshalJSON parse the json-encoded data and return the result
251+
func UnmarshalJSON(_ context.Context, d *TransformData) (interface{}, error) {
252+
if d.Value == nil {
253+
return nil, nil
254+
}
255+
inputStr := types.SafeString(d.Value)
256+
var result interface{}
257+
if inputStr != "" {
258+
decoded, err := url.QueryUnescape(inputStr)
259+
if err != nil {
260+
return nil, err
261+
}
262+
263+
err = json.Unmarshal([]byte(decoded), &result)
264+
if err != nil {
265+
return nil, err
266+
}
267+
}
268+
269+
return result, nil
270+
}
271+
249272
// ToString convert the value from transform data to a string
250273
func ToString(_ context.Context, d *TransformData) (interface{}, error) {
251274
if d.Value == nil {

plugin/transform/primitives_test.go

Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,318 @@ Statement:
814814
function: NullIfEmptySliceValue,
815815
expected: testStruct{},
816816
},
817+
"UnmarshalJSON nil": {
818+
d: &TransformData{
819+
Value: nil,
820+
},
821+
function: UnmarshalJSON,
822+
expected: nil,
823+
},
824+
"UnmarshalJSON JSON array": {
825+
d: &TransformData{
826+
Value: `["foo", "bar"]`,
827+
},
828+
function: UnmarshalJSON,
829+
expected: []interface{}{"foo", "bar"},
830+
},
831+
"UnmarshalJSON JSON map": {
832+
d: &TransformData{
833+
Value: `{
834+
"Version":"2012-10-17",
835+
"Statement":["foo"]
836+
}`,
837+
},
838+
function: UnmarshalJSON,
839+
expected: map[string]interface{}{
840+
"Version": "2012-10-17",
841+
"Statement": []interface{}{
842+
"foo",
843+
},
844+
},
845+
},
846+
"UnmarshalJSON JSON iam policy normalization encoded": {
847+
d: &TransformData{
848+
Value: "%7B%0A%20%20%22Version%22%3A%20%222012-10-17%22%2C%0A%20%20%22Statement%22%3A%20%5B%7B%22Sid%22%3A%22AWSAdmin%22%2C%22Effect%22%3A%22Allow%22%2C%22Action%22%3A%5B%22aws-marketplace-management%3Av%2A%22%2C%22aws-portal%3Av%2A%22%2C%22ce%3A%2A%22%2C%22iam%3Ag%2A%22%2C%22iam%3Al%2A%22%2C%22iam%3Asi%2A%22%2C%22iam%3At%2A%22%2C%22iam%3Aun%2A%22%2C%22pricing%3A%2A%22%2C%22s3%3Aa%2A%22%2C%22s3%3Ac%2A%22%2C%22s3%3Adeletea%2A%22%2C%22s3%3Adeleteb%2A%22%2C%22s3%3Adeleteo%2A%22%2C%22s3%3Ag%2A%22%2C%22s3%3Ah%2A%22%2C%22s3%3Al%2A%22%2C%22s3%3Aputa%2A%22%2C%22s3%3Aputbucketn%2A%22%2C%22s3%3Aputbucketp%2A%22%2C%22s3%3Aputbuckett%2A%22%2C%22s3%3Aputbucketv%2A%22%2C%22s3%3Aputbucketw%2A%22%2C%22s3%3Apute%2A%22%2C%22s3%3Aputi%2A%22%2C%22s3%3Aputl%2A%22%2C%22s3%3Aputm%2A%22%2C%22s3%3Aputobject%22%2C%22s3%3Aputobjectt%2A%22%2C%22s3%3Aputobjectversiont%2A%22%2C%22s3%3Ar%2A%22%2C%22sts%3A%2A%22%2C%22support%3A%2A%22%5D%2C%22Resource%22%3A%22%2A%22%7D%5D%0A%7D%0A",
849+
},
850+
function: UnmarshalJSON,
851+
expected: map[string]interface{}{
852+
"Version": "2012-10-17",
853+
"Statement": []interface{}{
854+
map[string]interface{}{
855+
"Sid": "AWSAdmin",
856+
"Effect": "Allow",
857+
"Action": []interface{}{
858+
"aws-marketplace-management:v*",
859+
"aws-portal:v*",
860+
"ce:*",
861+
"iam:g*",
862+
"iam:l*",
863+
"iam:si*",
864+
"iam:t*",
865+
"iam:un*",
866+
"pricing:*",
867+
"s3:a*",
868+
"s3:c*",
869+
"s3:deletea*",
870+
"s3:deleteb*",
871+
"s3:deleteo*",
872+
"s3:g*",
873+
"s3:h*",
874+
"s3:l*",
875+
"s3:puta*",
876+
"s3:putbucketn*",
877+
"s3:putbucketp*",
878+
"s3:putbuckett*",
879+
"s3:putbucketv*",
880+
"s3:putbucketw*",
881+
"s3:pute*",
882+
"s3:puti*",
883+
"s3:putl*",
884+
"s3:putm*",
885+
"s3:putobject",
886+
"s3:putobjectt*",
887+
"s3:putobjectversiont*",
888+
"s3:r*",
889+
"sts:*",
890+
"support:*",
891+
},
892+
"Resource": "*",
893+
},
894+
},
895+
},
896+
},
897+
"UnmarshalJSON JSON iam policy normalization decoded": {
898+
d: &TransformData{
899+
Value: `{
900+
"Version":"2012-10-17",
901+
"Statement":[
902+
{
903+
"Sid":"AWSAdmin",
904+
"Effect":"Allow",
905+
"Action":[
906+
"aws-marketplace-management:v*",
907+
"aws-portal:v*",
908+
"ce:*",
909+
"iam:g*",
910+
"iam:l*",
911+
"iam:si*",
912+
"iam:t*",
913+
"iam:un*",
914+
"pricing:*",
915+
"s3:a*",
916+
"s3:c*",
917+
"s3:deletea*",
918+
"s3:deleteb*",
919+
"s3:deleteo*",
920+
"s3:g*",
921+
"s3:h*",
922+
"s3:l*",
923+
"s3:puta*",
924+
"s3:putbucketn*",
925+
"s3:putbucketp*",
926+
"s3:putbuckett*",
927+
"s3:putbucketv*",
928+
"s3:putbucketw*",
929+
"s3:pute*",
930+
"s3:puti*",
931+
"s3:putl*",
932+
"s3:putm*",
933+
"s3:putobject",
934+
"s3:putobjectt*",
935+
"s3:putobjectversiont*",
936+
"s3:r*",
937+
"sts:*",
938+
"support:*"
939+
],
940+
"Resource":"*"
941+
}
942+
]
943+
}`,
944+
},
945+
function: UnmarshalJSON,
946+
expected: map[string]interface{}{
947+
"Version": "2012-10-17",
948+
"Statement": []interface{}{
949+
map[string]interface{}{
950+
"Sid": "AWSAdmin",
951+
"Effect": "Allow",
952+
"Action": []interface{}{
953+
"aws-marketplace-management:v*",
954+
"aws-portal:v*",
955+
"ce:*",
956+
"iam:g*",
957+
"iam:l*",
958+
"iam:si*",
959+
"iam:t*",
960+
"iam:un*",
961+
"pricing:*",
962+
"s3:a*",
963+
"s3:c*",
964+
"s3:deletea*",
965+
"s3:deleteb*",
966+
"s3:deleteo*",
967+
"s3:g*",
968+
"s3:h*",
969+
"s3:l*",
970+
"s3:puta*",
971+
"s3:putbucketn*",
972+
"s3:putbucketp*",
973+
"s3:putbuckett*",
974+
"s3:putbucketv*",
975+
"s3:putbucketw*",
976+
"s3:pute*",
977+
"s3:puti*",
978+
"s3:putl*",
979+
"s3:putm*",
980+
"s3:putobject",
981+
"s3:putobjectt*",
982+
"s3:putobjectversiont*",
983+
"s3:r*",
984+
"sts:*",
985+
"support:*",
986+
},
987+
"Resource": "*",
988+
},
989+
},
990+
},
991+
},
992+
"UnmarshalJSON JSON policy array encoded": {
993+
d: &TransformData{
994+
Value: "%5B%22aws-marketplace-management%3Av%2A%22%2C%22aws-portal%3Av%2A%22%2C%22ce%3A%2A%22%2C%22iam%3Ag%2A%22%2C%22iam%3Al%2A%22%2C%22iam%3Asi%2A%22%2C%22iam%3At%2A%22%2C%22iam%3Aun%2A%22%2C%22pricing%3A%2A%22%2C%22s3%3Aa%2A%22%2C%22s3%3Ac%2A%22%2C%22s3%3Adeletea%2A%22%2C%22s3%3Adeleteb%2A%22%2C%22s3%3Adeleteo%2A%22%2C%22s3%3Ag%2A%22%2C%22s3%3Ah%2A%22%2C%22s3%3Al%2A%22%2C%22s3%3Aputa%2A%22%2C%22s3%3Aputbucketn%2A%22%2C%22s3%3Aputbucketp%2A%22%2C%22s3%3Aputbuckett%2A%22%2C%22s3%3Aputbucketv%2A%22%2C%22s3%3Aputbucketw%2A%22%2C%22s3%3Apute%2A%22%2C%22s3%3Aputi%2A%22%2C%22s3%3Aputl%2A%22%2C%22s3%3Aputm%2A%22%2C%22s3%3Aputobject%22%2C%22s3%3Aputobjectt%2A%22%2C%22s3%3Aputobjectversiont%2A%22%2C%22s3%3Ar%2A%22%2C%22sts%3A%2A%22%2C%22support%3A%2A%22%5D",
995+
},
996+
function: UnmarshalJSON,
997+
expected: []interface{}{
998+
"aws-marketplace-management:v*",
999+
"aws-portal:v*",
1000+
"ce:*",
1001+
"iam:g*",
1002+
"iam:l*",
1003+
"iam:si*",
1004+
"iam:t*",
1005+
"iam:un*",
1006+
"pricing:*",
1007+
"s3:a*",
1008+
"s3:c*",
1009+
"s3:deletea*",
1010+
"s3:deleteb*",
1011+
"s3:deleteo*",
1012+
"s3:g*",
1013+
"s3:h*",
1014+
"s3:l*",
1015+
"s3:puta*",
1016+
"s3:putbucketn*",
1017+
"s3:putbucketp*",
1018+
"s3:putbuckett*",
1019+
"s3:putbucketv*",
1020+
"s3:putbucketw*",
1021+
"s3:pute*",
1022+
"s3:puti*",
1023+
"s3:putl*",
1024+
"s3:putm*",
1025+
"s3:putobject",
1026+
"s3:putobjectt*",
1027+
"s3:putobjectversiont*",
1028+
"s3:r*",
1029+
"sts:*",
1030+
"support:*",
1031+
},
1032+
},
1033+
"UnmarshalJSON JSON policy array decoded": {
1034+
d: &TransformData{
1035+
Value: `["aws-marketplace-management:v*","aws-portal:v*","ce:*","iam:g*","iam:l*","iam:si*","iam:t*","iam:un*","pricing:*","s3:a*","s3:c*","s3:deletea*","s3:deleteb*","s3:deleteo*","s3:g*","s3:h*","s3:l*","s3:puta*","s3:putbucketn*","s3:putbucketp*","s3:putbuckett*","s3:putbucketv*","s3:putbucketw*","s3:pute*","s3:puti*","s3:putl*","s3:putm*","s3:putobject","s3:putobjectt*","s3:putobjectversiont*","s3:r*","sts:*","support:*"]`,
1036+
},
1037+
function: UnmarshalJSON,
1038+
expected: []interface{}{
1039+
"aws-marketplace-management:v*",
1040+
"aws-portal:v*",
1041+
"ce:*",
1042+
"iam:g*",
1043+
"iam:l*",
1044+
"iam:si*",
1045+
"iam:t*",
1046+
"iam:un*",
1047+
"pricing:*",
1048+
"s3:a*",
1049+
"s3:c*",
1050+
"s3:deletea*",
1051+
"s3:deleteb*",
1052+
"s3:deleteo*",
1053+
"s3:g*",
1054+
"s3:h*",
1055+
"s3:l*",
1056+
"s3:puta*",
1057+
"s3:putbucketn*",
1058+
"s3:putbucketp*",
1059+
"s3:putbuckett*",
1060+
"s3:putbucketv*",
1061+
"s3:putbucketw*",
1062+
"s3:pute*",
1063+
"s3:puti*",
1064+
"s3:putl*",
1065+
"s3:putm*",
1066+
"s3:putobject",
1067+
"s3:putobjectt*",
1068+
"s3:putobjectversiont*",
1069+
"s3:r*",
1070+
"sts:*",
1071+
"support:*",
1072+
},
1073+
},
1074+
"UnmarshalJSON invalid JSON": {
1075+
d: &TransformData{
1076+
Value: `{"invalid": json}`,
1077+
},
1078+
function: UnmarshalJSON,
1079+
expected: "ERROR",
1080+
},
1081+
"UnmarshalJSON empty string": {
1082+
d: &TransformData{
1083+
Value: "",
1084+
},
1085+
function: UnmarshalJSON,
1086+
expected: nil,
1087+
},
1088+
"UnmarshalJSON simple object": {
1089+
d: &TransformData{
1090+
Value: `{"name": "test", "value": 123, "active": true}`,
1091+
},
1092+
function: UnmarshalJSON,
1093+
expected: map[string]interface{}{
1094+
"name": "test",
1095+
"value": float64(123),
1096+
"active": true,
1097+
},
1098+
},
1099+
"UnmarshalJSON nested object": {
1100+
d: &TransformData{
1101+
Value: `{"user": {"id": 1, "profile": {"name": "John", "age": 30}}}`,
1102+
},
1103+
function: UnmarshalJSON,
1104+
expected: map[string]interface{}{
1105+
"user": map[string]interface{}{
1106+
"id": float64(1),
1107+
"profile": map[string]interface{}{
1108+
"name": "John",
1109+
"age": float64(30),
1110+
},
1111+
},
1112+
},
1113+
},
1114+
"UnmarshalJSON mixed array": {
1115+
d: &TransformData{
1116+
Value: `[1, "string", true, null, {"key": "value"}]`,
1117+
},
1118+
function: UnmarshalJSON,
1119+
expected: []interface{}{
1120+
float64(1),
1121+
"string",
1122+
true,
1123+
nil,
1124+
map[string]interface{}{
1125+
"key": "value",
1126+
},
1127+
},
1128+
},
8171129
}
8181130

8191131
func TestTransformFunctions(t *testing.T) {

0 commit comments

Comments
 (0)