Files
releases/plugins/logs/ptr_test.go
T
Torin Sandall c0cc24676d logs: Update decision logger to support masking
These changes enhance the in-built decision logger to support masking
of input and result fields for cases where sensitive information is
passed to OPA (or generated by the policy.)

Also, fix rego package to avoid panic-ing on programmatically created
queriest that lack Location information.

Fixes #779

Signed-off-by: Torin Sandall <torinsandall@gmail.com>
2019-06-04 16:14:46 -07:00

238 lines
5.2 KiB
Go

package logs
import (
"encoding/json"
"fmt"
"reflect"
"strings"
"testing"
"github.com/open-policy-agent/opa/util"
)
func TestParsePtr(t *testing.T) {
tests := []struct {
note string
input string
expErr error
expPtr ptr
}{
{
note: "empty",
input: "",
expErr: fmt.Errorf("mask must be non-empty"),
},
{
note: "missing slash",
input: "foo/bar",
expErr: fmt.Errorf("mask must be slash-prefixed"),
},
{
note: "no prefix",
input: "/",
expErr: fmt.Errorf("mask prefix not allowed"),
},
{
note: "bad prefix key",
input: "/labels/foo",
expErr: fmt.Errorf("mask prefix not allowed"),
},
{
note: "standard",
input: "/input/a/b/c",
expPtr: ptr{"input", "a", "b", "c"},
},
{
note: "escaping",
input: "/input/a/%2F%2F/b",
expPtr: ptr{"input", "a", "//", "b"},
},
{
note: "bad escape",
input: "/input/a/%F/b",
expErr: fmt.Errorf("invalid URL escape"),
},
{
note: "empty component",
input: "/input//foo",
expPtr: ptr{"input", "", "foo"},
},
{
note: "result",
input: "/result/a",
expPtr: ptr{"result", "a"},
},
{
note: "root",
input: "/input",
expPtr: ptr{"input"},
},
}
for _, tc := range tests {
t.Run(tc.note, func(t *testing.T) {
result, err := parsePtr(tc.input)
if tc.expErr != nil {
if err == nil {
t.Fatalf("Expected error but got: %v", result)
} else if !strings.Contains(err.Error(), tc.expErr.Error()) {
t.Fatalf("Expected error: %v, but got error: %v", tc.expErr, err)
}
} else {
if err != nil {
t.Fatal("Unexpected error:", err)
}
if !reflect.DeepEqual(result, tc.expPtr) {
t.Fatalf("Expected %v but got %v", tc.expPtr, result)
}
}
})
}
}
func TestPtrString(t *testing.T) {
result := ptr{"input", "foo/bar", "baz", ""}.String()
exp := "/input/foo%2Fbar/baz/"
if result != exp {
t.Fatalf("Expected %q but got %q", exp, result)
}
}
func TestPtrErase(t *testing.T) {
tests := []struct {
note string
ptr string
event string
exp string
}{
{
note: "erase input",
ptr: "/input",
event: `{"input": {"a": 1}}`,
exp: `{"erased": ["/input"]}`,
},
{
note: "erase result",
ptr: "/result",
event: `{"result": "foo"}`,
exp: `{"erased": ["/result"]}`,
},
{
note: "erase: undefined input",
ptr: "/input/foo",
event: `{}`,
exp: `{}`,
},
{
note: "erase: undefined result",
ptr: "/result/foo",
event: `{}`,
exp: `{}`,
},
{
note: "erase: undefined node",
ptr: "/input/foo",
event: `{"input": {"bar": 1}}`,
exp: `{"input": {"bar": 1}}`,
},
{
note: "erase: undefined node-2",
ptr: "/input/foo/bar",
event: `{"input": {"foo": 1}}`,
exp: `{"input": {"foo": 1}}`,
},
{
note: "erase: undefined object: missing key",
ptr: "/input/foo/bar/baz",
event: `{"input": {"foo": {}}}`,
exp: `{"input": {"foo": {}}}`,
},
{
note: "erase: undefined scalar",
ptr: "/input/foo/bar/baz",
event: `{"input": {"foo": 1}}`,
exp: `{"input": {"foo": 1}}`,
},
{
note: "erase: undefined array: non-int index",
ptr: "/input/foo/bar/baz", // bar is invalid
event: `{"input": {"foo": [{"baz": 1}]}}`,
exp: `{"input": {"foo": [{"baz": 1}]}}`,
},
{
note: "erase: undefined array: negative index",
ptr: "/input/foo/-1/baz",
event: `{"input": {"foo": [{"baz": 1}]}}`,
exp: `{"input": {"foo": [{"baz": 1}]}}`,
},
{
note: "erase: undefined array: index out of range",
ptr: "/input/foo/1/baz",
event: `{"input": {"foo": [{"baz": 1}]}}`,
exp: `{"input": {"foo": [{"baz": 1}]}}`,
},
{
note: "erase: undefined array: remove element",
ptr: "/input/foo/0",
event: `{"input": {"foo": [1]}}`,
exp: `{"input": {"foo": [1]}}`,
},
{
note: "erase: object key",
ptr: "/input/foo",
event: `{"input": {"bar": 1, "foo": [{"baz": 1}]}}`,
exp: `{"input": {"bar": 1}, "erased": ["/input/foo"]}`,
},
{
note: "erase: object key (multiple)",
ptr: "/input/bar",
event: `{"input": {"bar": 1}, "erased": ["/input/foo"]}`,
exp: `{"input": {}, "erased": ["/input/foo", "/input/bar"]}`,
},
{
note: "erase: object key (nested array)",
ptr: "/input/foo/0/bar",
event: `{"input": {"foo": [{"bar": 1, "baz": 2}]}}`,
exp: `{"input": {"foo": [{"baz": 2}]}, "erased": ["/input/foo/0/bar"]}`,
},
{
note: "erase: result key",
ptr: "/result/foo/bar/baz",
event: `{"result": {"foo": {"bar": {"baz": 1}}}}`,
exp: `{"result": {"foo": {"bar": {}}}, "erased": ["/result/foo/bar/baz"]}`,
},
}
for _, tc := range tests {
t.Run(tc.note, func(t *testing.T) {
ptr, err := parsePtr(tc.ptr)
if err != nil {
panic(err)
}
var exp EventV1
if err := util.UnmarshalJSON([]byte(tc.exp), &exp); err != nil {
panic(err)
}
var event EventV1
if err := util.UnmarshalJSON([]byte(tc.event), &event); err != nil {
panic(err)
}
ptr.Erase(&event)
if !reflect.DeepEqual(event, exp) {
bs1, _ := json.MarshalIndent(exp, "", " ")
bs2, _ := json.MarshalIndent(event, "", " ")
t.Fatalf("Expected: %s\nGot: %s", bs1, bs2)
}
})
}
}