From b247a645fd9f8493caa71b8da08d1efbd03fbcbc Mon Sep 17 00:00:00 2001 From: Torin Sandall Date: Wed, 19 Aug 2020 15:29:51 -0400 Subject: [PATCH] topdown: Remove duplicate tests Signed-off-by: Torin Sandall --- topdown/aggregates_test.go | 93 - topdown/array_test.go | 37 - topdown/bits_test.go | 148 - topdown/casts_test.go | 85 - topdown/cidr_test.go | 180 -- topdown/crypto_test.go | 264 -- topdown/glob_test.go | 60 - topdown/json_test.go | 369 --- topdown/numbers_test.go | 51 - topdown/object_test.go | 543 ---- topdown/parse_test.go | 28 - topdown/reachable_test.go | 101 - topdown/regex_test.go | 84 - topdown/semver_test.go | 67 - topdown/sets_test.go | 51 - topdown/strings_test.go | 112 - .../jwtbuiltins/test-jwtbuiltins-0400.yaml | 9 + topdown/tokens_test.go | 1526 ---------- topdown/topdown_test.go | 2522 ----------------- 19 files changed, 9 insertions(+), 6321 deletions(-) delete mode 100644 topdown/aggregates_test.go delete mode 100644 topdown/array_test.go delete mode 100644 topdown/bits_test.go delete mode 100644 topdown/casts_test.go delete mode 100644 topdown/crypto_test.go delete mode 100644 topdown/glob_test.go delete mode 100644 topdown/numbers_test.go delete mode 100644 topdown/object_test.go delete mode 100644 topdown/parse_test.go delete mode 100644 topdown/reachable_test.go delete mode 100644 topdown/regex_test.go delete mode 100644 topdown/semver_test.go delete mode 100644 topdown/sets_test.go delete mode 100644 topdown/strings_test.go diff --git a/topdown/aggregates_test.go b/topdown/aggregates_test.go deleted file mode 100644 index d15a8b8388..0000000000 --- a/topdown/aggregates_test.go +++ /dev/null @@ -1,93 +0,0 @@ -package topdown - -import ( - "testing" -) - -func TestTopDownAggregates(t *testing.T) { - - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"count", []string{`p[x] { count(a, x) }`}, "[4]"}, - {"count virtual", []string{`p[x] { count([y | q[y]], x) }`, `q[x] { x = a[_] }`}, "[4]"}, - {"count keys", []string{`p[x] { count(b, x) }`}, "[2]"}, - {"count keys virtual", []string{`p[x] { count([k | q[k] = _], x) }`, `q[k] = v { b[k] = v }`}, "[2]"}, - {"count set", []string{`p = x { count(q, x) }`, `q[x] { x = a[_] }`}, "4"}, - {"sum", []string{`p[x] { sum([1, 2, 3, 4], x) }`}, "[10]"}, - {"sum set", []string{`p = x { sum({1, 2, 3, 4}, x) }`}, "10"}, - {"sum virtual", []string{`p[x] { sum([y | q[y]], x) }`, `q[x] { a[_] = x }`}, "[10]"}, - {"sum virtual set", []string{`p = x { sum(q, x) }`, `q[x] { a[_] = x }`}, "10"}, - {"bug 2469 - precision", []string{"p = true { sum([49649733057, 1]) == 49649733058 }"}, "true"}, - {"product", []string{"p { product([1,2,3,4], 24) }"}, "true"}, - {"product set", []string{`p = x { product({1, 2, 3, 4}, x) }`}, "24"}, - {"max", []string{`p[x] { max([1, 2, 3, 4], x) }`}, "[4]"}, - {"max set", []string{`p = x { max({1, 2, 3, 4}, x) }`}, "4"}, - {"max virtual", []string{`p[x] { max([y | q[y]], x) }`, `q[x] { a[_] = x }`}, "[4]"}, - {"max virtual set", []string{`p = x { max(q, x) }`, `q[x] { a[_] = x }`}, "4"}, - {"min", []string{`p[x] { min([1, 2, 3, 4], x) }`}, "[1]"}, - {"min dups", []string{`p[x] { min([1, 2, 1, 3, 4], x) }`}, "[1]"}, - {"min out-of-order", []string{`p[x] { min([3, 2, 1, 4, 6, -7, 10], x) }`}, "[-7]"}, - {"min set", []string{`p = x { min({1, 2, 3, 4}, x) }`}, "1"}, - {"min virtual", []string{`p[x] { min([y | q[y]], x) }`, `q[x] { a[_] = x }`}, "[1]"}, - {"min virtual set", []string{`p = x { min(q, x) }`, `q[x] { a[_] = x }`}, "1"}, - {"reduce ref dest", []string{`p = true { max([1, 2, 3, 4], a[3]) }`}, "true"}, - {"reduce ref dest (2)", []string{`p = true { not max([1, 2, 3, 4, 5], a[3]) }`}, "true"}, - {"sort", []string{`p = x { sort([4, 3, 2, 1], x) }`}, "[1 ,2, 3, 4]"}, - {"sort set", []string{`p = x { sort({4,3,2,1}, x) }`}, "[1,2,3,4]"}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestAll(t *testing.T) { - - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"empty set", []string{`p = x { x := all(set()) }`}, "true"}, - {"empty array", []string{`p = x { x := all([]) }`}, "true"}, - {"set success", []string{`p = x { x := all({true, true, true}) }`}, "true"}, - {"array success", []string{`p = x { x := all( [true, true, true] ) }`}, "true"}, - {"set fail", []string{`p = x { x := all( {true, false, true} ) }`}, "false"}, - {"array fail", []string{`p = x { x := all( [false, true, true] ) }`}, "false"}, - {"other types", []string{`p = x { x := all( [{}, "", true, true, 123] ) }`}, "false"}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestAny(t *testing.T) { - - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"empty set", []string{`p = x { x := any(set()) }`}, "false"}, - {"empty array", []string{`p = x { x := any([]) }`}, "false"}, - {"set success", []string{`p = x { x := any({false, false, true}) }`}, "true"}, - {"array success", []string{`p = x { x := any( [true, true, true, false, false] ) }`}, "true"}, - {"set fail", []string{`p = x { x := any( {false, false, false} ) }`}, "false"}, - {"array fail", []string{`p = x { x := any( [false] ) }`}, "false"}, - {"other types", []string{`p = x { x := any( [true, {}, "false"] ) }`}, "true"}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} diff --git a/topdown/array_test.go b/topdown/array_test.go deleted file mode 100644 index 870641f7c8..0000000000 --- a/topdown/array_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2018 The OPA Authors. All rights reserved. -// Use of this source code is governed by an Apache2 -// license that can be found in the LICENSE file. - -package topdown - -import ( - "testing" -) - -func TestTopDownArray(t *testing.T) { - - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"concat", []string{`p = x { x = array.concat([1,2], [3,4]) }`}, "[1,2,3,4]"}, - {"concat: err", []string{`p = x { x = array.concat(data.b, [3,4]) }`}, &Error{Code: TypeErr, Message: "array.concat: operand 1 must be array but got object"}}, - {"concat: err rhs", []string{`p = x { x = array.concat([1,2], data.b) }`}, &Error{Code: TypeErr, Message: "array.concat: operand 2 must be array but got object"}}, - - {"slice", []string{`p = x { x = array.slice([1,2,3,4,5], 1, 3) }`}, "[2,3]"}, - {"slice: empty slice", []string{`p = x { x = array.slice([1,2,3], 0, 0) }`}, "[]"}, - {"slice: negative indices", []string{`p = x { x = array.slice([1,2,3,4,5], -4, -1) }`}, "[]"}, - {"slice: stopIndex < startIndex", []string{`p = x { x = array.slice([1,2,3,4,5], 4, 1) }`}, "[]"}, - {"slice: clamp startIndex", []string{`p = x { x = array.slice([1,2,3,4,5], -1, 2) }`}, `[1,2]`}, - {"slice: clamp stopIndex", []string{`p = x {x = array.slice([1,2,3,4,5], 3, 6) }`}, `[4,5]`}, - {"slice: clamp both out of range", []string{"p = x { x = array.slice([], 1000, 2000) }"}, `[]`}, - {"slice: clamp both out of range non-empty", []string{"p = x { x = array.slice([1,2,3], 1000, 2000) }"}, `[]`}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} diff --git a/topdown/bits_test.go b/topdown/bits_test.go deleted file mode 100644 index 3953cc9bcf..0000000000 --- a/topdown/bits_test.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2020 The OPA Authors. All rights reserved. -// Use of this source code is governed by an Apache2 -// license that can be found in the LICENSE file. - -package topdown - -import ( - "fmt" - "math" - "testing" - - "github.com/open-policy-agent/opa/ast" -) - -func TestBuiltinBitsOr(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"basic bitwise-or", []string{`p[x] { x := bits.or(7, 9) }`}, `[15]`}, - {"or with zero is value", []string{`p[x] { x := bits.or(50, 0) }`}, `[50]`}, - {"lhs (float) error", []string{`p = x { x := bits.or(7.2, 42) }`}, &Error{Code: TypeErr, Message: "bits.or: operand 1 must be integer number but got floating-point number"}}, - { - "rhs (wrong type-type) error", - []string{`p = x { x := bits.or(7, "hi") }`}, - ast.Errors{ast.NewError(ast.TypeErr, nil, "bits.or: invalid argument(s)")}, - }, - } - - for _, tc := range tests { - runTopDownTestCase(t, map[string]interface{}{}, tc.note, tc.rules, tc.expected) - } -} - -func TestBuiltinBitsAnd(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"basic bitwise-and", []string{`p[x] { x := bits.and(7, 9) }`}, `[1]`}, - {"and with zero is and", []string{`p[x] { x := bits.and(50, 0) }`}, `[0]`}, - {"lhs (float) error", []string{`p = x { x := bits.and(7.2, 42) }`}, &Error{Code: TypeErr, Message: "bits.and: operand 1 must be integer number but got floating-point number"}}, - { - "rhs (wrong type-type) error", - []string{`p = x { x := bits.and(7, "hi") }`}, - ast.Errors{ast.NewError(ast.TypeErr, nil, "bits.and: invalid argument(s)")}, - }, - } - - for _, tc := range tests { - runTopDownTestCase(t, map[string]interface{}{}, tc.note, tc.rules, tc.expected) - } -} - -func TestBuiltinBitsNegate(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"basic bitwise-negate", []string{`p[x] { x := bits.negate(42) }`}, `[-43]`}, - {"float error", []string{`p = x { x := bits.negate(7.2) }`}, &Error{Code: TypeErr, Message: "bits.negate: operand 1 must be integer number but got floating-point number"}}, - { - "type error", - []string{`p = x { x := bits.negate("hi") }`}, - ast.Errors{ast.NewError(ast.TypeErr, nil, "bits.negate: invalid argument(s)")}, - }, - } - - for _, tc := range tests { - runTopDownTestCase(t, map[string]interface{}{}, tc.note, tc.rules, tc.expected) - } -} - -func TestBuiltinBitsXOr(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"basic bitwise-xor", []string{`p[x] { x := bits.xor(42, 3) }`}, `[41]`}, - {"xor same is 0", []string{`p[x] { x := bits.xor(42, 42) }`}, `[0]`}, - {"lhs (float) error", []string{`p = x { x := bits.xor(7.2, 42) }`}, &Error{Code: TypeErr, Message: "bits.xor: operand 1 must be integer number but got floating-point number"}}, - { - "rhs (wrong type-type) error", - []string{`p = x { x := bits.xor(7, "hi") }`}, - ast.Errors{ast.NewError(ast.TypeErr, nil, "bits.xor: invalid argument(s)")}, - }, - } - - for _, tc := range tests { - runTopDownTestCase(t, map[string]interface{}{}, tc.note, tc.rules, tc.expected) - } -} - -func TestBuiltinBitsShiftLeft(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"basic shift-left", []string{`p[x] { x := bits.lsh(1, 3) }`}, `[8]`}, - {"lhs (float) error", []string{`p = x { x := bits.lsh(7.2, 42) }`}, &Error{Code: TypeErr, Message: "bits.lsh: operand 1 must be integer number but got floating-point number"}}, - { - "rhs (wrong type-type) error", - []string{`p = x { x := bits.lsh(7, "hi") }`}, - ast.Errors{ast.NewError(ast.TypeErr, nil, "bits.lsh: invalid argument(s)")}, - }, - {"rhs must be unsigned", []string{`p = x { x := bits.lsh(7, -1) }`}, &Error{Code: TypeErr, Message: "bits.lsh: operand 2 must be an unsigned integer number but got a negative integer"}}, - { - "shift of max int32 doesn't overflow", - []string{fmt.Sprintf(`p = x { x := bits.lsh(%d, 1) }`, math.MaxInt32)}, - `4294967294`, - }, - { - "shift of max int64 doesn't overflow and is not lossy", - []string{fmt.Sprintf(`p = x { x := bits.lsh(%d, 1) }`, math.MaxInt64)}, - `18446744073709551614`, - }, - } - - for _, tc := range tests { - runTopDownTestCase(t, map[string]interface{}{}, tc.note, tc.rules, tc.expected) - } -} - -func TestBuiltinBitsShiftRight(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"basic shift-right", []string{`p[x] { x := bits.rsh(8, 3) }`}, `[1]`}, - {"lhs (float) error", []string{`p = x { x := bits.rsh(7.2, 42) }`}, &Error{Code: TypeErr, Message: "bits.rsh: operand 1 must be integer number but got floating-point number"}}, - { - "rhs (wrong type-type) error", - []string{`p = x { x := bits.rsh(7, "hi") }`}, - ast.Errors{ast.NewError(ast.TypeErr, nil, "bits.rsh: invalid argument(s)")}, - }, - {"rhs must be unsigned", []string{`p = x { x := bits.rsh(7, -1) }`}, &Error{Code: TypeErr, Message: "bits.rsh: operand 2 must be an unsigned integer number but got a negative integer"}}, - } - - for _, tc := range tests { - runTopDownTestCase(t, map[string]interface{}{}, tc.note, tc.rules, tc.expected) - } -} diff --git a/topdown/casts_test.go b/topdown/casts_test.go deleted file mode 100644 index d70eec0f7b..0000000000 --- a/topdown/casts_test.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2018 The OPA Authors. All rights reserved. -// Use of this source code is governed by an Apache2 -// license that can be found in the LICENSE file. - -package topdown - -import ( - "testing" - - "github.com/open-policy-agent/opa/ast" -) - -func TestToArray(t *testing.T) { - - // expected result - expectedResult := []interface{}{1, 2, 3} - resultObj, err := ast.InterfaceToValue(expectedResult) - if err != nil { - panic(err) - } - - typeErr := &Error{Code: TypeErr, Message: "operand 1 must be one of {array, set}"} - - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"array input", []string{`p = x { cast_array([1,2,3], x) }`}, resultObj.String()}, - {"set input", []string{`p = x { cast_array({1,2,3}, x) }`}, resultObj.String()}, - {"bad type", []string{`p = x { cast_array("hello", x) }`}, typeErr}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestToSet(t *testing.T) { - - typeErr := &Error{Code: TypeErr, Message: "operand 1 must be one of {array, set}"} - - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"array input", []string{`p = x { cast_set([1,1,1], x) }`}, "[1]"}, - {"set input", []string{`p = x { cast_set({1,1,2,3}, x) }`}, "[1,2,3]"}, - {"bad type", []string{`p = x { cast_set("hello", x) }`}, typeErr}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestCasts(t *testing.T) { - typeErr := &Error{Code: TypeErr} - - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"null valid", []string{`p = x { cast_null(null, x) }`}, "null"}, - {"null invalid", []string{`p = x { cast_null({}, x) }`}, typeErr}, - //{"string valid", []string{`p = x { cast_string("potato", x) }`}, "potato"}, - {"string invalid", []string{`p = x { cast_string({1,1,2,3}, x) }`}, typeErr}, - {"boolean valid", []string{`p = x { cast_boolean(false, x) }`}, "false"}, - {"boolean valid", []string{`p = x { cast_boolean(1, x) }`}, typeErr}, - {"obj valid", []string{`p = x { cast_object({}, x) }`}, "{}"}, - {"obj invalid", []string{`p = x { cast_object([1,2,3], x) }`}, typeErr}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} diff --git a/topdown/cidr_test.go b/topdown/cidr_test.go index 0fe79d1650..bfbfacdd63 100644 --- a/topdown/cidr_test.go +++ b/topdown/cidr_test.go @@ -10,186 +10,6 @@ import ( "github.com/open-policy-agent/opa/storage/inmem" ) -func TestNetCIDROverlap(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"cidr match", []string{`p[x] { net.cidr_overlap("192.168.1.0/24", "192.168.1.67", x) }`}, "[true]"}, - {"cidr mismatch", []string{`p[x] { net.cidr_overlap("192.168.1.0/28", "192.168.1.67", x) }`}, "[false]"}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestNetCIDRIntersects(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"cidr subnet overlaps", []string{`p[x] { net.cidr_intersects("192.168.1.0/25", "192.168.1.64/25", x) }`}, "[true]"}, - {"cidr subnet does not overlap", []string{`p[x] { net.cidr_intersects("192.168.1.0/24", "192.168.2.0/24", x) }`}, "[false]"}, - {"cidr ipv6 subnet overlaps", []string{`p[x] { net.cidr_intersects("fd1e:5bfe:8af3:9ddc::/64", "fd1e:5bfe:8af3:9ddc:1111::/72", x) }`}, "[true]"}, - {"cidr ipv6 subnet does not overlap", []string{`p[x] { net.cidr_intersects("fd1e:5bfe:8af3:9ddc::/64", "2001:4860:4860::8888/32", x) }`}, "[false]"}, - {"cidr subnet overlap malformed cidr a", []string{`p[x] { net.cidr_intersects("not-a-cidr", "192.168.1.0/24", x) }`}, &Error{Code: BuiltinErr}}, - {"cidr subnet overlap malformed cidr b", []string{`p[x] { net.cidr_intersects("192.168.1.0/28", "not-a-cidr", x) }`}, &Error{Code: BuiltinErr}}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestNetCIDRContains(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"cidr contains subnet", []string{`p[x] { net.cidr_contains("10.0.0.0/8", "10.1.0.0/24", x) }`}, "[true]"}, - {"cidr does not contain subnet partial", []string{`p[x] { net.cidr_contains("172.17.0.0/24", "172.17.0.0/16", x) }`}, "[false]"}, - {"cidr does not contain subnet", []string{`p[x] { net.cidr_contains("10.0.0.0/8", "192.168.1.0/24", x) }`}, "[false]"}, - {"cidr contains single ip subnet", []string{`p[x] { net.cidr_contains("10.0.0.0/8", "10.1.1.1/32", x) }`}, "[true]"}, - {"cidr contains subnet ipv6", []string{`p[x] { net.cidr_contains("2001:4860:4860::8888/32", "2001:4860:4860:1234::8888/40", x) }`}, "[true]"}, - {"cidr contains single ip subnet ipv6", []string{`p[x] { net.cidr_contains("2001:4860:4860::8888/32", "2001:4860:4860:1234:5678:1234:5678:8888/128", x) }`}, "[true]"}, - {"cidr does not contain subnet partial ipv6", []string{`p[x] { net.cidr_contains("2001:4860::/96", "2001:4860::/32", x) }`}, "[false]"}, - {"cidr does not contain subnet ipv6", []string{`p[x] { net.cidr_contains("2001:4860::/32", "fd1e:5bfe:8af3:9ddc::/64", x) }`}, "[false]"}, - {"cidr subnet overlap malformed cidr a", []string{`p[x] { net.cidr_contains("not-a-cidr", "192.168.1.67", x) }`}, &Error{Code: BuiltinErr}}, - {"cidr subnet overlap malformed cider b", []string{`p[x] { net.cidr_contains("192.168.1.0/28", "not-a-cidr", x) }`}, &Error{Code: BuiltinErr}}, - {"cidr contains ip", []string{`p[x] { net.cidr_contains("10.0.0.0/8", "10.1.2.3", x) }`}, "[true]"}, - {"cidr does not contain ip", []string{`p[x] { net.cidr_contains("10.0.0.0/8", "192.168.1.1", x) }`}, "[false]"}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestNetCIDRContainsMatches(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - { - note: "strings", - rules: []string{`p = x { x := net.cidr_contains_matches("1.1.1.0/24", "1.1.1.1") }`}, - expected: `[["1.1.1.0/24", "1.1.1.1"]]`, - }, - { - note: "arrays", - rules: []string{`p = x { x := net.cidr_contains_matches(["1.1.2.0/24", "1.1.1.0/24"], ["1.1.1.1", "1.1.2.1"]) }`}, - expected: `[[0,1], [1,0]]`, - }, - { - note: "arrays of tuples", - rules: []string{`p = x { x := net.cidr_contains_matches([["1.1.2.0/24", 1], "1.1.1.0/24"], ["1.1.1.1", "1.1.2.1"]) }`}, - expected: `[[0,1], [1,0]]`, - }, - { - note: "bad array", - rules: []string{`p = x { x := net.cidr_contains_matches(["1.1.2.0/24", "1.1.1.0/24"], ["1.1.1.1", data.a[0]]) }`}, - expected: &Error{Code: BuiltinErr, Message: "net.cidr_contains_matches: operand 2: element must be string or non-empty array"}, - }, - { - note: "sets of strings", - rules: []string{`p = x { x := net.cidr_contains_matches({"1.1.2.0/24", "1.1.1.0/24"}, {"1.1.1.1", "1.1.2.1"}) }`}, - expected: `[["1.1.1.0/24", "1.1.1.1"], ["1.1.2.0/24", "1.1.2.1"]]`, - }, - { - note: "sets of tuples", - rules: []string{`p = x { x := net.cidr_contains_matches({["1.1.2.0/24", "foo"], ["1.1.1.0/24", "bar"]}, {["1.1.1.1", "baz"], ["1.1.2.1", "qux"]}) }`}, - expected: `[[["1.1.1.0/24", "bar"], ["1.1.1.1", "baz"]], [["1.1.2.0/24", "foo"], ["1.1.2.1", "qux"]]]`, - }, - { - note: "bad set", - rules: []string{`p = x { x := net.cidr_contains_matches({["1.1.2.0/24", "foo"], ["1.1.1.0/24", "bar"]}, {data.a[0], ["1.1.2.1", "qux"]}) }`}, - expected: &Error{Code: BuiltinErr, Message: `net.cidr_contains_matches: operand 2: element must be string or non-empty array`}, - }, - { - note: "bad set tuple element", - rules: []string{`p = x { x := net.cidr_contains_matches({["1.1.2.0/24", "foo"], ["1.1.1.0/24", "bar"]}, {[], ["1.1.2.1", "qux"]}) }`}, - expected: &Error{Code: BuiltinErr, Message: `net.cidr_contains_matches: operand 2: element must be string or non-empty array`}, - }, - { - note: "objects", - rules: []string{`p = x { x := net.cidr_contains_matches({"k1": "1.1.1.1/24", "k2": ["1.1.1.2/24", 1]}, "1.1.1.128") }`}, - expected: `[["k1", "1.1.1.128"], ["k2", "1.1.1.128"]]`, - }, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestNetCIDRExpand(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - { - note: "cidr includes host and broadcast", - rules: []string{ - `p = x { net.cidr_expand("192.168.1.1/30", x) }`, - }, - expected: `[ - "192.168.1.0", - "192.168.1.1", - "192.168.1.2", - "192.168.1.3" - ]`, - }, - { - note: "cidr last octet all 1s", - rules: []string{ - `p = x { net.cidr_expand("172.16.100.255/30", x) }`, - }, - expected: `[ - "172.16.100.252", - "172.16.100.253", - "172.16.100.254", - "172.16.100.255" - ]`, - }, - { - note: "cidr all bits", - rules: []string{ - `p = x { net.cidr_expand("192.168.1.1/32", x) }`, - }, - expected: `[ - "192.168.1.1" - ]`, - }, - { - note: "cidr invalid mask", - rules: []string{ - `p = x { net.cidr_expand("192.168.1.1/33", x) }`, - }, - expected: &Error{Code: BuiltinErr, Message: "net.cidr_expand: invalid CIDR address: 192.168.1.1/33"}, - }, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - func TestNetCIDRExpandCancellation(t *testing.T) { ctx := context.Background() diff --git a/topdown/crypto_test.go b/topdown/crypto_test.go deleted file mode 100644 index baa28fee48..0000000000 --- a/topdown/crypto_test.go +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright 2018 The OPA Authors. All rights reserved. -// Use of this source code is governed by an Apache2 -// license that can be found in the LICENSE file. - -package topdown - -import ( - "fmt" - "testing" -) - -func TestCryptoX509ParseCertificates(t *testing.T) { - - rule := ` - p = x { - parsed := crypto.x509.parse_certificates(certs) - x := [ x | x := parsed[_].Subject.CommonName ] - } - ` - - tests := []struct { - note string - certs string - rule string - expected interface{} - }{ - { - note: "DER, single cert, b64", - certs: `MIIDujCCAqKgAwIBAgIIE31FZVaPXTUwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UEBhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMTI5MTMyNzQzWhcNMTQwNTI5MDAwMDAwWjBpMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEYMBYGA1UEAwwPbWFpbC5nb29nbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfRrObuSW5T7q5CnSEqefEmtH4CCv6+5EckuriNr1CjfVvqzwfAhopXkLrq45EQm8vkmf7W96XJhC7ZM0dYi1/qOCAU8wggFLMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAaBgNVHREEEzARgg9tYWlsLmdvb2dsZS5jb20wCwYDVR0PBAQDAgeAMGgGCCsGAQUFBwEBBFwwWjArBggrBgEFBQcwAoYfaHR0cDovL3BraS5nb29nbGUuY29tL0dJQUcyLmNydDArBggrBgEFBQcwAYYfaHR0cDovL2NsaWVudHMxLmdvb2dsZS5jb20vb2NzcDAdBgNVHQ4EFgQUiJxtimAuTfwb+aUtBn5UYKreKvMwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBRK3QYWG7z2aLV29YG2u2IaulqBLzAXBgNVHSAEEDAOMAwGCisGAQQB1nkCBQEwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL3BraS5nb29nbGUuY29tL0dJQUcyLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAH6RYHxHdcGpMpFE3oxDoFnP+gtuBCHan2yE2GRbJ2Cw8Lw0MmuKqHlf9RSeYfd3BXeKkj1qO6TVKwCh+0HdZk283TZZyzmEOyclm3UGFYe82P/iDFt+CeQ3NpmBg+GoaVCuWAARJN/KfglbLyyYygcQq0SgeDh8dRKUiaW3HQSoYvTvdTuqzwK4CXsr3b5/dAOY8uMuG/IAR3FgwTbZ1dtoWRvOTa8hYiU6A475WuZKyEHcwnGYe57u2I2KbMgcKjPniocj4QzgYsVAVKW3IwaOhyE+vPxsiUkvQHdO2fojCkY8jg70jxM+gu59tPDNbw3Uh/2Ij310FgTHsnGQMyA==`, - rule: rule, - expected: `["mail.google.com"]`, - }, - { - note: "DER, chain, b64", - certs: `MIIDIjCCAougAwIBAgIQbt8NlJn9RTPdEpf8Qqk74TANBgkqhkiG9w0BAQUFADBMMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wOTAzMjUxNjQ5MjlaFw0xMDAzMjUxNjQ5MjlaMGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKEwpHb29nbGUgSW5jMRgwFgYDVQQDEw9tYWlsLmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMXW+JL8yvVhSwZBSegKLJWBohjvQew1vXpYElrnb56lTdyJOrvrAp9rc2Fr8P/YaHkfunr5xK6/Nwa6Puru0nQ1tN3PsVfAXzUdZqqH/uDeBy1m13Ov+9Nqt4vvCQ4MyGGpA6yQ3Zi1HJxBVmwBfwvuw7/zkQUf+6D1zGhQrSpZAgMBAAGjgecwgeQwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUFBwMCBglghkgBhvhCBAEwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC50aGF3dGUuY29tL1RoYXd0ZVNHQ0NBLmNybDByBggrBgEFBQcBAQRmMGQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnRoYXd0ZS5jb20wPgYIKwYBBQUHMAKGMmh0dHA6Ly93d3cudGhhd3RlLmNvbS9yZXBvc2l0b3J5L1RoYXd0ZV9TR0NfQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQEFBQADgYEAYvHzBQ68EF5JfHrt+H4k0vSphrs7g3vRm5HrytmLBlmS9r0rSbfW08suQnqZ1gbHsdRjUlJ/rDnmqLZybeW/cCEqUsugdjSl4zIBG9GGjnjrXjyTzwMHInZ4byB0lP6qDtnVOyEQp2Vx+QIJza6IQ4XIglhwMO4V8z12Hi5FprwwggMjMIICjKADAgECAgQwAAACMA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDA1MTMwMDAwMDBaFw0xNDA1MTIyMzU5NTlaMEwxCzAJBgNVBAYTAlpBMSUwIwYDVQQKExxUaGF3dGUgQ29uc3VsdGluZyAoUHR5KSBMdGQuMRYwFAYDVQQDEw1UaGF3dGUgU0dDIENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDU02fQjRV/rs0x/n0dkaE/C3E8rMzIZPtj/DJLB5S9b4C6L+EEk8Az/AkzI+kLdCtxxAPG0s3iL/UJY83/SKUAv+Dn84i3LTLemDbmCq0Ae8RkSjuEdQPycJJ9DmL1IatpNoQxdZD4v8dsiBsGlXzJ5ajedaEsemjf1coch1hgGQIDAQABo4H+MIH7MBIGA1UdEwEB/wQIMAYBAf8CAQAwCwYDVR0PBAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIBBjAoBgNVHREEITAfpB0wGzEZMBcGA1UEAxMQUHJpdmF0ZUxhYmVsMy0xNTAxBgNVHR8EKjAoMCagJKAihiBodHRwOi8vY3JsLnZlcmlzaWduLmNvbS9wY2EzLmNybDAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnRoYXd0ZS5jb20wNAYDVR0lBC0wKwYIKwYBBQUHAwEGCCsGAQUFBwMCBglghkgBhvhCBAEGCmCGSAGG+EUBCAEwDQYJKoZIhvcNAQEFBQADgYEAVaxj6t6h3dKQX58Lzna+E1GPk9kFK8gbd0utaVCh7t7c/dsH6eg5lNyrcnkvBr+rgXDEqO3qUzTt7x5T2QbHVivRXPTRio60K7E3kEgIQiXFPorLf+tvBNFtxXSi96J8e2A8d80OzkgCfwEvtps34CoqNtzVhdas5T9Ub5YeBa8=`, - rule: rule, - expected: `["mail.google.com","Thawte SGC CA"]`, - }, - { - note: "PEM, single cert, b64", - certs: `LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlGZHpDQ0JGK2dBd0lCQWdJU0EzTnJpQUV1cy8rY3ZmbHZoVlFPVzV6VE1BMEdDU3FHU0liM0RRRUJDd1VBDQpNRW94Q3pBSkJnTlZCQVlUQWxWVE1SWXdGQVlEVlFRS0V3MU1aWFFuY3lCRmJtTnllWEIwTVNNd0lRWURWUVFEDQpFeHBNWlhRbmN5QkZibU55ZVhCMElFRjFkR2h2Y21sMGVTQllNekFlRncweU1EQTNNVEF4TmpBd016QmFGdzB5DQpNREV3TURneE5qQXdNekJhTUI0eEhEQWFCZ05WQkFNVEUyOXdaVzV3YjJ4cFkzbGhaMlZ1ZEM1dmNtY3dnZ0VpDQpNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUUN5eThIWlhWVEoyVFNIWFlub0wrQ0tZcG80DQp3ejF3b3dVY2R0L1hCZ04wOGYzN054YU5rK1ZBajhHRDJzNnpob0hMU2h5WVMyUFZvc2Y3eHVtdnlHOTE0UExwDQpJSE85V21DYVpNcXdFeXZNTS9WRTlkQmtLZmFUbzc4QlQ2YVh5Sm1ua2pwZUZtQk9HczN1UDViVUFSajNPbm5yDQo3QW9zOWo0NXJncnl0cGVsWVRNbExpNmpWdEJ2NVJJWnVNb0oxNVcyNTJ0OGVJZ3NPcTU3YWQwQm9iZXl5NFR1DQpHaHZlUDBWM3ZVSnZJM2licUg1RTljV3pJMmY4VXRvaXJVTmYwSjN0Y25nOEpxU091dXpXRFlXclJEQXpRYkpZDQpxS3p2VkRjTitwdHFWN0daNkp1cUhoZHdnRGVxQk9zdmVEYnpBQXlZU1ZQSmpSV1llYThNeGxNN09YYnRBZ01CDQpBQUdqZ2dLQk1JSUNmVEFPQmdOVkhROEJBZjhFQkFNQ0JhQXdIUVlEVlIwbEJCWXdGQVlJS3dZQkJRVUhBd0VHDQpDQ3NHQVFVRkJ3TUNNQXdHQTFVZEV3RUIvd1FDTUFBd0hRWURWUjBPQkJZRUZIRHdlYjZLcHJTdldydy92UjZrDQp3VFZwdWRQdE1COEdBMVVkSXdRWU1CYUFGS2hLYW1NRWZkMjY1dEU1dDZaRlplL3pxT3loTUc4R0NDc0dBUVVGDQpCd0VCQkdNd1lUQXVCZ2dyQmdFRkJRY3dBWVlpYUhSMGNEb3ZMMjlqYzNBdWFXNTBMWGd6TG14bGRITmxibU55DQplWEIwTG05eVp6QXZCZ2dyQmdFRkJRY3dBb1lqYUhSMGNEb3ZMMk5sY25RdWFXNTBMWGd6TG14bGRITmxibU55DQplWEIwTG05eVp5OHdOd1lEVlIwUkJEQXdMb0lUYjNCbGJuQnZiR2xqZVdGblpXNTBMbTl5WjRJWGQzZDNMbTl3DQpaVzV3YjJ4cFkzbGhaMlZ1ZEM1dmNtY3dUQVlEVlIwZ0JFVXdRekFJQmdabmdRd0JBZ0V3TndZTEt3WUJCQUdDDQozeE1CQVFFd0tEQW1CZ2dyQmdFRkJRY0NBUllhYUhSMGNEb3ZMMk53Y3k1c1pYUnpaVzVqY25sd2RDNXZjbWN3DQpnZ0VFQmdvckJnRUVBZFo1QWdRQ0JJSDFCSUh5QVBBQWRnQmVwM1A1MzFiQTU3VTJTSDNRU2VBeWVwR2FESVNoDQpFaEtFR0hXV2dYRkZXQUFBQVhNNXE5dkRBQUFFQXdCSE1FVUNJUUNSSHFncnRsMDdZNlRyeWZNbVFONlROS1JWDQptMUxUeTl2STNNaC9rcmJTUVFJZ1lnVkFLd1hSb1BSK0JOMXBjSmJKdjNBaXZiaDZFN0w5ODdyTVNFUWs1Vm9BDQpkZ0N5SGdYTWk2TE5paUJPaDJiNUs3bUtKU0JuYTlyNmNPZXlTVk10NzR1UVhnQUFBWE01cTl1dUFBQUVBd0JIDQpNRVVDSVFEZHJ1VHV0US9VY2hja3FZUSsycDltdXRuclNublFYYTh4TEE0MVlHelpIZ0lnWFhFVEZiR2ZuczJDDQo3WUo4Y0RvWVlBam1kek1nOGs3aEtYUUd1L0tzQWI0d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFHazlwNXl0DQpPYURJUFJQazVJbXBIMWY2ZjAxMG1VTFdQVjVQam42a3pNSFA5ejVuZE16KysxTk92SFY0R1ZCQ29ldUtxMWJwDQpGQ0QrSWdBOXBjSkFFWFEvdTRHcG1iQUtVWnptZk1JYjg5YVJnbkpwMG14OVk0QkJkNDVFeFVXczh3NGNmZ0ZaDQp5WlVlSHZXczFhbnBBY1IyRklacEFWTVFDYUlnak90MmRkUjF4djRhY0N3K21EL0I5b0tmR1pFVWd5SUFOdnBCDQpJRGFiZ2dMU3dGYTlPS0tYUkJWUkFhZm83T2FjMjFIUVU3RTNzWHBoYUhaR2ZuMkYyN2REL3FvcVVjTHFyNGxDDQpjN2xORTBZR3A2cithUG85VkxjSDJWMGxONHQrMVZiVkFyd0t6bnNOZGNRbndLQmV0Z3F2WnJnTGc0K3FqbzR5DQp1aXhKWTM4WFUvYjdiYVU9DQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tDQo=`, - rule: rule, - expected: `["openpolicyagent.org"]`, - }, - { - note: "PEM, single cert, string", - certs: `-----BEGIN CERTIFICATE----- -MIIFdzCCBF+gAwIBAgISA3NriAEus/+cvflvhVQOW5zTMA0GCSqGSIb3DQEBCwUA -MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD -ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0yMDA3MTAxNjAwMzBaFw0y -MDEwMDgxNjAwMzBaMB4xHDAaBgNVBAMTE29wZW5wb2xpY3lhZ2VudC5vcmcwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCyy8HZXVTJ2TSHXYnoL+CKYpo4 -wz1wowUcdt/XBgN08f37NxaNk+VAj8GD2s6zhoHLShyYS2PVosf7xumvyG914PLp -IHO9WmCaZMqwEyvMM/VE9dBkKfaTo78BT6aXyJmnkjpeFmBOGs3uP5bUARj3Onnr -7Aos9j45rgrytpelYTMlLi6jVtBv5RIZuMoJ15W252t8eIgsOq57ad0Bobeyy4Tu -GhveP0V3vUJvI3ibqH5E9cWzI2f8UtoirUNf0J3tcng8JqSOuuzWDYWrRDAzQbJY -qKzvVDcN+ptqV7GZ6JuqHhdwgDeqBOsveDbzAAyYSVPJjRWYea8MxlM7OXbtAgMB -AAGjggKBMIICfTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG -CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFHDweb6KprSvWrw/vR6k -wTVpudPtMB8GA1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsGAQUF -BwEBBGMwYTAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNy -eXB0Lm9yZzAvBggrBgEFBQcwAoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNlbmNy -eXB0Lm9yZy8wNwYDVR0RBDAwLoITb3BlbnBvbGljeWFnZW50Lm9yZ4IXd3d3Lm9w -ZW5wb2xpY3lhZ2VudC5vcmcwTAYDVR0gBEUwQzAIBgZngQwBAgEwNwYLKwYBBAGC -3xMBAQEwKDAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcw -ggEEBgorBgEEAdZ5AgQCBIH1BIHyAPAAdgBep3P531bA57U2SH3QSeAyepGaDISh -EhKEGHWWgXFFWAAAAXM5q9vDAAAEAwBHMEUCIQCRHqgrtl07Y6TryfMmQN6TNKRV -m1LTy9vI3Mh/krbSQQIgYgVAKwXRoPR+BN1pcJbJv3Aivbh6E7L987rMSEQk5VoA -dgCyHgXMi6LNiiBOh2b5K7mKJSBna9r6cOeySVMt74uQXgAAAXM5q9uuAAAEAwBH -MEUCIQDdruTutQ/UchckqYQ+2p9mutnrSnnQXa8xLA41YGzZHgIgXXETFbGfns2C -7YJ8cDoYYAjmdzMg8k7hKXQGu/KsAb4wDQYJKoZIhvcNAQELBQADggEBAGk9p5yt -OaDIPRPk5ImpH1f6f010mULWPV5Pjn6kzMHP9z5ndMz++1NOvHV4GVBCoeuKq1bp -FCD+IgA9pcJAEXQ/u4GpmbAKUZzmfMIb89aRgnJp0mx9Y4BBd45ExUWs8w4cfgFZ -yZUeHvWs1anpAcR2FIZpAVMQCaIgjOt2ddR1xv4acCw+mD/B9oKfGZEUgyIANvpB -IDabggLSwFa9OKKXRBVRAafo7Oac21HQU7E3sXphaHZGfn2F27dD/qoqUcLqr4lC -c7lNE0YGp6r+aPo9VLcH2V0lN4t+1VbVArwKznsNdcQnwKBetgqvZrgLg4+qjo4y -uixJY38XU/b7baU= ------END CERTIFICATE-----`, - rule: rule, - expected: `["openpolicyagent.org"]`, - }, - { - note: "PEM, chain, b64", - certs: `LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlGZHpDQ0JGK2dBd0lCQWdJU0EzTnJpQUV1cy8rY3ZmbHZoVlFPVzV6VE1BMEdDU3FHU0liM0RRRUJDd1VBTUVveEN6QUpCZ05WQkFZVEFsVlRNUll3RkFZRFZRUUtFdzFNWlhRbmN5QkZibU55ZVhCME1TTXdJUVlEVlFRREV4cE1aWFFuY3lCRmJtTnllWEIwSUVGMWRHaHZjbWwwZVNCWU16QWVGdzB5TURBM01UQXhOakF3TXpCYUZ3MHlNREV3TURneE5qQXdNekJhTUI0eEhEQWFCZ05WQkFNVEUyOXdaVzV3YjJ4cFkzbGhaMlZ1ZEM1dmNtY3dnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDeXk4SFpYVlRKMlRTSFhZbm9MK0NLWXBvNHd6MXdvd1VjZHQvWEJnTjA4ZjM3TnhhTmsrVkFqOEdEMnM2emhvSExTaHlZUzJQVm9zZjd4dW12eUc5MTRQTHBJSE85V21DYVpNcXdFeXZNTS9WRTlkQmtLZmFUbzc4QlQ2YVh5Sm1ua2pwZUZtQk9HczN1UDViVUFSajNPbm5yN0FvczlqNDVyZ3J5dHBlbFlUTWxMaTZqVnRCdjVSSVp1TW9KMTVXMjUydDhlSWdzT3E1N2FkMEJvYmV5eTRUdUdodmVQMFYzdlVKdkkzaWJxSDVFOWNXekkyZjhVdG9pclVOZjBKM3Rjbmc4SnFTT3V1eldEWVdyUkRBelFiSllxS3p2VkRjTitwdHFWN0daNkp1cUhoZHdnRGVxQk9zdmVEYnpBQXlZU1ZQSmpSV1llYThNeGxNN09YYnRBZ01CQUFHamdnS0JNSUlDZlRBT0JnTlZIUThCQWY4RUJBTUNCYUF3SFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdFR0NDc0dBUVVGQndNQ01Bd0dBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRkhEd2ViNktwclN2V3J3L3ZSNmt3VFZwdWRQdE1COEdBMVVkSXdRWU1CYUFGS2hLYW1NRWZkMjY1dEU1dDZaRlplL3pxT3loTUc4R0NDc0dBUVVGQndFQkJHTXdZVEF1QmdnckJnRUZCUWN3QVlZaWFIUjBjRG92TDI5amMzQXVhVzUwTFhnekxteGxkSE5sYm1OeWVYQjBMbTl5WnpBdkJnZ3JCZ0VGQlFjd0FvWWphSFIwY0RvdkwyTmxjblF1YVc1MExYZ3pMbXhsZEhObGJtTnllWEIwTG05eVp5OHdOd1lEVlIwUkJEQXdMb0lUYjNCbGJuQnZiR2xqZVdGblpXNTBMbTl5WjRJWGQzZDNMbTl3Wlc1d2IyeHBZM2xoWjJWdWRDNXZjbWN3VEFZRFZSMGdCRVV3UXpBSUJnWm5nUXdCQWdFd053WUxLd1lCQkFHQzN4TUJBUUV3S0RBbUJnZ3JCZ0VGQlFjQ0FSWWFhSFIwY0RvdkwyTndjeTVzWlhSelpXNWpjbmx3ZEM1dmNtY3dnZ0VFQmdvckJnRUVBZFo1QWdRQ0JJSDFCSUh5QVBBQWRnQmVwM1A1MzFiQTU3VTJTSDNRU2VBeWVwR2FESVNoRWhLRUdIV1dnWEZGV0FBQUFYTTVxOXZEQUFBRUF3QkhNRVVDSVFDUkhxZ3J0bDA3WTZUcnlmTW1RTjZUTktSVm0xTFR5OXZJM01oL2tyYlNRUUlnWWdWQUt3WFJvUFIrQk4xcGNKYkp2M0FpdmJoNkU3TDk4N3JNU0VRazVWb0FkZ0N5SGdYTWk2TE5paUJPaDJiNUs3bUtKU0JuYTlyNmNPZXlTVk10NzR1UVhnQUFBWE01cTl1dUFBQUVBd0JITUVVQ0lRRGRydVR1dFEvVWNoY2txWVErMnA5bXV0bnJTbm5RWGE4eExBNDFZR3paSGdJZ1hYRVRGYkdmbnMyQzdZSjhjRG9ZWUFqbWR6TWc4azdoS1hRR3UvS3NBYjR3RFFZSktvWklodmNOQVFFTEJRQURnZ0VCQUdrOXA1eXRPYURJUFJQazVJbXBIMWY2ZjAxMG1VTFdQVjVQam42a3pNSFA5ejVuZE16KysxTk92SFY0R1ZCQ29ldUtxMWJwRkNEK0lnQTlwY0pBRVhRL3U0R3BtYkFLVVp6bWZNSWI4OWFSZ25KcDBteDlZNEJCZDQ1RXhVV3M4dzRjZmdGWnlaVWVIdldzMWFucEFjUjJGSVpwQVZNUUNhSWdqT3QyZGRSMXh2NGFjQ3crbUQvQjlvS2ZHWkVVZ3lJQU52cEJJRGFiZ2dMU3dGYTlPS0tYUkJWUkFhZm83T2FjMjFIUVU3RTNzWHBoYUhaR2ZuMkYyN2REL3FvcVVjTHFyNGxDYzdsTkUwWUdwNnIrYVBvOVZMY0gyVjBsTjR0KzFWYlZBcndLem5zTmRjUW53S0JldGdxdlpyZ0xnNCtxam80eXVpeEpZMzhYVS9iN2JhVT0NCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0NCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQ0KTUlJRWtqQ0NBM3FnQXdJQkFnSVFDZ0ZCUWdBQUFWT0ZjMm9MaGV5bkNEQU5CZ2txaGtpRzl3MEJBUXNGQURBL01TUXdJZ1lEVlFRS0V4dEVhV2RwZEdGc0lGTnBaMjVoZEhWeVpTQlVjblZ6ZENCRGJ5NHhGekFWQmdOVkJBTVREa1JUVkNCU2IyOTBJRU5CSUZnek1CNFhEVEUyTURNeE56RTJOREEwTmxvWERUSXhNRE14TnpFMk5EQTBObG93U2pFTE1Ba0dBMVVFQmhNQ1ZWTXhGakFVQmdOVkJBb1REVXhsZENkeklFVnVZM0o1Y0hReEl6QWhCZ05WQkFNVEdreGxkQ2R6SUVWdVkzSjVjSFFnUVhWMGFHOXlhWFI1SUZnek1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBbk5NTThGcmxMa2UzY2wwM2c3Tm9ZekRxMXpVbUdTWGh2YjQxOFhDU0w3ZTRTMEVGcTZtZU5RaFk3TEVxeEdpSEM2UGpkZVRtODZkaWNicDVnV0FmMTVHYW4vUFFlR2R4eUdrT2xaSFAvdWFaNldBOFNNeCt5azEzRWlTZFJ4dGE2N25zSGpjQUhKeXNlNmNGNnM1SzY3MUI1VGFZdWN2OWJUeVdhTjhqS2tLUURJWjBaOGgvcFpxNFVtRVVFejlsNllLSHk5djZEbGIyaG9uemhUK1hocSt3M0JydmF3MlZGbjNFSzZCbHNwa0VObldBYTZ4Szh4dVFTWGd2b3BaUEtpQWxLUVRHZE1EUU1jMlBNVGlWRnJxb003aEQ4YkVmd3pCL29ua3hFejB0TnZqai9QSXphcms1TWNXdnhJME5IV1FXTTZyNmhDbTIxQXZBMkgzRGt3SURBUUFCbzRJQmZUQ0NBWGt3RWdZRFZSMFRBUUgvQkFnd0JnRUIvd0lCQURBT0JnTlZIUThCQWY4RUJBTUNBWVl3ZndZSUt3WUJCUVVIQVFFRWN6QnhNRElHQ0NzR0FRVUZCekFCaGlab2RIUndPaTh2YVhOeVp5NTBjblZ6ZEdsa0xtOWpjM0F1YVdSbGJuUnlkWE4wTG1OdmJUQTdCZ2dyQmdFRkJRY3dBb1l2YUhSMGNEb3ZMMkZ3Y0hNdWFXUmxiblJ5ZFhOMExtTnZiUzl5YjI5MGN5OWtjM1J5YjI5MFkyRjRNeTV3TjJNd0h3WURWUjBqQkJnd0ZvQVV4S2V4cEhzc2NmcmI0VXVRZGYvRUZXQ0ZpUkF3VkFZRFZSMGdCRTB3U3pBSUJnWm5nUXdCQWdFd1B3WUxLd1lCQkFHQzN4TUJBUUV3TURBdUJnZ3JCZ0VGQlFjQ0FSWWlhSFIwY0RvdkwyTndjeTV5YjI5MExYZ3hMbXhsZEhObGJtTnllWEIwTG05eVp6QThCZ05WSFI4RU5UQXpNREdnTDZBdGhpdG9kSFJ3T2k4dlkzSnNMbWxrWlc1MGNuVnpkQzVqYjIwdlJGTlVVazlQVkVOQldETkRVa3d1WTNKc01CMEdBMVVkRGdRV0JCU29TbXBqQkgzZHV1YlJPYmVtUldYdjg2anNvVEFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBM1RQWEVmTmpXRGpkR0JYN0NWVytkbGE1Y0VpbGFVY25lOElrQ0pMeFdoOUtFaWszSkhSUkhHSm91TTJWY0dmbDk2UzhUaWhSelp2b3JvZWQ2dGk2V3FFQm10enczV29kYXRnK1Z5T2VwaDRFWXByLzF3WEt0eDgvd0FwSXZKU3d0bVZpNE1GVTVhTXFyU0RFNmVhNzNNajJ0Y015bzVqTWQ2am1lV1VISzhzby9qb1dVb0hPVWd3dVg0UG8xUVl6KzNkc3prRHFNcDRma2x4QndYUnNXMTBLWHpQTVRaK3NPUEF2ZXl4aW5kbWprVzhsR3krUXNSbEdQZlorRzZaNmg3bWplbTBZK2lXbGtZY1Y0UElXTDFpd0JpOHNhQ2JHUzVqTjJwOE0rWCtRN1VOS0VrUk9iM042S09xa3FtNTdUSDJIM2VESkFrU25oNi9ETkZ1MFFnPT0NCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0NCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQ0KTUlJRFNqQ0NBaktnQXdJQkFnSVFSSyt3Z05hako3cUpNRG1HTHZoQWF6QU5CZ2txaGtpRzl3MEJBUVVGQURBL01TUXdJZ1lEVlFRS0V4dEVhV2RwZEdGc0lGTnBaMjVoZEhWeVpTQlVjblZ6ZENCRGJ5NHhGekFWQmdOVkJBTVREa1JUVkNCU2IyOTBJRU5CSUZnek1CNFhEVEF3TURrek1ESXhNVEl4T1ZvWERUSXhNRGt6TURFME1ERXhOVm93UHpFa01DSUdBMVVFQ2hNYlJHbG5hWFJoYkNCVGFXZHVZWFIxY21VZ1ZISjFjM1FnUTI4dU1SY3dGUVlEVlFRREV3NUVVMVFnVW05dmRDQkRRU0JZTXpDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTit2NlpkUUNJTlh0TXhpWmZhUWd1ekgweXhyTU1wYjdObkRmY2RBd1JnVWkrRG9NM1pKS3VNL0lVbVRyRTRPcno1SXkyWHUvTk1oRDJYU0t0a3lqNHpsOTNld0VudTFsY0NKbzZtNjdYTXVlZ3dHTW9PaWZvb1VNTTBSb09FcU9MbDVDakg5VUwyQVpkKzNVV09EeU9LSVllcExZWUhzVW11NW91SkxHaWlmU0tPZUROb0pqajRYTGg3ZElOOWJ4aXFLcXk2OWNLM0ZDeG9sa0hSeXhYdHFxelRXTUluLzVXZ1RlMVFMeU5hdTdGcWNraDQ5WkxPTXh0Ky95VUZ3N0JaeTFTYnNPRlU1UTlEOC9SaGNRUEdYNjlXYW00MGR1dG9sdWNiWTM4RVZBanFyMm03eFBpNzFYQWljUE5hRGFlUVFteGtxdGlsWDQrVTltNS93QWwwQ0F3RUFBYU5DTUVBd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBT0JnTlZIUThCQWY4RUJBTUNBUVl3SFFZRFZSME9CQllFRk1TbnNhUjdMSEg2MitGTGtIWC94QlZnaFlrUU1BMEdDU3FHU0liM0RRRUJCUVVBQTRJQkFRQ2pHaXliRndCY3FSN3VLR1kzT3IrRHh6OUx3d21nbFNCZDQ5bFpSTkkrRFQ2OWlrdWdkQi9PRUlLY2RCb2RmcGdhM2NzVFM3TWdST1NSNmN6OGZhWGJhdVgrNXYzZ1R0MjNBRHExY0Vtdjh1WHJBdkhSQW9zWnk1UTZYa2pFR0I1WUdWOGVBbHJ3RFBHeHJhbmNXWWFMYnVtUjlZYksrcmxtTTZwWlc4N2lweFp6UjhzcnpKbXdOMGpQNDFaTDljOFBESEl5aDhid1JMdFRjbTFEOVNaSW1sSm50MWlyL21kMmNYamJEYUpXRkJNNUpER0ZvcWdDV2pCSDRkMVFCN3dDQ1pBQTYyUmpZSnNXdklqSkV1YlNmWkdMK1QweWpXVzA2WHl4VjNicXhiWW9PYjhWWlJ6STluZVdhZ3FOZHd2WWtRc0VqZ2ZiS2JZSzdwMkNOVFVRDQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tDQo=`, - rule: rule, - expected: `["openpolicyagent.org", "Let's Encrypt Authority X3", "DST Root CA X3"]`, - }, - { - note: "PEM, chain, string", - certs: `-----BEGIN CERTIFICATE----- -MIIFdzCCBF+gAwIBAgISA3NriAEus/+cvflvhVQOW5zTMA0GCSqGSIb3DQEBCwUAMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0yMDA3MTAxNjAwMzBaFw0yMDEwMDgxNjAwMzBaMB4xHDAaBgNVBAMTE29wZW5wb2xpY3lhZ2VudC5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCyy8HZXVTJ2TSHXYnoL+CKYpo4wz1wowUcdt/XBgN08f37NxaNk+VAj8GD2s6zhoHLShyYS2PVosf7xumvyG914PLpIHO9WmCaZMqwEyvMM/VE9dBkKfaTo78BT6aXyJmnkjpeFmBOGs3uP5bUARj3Onnr7Aos9j45rgrytpelYTMlLi6jVtBv5RIZuMoJ15W252t8eIgsOq57ad0Bobeyy4TuGhveP0V3vUJvI3ibqH5E9cWzI2f8UtoirUNf0J3tcng8JqSOuuzWDYWrRDAzQbJYqKzvVDcN+ptqV7GZ6JuqHhdwgDeqBOsveDbzAAyYSVPJjRWYea8MxlM7OXbtAgMBAAGjggKBMIICfTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFHDweb6KprSvWrw/vR6kwTVpudPtMB8GA1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsGAQUFBwEBBGMwYTAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0Lm9yZzAvBggrBgEFBQcwAoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNlbmNyeXB0Lm9yZy8wNwYDVR0RBDAwLoITb3BlbnBvbGljeWFnZW50Lm9yZ4IXd3d3Lm9wZW5wb2xpY3lhZ2VudC5vcmcwTAYDVR0gBEUwQzAIBgZngQwBAgEwNwYLKwYBBAGC3xMBAQEwKDAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcwggEEBgorBgEEAdZ5AgQCBIH1BIHyAPAAdgBep3P531bA57U2SH3QSeAyepGaDIShEhKEGHWWgXFFWAAAAXM5q9vDAAAEAwBHMEUCIQCRHqgrtl07Y6TryfMmQN6TNKRVm1LTy9vI3Mh/krbSQQIgYgVAKwXRoPR+BN1pcJbJv3Aivbh6E7L987rMSEQk5VoAdgCyHgXMi6LNiiBOh2b5K7mKJSBna9r6cOeySVMt74uQXgAAAXM5q9uuAAAEAwBHMEUCIQDdruTutQ/UchckqYQ+2p9mutnrSnnQXa8xLA41YGzZHgIgXXETFbGfns2C7YJ8cDoYYAjmdzMg8k7hKXQGu/KsAb4wDQYJKoZIhvcNAQELBQADggEBAGk9p5ytOaDIPRPk5ImpH1f6f010mULWPV5Pjn6kzMHP9z5ndMz++1NOvHV4GVBCoeuKq1bpFCD+IgA9pcJAEXQ/u4GpmbAKUZzmfMIb89aRgnJp0mx9Y4BBd45ExUWs8w4cfgFZyZUeHvWs1anpAcR2FIZpAVMQCaIgjOt2ddR1xv4acCw+mD/B9oKfGZEUgyIANvpBIDabggLSwFa9OKKXRBVRAafo7Oac21HQU7E3sXphaHZGfn2F27dD/qoqUcLqr4lCc7lNE0YGp6r+aPo9VLcH2V0lN4t+1VbVArwKznsNdcQnwKBetgqvZrgLg4+qjo4yuixJY38XU/b7baU= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0NlowSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMTGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EFq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWAa6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIGCCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNvbTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9kc3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAwVAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcCARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwuY3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsFAAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJouM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwuX4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlGPfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ ------END CERTIFICATE-----`, - rule: rule, - expected: `["openpolicyagent.org", "Let's Encrypt Authority X3", "DST Root CA X3"]`, - }, - { - note: "invalid DER or PEM data, b64", - certs: `YmFkc3RyaW5n`, - rule: rule, - expected: &Error{Code: BuiltinErr, Message: "asn1: structure error"}, - }, - { - note: "invalid DER or PEM data, string", - certs: `foobar`, - rule: rule, - expected: &Error{Code: BuiltinErr, Message: "illegal base64"}, - }, - } - - data := loadSmallTestData() - - for _, tc := range tests { - rules := []string{ - fmt.Sprintf("certs = %q { true }", tc.certs), - tc.rule, - } - runTopDownTestCase(t, data, tc.note, rules, tc.expected) - } - -} - -func TestCryptoX509ParseCertificateRequest(t *testing.T) { - rule := ` - p = x { - parsed := crypto.x509.parse_certificate_request(csr) - x := parsed.Subject.CommonName - } - ` - - tests := []struct { - note string - csr string - rule string - expected interface{} - }{ - { - note: "PEM, b64", - csr: `LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ21EQ0NBWUFDQVFBd1V6RUxNQWtHQTFVRUJoTUNWVk14RkRBU0JnTlZCQU1NQzJWNFlXMXdiR1V1WTI5dApNUW93Q0FZRFZRUUhEQUVnTVFvd0NBWURWUVFLREFFZ01Rb3dDQVlEVlFRSURBRWdNUW93Q0FZRFZRUUxEQUVnCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBMlpkaG1zaERBVTBYYnhnTk1GQWsKeEdWQnNjaHdWb2s5dXBBU2ZVWDA4VFlqMFZrV0VxNitmemdOdmRQSnd6Nm1lUDlnL01hRmhPYW91Nmh1UEhmbwpTVTlKN1FiTW56Uktsc0VJTzNodEM1QUt3OXYyZldVZGpCQS92Q1dZdXU1aUc1ZTdtUHNXWjd1cGxuVGZSekM4ClJLK0srWXJtNEQ4NHE1bHR5NEMzS2tRc0FjU0xQZk9MMXMvYjJyV21KR0FoV3NSa2doTVk2V3dza3VYWXRINTkKRzl5VURHUUhoalprcHFlZFY0OUM4c0NwMU8vWVpvU0hncDdHK0JiaFRta05CRzY3OFZHREplTnB3SG96dnRjVQpyQVNGRFJ4WnhPdTFHRzE3L1FiVW9SNVVkOTNwaUtaU0U2UHVDU2VCcy9UQmFJc3ZwUGtudVhkOXI4WGovbVd5CmtRSURBUUFCb0FBd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFBeDJkaCtkMU1CaEwwaDJYZklxaDVEYy9lYWoKU0xadGFNTWlJY1h1cC96UTl2eENXSkZlSGYzczBJdXliMEhkMlZNZ1BSYU8ydWRkY2JZdFFlKzJnWUtrTzFMWApCdHdQcXcwWHAweUF2dDUxRzJvZmVCbCtFa0ptNjk3RlNtemg4eDJJZFFBSkMzWi9ROFdMVmh3NFg2WlVicnhqCjJnTjJmaVhjS0RKbGVkcUgxY2V4WVVvbnlLSDZubG4wbzQzUUtEOFlSZG9hNVFqb3Ixb0JkY3dSTTA0VDM4ak0KV1B3d2JZTjNrVE9Ea0tiaVFVVWxVeFZuNnFnZTlNTWt0c0lOWkc0eDY1QmIwaWxTdHExRWQwN2Y5NmVnbHNKaApZVE9VRnZpZDZVSkVEcEJzcjhyZFROSW1JQkhCdkkra1BHS2FqcW83Z0VNc3hFYkNkemFHUTNZZnNYWT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUgUkVRVUVTVC0tLS0t`, - rule: rule, - expected: `"example.com"`, - }, - { - note: "PEM, string", - csr: `-----BEGIN CERTIFICATE REQUEST----- -MIICmDCCAYACAQAwUzELMAkGA1UEBhMCVVMxFDASBgNVBAMMC2V4YW1wbGUuY29t -MQowCAYDVQQHDAEgMQowCAYDVQQKDAEgMQowCAYDVQQIDAEgMQowCAYDVQQLDAEg -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2ZdhmshDAU0XbxgNMFAk -xGVBschwVok9upASfUX08TYj0VkWEq6+fzgNvdPJwz6meP9g/MaFhOaou6huPHfo -SU9J7QbMnzRKlsEIO3htC5AKw9v2fWUdjBA/vCWYuu5iG5e7mPsWZ7uplnTfRzC8 -RK+K+Yrm4D84q5lty4C3KkQsAcSLPfOL1s/b2rWmJGAhWsRkghMY6WwskuXYtH59 -G9yUDGQHhjZkpqedV49C8sCp1O/YZoSHgp7G+BbhTmkNBG678VGDJeNpwHozvtcU -rASFDRxZxOu1GG17/QbUoR5Ud93piKZSE6PuCSeBs/TBaIsvpPknuXd9r8Xj/mWy -kQIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAAx2dh+d1MBhL0h2XfIqh5Dc/eaj -SLZtaMMiIcXup/zQ9vxCWJFeHf3s0Iuyb0Hd2VMgPRaO2uddcbYtQe+2gYKkO1LX -BtwPqw0Xp0yAvt51G2ofeBl+EkJm697FSmzh8x2IdQAJC3Z/Q8WLVhw4X6ZUbrxj -2gN2fiXcKDJledqH1cexYUonyKH6nln0o43QKD8YRdoa5Qjor1oBdcwRM04T38jM -WPwwbYN3kTODkKbiQUUlUxVn6qge9MMktsINZG4x65Bb0ilStq1Ed07f96eglsJh -YTOUFvid6UJEDpBsr8rdTNImIBHBvI+kPGKajqo7gEMsxEbCdzaGQ3YfsXY= ------END CERTIFICATE REQUEST-----`, - rule: rule, - expected: `"example.com"`, - }, - { - note: "DER, b64", - csr: `MIICmDCCAYACAQAwUzELMAkGA1UEBhMCVVMxFDASBgNVBAMMC2V4YW1wbGUuY29tMQowCAYDVQQHDAEgMQowCAYDVQQKDAEgMQowCAYDVQQIDAEgMQowCAYDVQQLDAEgMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2ZdhmshDAU0XbxgNMFAkxGVBschwVok9upASfUX08TYj0VkWEq6+fzgNvdPJwz6meP9g/MaFhOaou6huPHfoSU9J7QbMnzRKlsEIO3htC5AKw9v2fWUdjBA/vCWYuu5iG5e7mPsWZ7uplnTfRzC8RK+K+Yrm4D84q5lty4C3KkQsAcSLPfOL1s/b2rWmJGAhWsRkghMY6WwskuXYtH59G9yUDGQHhjZkpqedV49C8sCp1O/YZoSHgp7G+BbhTmkNBG678VGDJeNpwHozvtcUrASFDRxZxOu1GG17/QbUoR5Ud93piKZSE6PuCSeBs/TBaIsvpPknuXd9r8Xj/mWykQIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAAx2dh+d1MBhL0h2XfIqh5Dc/eajSLZtaMMiIcXup/zQ9vxCWJFeHf3s0Iuyb0Hd2VMgPRaO2uddcbYtQe+2gYKkO1LXBtwPqw0Xp0yAvt51G2ofeBl+EkJm697FSmzh8x2IdQAJC3Z/Q8WLVhw4X6ZUbrxj2gN2fiXcKDJledqH1cexYUonyKH6nln0o43QKD8YRdoa5Qjor1oBdcwRM04T38jMWPwwbYN3kTODkKbiQUUlUxVn6qge9MMktsINZG4x65Bb0ilStq1Ed07f96eglsJhYTOUFvid6UJEDpBsr8rdTNImIBHBvI+kPGKajqo7gEMsxEbCdzaGQ3YfsXY=`, - rule: rule, - expected: `"example.com"`, - }, - { - note: "invalid DER or PEM data, b64", - csr: `YmFkc3RyaW5n`, - rule: rule, - expected: &Error{Code: BuiltinErr, Message: "asn1: structure error"}, - }, - { - note: "invalid DER or PEM data, string", - csr: `foobar`, - rule: rule, - expected: &Error{Code: BuiltinErr, Message: "illegal base64"}, - }, - } - - data := loadSmallTestData() - - for _, tc := range tests { - rules := []string{ - fmt.Sprintf("csr = %q { true }", tc.csr), - tc.rule, - } - runTopDownTestCase(t, data, tc.note, rules, tc.expected) - } -} - -func TestCryptoMd5(t *testing.T) { - - tests := []struct { - note string - rule []string - expected interface{} - }{ - { - note: "crypto.md5 with string", - rule: []string{`p[hash] { hash := crypto.md5("lorem ipsum") }`}, - expected: `["80a751fde577028640c419000e33eba6"]`, - }, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rule, tc.expected) - } - -} - -func TestCryptoSha1(t *testing.T) { - - tests := []struct { - note string - rule []string - expected interface{} - }{ - { - note: "crypto.sha1 with string", - rule: []string{`p[hash] { hash := crypto.sha1("lorem ipsum") }`}, - expected: `["bfb7759a67daeb65410490b4d98bb9da7d1ea2ce"]`, - }, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rule, tc.expected) - } - -} - -func TestCryptoSha256(t *testing.T) { - - tests := []struct { - note string - rule []string - expected interface{} - }{ - { - note: "crypto.sha256 with string", - rule: []string{`p[hash] { hash := crypto.sha256("lorem ipsum") }`}, - expected: `["5e2bf57d3f40c4b6df69daf1936cb766f832374b4fc0259a7cbff06e2f70f269"]`, - }, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rule, tc.expected) - } - -} diff --git a/topdown/glob_test.go b/topdown/glob_test.go deleted file mode 100644 index f38253e77e..0000000000 --- a/topdown/glob_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package topdown - -import "testing" - -func TestGlobMatch(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"glob match with . delimiter", []string{`p[x] { glob.match("*.github.com", ["."], "api.github.com", x) }`}, "[true]"}, - {"super glob match with . delimiter", []string{`p[x] { glob.match("api.**.com", ["."], "api.github.com", x) }`}, "[true]"}, - {"super glob match with . delimiter", []string{`p[x] { glob.match("api.**.com", ["."], "api.cdn.github.com", x) }`}, "[true]"}, - {"glob match with : delimiter", []string{`p[x] { glob.match("*:github:com", [":"], "api:github:com", x) }`}, "[true]"}, - {"glob no match with . delimiter", []string{`p[x] { glob.match("*.github.com", ["."], "api.not-github.com", x) }`}, "[false]"}, - {"glob match with character-list matchers", []string{`p[x] { glob.match("[abc]at", [], "cat", x) }`}, "[true]"}, - {"glob no match with character-list matchers", []string{`p[x] { glob.match("[abc]at", [], "fat", x) }`}, "[false]"}, - {"glob match with negated character-list matchers", []string{`p[x] { glob.match("[!abc]at", [], "fat", x) }`}, "[true]"}, - {"glob no match with negated character-list matchers", []string{`p[x] { glob.match("[!abc]at", [], "cat", x) }`}, "[false]"}, - {"glob match with character-range matchers", []string{`p[x] { glob.match("[a-c]at", [], "bat", x) }`}, "[true]"}, - {"glob no match with character-range matchers", []string{`p[x] { glob.match("[a-c]at", [], "fat", x) }`}, "[false]"}, - {"glob no match with character-range matchers", []string{`p[x] { glob.match("[!a-c]at", [], "bat", x) }`}, "[false]"}, - {"glob match with character-range matchers", []string{`p[x] { glob.match("[!a-c]at", [], "fat", x) }`}, "[true]"}, - {"glob match with single wild-card", []string{`p[x] { glob.match("?at", [], "fat", x) }`}, "[true]"}, - {"glob no match with single wild-card", []string{`p[x] { glob.match("?at", [], "at", x) }`}, "[false]"}, - {"glob match with single wild-card and delimiter", []string{`p[x] { glob.match("?at", ["f"], "bat", x) }`}, "[true]"}, - {"glob no match with single wild-card and delimiter", []string{`p[x] { glob.match("?at", ["f"], "fat", x) }`}, "[false]"}, - {"glob match with pattern-alternatives list (cat)", []string{`p[x] { glob.match("{cat,bat,[fr]at}", [], "cat", x) }`}, "[true]"}, - {"glob match with pattern-alternatives list (bat)", []string{`p[x] { glob.match("{cat,bat,[fr]at}", [], "bat", x) }`}, "[true]"}, - {"glob match with pattern-alternatives list (fat)", []string{`p[x] { glob.match("{cat,bat,[fr]at}", [], "fat", x) }`}, "[true]"}, - {"glob match with pattern-alternatives list (rat)", []string{`p[x] { glob.match("{cat,bat,[fr]at}", [], "rat", x) }`}, "[true]"}, - {"glob no match with pattern-alternatives list", []string{`p[x] { glob.match("{cat,bat,[fr]at}", [], "at", x) }`}, "[false]"}, - {"glob match single with . delimiter", []string{`p[x] { glob.match("*", ["."], "foo", x) }`}, "[true]"}, - {"glob match single with default delimiter", []string{`p[x] { glob.match("*", [], "foo", x) }`}, "[true]"}, - {"glob no match single with . delimiter", []string{`p[x] { glob.match("*", ["."], "foo.bar", x) }`}, "[false]"}, - {"glob no match single with default delimiter", []string{`p[x] { glob.match("*", [], "foo.bar", x) }`}, "[false]"}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestGlobQuoteMeta(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"glob quote meta", []string{`p[x] { glob.quote_meta("*.github.com", x) }`}, `["\\*.github.com"]`}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} diff --git a/topdown/json_test.go b/topdown/json_test.go index 5e20f654c2..53d114e4ae 100644 --- a/topdown/json_test.go +++ b/topdown/json_test.go @@ -5,108 +5,11 @@ package topdown import ( - "fmt" "testing" "github.com/open-policy-agent/opa/ast" ) -func TestBuiltinJSONFilter(t *testing.T) { - cases := []struct { - note string - object string - filters string - expected interface{} - }{ - { - note: "base", - object: `{"a": {"b": {"c": 7, "d": 8}}, "e": 9}`, - filters: `{"a/b/c"}`, - expected: `{"a": {"b": {"c": 7}}}`, - }, - { - note: "multiple roots", - object: `{"a": {"b": {"c": 7, "d": 8}}, "e": 9}`, - filters: `{"a/b/c", "e"}`, - expected: `{"a": {"b": {"c": 7}}, "e": 9}`, - }, - { - note: "multiple roots array", - object: `{"a": {"b": {"c": 7, "d": 8}}, "e": 9}`, - filters: `["a/b/c", "e"]`, - expected: `{"a": {"b": {"c": 7}}, "e": 9}`, - }, - { - note: "shared roots", - object: `{"a": {"b": {"c": 7, "d": 8}, "e": 9}}`, - filters: `{"a/b/c", "a/e"}`, - expected: `{"a": {"b": {"c": 7}, "e": 9}}`, - }, - { - note: "conflict", - object: `{"a": {"b": 7}}`, - filters: `{"a", "a/b"}`, - expected: `{"a": {"b": 7}}`, - }, - { - note: "empty list", - object: `{"a": 7}`, - filters: `set()`, - expected: `{}`, - }, - { - note: "empty object", - object: `{}`, - filters: `{"a/b"}`, - expected: `{}`, - }, - { - note: "arrays", - object: `{"a": [{"b": 7, "c": 8}, {"d": 9}]}`, - filters: `{"a/0/b", "a/1"}`, - expected: `{"a": [{"b": 7}, {"d": 9}]}`, - }, - { - note: "object with number keys", - object: `{"a": [{"1":["b", "c", "d"]}, {"x": "y"}]}`, - filters: `{"a/0/1/2"}`, - expected: `{"a": [{"1": ["d"]}]}`, - }, - { - note: "arrays of roots", - object: `{"a": {"b": {"c": 7, "d": 8}}, "e": 9}`, - filters: `{["a", "b", "c"], ["e"]}`, - expected: `{"a": {"b": {"c": 7}}, "e": 9}`, - }, - { - note: "mixed root types", - object: `{"a": {"b": {"c": 7, "d": 8, "x": 0}}, "e": 9}`, - filters: `{["a", "b", "c"], "a/b/d"}`, - expected: `{"a": {"b": {"c": 7, "d": 8}}}`, - }, - } - - for _, tc := range cases { - rules := []string{ - fmt.Sprintf("p = x { x := json.filter(%s, %s) }", tc.object, tc.filters), - } - runTopDownTestCase(t, map[string]interface{}{}, tc.note, rules, tc.expected) - } -} - -func TestBuiltinJSONFilterIdempotent(t *testing.T) { - rule := ` - p { - # "base" should never be mutated - base := {"a": {"b": 2, "c": 3}} - json.filter(base, {"a/b"}) == {"a": {"b": 2}} - json.filter(base, {"a/c"}) == {"a": {"c": 3}} - base == {"a": {"b": 2, "c": 3}} - } - ` - runTopDownTestCase(t, map[string]interface{}{}, t.Name(), []string{rule}, "true") -} - func TestFiltersToObject(t *testing.T) { cases := []struct { note string @@ -198,275 +101,3 @@ func TestFiltersToObject(t *testing.T) { }) } } - -func TestBuiltinJSONRemove(t *testing.T) { - cases := []struct { - note string - object string - paths string - input string - expected interface{} - }{ - { - note: "base", - object: `{"a": {"b": {"c": 7, "d": 8}}, "e": 9}`, - paths: `{"a/b/c"}`, - expected: `{"a": {"b": {"d": 8}}, "e": 9}`, - }, - { - note: "multiple roots", - object: `{"a": {"b": {"c": 7, "d": 8}}, "e": 9}`, - paths: `{"a/b/c", "e"}`, - expected: `{"a": {"b": {"d": 8}}}`, - }, - { - note: "multiple roots array", - object: `{"a": {"b": {"c": 7, "d": 8}}, "e": 9}`, - paths: `["a/b/c", "e"]`, - expected: `{"a": {"b": {"d": 8}}}`, - }, - { - note: "shared roots", - object: `{"a": {"b": {"c": 7, "d": 8}, "e": 9}}`, - paths: `{"a/b/c", "a/e"}`, - expected: `{"a": {"b": {"d": 8}}}`, - }, - { - note: "conflict", - object: `{"a": {"b": 7}, "c": 1}`, - paths: `{"a", "a/b"}`, - expected: `{"c": 1}`, - }, - { - note: "empty list", - object: `{"a": 7}`, - paths: `set()`, - expected: `{"a": 7}`, - }, - { - note: "empty object", - object: `{}`, - paths: `{"a/b"}`, - expected: `{}`, - }, - { - note: "delete all", - object: `{"a": {"b": 7}, "c": 1}`, - paths: `{"a", "c"}`, - expected: `{}`, - }, - { - note: "delete last in object", - object: `{"a": {"b": 7}, "c": 1}`, - paths: `{"a/b", "c"}`, - expected: `{"a": {}}`, - }, - { - note: "arrays", - object: `{"a": [{"b": 7, "c": 8}, {"d": 9}]}`, - paths: `{"a/0/b", "a/1"}`, - expected: `{"a": [{"c": 8}]}`, - }, - { - note: "object with number keys", - object: `{"a": [{"1":["b", "c", "d"]}, {"x": "y"}]}`, - paths: `{"a/0/1/2"}`, - expected: `{"a": [{"1":["b", "c"]}, {"x": "y"}]}`, - }, - { - note: "arrays of roots", - object: `{"a": {"b": {"c": 7, "d": 8}}, "e": 9}`, - paths: `{["a", "b", "c"], ["e"]}`, - expected: `{"a": {"b": {"d": 8}}}`, - }, - { - note: "mixed root types", - object: `{"a": {"b": {"c": 7, "d": 8, "x": 0}}, "e": 9}`, - paths: `{["a", "b", "c"], "a/b/d"}`, - expected: `{"a": {"b": {"x": 0}}, "e": 9}`, - }, - { - note: "error invalid target type string", - object: `"foo"`, - paths: `{"a/b/c"}`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "json.remove: invalid argument(s)")}, - }, - { - note: "error invalid target type number", - object: `22`, - paths: `{"a/b/c"}`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "json.remove: invalid argument(s)")}, - }, - { - note: "error invalid target type boolean", - object: `false`, - paths: `{"a/b/c"}`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "json.remove: invalid argument(s)")}, - }, - { - note: "error invalid target type set", - object: `{"a"}`, - paths: `{"a/b/c"}`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "json.remove: invalid argument(s)")}, - }, - { - note: "error invalid target type array", - object: `["a"]`, - paths: `{"a/b/c"}`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "json.remove: invalid argument(s)")}, - }, - { - note: "error invalid target type string input", - object: `input.x`, - paths: `{"a/b/c"}`, - input: `{"x": "foo"}`, - expected: &Error{Code: TypeErr, Message: "json.remove: operand 1 must be object but got string"}, - }, - { - note: "error invalid target type number input", - object: `input.x`, - paths: `{"a/b/c"}`, - input: `{"x": 22}`, - expected: &Error{Code: TypeErr, Message: "json.remove: operand 1 must be object but got number"}, - }, - { - note: "error invalid target type boolean input", - object: `input.x`, - paths: `{"a/b/c"}`, - input: `{"x": true}`, - expected: &Error{Code: TypeErr, Message: "json.remove: operand 1 must be object but got boolean"}, - }, - { - note: "error invalid target type array input", - object: `input.x`, - paths: `{"a/b/c"}`, - input: `{"x": ["a", "b", "c"]}`, - expected: &Error{Code: TypeErr, Message: "json.remove: operand 1 must be object but got array"}, - }, - { - note: "error invalid paths type string", - object: `{"a": {"b": {"c": 123}}}`, - paths: `"foo"`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "json.remove: invalid argument(s)")}, - }, - { - note: "error invalid paths type number", - object: `{"a": {"b": {"c": 123}}}`, - paths: `22`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "json.remove: invalid argument(s)")}, - }, - { - note: "error invalid paths type boolean", - object: `{"a": {"b": {"c": 123}}}`, - paths: `true`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "json.remove: invalid argument(s)")}, - }, - { - note: "error invalid paths type object", - object: `{"a": {"b": {"c": 123}}}`, - paths: `{"x": 1}`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "json.remove: invalid argument(s)")}, - }, - { - note: "error invalid paths type set with numbers", - object: `{"a": {"b": {"c": 123}}}`, - paths: `{"a", 1, 2, 3}`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "json.remove: invalid argument(s)")}, - }, - { - note: "error invalid paths type set with objects", - object: `{"a": {"b": {"c": 123}}}`, - paths: `{"a", {"x": 1}, {"y": 2}}`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "json.remove: invalid argument(s)")}, - }, - { - note: "error invalid paths type array with numbers", - object: `{"a": {"b": {"c": 123}}}`, - paths: `["a", 1, 2, 3]`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "json.remove: invalid argument(s)")}, - }, - { - note: "error invalid paths type array with objects", - object: `{"a": {"b": {"c": 123}}}`, - paths: `["a", {"x": 1}, {"y": 2}]`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "json.remove: invalid argument(s)")}, - }, - { - note: "error invalid paths type string", - object: `{"a": {"b": {"c": 123}}}`, - paths: `input.x`, - input: `{"x": "foo"}`, - expected: &Error{Code: TypeErr, Message: "json.remove: operand 2 must be one of {set, array} but got string"}, - }, - { - note: "error invalid paths type number", - object: `{"a": {"b": {"c": 123}}}`, - paths: `input.x`, - input: `{"x": 22}`, - expected: &Error{Code: TypeErr, Message: "json.remove: operand 2 must be one of {set, array} but got number"}, - }, - { - note: "error invalid paths type boolean", - object: `{"a": {"b": {"c": 123}}}`, - paths: `input.x`, - input: `{"x": true}`, - expected: &Error{Code: TypeErr, Message: "json.remove: operand 2 must be one of {set, array} but got boolean"}, - }, - { - note: "error invalid paths type object", - object: `{"a": {"b": {"c": 123}}}`, - paths: `input.x`, - input: `{"x": {"y": 123}}`, - expected: &Error{Code: TypeErr, Message: "json.remove: operand 2 must be one of {set, array} but got object"}, - }, - { - note: "error invalid paths type set with numbers", - object: `{"a": {"b": {"c": 123}}}`, - paths: `input.x`, - input: `{"x": {"a", 1, 2, 3}}`, - expected: &Error{Code: TypeErr, Message: "json.remove: operand 2 must be one of {set, array} containing string paths or array of path segments but got number"}, - }, - { - note: "error invalid paths type set with objects", - object: `{"a": {"b": {"c": 123}}}`, - paths: `input.x`, - input: `{"x": {"a", {"x": 1}, {"y": 2}}}`, - expected: &Error{Code: TypeErr, Message: "json.remove: operand 2 must be one of {set, array} containing string paths or array of path segments but got object"}, - }, - { - note: "error invalid paths type array with numbers", - object: `{"a": {"b": {"c": 123}}}`, - paths: `input.x`, - input: `{"x": ["a", 1, 2, 3]}`, - expected: &Error{Code: TypeErr, Message: "json.remove: operand 2 must be one of {set, array} containing string paths or array of path segments but got number"}, - }, - { - note: "error invalid paths type array with objects", - object: `{"a": {"b": {"c": 123}}}`, - paths: `input.x`, - input: `{"x": ["a", {"x": 1}, {"y": 2}]}`, - expected: &Error{Code: TypeErr, Message: "json.remove: operand 2 must be one of {set, array} containing string paths or array of path segments but got object"}, - }, - } - - for _, tc := range cases { - rules := []string{ - fmt.Sprintf("p = x { x := json.remove(%s, %s) }", tc.object, tc.paths), - } - runTopDownTestCaseWithModules(t, map[string]interface{}{}, tc.note, rules, nil, tc.input, tc.expected) - } -} - -func TestBuiltinJSONRemoveIdempotent(t *testing.T) { - rule := ` - p { - # "base" should never be mutated - base := {"a": {"b": 2, "c": 3}} - json.remove(base, {"a"}) == {} - json.remove(base, {"a/b"}) == {"a": {"c": 3}} - json.remove(base, {"a/c"}) == {"a": {"b": 2}} - base == {"a": {"b": 2, "c": 3}} - } - ` - runTopDownTestCase(t, map[string]interface{}{}, t.Name(), []string{rule}, "true") -} diff --git a/topdown/numbers_test.go b/topdown/numbers_test.go deleted file mode 100644 index f03eac85af..0000000000 --- a/topdown/numbers_test.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2020 The OPA Authors. All rights reserved. -// Use of this source code is governed by an Apache2 -// license that can be found in the LICENSE file. -package topdown - -import ( - "testing" -) - -func TestBuiltinNumbersRange(t *testing.T) { - cases := []struct { - note string - stmt string - exp interface{} - }{ - { - note: "one", - stmt: "p = x { x := numbers.range(0, 0) }", - exp: "[0]", - }, - { - note: "ascending", - stmt: "p = x { x := numbers.range(-2, 3) }", - exp: "[-2, -1, 0, 1, 2, 3]", - }, - { - note: "descending", - stmt: "p = x { x := numbers.range(2, -3) }", - exp: "[2, 1, 0, -1, -2, -3]", - }, - { - note: "precision", - stmt: "p { numbers.range(49649733057, 49649733060, [49649733057, 49649733058, 49649733059, 49649733060]) }", - exp: "true", - }, - { - note: "error: floating-point number pos 1", - stmt: "p { numbers.range(3.14, 4) }", - exp: &Error{Code: TypeErr, Message: "numbers.range: operand 1 must be integer number but got floating-point number"}, - }, - { - note: "error: floating-point number pos 2", - stmt: "p { numbers.range(3, 3.14) }", - exp: &Error{Code: TypeErr, Message: "numbers.range: operand 2 must be integer number but got floating-point number"}, - }, - } - - for _, tc := range cases { - runTopDownTestCase(t, map[string]interface{}{}, tc.note, []string{tc.stmt}, tc.exp) - } -} diff --git a/topdown/object_test.go b/topdown/object_test.go deleted file mode 100644 index 4f7a0df999..0000000000 --- a/topdown/object_test.go +++ /dev/null @@ -1,543 +0,0 @@ -// Copyright 2020 The OPA Authors. All rights reserved. -// Use of this source code is governed by an Apache2 -// license that can be found in the LICENSE file. - -package topdown - -import ( - "fmt" - "testing" - - "github.com/open-policy-agent/opa/ast" -) - -func TestObjectGet(t *testing.T) { - cases := []struct { - note string - object string - key interface{} - fallback interface{} - expected interface{} - }{ - { - note: "basic case . found", - object: `{"a": "b"}`, - key: `"a"`, - fallback: `"c"`, - expected: `"b"`, - }, - { - note: "basic case . not found", - object: `{"a": "b"}`, - key: `"c"`, - fallback: `"c"`, - expected: `"c"`, - }, - { - - note: "integer key . found", - object: "{1: 2}", - key: "1", - fallback: "3", - expected: "2", - }, - { - note: "integer key . not found", - object: "{1: 2}", - key: "2", - fallback: "3", - expected: "3", - }, - { - note: "complex value . found", - object: `{"a": {"b": "c"}}`, - key: `"a"`, - fallback: "true", - expected: `{"b": "c"}`, - }, - { - note: "complex value . not found", - object: `{"a": {"b": "c"}}`, - key: `"b"`, - fallback: "true", - expected: "true", - }, - } - - for _, tc := range cases { - rules := []string{ - fmt.Sprintf("p = x { x := object.get(%s, %s, %s) }", tc.object, tc.key, tc.fallback), - } - runTopDownTestCase(t, map[string]interface{}{}, tc.note, rules, tc.expected) - } -} - -func TestBuiltinObjectUnion(t *testing.T) { - cases := []struct { - note string - objectA string - objectB string - input string - expected interface{} - }{ - { - note: "both empty", - objectA: `{}`, - objectB: `{}`, - expected: `{}`, - }, - { - note: "left empty", - objectA: `{}`, - objectB: `{"a": 1}`, - expected: `{"a": 1}`, - }, - { - note: "right empty", - objectA: `{"a": 1}`, - objectB: `{}`, - expected: `{"a": 1}`, - }, - { - note: "base", - objectA: `{"a": 1}`, - objectB: `{"b": 2}`, - expected: `{"a": 1, "b": 2}`, - }, - { - note: "nested", - objectA: `{"a": {"b": {"c": 1}}}`, - objectB: `{"b": 2}`, - expected: `{"a": {"b": {"c": 1}}, "b": 2}`, - }, - { - note: "nested reverse", - objectA: `{"b": 2}`, - objectB: `{"a": {"b": {"c": 1}}}`, - expected: `{"a": {"b": {"c": 1}}, "b": 2}`, - }, - { - note: "conflict simple", - objectA: `{"a": 1}`, - objectB: `{"a": 2}`, - expected: `{"a": 2}`, - }, - { - note: "conflict nested and extra field", - objectA: `{"a": 1}`, - objectB: `{"a": {"b": {"c": 1}}, "d": 7}`, - expected: `{"a": {"b": {"c": 1}}, "d": 7}`, - }, - { - note: "conflict multiple", - objectA: `{"a": {"b": {"c": 1}}, "e": 1}`, - objectB: `{"a": {"b": "foo", "b1": "bar"}, "d": 7, "e": 17}`, - expected: `{"a": {"b": "foo", "b1": "bar"}, "d": 7, "e": 17}`, - }, - { - note: "error wrong lhs type", - objectA: `[1, 2, 3]`, - objectB: `{"b": 2}`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "object.union: invalid argument(s)")}, - }, - { - note: "error wrong lhs type input", - objectA: `input.a`, - objectB: `{"b": 2}`, - input: `{"a": [1, 2, 3]}`, - expected: &Error{Code: TypeErr, Message: "object.union: operand 1 must be object but got array"}, - }, - { - note: "error wrong rhs type", - objectA: `{"a": 1}`, - objectB: `[1, 2, 3]`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "object.union: invalid argument(s)")}, - }, - { - note: "error wrong rhs type input", - objectA: `{"a": 1}`, - objectB: `input.b`, - input: `{"b": [1, 2, 3]}`, - expected: &Error{Code: TypeErr, Message: "object.union: operand 2 must be object but got array"}, - }, - { - note: "error wrong both params", - objectA: `"foo"`, - objectB: `[1, 2, 3]`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "object.union: invalid argument(s)")}, - }, - } - - for _, tc := range cases { - rules := []string{ - fmt.Sprintf("p = x { x := object.union(%s, %s) }", tc.objectA, tc.objectB), - } - runTopDownTestCaseWithModules(t, map[string]interface{}{}, tc.note, rules, nil, tc.input, tc.expected) - } -} - -func TestBuiltinObjectRemove(t *testing.T) { - cases := []struct { - note string - object string - keys string - input string - expected interface{} - }{ - { - note: "base", - object: `{"a": 1, "b": {"c": 3}}`, - keys: `{"a"}`, - expected: `{"b": {"c": 3}}`, - }, - { - note: "multiple keys set", - object: `{"a": 1, "b": {"c": 3}, "d": 4}`, - keys: `{"d", "b"}`, - expected: `{"a": 1}`, - }, - { - note: "multiple keys array", - object: `{"a": 1, "b": {"c": 3}, "d": 4}`, - keys: `["d", "b"]`, - expected: `{"a": 1}`, - }, - { - note: "multiple keys object", - object: `{"a": 1, "b": {"c": 3}, "d": 4}`, - keys: `{"d": "", "b": 1}`, - expected: `{"a": 1}`, - }, - { - note: "multiple keys object nested", - object: `{"a": {"b": {"c": 2}}, "x": 123}`, - keys: `{"a": {"b": {"foo": "bar"}}}`, - expected: `{"x": 123}`, - }, - { - note: "empty object", - object: `{}`, - keys: `{"a", "b"}`, - expected: `{}`, - }, - { - note: "empty keys set", - object: `{"a": 1, "b": {"c": 3}}`, - keys: `set()`, - expected: `{"a": 1, "b": {"c": 3}}`, - }, - { - note: "empty keys array", - object: `{"a": 1, "b": {"c": 3}}`, - keys: `[]`, - expected: `{"a": 1, "b": {"c": 3}}`, - }, - { - note: "empty keys obj", - object: `{"a": 1, "b": {"c": 3}}`, - keys: `{}`, - expected: `{"a": 1, "b": {"c": 3}}`, - }, - { - note: "key doesnt exist", - object: `{"a": 1, "b": {"c": 3}}`, - keys: `{"z"}`, - expected: `{"a": 1, "b": {"c": 3}}`, - }, - { - note: "error invalid object param type set", - object: `{"a"}`, - keys: `{"a"}`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "object.remove: invalid argument(s)")}, - }, - { - note: "error invalid object param type bool", - object: `false`, - keys: `{"a"}`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "object.remove: invalid argument(s)")}, - }, - { - note: "error invalid object param type array input", - object: `input.x`, - keys: `{"a"}`, - input: `{"x": ["a"]}`, - expected: &Error{Code: TypeErr, Message: "object.remove: operand 1 must be object but got array"}, - }, - { - note: "error invalid object param type bool input", - object: `input.x`, - keys: `{"a"}`, - input: `{"x": false}`, - expected: &Error{Code: TypeErr, Message: "object.remove: operand 1 must be object but got boolean"}, - }, - { - note: "error invalid object param type number input", - object: `input.x`, - keys: `{"a"}`, - input: `{"x": 123}`, - expected: &Error{Code: TypeErr, Message: "object.remove: operand 1 must be object but got number"}, - }, - { - note: "error invalid object param type string input", - object: `input.x`, - keys: `{"a"}`, - input: `{"x": "foo"}`, - expected: &Error{Code: TypeErr, Message: "object.remove: operand 1 must be object but got string"}, - }, - { - note: "error invalid object param type nil input", - object: `input.x`, - keys: `{"a"}`, - input: `{"x": null}`, - expected: &Error{Code: TypeErr, Message: "object.remove: operand 1 must be object but got null"}, - }, - { - note: "error invalid key param type string", - object: `{"a": 1}`, - keys: `"a"`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "object.remove: invalid argument(s)")}, - }, - { - note: "error invalid key param type boolean", - object: `{"a": 1}`, - keys: `false`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "object.remove: invalid argument(s)")}, - }, - { - note: "error invalid key param type string input", - object: `{"a": 1}`, - keys: `input.x`, - input: `{"x": "foo"}`, - expected: &Error{Code: TypeErr, Message: "object.remove: operand 2 must be one of {object, string, array} but got string"}, - }, - { - note: "error invalid key param type boolean input", - object: `{"a": 1}`, - keys: `input.x`, - input: `{"x": true}`, - expected: &Error{Code: TypeErr, Message: "object.remove: operand 2 must be one of {object, string, array} but got boolean"}, - }, - { - note: "error invalid key param type number input", - object: `{"a": 1}`, - keys: `input.x`, - input: `{"x": 22}`, - expected: &Error{Code: TypeErr, Message: "object.remove: operand 2 must be one of {object, string, array} but got number"}, - }, - { - note: "error invalid key param type nil input", - object: `{"a": 1}`, - keys: `input.x`, - input: `{"x": null}`, - expected: &Error{Code: TypeErr, Message: "object.remove: operand 2 must be one of {object, string, array} but got null"}, - }, - } - - for _, tc := range cases { - rules := []string{ - fmt.Sprintf("p = x { x := object.remove(%s, %s) }", tc.object, tc.keys), - } - runTopDownTestCaseWithModules(t, map[string]interface{}{}, tc.note, rules, nil, tc.input, tc.expected) - } -} - -func TestBuiltinObjectRemoveIdempotent(t *testing.T) { - rule := ` - p { - # "base" should never be mutated - base := {"a": 1, "b": 2, "c": 3} - object.remove(base, {"a"}) == {"b": 2, "c": 3} - object.remove(base, {"b"}) == {"a": 1, "c": 3} - object.remove(base, {"c"}) == {"a": 1, "b": 2} - base == {"a": 1, "b": 2, "c": 3} - } - ` - runTopDownTestCase(t, map[string]interface{}{}, t.Name(), []string{rule}, "true") -} - -func TestBuiltinObjectRemoveNonStringKey(t *testing.T) { - rules := []string{ - `p { x := object.remove({"a": 1, [[7]]: 2}, {[[7]]}); x == {"a": 1} }`, - } - runTopDownTestCase(t, map[string]interface{}{}, "non string root", rules, "true") -} - -func TestBuiltinObjectFilter(t *testing.T) { - cases := []struct { - note string - object string - filters string - input string - expected interface{} - }{ - { - note: "base", - object: `{"a": {"b": {"c": 7, "d": 8}}, "e": 9}`, - filters: `{"a"}`, - expected: `{"a": {"b": {"c": 7, "d": 8}}}`, - }, - { - note: "multiple roots set", - object: `{"a": 1, "b": 2, "c": 3, "e": 9}`, - filters: `{"a", "e"}`, - expected: `{"a": 1, "e": 9}`, - }, - { - note: "multiple roots array", - object: `{"a": 1, "b": 2, "c": 3, "e": 9}`, - filters: `["a", "e"]`, - expected: `{"a": 1, "e": 9}`, - }, - { - note: "multiple roots object", - object: `{"a": 1, "b": 2, "c": 3, "e": 9}`, - filters: `{"a": "foo", "e": ""}`, - expected: `{"a": 1, "e": 9}`, - }, - { - note: "duplicate roots", - object: `{"a": {"b": {"c": 7, "d": 8}}, "e": 9}`, - filters: `{"a", "a"}`, - expected: `{"a": {"b": {"c": 7, "d": 8}}}`, - }, - { - note: "empty roots set", - object: `{"a": 7}`, - filters: `set()`, - expected: `{}`, - }, - { - note: "empty roots array", - object: `{"a": 7}`, - filters: `[]`, - expected: `{}`, - }, - { - note: "empty roots object", - object: `{"a": 7}`, - filters: `{}`, - expected: `{}`, - }, - { - note: "empty object", - object: `{}`, - filters: `{"a"}`, - expected: `{}`, - }, - { - note: "error invalid object param type set", - object: `{"a"}`, - filters: `{"a"}`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "object.filter: invalid argument(s)")}, - }, - { - note: "error invalid object param type bool", - object: `false`, - filters: `{"a"}`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "object.filter: invalid argument(s)")}, - }, - { - note: "error invalid object param type array input", - object: `input.x`, - filters: `{"a"}`, - input: `{"x": ["a"]}`, - expected: &Error{Code: TypeErr, Message: "object.filter: operand 1 must be object but got array"}, - }, - { - note: "error invalid object param type bool input", - object: `input.x`, - filters: `{"a"}`, - input: `{"x": false}`, - expected: &Error{Code: TypeErr, Message: "object.filter: operand 1 must be object but got boolean"}, - }, - { - note: "error invalid object param type number input", - object: `input.x`, - filters: `{"a"}`, - input: `{"x": 123}`, - expected: &Error{Code: TypeErr, Message: "object.filter: operand 1 must be object but got number"}, - }, - { - note: "error invalid object param type string input", - object: `input.x`, - filters: `{"a"}`, - input: `{"x": "foo"}`, - expected: &Error{Code: TypeErr, Message: "object.filter: operand 1 must be object but got string"}, - }, - { - note: "error invalid object param type nil input", - object: `input.x`, - filters: `{"a"}`, - input: `{"x": null}`, - expected: &Error{Code: TypeErr, Message: "object.filter: operand 1 must be object but got null"}, - }, - { - note: "error invalid key param type string", - object: `{"a": 1}`, - filters: `"a"`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "object.filter: invalid argument(s)")}, - }, - { - note: "error invalid key param type boolean", - object: `{"a": 1}`, - filters: `false`, - expected: ast.Errors{ast.NewError(ast.TypeErr, nil, "object.filter: invalid argument(s)")}, - }, - { - note: "error invalid key param type string input", - object: `{"a": 1}`, - filters: `input.x`, - input: `{"x": "foo"}`, - expected: &Error{Code: TypeErr, Message: "object.filter: operand 2 must be one of {object, string, array} but got string"}, - }, - { - note: "error invalid key param type boolean input", - object: `{"a": 1}`, - filters: `input.x`, - input: `{"x": true}`, - expected: &Error{Code: TypeErr, Message: "object.filter: operand 2 must be one of {object, string, array} but got boolean"}, - }, - { - note: "error invalid key param type number input", - object: `{"a": 1}`, - filters: `input.x`, - input: `{"x": 22}`, - expected: &Error{Code: TypeErr, Message: "object.filter: operand 2 must be one of {object, string, array} but got number"}, - }, - { - note: "error invalid key param type nil input", - object: `{"a": 1}`, - filters: `input.x`, - input: `{"x": null}`, - expected: &Error{Code: TypeErr, Message: "object.filter: operand 2 must be one of {object, string, array} but got null"}, - }, - } - - for _, tc := range cases { - rules := []string{ - fmt.Sprintf("p = x { x := object.filter(%s, %s) }", tc.object, tc.filters), - } - runTopDownTestCaseWithModules(t, map[string]interface{}{}, tc.note, rules, nil, tc.input, tc.expected) - } -} - -func TestBuiltinObjectFilterNonStringKey(t *testing.T) { - rules := []string{ - `p { x := object.filter({"a": 1, [[7]]: 2}, {[[7]]}); x == {[[7]]: 2} }`, - } - runTopDownTestCase(t, map[string]interface{}{}, "non string root", rules, "true") -} - -func TestBuiltinObjectFilterIdempotent(t *testing.T) { - rule := ` - p { - # "base" should never be mutated - base := {"a": 1, "b": 2, "c": 3} - object.filter(base, {"a"}) == {"a": 1} - object.filter(base, {"b"}) == {"b": 2} - object.filter(base, {"c"}) == {"c": 3} - base == {"a": 1, "b": 2, "c": 3} - } - ` - runTopDownTestCase(t, map[string]interface{}{}, t.Name(), []string{rule}, "true") -} diff --git a/topdown/parse_test.go b/topdown/parse_test.go deleted file mode 100644 index e5f69d4bff..0000000000 --- a/topdown/parse_test.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2018 The OPA Authors. All rights reserved. -// Use of this source code is governed by an Apache2 -// license that can be found in the LICENSE file. - -package topdown - -import ( - "testing" -) - -func TestRegoParseModule(t *testing.T) { - - data := map[string]interface{}{ - "ok": `package foo.bar - - import data.a - - p { a = true }`, - "err": `package foo.`, - } - - runTopDownTestCase(t, data, "ok", []string{ - `p = x { rego.parse_module("x.rego", data.ok, module); x = module["package"].path[1].value }`}, `"foo"`) - - runTopDownTestCase(t, data, "error", []string{ - `p = x { rego.parse_module("x.rego", data.err, x) }`}, &Error{Code: BuiltinErr, Message: "rego_parse_error: unexpected eof token: expected ident"}) - -} diff --git a/topdown/reachable_test.go b/topdown/reachable_test.go deleted file mode 100644 index 4bca9e4383..0000000000 --- a/topdown/reachable_test.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2020 The OPA Authors. All rights reserved. -// Use of this source code is governed by an Apache2 -// license that can be found in the LICENSE file. - -package topdown - -import ( - "testing" -) - -func TestReachable(t *testing.T) { - data := map[string]interface{}{} - modules := []string{} - tests := []struct { - note string - rules []string - expected interface{} - input string - }{ - { - "empty", - []string{`p = x {x := graph.reachable({}, {"a"})}`}, - `[]`, - `{}`, - }, - { - "cycle", - []string{ - `p = x { - x := sort(graph.reachable( - { - "a": {"b"}, - "b": {"c"}, - "c": {"a"}, - }, - {"a"} - )) - }`}, - `["a", "b", "c"]`, - `{}`, - }, - { - "components", - []string{ - `p = x { - x := sort(graph.reachable( - { - "a": {"b", "c"}, - "b": {"d"}, - "c": {"d"}, - "d": set(), - "e": {"f"}, - "f": {"e"}, - "x": {"x"}, - }, - {"b", "e"} - )) - }`}, - `["b", "d", "e", "f"]`, - `{}`, - }, - { - "arrays", - []string{ - `p = x { - x := sort(graph.reachable( - { - "a": ["b"], - "b": ["c"], - "c": ["a"], - }, - ["a"] - )) - }`}, - `["a", "b", "c"]`, - `{}`, - }, - { - "malformed 1", - []string{`p = x {x := graph.reachable(input.graph, input.initial)}`}, - `[]`, - `{"graph": 1, "initial": [1]}`, - }, - { - "malformed 2", - []string{`p = x {x := graph.reachable(input.graph, input.initial)}`}, - `["a"]`, - `{"graph": {"a": null}, "initial": ["a"]}`, - }, - { - "malformed 3", - []string{`p = x {x := graph.reachable(input.graph, input.initial)}`}, - `[]`, - `{"graph": {"a": []}, "initial": "a"}`, - }, - } - - for _, tc := range tests { - runTopDownTestCaseWithModules(t, data, tc.note, tc.rules, modules, tc.input, tc.expected) - } -} diff --git a/topdown/regex_test.go b/topdown/regex_test.go deleted file mode 100644 index b9d3d9d86a..0000000000 --- a/topdown/regex_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package topdown - -import ( - "encoding/json" - "testing" -) - -func TestRegexIsValid(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - { - note: "bad operand type", - rules: []string{"p = x { regex.is_valid(data.num, x) }"}, - expected: "false", - }, - { - note: "bad pattern", - rules: []string{"p = x { regex.is_valid(`++`, x) }"}, - expected: "false", - }, - { - note: "good pattern", - rules: []string{"p = x { regex.is_valid(`.+`, x) }"}, - expected: "true", - }, - } - for _, tc := range tests { - runTopDownTestCase(t, map[string]interface{}{"num": json.Number("10")}, tc.note, tc.rules, tc.expected) - } -} - -func TestRegexMatchTemplate(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"matches wildcard with {}", []string{`p[x] { regex.template_match("urn:foo:{.*}", "urn:foo:bar:baz", "{", "}", x) }`}, "[true]"}, - {"matches wildcard with <>", []string{`p[x] { regex.template_match("urn:foo:<.*>", "urn:foo:bar:baz", "<", ">", x) }`}, "[true]"}, - } - - for _, tc := range tests { - runTopDownTestCase(t, map[string]interface{}{}, tc.note, tc.rules, tc.expected) - } -} - -func TestRegexFind(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"finds all match values", []string{`p[x] { x = regex.find_n("a.", "paranormal", -1) }`}, `[["ar", "an", "al"]]`}, - {"finds specified number of match values", []string{`p[x] { x = regex.find_n("a.", "paranormal", 2) }`}, `[["ar", "an"]]`}, - {"finds no matching values", []string{`p[x] { x = regex.find_n("bork", "paranormal", -1) }`}, `[[]]`}, - } - - for _, tc := range tests { - runTopDownTestCase(t, map[string]interface{}{}, tc.note, tc.rules, tc.expected) - } -} - -func TestRegexFindAllStringSubmatch(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"finds no matches", []string{`p[x] { x = regex.find_all_string_submatch_n("a(x*)b", "-", -1) }`}, `[[]]`}, - {"single match without captures", []string{`p[x] { x = regex.find_all_string_submatch_n("a(x*)b", "-ab-", -1) }`}, `[[["ab", ""]]]`}, - {"single match with a capture", []string{`p[x] { x = regex.find_all_string_submatch_n("a(x*)b", "-axxb-", -1) }`}, `[[["axxb", "xx"]]]`}, - {"multiple matches with captures-1", []string{`p[x] { x = regex.find_all_string_submatch_n("a(x*)b", "-ab-axb-", -1) }`}, `[[["ab", ""], ["axb", "x"]]]`}, - {"multiple matches with captures-2", []string{`p[x] { x = regex.find_all_string_submatch_n("a(x*)b", "-axxb-ab-", -1) }`}, `[[["axxb", "xx"], ["ab", ""]]]`}, - {"multiple patterns, matches, and captures", []string{`p[x] { x = regex.find_all_string_submatch_n("[^aouiye]([aouiye])([^aouiye])?", "somestri", -1) }`}, `[[["som", "o", "m"], ["ri", "i", ""]]]`}, - {"multiple patterns, matches, and captures with specified number of matches", []string{`p[x] { x = regex.find_all_string_submatch_n("[^aouiye]([aouiye])([^aouiye])?", "somestri", 1) }`}, `[[["som", "o", "m"]]]`}, - } - - for _, tc := range tests { - runTopDownTestCase(t, map[string]interface{}{}, tc.note, tc.rules, tc.expected) - } -} diff --git a/topdown/semver_test.go b/topdown/semver_test.go deleted file mode 100644 index 6f70b10cfe..0000000000 --- a/topdown/semver_test.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2020 The OPA Authors. All rights reserved. -// Use of this source code is governed by an Apache2 -// license that can be found in the LICENSE file. - -package topdown - -import ( - "testing" - - "github.com/open-policy-agent/opa/ast" -) - -func TestSemVerCompare(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"a < b", []string{`p = x { x = semver.compare("1.0.0", "2.0.0") }`}, "-1"}, - {"a > b", []string{`p = x { x = semver.compare("2.0.0", "1.0.0") }`}, "1"}, - {"a == b", []string{`p = x { x = semver.compare("1.0.0", "1.0.0") }`}, "0"}, - { - "invalid type a", - []string{`p = x { x = semver.compare(1, "1.0.0") }`}, - ast.Errors{ast.NewError(ast.TypeErr, nil, "semver.compare: invalid argument(s)")}, - }, - { - "invalid type b", - []string{`p = x { x = semver.compare("1.0.0", false) }`}, - ast.Errors{ast.NewError(ast.TypeErr, nil, "semver.compare: invalid argument(s)")}, - }, - { - "invalid version a", - []string{`p = x { x = semver.compare("1", "1.0.0") }`}, - &Error{Code: BuiltinErr, Message: `semver.compare("1", "1.0.0"): eval_builtin_error: semver.compare: operand 1: string "1" is not a valid SemVer`}, - }, - { - "invalid version b", - []string{`p = x { x = semver.compare("1.0.0", "1") }`}, - &Error{Code: BuiltinErr, Message: `semver.compare("1.0.0", "1"): eval_builtin_error: semver.compare: operand 2: string "1" is not a valid SemVer`}, - }, - } - - data := map[string]interface{}{} - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestSemVerIsValid(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"valid", []string{`p = x { x = semver.is_valid("1.0.0") }`}, "true"}, - {"invalid version", []string{`p = x { x = semver.is_valid("1") }`}, "false"}, - {"invalid type", []string{`p = x { x = semver.is_valid(1) }`}, "false"}, - } - - data := map[string]interface{}{} - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} diff --git a/topdown/sets_test.go b/topdown/sets_test.go deleted file mode 100644 index 4be42e77c3..0000000000 --- a/topdown/sets_test.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2018 The OPA Authors. All rights reserved. -// Use of this source code is governed by an Apache2 -// license that can be found in the LICENSE file. - -package topdown - -import ( - "testing" -) - -// TestIntersection tests intersection of the given input sets -func TestIntersection(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"intersection_0_sets", []string{`p = x { intersection(set(), x) }`}, "[]"}, - {"intersection_2_sets", []string{`p = x { intersection({set(), {1, 2}}, x) }`}, "[]"}, - {"intersection_2_sets", []string{`p = x { s1 = {1, 2, 3}; s2 = {2}; intersection({s1, s2}, x) }`}, "[2]"}, - {"intersection_3_sets", []string{`p = x { s1 = {1, 2, 3}; s2 = {2, 3, 4}; s3 = {4, 5, 6}; intersection({s1, s2, s3}, x) }`}, "[]"}, - {"intersection_4_sets", []string{`p = x { s1 = {"a", "b", "c", "d"}; s2 = {"b", "c", "d"}; s3 = {"c", "d"}; s4 = {"d"}; intersection({s1, s2, s3, s4}, x) }`}, "[\"d\"]"}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -// TestUnion tests union of the given input sets -func TestUnion(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"union_0_sets", []string{`p = x { union(set(), x) }`}, "[]"}, - {"union_2_sets", []string{`p = x { union({set(), {1, 2}}, x) }`}, "[1, 2]"}, - {"union_2_sets", []string{`p = x { s1 = {1, 2, 3}; s2 = {2}; union({s1, s2}, x) }`}, "[1, 2, 3]"}, - {"union_3_sets", []string{`p = x { s1 = {1, 2, 3}; s2 = {2, 3, 4}; s3 = {4, 5, 6}; union({s1, s2, s3}, x) }`}, "[1, 2, 3, 4, 5, 6]"}, - {"union_4_sets", []string{`p = x { s1 = {"a", "b", "c", "d"}; s2 = {"b", "c", "d"}; s3 = {"c", "d"}; s4 = {"d"}; union({s1, s2, s3, s4}, x) }`}, "[\"a\", \"b\", \"c\", \"d\"]"}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} diff --git a/topdown/strings_test.go b/topdown/strings_test.go deleted file mode 100644 index f8583767e3..0000000000 --- a/topdown/strings_test.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2019 The OPA Authors. All rights reserved. -// Use of this source code is governed by an Apache2 -// license that can be found in the LICENSE file. - -package topdown - -import "testing" - -func TestBuiltinTrim(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"trims '!¡' from string", []string{`p[x] { x := trim("¡¡¡foo, bar!!!", "!¡") }`}, `["foo, bar"]`}, - {"trims nothing from string", []string{`p[x] { x := trim("¡¡¡foo, bar!!!", "i") }`}, `["¡¡¡foo, bar!!!"]`}, - } - - for _, tc := range tests { - runTopDownTestCase(t, map[string]interface{}{}, tc.note, tc.rules, tc.expected) - } -} - -func TestBuiltinTrimLeft(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"trims leading '!¡' from string", []string{`p[x] { x := trim_left("¡¡¡foo, bar!!!", "!¡") }`}, `["foo, bar!!!"]`}, - {"trims nothing from string", []string{`p[x] { x := trim_left("!!!foo, bar¡¡¡", "¡") }`}, `["!!!foo, bar¡¡¡"]`}, - } - - for _, tc := range tests { - runTopDownTestCase(t, map[string]interface{}{}, tc.note, tc.rules, tc.expected) - } -} - -func TestBuiltinTrimPrefix(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"trims prefix '!¡' from string", []string{`p[x] { x := trim_prefix("¡¡¡foo, bar!!!", "¡¡¡foo") }`}, `[", bar!!!"]`}, - {"trims nothing from string", []string{`p[x] { x := trim_prefix("¡¡¡foo, bar!!!", "¡¡¡bar") }`}, `["¡¡¡foo, bar!!!"]`}, - } - - for _, tc := range tests { - runTopDownTestCase(t, map[string]interface{}{}, tc.note, tc.rules, tc.expected) - } -} - -func TestBuiltinTrimRight(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"trims trailing '!¡' from string", []string{`p[x] { x := trim_right("¡¡¡foo, bar!!!", "!¡") }`}, `["¡¡¡foo, bar"]`}, - {"trims nothing from string", []string{`p[x] { x := trim_right("!!!foo, bar¡¡¡", "!") }`}, `["!!!foo, bar¡¡¡"]`}, - } - - for _, tc := range tests { - runTopDownTestCase(t, map[string]interface{}{}, tc.note, tc.rules, tc.expected) - } -} - -func TestBuiltinTrimSuffix(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"trims suffix '!¡' from string", []string{`p[x] { x := trim_suffix("¡¡¡foo, bar!!!", ", bar!!!") }`}, `["¡¡¡foo"]`}, - {"trims nothing from string", []string{`p[x] { x := trim_suffix("¡¡¡foo, bar!!!", ", foo!!!") }`}, `["¡¡¡foo, bar!!!"]`}, - } - - for _, tc := range tests { - runTopDownTestCase(t, map[string]interface{}{}, tc.note, tc.rules, tc.expected) - } -} - -func TestBuiltinTrimSpace(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"trims all leading and trailing white space from string", []string{`p[x] { x := trim_space(" \t\n foo, bar \n\t\r\n") }`}, `["foo, bar"]`}, - {"trims nothing from string", []string{`p[x] { x := trim_space("foo, bar") }`}, `["foo, bar"]`}, - } - - for _, tc := range tests { - runTopDownTestCase(t, map[string]interface{}{}, tc.note, tc.rules, tc.expected) - } -} - -func TestReplaceN(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"replace multiple patterns", []string{`p[x] { x = strings.replace_n({"<": "<", ">": ">"}, "This is HTML!") }`}, `["This is <b>HTML</b>!"]`}, - {"find no patterns", []string{`p[x] { x = strings.replace_n({"old1": "new1", "old2": "new2"}, "Everything is new1, new2") }`}, `["Everything is new1, new2"]`}, - } - - for _, tc := range tests { - runTopDownTestCase(t, map[string]interface{}{}, tc.note, tc.rules, tc.expected) - } -} diff --git a/topdown/testdata/cases/jwtbuiltins/test-jwtbuiltins-0400.yaml b/topdown/testdata/cases/jwtbuiltins/test-jwtbuiltins-0400.yaml index 43bf590414..30da1f4460 100644 --- a/topdown/testdata/cases/jwtbuiltins/test-jwtbuiltins-0400.yaml +++ b/topdown/testdata/cases/jwtbuiltins/test-jwtbuiltins-0400.yaml @@ -89,6 +89,15 @@ cases: p = [x, y, z] { io.jwt.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiAiMCIsImlzcyI6ICJub3Qgb3BhIiwgImlzcyI6ICJhbHNvIG5vdCBvcGEiLCAiaXNzIjogIm9wYSJ9.XmVoLoHI3pxMtMO_WRONMSJzGUDP9pDjy8Jp0_tdRXY", [x, y, z]) } + # The test below checks that payloads with duplicate keys + # in their encoding produce a token object that binds the key + # to the last occurring value, as per RFC 7519 Section 4. + # It tests a payload encoding that has 3 duplicates of the + # "iss" key, with the values "not opa", "also not opa" and + # "opa", in that order. + # Go's json.Unmarshal exhibits this behavior, but it is not + # documented, so this test is meant to catch that behavior + # if it changes. note: jwtbuiltins/duplicate-keys query: data.generated.p = x want_result: diff --git a/topdown/tokens_test.go b/topdown/tokens_test.go index fdad033e40..2ef51e85eb 100644 --- a/topdown/tokens_test.go +++ b/topdown/tokens_test.go @@ -7,7 +7,6 @@ import ( "crypto/rsa" "encoding/base64" "encoding/json" - "errors" "fmt" "os" "strings" @@ -189,292 +188,6 @@ func TestParseTokenHeader(t *testing.T) { }) } -func TestTopDownJWTEncodeSignPayloadErrors(t *testing.T) { - - const examplePayloadError = `{"iss:"joe",` + "\r\n" + ` "exp":1300819380,` + "\r\n" + ` "http://example.com/is_root":true}` - const hs256Hdr = `{"typ":"JWT",` + "\r\n " + `"alg":"HS256"}` - - params := []struct { - note string - input1 string - input2 string - input3 string - result string - err string - }{ - { - "No Payload", - hs256Hdr, - "", - `{ -"kty":"oct", -"k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow" -}`, - - "", - "type is JWT but payload is not JSON", - }, - { - "Payload JSON Error", - hs256Hdr, - examplePayloadError, - `{ -"kty":"oct", -"k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow" -}`, - - "", - "type is JWT but payload is not JSON", - }, - { - "Non JSON Error", - hs256Hdr, - "e", - `{ -"kty":"oct", -"k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow" -}`, - - "", - "type is JWT but payload is not JSON", - }, - } - type test struct { - note string - rules []string - expected interface{} - } - var tests []test - - for _, p := range params { - var exp interface{} - exp = fmt.Sprintf(`%s`, p.result) - if p.err != "" { - exp = &Error{Code: BuiltinErr, Message: p.err} - } - - tests = append(tests, test{ - p.note, - []string{fmt.Sprintf(`p = x { io.jwt.encode_sign_raw(%q, %q, %q, x) }`, p.input1, p.input2, p.input3)}, - exp, - }) - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } - -} - -func TestTopDownJWTEncodeSignHeaderErrors(t *testing.T) { - - const examplePayload = `{"iss":"joe",` + "\r\n" + ` "exp":1300819380,` + "\r\n" + ` "http://example.com/is_root":true}` - const hs256HdrError = `{"typ:"JWT",` + "\r\n " + `"alg":"HS256"}` - - params := []struct { - note string - input1 string - input2 string - input3 string - result string - err string - }{ - { - "Unknown signature algorithm", - hs256HdrError, - examplePayload, - `{ -"kty":"oct", -"k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow" -}`, - - "", - "invalid character", - }, - { - "Unknown signature algorithm", - `{"alg":"dummy"}`, - examplePayload, - `{ -"kty":"oct", -"k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow" -}`, - - "", - "Unknown signature algorithm", - }, - { - "Empty JSON header Error", - "{}", - examplePayload, - `{ -"kty":"oct", -"k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow" -}`, - - "", - "unsupported signature algorithm", - }, - { - "Empty headers input error", - "", - examplePayload, - `{ -"kty":"oct", -"k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow" -}`, - - "", - "unexpected end of JSON input", - }, - { - "No JSON Error", - "e", - examplePayload, - `{ -"kty":"oct", -"k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow" -}`, - - "", - "invalid character", - }, - } - type test struct { - note string - rules []string - expected interface{} - } - var tests []test - - for _, p := range params { - var exp interface{} - exp = fmt.Sprintf(`%s`, p.result) - if p.err != "" { - exp = &Error{Code: BuiltinErr, Message: p.err} - } - - tests = append(tests, test{ - p.note, - []string{fmt.Sprintf(`p = x { io.jwt.encode_sign_raw(%q, %q, %q, x) }`, p.input1, p.input2, p.input3)}, - exp, - }) - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownJWTEncodeSignRaw(t *testing.T) { - - const examplePayload = `{"iss":"joe",` + "\r\n" + ` "exp":1300819380,` + "\r\n" + ` "http://example.com/is_root":true}` - const hs256Hdr = `{"typ":"JWT",` + "\r\n " + `"alg":"HS256"}` - const rs256Hdr = `{"alg":"RS256"}` - const hs256HdrPlain = `{"typ":"text/plain",` + "\r\n " + `"alg":"HS256"}` - const symmetricKey = `{ -"kty":"oct", -"k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow" -}` - const rsaKey = `{ - "kty":"RSA", - "n":"ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddxHmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMsD1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSHSXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ", - "e":"AQAB", - "d":"Eq5xpGnNCivDflJsRQBXHx1hdR1k6Ulwe2JZD50LpXyWPEAeP88vLNO97IjlA7_GQ5sLKMgvfTeXZx9SE-7YwVol2NXOoAJe46sui395IW_GO-pWJ1O0BkTGoVEn2bKVRUCgu-GjBVaYLU6f3l9kJfFNS3E0QbVdxzubSu3Mkqzjkn439X0M_V51gfpRLI9JYanrC4D4qAdGcopV_0ZHHzQlBjudU2QvXt4ehNYTCBr6XCLQUShb1juUO1ZdiYoFaFQT5Tw8bGUl_x_jTj3ccPDVZFD9pIuhLhBOneufuBiB4cS98l2SR_RQyGWSeWjnczT0QU91p1DhOVRuOopznQ", - "p":"4BzEEOtIpmVdVEZNCqS7baC4crd0pqnRH_5IB3jw3bcxGn6QLvnEtfdUdiYrqBdss1l58BQ3KhooKeQTa9AB0Hw_Py5PJdTJNPY8cQn7ouZ2KKDcmnPGBY5t7yLc1QlQ5xHdwW1VhvKn-nXqhJTBgIPgtldC-KDV5z-y2XDwGUc", - "q":"uQPEfgmVtjL0Uyyx88GZFF1fOunH3-7cepKmtH4pxhtCoHqpWmT8YAmZxaewHgHAjLYsp1ZSe7zFYHj7C6ul7TjeLQeZD_YwD66t62wDmpe_HlB-TnBA-njbglfIsRLtXlnDzQkv5dTltRJ11BKBBypeeF6689rjcJIDEz9RWdc", - "dp":"BwKfV3Akq5_MFZDFZCnW-wzl-CCo83WoZvnLQwCTeDv8uzluRSnm71I3QCLdhrqE2e9YkxvuxdBfpT_PI7Yz-FOKnu1R6HsJeDCjn12Sk3vmAktV2zb34MCdy7cpdTh_YVr7tss2u6vneTwrA86rZtu5Mbr1C1XsmvkxHQAdYo0", - "dq":"h_96-mK1R_7glhsum81dZxjTnYynPbZpHziZjeeHcXYsXaaMwkOlODsWa7I9xXDoRwbKgB719rrmI2oKr6N3Do9U0ajaHF-NKJnwgjMd2w9cjz3_-kyNlxAr2v4IKhGNpmM5iIgOS1VZnOZ68m6_pbLBSp3nssTdlqvd0tIiTHU", - "qi":"IYd7DHOhrWvxkwPQsRM2tOgrjbcrfvtQJipd-DlcxyVuuM9sQLdgjVk2oy26F0EmpScGLq2MowX7fhd_QJQ3ydy5cY7YIBi87w93IKLEdfnbJtoOPLUW0ITrJReOgo1cq9SbsxYawBgfp_gh6A5603k2-ZQwVK0JKSHuLFkuQ3U" - }` - - params := []struct { - note string - input1 string - input2 string - input3 string - result string - err string - }{ - { - "https://tools.ietf.org/html/rfc7515#appendix-A.1", - "`" + hs256Hdr + "`", - "`" + examplePayload + "`", - "`" + symmetricKey + "`", - - `"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"`, - "", - }, - { - "No Payload but Media Type is Plain", - "`" + hs256HdrPlain + "`", - "`" + "" + "`", - "`" + symmetricKey + "`", - - `"eyJ0eXAiOiJ0ZXh0L3BsYWluIiwNCiAiYWxnIjoiSFMyNTYifQ..sXoGQMWwM-SmX495-htA7kndgbkwz1PnqsDeY275gnI"`, - "", - }, - { - "text/plain media type", - "`" + hs256HdrPlain + "`", - "`" + "e" + "`", - "`" + symmetricKey + "`", - - `"eyJ0eXAiOiJ0ZXh0L3BsYWluIiwNCiAiYWxnIjoiSFMyNTYifQ.ZQ.oO8Vnc4Jv7-J231a1bEcQrgXfKbNW-kEvVY7BP1v5rM"`, - "", - }, - { - "Empty JSON payload", - "`" + hs256Hdr + "`", - "`" + "{}" + "`", - "`" + symmetricKey + "`", - - `"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.e30.KAml6HRetE0sq22SYNh_CQExhf-X31ChYTfGwUBIWu8"`, - "", - }, - { - "https://tools.ietf.org/html/rfc7515#appendix-A.2", - "`" + rs256Hdr + "`", - "`" + examplePayload + "`", - "`" + rsaKey + "`", - - `"eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw"`, - "", - }, - } - type test struct { - note string - rules []string - expected interface{} - } - var rawTests []test - - for _, p := range params { - var exp interface{} - exp = fmt.Sprintf(`%s`, p.result) - if p.err != "" { - exp = &Error{Code: BuiltinErr, Message: p.err} - } - - rawTests = append(rawTests, test{ - p.note, - []string{fmt.Sprintf(`p = x { io.jwt.encode_sign_raw(%s, %s, %s, x) }`, p.input1, p.input2, p.input3)}, - exp, - }) - } - - data := loadSmallTestData() - - for _, tc := range rawTests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } - -} - func TestTopDownJWTEncodeSignES256(t *testing.T) { const examplePayload = `{"iss":"joe",` + "\r\n" + ` "exp":1300819380,` + "\r\n" + ` "http://example.com/is_root":true}` @@ -717,1242 +430,3 @@ func TestTopDownJWTEncodeSignES512(t *testing.T) { t.Fatal("Failed to verify message") } } - -func TestTopDownJWTBuiltins(t *testing.T) { - params := []struct { - note string - input string - header string - payload string - signature string - err string - }{ - { - "simple", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIwIiwiaXNzIjoib3BhIn0.XmVoLoHI3pxMtMO_WRONMSJzGUDP9pDjy8Jp0_tdRXY`, - `{ "alg": "HS256", "typ": "JWT" }`, - `{ "sub": "0", "iss": "opa" }`, - `5e65682e81c8de9c4cb4c3bf59138d3122731940cff690e3cbc269d3fb5d4576`, - "", - }, - { - "simple-non-registered", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuZXciOiJJIGFtIGEgdXNlciBjcmVhdGVkIGZpZWxkIiwiaXNzIjoib3BhIn0.6UmjsclVDGD9jcmX_F8RJzVgHtUZuLu2pxkF_UEQCrE`, - `{ "alg": "HS256", "typ": "JWT" }`, - `{ "new": "I am a user created field", "iss": "opa" }`, - `e949a3b1c9550c60fd8dc997fc5f112735601ed519b8bbb6a71905fd41100ab1`, - "", - }, - { - "no-support-jwe", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImVuYyI6ImJsYWgifQ.eyJuZXciOiJJIGFtIGEgdXNlciBjcmVhdGVkIGZpZWxkIiwiaXNzIjoib3BhIn0.McGUb1e-UviZKy6UyQErNNQzEUgeV25Buwk7OHOa8U8`, - ``, - ``, - ``, - "JWT is a JWE object, which is not supported", - }, - { - "no-periods", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9eyJzdWIiOiIwIiwiaXNzIjoib3BhIn0XmVoLoHI3pxMtMO_WRONMSJzGUDP9pDjy8Jp0_tdRXY`, - ``, - ``, - ``, - "encoded JWT had no period separators", - }, - { - "wrong-period-count", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXV.CJ9eyJzdWIiOiIwIiwiaXNzIjoib3BhIn0XmVoLoHI3pxMtMO_WRONMSJzGUDP9pDjy8Jp0_tdRXY`, - ``, - ``, - ``, - "encoded JWT must have 3 sections, found 2", - }, - { - "bad-header-encoding", - `eyJhbGciOiJIU^%zI1NiI+sInR5cCI6IkpXVCJ9.eyJzdWIiOiIwIiwiaXNzIjoib3BhIn0.XmVoLoHI3pxMtMO_WRONMSJzGUDP9pDjy8Jp0_tdRXY`, - ``, - ``, - ``, - "JWT header had invalid encoding: illegal base64 data at input byte 13", - }, - { - "bad-payload-encoding", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIwIiwia/XNzIjoib3BhIn0.XmVoLoHI3pxMtMO_WRONMSJzGUDP9pDjy8Jp0_tdRXY`, - ``, - ``, - ``, - "JWT payload had invalid encoding: illegal base64 data at input byte 17", - }, - { - "bad-signature-encoding", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIwIiwiaXNzIjoib3BhIn0.XmVoLoHI3pxMtMO(_WRONMSJzGUDP9pDjy8Jp0_tdRXY`, - ``, - ``, - ``, - "JWT signature had invalid encoding: illegal base64 data at input byte 15", - }, - { - "nested", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkpXVCJ9.ImV5SmhiR2NpT2lKSVV6STFOaUlzSW5SNWNDSTZJa3BYVkNKOS5leUp6ZFdJaU9pSXdJaXdpYVhOeklqb2liM0JoSW4wLlhtVm9Mb0hJM3B4TXRNT19XUk9OTVNKekdVRFA5cERqeThKcDBfdGRSWFki.8W0qx4mLxslmZl7wEMUWBxH7tST3XsEuWXxesXqFnRI`, - `{ "alg": "HS256", "typ": "JWT" }`, - `{ "sub": "0", "iss": "opa" }`, - `5e65682e81c8de9c4cb4c3bf59138d3122731940cff690e3cbc269d3fb5d4576`, - "", - }, - { - "double-nested", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkpXVCJ9.ImV5SmhiR2NpT2lKSVV6STFOaUlzSW5SNWNDSTZJa3BYVkNJc0ltTjBlU0k2SWtwWFZDSjkuSW1WNVNtaGlSMk5wVDJsS1NWVjZTVEZPYVVselNXNVNOV05EU1RaSmEzQllWa05LT1M1bGVVcDZaRmRKYVU5cFNYZEphWGRwWVZoT2VrbHFiMmxpTTBKb1NXNHdMbGh0Vm05TWIwaEpNM0I0VFhSTlQxOVhVazlPVFZOS2VrZFZSRkE1Y0VScWVUaEtjREJmZEdSU1dGa2kuOFcwcXg0bUx4c2xtWmw3d0VNVVdCeEg3dFNUM1hzRXVXWHhlc1hxRm5SSSI.U8rwnGAJ-bJoGrAYKEzNtbJQWd3x1eW0Y25nLKHDCgo`, - `{ "alg": "HS256", "typ": "JWT" }`, - `{ "sub": "0", "iss": "opa" }`, - `5e65682e81c8de9c4cb4c3bf59138d3122731940cff690e3cbc269d3fb5d4576`, - "", - }, - { - "complex-values", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIwIiwiaXNzIjoib3BhIiwiZXh0Ijp7ImFiYyI6IjEyMyIsImNiYSI6WzEwLCIxMCJdfX0.IIxF-uJ6i4K5Dj71xNLnUeqB9jmujl6ujTInhii1PxE`, - `{ "alg": "HS256", "typ": "JWT" }`, - `{ "sub": "0", "iss": "opa", "ext": { "abc": "123", "cba": [10, "10"] } }`, - `208c45fae27a8b82b90e3ef5c4d2e751ea81f639ae8e5eae8d32278628b53f11`, - "", - }, - // The test below checks that payloads with duplicate keys - // in their encoding produce a token object that binds the key - // to the last occurring value, as per RFC 7519 Section 4. - // It tests a payload encoding that has 3 duplicates of the - // "iss" key, with the values "not opa", "also not opa" and - // "opa", in that order. - // Go's json.Unmarshal exhibits this behavior, but it is not - // documented, so this test is meant to catch that behavior - // if it changes. - { - "duplicate-keys", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiAiMCIsImlzcyI6ICJub3Qgb3BhIiwgImlzcyI6ICJhbHNvIG5vdCBvcGEiLCAiaXNzIjogIm9wYSJ9.XmVoLoHI3pxMtMO_WRONMSJzGUDP9pDjy8Jp0_tdRXY`, - `{ "alg": "HS256", "typ": "JWT" }`, - `{ "sub": "0", "iss": "opa" }`, - `5e65682e81c8de9c4cb4c3bf59138d3122731940cff690e3cbc269d3fb5d4576`, - "", - }, - } - - type test struct { - note string - rules []string - expected interface{} - } - tests := []test{} - - for _, p := range params { - var exp interface{} - exp = fmt.Sprintf(`[%s, %s, "%s"]`, p.header, p.payload, p.signature) - if p.err != "" { - exp = &Error{Code: BuiltinErr, Message: p.err} - } - - tests = append(tests, test{ - p.note, - []string{fmt.Sprintf(`p = [x, y, z] { io.jwt.decode("%s", [x, y, z]) }`, p.input)}, - exp, - }) - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -const ( - certPem = `-----BEGIN CERTIFICATE-----\nMIIFiDCCA3ACCQCGV6XsfG/oRTANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMC\nVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFTATBgNVBAcMDFJlZHdvb2QgQ2l0eTEO\nMAwGA1UECgwFU3R5cmExDDAKBgNVBAsMA0RldjESMBAGA1UEAwwJbG9jYWxob3N0\nMRgwFgYJKoZIhvcNAQkBFglhc2hAc3R5cmEwHhcNMTgwMzA2MDAxNTU5WhcNMTkw\nMzA2MDAxNTU5WjCBhTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx\nFTATBgNVBAcMDFJlZHdvb2QgQ2l0eTEOMAwGA1UECgwFU3R5cmExDDAKBgNVBAsM\nA0RldjESMBAGA1UEAwwJbG9jYWxob3N0MRgwFgYJKoZIhvcNAQkBFglhc2hAc3R5\ncmEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDucnAwTRA0zqDQ671L\nKWOVwhjhycFyzyhZUd7vhsnslOBiYM6TYIDXhETfAk2RQoRE/9xF16woMD8FOglc\nlSuhi+GNfFRif6LfArm84ZFj1ZS1MX2logikhXhRJQ7AOHe5+ED0re3KH5lWyqfz\nR6bQuPYwTQSBJy6Tq7T9RiOM29yadCX64OaCEbzEFmHtNlbb5px4zCVvgskg/fpV\nGGCMpAYjGDatbxE5eAloVs1EJuI5RSqWr1JRm6EejxM04BFdfGn1HgWrsKXtlvBa\n00/AC0zXL5n6LK7+L3WbRguVTZcE4Yu70gDwhmM+VsKeT9LKClX003BNj0NJDRB9\ndw9MaWxsXDNHNOWEfbnASXeP7ZRv3D81ftij6P8SL14ZnxyrRty8TAN4ij3wd41l\nastRQCtrJFi+HzO606XOp6HDzBoWT0DGl8Sn2hZ6RLPyBnD04vvvcSGeCVjHGOQ8\nc3OTroK58u5MR/q4T00sTkeeVAxuKoEWKsjIBYYrJTe/a2mEq9yiDGbPNYDnWnQZ\njSUZm+Us23Y2sm/agZ5zKXcEuoecGL6sYCixr/xeB9BPxEiTthH+0M8OY99qpIhz\nSmj41wdgQfzZi/6B8pIr77V/KywYKxJEmzw8Uy48aC/rZ8WsT8QdKwclo1aiNJhx\n79OvGbZFoeHD/w7igpx+ttpF/wIDAQABMA0GCSqGSIb3DQEBBQUAA4ICAQC3wWUs\nfXz+aSfFVz+O3mLFkr65NIgazbGAySgMgMNVuadheIkPL4k21atyflfpx4pg9FGv\n40vWCLMajpvynfz4oqah0BACnpqzQ8Dx6HYkmlXK8fLB+WtPrZBeUEsGPKuJYt4M\nd5TeY3VpNgWOPXmnE4lvxHZqh/8OwmOpjBfC9E3e2eqgwiwOkXnMaZEPgKP6JiWk\nEFaQ9jgMQqJZnNcv6NmiqqsZeI0/NNjBpkmEWQl+wLegVusHiQ0FMBMQ0taEo21r\nzUwHoNJR3h3wgGQiKxKOH1FUKHBV7hEqObLraD/hfG5xYucJfvvAAP1iH0ycPs+9\nhSccrn5/HY1c9AZnW8Kh7atp/wFP+sHjtECWK/lUmXfhASS293hprCpJk2n9pkmR\nziXKJhjwkxlC8NcHuiVfaxdfDa4+1Qta2gK7GEypbvLoEmIt/dsYUsxUg84lwJJ9\nnyC/pfZ5a8wFSf186JeVH4kHd3bnkzlQz460HndOMSJ/Xi1wSfuZlOVupFf8TVKl\np4j28MTLH2Wqx50NssKThdaX6hoCiMqreYa+EVaN1f/cIGQxZSCzdzMCKqdB8lKB\n3Eax+5zsIa/UyPwGxZcyXBRHAlz5ZnkjuRxInyiMkBWWz3IZXjTe6Fq8BNd2UWNc\nw35+2nO5n1LKXgR2+nzhZUOk8TPsi9WUywRluQ==\n-----END CERTIFICATE-----` - certKey = `-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7nJwME0QNM6g0Ou9SyljlcIY4cnBcs8oWVHe74bJ7JTgYmDOk2CA14RE3wJNkUKERP/cRdesKDA/BToJXJUroYvhjXxUYn+i3wK5vOGRY9WUtTF9paIIpIV4USUOwDh3ufhA9K3tyh+ZVsqn80em0Lj2ME0EgScuk6u0/UYjjNvcmnQl+uDmghG8xBZh7TZW2+aceMwlb4LJIP36VRhgjKQGIxg2rW8ROXgJaFbNRCbiOUUqlq9SUZuhHo8TNOARXXxp9R4Fq7Cl7ZbwWtNPwAtM1y+Z+iyu/i91m0YLlU2XBOGLu9IA8IZjPlbCnk/SygpV9NNwTY9DSQ0QfXcPTGlsbFwzRzTlhH25wEl3j+2Ub9w/NX7Yo+j/Ei9eGZ8cq0bcvEwDeIo98HeNZWrLUUArayRYvh8zutOlzqehw8waFk9AxpfEp9oWekSz8gZw9OL773EhnglYxxjkPHNzk66CufLuTEf6uE9NLE5HnlQMbiqBFirIyAWGKyU3v2tphKvcogxmzzWA51p0GY0lGZvlLNt2NrJv2oGecyl3BLqHnBi+rGAosa/8XgfQT8RIk7YR/tDPDmPfaqSIc0po+NcHYEH82Yv+gfKSK++1fyssGCsSRJs8PFMuPGgv62fFrE/EHSsHJaNWojSYce/Trxm2RaHhw/8O4oKcfrbaRf8CAwEAAQ==\n-----END PUBLIC KEY-----` - keyJWK = `{"kty":"RSA","e":"AQAB","kid":"4db88b6b-cda9-4242-b79e-51346edc313c","n":"7nJwME0QNM6g0Ou9SyljlcIY4cnBcs8oWVHe74bJ7JTgYmDOk2CA14RE3wJNkUKERP_cRdesKDA_BToJXJUroYvhjXxUYn-i3wK5vOGRY9WUtTF9paIIpIV4USUOwDh3ufhA9K3tyh-ZVsqn80em0Lj2ME0EgScuk6u0_UYjjNvcmnQl-uDmghG8xBZh7TZW2-aceMwlb4LJIP36VRhgjKQGIxg2rW8ROXgJaFbNRCbiOUUqlq9SUZuhHo8TNOARXXxp9R4Fq7Cl7ZbwWtNPwAtM1y-Z-iyu_i91m0YLlU2XBOGLu9IA8IZjPlbCnk_SygpV9NNwTY9DSQ0QfXcPTGlsbFwzRzTlhH25wEl3j-2Ub9w_NX7Yo-j_Ei9eGZ8cq0bcvEwDeIo98HeNZWrLUUArayRYvh8zutOlzqehw8waFk9AxpfEp9oWekSz8gZw9OL773EhnglYxxjkPHNzk66CufLuTEf6uE9NLE5HnlQMbiqBFirIyAWGKyU3v2tphKvcogxmzzWA51p0GY0lGZvlLNt2NrJv2oGecyl3BLqHnBi-rGAosa_8XgfQT8RIk7YR_tDPDmPfaqSIc0po-NcHYEH82Yv-gfKSK--1fyssGCsSRJs8PFMuPGgv62fFrE_EHSsHJaNWojSYce_Trxm2RaHhw_8O4oKcfrbaRf8"}` - certPemRs = `-----BEGIN CERTIFICATE-----\nMIIDXDCCAkSgAwIBAgIBLjANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJVUzEV\nMBMGA1UEBxMMUmVkd29vZCBDaXR5MQ4wDAYDVQQKEwVTdHlyYTEMMAoGA1UECxMD\nRGV2MRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMjAwNTA3MDg1MTAzWhcNMjAwNTA3\nMTA1MTAzWjBWMQswCQYDVQQGEwJVUzEVMBMGA1UEBxMMUmVkd29vZCBDaXR5MQ4w\nDAYDVQQKEwVTdHlyYTEMMAoGA1UECxMDRGV2MRIwEAYDVQQDEwlsb2NhbGhvc3Qw\nggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDeRmygX/fOOUu5Wm91PFNo\nsHDG1CzG9a1iKBjUeMgi9bXXScUfatPmsNlxb56uSi0RXUsvJmY/yxkIIhRyapxW\n49j2idAM3SGGL1nOZf/XdpDHYsAFFZ237HGb8DOEk/p3xCFv0tH/iQ+kLP36EM1+\ntn6BfUXdJnVyvkSK2iMNeRY7A4DMX7sGX39LXsVJiCokIC8E0QUFrSjvrAm9ejKE\ntPojydo4c3VUxLfmFuyMXoD3bfk1Jv5i2J5RjtomjgK6zNCvgYzpspiodHChkzlU\nX8yk2YqlAHX3XdJA94LaDE2kNXiOQnFkUb8GsP7hmEbwGtMUEQie+jfgKplxJ49B\nAgMBAAGjNTAzMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAM\nBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQC9f2/kxT7DnQ94ownhHvd6\nrzk1WirI90rFM2MxhfkaDrOHhSGZL9nDf6TIZ4qeFKZXthpKxpiZm2Oxmn+vUsik\nW6bYjq1nX0GCchQLaaFf9Jh1IOLwkfoBdX55tV8xUGHRWgDlCuGbqiixz+Bm0Kap\nkmbyJynVcoiKhdLyYm/YTn/pC32SJW666reQ+0qCAoxzLQowBetHjwDam9RsDEf4\n+JRDjYPutNXyJ5X8BaBA6PzHanzMG/7RFYcx/2YhXwVxdfPHku4ALJcddIGAGNx2\n5yte+HY0aEu+06J67eD9+4fU7NixRMKigk9KbjqpeWD+0be+VgX8Dot4jaISgI/3\n-----END CERTIFICATE-----` - certKeyRs = `-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3kZsoF/3zjlLuVpvdTxT\naLBwxtQsxvWtYigY1HjIIvW110nFH2rT5rDZcW+erkotEV1LLyZmP8sZCCIUcmqc\nVuPY9onQDN0hhi9ZzmX/13aQx2LABRWdt+xxm/AzhJP6d8Qhb9LR/4kPpCz9+hDN\nfrZ+gX1F3SZ1cr5EitojDXkWOwOAzF+7Bl9/S17FSYgqJCAvBNEFBa0o76wJvXoy\nhLT6I8naOHN1VMS35hbsjF6A9235NSb+YtieUY7aJo4CuszQr4GM6bKYqHRwoZM5\nVF/MpNmKpQB1913SQPeC2gxNpDV4jkJxZFG/BrD+4ZhG8BrTFBEInvo34CqZcSeP\nQQIDAQAB\n-----END PUBLIC KEY-----` - keyJWKRs = `{"kty":"RSA","n":"3kZsoF_3zjlLuVpvdTxTaLBwxtQsxvWtYigY1HjIIvW110nFH2rT5rDZcW-erkotEV1LLyZmP8sZCCIUcmqcVuPY9onQDN0hhi9ZzmX_13aQx2LABRWdt-xxm_AzhJP6d8Qhb9LR_4kPpCz9-hDNfrZ-gX1F3SZ1cr5EitojDXkWOwOAzF-7Bl9_S17FSYgqJCAvBNEFBa0o76wJvXoyhLT6I8naOHN1VMS35hbsjF6A9235NSb-YtieUY7aJo4CuszQr4GM6bKYqHRwoZM5VF_MpNmKpQB1913SQPeC2gxNpDV4jkJxZFG_BrD-4ZhG8BrTFBEInvo34CqZcSePQQ","e":"AQAB"}` - certPemPs = `-----BEGIN CERTIFICATE-----\nMIIC/DCCAeSgAwIBAgIJAJRvYDU3ei3EMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNV\nBAMMCHdoYXRldmVyMB4XDTE4MDgxMDEwMzgxNloXDTE4MDkwOTEwMzgxNlowEzER\nMA8GA1UEAwwId2hhdGV2ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB\nAQC4kCmzLMW/5jzkzkmN7Me8wPD+ymBUIjsGqliGfMrfFfDV2eTPVtZcYD3IXoB4\nAOUT7XJzWjOsBRFOcVKKEiCPjXiLcwLb/QWQ1x0Budft32r3+N0KQd1rgcRHTPNc\nJoeWCfOgDPp51RTzTT6HQuV4ud+CDhRJP7QMVMIgal9Nuzs49LLZaBPW8/rFsHjk\nJQ4kDujSrpcT6F2FZY3SmWsOJgP7RjVKk5BheYeFKav5ZV4p6iHn/TN4RVpvpNBh\n5z/XoHITJ6lpkHSDpbIaQUTpobU2um8N3biz+HsEAmD9Laa27WUpYSpiM6DDMSXl\ndBDJdumerVRJvXYCtfXqtl17AgMBAAGjUzBRMB0GA1UdDgQWBBRz74MkVzT2K52/\nFJC4mTa9coM/DTAfBgNVHSMEGDAWgBRz74MkVzT2K52/FJC4mTa9coM/DTAPBgNV\nHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAD1ZE4IaIAetqGG+vt9oz1\nIx0j4EPok0ONyhhmiSsF6rSv8zlNWweVf5y6Z+AoTNY1Fym0T7dbpbqIox0EdKV3\nFLzniWOjznupbnqfXwHX/g1UAZSyt3akSatVhvNpGlnd7efTIAiNinX/TkzIjhZ7\nihMIZCGykT1P0ys1OaeEf57wAzviatD4pEMTIW0OOqY8bdRGhuJR1kKUZ/2Nm8Ln\ny7E0y8uODVbH9cAwGyzWB/QFc+bffNgi9uJaPQQc5Zxwpu9utlqyzFvXgV7MBYUK\nEYSLyxp4g4e5aujtLugaC8H6n9vP1mEBr/+T8HGynBZHNTKlDhhL9qDbpkkNB6/w\n-----END CERTIFICATE-----` - keyJWKPs = `{"kty":"RSA","e":"AQAB","kid":"bf688c97-bf51-49ba-b9d3-115195bb0eb8","n":"uJApsyzFv-Y85M5JjezHvMDw_spgVCI7BqpYhnzK3xXw1dnkz1bWXGA9yF6AeADlE-1yc1ozrAURTnFSihIgj414i3MC2_0FkNcdAbnX7d9q9_jdCkHda4HER0zzXCaHlgnzoAz6edUU800-h0LleLnfgg4UST-0DFTCIGpfTbs7OPSy2WgT1vP6xbB45CUOJA7o0q6XE-hdhWWN0plrDiYD-0Y1SpOQYXmHhSmr-WVeKeoh5_0zeEVab6TQYec_16ByEyepaZB0g6WyGkFE6aG1NrpvDd24s_h7BAJg_S2mtu1lKWEqYjOgwzEl5XQQyXbpnq1USb12ArX16rZdew"}` - certPemPs384 = `-----BEGIN CERTIFICATE-----\nMIIDXDCCAkSgAwIBAgIBKjANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJVUzEV\nMBMGA1UEBxMMUmVkd29vZCBDaXR5MQ4wDAYDVQQKEwVTdHlyYTEMMAoGA1UECxMD\nRGV2MRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMjAwNTA3MDkxMjU2WhcNMjAwNTA3\nMTExMjU2WjBWMQswCQYDVQQGEwJVUzEVMBMGA1UEBxMMUmVkd29vZCBDaXR5MQ4w\nDAYDVQQKEwVTdHlyYTEMMAoGA1UECxMDRGV2MRIwEAYDVQQDEwlsb2NhbGhvc3Qw\nggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtyVWH2FE8cU8LRcArH4Tw\nDhBOFcmJF28LrvRObcbDYsae6rEwby0aRgSxjTEMgyGBjroBSl22wOSA93kwx4pu\npfXEqbwywn9FhyKBb/OXQSglPmwrpmzQtPJGzBHncL+PPjRhPfqimwf7ZIPKAAgI\nz9O6ppGhE/x4Ct444jthUIBZuG5cUXhgiPBQdIQ3K88QhgVwcufTZkNHj4iSDfhl\nVFDHVjXjd2B/yGODjyv0TyChV0YBNGjMv7YFLWmIFUFzK+6qNSxu4czPtRkyfwaV\n2GW/PBT5f8fc6fKgQZ6k6BLK6+pi0iPh5TUizyHtqtueWDbrJ+wfdJilQS8D+EGr\nAgMBAAGjNTAzMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAM\nBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQBgVAM50/0aBTBxESYKIKN4\nE+qbV6aE0C+wYJLet0EWPTxwmFZamq5LNEO/D6xyoY5WHY60EyHRMs0agSB/ATBX\n5ULdEwh9G0NjxqivCcoddQ1fuVS2PrrqNL7VlRnYbTpd8/Dh4qnyl5FltlyZ/29L\ny7BWOwlcBlZdhsfH8svNX4PUxjRD+jmnczCDi7XSOKT8htKUV2ih1c9JrWpIhCi/\nHzEXkaAxNdhBNdIsLQMo3qq9fkSgNZQk9/ecJNPeuJ/UYyr5Xa4PxIWl4U+P7yuI\n+Q3FSPmUbiVsSGqMhh6V/DN8M+T5/KiSB47gFOfxc2/RR5aw4HkSp3WxwbT9njbE\n-----END CERTIFICATE-----` - certKeyPs384 = `-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7clVh9hRPHFPC0XAKx+E\n8A4QThXJiRdvC670Tm3Gw2LGnuqxMG8tGkYEsY0xDIMhgY66AUpdtsDkgPd5MMeK\nbqX1xKm8MsJ/RYcigW/zl0EoJT5sK6Zs0LTyRswR53C/jz40YT36opsH+2SDygAI\nCM/TuqaRoRP8eAreOOI7YVCAWbhuXFF4YIjwUHSENyvPEIYFcHLn02ZDR4+Ikg34\nZVRQx1Y143dgf8hjg48r9E8goVdGATRozL+2BS1piBVBcyvuqjUsbuHMz7UZMn8G\nldhlvzwU+X/H3OnyoEGepOgSyuvqYtIj4eU1Is8h7arbnlg26yfsH3SYpUEvA/hB\nqwIDAQAB\n-----END PUBLIC KEY-----` - keyJWKPs384 = `{"kty":"RSA","n":"7clVh9hRPHFPC0XAKx-E8A4QThXJiRdvC670Tm3Gw2LGnuqxMG8tGkYEsY0xDIMhgY66AUpdtsDkgPd5MMeKbqX1xKm8MsJ_RYcigW_zl0EoJT5sK6Zs0LTyRswR53C_jz40YT36opsH-2SDygAICM_TuqaRoRP8eAreOOI7YVCAWbhuXFF4YIjwUHSENyvPEIYFcHLn02ZDR4-Ikg34ZVRQx1Y143dgf8hjg48r9E8goVdGATRozL-2BS1piBVBcyvuqjUsbuHMz7UZMn8GldhlvzwU-X_H3OnyoEGepOgSyuvqYtIj4eU1Is8h7arbnlg26yfsH3SYpUEvA_hBqw","e":"AQAB"}` - certPemPs512 = `-----BEGIN CERTIFICATE-----\nMIIDXDCCAkSgAwIBAgIBKjANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJVUzEV\nMBMGA1UEBxMMUmVkd29vZCBDaXR5MQ4wDAYDVQQKEwVTdHlyYTEMMAoGA1UECxMD\nRGV2MRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMjAwNTA3MDkxMjU2WhcNMjAwNTA3\nMTExMjU2WjBWMQswCQYDVQQGEwJVUzEVMBMGA1UEBxMMUmVkd29vZCBDaXR5MQ4w\nDAYDVQQKEwVTdHlyYTEMMAoGA1UECxMDRGV2MRIwEAYDVQQDEwlsb2NhbGhvc3Qw\nggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtyVWH2FE8cU8LRcArH4Tw\nDhBOFcmJF28LrvRObcbDYsae6rEwby0aRgSxjTEMgyGBjroBSl22wOSA93kwx4pu\npfXEqbwywn9FhyKBb/OXQSglPmwrpmzQtPJGzBHncL+PPjRhPfqimwf7ZIPKAAgI\nz9O6ppGhE/x4Ct444jthUIBZuG5cUXhgiPBQdIQ3K88QhgVwcufTZkNHj4iSDfhl\nVFDHVjXjd2B/yGODjyv0TyChV0YBNGjMv7YFLWmIFUFzK+6qNSxu4czPtRkyfwaV\n2GW/PBT5f8fc6fKgQZ6k6BLK6+pi0iPh5TUizyHtqtueWDbrJ+wfdJilQS8D+EGr\nAgMBAAGjNTAzMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAM\nBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQBgVAM50/0aBTBxESYKIKN4\nE+qbV6aE0C+wYJLet0EWPTxwmFZamq5LNEO/D6xyoY5WHY60EyHRMs0agSB/ATBX\n5ULdEwh9G0NjxqivCcoddQ1fuVS2PrrqNL7VlRnYbTpd8/Dh4qnyl5FltlyZ/29L\ny7BWOwlcBlZdhsfH8svNX4PUxjRD+jmnczCDi7XSOKT8htKUV2ih1c9JrWpIhCi/\nHzEXkaAxNdhBNdIsLQMo3qq9fkSgNZQk9/ecJNPeuJ/UYyr5Xa4PxIWl4U+P7yuI\n+Q3FSPmUbiVsSGqMhh6V/DN8M+T5/KiSB47gFOfxc2/RR5aw4HkSp3WxwbT9njbE\n-----END CERTIFICATE-----` - certKeyPs512 = `-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7clVh9hRPHFPC0XAKx+E\n8A4QThXJiRdvC670Tm3Gw2LGnuqxMG8tGkYEsY0xDIMhgY66AUpdtsDkgPd5MMeK\nbqX1xKm8MsJ/RYcigW/zl0EoJT5sK6Zs0LTyRswR53C/jz40YT36opsH+2SDygAI\nCM/TuqaRoRP8eAreOOI7YVCAWbhuXFF4YIjwUHSENyvPEIYFcHLn02ZDR4+Ikg34\nZVRQx1Y143dgf8hjg48r9E8goVdGATRozL+2BS1piBVBcyvuqjUsbuHMz7UZMn8G\nldhlvzwU+X/H3OnyoEGepOgSyuvqYtIj4eU1Is8h7arbnlg26yfsH3SYpUEvA/hB\nqwIDAQAB\n-----END PUBLIC KEY-----` - keyJWKPs512 = `{"kty":"RSA","n":"7clVh9hRPHFPC0XAKx-E8A4QThXJiRdvC670Tm3Gw2LGnuqxMG8tGkYEsY0xDIMhgY66AUpdtsDkgPd5MMeKbqX1xKm8MsJ_RYcigW_zl0EoJT5sK6Zs0LTyRswR53C_jz40YT36opsH-2SDygAICM_TuqaRoRP8eAreOOI7YVCAWbhuXFF4YIjwUHSENyvPEIYFcHLn02ZDR4-Ikg34ZVRQx1Y143dgf8hjg48r9E8goVdGATRozL-2BS1piBVBcyvuqjUsbuHMz7UZMn8GldhlvzwU-X_H3OnyoEGepOgSyuvqYtIj4eU1Is8h7arbnlg26yfsH3SYpUEvA_hBqw","e":"AQAB"}` - certPemEs256 = `-----BEGIN CERTIFICATE-----\nMIIBcDCCARagAwIBAgIJAMZmuGSIfvgzMAoGCCqGSM49BAMCMBMxETAPBgNVBAMM\nCHdoYXRldmVyMB4XDTE4MDgxMDE0Mjg1NFoXDTE4MDkwOTE0Mjg1NFowEzERMA8G\nA1UEAwwId2hhdGV2ZXIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATPwn3WCEXL\nmjp/bFniDwuwsfu7bASlPae2PyWhqGeWwe23Xlyx+tSqxlkXYe4pZ23BkAAscpGj\nyn5gXHExyDlKo1MwUTAdBgNVHQ4EFgQUElRjSoVgKjUqY5AXz2o74cLzzS8wHwYD\nVR0jBBgwFoAUElRjSoVgKjUqY5AXz2o74cLzzS8wDwYDVR0TAQH/BAUwAwEB/zAK\nBggqhkjOPQQDAgNIADBFAiEA4yQ/88ZrUX68c6kOe9G11u8NUaUzd8pLOtkKhniN\nOHoCIHmNX37JOqTcTzGn2u9+c8NlnvZ0uDvsd1BmKPaUmjmm\n-----END CERTIFICATE-----\n` - keyJWKEs256 = `{"kty":"EC","crv":"P-256","x":"z8J91ghFy5o6f2xZ4g8LsLH7u2wEpT2ntj8loahnlsE","y":"7bdeXLH61KrGWRdh7ilnbcGQACxykaPKfmBccTHIOUo"}` - certPemEs384 = `-----BEGIN CERTIFICATE-----\nMIICDDCCAZOgAwIBAgIBIzAKBggqhkjOPQQDAzBWMQswCQYDVQQGEwJVUzEVMBMG\nA1UEBxMMUmVkd29vZCBDaXR5MQ4wDAYDVQQKEwVTdHlyYTEMMAoGA1UECxMDRGV2\nMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMjAwNTA3MDk0MzU1WhcNMjAwNTA3MTE0\nMzU1WjBWMQswCQYDVQQGEwJVUzEVMBMGA1UEBxMMUmVkd29vZCBDaXR5MQ4wDAYD\nVQQKEwVTdHlyYTEMMAoGA1UECxMDRGV2MRIwEAYDVQQDEwlsb2NhbGhvc3QwdjAQ\nBgcqhkjOPQIBBgUrgQQAIgNiAARjcwW7g9wx4ePsuwcVzDJCVo4f8I1C1X5US4B1\nrWN+5zFSJoGCKaPTXMDhAdS08D1G20AIRmA0AlVVXRxrZYZ+Y282O6s+EGsB5T1W\nMCnUFk2Sa+xZiGPApYz4zSGbNEqjNTAzMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUE\nDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMAoGCCqGSM49BAMDA2cAMGQCMGSG\nVjx3DZP71ZGNDBw+AVdhNU3pgJW8kNpqjta3HFLb6pzqNOsfOn1ZeIWciEcyEgIw\nTGxli48W1AJ2s7Pw+3wOA6f9HAmczJPaiZ9CY038UiT8mk+pND5FEdqLhT/5lMEz\n-----END CERTIFICATE-----` - certKeyEs384 = `-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEY3MFu4PcMeHj7LsHFcwyQlaOH/CNQtV+\nVEuAda1jfucxUiaBgimj01zA4QHUtPA9RttACEZgNAJVVV0ca2WGfmNvNjurPhBr\nAeU9VjAp1BZNkmvsWYhjwKWM+M0hmzRK\n-----END PUBLIC KEY-----` - keyJWKEs384 = `{"kty":"EC","crv":"P-384","x":"Y3MFu4PcMeHj7LsHFcwyQlaOH_CNQtV-VEuAda1jfucxUiaBgimj01zA4QHUtPA9","y":"RttACEZgNAJVVV0ca2WGfmNvNjurPhBrAeU9VjAp1BZNkmvsWYhjwKWM-M0hmzRK"}` - certPemEs512 = `-----BEGIN CERTIFICATE-----\nMIICWDCCAbmgAwIBAgIBAjAKBggqhkjOPQQDBDBWMQswCQYDVQQGEwJVUzEVMBMG\nA1UEBxMMUmVkd29vZCBDaXR5MQ4wDAYDVQQKEwVTdHlyYTEMMAoGA1UECxMDRGV2\nMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMjAwNTA3MTA1NDM3WhcNMjAwNTA3MTI1\nNDM3WjBWMQswCQYDVQQGEwJVUzEVMBMGA1UEBxMMUmVkd29vZCBDaXR5MQ4wDAYD\nVQQKEwVTdHlyYTEMMAoGA1UECxMDRGV2MRIwEAYDVQQDEwlsb2NhbGhvc3QwgZsw\nEAYHKoZIzj0CAQYFK4EEACMDgYYABAHLm3IMD/88vC/S1cCTyjrCjwHIGsjibFBw\nPBXt36YKCjUdS7jiJJR5YQVPypSv7gPaKKn1E8CqkfVdd3rrp1TocAEms4XvigtW\nZBZzffw9xyZCgmtQ2dTHsufi/5W/Yx8N3Uw+D2wl1LKcJraouo+qgamGfuou6WbA\noPEtdOg0+B4jF6M1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUF\nBwMBMAwGA1UdEwEB/wQCMAAwCgYIKoZIzj0EAwQDgYwAMIGIAkIAzAAYDqMghX3S\n8UbS8s5TPAztJy9oNXFra5V8pPlUdNFc2ov2LN++scW46wCb/cJUyEc58sY7xFuK\nI5sCOkv95N8CQgFXmu354LZJ31zIovuUA8druOPe3TDnxMGwEEm2Lt43JNuhzNyP\nhJYh9/QKfe2AiwrLXEG4VVOIXdjq7vexl87evg==\n-----END CERTIFICATE-----` - certKeyEs512 = `-----BEGIN PUBLIC KEY-----\nMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBy5tyDA//PLwv0tXAk8o6wo8ByBrI\n4mxQcDwV7d+mCgo1HUu44iSUeWEFT8qUr+4D2iip9RPAqpH1XXd666dU6HABJrOF\n74oLVmQWc338PccmQoJrUNnUx7Ln4v+Vv2MfDd1MPg9sJdSynCa2qLqPqoGphn7q\nLulmwKDxLXToNPgeIxc=\n-----END PUBLIC KEY-----` - keyJWKEs512 = `{"kty":"EC","crv":"P-521","x":"AcubcgwP_zy8L9LVwJPKOsKPAcgayOJsUHA8Fe3fpgoKNR1LuOIklHlhBU_KlK_uA9ooqfUTwKqR9V13euunVOhw","y":"ASazhe-KC1ZkFnN9_D3HJkKCa1DZ1Mey5-L_lb9jHw3dTD4PbCXUspwmtqi6j6qBqYZ-6i7pZsCg8S106DT4HiMX"}` - certPemBadBlock = `-----BEGIN CERT-----\nMIIFiDCCA3ACCQCGV6XsfG/oRTANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMC\nVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFTATBgNVBAcMDFJlZHdvb2QgQ2l0eTEO\nMAwGA1UECgwFU3R5cmExDDAKBgNVBAsMA0RldjESMBAGA1UEAwwJbG9jYWxob3N0\nMRgwFgYJKoZIhvcNAQkBFglhc2hAc3R5cmEwHhcNMTgwMzA2MDAxNTU5WhcNMTkw\nMzA2MDAxNTU5WjCBhTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx\nFTATBgNVBAcMDFJlZHdvb2QgQ2l0eTEOMAwGA1UECgwFU3R5cmExDDAKBgNVBAsM\nA0RldjESMBAGA1UEAwwJbG9jYWxob3N0MRgwFgYJKoZIhvcNAQkBFglhc2hAc3R5\ncmEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDucnAwTRA0zqDQ671L\nKWOVwhjhycFyzyhZUd7vhsnslOBiYM6TYIDXhETfAk2RQoRE/9xF16woMD8FOglc\nlSuhi+GNfFRif6LfArm84ZFj1ZS1MX2logikhXhRJQ7AOHe5+ED0re3KH5lWyqfz\nR6bQuPYwTQSBJy6Tq7T9RiOM29yadCX64OaCEbzEFmHtNlbb5px4zCVvgskg/fpV\nGGCMpAYjGDatbxE5eAloVs1EJuI5RSqWr1JRm6EejxM04BFdfGn1HgWrsKXtlvBa\n00/AC0zXL5n6LK7+L3WbRguVTZcE4Yu70gDwhmM+VsKeT9LKClX003BNj0NJDRB9\ndw9MaWxsXDNHNOWEfbnASXeP7ZRv3D81ftij6P8SL14ZnxyrRty8TAN4ij3wd41l\nastRQCtrJFi+HzO606XOp6HDzBoWT0DGl8Sn2hZ6RLPyBnD04vvvcSGeCVjHGOQ8\nc3OTroK58u5MR/q4T00sTkeeVAxuKoEWKsjIBYYrJTe/a2mEq9yiDGbPNYDnWnQZ\njSUZm+Us23Y2sm/agZ5zKXcEuoecGL6sYCixr/xeB9BPxEiTthH+0M8OY99qpIhz\nSmj41wdgQfzZi/6B8pIr77V/KywYKxJEmzw8Uy48aC/rZ8WsT8QdKwclo1aiNJhx\n79OvGbZFoeHD/w7igpx+ttpF/wIDAQABMA0GCSqGSIb3DQEBBQUAA4ICAQC3wWUs\nfXz+aSfFVz+O3mLFkr65NIgazbGAySgMgMNVuadheIkPL4k21atyflfpx4pg9FGv\n40vWCLMajpvynfz4oqah0BACnpqzQ8Dx6HYkmlXK8fLB+WtPrZBeUEsGPKuJYt4M\nd5TeY3VpNgWOPXmnE4lvxHZqh/8OwmOpjBfC9E3e2eqgwiwOkXnMaZEPgKP6JiWk\nEFaQ9jgMQqJZnNcv6NmiqqsZeI0/NNjBpkmEWQl+wLegVusHiQ0FMBMQ0taEo21r\nzUwHoNJR3h3wgGQiKxKOH1FUKHBV7hEqObLraD/hfG5xYucJfvvAAP1iH0ycPs+9\nhSccrn5/HY1c9AZnW8Kh7atp/wFP+sHjtECWK/lUmXfhASS293hprCpJk2n9pkmR\nziXKJhjwkxlC8NcHuiVfaxdfDa4+1Qta2gK7GEypbvLoEmIt/dsYUsxUg84lwJJ9\nnyC/pfZ5a8wFSf186JeVH4kHd3bnkzlQz460HndOMSJ/Xi1wSfuZlOVupFf8TVKl\np4j28MTLH2Wqx50NssKThdaX6hoCiMqreYa+EVaN1f/cIGQxZSCzdzMCKqdB8lKB\n3Eax+5zsIa/UyPwGxZcyXBRHAlz5ZnkjuRxInyiMkBWWz3IZXjTe6Fq8BNd2UWNc\nw35+2nO5n1LKXgR2+nzhZUOk8TPsi9WUywRluQ==\n-----END CERT-----` - certPemExtraData = `-----BEGIN CERTIFICATE-----\nMIIFiDCCA3ACCQCGV6XsfG/oRTANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMC\nVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFTATBgNVBAcMDFJlZHdvb2QgQ2l0eTEO\nMAwGA1UECgwFU3R5cmExDDAKBgNVBAsMA0RldjESMBAGA1UEAwwJbG9jYWxob3N0\nMRgwFgYJKoZIhvcNAQkBFglhc2hAc3R5cmEwHhcNMTgwMzA2MDAxNTU5WhcNMTkw\nMzA2MDAxNTU5WjCBhTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx\nFTATBgNVBAcMDFJlZHdvb2QgQ2l0eTEOMAwGA1UECgwFU3R5cmExDDAKBgNVBAsM\nA0RldjESMBAGA1UEAwwJbG9jYWxob3N0MRgwFgYJKoZIhvcNAQkBFglhc2hAc3R5\ncmEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDucnAwTRA0zqDQ671L\nKWOVwhjhycFyzyhZUd7vhsnslOBiYM6TYIDXhETfAk2RQoRE/9xF16woMD8FOglc\nlSuhi+GNfFRif6LfArm84ZFj1ZS1MX2logikhXhRJQ7AOHe5+ED0re3KH5lWyqfz\nR6bQuPYwTQSBJy6Tq7T9RiOM29yadCX64OaCEbzEFmHtNlbb5px4zCVvgskg/fpV\nGGCMpAYjGDatbxE5eAloVs1EJuI5RSqWr1JRm6EejxM04BFdfGn1HgWrsKXtlvBa\n00/AC0zXL5n6LK7+L3WbRguVTZcE4Yu70gDwhmM+VsKeT9LKClX003BNj0NJDRB9\ndw9MaWxsXDNHNOWEfbnASXeP7ZRv3D81ftij6P8SL14ZnxyrRty8TAN4ij3wd41l\nastRQCtrJFi+HzO606XOp6HDzBoWT0DGl8Sn2hZ6RLPyBnD04vvvcSGeCVjHGOQ8\nc3OTroK58u5MR/q4T00sTkeeVAxuKoEWKsjIBYYrJTe/a2mEq9yiDGbPNYDnWnQZ\njSUZm+Us23Y2sm/agZ5zKXcEuoecGL6sYCixr/xeB9BPxEiTthH+0M8OY99qpIhz\nSmj41wdgQfzZi/6B8pIr77V/KywYKxJEmzw8Uy48aC/rZ8WsT8QdKwclo1aiNJhx\n79OvGbZFoeHD/w7igpx+ttpF/wIDAQABMA0GCSqGSIb3DQEBBQUAA4ICAQC3wWUs\nfXz+aSfFVz+O3mLFkr65NIgazbGAySgMgMNVuadheIkPL4k21atyflfpx4pg9FGv\n40vWCLMajpvynfz4oqah0BACnpqzQ8Dx6HYkmlXK8fLB+WtPrZBeUEsGPKuJYt4M\nd5TeY3VpNgWOPXmnE4lvxHZqh/8OwmOpjBfC9E3e2eqgwiwOkXnMaZEPgKP6JiWk\nEFaQ9jgMQqJZnNcv6NmiqqsZeI0/NNjBpkmEWQl+wLegVusHiQ0FMBMQ0taEo21r\nzUwHoNJR3h3wgGQiKxKOH1FUKHBV7hEqObLraD/hfG5xYucJfvvAAP1iH0ycPs+9\nhSccrn5/HY1c9AZnW8Kh7atp/wFP+sHjtECWK/lUmXfhASS293hprCpJk2n9pkmR\nziXKJhjwkxlC8NcHuiVfaxdfDa4+1Qta2gK7GEypbvLoEmIt/dsYUsxUg84lwJJ9\nnyC/pfZ5a8wFSf186JeVH4kHd3bnkzlQz460HndOMSJ/Xi1wSfuZlOVupFf8TVKl\np4j28MTLH2Wqx50NssKThdaX6hoCiMqreYa+EVaN1f/cIGQxZSCzdzMCKqdB8lKB\n3Eax+5zsIa/UyPwGxZcyXBRHAlz5ZnkjuRxInyiMkBWWz3IZXjTe6Fq8BNd2UWNc\nw35+2nO5n1LKXgR2+nzhZUOk8TPsi9WUywRluQ==\n-----END CERTIFICATE-----\nEXTRA` - certPemBadCertificate = `-----BEGIN CERTIFICATE-----\ndeadiDCCA3ACCQCGV6XsfG/oRTANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMC\nVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFTATBgNVBAcMDFJlZHdvb2QgQ2l0eTEO\nMAwGA1UECgwFU3R5cmExDDAKBgNVBAsMA0RldjESMBAGA1UEAwwJbG9jYWxob3N0\nMRgwFgYJKoZIhvcNAQkBFglhc2hAc3R5cmEwHhcNMTgwMzA2MDAxNTU5WhcNMTkw\nMzA2MDAxNTU5WjCBhTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx\nFTATBgNVBAcMDFJlZHdvb2QgQ2l0eTEOMAwGA1UECgwFU3R5cmExDDAKBgNVBAsM\nA0RldjESMBAGA1UEAwwJbG9jYWxob3N0MRgwFgYJKoZIhvcNAQkBFglhc2hAc3R5\ncmEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDucnAwTRA0zqDQ671L\nKWOVwhjhycFyzyhZUd7vhsnslOBiYM6TYIDXhETfAk2RQoRE/9xF16woMD8FOglc\nlSuhi+GNfFRif6LfArm84ZFj1ZS1MX2logikhXhRJQ7AOHe5+ED0re3KH5lWyqfz\nR6bQuPYwTQSBJy6Tq7T9RiOM29yadCX64OaCEbzEFmHtNlbb5px4zCVvgskg/fpV\nGGCMpAYjGDatbxE5eAloVs1EJuI5RSqWr1JRm6EejxM04BFdfGn1HgWrsKXtlvBa\n00/AC0zXL5n6LK7+L3WbRguVTZcE4Yu70gDwhmM+VsKeT9LKClX003BNj0NJDRB9\ndw9MaWxsXDNHNOWEfbnASXeP7ZRv3D81ftij6P8SL14ZnxyrRty8TAN4ij3wd41l\nastRQCtrJFi+HzO606XOp6HDzBoWT0DGl8Sn2hZ6RLPyBnD04vvvcSGeCVjHGOQ8\nc3OTroK58u5MR/q4T00sTkeeVAxuKoEWKsjIBYYrJTe/a2mEq9yiDGbPNYDnWnQZ\njSUZm+Us23Y2sm/agZ5zKXcEuoecGL6sYCixr/xeB9BPxEiTthH+0M8OY99qpIhz\nSmj41wdgQfzZi/6B8pIr77V/KywYKxJEmzw8Uy48aC/rZ8WsT8QdKwclo1aiNJhx\n79OvGbZFoeHD/w7igpx+ttpF/wIDAQABMA0GCSqGSIb3DQEBBQUAA4ICAQC3wWUs\nfXz+aSfFVz+O3mLFkr65NIgazbGAySgMgMNVuadheIkPL4k21atyflfpx4pg9FGv\n40vWCLMajpvynfz4oqah0BACnpqzQ8Dx6HYkmlXK8fLB+WtPrZBeUEsGPKuJYt4M\nd5TeY3VpNgWOPXmnE4lvxHZqh/8OwmOpjBfC9E3e2eqgwiwOkXnMaZEPgKP6JiWk\nEFaQ9jgMQqJZnNcv6NmiqqsZeI0/NNjBpkmEWQl+wLegVusHiQ0FMBMQ0taEo21r\nzUwHoNJR3h3wgGQiKxKOH1FUKHBV7hEqObLraD/hfG5xYucJfvvAAP1iH0ycPs+9\nhSccrn5/HY1c9AZnW8Kh7atp/wFP+sHjtECWK/lUmXfhASS293hprCpJk2n9pkmR\nziXKJhjwkxlC8NcHuiVfaxdfDa4+1Qta2gK7GEypbvLoEmIt/dsYUsxUg84lwJJ9\nnyC/pfZ5a8wFSf186JeVH4kHd3bnkzlQz460HndOMSJ/Xi1wSfuZlOVupFf8TVKl\np4j28MTLH2Wqx50NssKThdaX6hoCiMqreYa+EVaN1f/cIGQxZSCzdzMCKqdB8lKB\n3Eax+5zsIa/UyPwGxZcyXBRHAlz5ZnkjuRxInyiMkBWWz3IZXjTe6Fq8BNd2UWNc\nw35+2nO5n1LKXgR2+nzhZUOk8TPsi9WUywRluQ==\n-----END CERTIFICATE-----` - keyJWKBadKey = `{"kty":"bogus key type","e":"AQAB","kid":"4db88b6b-cda9-4242-b79e-51346edc313c","n":"7nJwME0QNM6g0Ou9SyljlcIY4cnBcs8oWVHe74bJ7JTgYmDOk2CA14RE3wJNkUKERP_cRdesKDA_BToJXJUroYvhjXxUYn-i3wK5vOGRY9WUtTF9paIIpIV4USUOwDh3ufhA9K3tyh-ZVsqn80em0Lj2ME0EgScuk6u0_UYjjNvcmnQl-uDmghG8xBZh7TZW2-aceMwlb4LJIP36VRhgjKQGIxg2rW8ROXgJaFbNRCbiOUUqlq9SUZuhHo8TNOARXXxp9R4Fq7Cl7ZbwWtNPwAtM1y-Z-iyu_i91m0YLlU2XBOGLu9IA8IZjPlbCnk_SygpV9NNwTY9DSQ0QfXcPTGlsbFwzRzTlhH25wEl3j-2Ub9w_NX7Yo-j_Ei9eGZ8cq0bcvEwDeIo98HeNZWrLUUArayRYvh8zutOlzqehw8waFk9AxpfEp9oWekSz8gZw9OL773EhnglYxxjkPHNzk66CufLuTEf6uE9NLE5HnlQMbiqBFirIyAWGKyU3v2tphKvcogxmzzWA51p0GY0lGZvlLNt2NrJv2oGecyl3BLqHnBi-rGAosa_8XgfQT8RIk7YR_tDPDmPfaqSIc0po-NcHYEH82Yv-gfKSK--1fyssGCsSRJs8PFMuPGgv62fFrE_EHSsHJaNWojSYce_Trxm2RaHhw_8O4oKcfrbaRf8"}` - multiKeyJWkS = `{ - "keys": [ - { - "kty": "EC", - "use": "sig", - "crv": "P-256", - "kid": "k1", - "x": "9Qq5S5VqMQoH-FOI4atcH6V3bua03C-5ZMZMG1rszwA", - "y": "LLbFxWkGBEBrTm1GMYZJy1OXCH1KLweJMCgIEPIsibU", - "alg": "ES256" - }, - { - "kty": "RSA", - "e": "AQAB", - "use": "enc", - "kid": "k2", - "alg": "RS256", - "n": "sGu-fYVE2nq2dPxJlqAMI0Z8G3FD0XcWDnD8mkfO1ddKRGuUQZmfj4gWeZGyIk3cnuoy7KJCEqa3daXc08QHuFZyfn0rH33t8_AFsvb0q0i7R2FK-Gdqs_E0-sGpYMsRJdZWfCioLkYjIHEuVnRbi3DEsWqe484rEGbKF60jNRgGC4b-8pz-E538ZkssWxcqHrYIj5bjGEU36onjS3M_yrTuNvzv_8wRioK4fbcwmGne9bDxu8LcoSReWpPn0CnUkWnfqroRcMJnC87ZuJagDW1ZWCmU3psdsVanmFFh0DP6z0fsA4h8G2n9-qp-LEKFaWwo3IWlOsIzU3MHdcEiGw" - } - ] -}` -) - -func TestTopDownJWTVerifyRSA(t *testing.T) { - params := []struct { - note string - alg string - input1 string - input2 string - result bool - err string - }{ - { - "success-cert", - "rs256", - `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9.N0-EVdv5pvUfZYFRzMGnsWpNLHgwMEgViPwpuLBEtt32682OgnOK-N4X-2gpQEjQIbUr0IFym8YsRQU9GZvqQP72Sd6yOQNGSNeE74DpUZCAjBa9SBIb1UlD2MxZB-e7YJiEyo7pZhimaqorXrgorlaXYGMvsCFWDYmBLzGaGYaGJyEpkZHzHb7ujsDrJJjdEtDV3kh13gTHzLPvqnoXuuxelXye_8LPIhvgDy52gT4shUEso71pJCMv_IqAR19ljVE17lJzoi6VhRn6ReNUE-yg4KfCO4Ypnuu-mcQr7XtmSYoWkX72L5UQ-EyWkoz-w0SYKoJTPzHkTL2thYStksVpeNkGuck25aUdtrQgmPbao0QOWBFlkg03e6mPCD2-aXOt1ofth9mZGjxWMHX-mUqHaNmaWM3WhRztJ73hWrmB1YOdYQtOEHejfvR_td5tqIw4W6ufRy2ScOypGQe7kNaUZxpgxZ1927ZGNiQgawIOAQwXOcFx1JNSEIeg55-cYJrHPxsXGOB9ZxW-qnswmFJp474iUVXjzGhLexJDXBwvKGs_O3JFjMsvyV9_hm7bnQU0vG_HgPYs5i9VOHRMujq1vFBcm52TFVOBGdWaGfb9RRdLLYvVkJLk0Poh19rsCWb7-Vc3mAaGGpvuk4Wv-PnGGNC-V-FQqIbijHDrn_g`, - fmt.Sprintf(`"%s"`, certPem), - true, - "", - }, - { - "success-cert", - "rs256", - `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9.N0-EVdv5pvUfZYFRzMGnsWpNLHgwMEgViPwpuLBEtt32682OgnOK-N4X-2gpQEjQIbUr0IFym8YsRQU9GZvqQP72Sd6yOQNGSNeE74DpUZCAjBa9SBIb1UlD2MxZB-e7YJiEyo7pZhimaqorXrgorlaXYGMvsCFWDYmBLzGaGYaGJyEpkZHzHb7ujsDrJJjdEtDV3kh13gTHzLPvqnoXuuxelXye_8LPIhvgDy52gT4shUEso71pJCMv_IqAR19ljVE17lJzoi6VhRn6ReNUE-yg4KfCO4Ypnuu-mcQr7XtmSYoWkX72L5UQ-EyWkoz-w0SYKoJTPzHkTL2thYStksVpeNkGuck25aUdtrQgmPbao0QOWBFlkg03e6mPCD2-aXOt1ofth9mZGjxWMHX-mUqHaNmaWM3WhRztJ73hWrmB1YOdYQtOEHejfvR_td5tqIw4W6ufRy2ScOypGQe7kNaUZxpgxZ1927ZGNiQgawIOAQwXOcFx1JNSEIeg55-cYJrHPxsXGOB9ZxW-qnswmFJp474iUVXjzGhLexJDXBwvKGs_O3JFjMsvyV9_hm7bnQU0vG_HgPYs5i9VOHRMujq1vFBcm52TFVOBGdWaGfb9RRdLLYvVkJLk0Poh19rsCWb7-Vc3mAaGGpvuk4Wv-PnGGNC-V-FQqIbijHDrn_g`, - fmt.Sprintf(`"%s"`, certKey), - true, - "", - }, - { - "success-jwk", - "rs256", - `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9.N0-EVdv5pvUfZYFRzMGnsWpNLHgwMEgViPwpuLBEtt32682OgnOK-N4X-2gpQEjQIbUr0IFym8YsRQU9GZvqQP72Sd6yOQNGSNeE74DpUZCAjBa9SBIb1UlD2MxZB-e7YJiEyo7pZhimaqorXrgorlaXYGMvsCFWDYmBLzGaGYaGJyEpkZHzHb7ujsDrJJjdEtDV3kh13gTHzLPvqnoXuuxelXye_8LPIhvgDy52gT4shUEso71pJCMv_IqAR19ljVE17lJzoi6VhRn6ReNUE-yg4KfCO4Ypnuu-mcQr7XtmSYoWkX72L5UQ-EyWkoz-w0SYKoJTPzHkTL2thYStksVpeNkGuck25aUdtrQgmPbao0QOWBFlkg03e6mPCD2-aXOt1ofth9mZGjxWMHX-mUqHaNmaWM3WhRztJ73hWrmB1YOdYQtOEHejfvR_td5tqIw4W6ufRy2ScOypGQe7kNaUZxpgxZ1927ZGNiQgawIOAQwXOcFx1JNSEIeg55-cYJrHPxsXGOB9ZxW-qnswmFJp474iUVXjzGhLexJDXBwvKGs_O3JFjMsvyV9_hm7bnQU0vG_HgPYs5i9VOHRMujq1vFBcm52TFVOBGdWaGfb9RRdLLYvVkJLk0Poh19rsCWb7-Vc3mAaGGpvuk4Wv-PnGGNC-V-FQqIbijHDrn_g`, - fmt.Sprintf("`%s`", keyJWK), - true, - "", - }, - { - "success-ps256-cert", - "ps256", - `eyJ0eXAiOiAiSldUIiwgImFsZyI6ICJQUzI1NiJ9.eyJuYmYiOiAxNDQ0NDc4NDAwLCAiZm9vIjogImJhciJ9.i0F3MHWzOsBNLqjQzK1UVeQid9xPMowCoUsoM-C2BDxUY-FMKmCeJ1NJ4TGnS9HzFK1ftEvRnPT7EOxOkHPoCk1rz3feTFgtHtNzQqLM1IBTnz6aHHOrda_bKPHH9ZIYCRQUPXhpC90ivW_IJR-f7Z1WLrMXaJ71i1XteruENHrJJJDn0HedHG6N0VHugBHrak5k57cbE31utAdx83TEd8v2Y8wAkCJXKrdmTa-8419LNxW_yjkvoDD53n3X5CHhYkSymU77p0v6yWO38qDWeKJ-Fm_PrMAo72_rizDBj_yPa5LA3bT_EnsgZtC-sp8_SCDIH41bjiCGpRHhqgZmyw`, - fmt.Sprintf(`"%s"`, certPemPs), - true, - "", - }, - { - "success-ps256-jwk", - "ps256", - `eyJ0eXAiOiAiSldUIiwgImFsZyI6ICJQUzI1NiJ9.eyJuYmYiOiAxNDQ0NDc4NDAwLCAiZm9vIjogImJhciJ9.i0F3MHWzOsBNLqjQzK1UVeQid9xPMowCoUsoM-C2BDxUY-FMKmCeJ1NJ4TGnS9HzFK1ftEvRnPT7EOxOkHPoCk1rz3feTFgtHtNzQqLM1IBTnz6aHHOrda_bKPHH9ZIYCRQUPXhpC90ivW_IJR-f7Z1WLrMXaJ71i1XteruENHrJJJDn0HedHG6N0VHugBHrak5k57cbE31utAdx83TEd8v2Y8wAkCJXKrdmTa-8419LNxW_yjkvoDD53n3X5CHhYkSymU77p0v6yWO38qDWeKJ-Fm_PrMAo72_rizDBj_yPa5LA3bT_EnsgZtC-sp8_SCDIH41bjiCGpRHhqgZmyw`, - fmt.Sprintf("`%s`", keyJWKPs), - true, - "", - }, - { - "success-es256-cert", - "es256", - `eyJ0eXAiOiAiSldUIiwgImFsZyI6ICJFUzI1NiJ9.eyJuYmYiOiAxNDQ0NDc4NDAwLCAiaXNzIjogInh4eCJ9.lArczfN-pIL8oUU-7PU83u-zfXougXBZj6drFeKFsPEoVhy9WAyiZlRshYqjTSXdaw8yw2L-ovt4zTUZb2PWMg`, - fmt.Sprintf(`"%s"`, certPemEs256), - true, - "", - }, - { - "success-es256-jwk", - "es256", - `eyJ0eXAiOiAiSldUIiwgImFsZyI6ICJFUzI1NiJ9.eyJuYmYiOiAxNDQ0NDc4NDAwLCAiaXNzIjogInh4eCJ9.lArczfN-pIL8oUU-7PU83u-zfXougXBZj6drFeKFsPEoVhy9WAyiZlRshYqjTSXdaw8yw2L-ovt4zTUZb2PWMg`, - fmt.Sprintf("`%s`", keyJWKEs256), - true, - "", - }, - { - "failure-bad token", - "rs256", - `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9.Yt89BjaPCNgol478rYyH66-XgkHos02TsVwxLH3ZlvOoIVjbhYW8q1_MHehct1-yBf1UOX3g-lUrIjpoDtX1TfAESuaWTjYPixRvjfJ-Nn75JF8QuAl5PD27C6aJ4PjUPNfj0kwYBnNQ_oX-ZFb781xRi7qRDB6swE4eBUxzHqKUJBLaMM2r8k1-9iE3ERNeqTJUhV__p0aSyRj-i62rdZ4TC5nhxtWodiGP4e4GrYlXkdaKduK63cfdJF-kfZfTsoDs_xy84pZOkzlflxuNv9bNqd-3ISAdWe4gsEvWWJ8v70-QWkydnH8rhj95DaqoXrjfzbOgDpKtdxJC4daVPKvntykzrxKhZ9UtWzm3OvJSKeyWujFZlldiTfBLqNDgdi-Boj_VxO5Pdh-67lC3L-pBMm4BgUqf6rakBQvoH7AV6zD5CbFixh7DuqJ4eJHHItWzJwDctMrV3asm-uOE1E2B7GErGo3iX6S9Iun_kvRUp6kyvOaDq5VvXzQOKyLQIQyHGGs0aIV5cFI2IuO5Rt0uUj5mzPQrQWHgI4r6Mc5bzmq2QLxBQE8OJ1RFhRpsuoWQyDM8aRiMQIJe1g3x4dnxbJK4dYheYblKHFepScYqT1hllDp3oUNn89sIjQIhJTe8KFATu4K8ppluys7vhpE2a_tq8i5O0MFxWmsxN4Q`, - fmt.Sprintf(`"%s"`, certPem), - false, - "", - }, - { - "failure-wrong key", - "ps256", - `eyJ0eXAiOiAiSldUIiwgImFsZyI6ICJQUzI1NiJ9.eyJuYmYiOiAxNDQ0NDc4NDAwLCAiZm9vIjogImJhciJ9.i0F3MHWzOsBNLqjQzK1UVeQid9xPMowCoUsoM-C2BDxUY-FMKmCeJ1NJ4TGnS9HzFK1ftEvRnPT7EOxOkHPoCk1rz3feTFgtHtNzQqLM1IBTnz6aHHOrda_bKPHH9ZIYCRQUPXhpC90ivW_IJR-f7Z1WLrMXaJ71i1XteruENHrJJJDn0HedHG6N0VHugBHrak5k57cbE31utAdx83TEd8v2Y8wAkCJXKrdmTa-8419LNxW_yjkvoDD53n3X5CHhYkSymU77p0v6yWO38qDWeKJ-Fm_PrMAo72_rizDBj_yPa5LA3bT_EnsgZtC-sp8_SCDIH41bjiCGpRHhqgZmyw`, - fmt.Sprintf(`"%s"`, certPem), - false, - "", - }, - { - "failure-wrong alg", - "ps256", - `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9.N0-EVdv5pvUfZYFRzMGnsWpNLHgwMEgViPwpuLBEtt32682OgnOK-N4X-2gpQEjQIbUr0IFym8YsRQU9GZvqQP72Sd6yOQNGSNeE74DpUZCAjBa9SBIb1UlD2MxZB-e7YJiEyo7pZhimaqorXrgorlaXYGMvsCFWDYmBLzGaGYaGJyEpkZHzHb7ujsDrJJjdEtDV3kh13gTHzLPvqnoXuuxelXye_8LPIhvgDy52gT4shUEso71pJCMv_IqAR19ljVE17lJzoi6VhRn6ReNUE-yg4KfCO4Ypnuu-mcQr7XtmSYoWkX72L5UQ-EyWkoz-w0SYKoJTPzHkTL2thYStksVpeNkGuck25aUdtrQgmPbao0QOWBFlkg03e6mPCD2-aXOt1ofth9mZGjxWMHX-mUqHaNmaWM3WhRztJ73hWrmB1YOdYQtOEHejfvR_td5tqIw4W6ufRy2ScOypGQe7kNaUZxpgxZ1927ZGNiQgawIOAQwXOcFx1JNSEIeg55-cYJrHPxsXGOB9ZxW-qnswmFJp474iUVXjzGhLexJDXBwvKGs_O3JFjMsvyV9_hm7bnQU0vG_HgPYs5i9VOHRMujq1vFBcm52TFVOBGdWaGfb9RRdLLYvVkJLk0Poh19rsCWb7-Vc3mAaGGpvuk4Wv-PnGGNC-V-FQqIbijHDrn_g`, - fmt.Sprintf(`"%s"`, certPem), - false, - "", - }, - { - "failure-invalid token", - "rs256", - `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9`, - fmt.Sprintf(`"%s"`, certPem), - false, - "encoded JWT must have 3 sections, found 2", - }, - { - "failure-bad pem certificate block", - "rs256", - `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9.N0-EVdv5pvUfZYFRzMGnsWpNLHgwMEgViPwpuLBEtt32682OgnOK-N4X-2gpQEjQIbUr0IFym8YsRQU9GZvqQP72Sd6yOQNGSNeE74DpUZCAjBa9SBIb1UlD2MxZB-e7YJiEyo7pZhimaqorXrgorlaXYGMvsCFWDYmBLzGaGYaGJyEpkZHzHb7ujsDrJJjdEtDV3kh13gTHzLPvqnoXuuxelXye_8LPIhvgDy52gT4shUEso71pJCMv_IqAR19ljVE17lJzoi6VhRn6ReNUE-yg4KfCO4Ypnuu-mcQr7XtmSYoWkX72L5UQ-EyWkoz-w0SYKoJTPzHkTL2thYStksVpeNkGuck25aUdtrQgmPbao0QOWBFlkg03e6mPCD2-aXOt1ofth9mZGjxWMHX-mUqHaNmaWM3WhRztJ73hWrmB1YOdYQtOEHejfvR_td5tqIw4W6ufRy2ScOypGQe7kNaUZxpgxZ1927ZGNiQgawIOAQwXOcFx1JNSEIeg55-cYJrHPxsXGOB9ZxW-qnswmFJp474iUVXjzGhLexJDXBwvKGs_O3JFjMsvyV9_hm7bnQU0vG_HgPYs5i9VOHRMujq1vFBcm52TFVOBGdWaGfb9RRdLLYvVkJLk0Poh19rsCWb7-Vc3mAaGGpvuk4Wv-PnGGNC-V-FQqIbijHDrn_g`, - fmt.Sprintf(`"%s"`, certPemBadBlock), - false, - "failed to extract a Key from the PEM certificate", - }, - { - "failure-extra data after pem certificate block", - "rs256", - `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9.N0-EVdv5pvUfZYFRzMGnsWpNLHgwMEgViPwpuLBEtt32682OgnOK-N4X-2gpQEjQIbUr0IFym8YsRQU9GZvqQP72Sd6yOQNGSNeE74DpUZCAjBa9SBIb1UlD2MxZB-e7YJiEyo7pZhimaqorXrgorlaXYGMvsCFWDYmBLzGaGYaGJyEpkZHzHb7ujsDrJJjdEtDV3kh13gTHzLPvqnoXuuxelXye_8LPIhvgDy52gT4shUEso71pJCMv_IqAR19ljVE17lJzoi6VhRn6ReNUE-yg4KfCO4Ypnuu-mcQr7XtmSYoWkX72L5UQ-EyWkoz-w0SYKoJTPzHkTL2thYStksVpeNkGuck25aUdtrQgmPbao0QOWBFlkg03e6mPCD2-aXOt1ofth9mZGjxWMHX-mUqHaNmaWM3WhRztJ73hWrmB1YOdYQtOEHejfvR_td5tqIw4W6ufRy2ScOypGQe7kNaUZxpgxZ1927ZGNiQgawIOAQwXOcFx1JNSEIeg55-cYJrHPxsXGOB9ZxW-qnswmFJp474iUVXjzGhLexJDXBwvKGs_O3JFjMsvyV9_hm7bnQU0vG_HgPYs5i9VOHRMujq1vFBcm52TFVOBGdWaGfb9RRdLLYvVkJLk0Poh19rsCWb7-Vc3mAaGGpvuk4Wv-PnGGNC-V-FQqIbijHDrn_g`, - fmt.Sprintf(`"%s"`, certPemExtraData), - false, - "extra data after a PEM certificate block", - }, - { - "failure-bad pem certificate", - "rs256", - `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9.N0-EVdv5pvUfZYFRzMGnsWpNLHgwMEgViPwpuLBEtt32682OgnOK-N4X-2gpQEjQIbUr0IFym8YsRQU9GZvqQP72Sd6yOQNGSNeE74DpUZCAjBa9SBIb1UlD2MxZB-e7YJiEyo7pZhimaqorXrgorlaXYGMvsCFWDYmBLzGaGYaGJyEpkZHzHb7ujsDrJJjdEtDV3kh13gTHzLPvqnoXuuxelXye_8LPIhvgDy52gT4shUEso71pJCMv_IqAR19ljVE17lJzoi6VhRn6ReNUE-yg4KfCO4Ypnuu-mcQr7XtmSYoWkX72L5UQ-EyWkoz-w0SYKoJTPzHkTL2thYStksVpeNkGuck25aUdtrQgmPbao0QOWBFlkg03e6mPCD2-aXOt1ofth9mZGjxWMHX-mUqHaNmaWM3WhRztJ73hWrmB1YOdYQtOEHejfvR_td5tqIw4W6ufRy2ScOypGQe7kNaUZxpgxZ1927ZGNiQgawIOAQwXOcFx1JNSEIeg55-cYJrHPxsXGOB9ZxW-qnswmFJp474iUVXjzGhLexJDXBwvKGs_O3JFjMsvyV9_hm7bnQU0vG_HgPYs5i9VOHRMujq1vFBcm52TFVOBGdWaGfb9RRdLLYvVkJLk0Poh19rsCWb7-Vc3mAaGGpvuk4Wv-PnGGNC-V-FQqIbijHDrn_g`, - fmt.Sprintf(`"%s"`, certPemBadCertificate), - false, - "failed to parse a PEM certificate", - }, - { - "failure-bad jwk key", - "rs256", - `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJuYmYiOjE0NDQ0Nzg0MDB9.N0-EVdv5pvUfZYFRzMGnsWpNLHgwMEgViPwpuLBEtt32682OgnOK-N4X-2gpQEjQIbUr0IFym8YsRQU9GZvqQP72Sd6yOQNGSNeE74DpUZCAjBa9SBIb1UlD2MxZB-e7YJiEyo7pZhimaqorXrgorlaXYGMvsCFWDYmBLzGaGYaGJyEpkZHzHb7ujsDrJJjdEtDV3kh13gTHzLPvqnoXuuxelXye_8LPIhvgDy52gT4shUEso71pJCMv_IqAR19ljVE17lJzoi6VhRn6ReNUE-yg4KfCO4Ypnuu-mcQr7XtmSYoWkX72L5UQ-EyWkoz-w0SYKoJTPzHkTL2thYStksVpeNkGuck25aUdtrQgmPbao0QOWBFlkg03e6mPCD2-aXOt1ofth9mZGjxWMHX-mUqHaNmaWM3WhRztJ73hWrmB1YOdYQtOEHejfvR_td5tqIw4W6ufRy2ScOypGQe7kNaUZxpgxZ1927ZGNiQgawIOAQwXOcFx1JNSEIeg55-cYJrHPxsXGOB9ZxW-qnswmFJp474iUVXjzGhLexJDXBwvKGs_O3JFjMsvyV9_hm7bnQU0vG_HgPYs5i9VOHRMujq1vFBcm52TFVOBGdWaGfb9RRdLLYvVkJLk0Poh19rsCWb7-Vc3mAaGGpvuk4Wv-PnGGNC-V-FQqIbijHDrn_g`, - fmt.Sprintf("`%s`", keyJWKBadKey), - false, - "failed to parse a JWK key (set)", - }, - { - "success-cert", - "rs384", - `eyJhbGciOiJSUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.b__y2zjqMoD7iWbHeQ0lNpnche3ph5-AwrIQICLMQQGtEz9WMBteHydkC5g01bm3TBX1d04Z5IEOsuK6btAtWma04c5NYqaUyNEUJKYCFoY02uH0jGdGfL6R5Kkv0lkNvN0s3Nex9jMaVVgqx8bcrOU0uRBFT67sXcm11LHaB9BwKFslolzHClxgXy5RIZb4OFk_7Yk7xTC6PcvEWkkGR9uXBhfDEig5WqdwOWPeulimvARDw14U35rzeh9xpGAPjBKeE-y20fXAk0cSF1H69C-Qa1jDQheYIrAJ6XMYGNZWuay5-smmeefe67eweEt1q-AD1NFepqkmZX382DGuYQ`, - fmt.Sprintf(`"%s"`, certPemRs), - true, - "", - }, - { - "success-key", - "rs384", - `eyJhbGciOiJSUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.b__y2zjqMoD7iWbHeQ0lNpnche3ph5-AwrIQICLMQQGtEz9WMBteHydkC5g01bm3TBX1d04Z5IEOsuK6btAtWma04c5NYqaUyNEUJKYCFoY02uH0jGdGfL6R5Kkv0lkNvN0s3Nex9jMaVVgqx8bcrOU0uRBFT67sXcm11LHaB9BwKFslolzHClxgXy5RIZb4OFk_7Yk7xTC6PcvEWkkGR9uXBhfDEig5WqdwOWPeulimvARDw14U35rzeh9xpGAPjBKeE-y20fXAk0cSF1H69C-Qa1jDQheYIrAJ6XMYGNZWuay5-smmeefe67eweEt1q-AD1NFepqkmZX382DGuYQ`, - fmt.Sprintf(`"%s"`, certKeyRs), - true, - "", - }, - { - "success-jwk", - "rs384", - `eyJhbGciOiJSUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.b__y2zjqMoD7iWbHeQ0lNpnche3ph5-AwrIQICLMQQGtEz9WMBteHydkC5g01bm3TBX1d04Z5IEOsuK6btAtWma04c5NYqaUyNEUJKYCFoY02uH0jGdGfL6R5Kkv0lkNvN0s3Nex9jMaVVgqx8bcrOU0uRBFT67sXcm11LHaB9BwKFslolzHClxgXy5RIZb4OFk_7Yk7xTC6PcvEWkkGR9uXBhfDEig5WqdwOWPeulimvARDw14U35rzeh9xpGAPjBKeE-y20fXAk0cSF1H69C-Qa1jDQheYIrAJ6XMYGNZWuay5-smmeefe67eweEt1q-AD1NFepqkmZX382DGuYQ`, - fmt.Sprintf("`%s`", keyJWKRs), - true, - "", - }, - { - "failure-wrong key", - "rs384", - `eyJhbGciOiJSUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.b__y2zjqMoD7iWbHeQ0lNpnche3ph5-AwrIQICLMQQGtEz9WMBteHydkC5g01bm3TBX1d04Z5IEOsuK6btAtWma04c5NYqaUyNEUJKYCFoY02uH0jGdGfL6R5Kkv0lkNvN0s3Nex9jMaVVgqx8bcrOU0uRBFT67sXcm11LHaB9BwKFslolzHClxgXy5RIZb4OFk_7Yk7xTC6PcvEWkkGR9uXBhfDEig5WqdwOWPeulimvARDw14U35rzeh9xpGAPjBKeE-y20fXAk0cSF1H69C-Qa1jDQheYIrAJ6XMYGNZWuay5-smmeefe67eweEt1q-AD1NFepqkmZX382DGuYQ`, - fmt.Sprintf(`"%s"`, certPem), - false, - "", - }, - { - "success-cert", - "rs512", - `eyJhbGciOiJSUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.VSe3qK5Gp0Q0_5nRgMFu25yw74FIgX-kXPOemSi62l-AxeVdUw8rOpEFrSTCaVjd3mPfKb-B056a-gtrbpXK9sUQnFdqdsyt8gHK-umz5lVyWfoAgj51Ontv-9K_pRORD9wqKqdTLZjCxJ5tyKoO0gY3SwwqSqGrp85vUjvEcK3jbMKINGRUNnOokeSm7byUEJsfKVUbPboSX1TGyvjDOZxxSITj8-bzZZ3F21DJ23N2IiJN7FW8Xj-SYyphXo-ML50o5bjW9YlQ5BDk-RW1I4eE-KpsxhApPv_xIgE8d89PVtXFuoJtv0yLRaZ1q04Fl9KNoMyZrmr349yppn0JlQ`, - fmt.Sprintf(`"%s"`, certPemRs), - true, - "", - }, - { - "success-key", - "rs512", - `eyJhbGciOiJSUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.VSe3qK5Gp0Q0_5nRgMFu25yw74FIgX-kXPOemSi62l-AxeVdUw8rOpEFrSTCaVjd3mPfKb-B056a-gtrbpXK9sUQnFdqdsyt8gHK-umz5lVyWfoAgj51Ontv-9K_pRORD9wqKqdTLZjCxJ5tyKoO0gY3SwwqSqGrp85vUjvEcK3jbMKINGRUNnOokeSm7byUEJsfKVUbPboSX1TGyvjDOZxxSITj8-bzZZ3F21DJ23N2IiJN7FW8Xj-SYyphXo-ML50o5bjW9YlQ5BDk-RW1I4eE-KpsxhApPv_xIgE8d89PVtXFuoJtv0yLRaZ1q04Fl9KNoMyZrmr349yppn0JlQ`, - fmt.Sprintf(`"%s"`, certKeyRs), - true, - "", - }, - { - "success-jwk", - "rs512", - `eyJhbGciOiJSUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.VSe3qK5Gp0Q0_5nRgMFu25yw74FIgX-kXPOemSi62l-AxeVdUw8rOpEFrSTCaVjd3mPfKb-B056a-gtrbpXK9sUQnFdqdsyt8gHK-umz5lVyWfoAgj51Ontv-9K_pRORD9wqKqdTLZjCxJ5tyKoO0gY3SwwqSqGrp85vUjvEcK3jbMKINGRUNnOokeSm7byUEJsfKVUbPboSX1TGyvjDOZxxSITj8-bzZZ3F21DJ23N2IiJN7FW8Xj-SYyphXo-ML50o5bjW9YlQ5BDk-RW1I4eE-KpsxhApPv_xIgE8d89PVtXFuoJtv0yLRaZ1q04Fl9KNoMyZrmr349yppn0JlQ`, - fmt.Sprintf("`%s`", keyJWKRs), - true, - "", - }, - { - "failure-wrong key", - "rs512", - `eyJhbGciOiJSUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.VSe3qK5Gp0Q0_5nRgMFu25yw74FIgX-kXPOemSi62l-AxeVdUw8rOpEFrSTCaVjd3mPfKb-B056a-gtrbpXK9sUQnFdqdsyt8gHK-umz5lVyWfoAgj51Ontv-9K_pRORD9wqKqdTLZjCxJ5tyKoO0gY3SwwqSqGrp85vUjvEcK3jbMKINGRUNnOokeSm7byUEJsfKVUbPboSX1TGyvjDOZxxSITj8-bzZZ3F21DJ23N2IiJN7FW8Xj-SYyphXo-ML50o5bjW9YlQ5BDk-RW1I4eE-KpsxhApPv_xIgE8d89PVtXFuoJtv0yLRaZ1q04Fl9KNoMyZrmr349yppn0JlQ`, - fmt.Sprintf(`"%s"`, certPem), - false, - "", - }, - { - "success-ps384-cert", - "ps384", - `eyJhbGciOiJQUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.EHPUvPr6uJOYqdza95WbM1SYD8atZHJEVRggpwOWnHGsjQBoEarJb8QgW7TY22OXwGw2HWluTiyT_MAz02NaHRzZv6AgrmxCLChMWkCHLwPxqjs0xSvVAMLzHHq2X2Bcujo9KORGudR7zKz8pOX5Mfnm7Z6OGtqPCPLaIdVJlddNsG6a571NOuVuDWbcg0omeRDANZpCZMJeAQN2M-4Q61ef6zcQHK1R-QqzBhw6HzMgqR1LRJ0xbrmD-L5o53JM3pV1e1juKNXVK3vWkDQRCQORFn1lyH5isfSsiiHW-x90sUC7TrU_cOji4MMmOCME6kkwxe57ZgpeXtdVTvldpw`, - fmt.Sprintf(`"%s"`, certPemPs384), - true, - "", - }, - { - "success-ps384-key", - "ps384", - `eyJhbGciOiJQUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.EHPUvPr6uJOYqdza95WbM1SYD8atZHJEVRggpwOWnHGsjQBoEarJb8QgW7TY22OXwGw2HWluTiyT_MAz02NaHRzZv6AgrmxCLChMWkCHLwPxqjs0xSvVAMLzHHq2X2Bcujo9KORGudR7zKz8pOX5Mfnm7Z6OGtqPCPLaIdVJlddNsG6a571NOuVuDWbcg0omeRDANZpCZMJeAQN2M-4Q61ef6zcQHK1R-QqzBhw6HzMgqR1LRJ0xbrmD-L5o53JM3pV1e1juKNXVK3vWkDQRCQORFn1lyH5isfSsiiHW-x90sUC7TrU_cOji4MMmOCME6kkwxe57ZgpeXtdVTvldpw`, - fmt.Sprintf(`"%s"`, certKeyPs384), - true, - "", - }, - { - "success-ps384-jwk", - "ps384", - `eyJhbGciOiJQUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.EHPUvPr6uJOYqdza95WbM1SYD8atZHJEVRggpwOWnHGsjQBoEarJb8QgW7TY22OXwGw2HWluTiyT_MAz02NaHRzZv6AgrmxCLChMWkCHLwPxqjs0xSvVAMLzHHq2X2Bcujo9KORGudR7zKz8pOX5Mfnm7Z6OGtqPCPLaIdVJlddNsG6a571NOuVuDWbcg0omeRDANZpCZMJeAQN2M-4Q61ef6zcQHK1R-QqzBhw6HzMgqR1LRJ0xbrmD-L5o53JM3pV1e1juKNXVK3vWkDQRCQORFn1lyH5isfSsiiHW-x90sUC7TrU_cOji4MMmOCME6kkwxe57ZgpeXtdVTvldpw`, - fmt.Sprintf("`%s`", keyJWKPs384), - true, - "", - }, - { - "failure-ps384-wrong key", - "ps384", - `eyJhbGciOiJQUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.EHPUvPr6uJOYqdza95WbM1SYD8atZHJEVRggpwOWnHGsjQBoEarJb8QgW7TY22OXwGw2HWluTiyT_MAz02NaHRzZv6AgrmxCLChMWkCHLwPxqjs0xSvVAMLzHHq2X2Bcujo9KORGudR7zKz8pOX5Mfnm7Z6OGtqPCPLaIdVJlddNsG6a571NOuVuDWbcg0omeRDANZpCZMJeAQN2M-4Q61ef6zcQHK1R-QqzBhw6HzMgqR1LRJ0xbrmD-L5o53JM3pV1e1juKNXVK3vWkDQRCQORFn1lyH5isfSsiiHW-x90sUC7TrU_cOji4MMmOCME6kkwxe57ZgpeXtdVTvldpw`, - fmt.Sprintf(`"%s"`, certPem), - false, - "", - }, - { - "success-ps512-cert", - "ps512", - `eyJhbGciOiJQUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.VRlkPtiUq5MmBNgyuBqxv2_aX40STrWrBB2sSmGbxI78jVG_3hVoh7Mk-wUmFL389qpf05xNdn-gpMe-MSDUux7U7EuFspFZdYTUBo9wRvEBe4e1rHUCG00lVdYCG7eEgbAxM3cUhrHRwExBte30qBrFFUY9FgG-kJdYhgyh7VquMGuKgiS8CP_H0Gp1mIvTw6eEnSFAoKiryw9edUZ78pHELNn4y18YZvEndeNZh7f19LCtrB0G2bJUHGM4vPcwo2D-UAhEFBpSlnnqXDLSWOhUgLNLu0kZACXhT808KT6fdF6eFihdThmWN7_HUz2znjrjs71CqqDJgLhkGs8UvQ`, - fmt.Sprintf(`"%s"`, certPemPs512), - true, - "", - }, - { - "success-ps512-key", - "ps512", - `eyJhbGciOiJQUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.VRlkPtiUq5MmBNgyuBqxv2_aX40STrWrBB2sSmGbxI78jVG_3hVoh7Mk-wUmFL389qpf05xNdn-gpMe-MSDUux7U7EuFspFZdYTUBo9wRvEBe4e1rHUCG00lVdYCG7eEgbAxM3cUhrHRwExBte30qBrFFUY9FgG-kJdYhgyh7VquMGuKgiS8CP_H0Gp1mIvTw6eEnSFAoKiryw9edUZ78pHELNn4y18YZvEndeNZh7f19LCtrB0G2bJUHGM4vPcwo2D-UAhEFBpSlnnqXDLSWOhUgLNLu0kZACXhT808KT6fdF6eFihdThmWN7_HUz2znjrjs71CqqDJgLhkGs8UvQ`, - fmt.Sprintf(`"%s"`, certKeyPs512), - true, - "", - }, - { - "success-ps512-jwk", - "ps512", - `eyJhbGciOiJQUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.VRlkPtiUq5MmBNgyuBqxv2_aX40STrWrBB2sSmGbxI78jVG_3hVoh7Mk-wUmFL389qpf05xNdn-gpMe-MSDUux7U7EuFspFZdYTUBo9wRvEBe4e1rHUCG00lVdYCG7eEgbAxM3cUhrHRwExBte30qBrFFUY9FgG-kJdYhgyh7VquMGuKgiS8CP_H0Gp1mIvTw6eEnSFAoKiryw9edUZ78pHELNn4y18YZvEndeNZh7f19LCtrB0G2bJUHGM4vPcwo2D-UAhEFBpSlnnqXDLSWOhUgLNLu0kZACXhT808KT6fdF6eFihdThmWN7_HUz2znjrjs71CqqDJgLhkGs8UvQ`, - fmt.Sprintf("`%s`", keyJWKPs512), - true, - "", - }, - { - "failure-wrong key", - "ps512", - `eyJhbGciOiJQUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.VRlkPtiUq5MmBNgyuBqxv2_aX40STrWrBB2sSmGbxI78jVG_3hVoh7Mk-wUmFL389qpf05xNdn-gpMe-MSDUux7U7EuFspFZdYTUBo9wRvEBe4e1rHUCG00lVdYCG7eEgbAxM3cUhrHRwExBte30qBrFFUY9FgG-kJdYhgyh7VquMGuKgiS8CP_H0Gp1mIvTw6eEnSFAoKiryw9edUZ78pHELNn4y18YZvEndeNZh7f19LCtrB0G2bJUHGM4vPcwo2D-UAhEFBpSlnnqXDLSWOhUgLNLu0kZACXhT808KT6fdF6eFihdThmWN7_HUz2znjrjs71CqqDJgLhkGs8UvQ`, - fmt.Sprintf(`"%s"`, certPem), - false, - "", - }, - { - "success-es384-cert", - "es384", - `eyJhbGciOiJFUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.w85PzWrIQbJBOROnah0pa8or2LsXWnj88bwG1R-zf5Mm20CaYGPKPTQEsU_y-dzaWyDV1Na7nfaGaH3Khcvj8yS-bidZ0OZVVFDk9oabX7ZYvAHo2pTAOfxc11TeOYSF`, - fmt.Sprintf(`"%s"`, certPemEs384), - true, - "", - }, - { - "success-es384-key", - "es384", - `eyJhbGciOiJFUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.w85PzWrIQbJBOROnah0pa8or2LsXWnj88bwG1R-zf5Mm20CaYGPKPTQEsU_y-dzaWyDV1Na7nfaGaH3Khcvj8yS-bidZ0OZVVFDk9oabX7ZYvAHo2pTAOfxc11TeOYSF`, - fmt.Sprintf(`"%s"`, certKeyEs384), - true, - "", - }, - { - "success-es384-jwk", - "es384", - `eyJhbGciOiJFUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.w85PzWrIQbJBOROnah0pa8or2LsXWnj88bwG1R-zf5Mm20CaYGPKPTQEsU_y-dzaWyDV1Na7nfaGaH3Khcvj8yS-bidZ0OZVVFDk9oabX7ZYvAHo2pTAOfxc11TeOYSF`, - fmt.Sprintf("`%s`", keyJWKEs384), - true, - "", - }, - { - "failure-wrong key", - "es384", - `eyJhbGciOiJFUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.w85PzWrIQbJBOROnah0pa8or2LsXWnj88bwG1R-zf5Mm20CaYGPKPTQEsU_y-dzaWyDV1Na7nfaGaH3Khcvj8yS-bidZ0OZVVFDk9oabX7ZYvAHo2pTAOfxc11TeOYSF`, - fmt.Sprintf(`"%s"`, certPem), - false, - "", - }, - { - "success-es512-cert", - "es512", - `eyJhbGciOiJFUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.AYpssEoEqq9We9aKsnRykpECAVEOBRJJu8UgDzoL-F8fmB2LPxpS4Gl7D-9wAO5AJt4-9YSsgOb5FLc20MrZN30AAFYopZf75T1pEJQFrdDmOKT45abbrorcR7G_AHDbhBdDNM_R6GojYFg_HPxHndof745Yq5Tfw9PpJc-9kSyk6kqO`, - fmt.Sprintf(`"%s"`, certPemEs512), - true, - "", - }, - { - "success-es512-key", - "es512", - `eyJhbGciOiJFUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.AYpssEoEqq9We9aKsnRykpECAVEOBRJJu8UgDzoL-F8fmB2LPxpS4Gl7D-9wAO5AJt4-9YSsgOb5FLc20MrZN30AAFYopZf75T1pEJQFrdDmOKT45abbrorcR7G_AHDbhBdDNM_R6GojYFg_HPxHndof745Yq5Tfw9PpJc-9kSyk6kqO`, - fmt.Sprintf(`"%s"`, certKeyEs512), - true, - "", - }, - { - "success-es512-jwk", - "es512", - `eyJhbGciOiJFUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.AYpssEoEqq9We9aKsnRykpECAVEOBRJJu8UgDzoL-F8fmB2LPxpS4Gl7D-9wAO5AJt4-9YSsgOb5FLc20MrZN30AAFYopZf75T1pEJQFrdDmOKT45abbrorcR7G_AHDbhBdDNM_R6GojYFg_HPxHndof745Yq5Tfw9PpJc-9kSyk6kqO`, - fmt.Sprintf("`%s`", keyJWKEs512), - true, - "", - }, - { - "failure-wrong key", - "es512", - `eyJhbGciOiJFUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.AYpssEoEqq9We9aKsnRykpECAVEOBRJJu8UgDzoL-F8fmB2LPxpS4Gl7D-9wAO5AJt4-9YSsgOb5FLc20MrZN30AAFYopZf75T1pEJQFrdDmOKT45abbrorcR7G_AHDbhBdDNM_R6GojYFg_HPxHndof745Yq5Tfw9PpJc-9kSyk6kqO`, - fmt.Sprintf(`"%s"`, certPem), - false, - "", - }, - } - - type test struct { - note string - rules []string - expected interface{} - } - tests := []test{} - - for _, p := range params { - var exp interface{} - exp = fmt.Sprintf(`%t`, p.result) - if p.err != "" { - exp = &Error{Code: BuiltinErr, Message: p.err} - } - - tests = append(tests, test{ - p.note, - []string{fmt.Sprintf(`p = x { io.jwt.verify_%s("%s", %s, x) }`, p.alg, p.input1, p.input2)}, - exp, - }) - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownJWTVerifyHS256(t *testing.T) { - params := []struct { - note string - input1 string - input2 string - result bool - err string - }{ - { - "success", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWxpY2UiLCJhenAiOiJhbGljZSIsInN1Ym9yZGluYXRlcyI6W10sImhyIjpmYWxzZX0.rz3jTY033z-NrKfwrK89_dcLF7TN4gwCMj-fVBDyLoM`, - "secret", - true, - "", - }, - { - "failure-bad token", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWxpY2UiLCJhenAiOiJhbGljZSIsInN1Ym9yZGluYXRlcyI6W10sImhyIjpmYWxzZX0.R0NDxM1gHTucWQKwayMDre2PbMNR9K9efmOfygDZWcE`, - "secret", - false, - "", - }, - { - "failure-invalid token", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWxpY2UiLCJhenAiOiJhbGljZSIsInN1Ym9yZGluYXRlcyI6W10sImhyIjpmYWxzZX0`, - "secret", - false, - "encoded JWT must have 3 sections, found 2", - }, - } - - type test struct { - note string - rules []string - expected interface{} - } - tests := []test{} - - for _, p := range params { - var exp interface{} - exp = fmt.Sprintf(`%t`, p.result) - if p.err != "" { - exp = &Error{Code: BuiltinErr, Message: p.err} - } - - tests = append(tests, test{ - p.note, - []string{fmt.Sprintf(`p = x { io.jwt.verify_hs256("%s", "%s", x) }`, p.input1, p.input2)}, - exp, - }) - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownJWTVerifyHS384(t *testing.T) { - params := []struct { - note string - input1 string - input2 string - result bool - err string - }{ - { - "success", - `eyJhbGciOiJIUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.g98lHYzuqINVppLMoEZT7jlpX0IBSo9zKGoN9DhQg7Ua3YjLXbJMjzESjIHXOGLB`, - "secret", - true, - "", - }, - { - "failure-bad token", - `eyJhbGciOiJIUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.g98lHYzuqINVppLMoEZT7jlpX0IBSo9zKGoN9DhQg7Ua3YjLXbJMjzESjIHXOBAD`, - "secret", - false, - "", - }, - { - "failure-invalid token", - `eyJhbGciOiJIUzM4NCJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0`, - "secret", - false, - "encoded JWT must have 3 sections, found 2", - }, - } - - type test struct { - note string - rules []string - expected interface{} - } - tests := []test{} - - for _, p := range params { - var exp interface{} - exp = fmt.Sprintf(`%t`, p.result) - if p.err != "" { - exp = &Error{Code: BuiltinErr, Message: p.err} - } - - tests = append(tests, test{ - p.note, - []string{fmt.Sprintf(`p = x { io.jwt.verify_hs384("%s", "%s", x) }`, p.input1, p.input2)}, - exp, - }) - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownJWTVerifyHS512(t *testing.T) { - params := []struct { - note string - input1 string - input2 string - result bool - err string - }{ - { - "success", - `eyJhbGciOiJIUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.F6-xviRhK2OLcJJHFivhQqMN_dgX5boDrwbVKkdo9flQQNk-AaKpH3uYycFvBEd_erVefcsri_PkL4fjLSZ7ZA`, - "secret", - true, - "", - }, - { - "failure-bad token", - `eyJhbGciOiJIUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0.F6-xviRhK2OLcJJHFivhQqMN_dgX5boDrwbVKkdo9flQQNk-AaKpH3uYycFvBEd_erVefcsri_PkL4fjLSZBAD`, - "secret", - false, - "", - }, - { - "failure-invalid token", - `eyJhbGciOiJIUzUxMiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sIm5iZiI6MTQ1MTYwNjQwMH0`, - "secret", - false, - "encoded JWT must have 3 sections, found 2", - }, - } - - type test struct { - note string - rules []string - expected interface{} - } - tests := []test{} - - for _, p := range params { - var exp interface{} - exp = fmt.Sprintf(`%t`, p.result) - if p.err != "" { - exp = &Error{Code: BuiltinErr, Message: p.err} - } - - tests = append(tests, test{ - p.note, - []string{fmt.Sprintf(`p = x { io.jwt.verify_hs512("%s", "%s", x) }`, p.input1, p.input2)}, - exp, - }) - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownJWTDecodeVerify(t *testing.T) { - params := []struct { - note string // test name - token string // JWT - constraints string // constraints argument - valid bool // expected validity value - header string // expected header - payload string // expected claims - err string // expected error or "" for succes - }{ - { - "ps256-unconstrained", // no constraints at all (apart from supplying a key) - "eyJhbGciOiAiUFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieHh4In0.iCePYnD1U13oBe_6ylhmojmkY_VZNYXqVszAej8RImMGv51OEqARmYFkRZYTiYCiVFober7vcDq_stOj1uAJCuttygGW_dpHiN-3EWsU2E2vCnXlygWe0ud38pOC-OVyEFbXxO9-m51vnS-3VmBjEO8G1UE8bLFXTeFOGkUIj9dqlefJSWh5wa8XA3g9mj0jqpuJi-7QgEIeVHk-JzhGpoFqI2f-Df_agVvc2x4V-6fJmj7wV2IsaFPRi36mVQmg8S-dkxu4AlaeCILhyNZl8ewjBHHBjJFRwzcy88L00mzdO51ZxEYsBdQav3ux2sc6vjT9PvvjAwzcthQxEoEaNA", - fmt.Sprintf(`{"cert": "%s"}`, certPemPs), - true, - `{"alg": "PS256", "typ": "JWT"}`, - `{"iss": "xxx"}`, - "", - }, - { - "ps256-key-wrong", // wrong key for signature - "eyJhbGciOiAiUFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieHh4In0.iCePYnD1U13oBe_6ylhmojmkY_VZNYXqVszAej8RImMGv51OEqARmYFkRZYTiYCiVFober7vcDq_stOj1uAJCuttygGW_dpHiN-3EWsU2E2vCnXlygWe0ud38pOC-OVyEFbXxO9-m51vnS-3VmBjEO8G1UE8bLFXTeFOGkUIj9dqlefJSWh5wa8XA3g9mj0jqpuJi-7QgEIeVHk-JzhGpoFqI2f-Df_agVvc2x4V-6fJmj7wV2IsaFPRi36mVQmg8S-dkxu4AlaeCILhyNZl8ewjBHHBjJFRwzcy88L00mzdO51ZxEYsBdQav3ux2sc6vjT9PvvjAwzcthQxEoEaNA", - fmt.Sprintf(`{"cert": "%s"}`, certPem), - false, - `{}`, - `{}`, - "", - }, - { - "rs256-key-wrong", // wrong key for signature - "eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieHh4IiwgImV4cCI6IDMwMDB9.hqDP3AzshNhUZMI02U3nLPrj93QFrgs-74XFrF1Vry2bplrz-NKpdVdfTu8iY_bhmkWf2Om5DdwRZj2ZgpGahtnshnHaRq0RyqF-m3Y7oNj6JL_YMwgxsFIIHtBlagBqDU-gZK99iqSOSGqVhvxqX6gCqFgE7vnEGHeeDedtRM53coAJuwzy8rQV9m3TewoofPdPasGv-dBLQZ3qgmnibkSgb7SmFpjXBy8zL3xJXOZhAHYlgcmcEoFVaWlBguIcWA87WZlpCLYcdYTJzSZweC3QLUhZ4RLJW84-LMKp6xWLLPrp3OgnsduB2G9PYMmYw_qCkuY1KGwfH4PvCQbAzQ", - fmt.Sprintf(`{"cert": "%s"}`, certPem), - false, - `{}`, - `{}`, - "", - }, - { - "ps256-iss-ok", // enforce issuer - "eyJhbGciOiAiUFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieHh4In0.iCePYnD1U13oBe_6ylhmojmkY_VZNYXqVszAej8RImMGv51OEqARmYFkRZYTiYCiVFober7vcDq_stOj1uAJCuttygGW_dpHiN-3EWsU2E2vCnXlygWe0ud38pOC-OVyEFbXxO9-m51vnS-3VmBjEO8G1UE8bLFXTeFOGkUIj9dqlefJSWh5wa8XA3g9mj0jqpuJi-7QgEIeVHk-JzhGpoFqI2f-Df_agVvc2x4V-6fJmj7wV2IsaFPRi36mVQmg8S-dkxu4AlaeCILhyNZl8ewjBHHBjJFRwzcy88L00mzdO51ZxEYsBdQav3ux2sc6vjT9PvvjAwzcthQxEoEaNA", - fmt.Sprintf(`{"cert": "%s", "iss": "xxx"}`, certPemPs), - true, - `{"alg": "PS256", "typ": "JWT"}`, - `{"iss": "xxx"}`, - "", - }, - { - "ps256-iss-wrong", // wrong issuer - "eyJhbGciOiAiUFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieHh4In0.iCePYnD1U13oBe_6ylhmojmkY_VZNYXqVszAej8RImMGv51OEqARmYFkRZYTiYCiVFober7vcDq_stOj1uAJCuttygGW_dpHiN-3EWsU2E2vCnXlygWe0ud38pOC-OVyEFbXxO9-m51vnS-3VmBjEO8G1UE8bLFXTeFOGkUIj9dqlefJSWh5wa8XA3g9mj0jqpuJi-7QgEIeVHk-JzhGpoFqI2f-Df_agVvc2x4V-6fJmj7wV2IsaFPRi36mVQmg8S-dkxu4AlaeCILhyNZl8ewjBHHBjJFRwzcy88L00mzdO51ZxEYsBdQav3ux2sc6vjT9PvvjAwzcthQxEoEaNA", - fmt.Sprintf(`{"cert": "%s", "iss": "yyy"}`, certPemPs), - false, - `{}`, - `{}`, - "", - }, - { - "ps256-alg-ok", // constrained algorithm - "eyJhbGciOiAiUFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieHh4In0.iCePYnD1U13oBe_6ylhmojmkY_VZNYXqVszAej8RImMGv51OEqARmYFkRZYTiYCiVFober7vcDq_stOj1uAJCuttygGW_dpHiN-3EWsU2E2vCnXlygWe0ud38pOC-OVyEFbXxO9-m51vnS-3VmBjEO8G1UE8bLFXTeFOGkUIj9dqlefJSWh5wa8XA3g9mj0jqpuJi-7QgEIeVHk-JzhGpoFqI2f-Df_agVvc2x4V-6fJmj7wV2IsaFPRi36mVQmg8S-dkxu4AlaeCILhyNZl8ewjBHHBjJFRwzcy88L00mzdO51ZxEYsBdQav3ux2sc6vjT9PvvjAwzcthQxEoEaNA", - fmt.Sprintf(`{"cert": "%s", "alg": "PS256"}`, certPemPs), - true, - `{"alg": "PS256", "typ": "JWT"}`, - `{"iss": "xxx"}`, - "", - }, - { - "ps256-alg-wrong", // constrained algorithm, and it's wrong - "eyJhbGciOiAiUFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieHh4In0.iCePYnD1U13oBe_6ylhmojmkY_VZNYXqVszAej8RImMGv51OEqARmYFkRZYTiYCiVFober7vcDq_stOj1uAJCuttygGW_dpHiN-3EWsU2E2vCnXlygWe0ud38pOC-OVyEFbXxO9-m51vnS-3VmBjEO8G1UE8bLFXTeFOGkUIj9dqlefJSWh5wa8XA3g9mj0jqpuJi-7QgEIeVHk-JzhGpoFqI2f-Df_agVvc2x4V-6fJmj7wV2IsaFPRi36mVQmg8S-dkxu4AlaeCILhyNZl8ewjBHHBjJFRwzcy88L00mzdO51ZxEYsBdQav3ux2sc6vjT9PvvjAwzcthQxEoEaNA", - fmt.Sprintf(`{"cert": "%s", "alg": "RS256"}`, certPemPs), - false, - `{}`, - `{}`, - "", - }, - { - "rs256-exp-ok", // token expires, and it's still valid - "eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieHh4IiwgImV4cCI6IDMwMDB9.hqDP3AzshNhUZMI02U3nLPrj93QFrgs-74XFrF1Vry2bplrz-NKpdVdfTu8iY_bhmkWf2Om5DdwRZj2ZgpGahtnshnHaRq0RyqF-m3Y7oNj6JL_YMwgxsFIIHtBlagBqDU-gZK99iqSOSGqVhvxqX6gCqFgE7vnEGHeeDedtRM53coAJuwzy8rQV9m3TewoofPdPasGv-dBLQZ3qgmnibkSgb7SmFpjXBy8zL3xJXOZhAHYlgcmcEoFVaWlBguIcWA87WZlpCLYcdYTJzSZweC3QLUhZ4RLJW84-LMKp6xWLLPrp3OgnsduB2G9PYMmYw_qCkuY1KGwfH4PvCQbAzQ", - fmt.Sprintf(`{"cert": "%s", "time": 2000000000000}`, certPemPs), - true, - `{"alg": "RS256", "typ": "JWT"}`, - `{"iss": "xxx", "exp": 3000}`, - "", - }, - { - "rs256-exp-expired", // token expires, and it's stale at a chosen time - "eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieHh4IiwgImV4cCI6IDMwMDB9.hqDP3AzshNhUZMI02U3nLPrj93QFrgs-74XFrF1Vry2bplrz-NKpdVdfTu8iY_bhmkWf2Om5DdwRZj2ZgpGahtnshnHaRq0RyqF-m3Y7oNj6JL_YMwgxsFIIHtBlagBqDU-gZK99iqSOSGqVhvxqX6gCqFgE7vnEGHeeDedtRM53coAJuwzy8rQV9m3TewoofPdPasGv-dBLQZ3qgmnibkSgb7SmFpjXBy8zL3xJXOZhAHYlgcmcEoFVaWlBguIcWA87WZlpCLYcdYTJzSZweC3QLUhZ4RLJW84-LMKp6xWLLPrp3OgnsduB2G9PYMmYw_qCkuY1KGwfH4PvCQbAzQ", - fmt.Sprintf(`{"cert": "%s", "time": 4000000000000}`, certPemPs), - false, - `{}`, - `{}`, - "", - }, - { - "rs256-exp-now-expired", // token expires, and it's stale at the current implicitly specified real time - "eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieHh4IiwgImV4cCI6IDMwMDB9.hqDP3AzshNhUZMI02U3nLPrj93QFrgs-74XFrF1Vry2bplrz-NKpdVdfTu8iY_bhmkWf2Om5DdwRZj2ZgpGahtnshnHaRq0RyqF-m3Y7oNj6JL_YMwgxsFIIHtBlagBqDU-gZK99iqSOSGqVhvxqX6gCqFgE7vnEGHeeDedtRM53coAJuwzy8rQV9m3TewoofPdPasGv-dBLQZ3qgmnibkSgb7SmFpjXBy8zL3xJXOZhAHYlgcmcEoFVaWlBguIcWA87WZlpCLYcdYTJzSZweC3QLUhZ4RLJW84-LMKp6xWLLPrp3OgnsduB2G9PYMmYw_qCkuY1KGwfH4PvCQbAzQ", - fmt.Sprintf(`{"cert": "%s"}`, certPemPs), - false, - `{}`, - `{}`, - "", - }, - { - "rs256-exp-now-explicit-expired", // token expires, and it's stale at the current explicitly specified real time - "eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieHh4IiwgImV4cCI6IDMwMDB9.hqDP3AzshNhUZMI02U3nLPrj93QFrgs-74XFrF1Vry2bplrz-NKpdVdfTu8iY_bhmkWf2Om5DdwRZj2ZgpGahtnshnHaRq0RyqF-m3Y7oNj6JL_YMwgxsFIIHtBlagBqDU-gZK99iqSOSGqVhvxqX6gCqFgE7vnEGHeeDedtRM53coAJuwzy8rQV9m3TewoofPdPasGv-dBLQZ3qgmnibkSgb7SmFpjXBy8zL3xJXOZhAHYlgcmcEoFVaWlBguIcWA87WZlpCLYcdYTJzSZweC3QLUhZ4RLJW84-LMKp6xWLLPrp3OgnsduB2G9PYMmYw_qCkuY1KGwfH4PvCQbAzQ", - fmt.Sprintf(`{"cert": "%s", "time": now}`, certPemPs), - false, - `{}`, - `{}`, - "", - }, - { - "rs256-nbf-ok", // token has a commencement time, and it's commenced at a chosen time - "eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJuYmYiOiAxMDAwLCAiaXNzIjogInh4eCJ9.cwwYDfJhU_ambPIpwBJwDek05miffoudprr41IAYsl0IKekb1ii2uEgwkNM-LJtVXHe9hsK3gANFyfqoJuCZIBvaNMx_3Z0BUdeBs4k1UwBiZCpuud0ofgHKURwvehNgqDvRfchq_-K_Agi2iRdl0oShgLjN-gVbBl8pRwUbQrvASlcsCpZIKUyOzXNtaIZEFh1z6ISDy8UHHOdoieKpN23swya7QAcEb0wXEEKMkkhiRd5QHgWLk37Lnw2K89mKcq4Om0CtV9nHrxxmpYGSMPojCy16Gjdg5-xKyJWvxCfb3YUBUVM4RWa7ICOPRJWPuHxu9pPYG63hb_qDU6NLsw", - fmt.Sprintf(`{"cert": "%s", "time": 2000000000000}`, certPemPs), - true, - `{"alg": "RS256", "typ": "JWT"}`, - `{"iss": "xxx", "nbf": 1000}`, - "", - }, - { - "rs256-nbf-now-ok", // token has a commencement time, and it's commenced at the current implicitly specified time - "eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJuYmYiOiAxMDAwLCAiaXNzIjogInh4eCJ9.cwwYDfJhU_ambPIpwBJwDek05miffoudprr41IAYsl0IKekb1ii2uEgwkNM-LJtVXHe9hsK3gANFyfqoJuCZIBvaNMx_3Z0BUdeBs4k1UwBiZCpuud0ofgHKURwvehNgqDvRfchq_-K_Agi2iRdl0oShgLjN-gVbBl8pRwUbQrvASlcsCpZIKUyOzXNtaIZEFh1z6ISDy8UHHOdoieKpN23swya7QAcEb0wXEEKMkkhiRd5QHgWLk37Lnw2K89mKcq4Om0CtV9nHrxxmpYGSMPojCy16Gjdg5-xKyJWvxCfb3YUBUVM4RWa7ICOPRJWPuHxu9pPYG63hb_qDU6NLsw", - fmt.Sprintf(`{"cert": "%s"}`, certPemPs), - true, - `{"alg": "RS256", "typ": "JWT"}`, - `{"iss": "xxx", "nbf": 1000}`, - "", - }, - { - "rs256-nbf-toosoon", // token has a commencement time, and the chosen time is too early - "eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJuYmYiOiAxMDAwLCAiaXNzIjogInh4eCJ9.cwwYDfJhU_ambPIpwBJwDek05miffoudprr41IAYsl0IKekb1ii2uEgwkNM-LJtVXHe9hsK3gANFyfqoJuCZIBvaNMx_3Z0BUdeBs4k1UwBiZCpuud0ofgHKURwvehNgqDvRfchq_-K_Agi2iRdl0oShgLjN-gVbBl8pRwUbQrvASlcsCpZIKUyOzXNtaIZEFh1z6ISDy8UHHOdoieKpN23swya7QAcEb0wXEEKMkkhiRd5QHgWLk37Lnw2K89mKcq4Om0CtV9nHrxxmpYGSMPojCy16Gjdg5-xKyJWvxCfb3YUBUVM4RWa7ICOPRJWPuHxu9pPYG63hb_qDU6NLsw", - fmt.Sprintf(`{"cert": "%s", "time": 500000000000}`, certPemPs), - false, - `{}`, - `{}`, - "", - }, - { - "rs256-alg-missing", // alg is missing from the JOSE header - "eyJ0eXAiOiAiSldUIiwgImtpZCI6ICJrMSJ9.eyJpc3MiOiAieHh4IiwgInN1YiI6ICJmcmVkIn0.J4J4FgUD_P5fviVVjgvQWJDg-5XYTP_tHCwB3kSlYVKv8vmnZRNh4ke68OxfMP96iM-LZswG2fNqe-_piGIMepF5rCe1iIWAuz3qqkxfS9YVF3hvwoXhjJT0yIgrDMl1lfW5_XipNshZoxddWK3B7dnVW74MFazEEFuefiQm3PdMUX8jWGsmfgPnqBIZTizErNhoIMuRvYaVM1wA2nfrpVGONxMTaw8T0NRwYIuZwubbnNQ1yLhI0y3dsZvQ_lrh9Khtk9fS1V3SRh7aa9AvferJ4T-48qn_V1m3sINPgoA-uLGyyu3k_GkXRYW1yGNC-MH4T2cwhj89WITbIhusgQ", - fmt.Sprintf(`{"cert": "%s"}`, certPemPs), - false, - `{}`, - `{}`, - "", - }, - { - "rs256-crit-junk", // the JOSE header contains an unrecognized critical parameter - "eyJjcml0IjogWyJqdW5rIl0sICJraWQiOiAiazEiLCAiYWxnIjogIlJTMjU2IiwgInR5cCI6ICJKV1QiLCAianVuayI6ICJ4eHgifQ.eyJpc3MiOiAieHh4IiwgInN1YiI6ICJmcmVkIn0.YfoUpW5CgDBtxtBuOix3cdYJGT8cX9Mq7wOhIbjDK7eRQUsAmMY_0EQPh7bd7Yi1gLI3e11BKzguf2EHqAa1kbkHWwFniBO-RIi8q42v2uxC4lpEpIjfaaXB5XmsLfAXtYRqh0AObvbSho6VDXBP_Kn81nhIiE2yFbH14_jhRMSxDBs5ToSkXV-XJHw5bONP8NxPqEk9KF3ZJGzN7J_KoD6LjqfYai5K0eLNEIZh4C1WjTdmCKMR4K6ieZRQWZiSsnhSqLSQERir4n22G3QsdY7dOnCp-SS4VYu3V-PfsOSFMvQ-TTAN1geqMZ9A7k1CCLW0wxKBs-KCiYzmRTzwxA", - fmt.Sprintf(`{"cert": "%s"}`, certPemPs), - false, - `{}`, - `{}`, - "", - }, - { - "rsa256-nested", // one nesting level - "eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCIsICJjdHkiOiAiSldUIn0.ZXlKaGJHY2lPaUFpVWxNeU5UWWlMQ0FpZEhsd0lqb2dJa3BYVkNKOS5leUpwYzNNaU9pQWllSGg0SW4wLnJSUnJlUU9DYW9ZLW1Nazcyak5GZVk1YVlFUWhJZ0lFdFZkUTlYblltUUwyTHdfaDdNbkk0U0VPMVBwa0JIVEpyZnljbEplTHpfalJ2UGdJMlcxaDFCNGNaVDhDZ21pVXdxQXI5c0puZHlVQ1FtSWRrbm53WkI5cXAtX3BTdGRHWEo5WnAzeEo4NXotVEJpWlN0QUNUZFdlUklGSUU3VkxPa20tRmxZdzh5OTdnaUN4TmxUdWl3amxlTjMwZDhnWHUxNkZGQzJTSlhtRjZKbXYtNjJHbERhLW1CWFZ0bGJVSTVlWVUwaTdueTNyQjBYUVQxRkt4ZUZ3OF85N09FdV9jY3VLcl82ZHlHZVFHdnQ5Y3JJeEFBMWFZbDdmbVBrNkVhcjllTTNKaGVYMi00Wkx0d1FOY1RDT01YV0dIck1DaG5MWVc4WEFrTHJEbl9yRmxUaVMtZw.Xicc2sWCZ_Nithucsw9XD7YOKrirUdEnH3MyiPM-Ck3vEU2RsTBsfU2JPhfjp3phc0VOgsAXCzwU5PwyNyUo1490q8YSym-liMyO2Lk-hjH5fAxoizg9yD4II_lK6Wz_Tnpc0bBGDLdbuUhvgvO7yqo-leBQlsfRXOvw4VSPSEy8QPtbURtbnLpWY2jGBKz7vGI_o4qDJ3PicG0kyEiWZNh3wjeeCYRCWvXN8qh7Uk5EA-8J5vX651GqV-7gmaX1n-8DXamhaCQcE-p1cjSj04-X-_bJlQtmb-TT3bSyUPxgHVncvxNUby8jkUTzfi5MMbmIzWWkxI5YtJTdtmCkPQ", - fmt.Sprintf(`{"cert": "%s"}`, certPemPs), - true, - `{"alg": "RS256", "typ": "JWT"}`, - `{"iss": "xxx"}`, - "", - }, - { - "rsa256-nested2", // two nesting levels - "eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCIsICJjdHkiOiAiSldUIn0.ZXlKaGJHY2lPaUFpVWxNeU5UWWlMQ0FpZEhsd0lqb2dJa3BYVkNJc0lDSmpkSGtpT2lBaVNsZFVJbjAuWlhsS2FHSkhZMmxQYVVGcFZXeE5lVTVVV1dsTVEwRnBaRWhzZDBscWIyZEphM0JZVmtOS09TNWxlVXB3WXpOTmFVOXBRV2xsU0dnMFNXNHdMbkpTVW5KbFVVOURZVzlaTFcxTmF6Y3lhazVHWlZrMVlWbEZVV2hKWjBsRmRGWmtVVGxZYmxsdFVVd3lUSGRmYURkTmJrazBVMFZQTVZCd2EwSklWRXB5Wm5samJFcGxUSHBmYWxKMlVHZEpNbGN4YURGQ05HTmFWRGhEWjIxcFZYZHhRWEk1YzBwdVpIbFZRMUZ0U1dScmJtNTNXa0k1Y1hBdFgzQlRkR1JIV0VvNVduQXplRW80TlhvdFZFSnBXbE4wUVVOVVpGZGxVa2xHU1VVM1ZreFBhMjB0Um14WmR6aDVPVGRuYVVONFRteFVkV2wzYW14bFRqTXdaRGhuV0hVeE5rWkdRekpUU2xodFJqWktiWFl0TmpKSGJFUmhMVzFDV0ZaMGJHSlZTVFZsV1ZVd2FUZHVlVE55UWpCWVVWUXhSa3Q0WlVaM09GODVOMDlGZFY5alkzVkxjbDgyWkhsSFpWRkhkblE1WTNKSmVFRkJNV0ZaYkRkbWJWQnJOa1ZoY2psbFRUTkthR1ZZTWkwMFdreDBkMUZPWTFSRFQwMVlWMGRJY2sxRGFHNU1XVmM0V0VGclRISkVibDl5Um14VWFWTXRady5YaWNjMnNXQ1pfTml0aHVjc3c5WEQ3WU9LcmlyVWRFbkgzTXlpUE0tQ2szdkVVMlJzVEJzZlUySlBoZmpwM3BoYzBWT2dzQVhDendVNVB3eU55VW8xNDkwcThZU3ltLWxpTXlPMkxrLWhqSDVmQXhvaXpnOXlENElJX2xLNld6X1RucGMwYkJHRExkYnVVaHZndk83eXFvLWxlQlFsc2ZSWE92dzRWU1BTRXk4UVB0YlVSdGJuTHBXWTJqR0JLejd2R0lfbzRxREozUGljRzBreUVpV1pOaDN3amVlQ1lSQ1d2WE44cWg3VWs1RUEtOEo1dlg2NTFHcVYtN2dtYVgxbi04RFhhbWhhQ1FjRS1wMWNqU2owNC1YLV9iSmxRdG1iLVRUM2JTeVVQeGdIVm5jdnhOVWJ5OGprVVR6Zmk1TU1ibUl6V1dreEk1WXRKVGR0bUNrUFE.ODBVH_gooCLJxtPVr1MjJC1syG4MnVUFP9LkI9pSaj0QABV4vpfqrBshHn8zOPgUTDeHwbc01Qy96cQlTMQQb94YANmZyL1nzwmdR4piiGXMGSlcCNfDg1o8DK4msMSR-X-j2IkxBDB8rfeFSfLRMgDCjAF0JolW7qWmMD9tBmFNYAjly4vMwToOXosDmFLl5eqyohXDf-3Ohljm5kIjtyMWkt5S9EVuwlIXh2owK5l59c4-TH29gkuaZ3uU4LFPjD7XKUrlOQnEMuu2QD8LAqTyxbnY4JyzUWEvyTM1dVmGnFpLKCg9QBly__y1u2ffhvDsHyuCmEKAbhPE98YvFA", - fmt.Sprintf(`{"cert": "%s"}`, certPemPs), - true, - `{"alg": "RS256", "typ": "JWT"}`, - `{"iss": "xxx"}`, - "", - }, - { - "es256-unconstrained", // ECC key, no constraints - "eyJhbGciOiAiRVMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieHh4In0.JvbTLBF06FR70gb7lCbx_ojhp4bk9--B_aULgNlYM0fYf9OSawaqBQp2lwW6FADFtRJ2WFUk5g0zwVOUlnrlzw", - fmt.Sprintf(`{"cert": "%s"}`, certPemEs256), - true, - `{"alg": "ES256", "typ": "JWT"}`, - `{"iss": "xxx"}`, - "", - }, - { - "hs256-unconstrained", // HMAC key, no constraints - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWxpY2UiLCJhenAiOiJhbGljZSIsInN1Ym9yZGluYXRlcyI6W10sImhyIjpmYWxzZX0.rz3jTY033z-NrKfwrK89_dcLF7TN4gwCMj-fVBDyLoM`, - `{"secret": "secret"}`, - true, - `{"alg": "HS256", "typ": "JWT"}`, - `{"user": "alice", "azp": "alice", "subordinates": [], "hr": false}`, - "", - }, - { - "hs256-key-wrong", // HMAC with wrong key - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWxpY2UiLCJhenAiOiJhbGljZSIsInN1Ym9yZGluYXRlcyI6W10sImhyIjpmYWxzZX0.rz3jTY033z-NrKfwrK89_dcLF7TN4gwCMj-fVBDyLoM`, - `{"secret": "the wrong key"}`, - false, - `{}`, - `{}`, - "", - }, - { - "rs256-aud", // constraint requires an audience, found right one in JWT - "eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieHh4IiwgImF1ZCI6ICJmcmVkIn0.F-9m2Tx8r1tuQFirazsI4FK05bXX3uP4ut8M2FryJ07k3bQhy262fdwNDmuFcGx0NfL-c80agcwGoTzMWXkVEgZ2KTz0QSAdcdGk3ZWtUy-Mj2IilZ1dzkVvW8LsithYFTGcUtkelFDrJwtMQ0Kum7SXJpC_HCBk4PbftY0XD6jRgHLnQdeT9_J11L4sd19vCdpxxxm3_m_yvUV3ZynzB4vhQbS3CET4EClAVhi-m_gMh9mj85gY1ycIz6-FxWv8xM2Igm2SMeIdyJwAvEGnIauRS928P_OqVCZgCH2Pafnxtzy77Llpxy8XS0xu5PtPw3_azhg33GaXDCFsfz6GpA", - fmt.Sprintf(`{"cert": "%s", "aud": "fred"}`, certPemPs), - true, - `{"alg": "RS256", "typ": "JWT"}`, - `{"aud": "fred", "iss": "xxx"}`, - "", - }, - { - "rs256-aud-list", // constraint requires an audience, found list including right one in JWT - "eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieHh4IiwgImF1ZCI6IFsiZnJlZCIsICJib2IiXX0.k8jW7PUiMkQCKCjnSFBFFKPDO0RXwZgVkLUwUfi8sMdrrcKi12LC8wd5fLBn0YraFtMXWKdMweKf9ZC-K33h5TK7kkTVKOXctF50mleMlUn0Up_XjtdP1v-2WOfivUXcexN1o-hu0kH7sSQnielXIjC2EAleG6A54YUOZFBdzvd1PKHlsxA7x2iiL73uGeFlyxoaMki8E5tx7FY6JGF1RdhWCoIV5A5J8QnwI5EetduJQ505U65Pk7UApWYWu4l2DT7KCCJa5dJaBvCBemVxWaBhCQWtJKU2ZgOEkpiK7b_HsdeRBmpG9Oi1o5mt5ybC09VxSD-lEda_iJO_7i042A", - fmt.Sprintf(`{"cert": "%s", "aud": "bob"}`, certPemPs), - true, - `{"alg": "RS256", "typ": "JWT"}`, - `{"aud": ["fred", "bob"], "iss": "xxx"}`, - "", - }, - { - "ps256-no-aud", // constraint requires an audience, none in JWT - "eyJhbGciOiAiUFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieHh4In0.iCePYnD1U13oBe_6ylhmojmkY_VZNYXqVszAej8RImMGv51OEqARmYFkRZYTiYCiVFober7vcDq_stOj1uAJCuttygGW_dpHiN-3EWsU2E2vCnXlygWe0ud38pOC-OVyEFbXxO9-m51vnS-3VmBjEO8G1UE8bLFXTeFOGkUIj9dqlefJSWh5wa8XA3g9mj0jqpuJi-7QgEIeVHk-JzhGpoFqI2f-Df_agVvc2x4V-6fJmj7wV2IsaFPRi36mVQmg8S-dkxu4AlaeCILhyNZl8ewjBHHBjJFRwzcy88L00mzdO51ZxEYsBdQav3ux2sc6vjT9PvvjAwzcthQxEoEaNA", - fmt.Sprintf(`{"cert": "%s", "aud": "cath"}`, certPemPs), - false, - `{}`, - `{}`, - "", - }, - { - "rs256-missing-aud", // constraint requires no audience, found one in JWT - "eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieHh4IiwgImF1ZCI6ICJmcmVkIn0.F-9m2Tx8r1tuQFirazsI4FK05bXX3uP4ut8M2FryJ07k3bQhy262fdwNDmuFcGx0NfL-c80agcwGoTzMWXkVEgZ2KTz0QSAdcdGk3ZWtUy-Mj2IilZ1dzkVvW8LsithYFTGcUtkelFDrJwtMQ0Kum7SXJpC_HCBk4PbftY0XD6jRgHLnQdeT9_J11L4sd19vCdpxxxm3_m_yvUV3ZynzB4vhQbS3CET4EClAVhi-m_gMh9mj85gY1ycIz6-FxWv8xM2Igm2SMeIdyJwAvEGnIauRS928P_OqVCZgCH2Pafnxtzy77Llpxy8XS0xu5PtPw3_azhg33GaXDCFsfz6GpA", - fmt.Sprintf(`{"cert": "%s"}`, certPemPs), - false, - `{}`, - `{}`, - "", - }, - { - "rs256-wrong-aud", // constraint requires an audience, found wrong one in JWT - "eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieHh4IiwgImF1ZCI6ICJmcmVkIn0.F-9m2Tx8r1tuQFirazsI4FK05bXX3uP4ut8M2FryJ07k3bQhy262fdwNDmuFcGx0NfL-c80agcwGoTzMWXkVEgZ2KTz0QSAdcdGk3ZWtUy-Mj2IilZ1dzkVvW8LsithYFTGcUtkelFDrJwtMQ0Kum7SXJpC_HCBk4PbftY0XD6jRgHLnQdeT9_J11L4sd19vCdpxxxm3_m_yvUV3ZynzB4vhQbS3CET4EClAVhi-m_gMh9mj85gY1ycIz6-FxWv8xM2Igm2SMeIdyJwAvEGnIauRS928P_OqVCZgCH2Pafnxtzy77Llpxy8XS0xu5PtPw3_azhg33GaXDCFsfz6GpA", - fmt.Sprintf(`{"cert": "%s", "aud": "cath"}`, certPemPs), - false, - `{}`, - `{}`, - "", - }, - { - "rs256-wrong-aud-list", // constraint requires an audience, found list of wrong ones in JWT - "eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieHh4IiwgImF1ZCI6IFsiZnJlZCIsICJib2IiXX0.k8jW7PUiMkQCKCjnSFBFFKPDO0RXwZgVkLUwUfi8sMdrrcKi12LC8wd5fLBn0YraFtMXWKdMweKf9ZC-K33h5TK7kkTVKOXctF50mleMlUn0Up_XjtdP1v-2WOfivUXcexN1o-hu0kH7sSQnielXIjC2EAleG6A54YUOZFBdzvd1PKHlsxA7x2iiL73uGeFlyxoaMki8E5tx7FY6JGF1RdhWCoIV5A5J8QnwI5EetduJQ505U65Pk7UApWYWu4l2DT7KCCJa5dJaBvCBemVxWaBhCQWtJKU2ZgOEkpiK7b_HsdeRBmpG9Oi1o5mt5ybC09VxSD-lEda_iJO_7i042A", - fmt.Sprintf(`{"cert": "%s", "aud": "cath"}`, certPemPs), - false, - `{}`, - `{}`, - "", - }, - { - "multiple-keys-one-valid", - "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.ZcLZbBKpPFFz8YGD2jEbXzwHT7DWtqRVk1PTV-cAWUV8jr6f2a--Fw9SFR3vSbrtFif06AQ3aWY7PMM2AuxDjiUVGjItmHRz0sJBEijcE2QVkDN7MNK3Kk1fsM_hbEXzNCzChZpEkTZnLy9ijkJJFD0j6lBat4lO5Zc_LC2lXUftV_hU2aW9mQ7pLSgJjItzRymivnN0g-WUDq5IPK_M8b3yPy_N9iByj8B2FO0sC3TuOrXWbrYrX4ve4bAaSqOFOXiL5Z5BJfmmtT--xKdWDGJxnei8lbv7in7t223fVsUpsH-zmybp529Fya37BsaIlcgLrl38ghvoqy2sHu2wAA", - fmt.Sprintf("{\"cert\": `%s`, \"time\": 1574723450396363500}", multiKeyJWkS), - true, - `{ - "alg": "RS256", - "typ": "JWT" - }`, - `{ - "admin": true, - "iat": 1516239022, - "name": "John Doe", - "sub": "1234567890" - }`, - "", - }, - { - "multiple-keys-no-valid", - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.G051ZlKno4XdDz4pdPthPKH1cKlFqkREvx_dHhl6kwM", - fmt.Sprintf("{\"cert\": `%s`, \"time\": 1574723450396363500}", multiKeyJWkS), - false, - `{}`, - `{}`, - "", - }, - { - "hs256-float-nbf", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ4eHgiLCJuYmYiOjEwMDAuMX0.8ab0xurlRs_glclA3Sm7OMQgwkQvE4HuLsfMOc4nVO8`, - `{"secret": "secret", "time": 2000000000000.1}`, - true, - `{"alg": "HS256", "typ": "JWT"}`, - `{"iss": "xxx", "nbf": 1000.1 }`, - "", - }, - { - "hs256-float-nbf-not-valid", // nbf set to 3000.1 - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ4eHgiLCJuYmYiOjMwMDAuMX0.khHsSae91zHwuaTIvszln3kyrOdPyUYiGSvCI0j2ie8`, - `{"secret": "secret", "time": 2000000000000.1}`, - false, - `{}`, - `{}`, - "", - }, - { - "hs256-float-exp-valid", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjMwMDAuMiwiaXNzIjoieHh4In0.XUen7GtDmICV3O1ngsoO-tQrjrXtOgJI06oGW0nQSIM`, - `{"secret": "secret", "time": 2000000000000.1}`, - true, - `{"alg": "HS256", "typ": "JWT"}`, - `{"iss": "xxx", "exp": 3000.2 }`, - "", - }, - { - "hs256-float-exp-expired", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjMwMDAuMiwiaXNzIjoieHh4In0.XUen7GtDmICV3O1ngsoO-tQrjrXtOgJI06oGW0nQSIM`, - `{"secret": "secret", "time": 4000000000000.1}`, - false, - `{}`, - `{}`, - "", - }, - { - "hs256-float-nbf-one-tenth-second-before", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ4eHgiLCJuYmYiOjEuNTg5Mzg1NzcwMTIzNGUrMDl9.lvrsV1nam-BZr0SomWwsr4dBfu6BDrR2FzQ1iS_Xnrw`, - `{"secret": "secret", "time": 1589385770023400000}`, - false, - `{}`, - `{}`, - "", - }, - { - "hs256-float-nbf-equal", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ4eHgiLCJuYmYiOjEuNTg5Mzg1NzcwMTIzNGUrMDl9.lvrsV1nam-BZr0SomWwsr4dBfu6BDrR2FzQ1iS_Xnrw`, - `{"secret": "secret", "time": 1589385770123400000}`, - true, - `{"alg": "HS256", "typ": "JWT"}`, - `{"iss": "xxx", "nbf": 1.5893857701234e+09 }`, - "", - }, - { - "hs256-float-one-millisecond-after-nbf", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ4eHgiLCJuYmYiOjEuNTg5Mzg1NzcwMTIzNGUrMDl9.lvrsV1nam-BZr0SomWwsr4dBfu6BDrR2FzQ1iS_Xnrw`, - `{"secret": "secret", "time": 1589385770124400000}`, - true, - `{"alg": "HS256", "typ": "JWT"}`, - `{"iss": "xxx", "nbf": 1.5893857701234e+09 }`, - "", - }, - { - "hs256-float-one-tenth-second-after-nbf", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ4eHgiLCJuYmYiOjEuNTg5Mzg1NzcwMTIzNGUrMDl9.lvrsV1nam-BZr0SomWwsr4dBfu6BDrR2FzQ1iS_Xnrw`, - `{"secret": "secret", "time": 1589385770223400000}`, - true, - `{"alg": "HS256", "typ": "JWT"}`, - `{"iss": "xxx", "nbf": 1.5893857701234e+09 }`, - "", - }, - { - "hs256-float-one-second-after-nbf", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ4eHgiLCJuYmYiOjEuNTg5Mzg1NzcwMTIzNGUrMDl9.lvrsV1nam-BZr0SomWwsr4dBfu6BDrR2FzQ1iS_Xnrw`, - `{"secret": "secret", "time": 1589385771123400000}`, - true, - `{"alg": "HS256", "typ": "JWT"}`, - `{"iss": "xxx", "nbf": 1.5893857701234e+09 }`, - "", - }, - { - "hs256-float-one-second-before-exp", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEuNTg5Mzg1NzcxMTIzNGUrMDksImlzcyI6Inh4eCJ9.PZ2z6VfHt9YdvHHUbilkTnw4R9TK3_V0LV1h-q0k9xg`, - `{"secret": "secret", "time": 1589385770123400000}`, - true, - `{"alg": "HS256", "typ": "JWT"}`, - `{"iss": "xxx", "exp": 1.5893857711234e+09 }`, - "", - }, - { - "hs256-float-one-tenth-second-before-exp", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEuNTg5Mzg1NzcxMTIzNGUrMDksImlzcyI6Inh4eCJ9.PZ2z6VfHt9YdvHHUbilkTnw4R9TK3_V0LV1h-q0k9xg`, - `{"secret": "secret", "time": 1589385771023400000}`, - true, - `{"alg": "HS256", "typ": "JWT"}`, - `{"iss": "xxx", "exp": 1.5893857711234e+09 }`, - "", - }, - { - "hs256-float-equal-exp", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEuNTg5Mzg1NzcxMTIzNGUrMDksImlzcyI6Inh4eCJ9.PZ2z6VfHt9YdvHHUbilkTnw4R9TK3_V0LV1h-q0k9xg`, - `{"secret": "secret", "time": 1589385771123400000}`, - false, - `{}`, - `{}`, - "", - }, - { - "hs256-float-one-tenth-second-after-exp", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEuNTg5Mzg1NzcxMTIzNGUrMDksImlzcyI6Inh4eCJ9.PZ2z6VfHt9YdvHHUbilkTnw4R9TK3_V0LV1h-q0k9xg`, - `{"secret": "secret", "time": 1589385771223400000}`, - false, - `{}`, - `{}`, - "", - }, - { - "hs256-float-one-second-after-exp", - `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEuNTg5Mzg1NzcxMTIzNGUrMDksImlzcyI6Inh4eCJ9.PZ2z6VfHt9YdvHHUbilkTnw4R9TK3_V0LV1h-q0k9xg`, - `{"secret": "secret", "time": 1589385772123400000}`, - false, - `{}`, - `{}`, - "", - }, - } - - type test struct { - note string - rules []string - expected interface{} - } - tests := []test{} - - for _, p := range params { - var exp interface{} - exp = fmt.Sprintf(`[%#v, %s, %s]`, p.valid, p.header, p.payload) - if p.err != "" { - exp = errors.New(p.err) - } - - tests = append(tests, test{ - p.note, - []string{fmt.Sprintf(`p = [x, y, z] { time.now_ns(now); io.jwt.decode_verify("%s", %s, [x, y, z]) }`, p.token, p.constraints)}, - exp, - }) - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownJWTEncodeSign(t *testing.T) { - - astHeaderHS256Term := ast.MustParseTerm(`{"typ": "JWT", "alg": "HS256"}`) - astPayloadTerm := ast.MustParseTerm(`{"iss": "joe", "exp": 1300819380, "aud": ["bob", "saul"], "http://example.com/is_root": true, "privateParams": {"private_one": "one", "private_two": "two"}}`) - astSymmetricKeyTerm := ast.MustParseTerm(`{"kty": "oct", "k": "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"}`) - - astHeaderHS256Obj := astHeaderHS256Term.Value.(ast.Object) - astPayloadObj := astPayloadTerm.Value.(ast.Object) - astSymmetricKeyObj := astSymmetricKeyTerm.Value.(ast.Object) - - astHeaderRS256Term := ast.MustParseTerm(`{"alg": "RS256"}`) - astHeaderRS256Obj := astHeaderRS256Term.Value.(ast.Object) - - astRSAKeyTerm := ast.MustParseTerm(`{"kty": "RSA", "n": "ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddxHmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMsD1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSHSXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ", "e": "AQAB", "d": "Eq5xpGnNCivDflJsRQBXHx1hdR1k6Ulwe2JZD50LpXyWPEAeP88vLNO97IjlA7_GQ5sLKMgvfTeXZx9SE-7YwVol2NXOoAJe46sui395IW_GO-pWJ1O0BkTGoVEn2bKVRUCgu-GjBVaYLU6f3l9kJfFNS3E0QbVdxzubSu3Mkqzjkn439X0M_V51gfpRLI9JYanrC4D4qAdGcopV_0ZHHzQlBjudU2QvXt4ehNYTCBr6XCLQUShb1juUO1ZdiYoFaFQT5Tw8bGUl_x_jTj3ccPDVZFD9pIuhLhBOneufuBiB4cS98l2SR_RQyGWSeWjnczT0QU91p1DhOVRuOopznQ", "p": "4BzEEOtIpmVdVEZNCqS7baC4crd0pqnRH_5IB3jw3bcxGn6QLvnEtfdUdiYrqBdss1l58BQ3KhooKeQTa9AB0Hw_Py5PJdTJNPY8cQn7ouZ2KKDcmnPGBY5t7yLc1QlQ5xHdwW1VhvKn-nXqhJTBgIPgtldC-KDV5z-y2XDwGUc", "q": "uQPEfgmVtjL0Uyyx88GZFF1fOunH3-7cepKmtH4pxhtCoHqpWmT8YAmZxaewHgHAjLYsp1ZSe7zFYHj7C6ul7TjeLQeZD_YwD66t62wDmpe_HlB-TnBA-njbglfIsRLtXlnDzQkv5dTltRJ11BKBBypeeF6689rjcJIDEz9RWdc", "dp": "BwKfV3Akq5_MFZDFZCnW-wzl-CCo83WoZvnLQwCTeDv8uzluRSnm71I3QCLdhrqE2e9YkxvuxdBfpT_PI7Yz-FOKnu1R6HsJeDCjn12Sk3vmAktV2zb34MCdy7cpdTh_YVr7tss2u6vneTwrA86rZtu5Mbr1C1XsmvkxHQAdYo0", "dq": "h_96-mK1R_7glhsum81dZxjTnYynPbZpHziZjeeHcXYsXaaMwkOlODsWa7I9xXDoRwbKgB719rrmI2oKr6N3Do9U0ajaHF-NKJnwgjMd2w9cjz3_-kyNlxAr2v4IKhGNpmM5iIgOS1VZnOZ68m6_pbLBSp3nssTdlqvd0tIiTHU", "qi": "IYd7DHOhrWvxkwPQsRM2tOgrjbcrfvtQJipd-DlcxyVuuM9sQLdgjVk2oy26F0EmpScGLq2MowX7fhd_QJQ3ydy5cY7YIBi87w93IKLEdfnbJtoOPLUW0ITrJReOgo1cq9SbsxYawBgfp_gh6A5603k2-ZQwVK0JKSHuLFkuQ3U"}`) - - astRSAKeyObj := astRSAKeyTerm.Value.(ast.Object) - - params := []struct { - note string - input1 ast.Object - input2 ast.Object - input3 ast.Object - result string - err string - }{ - { - "https://tools.ietf.org/html/rfc7515#appendix-A.1", - astHeaderHS256Obj, - astPayloadObj, - astSymmetricKeyObj, - - `"eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJhdWQiOiBbImJvYiIsICJzYXVsIl0sICJleHAiOiAxMzAwODE5MzgwLCAiaHR0cDovL2V4YW1wbGUuY29tL2lzX3Jvb3QiOiB0cnVlLCAiaXNzIjogImpvZSIsICJwcml2YXRlUGFyYW1zIjogeyJwcml2YXRlX29uZSI6ICJvbmUiLCAicHJpdmF0ZV90d28iOiAidHdvIn19.M10TcaFADr_JYAx7qJ71wktdyuN4IAnhWvVbgrZ5j_4"`, - "", - }, - { - "Empty JSON payload", - astHeaderHS256Obj, - ast.NewObject(), - astSymmetricKeyObj, - - `"eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.e30.Odp4A0Fj6NoKsV4Gyoy1NAmSs6KVZiC15S9VRGZyR20"`, - "", - }, - { - "https://tools.ietf.org/html/rfc7515#appendix-A.2", - astHeaderRS256Obj, - astPayloadObj, - astRSAKeyObj, - - `"eyJhbGciOiAiUlMyNTYifQ.eyJhdWQiOiBbImJvYiIsICJzYXVsIl0sICJleHAiOiAxMzAwODE5MzgwLCAiaHR0cDovL2V4YW1wbGUuY29tL2lzX3Jvb3QiOiB0cnVlLCAiaXNzIjogImpvZSIsICJwcml2YXRlUGFyYW1zIjogeyJwcml2YXRlX29uZSI6ICJvbmUiLCAicHJpdmF0ZV90d28iOiAidHdvIn19.ITpfhDICCeVV__1nHRN2CvUFni0yyYESvhNlt4ET0yiySMzJ5iySGynrsM3kgzAv7mVmx5uEtSCs_xPHyLVfVnADKmDFtkZfuvJ8jHfcOe8TUqR1f7j1Zf_kDkdqJAsuGuqkJoFJ3S_gxWcZNwtDXV56O3k_7Mq03Ixuuxtip2oF0X3fB7QtUzjzB8mWPTJDFG2TtLLOYCcobPHmn36aAgesHMzJZj8U8sRLmqPXsIc-Lo_btt8gIUc9zZSgRiy7NOSHxw5mYcIMlKl93qvLXu7AaAcVLvzlIOCGWEnFpGGcRFgSOLnShQX6hDylWavKLQG-VOUJKmtXH99KBK-OYQ"`, - "", - }, - } - type test struct { - note string - rules []string - expected interface{} - } - var tests []test - - for _, p := range params { - var exp interface{} - exp = fmt.Sprintf(`%s`, p.result) - if p.err != "" { - exp = errors.New(p.err) - } - - tests = append(tests, test{ - p.note, - []string{fmt.Sprintf(`p = x { io.jwt.encode_sign(%v, %v, %v, x) }`, p.input1, p.input2, p.input3)}, - exp, - }) - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } - -} diff --git a/topdown/topdown_test.go b/topdown/topdown_test.go index e3c16b189b..e84473760b 100644 --- a/topdown/topdown_test.go +++ b/topdown/topdown_test.go @@ -34,40 +34,6 @@ import ( testutil "github.com/open-policy-agent/opa/util/test" ) -func TestTopDownCompleteDoc(t *testing.T) { - tests := []struct { - note string - rule string - expected interface{} - }{ - {"undefined", `p = null { false }`, ""}, // "" will be converted to Undefined - {"null", `p = null { true }`, "null"}, - {"bool: true", `p = true { true }`, "true"}, - {"bool: false", `p = false { true }`, "false"}, - {"number: 3", `p = 3 { true }`, "3"}, - {"number: 3.0", `p = 3 { true }`, "3"}, - {"number: 66.66667", `p = 66.66667 { true }`, "66.66667"}, - {`string: "hello"`, `p = "hello" { true }`, `"hello"`}, - {`string: ""`, `p = "" { true }`, `""`}, - {"array: [1,2,3,4]", `p = [1, 2, 3, 4] { true }`, "[1,2,3,4]"}, - {"array: []", `p = [] { true }`, "[]"}, - {`object/nested composites: {"a": [1], "b": [2], "c": [3]}`, - `p = {"a": [1], "b": [2], "c": [3]} { true }`, - `{"a": [1], "b": [2], "c": [3]}`}, - {"object/non-string key:", `p = {1: 2, {3: 4}: 5} { true }`, `{"1": 2, "{\"3\":4}": 5}`}, - {"set/nested: {{1,2},{2,3}}", `p = {{1, 2}, {2, 3}} { true }`, "[[1,2], [2,3]]"}, - {"vars", `p = {"a": [x, y]} { x = 1; y = 2 }`, `{"a": [1,2]}`}, - {"vars conflict", `p = {"a": [x, y]} { xs = [1, 2]; ys = [1, 2]; x = xs[_]; y = ys[_] }`, - completeDocConflictErr(nil)}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, []string{tc.rule}, tc.expected) - } -} - func TestTopDownQueryIDsUnique(t *testing.T) { ctx := context.Background() store := inmem.New() @@ -159,1919 +125,6 @@ func TestTopDownIndexExpr(t *testing.T) { } } -func TestTopDownPartialSetDoc(t *testing.T) { - - tests := []struct { - note string - rule string - expected string - }{ - {"array values", `p[x] { a[i] = x }`, `[1, 2, 3, 4]`}, - {"array indices", `p[x] { a[x] = _ }`, `[0, 1, 2, 3]`}, - {"object keys", `p[x] { b[x] = _ }`, `["v1", "v2"]`}, - {"object values", `p[x] { b[i] = x }`, `["hello", "goodbye"]`}, - {"nested composites", `p[x] { f[i] = x }`, `[{"xs": [1.0], "ys": [2.0]}, {"xs": [2.0], "ys": [3.0]}]`}, - {"deep ref/heterogeneous", `p[x] { c[i][j][k] = x }`, `[null, 3.14159, false, true, "foo"]`}, - {"composite var value", `p[x] { x = [i, a[i]] }`, "[[0,1],[1,2],[2,3],[3,4]]"}, - {"composite key", `p[[x, {"y": y}]] { x = 1; y = 2 }`, `[[1,{"y": 2}]]`}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, []string{tc.rule}, tc.expected) - } -} - -func TestTopDownPartialObjectDoc(t *testing.T) { - tests := []struct { - note string - rule string - expected interface{} - }{ - {"identity", `p[k] = v { b[k] = v }`, `{"v1": "hello", "v2": "goodbye"}`}, - {"composites", `p[k] = v { d[k] = v }`, `{"e": ["bar", "baz"]}`}, - {"body/join var", `p[k] = v { a[i] = v; g[k][i] = v }`, `{"a": 1, "b": 2, "c": 4}`}, - {"composite value", `p[k] = [v1, {"v2": v2}] { g[k] = x; x[v1] = v2; v2 != 0 }`, `{ - "a": [0, {"v2": 1}], - "b": [1, {"v2": 2}], - "c": [3, {"v2": 4}] - }`}, - {"same key/value pair", `p[k] = 1 { ks = ["a", "b", "c", "a"]; ks[_] = k }`, `{"a":1,"b":1,"c":1}`}, - {"non-string key", `p[k] = 1 { ks = [1,{},null]; ks[_] = k }`, `{"1": 1, "{}": 1, "null": 1}`}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, []string{tc.rule}, tc.expected) - } -} - -func TestTopDownEvalTermExpr(t *testing.T) { - - tests := []struct { - note string - rule string - expected string - }{ - {"true", `p = true { true }`, "true"}, - {"false", `p = true { false }`, ""}, - {"number non-zero", `p = true { -3.14 }`, "true"}, - {"number zero", `p = true { null }`, "true"}, - {"null", `p = true { null }`, "true"}, - {"string non-empty", `p = true { "abc" }`, "true"}, - {"string empty", `p = true { "" }`, "true"}, - {"array non-empty", `p = true { [1, 2, 3] }`, "true"}, - {"array empty", `p = true { [] }`, "true"}, - {"object non-empty", `p = true { {"a": 1} }`, "true"}, - {"object empty", `p = true { {} }`, "true"}, - {"set non-empty", `p = true { {1, 2, 3} }`, "true"}, - {"set empty", `p = true { set() }`, "true"}, - {"ref", `p = true { a[i] }`, "true"}, - {"ref undefined", `p = true { data.deadbeef[i] }`, ""}, - {"ref undefined (path)", `p = true { data.a[true] }`, ""}, - {"ref false", `p = true { data.c[0].x[1] }`, ""}, - {"array comprehension", `p = true { [x | x = 1] }`, "true"}, - {"array comprehension empty", `p = true { [x | x = 1; x = 2] }`, "true"}, - {"arbitrary position", `p = true { a[i] = x; x; i }`, "true"}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, []string{tc.rule}, tc.expected) - } -} - -func TestTopDownEqExpr(t *testing.T) { - - tests := []struct { - note string - rule string - expected interface{} - }{ - // undefined cases - {"undefined: same type", `p = true { true = false }`, ""}, - {"undefined: array order", `p = true { [1, 2, 3] = [1, 3, 2] }`, ""}, - {"undefined: ref value", `p = true { a[3] = 9999 }`, ""}, - {"undefined: ref values", `p = true { a[i] = 9999 }`, ""}, - {"undefined: ground var", `p = true { a[3] = x; x = 3 }`, ""}, - {"undefined: array var 1", `p = true { [1, x, x] = [1, 2, 3] }`, ""}, - {"undefined: array var 2", `p = true { [1, x, 3] = [1, 2, x] }`, ""}, - {"undefined: object var 1", `p = true { {"a": 1, "b": 2} = {"a": a, "b": a} }`, ""}, - {"undefined: array deep var 1", `p = true { [[1, x], [3, x]] = [[1, 2], [3, 4]] }`, ""}, - {"undefined: array deep var 2", `p = true { [[1, x], [3, 4]] = [[1, 2], [x, 4]] }`, ""}, - {"undefined: set", `p = true { {1, 2, 3} = {1, 2, 4} }`, ""}, - - // ground terms - {"ground: bool", `p = true { true = true }`, "true"}, - {"ground: string", `p = true { "string" = "string" }`, "true"}, - {"ground: number", `p = true { 17 = 17 }`, "true"}, - {"ground: null", `p = true { null = null }`, "true"}, - {"ground: array", `p = true { [1, 2, 3] = [1, 2, 3] }`, "true"}, - {"ground: set", `p = true { {1, 2, 3} = {3, 2, 1} }`, "true"}, - {"ground: object", `p = true { {"b": false, "a": [1, 2, 3]} = {"a": [1, 2, 3], "b": false} }`, "true"}, - {"ground: ref 1", `p = true { a[2] = 3 }`, "true"}, - {"ground: ref 2", `p = true { b.v2 = "goodbye" }`, "true"}, - {"ground: ref 3", `p = true { d.e = ["bar", "baz"] }`, "true"}, - {"ground: ref 4", `p = true { c[0].x[1] = c[0].z.q }`, "true"}, - - // variables - {"var: x=y=z", `p[x] { x = y; z = 42; y = z }`, "[42]"}, - {"var: ref value", `p = true { a[3] = x; x = 4 }`, "true"}, - {"var: ref values", `p = true { a[i] = x; x = 2 }`, "true"}, - {"var: ref key", `p = true { a[i] = 4; x = 3 }`, "true"}, - {"var: ref keys", `p = true { a[i] = x; i = 2 }`, "true"}, - {"var: ref ground var", `p[x] { i = 2; a[i] = x }`, "[3]"}, - {"var: ref ref", `p[x] { c[0].x[i] = c[0].z[j]; x = [i, j] }`, `[[0, "p"], [1, "q"]]`}, - - // arrays and variables - {"pattern: array", `p[x] { [1, x, 3] = [1, 2, 3] }`, "[2]"}, - {"pattern: array 2", `p[x] { [[1, x], [3, 4]] = [[1, 2], [3, 4]] }`, "[2]"}, - {"pattern: array same var", `p[x] { [2, x, 3] = [x, 2, 3] }`, "[2]"}, - {"pattern: array multiple vars", `p[z] { [1, x, y] = [1, 2, 3]; z = [x, y] }`, "[[2, 3]]"}, - {"pattern: array multiple vars 2", `p[z] { [1, x, 3] = [y, 2, 3]; z = [x, y] }`, "[[2, 1]]"}, - {"pattern: array ref", `p[x] { [1, 2, 3, x] = [a[0], a[1], a[2], a[3]] }`, "[4]"}, - {"pattern: array non-ground ref", `p[x] { [1, 2, 3, x] = [a[0], a[1], a[2], a[i]] }`, "[1,2,3,4]"}, - {"pattern: array = ref", `p[x] { [true, false, x] = c[i][j] }`, `["foo"]`}, - {"pattern: array = ref (reversed)", `p[x] { c[i][j] = [true, false, x] }`, `["foo"]`}, - {"pattern: array = var", `p[y] { [1, 2, x] = y; x = 3 }`, "[[1,2,3]]"}, - - // objects and variables - {"pattern: object val", `p[y] { {"x": y} = {"x": "y"} }`, `["y"]`}, - {"pattern: object same var", `p[x] { {"x": x, "y": x} = {"x": 1, "y": 1} }`, "[1]"}, - {"pattern: object multiple vars", `p[z] { {"x": x, "y": y} = {"x": 1, "y": 2}; z = [x, y] }`, "[[1, 2]]"}, - {"pattern: object multiple vars 2", `p[z] { {"x": x, "y": 2} = {"x": 1, "y": y}; z = [x, y] }`, "[[1, 2]]"}, - {"pattern: object ref", `p[x] { {"p": c[0].x[0], "q": x} = c[i][j] }`, `[false]`}, - {"pattern: object non-ground ref", `p[x] { {"a": 1, "b": x} = {"a": 1, "b": c[0].x[i]} }`, `[true, false, "foo"]`}, - {"pattern: object = ref", `p[x] { {"p": y, "q": z} = c[i][j]; x = [i, j, y, z] }`, `[[0, "z", true, false]]`}, - {"pattern: object = ref (reversed)", `p[x] { c[i][j] = {"p": y, "q": z}; x = [i, j, y, z] }`, `[[0, "z", true, false]]`}, - {"pattern: object = var", `p[x] { {"a": 1, "b": y} = x; y = 2 }`, `[{"a": 1, "b": 2}]`}, - {"pattern: object/array nested", `p[ys] { f[i] = {"xs": [2], "ys": ys} }`, `[[3.0]]`}, - {"pattern: object/array nested 2", `p[v] { f[i] = {"xs": [x], "ys": [y]}; v = [x, y] }`, `[[1.0, 2.0], [2.0, 3.0]]`}, - - // unordered collections requiring plug - {"unordered: sets", `p[x] { x = 2; {1,x,3} = {1,2,3} }`, `[2]`}, - {"unordered: object keys", `p[x] { x = "a"; {x: 1} = {"a": 1} }`, `["a"]`}, - {"unordered: object keys (reverse)", `p[x] { x = "a"; {"a": 1} = {x: 1} }`, `["a"]`}, - - // indexing - {"indexing: intersection", `p = true { a[i] = g[i][j] }`, ""}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, []string{tc.rule}, tc.expected) - } -} - -func TestTopDownUndos(t *testing.T) { - tests := []struct { - note string - rule string - expected interface{} - }{ - { - note: "array-type", - rule: "p[x] { arr = [[1, [2]], [1, null], [2, [2]]]; [x, [2]] = arr[_] }", - expected: "[1, 2]", - }, - { - note: "arrays-element", - rule: "p[x] { arr = [[1, 2], [1, null], [2, 2]]; arr[_] = [x, 2] }", - expected: "[1, 2]", - }, - { - note: "arrays-length", - rule: "p[x] { arr = [[1, [2]], [1, []], [2, [2]]]; arr[_] = [x, [2]] }", - expected: "[1, 2]", - }, - { - note: "array-ref-element", - rule: "p[x] { arr = [[1, 2], data.arr_ref, [2, 2]]; arr[_] = [x, 2] }", - expected: "[1, 2]", - }, - { - note: "object-type", - rule: `p[x] { obj = {"a": {"x": 1, "y": {"v": 2}}, "b": {"x": 1, "y": null}, "c": {"x": 2, "y": {"v": 2}}}; {"x": x, "y": {"v": 2}} = obj[_] }`, - expected: "[1, 2]", - }, - { - note: "objects-element", - rule: `p[x] { obj = {"a": {"x": 1, "y": 2}, "b": {"x": 1, "y": null}, "c": {"x": 2, "y": 2}}; obj[_] = {"x": x, "y": 2}}`, - expected: "[1, 2]", - }, - { - note: "objects-length", - rule: `p[x] { obj = {"a": {"x": 1, "y": {"v": 2}}, "b": {"x": 1, "y": {}}, "c": {"x": 2, "y": {"v": 2}}}; obj[_] = {"x": x, "y": {"v": 2}}}`, - expected: "[1, 2]", - }, - { - note: "object-ref-element", - rule: `p[x] { obj = {"a": {"x": 1, "y": 2}, "b": obj_ref, "c": {"x": 2, "y": 2}}; obj[_] = {"x": x, "y": 2}}`, - expected: "[1, 2]", - }, - { - note: "object-ref-missing-key", - rule: `p[x] { obj = {"a": {"x": 1, "y": 2}, "b": obj_ref_missing_key, "c": {"x": 2, "y": 2}}; obj[_] = {"x": x, "y": 2}}`, - expected: "[1, 2]", - }, - } - - data := util.MustUnmarshalJSON([]byte(` - { - "arr_ref": [1, null], - "obj_ref": {"x": 1, "y": null}, - "obj_ref_missing_key": {"x": 3, "z": 2} - } - `)).(map[string]interface{}) - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, []string{tc.rule}, tc.expected) - } -} - -func TestTopDownComparisonExpr(t *testing.T) { - - tests := []struct { - note string - rule string - expected interface{} - }{ - {"equals", `p = true { 1 == 1; a[i] = x; x == 2 }`, "true"}, - {"noteq", `p = true { 0 != 1; a[i] = x; x != 2 }`, "true"}, - {"gt", `p = true { 1 > 0; a[i] = x; x > 2 }`, "true"}, - {"gteq", `p = true { 1 >= 1; a[i] = x; x >= 4 }`, "true"}, - {"lt", `p = true { -1 < 0; a[i] = x; x < 5 }`, "true"}, - {"lteq", `p = true { -1 <= 0; a[i] = x; x <= 1 }`, "true"}, - {"undefined: equals", `p = true { 0 == 1 }`, ""}, - {"undefined: noteq", `p = true { 0 != 0 }`, ""}, - {"undefined: gt", `p = true { 1 > 2 }`, ""}, - {"undefined: gteq", `p = true { 1 >= 2 }`, ""}, - {"undefined: lt", `p = true { 1 < -1 }`, ""}, - {"undefined: lteq", `p = true { 1 < -1 }`, ""}, - } - - data := loadSmallTestData() - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, []string{tc.rule}, tc.expected) - } -} - -func TestTopDownVirtualDocs(t *testing.T) { - - tests := []struct { - note string - rules []string - expected interface{} - }{ - // input to partial set and object docs - {"input: set 1", []string{`p = true { q[1] }`, `q[x] { a[i] = x }`}, "true"}, - {"input: set 2", []string{`p[x] { q[1] = x }`, `q[x] { a[i] = x }`}, "[1]"}, - {"input: set embedded", []string{`p[x] { x = {"b": [q[2]]} }`, `q[x] { a[i] = x }`}, `[{"b": [2]}]`}, - {"input: set undefined", []string{`p = true { q[1000] }`, `q[x] { a[x] = y }`}, ""}, - {"input: set dereference", []string{`p = y { x = [1]; q[x][0] = y }`, `q[[x]] { a[_] = x }`}, "1"}, - {"input: set ground var", []string{`p[x] { x = 1; q[x] }`, `q[y] { a[y] = i }`}, "[1]"}, - {"input: set ground composite (1)", []string{ - `p = true { z = [[1, 2], 2]; q[z] }`, - `q[[x, y]] { x = [1, y]; y = 2 }`, - }, "true"}, - {"input: set ground composite (2)", []string{ - `p = true { y = 2; z = [[1, y], y]; q[z] }`, - `q[[x, y]] { x = [1, y]; y = 2 }`, - }, "true"}, - {"input: set ground composite (3)", []string{ - `p = true { y = 2; x = [1, y]; z = [x, y]; q[z] }`, - `q[[x, y]] { x = [1, y]; y = 2 }`, - }, "true"}, - {"input: set partially ground composite", []string{ - `p[u] { y = 2; x = [1, u]; z = [x, y]; q[z] }`, // "u" is not ground here - `q[[x, y]] { x = [1, y]; y = 2 }`, - }, "[2]"}, - {"input: object 1", []string{`p = true { q[1] = 2 }`, `q[i] = x { a[i] = x }`}, "true"}, - {"input: object 2", []string{`p = true { q[1] = 0 }`, `q[x] = i { a[i] = x }`}, "true"}, - {"input: object embedded 1", []string{`p[x] { x = [1, q[3], q[2]] }`, `q[i] = x { a[i] = x }`}, "[[1,4,3]]"}, - {"input: object embedded 2", []string{`p[x] { x = {"a": [q[3]], "b": [q[2]]} }`, `q[i] = x { a[i] = x }`}, `[{"a": [4], "b": [3]}]`}, - {"input: object undefined val", []string{`p = true { q[1] = 9999 }`, `q[i] = x { a[i] = x }`}, ""}, - {"input: object undefined key 1", []string{`p = true { q[9999] = 2 }`, `q[i] = x { a[i] = x }`}, ""}, - {"input: object undefined key 2", []string{`p = true { q.foo = 2 }`, `q[i] = x { a[i] = x }`}, ""}, - {"input: object dereference ground", []string{`p = true { q[0].x[1] = false }`, `q[i] = x { x = c[i] }`}, "true"}, - {"input: object dereference ground 2", []string{`p[v] { x = "a"; q[x][y] = v }`, `q[k] = v { k = "a"; v = data.a }`}, "[1,2,3,4]"}, - {"input: object defererence non-ground", []string{`p = true { q[0][x][y] = false }`, `q[i] = x { x = c[i] }`}, "true"}, - {"input: object ground var key", []string{`p[y] { x = "b"; q[x] = y }`, `q[k] = v { x = {"a": 1, "b": 2}; x[k] = v }`}, "[2]"}, - {"input: object non-string key", []string{`p[y] { x = 1; q[x] = y }`, `q[k] = v { x = {2: 1, 1: 3}; x[k] = v }`}, "[3]"}, - {"input: variable binding substitution", []string{ - `p[x] = y { r[z] = y; q[x] = z }`, - `r[k] = v { x = {"a": 1, "b": 2, "c": 3, "d": 4}; x[k] = v }`, - `q[y] = x { z = {"a": "a", "b": "b", "d": "d"}; z[y] = x }`}, - `{"a": 1, "b": 2, "d": 4}`}, - - // output from partial set and object docs - {"output: set", []string{`p[x] { q[x] }`, `q[y] { a[i] = y }`}, "[1,2,3,4]"}, - {"output: set embedded", []string{`p[i] { {i: [i]} = {i: [q[i]]} }`, `q[x] { d.e[i] = x }`}, `["bar", "baz"]`}, - {"output: set var binding", []string{`p[x] { q[x] }`, `q[y] { y = [i, j]; i = 1; j = 2 }`}, `[[1,2]]`}, - {"output: set dereference", []string{`p[y] { q[x][0] = y }`, `q[[x]] { a[_] = x }`}, `[1,2,3,4]`}, - {"output: set dereference deep", []string{`p[y] { q[i][j][k][x] = y }`, `q[{{[1], [2]}, {[3], [4]}}] { true }`}, "[1,2,3,4]"}, - {"output: set falsy values", []string{`p[x] { q[x] }`, `q = {0, "", false, null, [], {}, set()} { true }`}, `[0, "", null, [], {}, []]`}, - {"output: object key", []string{`p[x] { q[x] = 4 }`, `q[i] = x { a[i] = x }`}, "[3]"}, - {"output: object non-string key", []string{`p[x] { q[x] = 1 }`, `q[k] = 1 { a[_] = k; k < 3 }`}, "[1,2]"}, - {"output: object value", []string{`p[x] = y { q[x] = y }`, `q[k] = v { b[k] = v }`}, `{"v1": "hello", "v2": "goodbye"}`}, - {"output: object embedded", []string{`p[k] = v { {k: [q[k]]} = {k: [v]} }`, `q[x] = y { b[x] = y }`}, `{"v1": "hello", "v2": "goodbye"}`}, - {"output: object dereference ground", []string{`p[i] { q[i].x[1] = false }`, `q[i] = x { x = c[i] }`}, "[0]"}, - {"output: object defererence non-ground", []string{ - `p[r] { q[x][y][z] = false; r = [x, y, z] }`, - `q[i] = x { x = c[i] }`}, - `[[0, "x", 1], [0, "z", "q"]]`}, - {"output: object dereference array of refs", []string{ - `p[x] { q[_][0].c[_] = x }`, - `q[k] = v { d.e[_] = k; v = [r | r = l[_]] }`, - }, "[1,2,3,4]"}, - {"output: object dereference array of refs within object", []string{ - `p[x] { q[_].x[0].c[_] = x }`, - `q[k] = v { d.e[_] = k; v = {"x": [r | r = l[_]]} }`, - }, "[1,2,3,4]"}, - {"output: object dereference object with key refs", []string{ - `p = true { q.bar[1].alice[0] = 1 }`, - `q[k] = v { d.e[_] = k; v = [x | x = {l[_].a: [1]}] }`, - }, "true"}, - {"output: object var binding", []string{ - `p[z] { q[x] = y; z = [x, y] }`, - `q[k] = v { v = [x, y]; x = "a"; y = "b"; k = "foo" }`}, - `[["foo", ["a", "b"]]]`}, - {"output: object key var binding", []string{ - `p[z] { q[x] = y; z = [x, y] }`, - `q[k] = v { k = y; y = x; x = "a"; v = "foo" }`}, - `[["a", "foo"]]`}, - {"object: self-join", []string{ - `p[[x, y]] { q[x] = 1; q[y] = x }`, - `q[x] = i { a[i] = x }`}, - "[[2,3]]"}, - - // input+output from partial set/object docs - {"i/o: objects", []string{ - `p[x] { q[x] = r[x] }`, - `q[x] = y { z = {"a": 1, "b": 2, "d": 4}; z[x] = y }`, - `r[k] = v { x = {"a": 1, "b": 2, "c": 4, "d": 3}; x[k] = v }`}, - `["a", "b"]`}, - - {"i/o: undefined keys", []string{ - `p[y] { q[x]; r[x] = y }`, - `q[x] { z = ["a", "b", "c", "d"]; z[y] = x }`, - `r[k] = v { x = {"a": 1, "b": 2, "d": 4}; x[k] = v }`}, - `[1, 2, 4]`}, - - // input/output to/from complete docs - {"input: complete array", []string{`p = true { q[1] = 2 }`, `q = [1, 2, 3, 4] { true }`}, "true"}, - {"input: complete object", []string{`p = true { q.b = 2 }`, `q = {"a": 1, "b": 2} { true }`}, "true"}, - {"input: complete set", []string{`p = true { q[3] }`, `q = {1, 2, 3, 4} { true }`}, "true"}, - {"input: complete array dereference ground", []string{`p = true { q[1][1] = 3 }`, `q = [[0, 1], [2, 3]] { true }`}, "true"}, - {"input: complete object dereference ground", []string{`p = true { q.b[1] = 4 }`, `q = {"a": [1, 2], "b": [3, 4]} { true }`}, "true"}, - {"input: complete array ground index", []string{`p[x] { z = [1, 2]; z[i] = y; q[y] = x }`, `q = [1, 2, 3, 4] { true }`}, "[2,3]"}, - {"input: complete object ground key", []string{`p[x] { z = ["b", "c"]; z[i] = y; q[y] = x }`, `q = {"a": 1, "b": 2, "c": 3, "d": 4} { true }`}, "[2,3]"}, - {"input: complete vars", []string{ - `p = true { q[1][1] = 2 }`, - `q = [{"x": x, "y": y}, z] { x = 1; y = 2; z = [1, 2, 3] }`, - }, `true`}, - {"output: complete array", []string{`p[x] { q[i] = e; x = [i, e] }`, `q = [1, 2, 3, 4] { true }`}, "[[0,1],[1,2],[2,3],[3,4]]"}, - {"output: complete object", []string{`p[x] { q[i] = e; x = [i, e] }`, `q = {"a": 1, "b": 2} { true }`}, `[["a", 1], ["b", 2]]`}, - {"output: complete set", []string{`p[x] { q[x] }`, `q = {1, 2, 3, 4} { true }`}, "[1,2,3,4]"}, - {"output: complete array dereference non-ground", []string{`p[r] { q[i][j] = 2; r = [i, j] }`, `q = [[1, 2], [3, 2]] { true }`}, "[[0, 1], [1, 1]]"}, - {"output: complete object defererence non-ground", []string{`p[r] { q[x][y] = 2; r = [x, y] }`, `q = {"a": {"x": 1}, "b": {"y": 2}, "c": {"z": 2}} { true }`}, `[["b", "y"], ["c", "z"]]`}, - {"output: complete vars", []string{ - `p[x] { q[_][_] = x }`, - `q = [{"x": x, "y": y}, z] { x = 1; y = 2; z = [1, 2, 3] }`, - }, `[1,2,3]`}, - - // no dereferencing - {"no suffix: complete", []string{`p = true { q }`, `q = true { true }`}, "true"}, - {"no suffix: complete vars", []string{ - `p = true { q }`, `q = x { x = true }`, - }, "true"}, - {"no suffix: complete incr (error)", []string{`p = true { q }`, `q = false { true }`, `q = true { true }`}, completeDocConflictErr(nil)}, - {"no suffix: complete incr", []string{`p = true { not q }`, `q = true { false }`, `q = false { true }`}, "true"}, - {"no suffix: object", []string{`p[x] = y { q = o; o[x] = y }`, `q[x] = y { b[x] = y }`}, `{"v1": "hello", "v2": "goodbye"}`}, - {"no suffix: object incr", []string{ - `p[x] = y { q = o; o[x] = y }`, - `q[x] = y { b[x] = y }`, - `q[x1] = y1 { d.e[y1] = x1 }`}, - `{"v1": "hello", "v2": "goodbye", "bar": 0, "baz": 1}`}, - {"no suffix: chained", []string{ - `p = true { q = x; x[i] = 4 }`, - `q[k] = v { r = x; x[k] = v }`, - `r[k] = v { s = x; x[k] = v }`, - `r[k] = v { t = x; x[v] = k }`, - `s = {"a": 1, "b": 2, "c": 4} { true }`, - `t = ["d", "e", "g"] { true }`}, - "true"}, - {"no suffix: object var binding", []string{ - `p[x] { q = x }`, - `q[k] = v { v = [i, j]; k = i; i = "a"; j = 1 }`}, - `[{"a": ["a", 1]}]`}, - {"no suffix: object composite value", []string{ - `p[x] { q = x }`, - `q[k] = {"v": v} { v = [i, j]; k = i; i = "a"; j = 1 }`}, - `[{"a": {"v": ["a", 1]}}]`}, - // data.c[0].z.p is longer than data.q - {"no suffix: bound ref with long prefix (#238)", []string{ - `p = true { q; q }`, - `q = x { x = data.c[0].z.p }`}, "true"}, - {"no suffix: object conflict (error)", []string{ - `p[x] = y { xs = ["a", "b", "c", "a"]; x = xs[i]; y = a[i] }`}, - objectDocKeyConflictErr(nil)}, - {"no suffix: set", []string{`p[x] { q = s; s[x] }`, `q[x] { a[i] = x }`}, "[1,2,3,4]"}, - - {"empty partial set", []string{"p[1] { a[0] = 100 }"}, "[]"}, - {"empty partial object", []string{`p["x"] = 1 { a[0] = 100 }`}, "{}"}, - - {"input: non-ground object keys", []string{ - `p = x { q.a.b = x }`, - `q = {x: {y: 1}} { x = "a"; y = "b" }`, - }, "1"}, - - {"input: non-ground set elements", []string{ - `p { q["c"] }`, - `q = {x, "b", z} { x = "a"; z = "c" }`, - }, "true"}, - - {"output: non-ground object keys", []string{ - `p[x] { q[i][j] = x }`, - `q = {x: {x1: 1}, y: {y1: 2}} { x = "a"; y = "b"; x1 = "a1"; y1 = "b1" }`, - }, "[1, 2]"}, - - {"output: non-ground set elements", []string{ - `p[x] { q[x] }`, - `q = {x, "b", z} { x = "a"; z = "c" }`, - }, `["a", "b", "c"]`}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownBaseAndVirtualDocs(t *testing.T) { - - // Define base docs that will overlap with virtual docs. - var data map[string]interface{} - - input := ` - { - "topdown": { - "a": { - "b": { - "c": { - "x": [100,200], - "y": false, - "z": { - "a": "b" - } - } - } - }, - "g": { - "h": { - "k": [1,2,3] - } - }, - "set": { - "u": [1,2,3,4] - }, - "conflicts": { - "k": "foo" - } - } - } - ` - if err := util.UnmarshalJSON([]byte(input), &data); err != nil { - panic(err) - } - - compiler := compileModules([]string{ - // Define virtual docs that will overlap with base docs. - `package topdown.a.b.c - -p = [1, 2] { true } -q = [3, 4] { true } -r["a"] = 1 { true } -r["b"] = 2 { true }`, - - `package topdown.a.b.c.s - -w = {"f": 10, "g": 9.9} { true }`, - - `package topdown.set - -v[data.topdown.set.u[_]] { true }`, - - `package topdown.no.base.doc - -p = true { true }`, - - `package topdown.a.b.c.undefined1 - -p = true { false } -p = true { false } -q = true { false }`, - - `package topdown.a.b.c.undefined2 - -p = true { input.foo }`, - - `package topdown.a.b.c.empty`, - - `package topdown.g.h - -p = true { false }`, - - `package topdown.virtual.constants - - p = 1 - q = 2 - r = 1`, - - `package topdown.missing.input.value - - p = input.deadbeef`, - - // Define virtual docs that we can query to obtain merged result. - `package topdown - -p[[x1, x2, x3, x4]] { data.topdown.a.b[x1][x2][x3] = x4 } -q[[x1, x2, x3]] { data.topdown.a.b[x1][x2][0] = x3 } -r[[x1, x2]] { data.topdown.a.b[x1] = x2 } -s = data.topdown.no { true } -t = data.topdown.a.b.c.undefined1 { true } -u = data.topdown.missing.input.value { true } -v = data.topdown.g { true } -w = data.topdown.set { true } - -iterate_ground[x] { data.topdown.virtual.constants[x] = 1 } -`, - `package topdown.conflicts - - k = "bar"`, - `package enum_errors.a.b.c - -p = x { x = 1/0 }`, - `package enum_errors.caller - -p[x] = y { data.enum_errors.a[x] = y }`, - }) - - store := inmem.NewFromObject(data) - - assertTopDownWithPath(t, compiler, store, "base/virtual", []string{"topdown", "p"}, "{}", `[ - ["c", "p", 0, 1], - ["c", "p", 1, 2], - ["c", "q", 0, 3], - ["c", "q", 1, 4], - ["c", "r", "a", 1], - ["c", "r", "b", 2], - ["c", "x", 0, 100], - ["c", "x", 1, 200], - ["c", "z", "a", "b"], - ["c", "s", "w", {"f":10, "g": 9.9}] - ]`) - - assertTopDownWithPath(t, compiler, store, "base/virtual: ground key", []string{"topdown", "q"}, "{}", `[ - ["c", "p", 1], - ["c", "q", 3], - ["c", "x", 100] - ]`) - - assertTopDownWithPath(t, compiler, store, "base/virtual: prefix", []string{"topdown", "r"}, "{}", `[ - ["c", { - "p": [1,2], - "q": [3,4], - "r": {"a": 1, "b": 2}, - "s": {"w": {"f": 10, "g": 9.9}}, - "x": [100,200], - "y": false, - "z": {"a": "b"}, - "undefined1": {}, - "undefined2": {}, - "empty": {} - }] - ]`) - - assertTopDownWithPath(t, compiler, store, "base/virtual: set", []string{"topdown", "w"}, "{}", `{ - "v": [1,2,3,4], - "u": [1,2,3,4] - }`) - - assertTopDownWithPath(t, compiler, store, "base/virtual: no base", []string{"topdown", "s"}, "{}", `{"base": {"doc": {"p": true}}}`) - assertTopDownWithPath(t, compiler, store, "base/virtual: undefined", []string{"topdown", "t"}, "{}", "{}") - assertTopDownWithPath(t, compiler, store, "base/virtual: undefined-2", []string{"topdown", "v"}, "{}", `{"h": {"k": [1,2,3]}}`) - assertTopDownWithPath(t, compiler, store, "base/virtual: missing input value", []string{"topdown", "u"}, "{}", "{}") - assertTopDownWithPath(t, compiler, store, "iterate ground", []string{"topdown", "iterate_ground"}, "{}", `["p", "r"]`) - assertTopDownWithPath(t, compiler, store, "base/virtual: conflicts", []string{"topdown.conflicts"}, "{}", `{"k": "foo"}`) - assertTopDownWithPath(t, compiler, store, "enumerate virtual errors", []string{"enum_errors", "caller", "p"}, `{}`, &Error{Code: BuiltinErr, Message: "divide by zero"}) -} - -func TestTopDownFix1863(t *testing.T) { - - compiler := ast.MustCompileModules(map[string]string{ - "test1.rego": ` - package a.b - - # this module is empty - `, - "test2.rego": ` - package x - - p = data.a.b # p should be defined (an empty object) - `, - }) - - store := inmem.New() - - assertTopDownWithPath(t, compiler, store, "is defined", []string{}, ``, `{"a": {"b": {}}, "x": {"p": {}}}`) - assertTopDownWithPath(t, compiler, store, "is defined", []string{"x"}, ``, `{"p": {}}`) - assertTopDownWithPath(t, compiler, store, "is defined", []string{"x", "p"}, ``, `{}`) -} - -func TestTopDownNestedReferences(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - // nested base document references - {"ground ref", []string{`p = true { a[h[0][0]] = 2 }`}, "true"}, - {"non-ground ref", []string{`p[x] { x = a[h[i][j]] }`}, "[2,3,4]"}, - {"two deep", []string{`p[x] { x = a[a[a[i]]] }`}, "[3,4]"}, - {"two deep", []string{`p[x] { x = a[h[i][a[j]]] }`}, "[3,4]"}, - {"two deep repeated var", []string{`p[x] { x = a[h[i][a[i]]] }`}, "[3]"}, - {"no suffix", []string{`p = true { 4 = a[three] }`}, "true"}, - {"var ref", []string{`p[y] { x = [1, 2, 3]; y = a[x[_]] }`}, "[2,3,4]"}, - {"undefined", []string{`p = true { a[three.deadbeef] = x }`}, ""}, - - // nested virtual document references - {"vdoc ref: complete", []string{`p[x] { x = a[q[_]] }`, `q = [2, 3] { true }`}, "[3,4]"}, - {"vdoc ref: complete: ground", []string{`p[x] { x = a[q[1]] }`, `q = [2, 3] { true }`}, "[4]"}, - {"vdoc ref: complete: no suffix", []string{`p = true { 2 = a[q] }`, `q = 1 { true }`}, "true"}, - {"vdoc ref: partial object", []string{ - `p[x] { x = a[q[_]] }`, - `q[k] = v { o = {"a": 2, "b": 3, "c": 100}; o[k] = v }`}, - "[3,4]"}, - {"vdoc ref: partial object: ground", []string{ - `p[x] { x = a[q.b] }`, - `q[k] = v { o = {"a": 2, "b": 3, "c": 100}; o[k] = v }`}, - "[4]"}, - - // mixed cases - {"vdoc ref: complete: nested bdoc ref", []string{ - `p[x] { x = a[q[b[_]]] }`, - `q = {"hello": 1, "goodbye": 3, "deadbeef": 1000} { true }`}, "[2,4]"}, - {"vdoc ref: partial object: nested bdoc ref", []string{ - `p[x] { x = a[q[b[_]]] }`, - // bind to value - `q[k] = v { o = {"hello": 1, "goodbye": 3, "deadbeef": 1000}; o[k] = v }`}, "[2,4]"}, - {"vdoc ref: partial object: nested bdoc ref-2", []string{ - `p[x] { x = a[q[d.e[_]]] }`, - // bind to reference - `q[k] = v { strings[k] = v }`}, "[3,4]"}, - {"vdoc ref: multiple", []string{ - `p[x] { x = q[a[_]].v[r[a[_]]] }`, - `q = [{"v": {}}, {"v": [0, 0, 1, 2]}, {"v": [0, 0, 3, 4]}, {"v": [0, 0]}, {}] { true }`, - `r = [1, 2, 3, 4] { true }`}, "[1,2,3,4]"}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownVarReferences(t *testing.T) { - - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"ground", []string{`p[x] { v = [[1, 2], [2, 3], [3, 4]]; x = v[2][1] }`}, "[4]"}, - {"non-ground", []string{`p[x] { v = [[1, 2], [2, 3], [3, 4]]; x = v[i][j] }`}, "[1,2,3,4]"}, - {"mixed", []string{`p[x] = y { v = [{"a": 1, "b": 2}, {"c": 3, "z": [4]}]; y = v[i][x][j] }`}, `{"z": 4}`}, - {"ref binding", []string{`p[x] { v = c[i][j]; x = v[k]; x = true }`}, "[true]"}, - {"existing ref binding", []string{`p = x { q = a; q[0] = x; q[0] }`}, `1`}, - {"embedded", []string{`p[x] { v = [1, 2, 3]; x = [{"a": v[i]}] }`}, `[[{"a": 1}], [{"a": 2}], [{"a": 3}]]`}, - {"embedded ref binding", []string{`p[x] { v = c[i][j]; w = [v[0], v[1]]; x = w[y] }`}, "[null, false, true, 3.14159]"}, - {"array: ground var", []string{`p[x] { i = [1, 2, 3, 4]; j = [1, 2, 999]; j[k] = y; i[y] = x }`}, "[2,3]"}, - {"array: ref", []string{`p[y] { i = [1,2,3,4]; x = data.a[_]; i[x] = y }`}, `[2, 3, 4]`}, - {"object: ground var", []string{`p[x] { i = {"a": 1, "b": 2, "c": 3}; j = ["a", "c", "deadbeef"]; j[k] = y; i[y] = x }`}, "[1, 3]"}, - {"object: ref", []string{`p[y] { i = {"1": 1, "2": 2, "4": 4}; x = data.numbers[_]; i[x] = y }`}, `[1, 2, 4]`}, - {"set: ground var", []string{`p[x] { i = {1, 2, 3, 4}; j = {1, 2, 99}; j[x]; i[x] }`}, "[1,2]"}, - {"set: ref", []string{`p[x] { i = {1, 2, 3, 4}; x = data.a[_]; i[x] }`}, `[1, 2, 3, 4]`}, - {"set: lookup: base docs", []string{`p = true { v = {[1, 999], [3, 4]}; pair = [a[2], 4]; v[pair] }`}, "true"}, - {"set: lookup: embedded", []string{`p = true { x = [{}, {[1, 2], [3, 4]}]; y = [3, 4]; x[i][y] }`}, "true"}, - {"set: lookup: dereference", []string{`p[[i, z, r]] { x = [{}, {[1, 2], [3, 4]}]; y = [3, 4]; x[i][y][z] = r }`}, "[[1,0,3], [1,1,4]]"}, - {"avoids indexer", []string{`p = true { somevar = [1, 2, 3]; somevar[i] = 2 }`}, "true"}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownCompositeReferences(t *testing.T) { - tests := []struct { - note string - rule string - expected interface{} - }{ - {"array", "p = fixture.r[[1, 2]]", "[1, 2]"}, - {"object", `p = fixture.r[{"foo": "bar"}]`, `{"foo": "bar"}`}, - {"set", `p = fixture.r[{1, 2}]`, "[1, 2]"}, - - {"unify array", `p = [x | fixture.r[[1, x]]]`, "[2, 3]"}, - {"unify object", `p = [x | fixture.r[{"foo": x}]]`, `["bar"]`}, - {"unify partial ground array", `p = [x | fixture.p1[[x,2]]]`, `[1,2]`}, - - {"complete doc unify", `p = [[x,y] | fixture.s[[x, y]]]`, `[[1, 2], [1, 3], [2, 7], [[1,1], 4]]`}, - {"partial doc unify", `p = [[x,y] | fixture.r[[x, y]]]`, `[[1, 2], [1, 3], [2, 7], [[1,1], 4]]`}, - - {"empty set", `p { fixture.empty[set()]} `, "true"}, - - {"ref", `p = fixture.r[[fixture.foo.bar, 3]]`, "[1,3]"}, - {"nested ref", `p = fixture.r[[fixture.foo[fixture.o.foo], 3]]`, "[1,3]"}, - - {"comprehension", `p = fixture.s[[[x | x = y[_]; y = [1, 1]], 4]]`, "[[1,1],4]"}, - - {"missing array", `p = fixture.r[[1, 4]]`, ``}, - {"missing object value", `p = fixture.r[{"foo": "baz"}]`, ``}, - {"missing set", `p = fixture.r[{1, 3}]`, ``}, - } - - fixture := `package fixture - empty = {set()} - s = {[1, 2], [1, 3], {"foo": "bar"}, {1, 2}, [2, 7], [[1,1], 4]} - r[x] { s[x] } - a = [1, 2] - o = {"foo": "bar"} - foo = {"bar": 1} - - p1[[1,2]] - p1[[1,3]] - p1[[2,2]] - ` - - for _, tc := range tests { - module := "package test\nimport data.fixture\n" + tc.rule - compiler := compileModules([]string{fixture, module}) - assertTopDownWithPath(t, compiler, inmem.New(), tc.note, []string{"test", "p"}, "", tc.expected) - } -} - -func TestTopDownIndirectReferences(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"array", []string{`p[x] {[1, 2, 3][x]}`}, "[0, 1, 2]"}, - {"call", []string{`p {split("foo.bar", ".")[0] == "foo"}`}, "true"}, - {"multiple call", []string{`p[x] {split(split("foo.bar:qux", ".")[_], ":")[i] = x}`}, `["foo", "bar", "qux"]`}, - {"user call", []string{`fn(x) = [x] {true}`, `p[x] {x = fn(1)[0]}`}, "[1]"}, - {"user call in comprehension", []string{`fn(x) = [x] {true}`, `p[x] {x = [y | y = fn(1)][_][_]}`}, "[1]"}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownDisjunction(t *testing.T) { - - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"incr: query set", []string{`p[x] { a[i] = x }`, `p[y] { b[j] = y }`}, `[1,2,3,4,"hello","goodbye"]`}, - {"incr: query set constants", []string{ - `p[100] { true }`, - `p[x] { a[x] }`}, - "[0,1,2,3,100]"}, - {"incr: query object", []string{ - `p[k] = v { b[v] = k }`, - `p[k] = v { a[i] = v; g[k][j] = v }`}, - `{"b": 2, "c": 4, "hello": "v1", "goodbye": "v2", "a": 1}`}, - {"incr: query object constant key", []string{ - `p["a"] = 1 { true }`, - `p["b"] = 2 { true }`}, - `{"a": 1, "b": 2}`}, - {"incr: iter set", []string{ - `p[x] { q[x] }`, - `q[x] { a[i] = x }`, - `q[y] { b[j] = y }`}, - `[1,2,3,4,"hello","goodbye"]`}, - {"incr: eval set", []string{ - `p[x] { q = s; s[x] }`, // make p a set so that test assertion orders result - `q[x] { a[_] = x }`, - `q[y] { b[_] = y }`}, - `[1,2,3,4,"hello","goodbye"]`}, - {"incr: eval object", []string{ - `p[k] = v { q[k] = v }`, - `q[k] = v { b[v] = k }`, - `q[k] = v { a[i] = v; g[k][j] = v }`}, - `{"b": 2, "c": 4, "hello": "v1", "goodbye": "v2", "a": 1}`}, - {"incr: eval object constant key", []string{ - `p[k] = v { q[k] = v }`, - `q["a"] = 1 { true }`, - `q["b"] = 2 { true }`}, - `{"a": 1, "b": 2}`}, - {"complete: undefined", []string{`p = true { false }`, `p = true { false }`}, ""}, - {"complete: error", []string{`p = true { true }`, `p = false { false }`, `p = false { true }`}, completeDocConflictErr(nil)}, - {"complete: valid", []string{`p = true { true }`, `p = true { true }`}, "true"}, - {"complete: valid-2", []string{`p = true { true }`, `p = false { false }`}, "true"}, - {"complete: reference error", []string{`p = true { q }`, `q = true { true }`, `q = false { true }`}, completeDocConflictErr(nil)}, - {"complete: reference valid", []string{`p = true { q }`, `q = true { true }`, `q = true { true }`}, "true"}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownNegation(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"neg: constants", []string{`p = true { not true = false }`}, "true"}, - {"neg: constants", []string{`p = true { not true = true }`}, ""}, - {"neg: set contains", []string{`p = true { not q.v0 }`, `q[x] { b[x] = v }`}, "true"}, - {"neg: set contains undefined", []string{`p = true { not q.v2 }`, `q[x] { b[x] = v }`}, ""}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownComprehensions(t *testing.T) { - - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"array simple", []string{`p[i] { xs = [x | x = a[_]]; xs[i] > 1 }`}, "[1,2,3]"}, - {"array nested", []string{`p[i] { ys = [y | y = x[_]; x = [z | z = a[_]]]; ys[i] > 1 }`}, "[1,2,3]"}, - {"array embedded array", []string{`p[i] { xs = [[x | x = a[_]]]; xs[0][i] > 1 }`}, "[1,2,3]"}, - {"array embedded object", []string{`p[i] { xs = {"a": [x | x = a[_]]}; xs.a[i] > 1 }`}, "[1,2,3]"}, - {"array embedded set", []string{`p = xs { xs = {[x | x = a[_]]} }`}, "[[1,2,3,4]]"}, - {"array closure", []string{`p[x] { y = 1; x = [y | y = 1] }`}, "[[1]]"}, - {"array dereference embedded", []string{ - `p[x] { q.a[2][i] = x }`, - `q[k] = v { k = "a"; v = [y | i[_] = _; i = y; i = [z | z = a[_]]] }`, - }, "[1,2,3,4]"}, - - {"object simple", []string{`p[i] { xs = {s: x | x = a[_]; format_int(x, 10, s)}; y = xs[i]; y > 1 }`}, `["2","3","4"]`}, - {"object non-string key", []string{`p[x] { xs = {k: 1 | a[_] = k}; xs[x]}`}, `[1,2,3,4]`}, - {"object nested", []string{`p = r { r = {x: y | z = {i: q | i = b[q]}; x = z[y]}}`}, `{"v1": "hello", "v2": "goodbye"}`}, - {"object embedded array", []string{`p[i] { xs = [{s: x | x = a[_]; format_int(x, 10, s)}]; xs[0][i] > 1 }`}, `["2","3","4"]`}, - {"object embedded object", []string{`p[i] { xs = {"a": {s: x | x = a[_]; format_int(x, 10, s)}}; xs.a[i] > 1 }`}, `["2","3","4"]`}, - {"object embedded set", []string{`p = xs { xs = {{s: x | x = a[_]; format_int(x, 10, s)}} }`}, `[{"1":1,"2":2,"3":3,"4":4}]`}, - {"object closure", []string{`p[x] { y = 1; x = {"foo":y | y = 1} }`}, `[{"foo": 1}]`}, - {"object dereference embedded", []string{ - `arr = [4] { true }`, - `p[x] { q.a = x }`, - `q[k] = v { k = "a"; v = {"bar": y | i[_] = _; i = y; i = {"foo": z | z = arr[_]}} }`, - }, `[{"bar": {"foo": 4}}]`}, - {"object conflict", []string{ - `p[x] { q.a = x }`, - `q[k] = v { k = "a"; v = {"bar": y | i[_] = _; i = y; i = {"foo": z | z = a[_]}} }`, - }, objectDocKeyConflictErr(nil)}, - - {"set simple", []string{`p = y {y = {x | x = a[_]; x > 1}}`}, "[2,3,4]"}, - {"set nested", []string{`p[i] { ys = {y | y = x[_]; x = {z | z = a[_]}}; ys[i] > 1 }`}, "[2,3,4]"}, - {"set embedded array", []string{`p[i] { xs = [{x | x = a[_]}]; xs[0][i] > 1 }`}, "[2,3,4]"}, - {"set embedded object", []string{`p[i] { xs = {"a": {x | x = a[_]}}; xs.a[i] > 1 }`}, "[2,3,4]"}, - {"set embedded set", []string{`p = xs { xs = {{x | x = a[_]}} }`}, "[[1,2,3,4]]"}, - {"set closure", []string{`p[x] { y = 1; x = {y | y = 1} }`}, "[[1]]"}, - {"set dereference embedded", []string{ - `p[x] { q.a = x }`, - `q[k] = v { k = "a"; v = {y | i[_] = _; i = y; i = {z | z = a[_]}} }`, - }, "[[[1,2,3,4]]]"}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownDefaultKeyword(t *testing.T) { - - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"undefined", []string{`p = 1 { false }`, `default p = 0`, `p = 2 { false }`}, "0"}, - {"defined", []string{`default p = 0`, `p = 1 { true }`, `p = 2 { false }`}, `1`}, - {"defined-ooo", []string{`p = 1 { true }`, `default p = 0`, `p = 2 { false }`}, "1"}, - {"array comprehension", []string{`p = 1 { false }`, `default p = [x | a[_] = x]`}, "[1,2,3,4]"}, - {"object comprehension", []string{`p = 1 { false }`, `default p = {x: k | d[k][_] = x}`}, `{"bar": "e", "baz": "e"}`}, - {"set comprehension", []string{`p = 1 { false }`, `default p = {x | a[_] = x}`}, `[1,2,3,4]`}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownArithmetic(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"plus", []string{`p[y] { a[i] = x; y = i + x }`}, "[1,3,5,7]"}, - {"minus", []string{`p[y] { a[i] = x; y = i - x }`}, "[-1]"}, - {"multiply", []string{`p[y] { a[i] = x; y = i * x }`}, "[0,2,6,12]"}, - {"divide+round", []string{`p[z] { a[i] = x; y = i / x; round(y, z) }`}, "[0, 1]"}, - {"divide+error", []string{`p[y] { a[i] = x; y = x / i }`}, &Error{Code: BuiltinErr, Message: "divide by zero"}}, - {"abs", []string{`p = true { abs(-10, x); x = 10 }`}, "true"}, - {"remainder", []string{`p = x { x = 7 % 4 }`}, "3"}, - {"remainder+error", []string{`p = x { x = 7 % 0 }`}, &Error{Code: BuiltinErr, Message: "modulo by zero"}}, - {"remainder+error+floating", []string{`p = x { x = 1.1 % 1 }`}, &Error{Code: BuiltinErr, Message: "modulo on floating-point number"}}, - {"arity 1 ref dest", []string{`p = true { abs(-4, a[3]) }`}, "true"}, - {"arity 1 ref dest (2)", []string{`p = true { not abs(-5, a[3]) }`}, "true"}, - {"arity 2 ref dest", []string{`p = true { a[2] = 1 + 2 }`}, "true"}, - {"arity 2 ref dest (2)", []string{`p = true { not a[2] = 2 + 3 }`}, "true"}, - {"bug 2469 - precision", []string{"p = true { 49649733057 + 1 == 49649733058 }"}, "true"}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownCasts(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"to_number", []string{ - `p = [x, y, z, i, j] { to_number("-42.0", x); to_number(false, y); to_number(100.1, z); to_number(null, i); to_number(true, j) }`, - }, - "[-42.0, 0, 100.1, 0, 1]"}, - {"to_number ref dest", []string{`p = true { to_number("3", a[2]) }`}, "true"}, - {"to_number ref dest", []string{`p = true { not to_number("-1", a[2]) }`}, "true"}, - {"to_number: bad input", []string{`p { to_number("broken", x) }`}, &Error{Code: BuiltinErr, Message: "invalid syntax"}}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownTypeBuiltin(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"is_number", []string{ - `p = [x, y, z] { is_number(-42.0, x); is_number(0, y); is_number(100.1, z) }`, - }, "[true, true, true]"}, - - {"is_number", []string{ - `p = x { is_number(null, x) }`, - }, ""}, - - {"is_number", []string{ - `p = x { is_number(false, x) }`, - }, ""}, - - {"is_number", []string{ - `p[x] {arr = [true, 1]; arr[_] = x; is_number(x) }`, - }, "[1]"}, - - {"is_string", []string{ - `p = [x, y, z] { is_string("Hello", x); is_string("There", y); is_string("OPA", z) }`, - }, "[true, true, true]"}, - - {"is_string", []string{ - `p = x { is_string(null, x) }`, - }, ""}, - - {"is_string", []string{ - `p = x { is_string(false, x) }`, - }, ""}, - - {"is_string", []string{ - `p[x] {arr = [true, 1, "Hey"]; arr[_] = x; is_string(x) }`, - }, "[\"Hey\"]"}, - - {"is_boolean", []string{ - `p = [x, y] { is_boolean(true, x); is_boolean(false, y) }`, - }, "[true, true]"}, - - {"is_boolean", []string{ - `p = x { is_boolean(null, x) }`, - }, ""}, - - {"is_boolean", []string{ - `p = x { is_boolean("Hello", x) }`, - }, ""}, - - {"is_boolean", []string{ - `p[x] {arr = [false, 1, "Hey"]; arr[_] = x; is_boolean(x) }`, - }, "[false]"}, - - {"is_array", []string{ - `p = [x, y] { is_array([1,2,3], x); is_array(["a", "b"], y) }`, - }, "[true, true]"}, - - {"is_array", []string{ - `p = x { is_array({1,2,3}, x) }`, - }, ""}, - - {"is_set", []string{ - `p = [x, y] { is_set({1,2,3}, x); is_set({"a", "b"}, y) }`, - }, "[true, true]"}, - - {"is_set", []string{ - `p = x { is_set([1,2,3], x) }`, - }, ""}, - - {"is_object", []string{ - `p = x { is_object({"foo": yy | yy = 1}, x) }`, - }, "true"}, - - {"is_object", []string{ - `p = x { is_object("foo", x) }`, - }, ""}, - - {"is_null", []string{ - `p = x { is_null(null, x) }`, - }, "true"}, - - {"is_null", []string{ - `p = x { is_null(true, x) }`, - }, ""}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownTypeNameBuiltin(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"type_name", []string{ - `p = x { type_name(null, x) }`}, `"null"`}, - {"type_name", []string{ - `p = x { type_name(true, x) }`}, `"boolean"`}, - {"type_name", []string{ - `p = x { type_name(100, x) }`}, `"number"`}, - {"type_name", []string{ - `p = x { type_name("Hello", x) }`}, `"string"`}, - {"type_name", []string{ - `p = x { type_name([1,2,3], x) }`}, `"array"`}, - {"type_name", []string{ - `p = x { type_name({1,2,3}, x) }`}, `"set"`}, - {"type_name", []string{ - `p = x { type_name({"foo": yy | yy = 1}, x) }`}, `"object"`}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } - -} - -func TestTopDownRegexMatch(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"re_match", []string{`p = true { re_match("^[a-z]+\\[[0-9]+\\]$", "foo[1]") }`}, "true"}, - {"re_match: undefined", []string{`p = true { re_match("^[a-z]+\\[[0-9]+\\]$", "foo[\"bar\"]") }`}, ""}, - {"re_match: bad pattern err", []string{`p = true { re_match("][", "foo[\"bar\"]") }`}, &Error{Code: BuiltinErr, Message: "re_match: error parsing regexp: missing closing ]: `[`"}}, - {"re_match: ref", []string{`p[x] { re_match("^b.*$", d.e[x]) }`}, "[0,1]"}, - - {"re_match: raw", []string{fmt.Sprintf(`p = true { re_match(%s, "foo[1]") }`, "`^[a-z]+\\[[0-9]+\\]$`")}, "true"}, - {"re_match: raw: undefined", []string{fmt.Sprintf(`p = true { re_match(%s, "foo[\"bar\"]") }`, "`^[a-z]+\\[[0-9]+\\]$`")}, ""}, - {"regex.match", []string{`p = true { regex.match("^[a-z]+\\[[0-9]+\\]$", "foo[1]") }`}, "true"}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownRegexSplit(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"regex.split: empty string", []string{`p = x { regex.split("^[a-z]+\\[[0-9]+\\]$", "", [x]) }`}, `""`}, - {"regex.split: non-repeat pattern", []string{`p = [v,w,x,y] { regex.split("a", "banana", [v,w,x,y]) }`}, `["b","n","n",""]`}, - {"regex.split: repeat pattern", []string{`p = [v,w] { regex.split("z+", "pizza", [v,w]) }`}, `["pi","a"]`}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownGlobsMatch(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"regex.globs_match", []string{`p = true { regex.globs_match("a.a.[0-9]+z", ".b.b2359825792*594823z") }`}, "true"}, - {"regex.globs_match", []string{`p = true { regex.globs_match("[a-z]+", "[0-9]*") }`}, ""}, - {"regex.globs_match: bad pattern err", []string{`p = true { regex.globs_match("pqrs]", "[a-b]+") }`}, &Error{Code: BuiltinErr, Message: "input:pqrs], pos:5, set-close ']' with no preceding '[': the input provided is invalid"}}, - {"regex.globs_match: ref", []string{`p[x] { regex.globs_match("b.*", d.e[x]) }`}, "[0,1]"}, - - {"regex.globs_match: raw", []string{fmt.Sprintf(`p = true { regex.globs_match(%s, "foo\\[1\\]") }`, "`[a-z]+\\[[0-9]+\\]`")}, "true"}, - {"regex.globs_match: raw: undefined", []string{fmt.Sprintf(`p = true { regex.globs_match(%s, "foo[\"bar\"]") }`, "`[a-z]+\\[[0-9]+\\]`")}, ""}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownSets(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"set_diff", []string{`p = x { s1 = {1, 2, 3, 4}; s2 = {1, 3}; x = s1 - s2 }`}, `[2,4]`}, - {"set_diff: refs", []string{`p = x { s1 = {a[2], a[1], a[0]}; s2 = {a[0], 2}; set_diff(s1, s2, x) }`}, "[3]"}, - {"set_diff: ground output", []string{`p = true { {1} = {1, 2, 3} - {2, 3} }`}, "true"}, - {"set_diff: virt docs", []string{`p = x { x = s1 - s2 }`, `s1[1] { true }`, `s1[2] { true }`, `s1["c"] { true }`, `s2 = {"c", 1} { true }`}, "[2]"}, - {"intersect", []string{`p = x { x = {a[1], a[2], 3} & {a[2], 4, 3} }`}, "[3]"}, - {"union", []string{`p = true { {2, 3, 4} = {a[1], a[2], 3} | {a[2], 4, 3} }`}, "true"}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownStrings(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"format_int", []string{`p = x { format_int(15.5, 16, x) }`}, `"f"`}, - {"format_int: undefined", []string{`p = true { format_int(15.5, 16, "10000") }`}, ""}, - {"format_int: ref dest", []string{`p = true { format_int(3.1, 10, numbers[2]) }`}, "true"}, - {"format_int: ref dest (2)", []string{`p = true { not format_int(4.1, 10, numbers[2]) }`}, "true"}, - {"format_int: err: bad base", []string{`p = true { format_int(4.1, 199, x) }`}, &Error{Code: TypeErr, Message: "operand 2 must be one of {2, 8, 10, 16}"}}, - {"concat", []string{`p = x { concat("/", ["", "foo", "bar", "0", "baz"], x) }`}, `"/foo/bar/0/baz"`}, - {"concat: set", []string{`p = x { concat(",", {"1", "2", "3"}, x) }`}, `"1,2,3"`}, - {"concat: undefined", []string{`p = true { concat("/", ["a", "b"], "deadbeef") }`}, ""}, - {"concat: ref dest", []string{`p = true { concat("", ["f", "o", "o"], c[0].x[2]) }`}, "true"}, - {"concat: ref dest (2)", []string{`p = true { not concat("", ["b", "a", "r"], c[0].x[2]) }`}, "true"}, - {"indexof", []string{`p = x { indexof("abcdefgh", "cde", x) }`}, "2"}, - {"indexof: not found", []string{`p = x { indexof("abcdefgh", "xyz", x) }`}, "-1"}, - {"substring", []string{`p = x { substring("abcdefgh", 2, 3, x) }`}, `"cde"`}, - {"substring: remainder", []string{`p = x { substring("abcdefgh", 2, -1, x) }`}, `"cdefgh"`}, - {"substring: too long", []string{`p = x { substring("abcdefgh", 2, 10000, x) }`}, `"cdefgh"`}, - {"substring: offset negative", []string{`p = x { substring("aaa", -1, -1, x) }`}, &Error{Code: BuiltinErr, Message: "negative offset"}}, - {"substring: offset too long", []string{`p = x { substring("aaa", 3, -1, x) }`}, `""`}, - {"substring: offset too long 2", []string{`p = x { substring("aaa", 4, -1, x) }`}, `""`}, - {"contains", []string{`p = true { contains("abcdefgh", "defg") }`}, "true"}, - {"contains: undefined", []string{`p = true { contains("abcdefgh", "ac") }`}, ""}, - {"startswith", []string{`p = true { startswith("abcdefgh", "abcd") }`}, "true"}, - {"startswith: undefined", []string{`p = true { startswith("abcdefgh", "bcd") }`}, ""}, - {"endswith", []string{`p = true { endswith("abcdefgh", "fgh") }`}, "true"}, - {"endswith: undefined", []string{`p = true { endswith("abcdefgh", "fg") }`}, ""}, - {"lower", []string{`p = x { lower("AbCdEf", x) }`}, `"abcdef"`}, - {"upper", []string{`p = x { upper("AbCdEf", x) }`}, `"ABCDEF"`}, - {"split: empty string", []string{`p = x { split("", ".", [x]) }`}, `""`}, - {"split: one", []string{`p = x { split("foo", ".", [x]) }`}, `"foo"`}, - {"split: many", []string{`p = [x,y] { split("foo.bar.baz", ".", [x,"bar",y]) }`}, `["foo","baz"]`}, - {"replace: empty string", []string{`p = x { replace("", "hi", "bye", x) }`}, `""`}, - {"replace: one", []string{`p = x { replace("foo.bar", ".", ",", x) }`}, `"foo,bar"`}, - {"replace: many", []string{`p = x { replace("foo.bar.baz", ".", ",", x) }`}, `"foo,bar,baz"`}, - {"replace: overlap", []string{`p = x { replace("foo...bar", "..", ",,", x) }`}, `"foo,,.bar"`}, - {"trim: empty string", []string{`p = x { trim("", ".", x) }`}, `""`}, - {"trim: end", []string{`p = x { trim("foo.bar...", ".", x) }`}, `"foo.bar"`}, - {"trim: start", []string{`p = x { trim("...foo.bar", ".", x) }`}, `"foo.bar"`}, - {"trim: both", []string{`p = x { trim("...foo.bar...", ".", x) }`}, `"foo.bar"`}, - {"trim: multi-cutset", []string{`p = x { trim("...foo.bar...", ".fr", x) }`}, `"oo.ba"`}, - {"trim: multi-cutset-none", []string{`p = x { trim("...foo.bar...", ".o", x) }`}, `"foo.bar"`}, - {"sprintf: none", []string{`p = x { sprintf("hi", [], x) }`}, `"hi"`}, - {"sprintf: string", []string{`p = x { sprintf("hi %s", ["there"], x) }`}, `"hi there"`}, - {"sprintf: int", []string{`p = x { sprintf("hi %02d", [5], x) }`}, `"hi 05"`}, - {"sprintf: hex", []string{`p = x { sprintf("hi %02X.%02X", [127, 1], x) }`}, `"hi 7F.01"`}, - {"sprintf: float", []string{`p = x { sprintf("hi %.2f", [3.1415], x) }`}, `"hi 3.14"`}, - {"sprintf: float too big", []string{`p = x { sprintf("hi %v", [2e308], x) }`}, `"hi 2e308"`}, - {"sprintf: bool", []string{`p = x { sprintf("hi %s", [true], x) }`}, `"hi true"`}, - {"sprintf: composite", []string{`p = x { sprintf("hi %v", [["there", 5, 3.14]], x) }`}, `"hi [\"there\", 5, 3.14]"`}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownJSONBuiltins(t *testing.T) { - - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"marshal", []string{`p = x { json.marshal([{"foo": {1,2,3}}], x) }`}, `"[{\"foo\":[1,2,3]}]"`}, - {"unmarshal", []string{`p = x { json.unmarshal("[{\"foo\":[1,2,3]}]", x) }`}, `[{"foo": [1,2,3]}]`}, - {"unmarshal-non-string", []string{`p = x { json.unmarshal(data.a[0], x) }`}, &Error{Code: TypeErr, Message: "operand 1 must be string but got number"}}, - {"yaml round-trip", []string{`p = y { yaml.marshal([{"foo": {1,2,3}}], x); yaml.unmarshal(x, y) }`}, `[{"foo": [1,2,3]}]`}, - {"yaml unmarshal error", []string{`p { yaml.unmarshal("[1,2,3", _) } `}, &Error{Code: BuiltinErr, Message: "yaml: line 1: did not find"}}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } - -} - -func TestTopDownBase64Builtins(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"encode-1", []string{`p = x { base64.encode("hello", x) }`}, `"aGVsbG8="`}, - {"encode-2", []string{`p = x { base64.encode("there", x) }`}, `"dGhlcmU="`}, - {"decode-1", []string{`p = x { base64.decode("aGVsbG8=", x) }`}, `"hello"`}, - {"decode-2", []string{`p = x { base64.decode("dGhlcmU=", x) }`}, `"there"`}, - {"encode-slash", []string{`p = x { base64.encode("subjects?_d", x) }`}, `"c3ViamVjdHM/X2Q="`}, - {"decode-slash", []string{`p = x { base64.decode("c3ViamVjdHM/X2Q=", x) }`}, `"subjects?_d"`}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownBase64UrlBuiltins(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"encode-1", []string{`p = x { base64url.encode("hello", x) }`}, `"aGVsbG8="`}, - {"encode-2", []string{`p = x { base64url.encode("there", x) }`}, `"dGhlcmU="`}, - {"decode-1", []string{`p = x { base64url.decode("aGVsbG8=", x) }`}, `"hello"`}, - {"decode-2", []string{`p = x { base64url.decode("dGhlcmU=", x) }`}, `"there"`}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownURLBuiltins(t *testing.T) { - tests := []struct { - note string - rules []string - expected interface{} - }{ - {"encode", []string{`p = x { urlquery.encode("a=b+1", x) }`}, `"a%3Db%2B1"`}, - {"encode empty", []string{`p = x { urlquery.encode("", x) }`}, `""`}, - {"decode", []string{`p = x { urlquery.decode("a%3Db%2B1", x) }`}, `"a=b+1"`}, - {"encode_object empty", []string{`p = x { urlquery.encode_object({}, x) }`}, `""`}, - {"encode_object strings", []string{`p = x { urlquery.encode_object({"a": "b", "c": "d"}, x) }`}, `"a=b&c=d"`}, - {"encode_object escape", []string{`p = x { urlquery.encode_object({"a": "c=b+1"}, x) }`}, `"a=c%3Db%2B1"`}, - {"encode_object array", []string{`p = x { urlquery.encode_object({"a": ["b+1","c+2"]}, x) }`}, `"a=b%2B1&a=c%2B2"`}, - {"encode_object set", []string{`p = x { urlquery.encode_object({"a": {"b+1"}}, x) }`}, `"a=b%2B1"`}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } -} - -func TestTopDownTime(t *testing.T) { - - data := loadSmallTestData() - - runTopDownTestCase(t, data, "time caching", []string{` - p { time.now_ns(t0); test.sleep("10ms"); time.now_ns(t1); t1 = t2 } - `}, "true") - - runTopDownTestCase(t, data, "parse nanos", []string{` - p = ns { time.parse_ns("2006-01-02T15:04:05Z07:00", "2017-06-02T19:00:00-07:00", ns) } - `}, "1496455200000000000") - - runTopDownTestCase(t, data, "parse rfc3339 nanos", []string{` - p = ns { time.parse_rfc3339_ns("2017-06-02T19:00:00-07:00", ns) } - `}, "1496455200000000000") - - runTopDownTestCase(t, data, "parse duration nanos", []string{` - p = ns { time.parse_duration_ns("100ms", ns) } - `}, "100000000") - - runTopDownTestCase(t, data, "date", []string{` - p = [year, month, day] { [year, month, day] := time.date(1517814000*1000*1000*1000) }`}, "[2018, 2, 5]") - - runTopDownTestCase(t, data, "date with LA tz", []string{` - p = [year, month, day] { [year, month, day] := time.date([ 1517814000*1000*1000*1000, "America/Los_Angeles" ]) }`}, "[2018, 2, 4]") - - runTopDownTestCase(t, data, "date with empty tz", []string{` - p = [year, month, day] { [year, month, day] := time.date([ 1517832000*1000*1000*1000, "" ]) }`}, "[2018, 2, 5]") - - runTopDownTestCase(t, data, "date leap day", []string{` - p = [year, month, day] { [year, month, day] := time.date(1582977600*1000*1000*1000) }`}, "[2020, 2, 29]") - - runTopDownTestCase(t, data, "date too big", []string{` - p = [year, month, day] { [year, month, day] := time.date(1582977600*1000*1000*1000*1000) }`}, &Error{Code: BuiltinErr, Message: "timestamp too big"}) - - runTopDownTestCase(t, data, "clock", []string{` - p = [hour, minute, second] { [hour, minute, second] := time.clock(1517832000*1000*1000*1000) }`}, "[12, 0, 0]") - - runTopDownTestCase(t, data, "clock with NY tz", []string{` - p = [hour, minute, second] { [hour, minute, second] := time.clock([ 1517832000*1000*1000*1000, "America/New_York" ]) }`}, "[7, 0, 0]") - - runTopDownTestCase(t, data, "clock leap day", []string{` - p = [hour, minute, second] { [hour, minute, second] := time.clock(1582977600*1000*1000*1000) }`}, "[12, 0, 0]") - - runTopDownTestCase(t, data, "clock too big", []string{` - p = [hour, minute, second] { [hour, minute, second] := time.clock(1582977600*1000*1000*1000*1000) }`}, &Error{Code: BuiltinErr, Message: "timestamp too big"}) - - for i, day := range []string{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"} { - ts := 1517832000*1000*1000*1000 + i*24*int(time.Hour) - runTopDownTestCase(t, data, "weekday", []string{fmt.Sprintf(`p = weekday { weekday := time.weekday(%d)}`, ts)}, - fmt.Sprintf("%q", day)) - } - - runTopDownTestCase(t, data, "weekday too big", []string{` - p = weekday { weekday := time.weekday(1582977600*1000*1000*1000*1000) }`}, &Error{Code: BuiltinErr, Message: "timestamp too big"}) - - runTopDownTestCase(t, data, "add_date year month day", []string{` - p = ns { ns := time.add_date(1585852421593912000, 3, 9, 12) }`}, "1705257221593912000") - - runTopDownTestCase(t, data, "add_date negative values", []string{` - p = ns { ns := time.add_date(1585852421593912000, -1, -1, -1) }`}, "1551465221593912000") -} - -func TestTopDownWalkBuiltin(t *testing.T) { - - tests := []struct { - note string - rules []string - expected interface{} - }{ - { - note: "scalar", - rules: []string{ - `p[x] { walk(data.a[0], x) }`, - }, - expected: `[ - [[], 1] - ]`, - }, - { - note: "arrays", - rules: []string{ - `p[x] { walk(data.a, x) }`, - }, - expected: `[ - [[], [1,2,3,4]], - [[0], 1], - [[1], 2], - [[2], 3], - [[3], 4] - ]`, - }, - { - note: "objects", - rules: []string{ - "p[x] { walk(data.b, x) }", - }, - expected: `[ - [[], {"v1": "hello", "v2": "goodbye"}], - [["v1"], "hello"], - [["v2"], "goodbye"] - ]`, - }, - { - note: "sets", - rules: []string{ - "p[x] { walk(q, x) }", - `q = {{1,2,3}} { true }`, - }, - expected: `[ - [[], [[1,2,3]]], - [[[1,2,3]], [1,2,3]], - [[[1,2,3], 1], 1], - [[[1,2,3], 2], 2], - [[[1,2,3], 3], 3] - ]`, - }, - { - note: "match and filter", - rules: []string{ - `p[[k,x]] { walk(q, [k, x]); contains(k[1], "oo") }`, - `q = [ - { - "foo": 1, - "bar": 2, - "bazoo": 3, - } - ] { true }`, - }, - expected: `[[[0, "foo"], 1], [[0, "bazoo"], 3]]`, - }, - { - note: "partially ground path", - rules: []string{ - `p[[k1,k2,x]] { - walk(q, [["a", k1, "b", k2], x]) - }`, - `q = { - "a": [ - { - "b": {"foo": 1, "bar": 2}, - }, - { - "b": {"baz": 3, "qux": 4}, - } - ] - } { true } - `, - }, - expected: `[[0, "foo", 1], [0, "bar", 2], [1, "baz", 3], [1, "qux", 4]]`, - }, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, tc.rules, tc.expected) - } - -} - -func TestTopDownEmbeddedVirtualDoc(t *testing.T) { - - compiler := compileModules([]string{ - `package b.c.d - -import data.a -import data.g - -p[x] { a[i] = x; q[x] } -q[x] { g[j][k] = x }`}) - - store := inmem.NewFromObject(loadSmallTestData()) - - assertTopDownWithPath(t, compiler, store, "deep embedded vdoc", []string{"b", "c", "d", "p"}, "{}", "[1, 2, 4]") -} - -func TestTopDownInputValues(t *testing.T) { - compiler := compileModules([]string{ - `package z - -import data.a -import input.req1 -import input.req2 as req2as -import input.req3.a.b -import input.req4.a.b as req4as - -p = true { a[i] = x; req1.foo = x; req2as.bar = x; q[x] } -q[x] { req1.foo = x; req2as.bar = x; r[x] } -r[x] { {"foo": req2as.bar, "bar": [x]} = {"foo": x, "bar": [req1.foo]} } -s = true { b.x[0] = 1 } -t = true { req4as.x[0] = 1 } -u[x] { b[_] = x; x > 1 } -w = [[1, 2], [3, 4]] { true } -gt1 = true { req1 > 1 } -keys[x] = y { data.numbers[_] = x; to_number(x, y) } -loopback = input { true } -sets { input.foo[{1}][1] = 1 } `}) - - store := inmem.NewFromObject(loadSmallTestData()) - - assertTopDownWithPath(t, compiler, store, "loopback", []string{"z", "loopback"}, `{"foo": 1}`, `{"foo": 1}`) - - assertTopDownWithPath(t, compiler, store, "loopback undefined", []string{"z", "loopback"}, ``, ``) - - assertTopDownWithPath(t, compiler, store, "simple", []string{"z", "p"}, `{ - "req1": {"foo": 4}, - "req2": {"bar": 4} - }`, "true") - - assertTopDownWithPath(t, compiler, store, "missing", []string{"z", "p"}, `{ - "req1": {"foo": 4} - }`, "") - - assertTopDownWithPath(t, compiler, store, "namespaced", []string{"z", "s"}, `{ - "req3": { - "a": { - "b": { - "x": [1,2,3,4] - } - } - } - }`, "true") - - assertTopDownWithPath(t, compiler, store, "namespaced with alias", []string{"z", "t"}, `{ - "req4": { - "a": { - "b": { - "x": [1,2,3,4] - } - } - } - }`, "true") - - assertTopDownWithPath(t, compiler, store, "input set", []string{"z", "sets"}, `{"foo": {{1}}}`, `true`) -} - -func TestTopDownPartialDocConstants(t *testing.T) { - compiler := compileModules([]string{ - `package ex - - foo["bar"] = 0 - foo["baz"] = 1 - foo["*"] = [1, 2, 3] { - input.foo = 7 - } - - bar["x"] - bar["y"] - bar["*"] { - input.foo = 7 - } - `}) - - store := inmem.NewFromObject(loadSmallTestData()) - ctx := context.Background() - txn := storage.NewTransactionOrDie(ctx, store) - defer store.Abort(ctx, txn) - - tests := []struct { - note string - path string - input string - expected string - }{ - { - note: "obj-1", - path: "ex.foo.bar", - expected: "0", - }, - { - note: "obj", - path: "ex.foo", - expected: `{"bar": 0, "baz": 1}`, - }, - { - note: "obj-all", - path: "ex.foo", - input: `{"foo": 7}`, - expected: `{"bar": 0, "baz": 1, "*": [1,2,3]}`, - }, - { - note: "set-1", - path: "ex.bar.x", - expected: `"x"`, - }, - { - note: "set", - path: "ex.bar", - expected: `["x", "y"]`, - }, - { - note: "set-all", - path: "ex.bar", - input: `{"foo": 7}`, - expected: `["x", "y", "*"]`, - }, - } - - for _, tc := range tests { - assertTopDownWithPath(t, compiler, store, tc.note, strings.Split(tc.path, "."), tc.input, tc.expected) - } -} - -func TestTopDownFunctions(t *testing.T) { - modules := []string{`package ex - - foo(x) = y { - split(x, "i", y) - } - - bar[x] = y { - data.l[_].a = x - foo(x, y) - } - - chain0(x) = y { - foo(x, y) - } - - chain1(a) = b { - chain0(a, b) - } - - chain2 = d { - chain1("fooibar", d) - } - - cross(x) = [a, b] { - split(x, "i", y) - foo(y[1], b) - data.test.foo(y[2], a) - } - - falsy_func(x) = false - - falsy_func_else(x) = true { x = 1 } else = false { true } - - falsy_undefined { - falsy_func(1) - } - - falsy_negation { - not falsy_func(1) - } - - falsy_else_value = falsy_func_else(2) - - falsy_else_undefined { - falsy_func_else(2) - } - - falsy_else_negation { - not falsy_func_else(2) - } - - arrays([x, y]) = [a, b] { - foo(x, a) - foo(y, b) - } - - arraysrule = y { - arrays(["hih", "foo"], y) - } - - objects({"foo": x, "bar": y}) = z { - foo(x, a) - data.test.foo(y, b) - z = [a, b] - } - - objectsrule = y { - objects({"foo": "hih", "bar": "hi ho"}, y) - } - - refoutput = y { - foo("hih", z) - y = z[1] - } - - void(x) { - x = "foo" - } - - voidGood { - not void("bar", true) - } - - voidBad { - void("bar", true) - } - - multi(1, x) = y { - y = x - } - - multi(2, x) = y { - a = 2*x - y = a+1 - } - - multi(3, x) = y { - y = x*10 - } - - multi("foo", x) = y { - y = "bar" - } - - multi1 = y { - multi(1, 2, y) - } - - multi2 = y { - multi(2, 2, y) - } - - multi3 = y { - multi(3, 2, y) - } - - multi4 = y { - multi("foo", 2, y) - } - - always_true_fn(x) - - always_true { - always_true_fn(1) - } - `, - ` - package test - - import data.ex - - foo(x) = y { - trim(x, "h o", y) - } - - cross = y { - ex.cross("hi, my name is foo", y) - } - - multi("foo", x) = y { - y = x - } - - multi("bar", x) = y { - y = "baz" - } - - multi_cross_pkg = [y, z] { - multi("foo", "bar", y) - ex.multi(2, 1, z) - }`, - ` - package test - - samepkg = y { - foo("how do you do?", y) - }`, - ` - package test.l1.l3 - - g(x) = x`, - ` - package test.l1.l2 - - p = true - f(x) = x`, - ` - package test.omit_result - - f(x) = x - - p { f(1) } - `, - } - - compiler := compileModules(modules) - store := inmem.NewFromObject(loadSmallTestData()) - ctx := context.Background() - txn := storage.NewTransactionOrDie(ctx, store) - defer store.Abort(ctx, txn) - - assertTopDownWithPath(t, compiler, store, "basic call", []string{"ex", "bar", "alice"}, "", `["al", "ce"]`) - assertTopDownWithPath(t, compiler, store, "false result", []string{"ex", "falsy_undefined"}, "", ``) - assertTopDownWithPath(t, compiler, store, "false result negation", []string{"ex", "falsy_negation"}, "", `true`) - assertTopDownWithPath(t, compiler, store, "false else value", []string{"ex", "falsy_else_value"}, "", `false`) - assertTopDownWithPath(t, compiler, store, "false else undefined", []string{"ex", "falsy_else_undefined"}, "", ``) - assertTopDownWithPath(t, compiler, store, "false else negation", []string{"ex", "falsy_else_negation"}, "", `true`) - assertTopDownWithPath(t, compiler, store, "chained", []string{"ex", "chain2"}, "", `["foo", "bar"]`) - assertTopDownWithPath(t, compiler, store, "cross package", []string{"test", "cross"}, "", `["s f", [", my name "]]`) - assertTopDownWithPath(t, compiler, store, "array params", []string{"ex", "arraysrule"}, "", `[["h", "h"], ["foo"]]`) - assertTopDownWithPath(t, compiler, store, "object params", []string{"ex", "objectsrule"}, "", `[["h", "h"], "i"]`) - assertTopDownWithPath(t, compiler, store, "ref func output", []string{"ex", "refoutput"}, "", `"h"`) - assertTopDownWithPath(t, compiler, store, "always_true", []string{"ex.always_true"}, ``, `true`) - assertTopDownWithPath(t, compiler, store, "same package call", []string{"test", "samepkg"}, "", `"w do you do?"`) - assertTopDownWithPath(t, compiler, store, "void good", []string{"ex", "voidGood"}, "", `true`) - assertTopDownWithPath(t, compiler, store, "void bad", []string{"ex", "voidBad"}, "", "") - assertTopDownWithPath(t, compiler, store, "multi1", []string{"ex", "multi1"}, "", `2`) - assertTopDownWithPath(t, compiler, store, "multi2", []string{"ex", "multi2"}, "", `5`) - assertTopDownWithPath(t, compiler, store, "multi3", []string{"ex", "multi3"}, "", `20`) - assertTopDownWithPath(t, compiler, store, "multi4", []string{"ex", "multi4"}, "", `"bar"`) - assertTopDownWithPath(t, compiler, store, "multi cross package", []string{"test", "multi_cross_pkg"}, "", `["bar", 3]`) - assertTopDownWithPath(t, compiler, store, "skip-functions", []string{"test.l1"}, ``, `{"l2": {"p": true}, "l3": {}}`) - assertTopDownWithPath(t, compiler, store, "omit result", []string{"test.omit_result.p"}, ``, `true`) -} - -func TestTopDownFunctionErrors(t *testing.T) { - compiler := compileModules([]string{ - ` - package test1 - - p(x) = y { - y = x[_] - } - - r = y { - p([1, 2, 3], y) - }`, - ` - package test2 - - p(1, x) = y { - y = x - } - - p(2, x) = y { - y = x+1 - } - - r = y { - p(3, 0, y) - }`, - ` - package test3 - - p(1, x) = y { - y = x - } - - p(2, x) = y { - y = x+1 - } - - p(x, y) = z { - z = x - } - - r = y { - p(1, 0, y) - }`, - }) - - store := inmem.NewFromObject(loadSmallTestData()) - ctx := context.Background() - txn := storage.NewTransactionOrDie(ctx, store) - defer store.Abort(ctx, txn) - - assertTopDownWithPath(t, compiler, store, "function output conflict single", []string{"test1", "r"}, "", functionConflictErr(nil)) - assertTopDownWithPath(t, compiler, store, "function input no match", []string{"test2", "r"}, "", "") - assertTopDownWithPath(t, compiler, store, "function output conflict multiple", []string{"test3", "r"}, "", functionConflictErr(nil)) -} - func TestTopDownWithKeyword(t *testing.T) { tests := []struct { @@ -2081,325 +134,6 @@ func TestTopDownWithKeyword(t *testing.T) { input string exp interface{} }{ - - { - note: "with", - exp: `true`, - modules: []string{`package ex - loopback = input`}, - rules: []string{`p { data.ex.loopback with input as true; data.ex.loopback = false with input as false }`}, - }, - { - note: "with not", - exp: `true`, - modules: []string{`package ex - loopback = input`}, - rules: []string{`p = true { not data.ex.loopback with input as false; data.ex.loopback with input as true }`}, - }, - { - note: "with composite", - exp: `[3,4]`, - modules: []string{`package ex - composite[x] { input.foo[_] = x; gt(x, 2) }`}, - rules: []string{`p[x] { data.ex.composite[x] with input.foo as [1, 2, 3, 4] }`}, - }, - { - note: "with vars", - exp: `{"foo": "hello", "bar": "world"}`, - modules: []string{`package ex - vars = x { y = input.bar; z = input.foo; x = {"bar": y, "foo": z} }`}, - rules: []string{`p = x { foo = "hello"; bar = "world"; x = data.ex.vars with input.foo as foo with input.bar as bar }`}, - }, - { - note: "with conflict", - exp: &Error{Code: ConflictErr, Message: errConflictingDoc.Error()}, - modules: []string{`package ex - loopback = __local0__ { true; __local0__ = input }`}, - rules: []string{`p = true { data.ex.loopback with input.foo as "x" with input.foo.bar as "y" }`}, - }, - { - note: "with stack", - input: `{"a": {"d": 3}, "e": 4}`, - exp: `{"a": {"b": 1, "c": 2, "d": 3}, "e": 4}`, - rules: []string{ - `r = input { true }`, - `q = x { r = x with input.a.c as 2 }`, - `p = x { q = x with input.a.b as 1 }`, - }, - }, { - note: "with not stack", - input: `{"a": {"d": 3}, "e": 4}`, - exp: `{"a": {"b": 1, "c": 2, "d": 3}, "e": 4}`, - rules: []string{ - `r = input { true }`, - `q = x { not false with input as {}; r = x with input.a.c as 2 }`, - `p = x { q = x with input.a.b as 1 }`, - }, - }, - { - note: "with stack (data)", - exp: `{"a": {"b": 1, "c": 2, "d": 3}, "e": 4}`, - modules: []string{ - `package test.a - d = 3`, - `package test - e = 4`, - }, - rules: []string{ - `r = data.test { true }`, - `q = x { r = x with data.test.a.c as 2 }`, - `p = x { q = x with data.test.a.b as 1 }`, - }, - }, - { - note: "with not stack (data)", - exp: `{"a": {"b": 1, "c": 2, "d": 3}, "e": 4}`, - modules: []string{ - `package test.a - d = 3`, - `package test - e = 4`, - }, - rules: []string{ - `r = data.test { true }`, - `n1 { data.test.a.z == 7 }`, - `n { not n1 } `, - `q = x { not n with data.test.a.z as 7; r = x with data.test.a.c as 2 }`, - `p = x { q = x with data.test.a.b as 1 }`, - }, - }, - { - note: "with stack overwrites", - input: `{"a": {"b": 1, "c": 2}}`, - exp: `{"a": {"d": 3}}`, - rules: []string{ - `q = input { true }`, - `p = x { q = x with input.a as {"d": 3} }`, - }, - }, - { - note: "with stack overwrites (data)", - exp: `{"a": {"d": 3}}`, - modules: []string{ - `package test - - a = {"b": 1, "c": 2}`, - }, - rules: []string{ - `q = data.test { true }`, - `p = x { q = x with data.test.a as {"d": 3} }`, - }, - }, - { - note: "with invalidate", - exp: `[2,3,4]`, - modules: []string{`package ex - input_eq = true { input.x = 1 }`}, - rules: []string{`p[x] { data.a[_] = x; not data.ex.input_eq with input.x as x }`}, - }, - { - note: "with invalidate input stack", - exp: `["a", "b"]`, - input: `"b"`, - rules: []string{ - `p = [x, y] { x = input with input as "a"; y = input }`, - }, - }, - { - note: "with invalidate input stack iteration", - exp: `[["a", "c"], ["b", "c"]]`, - input: `"c"`, - rules: []string{ - `q[x] { input[_] = x }`, - `p[[x,y]] { - q[x] with input as ["a", "b"] - y = input - }`, - }, - }, - { - note: "with invalidate virtual cache", - exp: `["a", "b"]`, - input: "2", - rules: []string{ - `q = "a" { input = x; x = 1 }`, - `q = "b" { input = x; x = 2 }`, - `p = [x, y] { - q = x with input as 1 - q = y - }`}, - }, - { - note: "with invalidate data stack", - exp: `["a", "b"]`, - rules: []string{ - `q = "b" { true }`, - `p = [x ,y] { - q = x with q as "a" - q = y - }`, - }, - }, - { - note: "with invalidate data stack iteration", - exp: `[["a", ["c"]], ["b", ["c"]]]`, - rules: []string{ - `q["c"] { true }`, - `p[[x, y]] { - q[x] with q as {"a", "b"} - y = q - }`, - }, - }, - { - note: "with basic data", - exp: `true`, - modules: []string{`package ex - allow_basic = true { data.a = "testdata" }`}, - rules: []string{`p = true { data.ex.allow_basic = true with data.a as "testdata" }`}, - }, - { - note: "with map data overwrite", - exp: `true`, - modules: []string{`package ex - allow_merge_1 = true { data.b = {"v1": "hello", "v2": "world"} }`}, - rules: []string{`p = true { data.ex.allow_merge_1 = true with data.b.v2 as "world" }`}, - }, - { - note: "with map data new key", - exp: `true`, - modules: []string{`package ex - allow_merge_2 = true { data.b = {"v1": "hello", "v2": "world", "v3": "again"} }`}, - rules: []string{`p = true { data.ex.allow_merge_2 = true with data.b.v2 as "world" with data.b.v3 as "again" }`}, - }, - { - note: "with data conflict", - exp: mergeConflictErr(nil), - modules: []string{`package ex - allow_basic = true { data.a = "testdata" }`}, - rules: []string{`p = true { data.ex.allow_basic = true with data.a.b as 5 }`}, - }, - { - note: "with base doc exact value", - exp: `["c", "e"]`, - rules: []string{`p[x] { data.a.b[x] = 1 with data.a.b as {"c": 1, "d": 2, "e": 1} }`}, - }, - { - note: "with base doc any index", - exp: `["c", "d", "e"]`, - rules: []string{`p[x] { data.a.b[x] with data.a.b as {"c": 1, "d": 2, "e": 1} }`}, - }, - { - note: "undefined_1", - exp: "", - rules: []string{`p = true { data.a.b.c with data.a.b as 1 }`}, - }, - { - note: "undefined_2", - exp: "", - rules: []string{`p = true { data.l.a with data.l as 1 }`}, - }, - { - note: "with virtual doc exact value", - exp: `[["c", "e"]]`, - modules: []string{`package ex - virtual[x] { data.a.b[x] = 1 }`}, - rules: []string{`p[x] { data.ex.virtual = x with data.a.b as {"c": 1, "d": 2, "e": 1} }`}, - }, - { - note: "with virtual doc any index", - exp: `["c", "e"]`, - modules: []string{`package ex - virtual[x] { data.a.b[x] = 1 }`}, - rules: []string{`p[x] { data.ex.virtual[x] with data.a.b as {"c": 1, "d": 2, "e": 1} }`}, - }, - { - note: "with virtual doc specific index", - exp: `"c"`, - modules: []string{`package ex - virtual[x] { data.a.b[x] = 1 }`}, - rules: []string{`p = y { y = data.ex.virtual.c with data.a.b as {"c": 1, "d": 2, "e": 1} }`}, - }, - { - note: "with virtual doc not specific index", - exp: `true`, - modules: []string{`package ex - virtual[x] { data.a.b[x] = 1 }`}, - rules: []string{`p = true { not data.ex.virtual.d with data.a.b as {"c": 1, "d": 2, "e": 1} }`}, - }, - { - note: "with mock var", - exp: `{"c": 1, "d": 2}`, - modules: []string{`package ex - mock_var = {"a": 0, "b": 0} { true }`}, - rules: []string{`p = y { y = data.ex.mock_var with data.ex.mock_var as {"c": 1, "d": 2} }`}, - }, - { - note: "with mock rule", - exp: `true`, - modules: []string{`package ex - mock_rule = false { 1 = 2 }`}, - rules: []string{`p = true { data.ex.mock_rule with data.ex.mock_rule as true }`}, - }, - { - note: "with rule chain", - exp: `true`, - modules: []string{`package ex - allow1 = true { data.label.b.c = [1, 2, 3] } - allow2 = true { data.label.b.c[x] = 2 } - allow3 = true { data.label.b[x] = 1 } - allow4 = true { data.label.b.c.d[x] = 1 } - allow = true { data.ex.allow1; data.ex.allow2; not data.ex.allow3; not data.ex.allow4 }`}, - rules: []string{`p = true { data.ex.allow with data.label.b.c as [1, 2, 3] }`}, - }, - { - note: "with mock iteration on sets", - exp: `[3,4]`, - rules: []string{ - `q[1] { true }`, - `q[2] { true }`, - `p[x] { q[x] with q as {3,4} }`, - }, - }, - { - note: "with mock iteration on objects", - exp: `{"a": 3, "c": 4}`, - rules: []string{ - `q["a"] = 1 { true }`, - `q["b"] = 2 { true }`, - `p[x] = y { q[x] = y with q as {"a": 3, "c": 4} }`, - }, - }, - { - note: "with mock iteration on arrays", - exp: `[3, 4]`, - rules: []string{ - `q[1] { true }`, - `q[2] { true }`, - `p[x] { q[_] = x with q as [3,4] }`, - }, - }, - { - note: "bug 1083", - exp: ``, - modules: []string{`package ex - input_eq = true { input.x = 1 }`}, - rules: []string{`p = true { data.ex.input_eq with data.foo as 1 }`}, - }, - { - note: "bug 1100", - exp: `true`, - modules: []string{`package ex - data_eq = true { data.a = x }`}, - rules: []string{`p = true { data.ex.data_eq with input as {} }`}, - }, - { - note: "set lookup", - exp: `true`, - modules: []string{`package ex - setl[x] { data.foo[x] }`}, - rules: []string{`p = true { data.ex.setl[1] with data.foo as {1} }`}, - }, { // NOTE(tsandall): This case assumes that partial sets are not memoized. // If we change that, it'll be harder to test that the comprehension @@ -2426,243 +160,6 @@ func TestTopDownWithKeyword(t *testing.T) { } } -func TestTopDownElseKeyword(t *testing.T) { - tests := []struct { - note string - path string - expected interface{} - }{ - {"no-op", "ex.no_op", "true"}, - {"trivial", "ex.bool", "true"}, - {"trivial-non-bool", "ex.non_bool", "[100]"}, - {"trivial-3", "ex.triple", `"hello"`}, - {"var-head", "ex.vars", `["hello", "goodbye"]`}, - {"ref-head", "ex.refs", `["hello", "goodbye"]`}, - {"first-match", "ex.multiple_defined", `true`}, - {"default-1", "ex.default_1", "2"}, - {"default-2", "ex.default_2", "2"}, - {"multiple-roots", "ex.multiple_roots", `2`}, - {"indexed", "ex.indexed", "2"}, - {"conflict-1", "ex.conflict_1", completeDocConflictErr(nil)}, - {"conflict-2", "ex.conflict_2", completeDocConflictErr(nil)}, - {"functions", "ex.fn_result", `["large", "small", "medium"]`}, - } - - for _, tc := range tests { - - compiler := compileModules([]string{ - `package ex - - no_op { true } else = false { true } - bool { false } else { true } - non_bool = null { false } else = [100] { true } - triple { false } else { false } else = "hello" { true } - vars { false } else = ["hello", x] { data.b.v2 = x } - refs { false } else = ["hello", data.b.v2] { true } - multiple_defined = false { false } else = true { true } else = false { true } - - default default_1 = 1 - default_1 { false } default_1 = 2 { true } - - default default_2 = 2 - default_2 { false } default_2 = 1 { false } - - multiple_roots { - false - } else = 1 { - false - } else = 2 { - true - } else = 3 { - true - } - - multiple_roots = 2 - - multiple_roots = 3 { - false - } else = 2 { - true - } - - indexed { - data.a[0] = 0 - } else = 2 { - data.a[0] = 1 - } else = 3 { - data.a[0] = 1 - } - - indexed { - data.a[0] = 1 - data.a[2] = 2 - } else { - false - } else = 2 { - data.a[0] = x - x = 1 - data.a[2] = 3 - } - - conflict_1 { false } else { true } - conflict_1 = false { true } - - conflict_2 { false } else = false { true } - conflict_2 { false } else = true { true } - - fn_result = [x,y,z] { fn(101, true, x); fn(100, true, y); fn(100, false, z) } - - fn(x, y) = "large" { - x > 100 - } else = "small" { - y = true - } else = "medium" { - true - } - `, - }) - - store := inmem.NewFromObject(loadSmallTestData()) - - assertTopDownWithPath(t, compiler, store, tc.note, strings.Split(tc.path, "."), "", tc.expected) - } -} - -// Test that dynamic dispatch is not broken by the recursion check. -func TestTopdownDynamicDispatch(t *testing.T) { - compiler := compileModules([]string{` - package animals - - dog = "woof" - cat = "meow" - `, ` - package dynamic - - sound = data.animals[animal] - animal = "dog" { - 2 > 1 - } - `}) - - data := map[string]interface{}{} - store := inmem.NewFromObject(data) - - assertTopDownWithPath(t, compiler, store, "dynamic dispatch", []string{}, `{}`, `{ - "animals": { - "cat": "meow", - "dog": "woof" - }, - "dynamic": { - "animal": "dog", - "sound": "woof" - } - }`) -} - -func TestTopDownSystemDocument(t *testing.T) { - - compiler := compileModules([]string{` - package system.somepolicy - - foo = "hello" - `, ` - package topdown.system - - bar = "goodbye" - `}) - - data := map[string]interface{}{ - "system": map[string]interface{}{ - "somedata": []interface{}{"a", "b", "c"}, - }, - "com": map[string]interface{}{ - "system": "deadbeef", - }, - } - - store := inmem.NewFromObject(data) - - assertTopDownWithPath(t, compiler, store, "root query", []string{}, `{}`, `{ - "topdown": { - "system": { - "bar": "goodbye" - } - }, - "com": { - "system": "deadbeef" - } - }`) - -} - -func TestExample(t *testing.T) { - - bd := ` - { - "servers": [ - {"id": "s1", "name": "app", "protocols": ["https", "ssh"], "ports": ["p1", "p2", "p3"]}, - {"id": "s2", "name": "db", "protocols": ["mysql"], "ports": ["p3"]}, - {"id": "s3", "name": "cache", "protocols": ["memcache", "http"], "ports": ["p3"]}, - {"id": "s4", "name": "dev", "protocols": ["http"], "ports": ["p1", "p2"]} - ], - "networks": [ - {"id": "n1", "public": false}, - {"id": "n2", "public": false}, - {"id": "n3", "public": true} - ], - "ports": [ - {"id": "p1", "networks": ["n1"]}, - {"id": "p2", "networks": ["n3"]}, - {"id": "p3", "networks": ["n2"]} - ] - } - ` - - vd := `package opa.example - -import data.servers -import data.networks -import data.ports - -public_servers[server] { server = servers[_]; server.ports[_] = ports[i].id; ports[i].networks[_] = networks[j].id; networks[j].public = true } -violations[server] { server = servers[_]; server.protocols[_] = "http"; public_servers[server] }` - - var doc map[string]interface{} - - if err := util.UnmarshalJSON([]byte(bd), &doc); err != nil { - panic(err) - } - - compiler := compileModules([]string{vd}) - - store := inmem.NewFromObject(doc) - - assertTopDownWithPath(t, compiler, store, "public servers", []string{"opa", "example", "public_servers"}, "{}", ` - [ - {"id": "s1", "name": "app", "protocols": ["https", "ssh"], "ports": ["p1", "p2", "p3"]}, - {"id": "s4", "name": "dev", "protocols": ["http"], "ports": ["p1", "p2"]} - ] - `) - - assertTopDownWithPath(t, compiler, store, "violations", []string{"opa", "example", "violations"}, "{}", ` - [ - {"id": "s4", "name": "dev", "protocols": ["http"], "ports": ["p1", "p2"]} - ] - `) - - assertTopDownWithPath(t, compiler, store, "both", []string{"opa", "example"}, "{}", ` - { - "public_servers": [ - {"id": "s1", "name": "app", "protocols": ["https", "ssh"], "ports": ["p1", "p2", "p3"]}, - {"id": "s4", "name": "dev", "protocols": ["http"], "ports": ["p1", "p2"]} - ], - "violations": [ - {"id": "s4", "name": "dev", "protocols": ["http"], "ports": ["p1", "p2"]} - ] - } - `) -} - func TestTopDownUnsupportedBuiltin(t *testing.T) { ast.RegisterBuiltin(&ast.Builtin{ @@ -2783,25 +280,6 @@ p[x] { data.a[i] = x }`, } } -func TestTopDownCompositeBaseDereference(t *testing.T) { - tests := []struct { - note string - rule string - expected interface{} - }{ - // Expect that each of these will evaluate without any errors raised - {"array", `p { not data.a[[0]] }`, "true"}, - {"object", `p { not data.a[{"b": "c"}] }`, "true"}, - {"set", `p { not data.a[["b"]] }`, "true"}, - } - - data := loadSmallTestData() - - for _, tc := range tests { - runTopDownTestCase(t, data, tc.note, []string{tc.rule}, tc.expected) - } -} - func compileModules(input []string) *ast.Compiler { mods := map[string]*ast.Module{}