From 06c514da1aa61c605d274f58e1d2034b625aa6b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuzhan=20Durgun?= Date: Thu, 23 Mar 2023 19:06:52 +0300 Subject: [PATCH] enhancement!: Group test results by test name (#1498) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhancement!: Group test results by test name Signed-off-by: Oğuzhan Durgun * Address reviews Signed-off-by: Oğuzhan Durgun * Address reviews Signed-off-by: Oğuzhan Durgun * Apply suggestions from code review Signed-off-by: Oğuzhan Durgun --------- Signed-off-by: Oğuzhan Durgun --- .../cerbos/policy/v1/hashpb_helpers.pb.go | 27 + api/genpb/cerbos/policy/v1/policy.pb.go | 343 ++++++++----- .../cerbos/policy/v1/policy.pb.validate.go | 172 +++++++ .../cerbos/policy/v1/policy_hashpb.pb.go | 8 + .../cerbos/policy/v1/policy_vtproto.pb.go | 241 +++++++++ .../cerbos/private/v1/hashpb_helpers.pb.go | 27 + .../cerbos/response/v1/hashpb_helpers.pb.go | 27 + api/public/cerbos/policy/v1/policy.proto | 8 +- .../compile/internal/verification/display.go | 37 +- internal/printer/colored/colored.go | 1 + .../server/playground/test/pgt_case_00.yaml | 478 +++++++++--------- .../verify/cases/case_001.yaml.golden | 114 +++-- .../verify/cases/case_002.yaml.golden | 67 +-- .../verify/cases/case_003.yaml.golden | 93 ++-- .../test/testdata/verify/cases/case_008.yaml | 2 +- .../verify/cases/case_008.yaml.golden | 129 +++-- .../test/testdata/verify/cases/case_009.yaml | 1 + .../verify/cases/case_009.yaml.golden | 72 +++ .../testdata/verify/cases/case_009.yaml.input | 70 +++ .../test/testdata/verify/cases/case_010.yaml | 1 + .../verify/cases/case_010.yaml.golden | 15 + .../testdata/verify/cases/case_010.yaml.input | 74 +++ internal/verify/test_fixture.go | 57 ++- internal/verify/verify_test.go | 5 +- .../cerbos/policy/v1/TestResults.schema.json | 21 + .../policy/v1/TestResults/Suite.schema.json | 21 + .../v1/TestResults/TestCase.schema.json | 229 +++++++++ .../v1/PlaygroundTestResponse.schema.json | 21 + .../TestResults.schema.json | 21 + .../openapiv2/cerbos/svc/v1/svc.swagger.json | 22 + 30 files changed, 1851 insertions(+), 553 deletions(-) create mode 100644 internal/test/testdata/verify/cases/case_009.yaml create mode 100644 internal/test/testdata/verify/cases/case_009.yaml.golden create mode 100644 internal/test/testdata/verify/cases/case_009.yaml.input create mode 100644 internal/test/testdata/verify/cases/case_010.yaml create mode 100644 internal/test/testdata/verify/cases/case_010.yaml.golden create mode 100644 internal/test/testdata/verify/cases/case_010.yaml.input create mode 100644 schema/jsonschema/cerbos/policy/v1/TestResults/TestCase.schema.json diff --git a/api/genpb/cerbos/policy/v1/hashpb_helpers.pb.go b/api/genpb/cerbos/policy/v1/hashpb_helpers.pb.go index 3fae27738..39eb98f1b 100644 --- a/api/genpb/cerbos/policy/v1/hashpb_helpers.pb.go +++ b/api/genpb/cerbos/policy/v1/hashpb_helpers.pb.go @@ -750,6 +750,16 @@ func cerbos_policy_v1_TestResults_Suite_hashpb_sum(m *TestResults_Suite, hasher _, _ = hasher.Write(protowire.AppendString(nil, m.Error)) } + if _, ok := ignore["cerbos.policy.v1.TestResults.Suite.test_cases"]; !ok { + if len(m.TestCases) > 0 { + for _, v := range m.TestCases { + if v != nil { + cerbos_policy_v1_TestResults_TestCase_hashpb_sum(v, hasher, ignore) + } + + } + } + } } func cerbos_policy_v1_TestResults_Summary_hashpb_sum(m *TestResults_Summary, hasher hash.Hash, ignore map[string]struct{}) { @@ -784,6 +794,23 @@ func cerbos_policy_v1_TestResults_Tally_hashpb_sum(m *TestResults_Tally, hasher } } +func cerbos_policy_v1_TestResults_TestCase_hashpb_sum(m *TestResults_TestCase, hasher hash.Hash, ignore map[string]struct{}) { + if _, ok := ignore["cerbos.policy.v1.TestResults.TestCase.name"]; !ok { + _, _ = hasher.Write(protowire.AppendString(nil, m.Name)) + + } + if _, ok := ignore["cerbos.policy.v1.TestResults.TestCase.principals"]; !ok { + if len(m.Principals) > 0 { + for _, v := range m.Principals { + if v != nil { + cerbos_policy_v1_TestResults_Principal_hashpb_sum(v, hasher, ignore) + } + + } + } + } +} + func cerbos_policy_v1_TestResults_hashpb_sum(m *TestResults, hasher hash.Hash, ignore map[string]struct{}) { if _, ok := ignore["cerbos.policy.v1.TestResults.suites"]; !ok { if len(m.Suites) > 0 { diff --git a/api/genpb/cerbos/policy/v1/policy.pb.go b/api/genpb/cerbos/policy/v1/policy.pb.go index 0595635ec..0aa82cf31 100644 --- a/api/genpb/cerbos/policy/v1/policy.pb.go +++ b/api/genpb/cerbos/policy/v1/policy.pb.go @@ -2084,11 +2084,13 @@ type TestResults_Suite struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - File string `protobuf:"bytes,1,opt,name=file,proto3" json:"file,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + File string `protobuf:"bytes,1,opt,name=file,proto3" json:"file,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // Deprecated: Marked as deprecated in cerbos/policy/v1/policy.proto. Principals []*TestResults_Principal `protobuf:"bytes,3,rep,name=principals,proto3" json:"principals,omitempty"` Summary *TestResults_Summary `protobuf:"bytes,4,opt,name=summary,proto3" json:"summary,omitempty"` Error string `protobuf:"bytes,5,opt,name=error,proto3" json:"error,omitempty"` + TestCases []*TestResults_TestCase `protobuf:"bytes,6,rep,name=test_cases,json=testCases,proto3" json:"test_cases,omitempty"` } func (x *TestResults_Suite) Reset() { @@ -2137,6 +2139,7 @@ func (x *TestResults_Suite) GetName() string { return "" } +// Deprecated: Marked as deprecated in cerbos/policy/v1/policy.proto. func (x *TestResults_Suite) GetPrincipals() []*TestResults_Principal { if x != nil { return x.Principals @@ -2158,6 +2161,68 @@ func (x *TestResults_Suite) GetError() string { return "" } +func (x *TestResults_Suite) GetTestCases() []*TestResults_TestCase { + if x != nil { + return x.TestCases + } + return nil +} + +type TestResults_TestCase struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Principals []*TestResults_Principal `protobuf:"bytes,2,rep,name=principals,proto3" json:"principals,omitempty"` +} + +func (x *TestResults_TestCase) Reset() { + *x = TestResults_TestCase{} + if protoimpl.UnsafeEnabled { + mi := &file_cerbos_policy_v1_policy_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TestResults_TestCase) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TestResults_TestCase) ProtoMessage() {} + +func (x *TestResults_TestCase) ProtoReflect() protoreflect.Message { + mi := &file_cerbos_policy_v1_policy_proto_msgTypes[40] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TestResults_TestCase.ProtoReflect.Descriptor instead. +func (*TestResults_TestCase) Descriptor() ([]byte, []int) { + return file_cerbos_policy_v1_policy_proto_rawDescGZIP(), []int{16, 3} +} + +func (x *TestResults_TestCase) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *TestResults_TestCase) GetPrincipals() []*TestResults_Principal { + if x != nil { + return x.Principals + } + return nil +} + type TestResults_Principal struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2170,7 +2235,7 @@ type TestResults_Principal struct { func (x *TestResults_Principal) Reset() { *x = TestResults_Principal{} if protoimpl.UnsafeEnabled { - mi := &file_cerbos_policy_v1_policy_proto_msgTypes[40] + mi := &file_cerbos_policy_v1_policy_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2183,7 +2248,7 @@ func (x *TestResults_Principal) String() string { func (*TestResults_Principal) ProtoMessage() {} func (x *TestResults_Principal) ProtoReflect() protoreflect.Message { - mi := &file_cerbos_policy_v1_policy_proto_msgTypes[40] + mi := &file_cerbos_policy_v1_policy_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2196,7 +2261,7 @@ func (x *TestResults_Principal) ProtoReflect() protoreflect.Message { // Deprecated: Use TestResults_Principal.ProtoReflect.Descriptor instead. func (*TestResults_Principal) Descriptor() ([]byte, []int) { - return file_cerbos_policy_v1_policy_proto_rawDescGZIP(), []int{16, 3} + return file_cerbos_policy_v1_policy_proto_rawDescGZIP(), []int{16, 4} } func (x *TestResults_Principal) GetName() string { @@ -2225,7 +2290,7 @@ type TestResults_Resource struct { func (x *TestResults_Resource) Reset() { *x = TestResults_Resource{} if protoimpl.UnsafeEnabled { - mi := &file_cerbos_policy_v1_policy_proto_msgTypes[41] + mi := &file_cerbos_policy_v1_policy_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2238,7 +2303,7 @@ func (x *TestResults_Resource) String() string { func (*TestResults_Resource) ProtoMessage() {} func (x *TestResults_Resource) ProtoReflect() protoreflect.Message { - mi := &file_cerbos_policy_v1_policy_proto_msgTypes[41] + mi := &file_cerbos_policy_v1_policy_proto_msgTypes[42] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2251,7 +2316,7 @@ func (x *TestResults_Resource) ProtoReflect() protoreflect.Message { // Deprecated: Use TestResults_Resource.ProtoReflect.Descriptor instead. func (*TestResults_Resource) Descriptor() ([]byte, []int) { - return file_cerbos_policy_v1_policy_proto_rawDescGZIP(), []int{16, 4} + return file_cerbos_policy_v1_policy_proto_rawDescGZIP(), []int{16, 5} } func (x *TestResults_Resource) GetName() string { @@ -2280,7 +2345,7 @@ type TestResults_Action struct { func (x *TestResults_Action) Reset() { *x = TestResults_Action{} if protoimpl.UnsafeEnabled { - mi := &file_cerbos_policy_v1_policy_proto_msgTypes[42] + mi := &file_cerbos_policy_v1_policy_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2293,7 +2358,7 @@ func (x *TestResults_Action) String() string { func (*TestResults_Action) ProtoMessage() {} func (x *TestResults_Action) ProtoReflect() protoreflect.Message { - mi := &file_cerbos_policy_v1_policy_proto_msgTypes[42] + mi := &file_cerbos_policy_v1_policy_proto_msgTypes[43] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2306,7 +2371,7 @@ func (x *TestResults_Action) ProtoReflect() protoreflect.Message { // Deprecated: Use TestResults_Action.ProtoReflect.Descriptor instead. func (*TestResults_Action) Descriptor() ([]byte, []int) { - return file_cerbos_policy_v1_policy_proto_rawDescGZIP(), []int{16, 5} + return file_cerbos_policy_v1_policy_proto_rawDescGZIP(), []int{16, 6} } func (x *TestResults_Action) GetName() string { @@ -2340,7 +2405,7 @@ type TestResults_Details struct { func (x *TestResults_Details) Reset() { *x = TestResults_Details{} if protoimpl.UnsafeEnabled { - mi := &file_cerbos_policy_v1_policy_proto_msgTypes[43] + mi := &file_cerbos_policy_v1_policy_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2353,7 +2418,7 @@ func (x *TestResults_Details) String() string { func (*TestResults_Details) ProtoMessage() {} func (x *TestResults_Details) ProtoReflect() protoreflect.Message { - mi := &file_cerbos_policy_v1_policy_proto_msgTypes[43] + mi := &file_cerbos_policy_v1_policy_proto_msgTypes[44] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2366,7 +2431,7 @@ func (x *TestResults_Details) ProtoReflect() protoreflect.Message { // Deprecated: Use TestResults_Details.ProtoReflect.Descriptor instead. func (*TestResults_Details) Descriptor() ([]byte, []int) { - return file_cerbos_policy_v1_policy_proto_rawDescGZIP(), []int{16, 6} + return file_cerbos_policy_v1_policy_proto_rawDescGZIP(), []int{16, 7} } func (x *TestResults_Details) GetResult() TestResults_Result { @@ -2432,7 +2497,7 @@ type TestResults_Failure struct { func (x *TestResults_Failure) Reset() { *x = TestResults_Failure{} if protoimpl.UnsafeEnabled { - mi := &file_cerbos_policy_v1_policy_proto_msgTypes[44] + mi := &file_cerbos_policy_v1_policy_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2445,7 +2510,7 @@ func (x *TestResults_Failure) String() string { func (*TestResults_Failure) ProtoMessage() {} func (x *TestResults_Failure) ProtoReflect() protoreflect.Message { - mi := &file_cerbos_policy_v1_policy_proto_msgTypes[44] + mi := &file_cerbos_policy_v1_policy_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2458,7 +2523,7 @@ func (x *TestResults_Failure) ProtoReflect() protoreflect.Message { // Deprecated: Use TestResults_Failure.ProtoReflect.Descriptor instead. func (*TestResults_Failure) Descriptor() ([]byte, []int) { - return file_cerbos_policy_v1_policy_proto_rawDescGZIP(), []int{16, 7} + return file_cerbos_policy_v1_policy_proto_rawDescGZIP(), []int{16, 8} } func (x *TestResults_Failure) GetExpected() v1.Effect { @@ -2876,7 +2941,7 @@ var file_cerbos_policy_v1_policy_proto_rawDesc = []byte{ 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x66, 0x66, 0x65, 0x63, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x22, 0xf3, 0x0a, 0x0a, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, + 0x02, 0x38, 0x01, 0x22, 0xa7, 0x0c, 0x0a, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x3b, 0x0a, 0x06, 0x73, 0x75, 0x69, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, @@ -2903,75 +2968,86 @@ var file_cerbos_policy_v1_policy_proto_rawDesc = []byte{ 0x23, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x54, 0x61, 0x6c, 0x6c, 0x79, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x75, 0x6e, - 0x74, 0x73, 0x1a, 0xcf, 0x01, 0x0a, 0x05, 0x53, 0x75, 0x69, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, + 0x74, 0x73, 0x1a, 0x9a, 0x02, 0x0a, 0x05, 0x53, 0x75, 0x69, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x47, 0x0a, 0x0a, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x4b, 0x0a, 0x0a, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, - 0x6c, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x73, 0x12, 0x3f, 0x0a, - 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, - 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x76, - 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x53, 0x75, - 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x14, - 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, - 0x72, 0x72, 0x6f, 0x72, 0x1a, 0x65, 0x0a, 0x09, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, - 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x44, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, - 0x73, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, - 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x1a, 0x5e, 0x0a, 0x08, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, + 0x6c, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, + 0x73, 0x12, 0x3f, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x70, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x73, 0x2e, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, + 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x45, 0x0a, 0x0a, 0x74, 0x65, 0x73, 0x74, + 0x5f, 0x63, 0x61, 0x73, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, + 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x76, 0x31, 0x2e, + 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x54, 0x65, 0x73, 0x74, + 0x43, 0x61, 0x73, 0x65, 0x52, 0x09, 0x74, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x73, 0x1a, + 0x67, 0x0a, 0x08, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x47, 0x0a, 0x0a, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x70, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x73, 0x2e, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x52, 0x0a, 0x70, 0x72, + 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x73, 0x1a, 0x65, 0x0a, 0x09, 0x50, 0x72, 0x69, 0x6e, + 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x44, 0x0a, 0x09, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x76, 0x31, 0x2e, - 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x41, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x5d, 0x0a, 0x06, 0x41, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3f, 0x0a, 0x07, 0x64, 0x65, 0x74, - 0x61, 0x69, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x65, 0x72, + 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x1a, + 0x5e, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x3e, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x24, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, + 0x5d, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3f, 0x0a, + 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, + 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x76, + 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x44, 0x65, + 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x1a, 0xe9, + 0x01, 0x0a, 0x07, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x3c, 0x0a, 0x06, 0x72, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, - 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, - 0x73, 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x1a, 0xe9, 0x01, 0x0a, 0x07, 0x44, - 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x3c, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x12, 0x41, 0x0a, 0x07, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x70, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x48, 0x00, 0x52, 0x07, - 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x16, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, - 0x3a, 0x0a, 0x0c, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x65, - 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x52, 0x0b, - 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x54, 0x72, 0x61, 0x63, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x6f, - 0x75, 0x74, 0x63, 0x6f, 0x6d, 0x65, 0x1a, 0x71, 0x0a, 0x07, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, - 0x65, 0x12, 0x34, 0x0a, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x65, 0x66, 0x66, - 0x65, 0x63, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x66, 0x66, 0x65, 0x63, 0x74, 0x52, 0x08, 0x65, - 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x30, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x75, 0x61, - 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, + 0x73, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x41, 0x0a, 0x07, 0x66, 0x61, 0x69, 0x6c, + 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x65, 0x72, 0x62, + 0x6f, 0x73, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, + 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, + 0x48, 0x00, 0x52, 0x07, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x16, 0x0a, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x12, 0x3a, 0x0a, 0x0c, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x5f, 0x74, 0x72, + 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x65, 0x72, 0x62, + 0x6f, 0x73, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, + 0x63, 0x65, 0x52, 0x0b, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x54, 0x72, 0x61, 0x63, 0x65, 0x42, + 0x09, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x63, 0x6f, 0x6d, 0x65, 0x1a, 0x71, 0x0a, 0x07, 0x46, 0x61, + 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x34, 0x0a, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x66, 0x66, 0x65, 0x63, - 0x74, 0x52, 0x06, 0x61, 0x63, 0x74, 0x75, 0x61, 0x6c, 0x22, 0x6e, 0x0a, 0x06, 0x52, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, 0x53, 0x55, 0x4c, 0x54, 0x5f, 0x55, 0x4e, - 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x52, - 0x45, 0x53, 0x55, 0x4c, 0x54, 0x5f, 0x53, 0x4b, 0x49, 0x50, 0x50, 0x45, 0x44, 0x10, 0x01, 0x12, - 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x53, 0x55, 0x4c, 0x54, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x45, 0x44, - 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x53, 0x55, 0x4c, 0x54, 0x5f, 0x46, 0x41, 0x49, - 0x4c, 0x45, 0x44, 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x53, 0x55, 0x4c, 0x54, 0x5f, - 0x45, 0x52, 0x52, 0x4f, 0x52, 0x45, 0x44, 0x10, 0x04, 0x42, 0x6f, 0x0a, 0x18, 0x64, 0x65, 0x76, - 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x70, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2f, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x62, 0x2f, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, - 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2f, 0x76, 0x31, 0x3b, 0x70, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x76, 0x31, 0xaa, 0x02, 0x14, 0x43, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x41, 0x70, 0x69, - 0x2e, 0x56, 0x31, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x74, 0x52, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, 0x30, 0x0a, 0x06, 0x61, + 0x63, 0x74, 0x75, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x63, 0x65, + 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x45, + 0x66, 0x66, 0x65, 0x63, 0x74, 0x52, 0x06, 0x61, 0x63, 0x74, 0x75, 0x61, 0x6c, 0x22, 0x6e, 0x0a, + 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, 0x53, 0x55, 0x4c, + 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x53, 0x55, 0x4c, 0x54, 0x5f, 0x53, 0x4b, 0x49, 0x50, 0x50, 0x45, + 0x44, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x53, 0x55, 0x4c, 0x54, 0x5f, 0x50, 0x41, + 0x53, 0x53, 0x45, 0x44, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x53, 0x55, 0x4c, 0x54, + 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x53, + 0x55, 0x4c, 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x45, 0x44, 0x10, 0x04, 0x42, 0x6f, 0x0a, + 0x18, 0x64, 0x65, 0x76, 0x2e, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x2f, 0x63, 0x65, 0x72, + 0x62, 0x6f, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x62, 0x2f, 0x63, 0x65, + 0x72, 0x62, 0x6f, 0x73, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2f, 0x76, 0x31, 0x3b, 0x70, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x76, 0x31, 0xaa, 0x02, 0x14, 0x43, 0x65, 0x72, 0x62, 0x6f, 0x73, + 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x56, 0x31, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2987,7 +3063,7 @@ func file_cerbos_policy_v1_policy_proto_rawDescGZIP() []byte { } var file_cerbos_policy_v1_policy_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_cerbos_policy_v1_policy_proto_msgTypes = make([]protoimpl.MessageInfo, 45) +var file_cerbos_policy_v1_policy_proto_msgTypes = make([]protoimpl.MessageInfo, 46) var file_cerbos_policy_v1_policy_proto_goTypes = []interface{}{ (TestResults_Result)(0), // 0: cerbos.policy.v1.TestResults.Result (*Policy)(nil), // 1: cerbos.policy.v1.Policy @@ -3030,19 +3106,20 @@ var file_cerbos_policy_v1_policy_proto_goTypes = []interface{}{ (*TestResults_Tally)(nil), // 38: cerbos.policy.v1.TestResults.Tally (*TestResults_Summary)(nil), // 39: cerbos.policy.v1.TestResults.Summary (*TestResults_Suite)(nil), // 40: cerbos.policy.v1.TestResults.Suite - (*TestResults_Principal)(nil), // 41: cerbos.policy.v1.TestResults.Principal - (*TestResults_Resource)(nil), // 42: cerbos.policy.v1.TestResults.Resource - (*TestResults_Action)(nil), // 43: cerbos.policy.v1.TestResults.Action - (*TestResults_Details)(nil), // 44: cerbos.policy.v1.TestResults.Details - (*TestResults_Failure)(nil), // 45: cerbos.policy.v1.TestResults.Failure - (*wrapperspb.UInt64Value)(nil), // 46: google.protobuf.UInt64Value - (v1.Effect)(0), // 47: cerbos.effect.v1.Effect - (*timestamppb.Timestamp)(nil), // 48: google.protobuf.Timestamp - (*v11.CheckInput)(nil), // 49: cerbos.engine.v1.CheckInput - (*v11.Principal)(nil), // 50: cerbos.engine.v1.Principal - (*v11.Resource)(nil), // 51: cerbos.engine.v1.Resource - (*v11.AuxData)(nil), // 52: cerbos.engine.v1.AuxData - (*v11.Trace)(nil), // 53: cerbos.engine.v1.Trace + (*TestResults_TestCase)(nil), // 41: cerbos.policy.v1.TestResults.TestCase + (*TestResults_Principal)(nil), // 42: cerbos.policy.v1.TestResults.Principal + (*TestResults_Resource)(nil), // 43: cerbos.policy.v1.TestResults.Resource + (*TestResults_Action)(nil), // 44: cerbos.policy.v1.TestResults.Action + (*TestResults_Details)(nil), // 45: cerbos.policy.v1.TestResults.Details + (*TestResults_Failure)(nil), // 46: cerbos.policy.v1.TestResults.Failure + (*wrapperspb.UInt64Value)(nil), // 47: google.protobuf.UInt64Value + (v1.Effect)(0), // 48: cerbos.effect.v1.Effect + (*timestamppb.Timestamp)(nil), // 49: google.protobuf.Timestamp + (*v11.CheckInput)(nil), // 50: cerbos.engine.v1.CheckInput + (*v11.Principal)(nil), // 51: cerbos.engine.v1.Principal + (*v11.Resource)(nil), // 52: cerbos.engine.v1.Resource + (*v11.AuxData)(nil), // 53: cerbos.engine.v1.AuxData + (*v11.Trace)(nil), // 54: cerbos.engine.v1.Trace } var file_cerbos_policy_v1_policy_proto_depIdxs = []int32{ 2, // 0: cerbos.policy.v1.Policy.metadata:type_name -> cerbos.policy.v1.Metadata @@ -3051,11 +3128,11 @@ var file_cerbos_policy_v1_policy_proto_depIdxs = []int32{ 7, // 3: cerbos.policy.v1.Policy.derived_roles:type_name -> cerbos.policy.v1.DerivedRoles 18, // 4: cerbos.policy.v1.Policy.variables:type_name -> cerbos.policy.v1.Policy.VariablesEntry 19, // 5: cerbos.policy.v1.Metadata.annotations:type_name -> cerbos.policy.v1.Metadata.AnnotationsEntry - 46, // 6: cerbos.policy.v1.Metadata.hash:type_name -> google.protobuf.UInt64Value + 47, // 6: cerbos.policy.v1.Metadata.hash:type_name -> google.protobuf.UInt64Value 4, // 7: cerbos.policy.v1.ResourcePolicy.rules:type_name -> cerbos.policy.v1.ResourceRule 11, // 8: cerbos.policy.v1.ResourcePolicy.schemas:type_name -> cerbos.policy.v1.Schemas 9, // 9: cerbos.policy.v1.ResourceRule.condition:type_name -> cerbos.policy.v1.Condition - 47, // 10: cerbos.policy.v1.ResourceRule.effect:type_name -> cerbos.effect.v1.Effect + 48, // 10: cerbos.policy.v1.ResourceRule.effect:type_name -> cerbos.effect.v1.Effect 6, // 11: cerbos.policy.v1.PrincipalPolicy.rules:type_name -> cerbos.policy.v1.PrincipalRule 20, // 12: cerbos.policy.v1.PrincipalRule.actions:type_name -> cerbos.policy.v1.PrincipalRule.Action 8, // 13: cerbos.policy.v1.DerivedRoles.definitions:type_name -> cerbos.policy.v1.RoleDef @@ -3066,7 +3143,7 @@ var file_cerbos_policy_v1_policy_proto_depIdxs = []int32{ 21, // 18: cerbos.policy.v1.Match.none:type_name -> cerbos.policy.v1.Match.ExprList 23, // 19: cerbos.policy.v1.Schemas.principal_schema:type_name -> cerbos.policy.v1.Schemas.Schema 23, // 20: cerbos.policy.v1.Schemas.resource_schema:type_name -> cerbos.policy.v1.Schemas.Schema - 48, // 21: cerbos.policy.v1.TestOptions.now:type_name -> google.protobuf.Timestamp + 49, // 21: cerbos.policy.v1.TestOptions.now:type_name -> google.protobuf.Timestamp 15, // 22: cerbos.policy.v1.TestSuite.tests:type_name -> cerbos.policy.v1.TestTable 30, // 23: cerbos.policy.v1.TestSuite.principals:type_name -> cerbos.policy.v1.TestSuite.PrincipalsEntry 31, // 24: cerbos.policy.v1.TestSuite.resources:type_name -> cerbos.policy.v1.TestSuite.ResourcesEntry @@ -3076,45 +3153,47 @@ var file_cerbos_policy_v1_policy_proto_depIdxs = []int32{ 34, // 28: cerbos.policy.v1.TestTable.expected:type_name -> cerbos.policy.v1.TestTable.Expectation 13, // 29: cerbos.policy.v1.TestTable.options:type_name -> cerbos.policy.v1.TestOptions 36, // 30: cerbos.policy.v1.Test.name:type_name -> cerbos.policy.v1.Test.TestName - 49, // 31: cerbos.policy.v1.Test.input:type_name -> cerbos.engine.v1.CheckInput + 50, // 31: cerbos.policy.v1.Test.input:type_name -> cerbos.engine.v1.CheckInput 37, // 32: cerbos.policy.v1.Test.expected:type_name -> cerbos.policy.v1.Test.ExpectedEntry 13, // 33: cerbos.policy.v1.Test.options:type_name -> cerbos.policy.v1.TestOptions 40, // 34: cerbos.policy.v1.TestResults.suites:type_name -> cerbos.policy.v1.TestResults.Suite 39, // 35: cerbos.policy.v1.TestResults.summary:type_name -> cerbos.policy.v1.TestResults.Summary 9, // 36: cerbos.policy.v1.PrincipalRule.Action.condition:type_name -> cerbos.policy.v1.Condition - 47, // 37: cerbos.policy.v1.PrincipalRule.Action.effect:type_name -> cerbos.effect.v1.Effect + 48, // 37: cerbos.policy.v1.PrincipalRule.Action.effect:type_name -> cerbos.effect.v1.Effect 10, // 38: cerbos.policy.v1.Match.ExprList.of:type_name -> cerbos.policy.v1.Match 22, // 39: cerbos.policy.v1.Schemas.Schema.ignore_when:type_name -> cerbos.policy.v1.Schemas.IgnoreWhen 27, // 40: cerbos.policy.v1.TestFixture.Principals.principals:type_name -> cerbos.policy.v1.TestFixture.Principals.PrincipalsEntry 28, // 41: cerbos.policy.v1.TestFixture.Resources.resources:type_name -> cerbos.policy.v1.TestFixture.Resources.ResourcesEntry 29, // 42: cerbos.policy.v1.TestFixture.AuxData.aux_data:type_name -> cerbos.policy.v1.TestFixture.AuxData.AuxDataEntry - 50, // 43: cerbos.policy.v1.TestFixture.Principals.PrincipalsEntry.value:type_name -> cerbos.engine.v1.Principal - 51, // 44: cerbos.policy.v1.TestFixture.Resources.ResourcesEntry.value:type_name -> cerbos.engine.v1.Resource - 52, // 45: cerbos.policy.v1.TestFixture.AuxData.AuxDataEntry.value:type_name -> cerbos.engine.v1.AuxData - 50, // 46: cerbos.policy.v1.TestSuite.PrincipalsEntry.value:type_name -> cerbos.engine.v1.Principal - 51, // 47: cerbos.policy.v1.TestSuite.ResourcesEntry.value:type_name -> cerbos.engine.v1.Resource - 52, // 48: cerbos.policy.v1.TestSuite.AuxDataEntry.value:type_name -> cerbos.engine.v1.AuxData + 51, // 43: cerbos.policy.v1.TestFixture.Principals.PrincipalsEntry.value:type_name -> cerbos.engine.v1.Principal + 52, // 44: cerbos.policy.v1.TestFixture.Resources.ResourcesEntry.value:type_name -> cerbos.engine.v1.Resource + 53, // 45: cerbos.policy.v1.TestFixture.AuxData.AuxDataEntry.value:type_name -> cerbos.engine.v1.AuxData + 51, // 46: cerbos.policy.v1.TestSuite.PrincipalsEntry.value:type_name -> cerbos.engine.v1.Principal + 52, // 47: cerbos.policy.v1.TestSuite.ResourcesEntry.value:type_name -> cerbos.engine.v1.Resource + 53, // 48: cerbos.policy.v1.TestSuite.AuxDataEntry.value:type_name -> cerbos.engine.v1.AuxData 35, // 49: cerbos.policy.v1.TestTable.Expectation.actions:type_name -> cerbos.policy.v1.TestTable.Expectation.ActionsEntry - 47, // 50: cerbos.policy.v1.TestTable.Expectation.ActionsEntry.value:type_name -> cerbos.effect.v1.Effect - 47, // 51: cerbos.policy.v1.Test.ExpectedEntry.value:type_name -> cerbos.effect.v1.Effect + 48, // 50: cerbos.policy.v1.TestTable.Expectation.ActionsEntry.value:type_name -> cerbos.effect.v1.Effect + 48, // 51: cerbos.policy.v1.Test.ExpectedEntry.value:type_name -> cerbos.effect.v1.Effect 0, // 52: cerbos.policy.v1.TestResults.Tally.result:type_name -> cerbos.policy.v1.TestResults.Result 0, // 53: cerbos.policy.v1.TestResults.Summary.overall_result:type_name -> cerbos.policy.v1.TestResults.Result 38, // 54: cerbos.policy.v1.TestResults.Summary.result_counts:type_name -> cerbos.policy.v1.TestResults.Tally - 41, // 55: cerbos.policy.v1.TestResults.Suite.principals:type_name -> cerbos.policy.v1.TestResults.Principal + 42, // 55: cerbos.policy.v1.TestResults.Suite.principals:type_name -> cerbos.policy.v1.TestResults.Principal 39, // 56: cerbos.policy.v1.TestResults.Suite.summary:type_name -> cerbos.policy.v1.TestResults.Summary - 42, // 57: cerbos.policy.v1.TestResults.Principal.resources:type_name -> cerbos.policy.v1.TestResults.Resource - 43, // 58: cerbos.policy.v1.TestResults.Resource.actions:type_name -> cerbos.policy.v1.TestResults.Action - 44, // 59: cerbos.policy.v1.TestResults.Action.details:type_name -> cerbos.policy.v1.TestResults.Details - 0, // 60: cerbos.policy.v1.TestResults.Details.result:type_name -> cerbos.policy.v1.TestResults.Result - 45, // 61: cerbos.policy.v1.TestResults.Details.failure:type_name -> cerbos.policy.v1.TestResults.Failure - 53, // 62: cerbos.policy.v1.TestResults.Details.engine_trace:type_name -> cerbos.engine.v1.Trace - 47, // 63: cerbos.policy.v1.TestResults.Failure.expected:type_name -> cerbos.effect.v1.Effect - 47, // 64: cerbos.policy.v1.TestResults.Failure.actual:type_name -> cerbos.effect.v1.Effect - 65, // [65:65] is the sub-list for method output_type - 65, // [65:65] is the sub-list for method input_type - 65, // [65:65] is the sub-list for extension type_name - 65, // [65:65] is the sub-list for extension extendee - 0, // [0:65] is the sub-list for field type_name + 41, // 57: cerbos.policy.v1.TestResults.Suite.test_cases:type_name -> cerbos.policy.v1.TestResults.TestCase + 42, // 58: cerbos.policy.v1.TestResults.TestCase.principals:type_name -> cerbos.policy.v1.TestResults.Principal + 43, // 59: cerbos.policy.v1.TestResults.Principal.resources:type_name -> cerbos.policy.v1.TestResults.Resource + 44, // 60: cerbos.policy.v1.TestResults.Resource.actions:type_name -> cerbos.policy.v1.TestResults.Action + 45, // 61: cerbos.policy.v1.TestResults.Action.details:type_name -> cerbos.policy.v1.TestResults.Details + 0, // 62: cerbos.policy.v1.TestResults.Details.result:type_name -> cerbos.policy.v1.TestResults.Result + 46, // 63: cerbos.policy.v1.TestResults.Details.failure:type_name -> cerbos.policy.v1.TestResults.Failure + 54, // 64: cerbos.policy.v1.TestResults.Details.engine_trace:type_name -> cerbos.engine.v1.Trace + 48, // 65: cerbos.policy.v1.TestResults.Failure.expected:type_name -> cerbos.effect.v1.Effect + 48, // 66: cerbos.policy.v1.TestResults.Failure.actual:type_name -> cerbos.effect.v1.Effect + 67, // [67:67] is the sub-list for method output_type + 67, // [67:67] is the sub-list for method input_type + 67, // [67:67] is the sub-list for extension type_name + 67, // [67:67] is the sub-list for extension extendee + 0, // [0:67] is the sub-list for field type_name } func init() { file_cerbos_policy_v1_policy_proto_init() } @@ -3484,7 +3563,7 @@ func file_cerbos_policy_v1_policy_proto_init() { } } file_cerbos_policy_v1_policy_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestResults_Principal); i { + switch v := v.(*TestResults_TestCase); i { case 0: return &v.state case 1: @@ -3496,7 +3575,7 @@ func file_cerbos_policy_v1_policy_proto_init() { } } file_cerbos_policy_v1_policy_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestResults_Resource); i { + switch v := v.(*TestResults_Principal); i { case 0: return &v.state case 1: @@ -3508,7 +3587,7 @@ func file_cerbos_policy_v1_policy_proto_init() { } } file_cerbos_policy_v1_policy_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestResults_Action); i { + switch v := v.(*TestResults_Resource); i { case 0: return &v.state case 1: @@ -3520,7 +3599,7 @@ func file_cerbos_policy_v1_policy_proto_init() { } } file_cerbos_policy_v1_policy_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestResults_Details); i { + switch v := v.(*TestResults_Action); i { case 0: return &v.state case 1: @@ -3532,6 +3611,18 @@ func file_cerbos_policy_v1_policy_proto_init() { } } file_cerbos_policy_v1_policy_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TestResults_Details); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cerbos_policy_v1_policy_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TestResults_Failure); i { case 0: return &v.state @@ -3559,7 +3650,7 @@ func file_cerbos_policy_v1_policy_proto_init() { (*Match_None)(nil), (*Match_Expr)(nil), } - file_cerbos_policy_v1_policy_proto_msgTypes[43].OneofWrappers = []interface{}{ + file_cerbos_policy_v1_policy_proto_msgTypes[44].OneofWrappers = []interface{}{ (*TestResults_Details_Failure)(nil), (*TestResults_Details_Error)(nil), } @@ -3569,7 +3660,7 @@ func file_cerbos_policy_v1_policy_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_cerbos_policy_v1_policy_proto_rawDesc, NumEnums: 1, - NumMessages: 45, + NumMessages: 46, NumExtensions: 0, NumServices: 0, }, diff --git a/api/genpb/cerbos/policy/v1/policy.pb.validate.go b/api/genpb/cerbos/policy/v1/policy.pb.validate.go index 77c7632e8..6f537d247 100644 --- a/api/genpb/cerbos/policy/v1/policy.pb.validate.go +++ b/api/genpb/cerbos/policy/v1/policy.pb.validate.go @@ -5345,6 +5345,40 @@ func (m *TestResults_Suite) validate(all bool) error { // no validation rules for Error + for idx, item := range m.GetTestCases() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, TestResults_SuiteValidationError{ + field: fmt.Sprintf("TestCases[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, TestResults_SuiteValidationError{ + field: fmt.Sprintf("TestCases[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return TestResults_SuiteValidationError{ + field: fmt.Sprintf("TestCases[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + if len(errors) > 0 { return TestResults_SuiteMultiError(errors) } @@ -5425,6 +5459,144 @@ var _ interface { ErrorName() string } = TestResults_SuiteValidationError{} +// Validate checks the field values on TestResults_TestCase with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *TestResults_TestCase) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on TestResults_TestCase with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// TestResults_TestCaseMultiError, or nil if none found. +func (m *TestResults_TestCase) ValidateAll() error { + return m.validate(true) +} + +func (m *TestResults_TestCase) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Name + + for idx, item := range m.GetPrincipals() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, TestResults_TestCaseValidationError{ + field: fmt.Sprintf("Principals[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, TestResults_TestCaseValidationError{ + field: fmt.Sprintf("Principals[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return TestResults_TestCaseValidationError{ + field: fmt.Sprintf("Principals[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if len(errors) > 0 { + return TestResults_TestCaseMultiError(errors) + } + + return nil +} + +// TestResults_TestCaseMultiError is an error wrapping multiple validation +// errors returned by TestResults_TestCase.ValidateAll() if the designated +// constraints aren't met. +type TestResults_TestCaseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m TestResults_TestCaseMultiError) Error() string { + var msgs []string + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m TestResults_TestCaseMultiError) AllErrors() []error { return m } + +// TestResults_TestCaseValidationError is the validation error returned by +// TestResults_TestCase.Validate if the designated constraints aren't met. +type TestResults_TestCaseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e TestResults_TestCaseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e TestResults_TestCaseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e TestResults_TestCaseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e TestResults_TestCaseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e TestResults_TestCaseValidationError) ErrorName() string { + return "TestResults_TestCaseValidationError" +} + +// Error satisfies the builtin error interface +func (e TestResults_TestCaseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sTestResults_TestCase.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = TestResults_TestCaseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = TestResults_TestCaseValidationError{} + // Validate checks the field values on TestResults_Principal with the rules // defined in the proto definition for this message. If any rules are // violated, the first error encountered is returned, or nil if there are no violations. diff --git a/api/genpb/cerbos/policy/v1/policy_hashpb.pb.go b/api/genpb/cerbos/policy/v1/policy_hashpb.pb.go index 77510f663..a3865e655 100644 --- a/api/genpb/cerbos/policy/v1/policy_hashpb.pb.go +++ b/api/genpb/cerbos/policy/v1/policy_hashpb.pb.go @@ -216,6 +216,14 @@ func (m *TestResults_Suite) HashPB(hasher hash.Hash, ignore map[string]struct{}) } } +// HashPB computes a hash of the message using the given hash function +// The ignore set must contain fully-qualified field names (pkg.msg.field) that should be ignored from the hash +func (m *TestResults_TestCase) HashPB(hasher hash.Hash, ignore map[string]struct{}) { + if m != nil { + cerbos_policy_v1_TestResults_TestCase_hashpb_sum(m, hasher, ignore) + } +} + // HashPB computes a hash of the message using the given hash function // The ignore set must contain fully-qualified field names (pkg.msg.field) that should be ignored from the hash func (m *TestResults_Principal) HashPB(hasher hash.Hash, ignore map[string]struct{}) { diff --git a/api/genpb/cerbos/policy/v1/policy_vtproto.pb.go b/api/genpb/cerbos/policy/v1/policy_vtproto.pb.go index 5725a8c5c..79275ad7d 100644 --- a/api/genpb/cerbos/policy/v1/policy_vtproto.pb.go +++ b/api/genpb/cerbos/policy/v1/policy_vtproto.pb.go @@ -2108,6 +2108,18 @@ func (m *TestResults_Suite) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if len(m.TestCases) > 0 { + for iNdEx := len(m.TestCases) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.TestCases[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x32 + } + } if len(m.Error) > 0 { i -= len(m.Error) copy(dAtA[i:], m.Error) @@ -2154,6 +2166,58 @@ func (m *TestResults_Suite) MarshalToSizedBufferVT(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *TestResults_TestCase) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TestResults_TestCase) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *TestResults_TestCase) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.Principals) > 0 { + for iNdEx := len(m.Principals) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.Principals[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarint(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *TestResults_Principal) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil @@ -3430,6 +3494,32 @@ func (m *TestResults_Suite) SizeVT() (n int) { if l > 0 { n += 1 + l + sov(uint64(l)) } + if len(m.TestCases) > 0 { + for _, e := range m.TestCases { + l = e.SizeVT() + n += 1 + l + sov(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *TestResults_TestCase) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sov(uint64(l)) + } + if len(m.Principals) > 0 { + for _, e := range m.Principals { + l = e.SizeVT() + n += 1 + l + sov(uint64(l)) + } + } n += len(m.unknownFields) return n } @@ -9238,6 +9328,157 @@ func (m *TestResults_Suite) UnmarshalVT(dAtA []byte) error { } m.Error = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TestCases", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TestCases = append(m.TestCases, &TestResults_TestCase{}) + if err := m.TestCases[len(m.TestCases)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TestResults_TestCase) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TestResults_TestCase: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TestResults_TestCase: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Principals", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Principals = append(m.Principals, &TestResults_Principal{}) + if err := m.Principals[len(m.Principals)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skip(dAtA[iNdEx:]) diff --git a/api/genpb/cerbos/private/v1/hashpb_helpers.pb.go b/api/genpb/cerbos/private/v1/hashpb_helpers.pb.go index 25d9af186..612b3fa64 100644 --- a/api/genpb/cerbos/private/v1/hashpb_helpers.pb.go +++ b/api/genpb/cerbos/private/v1/hashpb_helpers.pb.go @@ -935,6 +935,16 @@ func cerbos_policy_v1_TestResults_Suite_hashpb_sum(m *v11.TestResults_Suite, has _, _ = hasher.Write(protowire.AppendString(nil, m.Error)) } + if _, ok := ignore["cerbos.policy.v1.TestResults.Suite.test_cases"]; !ok { + if len(m.TestCases) > 0 { + for _, v := range m.TestCases { + if v != nil { + cerbos_policy_v1_TestResults_TestCase_hashpb_sum(v, hasher, ignore) + } + + } + } + } } func cerbos_policy_v1_TestResults_Summary_hashpb_sum(m *v11.TestResults_Summary, hasher hash.Hash, ignore map[string]struct{}) { @@ -969,6 +979,23 @@ func cerbos_policy_v1_TestResults_Tally_hashpb_sum(m *v11.TestResults_Tally, has } } +func cerbos_policy_v1_TestResults_TestCase_hashpb_sum(m *v11.TestResults_TestCase, hasher hash.Hash, ignore map[string]struct{}) { + if _, ok := ignore["cerbos.policy.v1.TestResults.TestCase.name"]; !ok { + _, _ = hasher.Write(protowire.AppendString(nil, m.Name)) + + } + if _, ok := ignore["cerbos.policy.v1.TestResults.TestCase.principals"]; !ok { + if len(m.Principals) > 0 { + for _, v := range m.Principals { + if v != nil { + cerbos_policy_v1_TestResults_Principal_hashpb_sum(v, hasher, ignore) + } + + } + } + } +} + func cerbos_policy_v1_TestResults_hashpb_sum(m *v11.TestResults, hasher hash.Hash, ignore map[string]struct{}) { if _, ok := ignore["cerbos.policy.v1.TestResults.suites"]; !ok { if len(m.Suites) > 0 { diff --git a/api/genpb/cerbos/response/v1/hashpb_helpers.pb.go b/api/genpb/cerbos/response/v1/hashpb_helpers.pb.go index a0894c84d..116c266e9 100644 --- a/api/genpb/cerbos/response/v1/hashpb_helpers.pb.go +++ b/api/genpb/cerbos/response/v1/hashpb_helpers.pb.go @@ -1167,6 +1167,16 @@ func cerbos_policy_v1_TestResults_Suite_hashpb_sum(m *v12.TestResults_Suite, has _, _ = hasher.Write(protowire.AppendString(nil, m.Error)) } + if _, ok := ignore["cerbos.policy.v1.TestResults.Suite.test_cases"]; !ok { + if len(m.TestCases) > 0 { + for _, v := range m.TestCases { + if v != nil { + cerbos_policy_v1_TestResults_TestCase_hashpb_sum(v, hasher, ignore) + } + + } + } + } } func cerbos_policy_v1_TestResults_Summary_hashpb_sum(m *v12.TestResults_Summary, hasher hash.Hash, ignore map[string]struct{}) { @@ -1201,6 +1211,23 @@ func cerbos_policy_v1_TestResults_Tally_hashpb_sum(m *v12.TestResults_Tally, has } } +func cerbos_policy_v1_TestResults_TestCase_hashpb_sum(m *v12.TestResults_TestCase, hasher hash.Hash, ignore map[string]struct{}) { + if _, ok := ignore["cerbos.policy.v1.TestResults.TestCase.name"]; !ok { + _, _ = hasher.Write(protowire.AppendString(nil, m.Name)) + + } + if _, ok := ignore["cerbos.policy.v1.TestResults.TestCase.principals"]; !ok { + if len(m.Principals) > 0 { + for _, v := range m.Principals { + if v != nil { + cerbos_policy_v1_TestResults_Principal_hashpb_sum(v, hasher, ignore) + } + + } + } + } +} + func cerbos_policy_v1_TestResults_hashpb_sum(m *v12.TestResults, hasher hash.Hash, ignore map[string]struct{}) { if _, ok := ignore["cerbos.policy.v1.TestResults.suites"]; !ok { if len(m.Suites) > 0 { diff --git a/api/public/cerbos/policy/v1/policy.proto b/api/public/cerbos/policy/v1/policy.proto index 0a44150d4..9f2596682 100644 --- a/api/public/cerbos/policy/v1/policy.proto +++ b/api/public/cerbos/policy/v1/policy.proto @@ -291,9 +291,15 @@ message TestResults { message Suite { string file = 1; string name = 2; - repeated Principal principals = 3; + repeated Principal principals = 3 [deprecated = true]; Summary summary = 4; string error = 5; + repeated TestCase test_cases = 6; + } + + message TestCase { + string name = 1; + repeated Principal principals = 2; } message Principal { diff --git a/cmd/cerbos/compile/internal/verification/display.go b/cmd/cerbos/compile/internal/verification/display.go index 1b404a456..2a39452d7 100644 --- a/cmd/cerbos/compile/internal/verification/display.go +++ b/cmd/cerbos/compile/internal/verification/display.go @@ -19,10 +19,11 @@ import ( const ( suiteLevel = 0 - principalLevel = 1 - resourceLevel = 2 - actionLevel = 3 - resultLevel = 4 + testCaseLevel = 1 + principalLevel = 2 + resourceLevel = 3 + actionLevel = 4 + resultLevel = 5 listIndent = 2 ) @@ -118,11 +119,37 @@ func (o *testOutput) addSuite(suite *policyv1.TestResults_Suite) { o.appendNode(suiteLevel, suiteText) - for _, principal := range suite.Principals { + for _, testCase := range suite.TestCases { + o.addTestCase(suite, testCase) + } +} + +func (o *testOutput) addTestCase(suite *policyv1.TestResults_Suite, testCase *policyv1.TestResults_TestCase) { + if !o.shouldAddTestCase(testCase) { + return + } + + o.appendNode(testCaseLevel, colored.TestCase(testCase.Name)) + + for _, principal := range testCase.Principals { o.addPrincipal(suite, principal) } } +func (o *testOutput) shouldAddTestCase(testCase *policyv1.TestResults_TestCase) bool { + if o.verbose { + return true + } + + for _, principal := range testCase.Principals { + if o.shouldAddPrincipal(principal) { + return true + } + } + + return false +} + func (o *testOutput) addPrincipal(suite *policyv1.TestResults_Suite, principal *policyv1.TestResults_Principal) { if !o.shouldAddPrincipal(principal) { return diff --git a/internal/printer/colored/colored.go b/internal/printer/colored/colored.go index 22a93605c..c1598a980 100644 --- a/internal/printer/colored/colored.go +++ b/internal/printer/colored/colored.go @@ -13,6 +13,7 @@ var ( FileName = color.New(color.FgCyan).SprintFunc() Header = color.New(color.FgHiWhite, color.Bold).SprintFunc() PassedTest = color.New(color.FgGreen).SprintFunc() + TestCase = color.New(color.FgBlue).SprintFunc() Principal = color.New(color.FgCyan).SprintFunc() REPLCmd = color.New(color.FgYellow).SprintFunc() REPLError = color.New(color.FgRed).SprintFunc() diff --git a/internal/test/testdata/server/playground/test/pgt_case_00.yaml b/internal/test/testdata/server/playground/test/pgt_case_00.yaml index a5381992c..5bffad2c3 100644 --- a/internal/test/testdata/server/playground/test/pgt_case_00.yaml +++ b/internal/test/testdata/server/playground/test/pgt_case_00.yaml @@ -4,235 +4,259 @@ wantStatus: httpStatusCode: 200 grpcStatusCode: 0 playgroundTest: - input: { - "playgroundId": "test", - "files": [ - { - "fileName": "common_roles.yaml", - "contents": "{{ fileString `store/derived_roles/common_roles.yaml` | b64enc }}", - }, - { - "fileName": "policy_04.yaml", - "contents": "{{ fileString `store/resource_policies/policy_04.yaml` | b64enc }}", - }, - { - "fileName": "policy_04_test.yaml", - "contents": "{{ fileString `store/tests/policy_04_test.yaml` | b64enc }}" - } - ] - } - wantResponse: { - "playgroundId": "test", - "success": { - "results": { - "suites": [ + input: + { + "playgroundId": "test", + "files": + [ { - "file": "policy_04_test.yaml", - "name": "album:object resource policy tests", - "principals": [ - { - "name": "user", - "resources": [ + "fileName": "common_roles.yaml", + "contents": "{{ fileString `store/derived_roles/common_roles.yaml` | b64enc }}", + }, + { + "fileName": "policy_04.yaml", + "contents": "{{ fileString `store/resource_policies/policy_04.yaml` | b64enc }}", + }, + { + "fileName": "policy_04_test.yaml", + "contents": "{{ fileString `store/tests/policy_04_test.yaml` | b64enc }}", + }, + ], + } + wantResponse: + { + "playgroundId": "test", + "success": + { + "results": + { + "suites": + [ { - "name": "album", - "actions": [ + "file": "policy_04_test.yaml", + "name": "album:object resource policy tests", + "testCases": + [ + { + name: "User can view public album", + "principals": + [ + { + "name": "user", + "resources": + [ + { + "name": "album", + "actions": + [ + { + "name": "view", + "details": + { + "result": "RESULT_PASSED", + "engineTrace": + [ + { + "components": + [ + { + "kind": "KIND_POLICY", + "policy": "cerbos.resource.album_object.vdefault", + }, + { + "kind": "KIND_SCOPE", + "scope": "", + }, + { + "kind": "KIND_DERIVED_ROLE", + "derivedRole": "abuse_moderator", + }, + ], + "event": + { + "status": "STATUS_SKIPPED", + "message": "No matching roles", + }, + }, + { + "components": + [ + { + "kind": "KIND_POLICY", + "policy": "cerbos.resource.album_object.vdefault", + }, + { + "kind": "KIND_SCOPE", + "scope": "", + }, + { + "kind": "KIND_DERIVED_ROLE", + "derivedRole": "owner", + }, + { + "kind": "KIND_CONDITION", + }, + { + "kind": "KIND_EXPR", + "expr": "request.resource.attr.owner == request.principal.id", + }, + ], + "event": + { + "status": "STATUS_ACTIVATED", + "result": false, + }, + }, + { + "components": + [ + { + "kind": "KIND_POLICY", + "policy": "cerbos.resource.album_object.vdefault", + }, + { + "kind": "KIND_SCOPE", + "scope": "", + }, + { + "kind": "KIND_DERIVED_ROLE", + "derivedRole": "owner", + }, + ], + "event": + { + "status": "STATUS_SKIPPED", + "message": "Condition not satisfied", + }, + }, + { + "components": + [ + { + "kind": "KIND_POLICY", + "policy": "cerbos.resource.album_object.vdefault", + }, + { + "kind": "KIND_SCOPE", + "scope": "", + }, + { + "kind": "KIND_RULE", + "rule": "rule-001", + }, + ], + "event": + { + "status": "STATUS_SKIPPED", + "message": "No matching roles or derived roles", + }, + }, + { + "components": + [ + { + "kind": "KIND_POLICY", + "policy": "cerbos.resource.album_object.vdefault", + }, + { + "kind": "KIND_SCOPE", + "scope": "", + }, + { + "kind": "KIND_RULE", + "rule": "rule-002", + }, + { + "kind": "KIND_ACTION", + "action": "view", + }, + { + "kind": "KIND_CONDITION", + }, + { + "kind": "KIND_EXPR", + "expr": "request.resource.attr.public == true", + }, + ], + "event": + { + "status": "STATUS_ACTIVATED", + "result": true, + }, + }, + { + "components": + [ + { + "kind": "KIND_POLICY", + "policy": "cerbos.resource.album_object.vdefault", + }, + { + "kind": "KIND_SCOPE", + "scope": "", + }, + { + "kind": "KIND_RULE", + "rule": "rule-002", + }, + { + "kind": "KIND_ACTION", + "action": "view", + }, + ], + "event": + { + "status": "STATUS_ACTIVATED", + "effect": "EFFECT_ALLOW", + }, + }, + { + "components": + [ + { + "kind": "KIND_POLICY", + "policy": "cerbos.resource.album_object.vdefault", + }, + { + "kind": "KIND_SCOPE", + "scope": "", + }, + { + "kind": "KIND_RULE", + "rule": "rule-003", + }, + ], + "event": + { + "status": "STATUS_SKIPPED", + "message": "No matching roles or derived roles", + }, + }, + ], + }, + }, + ], + }, + ], + }, + ], + }, + ], + "summary": { - "name": "view", - "details": { - "result": "RESULT_PASSED", - "engineTrace": [ - { - "components": [ - { - "kind": "KIND_POLICY", - "policy": "cerbos.resource.album_object.vdefault" - }, - { - "kind": "KIND_SCOPE", - "scope": "" - }, - { - "kind": "KIND_DERIVED_ROLE", - "derivedRole": "abuse_moderator" - } - ], - "event": { - "status": "STATUS_SKIPPED", - "message": "No matching roles" - } - }, - { - "components": [ - { - "kind": "KIND_POLICY", - "policy": "cerbos.resource.album_object.vdefault" - }, - { - "kind": "KIND_SCOPE", - "scope": "" - }, - { - "kind": "KIND_DERIVED_ROLE", - "derivedRole": "owner" - }, - { - "kind": "KIND_CONDITION" - }, - { - "kind": "KIND_EXPR", - "expr": "request.resource.attr.owner == request.principal.id" - } - ], - "event": { - "status": "STATUS_ACTIVATED", - "result": false - } - }, - { - "components": [ - { - "kind": "KIND_POLICY", - "policy": "cerbos.resource.album_object.vdefault" - }, - { - "kind": "KIND_SCOPE", - "scope": "" - }, - { - "kind": "KIND_DERIVED_ROLE", - "derivedRole": "owner" - } - ], - "event": { - "status": "STATUS_SKIPPED", - "message": "Condition not satisfied" - } - }, - { - "components": [ - { - "kind": "KIND_POLICY", - "policy": "cerbos.resource.album_object.vdefault" - }, - { - "kind": "KIND_SCOPE", - "scope": "" - }, - { - "kind": "KIND_RULE", - "rule": "rule-001" - } - ], - "event": { - "status": "STATUS_SKIPPED", - "message": "No matching roles or derived roles" - } - }, - { - "components": [ - { - "kind": "KIND_POLICY", - "policy": "cerbos.resource.album_object.vdefault" - }, - { - "kind": "KIND_SCOPE", - "scope": "" - }, - { - "kind": "KIND_RULE", - "rule": "rule-002" - }, - { - "kind": "KIND_ACTION", - "action": "view" - }, - { - "kind": "KIND_CONDITION" - }, - { - "kind": "KIND_EXPR", - "expr": "request.resource.attr.public == true" - } - ], - "event": { - "status": "STATUS_ACTIVATED", - "result": true - } - }, - { - "components": [ - { - "kind": "KIND_POLICY", - "policy": "cerbos.resource.album_object.vdefault" - }, - { - "kind": "KIND_SCOPE", - "scope": "" - }, - { - "kind": "KIND_RULE", - "rule": "rule-002" - }, - { - "kind": "KIND_ACTION", - "action": "view" - } - ], - "event": { - "status": "STATUS_ACTIVATED", - "effect": "EFFECT_ALLOW" - } - }, - { - "components": [ - { - "kind": "KIND_POLICY", - "policy": "cerbos.resource.album_object.vdefault" - }, - { - "kind": "KIND_SCOPE", - "scope": "" - }, - { - "kind": "KIND_RULE", - "rule": "rule-003" - } - ], - "event": { - "status": "STATUS_SKIPPED", - "message": "No matching roles or derived roles" - } - } - ] - } - } - ] - } - ] - } - ], - "summary": { - "overallResult": "RESULT_PASSED", - "testsCount": 1, - "resultCounts": [ + "overallResult": "RESULT_PASSED", + "testsCount": 1, + "resultCounts": + [{ "result": "RESULT_PASSED", "count": 1 }], + }, + }, + ], + "summary": { - "result": "RESULT_PASSED", - "count": 1 - } - ] - } - } - ], - "summary": { - "overallResult": "RESULT_PASSED", - "testsCount": 1, - "resultCounts": [ - { - "result": "RESULT_PASSED", - "count": 1 - } - ] - } - } + "overallResult": "RESULT_PASSED", + "testsCount": 1, + "resultCounts": [{ "result": "RESULT_PASSED", "count": 1 }], + }, + }, + }, } - } diff --git a/internal/test/testdata/verify/cases/case_001.yaml.golden b/internal/test/testdata/verify/cases/case_001.yaml.golden index 47e1dae37..4f6962e3d 100644 --- a/internal/test/testdata/verify/cases/case_001.yaml.golden +++ b/internal/test/testdata/verify/cases/case_001.yaml.golden @@ -3,73 +3,93 @@ { "file": "suite_test.yaml", "name": "TestSuite", - "principals": [ + "summary": { + "overallResult": "RESULT_PASSED", + "testsCount": 5, + "resultCounts": [ + { + "result": "RESULT_PASSED", + "count": 5 + } + ] + }, + "testCases": [ { - "name": "john", - "resources": [ + "name": "John and his leave request", + "principals": [ { - "name": "john_leave_request", - "actions": [ - { - "name": "view:public", - "details": { - "result": "RESULT_PASSED" - } - }, + "name": "john", + "resources": [ { - "name": "approve", - "details": { - "result": "RESULT_PASSED" - } - }, - { - "name": "defer", - "details": { - "result": "RESULT_PASSED" - } + "name": "john_leave_request", + "actions": [ + { + "name": "view:public", + "details": { + "result": "RESULT_PASSED" + } + }, + { + "name": "approve", + "details": { + "result": "RESULT_PASSED" + } + }, + { + "name": "defer", + "details": { + "result": "RESULT_PASSED" + } + } + ] } ] } ] }, { - "name": "bev", - "resources": [ + "name": "With global now", + "principals": [ { - "name": "stale_leave_request", - "actions": [ + "name": "bev", + "resources": [ { - "name": "remind", - "details": { - "result": "RESULT_PASSED" - } + "name": "stale_leave_request", + "actions": [ + { + "name": "remind", + "details": { + "result": "RESULT_PASSED" + } + } + ] } ] - }, + } + ] + }, + { + "name": "With local now", + "principals": [ { - "name": "stale_pending_leave_request", - "actions": [ + "name": "bev", + "resources": [ { - "name": "remind", - "details": { - "result": "RESULT_PASSED" - } + "name": "stale_pending_leave_request", + "actions": [ + { + "name": "remind", + "details": { + "result": "RESULT_PASSED" + } + } + ] } ] } ] } - ], - "summary": { - "overallResult": "RESULT_PASSED", - "testsCount": 5, - "resultCounts": [ - { - "result": "RESULT_PASSED", - "count": 5 - } - ] - } + ] } ], "summary": { diff --git a/internal/test/testdata/verify/cases/case_002.yaml.golden b/internal/test/testdata/verify/cases/case_002.yaml.golden index c7f09cf24..94c05e944 100644 --- a/internal/test/testdata/verify/cases/case_002.yaml.golden +++ b/internal/test/testdata/verify/cases/case_002.yaml.golden @@ -3,36 +3,6 @@ { "file": "inline_test.yaml", "name": "TestSuite", - "principals": [ - { - "name": "johnny", - "resources": [ - { - "name": "john_leave_request", - "actions": [ - { - "name": "view:public", - "details": { - "result": "RESULT_PASSED" - } - }, - { - "name": "approve", - "details": { - "result": "RESULT_PASSED" - } - }, - { - "name": "defer", - "details": { - "result": "RESULT_PASSED" - } - } - ] - } - ] - } - ], "summary": { "overallResult": "RESULT_PASSED", "testsCount": 3, @@ -42,7 +12,42 @@ "count": 3 } ] - } + }, + "testCases": [ + { + "name": "John and his leave request", + "principals": [ + { + "name": "johnny", + "resources": [ + { + "name": "john_leave_request", + "actions": [ + { + "name": "view:public", + "details": { + "result": "RESULT_PASSED" + } + }, + { + "name": "approve", + "details": { + "result": "RESULT_PASSED" + } + }, + { + "name": "defer", + "details": { + "result": "RESULT_PASSED" + } + } + ] + } + ] + } + ] + } + ] } ], "summary": { diff --git a/internal/test/testdata/verify/cases/case_003.yaml.golden b/internal/test/testdata/verify/cases/case_003.yaml.golden index b2d1cf41d..1ecc1ab08 100644 --- a/internal/test/testdata/verify/cases/case_003.yaml.golden +++ b/internal/test/testdata/verify/cases/case_003.yaml.golden @@ -3,62 +3,67 @@ { "file": "udf_test.yaml", "name": "TestSuite", - "principals": [ + "summary": { + "overallResult": "RESULT_PASSED", + "testsCount": 4, + "resultCounts": [ + { + "result": "RESULT_PASSED", + "count": 4 + } + ] + }, + "testCases": [ { - "name": "bev", - "resources": [ + "name": "John and his leave request", + "principals": [ { - "name": "pending_leave_request", - "actions": [ + "name": "bev", + "resources": [ { - "name": "delete", - "details": { - "result": "RESULT_PASSED" - } - }, - { - "name": "approve", - "details": { - "result": "RESULT_PASSED" - } + "name": "pending_leave_request", + "actions": [ + { + "name": "delete", + "details": { + "result": "RESULT_PASSED" + } + }, + { + "name": "approve", + "details": { + "result": "RESULT_PASSED" + } + } + ] } ] - } - ] - }, - { - "name": "matt", - "resources": [ + }, { - "name": "pending_leave_request", - "actions": [ - { - "name": "delete", - "details": { - "result": "RESULT_PASSED" - } - }, + "name": "matt", + "resources": [ { - "name": "approve", - "details": { - "result": "RESULT_PASSED" - } + "name": "pending_leave_request", + "actions": [ + { + "name": "delete", + "details": { + "result": "RESULT_PASSED" + } + }, + { + "name": "approve", + "details": { + "result": "RESULT_PASSED" + } + } + ] } ] } ] } - ], - "summary": { - "overallResult": "RESULT_PASSED", - "testsCount": 4, - "resultCounts": [ - { - "result": "RESULT_PASSED", - "count": 4 - } - ] - } + ] } ], "summary": { diff --git a/internal/test/testdata/verify/cases/case_008.yaml b/internal/test/testdata/verify/cases/case_008.yaml index a3c92e346..442958d3b 100644 --- a/internal/test/testdata/verify/cases/case_008.yaml +++ b/internal/test/testdata/verify/cases/case_008.yaml @@ -1 +1 @@ -description: Duplicate test (#1410) +description: Non-duplicate test (#1410) diff --git a/internal/test/testdata/verify/cases/case_008.yaml.golden b/internal/test/testdata/verify/cases/case_008.yaml.golden index 620fac0af..5adc3f1a8 100644 --- a/internal/test/testdata/verify/cases/case_008.yaml.golden +++ b/internal/test/testdata/verify/cases/case_008.yaml.golden @@ -3,76 +3,105 @@ { "file": "suite_test.yaml", "name": "TestSuite", - "principals": [ + "summary": { + "overallResult": "RESULT_FAILED", + "testsCount": 5, + "resultCounts": [ + { + "result": "RESULT_PASSED", + "count": 3 + }, + { + "result": "RESULT_FAILED", + "count": 2 + } + ] + }, + "testCases": [ { - "name": "john", - "resources": [ + "name": "John and his leave request", + "principals": [ { - "name": "john_leave_request", - "actions": [ + "name": "john", + "resources": [ { - "name": "view:public", - "details": { - "result": "RESULT_PASSED" - } - }, + "name": "john_leave_request", + "actions": [ + { + "name": "view:public", + "details": { + "result": "RESULT_PASSED" + } + }, + { + "name": "approve", + "details": { + "result": "RESULT_PASSED" + } + } + ] + } + ] + }, + { + "name": "alicia", + "resources": [ { - "name": "approve", - "details": { - "result": "RESULT_PASSED" - } + "name": "john_leave_request", + "actions": [ + { + "name": "view:public", + "details": { + "result": "RESULT_FAILED", + "failure": { + "expected": "EFFECT_DENY", + "actual": "EFFECT_ALLOW" + } + } + }, + { + "name": "approve", + "details": { + "result": "RESULT_PASSED" + } + } + ] } ] } ] }, { - "name": "alicia", - "resources": [ + "name": "Alicia approves John leave request", + "principals": [ { - "name": "john_leave_request", - "actions": [ + "name": "alicia", + "resources": [ { - "name": "view:public", - "details": { - "result": "RESULT_FAILED", - "failure": { - "expected": "EFFECT_DENY", - "actual": "EFFECT_ALLOW" + "name": "john_leave_request", + "actions": [ + { + "name": "approve", + "details": { + "result": "RESULT_FAILED", + "failure": { + "expected": "EFFECT_ALLOW", + "actual": "EFFECT_DENY" + } + } } - } - }, - { - "name": "approve", - "details": { - "result": "RESULT_PASSED" - } + ] } ] } ] } - ], - "summary": { - "overallResult": "RESULT_ERRORED", - "testsCount": 4, - "resultCounts": [ - { - "result": "RESULT_PASSED", - "count": 3 - }, - { - "result": "RESULT_FAILED", - "count": 1 - } - ] - }, - "error": "Duplicate test: The combination [alicia|john_leave_request|approve] in test \"Alicia approves John leave request\" was already exercised in test \"John and his leave request\"" + ] } ], "summary": { - "overallResult": "RESULT_ERRORED", - "testsCount": 4, + "overallResult": "RESULT_FAILED", + "testsCount": 5, "resultCounts": [ { "result": "RESULT_PASSED", @@ -80,7 +109,7 @@ }, { "result": "RESULT_FAILED", - "count": 1 + "count": 2 } ] } diff --git a/internal/test/testdata/verify/cases/case_009.yaml b/internal/test/testdata/verify/cases/case_009.yaml new file mode 100644 index 000000000..146621b9a --- /dev/null +++ b/internal/test/testdata/verify/cases/case_009.yaml @@ -0,0 +1 @@ +description: Non-duplicate test (#1490) diff --git a/internal/test/testdata/verify/cases/case_009.yaml.golden b/internal/test/testdata/verify/cases/case_009.yaml.golden new file mode 100644 index 000000000..955f03829 --- /dev/null +++ b/internal/test/testdata/verify/cases/case_009.yaml.golden @@ -0,0 +1,72 @@ +{ + "suites": [ + { + "file": "suite_test.yaml", + "name": "TestSuite", + "summary": { + "overallResult": "RESULT_PASSED", + "testsCount": 2, + "resultCounts": [ + { + "result": "RESULT_PASSED", + "count": 2 + } + ] + }, + "testCases": [ + { + "name": "Test 1", + "principals": [ + { + "name": "john", + "resources": [ + { + "name": "john_leave_request", + "actions": [ + { + "name": "view:public", + "details": { + "result": "RESULT_PASSED" + } + } + ] + } + ] + } + ] + }, + { + "name": "Test 2", + "principals": [ + { + "name": "john", + "resources": [ + { + "name": "john_leave_request", + "actions": [ + { + "name": "view:public", + "details": { + "result": "RESULT_PASSED" + } + } + ] + } + ] + } + ] + } + ] + } + ], + "summary": { + "overallResult": "RESULT_PASSED", + "testsCount": 2, + "resultCounts": [ + { + "result": "RESULT_PASSED", + "count": 2 + } + ] + } +} \ No newline at end of file diff --git a/internal/test/testdata/verify/cases/case_009.yaml.input b/internal/test/testdata/verify/cases/case_009.yaml.input new file mode 100644 index 000000000..f5cbff57d --- /dev/null +++ b/internal/test/testdata/verify/cases/case_009.yaml.input @@ -0,0 +1,70 @@ +-- testdata/principals.yaml -- +--- +principals: + john: + policyVersion: '20210210' + id: john + roles: + - employee + attr: + department: marketing + geography: GB + team: design + +-- testdata/resources.yaml -- +--- +resources: + john_leave_request: + policyVersion: '20210210' + kind: leave_request + id: XX125 + attr: &attr + department: marketing + geography: GB + id: XX125 + owner: john + team: design + +-- testdata/auxdata.yaml -- +--- +auxData: + myJWT: + jwt: + iss: cerbos-test-suite + aud: [cerbos-jwt-tests] + customArray: [A, B] + +-- suite_test.yaml -- +--- +name: TestSuite +description: Tests +tests: + - name: Test 1 + input: + principals: + - john + resources: + - john_leave_request + actions: + - view:public + auxData: myJWT + expected: + - principal: john + resource: john_leave_request + actions: + view:public: EFFECT_ALLOW + + - name: Test 2 + input: + principals: + - john + resources: + - john_leave_request + actions: + - view:public + auxData: myJWT + expected: + - principal: john + resource: john_leave_request + actions: + view:public: EFFECT_ALLOW diff --git a/internal/test/testdata/verify/cases/case_010.yaml b/internal/test/testdata/verify/cases/case_010.yaml new file mode 100644 index 000000000..a0c3d3398 --- /dev/null +++ b/internal/test/testdata/verify/cases/case_010.yaml @@ -0,0 +1 @@ +description: Duplicate test name diff --git a/internal/test/testdata/verify/cases/case_010.yaml.golden b/internal/test/testdata/verify/cases/case_010.yaml.golden new file mode 100644 index 000000000..7e0fed6ff --- /dev/null +++ b/internal/test/testdata/verify/cases/case_010.yaml.golden @@ -0,0 +1,15 @@ +{ + "suites": [ + { + "file": "suite_test.yaml", + "name": "TestSuite", + "summary": { + "overallResult": "RESULT_ERRORED" + }, + "error": "Invalid test suite: another test named \"Test 1\" already exists" + } + ], + "summary": { + "overallResult": "RESULT_ERRORED" + } +} \ No newline at end of file diff --git a/internal/test/testdata/verify/cases/case_010.yaml.input b/internal/test/testdata/verify/cases/case_010.yaml.input new file mode 100644 index 000000000..e4e16c88b --- /dev/null +++ b/internal/test/testdata/verify/cases/case_010.yaml.input @@ -0,0 +1,74 @@ +-- testdata/principals.yaml -- +--- +principals: + john: + policyVersion: '20210210' + id: john + roles: + - employee + attr: + department: marketing + geography: GB + team: design + + alicia: + id: alicia + policyVersion: '20210210' + roles: + - employee + attr: + department: marketing + geography: GB + team: design + +-- testdata/resources.yaml -- +--- +resources: + john_leave_request: + policyVersion: '20210210' + kind: leave_request + id: XX125 + attr: &attr + department: marketing + geography: GB + id: XX125 + owner: john + team: design + +-- suite_test.yaml -- +--- +name: TestSuite +description: Tests +tests: + - name: Test 1 + input: + principals: + - john + resources: + - john_leave_request + actions: + - view:public + expected: + - principal: john + resource: john_leave_request + actions: + view:public: EFFECT_ALLOW + + - name: Test 1 + input: + principals: + - alicia + resources: + - john_leave_request + actions: + - view:public + expected: + - principal: john + resource: john_leave_request + actions: + view:public: EFFECT_ALLOW + + - principal: alicia + resource: john_leave_request + actions: + view:public: EFFECT_DENY diff --git a/internal/verify/test_fixture.go b/internal/verify/test_fixture.go index 3f3b257d1..933e9b7dd 100644 --- a/internal/verify/test_fixture.go +++ b/internal/verify/test_fixture.go @@ -11,6 +11,7 @@ import ( "path/filepath" "time" + "go.uber.org/multierr" "google.golang.org/protobuf/proto" enginev1 "github.com/cerbos/cerbos/api/genpb/cerbos/engine/v1" @@ -116,6 +117,19 @@ func loadFixtureElement(fsys fs.FS, path string, pb validatableMessage) error { return pb.Validate() } +func (tf *testFixture) checkDupes(suite *policyv1.TestSuite) error { + dupes := make(map[string]struct{}) + var errs error + for _, t := range suite.Tests { + if _, ok := dupes[t.Name]; ok { + errs = multierr.Append(errs, fmt.Errorf("another test named %q already exists", t.Name)) + } + dupes[t.Name] = struct{}{} + } + + return errs +} + func (tf *testFixture) runTestSuite(ctx context.Context, eng Checker, shouldRun func(string) bool, file string, suite *policyv1.TestSuite, trace bool) *policyv1.TestResults_Suite { suiteResult := &policyv1.TestResults_Suite{ File: file, @@ -128,6 +142,12 @@ func (tf *testFixture) runTestSuite(ctx context.Context, eng Checker, shouldRun return suiteResult } + if err := tf.checkDupes(suite); err != nil { + suiteResult.Summary.OverallResult = policyv1.TestResults_RESULT_ERRORED + suiteResult.Error = fmt.Sprintf("Invalid test suite: %v", err) + return suiteResult + } + tests, err := tf.getTests(suite) if err != nil { suiteResult.Summary.OverallResult = policyv1.TestResults_RESULT_ERRORED @@ -135,26 +155,14 @@ func (tf *testFixture) runTestSuite(ctx context.Context, eng Checker, shouldRun return suiteResult } - dupes := make(map[string]string) for _, test := range tests { if err := ctx.Err(); err != nil { return suiteResult } for _, action := range test.Input.Actions { - testKey := fmt.Sprintf("%s|%s|%s", test.Name.PrincipalKey, test.Name.ResourceKey, action) - if prevTest, ok := dupes[testKey]; ok { - suiteResult.Summary.OverallResult = policyv1.TestResults_RESULT_ERRORED - suiteResult.Error = fmt.Sprintf( - "Duplicate test: The combination [%s] in test %q was already exercised in test %q", - testKey, test.Name.TestTableName, prevTest, - ) - return suiteResult - } - - dupes[testKey] = test.Name.TestTableName testResult := runTest(ctx, eng, test, action, shouldRun, suite, trace) - addTestResult(suiteResult, test.Name.PrincipalKey, test.Name.ResourceKey, action, testResult) + addTestResult(suiteResult, test.Name.PrincipalKey, test.Name.ResourceKey, action, test.Name.TestTableName, testResult) } } @@ -224,9 +232,8 @@ func performCheck(ctx context.Context, eng Checker, inputs []*enginev1.CheckInpu return output, traceCollector.Traces(), err } -func addTestResult(suite *policyv1.TestResults_Suite, principal, resource, action string, details *policyv1.TestResults_Details) { - addAction(addResource(addPrincipal(suite, principal), resource), action).Details = details - +func addTestResult(suite *policyv1.TestResults_Suite, principal, resource, action, testName string, details *policyv1.TestResults_Details) { + addAction(addResource(addPrincipal(addTestCase(suite, testName), principal), resource), action).Details = details suite.Summary.TestsCount++ incrementTally(suite.Summary, details.Result, 1) @@ -235,15 +242,27 @@ func addTestResult(suite *policyv1.TestResults_Suite, principal, resource, actio } } -func addPrincipal(suite *policyv1.TestResults_Suite, name string) *policyv1.TestResults_Principal { - for _, principal := range suite.Principals { +func addTestCase(suite *policyv1.TestResults_Suite, name string) *policyv1.TestResults_TestCase { + for _, tc := range suite.TestCases { + if tc.Name == name { + return tc + } + } + + tc := &policyv1.TestResults_TestCase{Name: name} + suite.TestCases = append(suite.TestCases, tc) + return tc +} + +func addPrincipal(testCaseResult *policyv1.TestResults_TestCase, name string) *policyv1.TestResults_Principal { + for _, principal := range testCaseResult.Principals { if principal.Name == name { return principal } } principal := &policyv1.TestResults_Principal{Name: name} - suite.Principals = append(suite.Principals, principal) + testCaseResult.Principals = append(testCaseResult.Principals, principal) return principal } diff --git a/internal/verify/verify_test.go b/internal/verify/verify_test.go index 472da8815..fa7ca06d7 100644 --- a/internal/verify/verify_test.go +++ b/internal/verify/verify_test.go @@ -352,8 +352,9 @@ func Test_doVerify(t *testing.T) { is.NoError(err) is.Len(result.Suites, 3) for i := 0; i < len(result.Suites); i++ { - is.Len(result.Suites[i].Principals, 2) - is.Len(result.Suites[i].Principals[0].Resources, 2) + is.Len(result.Suites[i].TestCases, 2) + is.Len(result.Suites[i].TestCases[0].Principals, 2) + is.Len(result.Suites[i].TestCases[0].Principals[0].Resources, 1) } is.Equal(policyv1.TestResults_RESULT_PASSED, result.Summary.OverallResult) }) diff --git a/schema/jsonschema/cerbos/policy/v1/TestResults.schema.json b/schema/jsonschema/cerbos/policy/v1/TestResults.schema.json index 68695267a..593fd8568 100644 --- a/schema/jsonschema/cerbos/policy/v1/TestResults.schema.json +++ b/schema/jsonschema/cerbos/policy/v1/TestResults.schema.json @@ -229,6 +229,12 @@ }, "summary": { "$ref": "#/definitions/cerbos.policy.v1.TestResults.Summary" + }, + "testCases": { + "type": "array", + "items": { + "$ref": "#/definitions/cerbos.policy.v1.TestResults.TestCase" + } } } }, @@ -264,6 +270,21 @@ } } }, + "cerbos.policy.v1.TestResults.TestCase": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "principals": { + "type": "array", + "items": { + "$ref": "#/definitions/cerbos.policy.v1.TestResults.Principal" + } + } + } + }, "google.protobuf.Value": { "title": "Value", "description": "A dynamically-typed value." diff --git a/schema/jsonschema/cerbos/policy/v1/TestResults/Suite.schema.json b/schema/jsonschema/cerbos/policy/v1/TestResults/Suite.schema.json index 0028f2c94..70b990759 100644 --- a/schema/jsonschema/cerbos/policy/v1/TestResults/Suite.schema.json +++ b/schema/jsonschema/cerbos/policy/v1/TestResults/Suite.schema.json @@ -240,6 +240,21 @@ } } }, + "cerbos.policy.v1.TestResults.TestCase": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "principals": { + "type": "array", + "items": { + "$ref": "#/definitions/cerbos.policy.v1.TestResults.Principal" + } + } + } + }, "google.protobuf.Value": { "title": "Value", "description": "A dynamically-typed value." @@ -265,6 +280,12 @@ }, "summary": { "$ref": "#/definitions/cerbos.policy.v1.TestResults.Summary" + }, + "testCases": { + "type": "array", + "items": { + "$ref": "#/definitions/cerbos.policy.v1.TestResults.TestCase" + } } } } diff --git a/schema/jsonschema/cerbos/policy/v1/TestResults/TestCase.schema.json b/schema/jsonschema/cerbos/policy/v1/TestResults/TestCase.schema.json new file mode 100644 index 000000000..8a48f2fb0 --- /dev/null +++ b/schema/jsonschema/cerbos/policy/v1/TestResults/TestCase.schema.json @@ -0,0 +1,229 @@ +{ + "$id": "https://api.cerbos.dev/cerbos/policy/v1/TestResults/TestCase.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "cerbos.effect.v1.Effect": { + "type": "string", + "enum": [ + "EFFECT_UNSPECIFIED", + "EFFECT_ALLOW", + "EFFECT_DENY", + "EFFECT_NO_MATCH" + ] + }, + "cerbos.engine.v1.Trace": { + "type": "object", + "additionalProperties": false, + "properties": { + "components": { + "type": "array", + "items": { + "$ref": "#/definitions/cerbos.engine.v1.Trace.Component" + } + }, + "event": { + "$ref": "#/definitions/cerbos.engine.v1.Trace.Event" + } + } + }, + "cerbos.engine.v1.Trace.Component": { + "type": "object", + "additionalProperties": false, + "properties": { + "action": { + "type": "string" + }, + "derivedRole": { + "type": "string" + }, + "expr": { + "type": "string" + }, + "index": { + "type": "integer", + "minimum": 0 + }, + "kind": { + "$ref": "#/definitions/cerbos.engine.v1.Trace.Component.Kind" + }, + "policy": { + "type": "string" + }, + "resource": { + "type": "string" + }, + "rule": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "variable": { + "$ref": "#/definitions/cerbos.engine.v1.Trace.Component.Variable" + } + } + }, + "cerbos.engine.v1.Trace.Component.Kind": { + "type": "string", + "enum": [ + "KIND_UNSPECIFIED", + "KIND_ACTION", + "KIND_CONDITION_ALL", + "KIND_CONDITION_ANY", + "KIND_CONDITION_NONE", + "KIND_CONDITION", + "KIND_DERIVED_ROLE", + "KIND_EXPR", + "KIND_POLICY", + "KIND_RESOURCE", + "KIND_RULE", + "KIND_SCOPE", + "KIND_VARIABLE", + "KIND_VARIABLES" + ] + }, + "cerbos.engine.v1.Trace.Component.Variable": { + "type": "object", + "additionalProperties": false, + "properties": { + "expr": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "cerbos.engine.v1.Trace.Event": { + "type": "object", + "additionalProperties": false, + "properties": { + "effect": { + "$ref": "#/definitions/cerbos.effect.v1.Effect" + }, + "error": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/definitions/google.protobuf.Value" + }, + "status": { + "$ref": "#/definitions/cerbos.engine.v1.Trace.Event.Status" + } + } + }, + "cerbos.engine.v1.Trace.Event.Status": { + "type": "string", + "enum": [ + "STATUS_UNSPECIFIED", + "STATUS_ACTIVATED", + "STATUS_SKIPPED" + ] + }, + "cerbos.policy.v1.TestResults.Action": { + "type": "object", + "additionalProperties": false, + "properties": { + "details": { + "$ref": "#/definitions/cerbos.policy.v1.TestResults.Details" + }, + "name": { + "type": "string" + } + } + }, + "cerbos.policy.v1.TestResults.Details": { + "type": "object", + "additionalProperties": false, + "properties": { + "engineTrace": { + "type": "array", + "items": { + "$ref": "#/definitions/cerbos.engine.v1.Trace" + } + }, + "error": { + "type": "string" + }, + "failure": { + "$ref": "#/definitions/cerbos.policy.v1.TestResults.Failure" + }, + "result": { + "$ref": "#/definitions/cerbos.policy.v1.TestResults.Result" + } + } + }, + "cerbos.policy.v1.TestResults.Failure": { + "type": "object", + "additionalProperties": false, + "properties": { + "actual": { + "$ref": "#/definitions/cerbos.effect.v1.Effect" + }, + "expected": { + "$ref": "#/definitions/cerbos.effect.v1.Effect" + } + } + }, + "cerbos.policy.v1.TestResults.Principal": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "resources": { + "type": "array", + "items": { + "$ref": "#/definitions/cerbos.policy.v1.TestResults.Resource" + } + } + } + }, + "cerbos.policy.v1.TestResults.Resource": { + "type": "object", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array", + "items": { + "$ref": "#/definitions/cerbos.policy.v1.TestResults.Action" + } + }, + "name": { + "type": "string" + } + } + }, + "cerbos.policy.v1.TestResults.Result": { + "type": "string", + "enum": [ + "RESULT_UNSPECIFIED", + "RESULT_SKIPPED", + "RESULT_PASSED", + "RESULT_FAILED", + "RESULT_ERRORED" + ] + }, + "google.protobuf.Value": { + "title": "Value", + "description": "A dynamically-typed value." + } + }, + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "principals": { + "type": "array", + "items": { + "$ref": "#/definitions/cerbos.policy.v1.TestResults.Principal" + } + } + } +} diff --git a/schema/jsonschema/cerbos/response/v1/PlaygroundTestResponse.schema.json b/schema/jsonschema/cerbos/response/v1/PlaygroundTestResponse.schema.json index bc7674a3b..b7a996687 100644 --- a/schema/jsonschema/cerbos/response/v1/PlaygroundTestResponse.schema.json +++ b/schema/jsonschema/cerbos/response/v1/PlaygroundTestResponse.schema.json @@ -244,6 +244,12 @@ }, "summary": { "$ref": "#/definitions/cerbos.policy.v1.TestResults.Summary" + }, + "testCases": { + "type": "array", + "items": { + "$ref": "#/definitions/cerbos.policy.v1.TestResults.TestCase" + } } } }, @@ -279,6 +285,21 @@ } } }, + "cerbos.policy.v1.TestResults.TestCase": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "principals": { + "type": "array", + "items": { + "$ref": "#/definitions/cerbos.policy.v1.TestResults.Principal" + } + } + } + }, "cerbos.response.v1.PlaygroundFailure": { "type": "object", "additionalProperties": false, diff --git a/schema/jsonschema/cerbos/response/v1/PlaygroundTestResponse/TestResults.schema.json b/schema/jsonschema/cerbos/response/v1/PlaygroundTestResponse/TestResults.schema.json index 3cf6ff482..b5060d0d4 100644 --- a/schema/jsonschema/cerbos/response/v1/PlaygroundTestResponse/TestResults.schema.json +++ b/schema/jsonschema/cerbos/response/v1/PlaygroundTestResponse/TestResults.schema.json @@ -244,6 +244,12 @@ }, "summary": { "$ref": "#/definitions/cerbos.policy.v1.TestResults.Summary" + }, + "testCases": { + "type": "array", + "items": { + "$ref": "#/definitions/cerbos.policy.v1.TestResults.TestCase" + } } } }, @@ -279,6 +285,21 @@ } } }, + "cerbos.policy.v1.TestResults.TestCase": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "principals": { + "type": "array", + "items": { + "$ref": "#/definitions/cerbos.policy.v1.TestResults.Principal" + } + } + } + }, "google.protobuf.Value": { "title": "Value", "description": "A dynamically-typed value." diff --git a/schema/openapiv2/cerbos/svc/v1/svc.swagger.json b/schema/openapiv2/cerbos/svc/v1/svc.swagger.json index 9072d008b..7f4a6fa03 100644 --- a/schema/openapiv2/cerbos/svc/v1/svc.swagger.json +++ b/schema/openapiv2/cerbos/svc/v1/svc.swagger.json @@ -1320,6 +1320,13 @@ }, "error": { "type": "string" + }, + "testCases": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/TestResultsTestCase" + } } } }, @@ -1354,6 +1361,21 @@ } } }, + "TestResultsTestCase": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "principals": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1TestResultsPrincipal" + } + } + } + }, "TraceComponent": { "type": "object", "properties": {