diff --git a/internal/caveats/run.go b/internal/caveats/run.go index 9df2c66de..7d79e3d6f 100644 --- a/internal/caveats/run.go +++ b/internal/caveats/run.go @@ -381,6 +381,12 @@ type ExpressionResult interface { // MissingVarNames returns the names of the parameters missing from the context. MissingVarNames() ([]string, error) + + // LeafCaveatResults returns all leaf caveat evaluation results from this + // expression tree. For a leaf CaveatResult, this returns a single-element + // slice containing itself. For a synthetic (AND/OR/NOT) result, this + // recursively collects results from all children. + LeafCaveatResults() []*caveats.CaveatResult } type syntheticResult struct { @@ -424,6 +430,17 @@ func (sr syntheticResult) MissingVarNames() ([]string, error) { return nil, errors.New("not a partial value") } +// LeafCaveatResults collects all leaf CaveatResult values from the children +// of this synthetic result. This is used to build per-caveat diagnostics +// when a permission check is denied due to caveat evaluation. +func (sr syntheticResult) LeafCaveatResults() []*caveats.CaveatResult { + var results []*caveats.CaveatResult + for _, child := range sr.exprResultsForDebug { + results = append(results, child.LeafCaveatResults()...) + } + return results +} + func isFalseResult(result ExpressionResult) bool { return !result.Value() && !result.IsPartial() } diff --git a/internal/graph/computed/computecheck.go b/internal/graph/computed/computecheck.go index ebf26d0a1..a95e7a090 100644 --- a/internal/graph/computed/computecheck.go +++ b/internal/graph/computed/computecheck.go @@ -9,6 +9,7 @@ import ( "github.com/authzed/spicedb/pkg/datalayer" "github.com/authzed/spicedb/pkg/datastore" "github.com/authzed/spicedb/pkg/genutil/slicez" + core "github.com/authzed/spicedb/pkg/proto/core/v1" v1 "github.com/authzed/spicedb/pkg/proto/dispatch/v1" "github.com/authzed/spicedb/pkg/spiceerrors" "github.com/authzed/spicedb/pkg/tuple" @@ -153,7 +154,7 @@ func computeCheck(ctx context.Context, } for _, resourceID := range resourceIDsToCheck { - computed, err := computeCaveatedCheckResult(ctx, caveatRunner, params, resourceID, checkResult) + computed, err := computeCaveatedCheckResult(ctx, caveatRunner, params, resourceID, checkResult, params.DebugOption) if err != nil { return false, err } @@ -165,7 +166,7 @@ func computeCheck(ctx context.Context, return results, metadata, debugInfo, err } -func computeCaveatedCheckResult(ctx context.Context, runner *cexpr.CaveatRunner, params CheckParameters, resourceID string, checkResult *v1.DispatchCheckResponse) (*v1.ResourceCheckResult, error) { +func computeCaveatedCheckResult(ctx context.Context, runner *cexpr.CaveatRunner, params CheckParameters, resourceID string, checkResult *v1.DispatchCheckResponse, debugOption DebugOption) (*v1.ResourceCheckResult, error) { result, ok := checkResult.ResultsByResourceId[resourceID] if !ok { return &v1.ResourceCheckResult{ @@ -204,7 +205,87 @@ func computeCaveatedCheckResult(ctx context.Context, runner *cexpr.CaveatRunner, }, nil } + // The caveat evaluated to false, resulting in NOT_MEMBER. + // Only collect per-caveat diagnostics when debugging is enabled, to avoid + // leaking caveat expression internals and context values in production + // responses, and to avoid the cost of re-evaluation on the hot path. + if debugOption != NoDebugging { + caveatEvalInfo, err := collectCaveatEvalInfo(ctx, runner, result.Expression, params.CaveatContext, sr) + if err != nil { + // If we fail to collect diagnostics, still return the NOT_MEMBER result + // without diagnostics rather than failing the entire check. + return &v1.ResourceCheckResult{ + Membership: v1.ResourceCheckResult_NOT_MEMBER, + }, nil + } + + return &v1.ResourceCheckResult{ + Membership: v1.ResourceCheckResult_NOT_MEMBER, + CaveatEvalInfo: caveatEvalInfo, + }, nil + } + return &v1.ResourceCheckResult{ Membership: v1.ResourceCheckResult_NOT_MEMBER, }, nil } + +// collectCaveatEvalInfo re-evaluates a caveat expression with debug information +// enabled to collect per-leaf caveat evaluation results. This is called only when +// the initial evaluation returned false (NOT_MEMBER), so the re-evaluation cost +// is acceptable since the request is already denied. +// +// This addresses https://github.com/authzed/spicedb/issues/2802 by providing +// applications with information about which specific caveat(s) caused a denial. +func collectCaveatEvalInfo( + ctx context.Context, + runner *cexpr.CaveatRunner, + expr *core.CaveatExpression, + caveatContext map[string]any, + reader cexpr.CaveatDefinitionLookup, +) ([]*v1.CaveatEvalResult, error) { + // Re-run with debug information to collect leaf results. + debugResult, err := runner.RunCaveatExpression(ctx, expr, caveatContext, reader, cexpr.RunCaveatExpressionWithDebugInformation) + if err != nil { + return nil, err + } + + leafResults := debugResult.LeafCaveatResults() + if len(leafResults) == 0 { + return nil, nil + } + + evalResults := make([]*v1.CaveatEvalResult, 0, len(leafResults)) + for _, leaf := range leafResults { + evalResult := &v1.CaveatEvalResult{ + CaveatName: leaf.ParentCaveat().Name(), + } + + // Determine the result. + if leaf.IsPartial() { + evalResult.Result = v1.CaveatEvalResult_RESULT_MISSING_SOME_CONTEXT + missingNames, _ := leaf.MissingVarNames() + evalResult.MissingContextParams = missingNames + } else if leaf.Value() { + evalResult.Result = v1.CaveatEvalResult_RESULT_TRUE + } else { + evalResult.Result = v1.CaveatEvalResult_RESULT_FALSE + } + + // Collect the expression string. + exprString, err := leaf.ExpressionString() + if err == nil { + evalResult.ExpressionString = exprString + } + + // Collect the context values used during evaluation. + contextStruct, err := leaf.ContextStruct() + if err == nil { + evalResult.Context = contextStruct + } + + evalResults = append(evalResults, evalResult) + } + + return evalResults, nil +} diff --git a/internal/graph/computed/computecheck_test.go b/internal/graph/computed/computecheck_test.go index 76f318182..bc2505f55 100644 --- a/internal/graph/computed/computecheck_test.go +++ b/internal/graph/computed/computecheck_test.go @@ -854,6 +854,206 @@ func TestComputeCheckWithCaveats(t *testing.T) { } } +func TestComputeCheckCaveatEvalDiagnostics(t *testing.T) { + testCases := []struct { + name string + schema string + updates []caveatedUpdate + check string + context map[string]any + expectedMembership v1.ResourceCheckResult_Membership + expectedCaveatNames []string // expected caveat names in CaveatEvalInfo + expectedFalseCount int // number of caveats expected to be FALSE + }{ + { + "single caveat evaluates to false", + `definition user {} + + definition document { + relation viewer: user | user with testcaveat + permission view = viewer + } + + caveat testcaveat(somecondition int) { + somecondition == 42 + }`, + []caveatedUpdate{ + {tuple.UpdateOperationCreate, "document:foo#viewer@user:tom", "testcaveat", nil}, + }, + "document:foo#view@user:tom", + map[string]any{"somecondition": "41"}, + v1.ResourceCheckResult_NOT_MEMBER, + []string{"testcaveat"}, + 1, + }, + { + "caveat false due to written context taking precedence", + `definition user {} + + definition document { + relation viewer: user | user with testcaveat + permission view = viewer + } + + caveat testcaveat(somecondition int) { + somecondition == 42 + }`, + []caveatedUpdate{ + {tuple.UpdateOperationCreate, "document:foo#viewer@user:tom", "testcaveat", map[string]any{ + "somecondition": 41, // written context says 41 (not 42) + }}, + }, + "document:foo#view@user:tom", + map[string]any{"somecondition": 42}, // request context says 42, but written takes precedence + v1.ResourceCheckResult_NOT_MEMBER, + []string{"testcaveat"}, + 1, + }, + { + "intersection with one false caveat", + `definition user {} + + definition document { + relation viewer: user | user with viewcaveat + relation editor: user | user with editcaveat + permission view_and_edit = viewer & editor + } + + caveat viewcaveat(somecondition int) { + somecondition == 42 + } + + caveat editcaveat(today string) { + today == 'tuesday' + }`, + []caveatedUpdate{ + {tuple.UpdateOperationCreate, "document:foo#viewer@user:tom", "viewcaveat", nil}, + {tuple.UpdateOperationCreate, "document:foo#editor@user:tom", "editcaveat", nil}, + }, + "document:foo#view_and_edit@user:tom", + map[string]any{"somecondition": "42", "today": "wednesday"}, + v1.ResourceCheckResult_NOT_MEMBER, + // Both leaf caveats are returned: viewcaveat (TRUE) and editcaveat (FALSE). + // This lets applications see the full evaluation picture. + []string{"editcaveat", "viewcaveat"}, + 1, // only editcaveat is FALSE + }, + { + "no caveat eval info for non-caveated NOT_MEMBER", + `definition user {} + + definition document { + relation viewer: user + permission view = viewer + }`, + []caveatedUpdate{ + {tuple.UpdateOperationCreate, "document:foo#viewer@user:alice", "", nil}, + }, + "document:foo#view@user:tom", + nil, + v1.ResourceCheckResult_NOT_MEMBER, + nil, // no caveat eval info expected + 0, + }, + { + "no caveat eval info for MEMBER result", + `definition user {} + + definition document { + relation viewer: user | user with testcaveat + permission view = viewer + } + + caveat testcaveat(somecondition int) { + somecondition == 42 + }`, + []caveatedUpdate{ + {tuple.UpdateOperationCreate, "document:foo#viewer@user:tom", "testcaveat", nil}, + }, + "document:foo#view@user:tom", + map[string]any{"somecondition": "42"}, + v1.ResourceCheckResult_MEMBER, + nil, // no caveat eval info expected for allowed results + 0, + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + ds, err := dsfortesting.NewMemDBDatastoreForTesting(t, 0, 0, memdb.DisableGC) + require.NoError(t, err) + + dispatch, err := graph.NewLocalOnlyDispatcher(graph.MustNewDefaultDispatcherParametersForTesting()) + require.NoError(t, err) + ctx := log.Logger.WithContext(datalayer.ContextWithHandle(t.Context())) + require.NoError(t, datalayer.SetInContext(ctx, datalayer.NewDataLayer(ds))) + + revision, err := writeCaveatedTuples(ctx, t, ds, tt.schema, tt.updates) + require.NoError(t, err) + + rel := tuple.MustParse(tt.check) + + // With debugging enabled, diagnostics should be populated on denial. + result, _, err := computed.ComputeCheck(ctx, dispatch, + caveattypes.Default.TypeSet, + computed.CheckParameters{ + ResourceType: rel.Resource.RelationReference(), + Subject: rel.Subject, + CaveatContext: tt.context, + AtRevision: revision, + MaximumDepth: 50, + DebugOption: computed.BasicDebuggingEnabled, + }, + rel.Resource.ObjectID, + 100, + ) + require.NoError(t, err) + require.Equal(t, tt.expectedMembership, result.Membership, "unexpected membership for %s", tt.check) + + // Verify that without debugging, diagnostics are NOT populated + // (to avoid leaking caveat internals in production). + resultNoDebug, _, err := computed.ComputeCheck(ctx, dispatch, + caveattypes.Default.TypeSet, + computed.CheckParameters{ + ResourceType: rel.Resource.RelationReference(), + Subject: rel.Subject, + CaveatContext: tt.context, + AtRevision: revision, + MaximumDepth: 50, + DebugOption: computed.NoDebugging, + }, + rel.Resource.ObjectID, + 100, + ) + require.NoError(t, err) + require.Empty(t, resultNoDebug.CaveatEvalInfo, "diagnostics must not be populated without debug mode") + + if tt.expectedCaveatNames == nil { + require.Empty(t, result.CaveatEvalInfo, "expected no caveat eval info") + } else { + require.NotEmpty(t, result.CaveatEvalInfo, "expected caveat eval info to be populated") + + // Collect caveat names from results + var caveatNames []string + falseCount := 0 + for _, evalInfo := range result.CaveatEvalInfo { + caveatNames = append(caveatNames, evalInfo.CaveatName) + if evalInfo.Result == v1.CaveatEvalResult_RESULT_FALSE { + falseCount++ + } + // Verify expression string is populated + require.NotEmpty(t, evalInfo.ExpressionString, "expected expression string for caveat %s", evalInfo.CaveatName) + } + + sort.Strings(caveatNames) + sort.Strings(tt.expectedCaveatNames) + require.Equal(t, tt.expectedCaveatNames, caveatNames, "unexpected caveat names in eval info") + require.Equal(t, tt.expectedFalseCount, falseCount, "unexpected number of FALSE results") + } + }) + } +} + func TestComputeCheckError(t *testing.T) { ds, err := dsfortesting.NewMemDBDatastoreForTesting(t, 0, 0, memdb.DisableGC) require.NoError(t, err) diff --git a/internal/services/v1/permissions.go b/internal/services/v1/permissions.go index ab7f304fa..2307c1a11 100644 --- a/internal/services/v1/permissions.go +++ b/internal/services/v1/permissions.go @@ -3,6 +3,7 @@ package v1 import ( "cmp" "context" + "encoding/json" "errors" "fmt" "io" @@ -165,6 +166,15 @@ func (ps *permissionServer) CheckPermission(ctx context.Context, req *v1.CheckPe permissionship, partialCaveat := checkResultToAPITypes(cr) + // If the check was denied due to caveat evaluation and debug/tracing was + // requested, surface per-caveat diagnostic information via gRPC response + // trailer metadata. This is gated behind debug mode to avoid leaking caveat + // expression internals in production responses. + // See https://github.com/authzed/spicedb/issues/2802 + if permissionship == v1.CheckPermissionResponse_PERMISSIONSHIP_NO_PERMISSION && len(cr.CaveatEvalInfo) > 0 { + setCaveatEvalDiagnosticsTrailer(ctx, cr.CaveatEvalInfo) + } + return &v1.CheckPermissionResponse{ CheckedAt: checkedAt, Permissionship: permissionship, @@ -188,6 +198,70 @@ func checkResultToAPITypes(cr *dispatch.ResourceCheckResult) (v1.CheckPermission return permissionship, partialCaveat } +// CaveatEvalDiagnosticsTrailerKey is the gRPC response trailer key for caveat evaluation +// diagnostics. When a CheckPermission call returns NO_PERMISSION due to one or more caveats +// evaluating to false, this trailer contains a JSON-encoded array of caveat evaluation results +// identifying which specific caveat(s) caused the denial. +// +// This addresses https://github.com/authzed/spicedb/issues/2802 +const CaveatEvalDiagnosticsTrailerKey = "io.spicedb.respmeta.caveat-eval-info" + +// setCaveatEvalDiagnosticsTrailer sets gRPC response trailer metadata with caveat evaluation +// diagnostic information. This allows applications to identify which specific caveat(s) +// caused a permission denial without requiring debug mode. +func setCaveatEvalDiagnosticsTrailer(ctx context.Context, evalInfo []*dispatch.CaveatEvalResult) { + if len(evalInfo) == 0 { + return + } + + // Build a JSON representation of the caveat eval results. + // We use a simple JSON format rather than proto serialization for ease of consumption + // by client libraries in any language. + type caveatEvalEntry struct { + CaveatName string `json:"caveat_name"` + Result string `json:"result"` + ExpressionString string `json:"expression,omitempty"` + Context map[string]any `json:"context,omitempty"` + MissingContextParams []string `json:"missing_context_params,omitempty"` + } + + entries := make([]caveatEvalEntry, 0, len(evalInfo)) + for _, info := range evalInfo { + resultStr := "UNSPECIFIED" + switch info.Result { + case dispatch.CaveatEvalResult_RESULT_FALSE: + resultStr = "FALSE" + case dispatch.CaveatEvalResult_RESULT_TRUE: + resultStr = "TRUE" + case dispatch.CaveatEvalResult_RESULT_MISSING_SOME_CONTEXT: + resultStr = "MISSING_SOME_CONTEXT" + case dispatch.CaveatEvalResult_RESULT_UNEVALUATED: + resultStr = "UNEVALUATED" + } + + entry := caveatEvalEntry{ + CaveatName: info.CaveatName, + Result: resultStr, + ExpressionString: info.ExpressionString, + MissingContextParams: info.MissingContextParams, + } + + if info.Context != nil { + entry.Context = info.Context.AsMap() + } + + entries = append(entries, entry) + } + + jsonBytes, err := json.Marshal(entries) + if err != nil { + return // Silently skip if marshaling fails — don't fail the request + } + + md := metadata.Pairs(CaveatEvalDiagnosticsTrailerKey, string(jsonBytes)) + _ = grpc.SetTrailer(ctx, md) +} + func (ps *permissionServer) CheckBulkPermissions(ctx context.Context, req *v1.CheckBulkPermissionsRequest) (*v1.CheckBulkPermissionsResponse, error) { // NOTE: perfinsights are added for the individual check results as well, so there is no shape here. perfinsights.SetInContext(ctx, perfinsights.NoLabels) diff --git a/pkg/caveats/eval.go b/pkg/caveats/eval.go index d8d7d1bbd..d79869642 100644 --- a/pkg/caveats/eval.go +++ b/pkg/caveats/eval.go @@ -84,6 +84,12 @@ func (cr CaveatResult) MissingVarNames() ([]string, error) { return cr.missingVarNames, nil } +// LeafCaveatResults returns this CaveatResult as a single-element slice. +// CaveatResult is a leaf node in the expression tree, so it returns itself. +func (cr *CaveatResult) LeafCaveatResults() []*CaveatResult { + return []*CaveatResult{cr} +} + // EvaluateCaveat evaluates the compiled caveat with the specified values, and returns // the result or an error. func EvaluateCaveat(caveat *CompiledCaveat, contextValues map[string]any) (*CaveatResult, error) { diff --git a/pkg/proto/dispatch/v1/dispatch.pb.go b/pkg/proto/dispatch/v1/dispatch.pb.go index 6ac2f9529..c46ca9147 100644 --- a/pkg/proto/dispatch/v1/dispatch.pb.go +++ b/pkg/proto/dispatch/v1/dispatch.pb.go @@ -172,6 +172,61 @@ func (ResourceCheckResult_Membership) EnumDescriptor() ([]byte, []int) { return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{3, 0} } +type CaveatEvalResult_Result int32 + +const ( + CaveatEvalResult_RESULT_UNSPECIFIED CaveatEvalResult_Result = 0 + CaveatEvalResult_RESULT_UNEVALUATED CaveatEvalResult_Result = 1 + CaveatEvalResult_RESULT_FALSE CaveatEvalResult_Result = 2 + CaveatEvalResult_RESULT_TRUE CaveatEvalResult_Result = 3 + CaveatEvalResult_RESULT_MISSING_SOME_CONTEXT CaveatEvalResult_Result = 4 +) + +// Enum value maps for CaveatEvalResult_Result. +var ( + CaveatEvalResult_Result_name = map[int32]string{ + 0: "RESULT_UNSPECIFIED", + 1: "RESULT_UNEVALUATED", + 2: "RESULT_FALSE", + 3: "RESULT_TRUE", + 4: "RESULT_MISSING_SOME_CONTEXT", + } + CaveatEvalResult_Result_value = map[string]int32{ + "RESULT_UNSPECIFIED": 0, + "RESULT_UNEVALUATED": 1, + "RESULT_FALSE": 2, + "RESULT_TRUE": 3, + "RESULT_MISSING_SOME_CONTEXT": 4, + } +) + +func (x CaveatEvalResult_Result) Enum() *CaveatEvalResult_Result { + p := new(CaveatEvalResult_Result) + *p = x + return p +} + +func (x CaveatEvalResult_Result) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CaveatEvalResult_Result) Descriptor() protoreflect.EnumDescriptor { + return file_dispatch_v1_dispatch_proto_enumTypes[3].Descriptor() +} + +func (CaveatEvalResult_Result) Type() protoreflect.EnumType { + return &file_dispatch_v1_dispatch_proto_enumTypes[3] +} + +func (x CaveatEvalResult_Result) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CaveatEvalResult_Result.Descriptor instead. +func (CaveatEvalResult_Result) EnumDescriptor() ([]byte, []int) { + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{4, 0} +} + type DispatchExpandRequest_ExpansionMode int32 const ( @@ -202,11 +257,11 @@ func (x DispatchExpandRequest_ExpansionMode) String() string { } func (DispatchExpandRequest_ExpansionMode) Descriptor() protoreflect.EnumDescriptor { - return file_dispatch_v1_dispatch_proto_enumTypes[3].Descriptor() + return file_dispatch_v1_dispatch_proto_enumTypes[4].Descriptor() } func (DispatchExpandRequest_ExpansionMode) Type() protoreflect.EnumType { - return &file_dispatch_v1_dispatch_proto_enumTypes[3] + return &file_dispatch_v1_dispatch_proto_enumTypes[4] } func (x DispatchExpandRequest_ExpansionMode) Number() protoreflect.EnumNumber { @@ -215,7 +270,7 @@ func (x DispatchExpandRequest_ExpansionMode) Number() protoreflect.EnumNumber { // Deprecated: Use DispatchExpandRequest_ExpansionMode.Descriptor instead. func (DispatchExpandRequest_ExpansionMode) EnumDescriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{4, 0} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{5, 0} } type CheckDebugTrace_RelationType int32 @@ -251,11 +306,11 @@ func (x CheckDebugTrace_RelationType) String() string { } func (CheckDebugTrace_RelationType) Descriptor() protoreflect.EnumDescriptor { - return file_dispatch_v1_dispatch_proto_enumTypes[4].Descriptor() + return file_dispatch_v1_dispatch_proto_enumTypes[5].Descriptor() } func (CheckDebugTrace_RelationType) Type() protoreflect.EnumType { - return &file_dispatch_v1_dispatch_proto_enumTypes[4] + return &file_dispatch_v1_dispatch_proto_enumTypes[5] } func (x CheckDebugTrace_RelationType) Number() protoreflect.EnumNumber { @@ -264,7 +319,7 @@ func (x CheckDebugTrace_RelationType) Number() protoreflect.EnumNumber { // Deprecated: Use CheckDebugTrace_RelationType.Descriptor instead. func (CheckDebugTrace_RelationType) EnumDescriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{20, 0} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{21, 0} } type DispatchCheckRequest struct { @@ -490,8 +545,14 @@ type ResourceCheckResult struct { Membership ResourceCheckResult_Membership `protobuf:"varint,1,opt,name=membership,proto3,enum=dispatch.v1.ResourceCheckResult_Membership" json:"membership,omitempty"` Expression *v1.CaveatExpression `protobuf:"bytes,2,opt,name=expression,proto3" json:"expression,omitempty"` MissingExprFields []string `protobuf:"bytes,3,rep,name=missing_expr_fields,json=missingExprFields,proto3" json:"missing_expr_fields,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // caveat_eval_info contains information about caveats that were evaluated + // during the permission check. When a caveated permission check results in + // NOT_MEMBER because a caveat evaluated to false, this field identifies which + // caveat(s) failed and provides their evaluation context. + // This addresses https://github.com/authzed/spicedb/issues/2802 + CaveatEvalInfo []*CaveatEvalResult `protobuf:"bytes,4,rep,name=caveat_eval_info,json=caveatEvalInfo,proto3" json:"caveat_eval_info,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ResourceCheckResult) Reset() { @@ -545,6 +606,98 @@ func (x *ResourceCheckResult) GetMissingExprFields() []string { return nil } +func (x *ResourceCheckResult) GetCaveatEvalInfo() []*CaveatEvalResult { + if x != nil { + return x.CaveatEvalInfo + } + return nil +} + +// CaveatEvalResult contains the evaluation result of a single caveat during +// a permission check. This enables applications to identify which specific +// caveat caused a permission denial. +type CaveatEvalResult struct { + state protoimpl.MessageState `protogen:"open.v1"` + // caveat_name is the name of the caveat that was evaluated. + CaveatName string `protobuf:"bytes,1,opt,name=caveat_name,json=caveatName,proto3" json:"caveat_name,omitempty"` + // result is the evaluation result of the caveat. + Result CaveatEvalResult_Result `protobuf:"varint,2,opt,name=result,proto3,enum=dispatch.v1.CaveatEvalResult_Result" json:"result,omitempty"` + // context contains the context values that were used during evaluation. + Context *structpb.Struct `protobuf:"bytes,3,opt,name=context,proto3" json:"context,omitempty"` + // expression_string is the human-readable CEL expression of the caveat. + ExpressionString string `protobuf:"bytes,4,opt,name=expression_string,json=expressionString,proto3" json:"expression_string,omitempty"` + // missing_context_params lists parameter names that were missing during + // evaluation, resulting in a partial/conditional result. + MissingContextParams []string `protobuf:"bytes,5,rep,name=missing_context_params,json=missingContextParams,proto3" json:"missing_context_params,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CaveatEvalResult) Reset() { + *x = CaveatEvalResult{} + mi := &file_dispatch_v1_dispatch_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CaveatEvalResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CaveatEvalResult) ProtoMessage() {} + +func (x *CaveatEvalResult) ProtoReflect() protoreflect.Message { + mi := &file_dispatch_v1_dispatch_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CaveatEvalResult.ProtoReflect.Descriptor instead. +func (*CaveatEvalResult) Descriptor() ([]byte, []int) { + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{4} +} + +func (x *CaveatEvalResult) GetCaveatName() string { + if x != nil { + return x.CaveatName + } + return "" +} + +func (x *CaveatEvalResult) GetResult() CaveatEvalResult_Result { + if x != nil { + return x.Result + } + return CaveatEvalResult_RESULT_UNSPECIFIED +} + +func (x *CaveatEvalResult) GetContext() *structpb.Struct { + if x != nil { + return x.Context + } + return nil +} + +func (x *CaveatEvalResult) GetExpressionString() string { + if x != nil { + return x.ExpressionString + } + return "" +} + +func (x *CaveatEvalResult) GetMissingContextParams() []string { + if x != nil { + return x.MissingContextParams + } + return nil +} + type DispatchExpandRequest struct { state protoimpl.MessageState `protogen:"open.v1"` Metadata *ResolverMeta `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` @@ -556,7 +709,7 @@ type DispatchExpandRequest struct { func (x *DispatchExpandRequest) Reset() { *x = DispatchExpandRequest{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[4] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -568,7 +721,7 @@ func (x *DispatchExpandRequest) String() string { func (*DispatchExpandRequest) ProtoMessage() {} func (x *DispatchExpandRequest) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[4] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -581,7 +734,7 @@ func (x *DispatchExpandRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DispatchExpandRequest.ProtoReflect.Descriptor instead. func (*DispatchExpandRequest) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{4} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{5} } func (x *DispatchExpandRequest) GetMetadata() *ResolverMeta { @@ -615,7 +768,7 @@ type DispatchExpandResponse struct { func (x *DispatchExpandResponse) Reset() { *x = DispatchExpandResponse{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[5] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -627,7 +780,7 @@ func (x *DispatchExpandResponse) String() string { func (*DispatchExpandResponse) ProtoMessage() {} func (x *DispatchExpandResponse) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[5] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -640,7 +793,7 @@ func (x *DispatchExpandResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DispatchExpandResponse.ProtoReflect.Descriptor instead. func (*DispatchExpandResponse) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{5} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{6} } func (x *DispatchExpandResponse) GetMetadata() *ResponseMeta { @@ -667,7 +820,7 @@ type Cursor struct { func (x *Cursor) Reset() { *x = Cursor{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[6] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -679,7 +832,7 @@ func (x *Cursor) String() string { func (*Cursor) ProtoMessage() {} func (x *Cursor) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[6] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -692,7 +845,7 @@ func (x *Cursor) ProtoReflect() protoreflect.Message { // Deprecated: Use Cursor.ProtoReflect.Descriptor instead. func (*Cursor) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{6} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{7} } func (x *Cursor) GetSections() []string { @@ -725,7 +878,7 @@ type DispatchLookupResources2Request struct { func (x *DispatchLookupResources2Request) Reset() { *x = DispatchLookupResources2Request{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[7] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -737,7 +890,7 @@ func (x *DispatchLookupResources2Request) String() string { func (*DispatchLookupResources2Request) ProtoMessage() {} func (x *DispatchLookupResources2Request) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[7] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -750,7 +903,7 @@ func (x *DispatchLookupResources2Request) ProtoReflect() protoreflect.Message { // Deprecated: Use DispatchLookupResources2Request.ProtoReflect.Descriptor instead. func (*DispatchLookupResources2Request) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{7} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{8} } func (x *DispatchLookupResources2Request) GetMetadata() *ResolverMeta { @@ -820,7 +973,7 @@ type PossibleResource struct { func (x *PossibleResource) Reset() { *x = PossibleResource{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[8] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -832,7 +985,7 @@ func (x *PossibleResource) String() string { func (*PossibleResource) ProtoMessage() {} func (x *PossibleResource) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[8] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -845,7 +998,7 @@ func (x *PossibleResource) ProtoReflect() protoreflect.Message { // Deprecated: Use PossibleResource.ProtoReflect.Descriptor instead. func (*PossibleResource) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{8} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{9} } func (x *PossibleResource) GetResourceId() string { @@ -880,7 +1033,7 @@ type DispatchLookupResources2Response struct { func (x *DispatchLookupResources2Response) Reset() { *x = DispatchLookupResources2Response{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[9] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -892,7 +1045,7 @@ func (x *DispatchLookupResources2Response) String() string { func (*DispatchLookupResources2Response) ProtoMessage() {} func (x *DispatchLookupResources2Response) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[9] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -905,7 +1058,7 @@ func (x *DispatchLookupResources2Response) ProtoReflect() protoreflect.Message { // Deprecated: Use DispatchLookupResources2Response.ProtoReflect.Descriptor instead. func (*DispatchLookupResources2Response) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{9} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{10} } func (x *DispatchLookupResources2Response) GetResource() *PossibleResource { @@ -945,7 +1098,7 @@ type DispatchLookupResources3Request struct { func (x *DispatchLookupResources3Request) Reset() { *x = DispatchLookupResources3Request{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[10] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -957,7 +1110,7 @@ func (x *DispatchLookupResources3Request) String() string { func (*DispatchLookupResources3Request) ProtoMessage() {} func (x *DispatchLookupResources3Request) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[10] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -970,7 +1123,7 @@ func (x *DispatchLookupResources3Request) ProtoReflect() protoreflect.Message { // Deprecated: Use DispatchLookupResources3Request.ProtoReflect.Descriptor instead. func (*DispatchLookupResources3Request) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{10} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{11} } func (x *DispatchLookupResources3Request) GetMetadata() *ResolverMeta { @@ -1038,7 +1191,7 @@ type DispatchLookupResources3Response struct { func (x *DispatchLookupResources3Response) Reset() { *x = DispatchLookupResources3Response{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[11] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1050,7 +1203,7 @@ func (x *DispatchLookupResources3Response) String() string { func (*DispatchLookupResources3Response) ProtoMessage() {} func (x *DispatchLookupResources3Response) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[11] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1063,7 +1216,7 @@ func (x *DispatchLookupResources3Response) ProtoReflect() protoreflect.Message { // Deprecated: Use DispatchLookupResources3Response.ProtoReflect.Descriptor instead. func (*DispatchLookupResources3Response) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{11} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{12} } func (x *DispatchLookupResources3Response) GetItems() []*LR3Item { @@ -1085,7 +1238,7 @@ type LR3Item struct { func (x *LR3Item) Reset() { *x = LR3Item{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[12] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1097,7 +1250,7 @@ func (x *LR3Item) String() string { func (*LR3Item) ProtoMessage() {} func (x *LR3Item) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[12] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1110,7 +1263,7 @@ func (x *LR3Item) ProtoReflect() protoreflect.Message { // Deprecated: Use LR3Item.ProtoReflect.Descriptor instead. func (*LR3Item) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{12} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{13} } func (x *LR3Item) GetResourceId() string { @@ -1153,7 +1306,7 @@ type DispatchLookupSubjectsRequest struct { func (x *DispatchLookupSubjectsRequest) Reset() { *x = DispatchLookupSubjectsRequest{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[13] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1165,7 +1318,7 @@ func (x *DispatchLookupSubjectsRequest) String() string { func (*DispatchLookupSubjectsRequest) ProtoMessage() {} func (x *DispatchLookupSubjectsRequest) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[13] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1178,7 +1331,7 @@ func (x *DispatchLookupSubjectsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DispatchLookupSubjectsRequest.ProtoReflect.Descriptor instead. func (*DispatchLookupSubjectsRequest) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{13} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{14} } func (x *DispatchLookupSubjectsRequest) GetMetadata() *ResolverMeta { @@ -1220,7 +1373,7 @@ type FoundSubject struct { func (x *FoundSubject) Reset() { *x = FoundSubject{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[14] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1232,7 +1385,7 @@ func (x *FoundSubject) String() string { func (*FoundSubject) ProtoMessage() {} func (x *FoundSubject) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[14] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1245,7 +1398,7 @@ func (x *FoundSubject) ProtoReflect() protoreflect.Message { // Deprecated: Use FoundSubject.ProtoReflect.Descriptor instead. func (*FoundSubject) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{14} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{15} } func (x *FoundSubject) GetSubjectId() string { @@ -1278,7 +1431,7 @@ type FoundSubjects struct { func (x *FoundSubjects) Reset() { *x = FoundSubjects{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[15] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1290,7 +1443,7 @@ func (x *FoundSubjects) String() string { func (*FoundSubjects) ProtoMessage() {} func (x *FoundSubjects) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[15] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1303,7 +1456,7 @@ func (x *FoundSubjects) ProtoReflect() protoreflect.Message { // Deprecated: Use FoundSubjects.ProtoReflect.Descriptor instead. func (*FoundSubjects) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{15} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{16} } func (x *FoundSubjects) GetFoundSubjects() []*FoundSubject { @@ -1323,7 +1476,7 @@ type DispatchLookupSubjectsResponse struct { func (x *DispatchLookupSubjectsResponse) Reset() { *x = DispatchLookupSubjectsResponse{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[16] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1335,7 +1488,7 @@ func (x *DispatchLookupSubjectsResponse) String() string { func (*DispatchLookupSubjectsResponse) ProtoMessage() {} func (x *DispatchLookupSubjectsResponse) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[16] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1348,7 +1501,7 @@ func (x *DispatchLookupSubjectsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DispatchLookupSubjectsResponse.ProtoReflect.Descriptor instead. func (*DispatchLookupSubjectsResponse) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{16} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{17} } func (x *DispatchLookupSubjectsResponse) GetFoundSubjectsByResourceId() map[string]*FoundSubjects { @@ -1378,7 +1531,7 @@ type ResolverMeta struct { func (x *ResolverMeta) Reset() { *x = ResolverMeta{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[17] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1390,7 +1543,7 @@ func (x *ResolverMeta) String() string { func (*ResolverMeta) ProtoMessage() {} func (x *ResolverMeta) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[17] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1403,7 +1556,7 @@ func (x *ResolverMeta) ProtoReflect() protoreflect.Message { // Deprecated: Use ResolverMeta.ProtoReflect.Descriptor instead. func (*ResolverMeta) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{17} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{18} } func (x *ResolverMeta) GetAtRevision() string { @@ -1447,7 +1600,7 @@ type ResponseMeta struct { func (x *ResponseMeta) Reset() { *x = ResponseMeta{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[18] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1459,7 +1612,7 @@ func (x *ResponseMeta) String() string { func (*ResponseMeta) ProtoMessage() {} func (x *ResponseMeta) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[18] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1472,7 +1625,7 @@ func (x *ResponseMeta) ProtoReflect() protoreflect.Message { // Deprecated: Use ResponseMeta.ProtoReflect.Descriptor instead. func (*ResponseMeta) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{18} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{19} } func (x *ResponseMeta) GetDispatchCount() uint32 { @@ -1512,7 +1665,7 @@ type DebugInformation struct { func (x *DebugInformation) Reset() { *x = DebugInformation{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[19] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1524,7 +1677,7 @@ func (x *DebugInformation) String() string { func (*DebugInformation) ProtoMessage() {} func (x *DebugInformation) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[19] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1537,7 +1690,7 @@ func (x *DebugInformation) ProtoReflect() protoreflect.Message { // Deprecated: Use DebugInformation.ProtoReflect.Descriptor instead. func (*DebugInformation) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{19} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{20} } func (x *DebugInformation) GetCheck() *CheckDebugTrace { @@ -1563,7 +1716,7 @@ type CheckDebugTrace struct { func (x *CheckDebugTrace) Reset() { *x = CheckDebugTrace{} - mi := &file_dispatch_v1_dispatch_proto_msgTypes[20] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1575,7 +1728,7 @@ func (x *CheckDebugTrace) String() string { func (*CheckDebugTrace) ProtoMessage() {} func (x *CheckDebugTrace) ProtoReflect() protoreflect.Message { - mi := &file_dispatch_v1_dispatch_proto_msgTypes[20] + mi := &file_dispatch_v1_dispatch_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1588,7 +1741,7 @@ func (x *CheckDebugTrace) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckDebugTrace.ProtoReflect.Descriptor instead. func (*CheckDebugTrace) Descriptor() ([]byte, []int) { - return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{20} + return file_dispatch_v1_dispatch_proto_rawDescGZIP(), []int{21} } func (x *CheckDebugTrace) GetRequest() *DispatchCheckRequest { @@ -1678,7 +1831,7 @@ const file_dispatch_v1_dispatch_proto_rawDesc = "" + "\x16results_by_resource_id\x18\x02 \x03(\v2;.dispatch.v1.DispatchCheckResponse.ResultsByResourceIdEntryR\x13resultsByResourceId\x1ah\n" + "\x18ResultsByResourceIdEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x126\n" + - "\x05value\x18\x02 \x01(\v2 .dispatch.v1.ResourceCheckResultR\x05value:\x028\x01\"\x99\x02\n" + + "\x05value\x18\x02 \x01(\v2 .dispatch.v1.ResourceCheckResultR\x05value:\x028\x01\"\xe2\x02\n" + "\x13ResourceCheckResult\x12K\n" + "\n" + "membership\x18\x01 \x01(\x0e2+.dispatch.v1.ResourceCheckResult.MembershipR\n" + @@ -1686,7 +1839,8 @@ const file_dispatch_v1_dispatch_proto_rawDesc = "" + "\n" + "expression\x18\x02 \x01(\v2\x19.core.v1.CaveatExpressionR\n" + "expression\x12.\n" + - "\x13missing_expr_fields\x18\x03 \x03(\tR\x11missingExprFields\"J\n" + + "\x13missing_expr_fields\x18\x03 \x03(\tR\x11missingExprFields\x12G\n" + + "\x10caveat_eval_info\x18\x04 \x03(\v2\x1d.dispatch.v1.CaveatEvalResultR\x0ecaveatEvalInfo\"J\n" + "\n" + "Membership\x12\v\n" + "\aUNKNOWN\x10\x00\x12\x0e\n" + @@ -1694,7 +1848,20 @@ const file_dispatch_v1_dispatch_proto_rawDesc = "" + "NOT_MEMBER\x10\x01\x12\n" + "\n" + "\x06MEMBER\x10\x02\x12\x13\n" + - "\x0fCAVEATED_MEMBER\x10\x03\"\xb8\x02\n" + + "\x0fCAVEATED_MEMBER\x10\x03\"\x85\x03\n" + + "\x10CaveatEvalResult\x12\x1f\n" + + "\vcaveat_name\x18\x01 \x01(\tR\n" + + "caveatName\x12<\n" + + "\x06result\x18\x02 \x01(\x0e2$.dispatch.v1.CaveatEvalResult.ResultR\x06result\x121\n" + + "\acontext\x18\x03 \x01(\v2\x17.google.protobuf.StructR\acontext\x12+\n" + + "\x11expression_string\x18\x04 \x01(\tR\x10expressionString\x124\n" + + "\x16missing_context_params\x18\x05 \x03(\tR\x14missingContextParams\"|\n" + + "\x06Result\x12\x16\n" + + "\x12RESULT_UNSPECIFIED\x10\x00\x12\x16\n" + + "\x12RESULT_UNEVALUATED\x10\x01\x12\x10\n" + + "\fRESULT_FALSE\x10\x02\x12\x0f\n" + + "\vRESULT_TRUE\x10\x03\x12\x1f\n" + + "\x1bRESULT_MISSING_SOME_CONTEXT\x10\x04\"\xb8\x02\n" + "\x15DispatchExpandRequest\x12?\n" + "\bmetadata\x18\x01 \x01(\v2\x19.dispatch.v1.ResolverMetaB\b\xfaB\x05\x8a\x01\x02\x10\x01R\bmetadata\x12X\n" + "\x15resource_and_relation\x18\x02 \x01(\v2\x1a.core.v1.ObjectAndRelationB\b\xfaB\x05\x8a\x01\x02\x10\x01R\x13resourceAndRelation\x12W\n" + @@ -1815,112 +1982,117 @@ func file_dispatch_v1_dispatch_proto_rawDescGZIP() []byte { return file_dispatch_v1_dispatch_proto_rawDescData } -var file_dispatch_v1_dispatch_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_dispatch_v1_dispatch_proto_msgTypes = make([]protoimpl.MessageInfo, 24) +var file_dispatch_v1_dispatch_proto_enumTypes = make([]protoimpl.EnumInfo, 6) +var file_dispatch_v1_dispatch_proto_msgTypes = make([]protoimpl.MessageInfo, 25) var file_dispatch_v1_dispatch_proto_goTypes = []any{ (DispatchCheckRequest_DebugSetting)(0), // 0: dispatch.v1.DispatchCheckRequest.DebugSetting (DispatchCheckRequest_ResultsSetting)(0), // 1: dispatch.v1.DispatchCheckRequest.ResultsSetting (ResourceCheckResult_Membership)(0), // 2: dispatch.v1.ResourceCheckResult.Membership - (DispatchExpandRequest_ExpansionMode)(0), // 3: dispatch.v1.DispatchExpandRequest.ExpansionMode - (CheckDebugTrace_RelationType)(0), // 4: dispatch.v1.CheckDebugTrace.RelationType - (*DispatchCheckRequest)(nil), // 5: dispatch.v1.DispatchCheckRequest - (*CheckHint)(nil), // 6: dispatch.v1.CheckHint - (*DispatchCheckResponse)(nil), // 7: dispatch.v1.DispatchCheckResponse - (*ResourceCheckResult)(nil), // 8: dispatch.v1.ResourceCheckResult - (*DispatchExpandRequest)(nil), // 9: dispatch.v1.DispatchExpandRequest - (*DispatchExpandResponse)(nil), // 10: dispatch.v1.DispatchExpandResponse - (*Cursor)(nil), // 11: dispatch.v1.Cursor - (*DispatchLookupResources2Request)(nil), // 12: dispatch.v1.DispatchLookupResources2Request - (*PossibleResource)(nil), // 13: dispatch.v1.PossibleResource - (*DispatchLookupResources2Response)(nil), // 14: dispatch.v1.DispatchLookupResources2Response - (*DispatchLookupResources3Request)(nil), // 15: dispatch.v1.DispatchLookupResources3Request - (*DispatchLookupResources3Response)(nil), // 16: dispatch.v1.DispatchLookupResources3Response - (*LR3Item)(nil), // 17: dispatch.v1.LR3Item - (*DispatchLookupSubjectsRequest)(nil), // 18: dispatch.v1.DispatchLookupSubjectsRequest - (*FoundSubject)(nil), // 19: dispatch.v1.FoundSubject - (*FoundSubjects)(nil), // 20: dispatch.v1.FoundSubjects - (*DispatchLookupSubjectsResponse)(nil), // 21: dispatch.v1.DispatchLookupSubjectsResponse - (*ResolverMeta)(nil), // 22: dispatch.v1.ResolverMeta - (*ResponseMeta)(nil), // 23: dispatch.v1.ResponseMeta - (*DebugInformation)(nil), // 24: dispatch.v1.DebugInformation - (*CheckDebugTrace)(nil), // 25: dispatch.v1.CheckDebugTrace - nil, // 26: dispatch.v1.DispatchCheckResponse.ResultsByResourceIdEntry - nil, // 27: dispatch.v1.DispatchLookupSubjectsResponse.FoundSubjectsByResourceIdEntry - nil, // 28: dispatch.v1.CheckDebugTrace.ResultsEntry - (*v1.RelationReference)(nil), // 29: core.v1.RelationReference - (*v1.ObjectAndRelation)(nil), // 30: core.v1.ObjectAndRelation - (*v1.CaveatExpression)(nil), // 31: core.v1.CaveatExpression - (*v1.RelationTupleTreeNode)(nil), // 32: core.v1.RelationTupleTreeNode - (*structpb.Struct)(nil), // 33: google.protobuf.Struct - (*durationpb.Duration)(nil), // 34: google.protobuf.Duration + (CaveatEvalResult_Result)(0), // 3: dispatch.v1.CaveatEvalResult.Result + (DispatchExpandRequest_ExpansionMode)(0), // 4: dispatch.v1.DispatchExpandRequest.ExpansionMode + (CheckDebugTrace_RelationType)(0), // 5: dispatch.v1.CheckDebugTrace.RelationType + (*DispatchCheckRequest)(nil), // 6: dispatch.v1.DispatchCheckRequest + (*CheckHint)(nil), // 7: dispatch.v1.CheckHint + (*DispatchCheckResponse)(nil), // 8: dispatch.v1.DispatchCheckResponse + (*ResourceCheckResult)(nil), // 9: dispatch.v1.ResourceCheckResult + (*CaveatEvalResult)(nil), // 10: dispatch.v1.CaveatEvalResult + (*DispatchExpandRequest)(nil), // 11: dispatch.v1.DispatchExpandRequest + (*DispatchExpandResponse)(nil), // 12: dispatch.v1.DispatchExpandResponse + (*Cursor)(nil), // 13: dispatch.v1.Cursor + (*DispatchLookupResources2Request)(nil), // 14: dispatch.v1.DispatchLookupResources2Request + (*PossibleResource)(nil), // 15: dispatch.v1.PossibleResource + (*DispatchLookupResources2Response)(nil), // 16: dispatch.v1.DispatchLookupResources2Response + (*DispatchLookupResources3Request)(nil), // 17: dispatch.v1.DispatchLookupResources3Request + (*DispatchLookupResources3Response)(nil), // 18: dispatch.v1.DispatchLookupResources3Response + (*LR3Item)(nil), // 19: dispatch.v1.LR3Item + (*DispatchLookupSubjectsRequest)(nil), // 20: dispatch.v1.DispatchLookupSubjectsRequest + (*FoundSubject)(nil), // 21: dispatch.v1.FoundSubject + (*FoundSubjects)(nil), // 22: dispatch.v1.FoundSubjects + (*DispatchLookupSubjectsResponse)(nil), // 23: dispatch.v1.DispatchLookupSubjectsResponse + (*ResolverMeta)(nil), // 24: dispatch.v1.ResolverMeta + (*ResponseMeta)(nil), // 25: dispatch.v1.ResponseMeta + (*DebugInformation)(nil), // 26: dispatch.v1.DebugInformation + (*CheckDebugTrace)(nil), // 27: dispatch.v1.CheckDebugTrace + nil, // 28: dispatch.v1.DispatchCheckResponse.ResultsByResourceIdEntry + nil, // 29: dispatch.v1.DispatchLookupSubjectsResponse.FoundSubjectsByResourceIdEntry + nil, // 30: dispatch.v1.CheckDebugTrace.ResultsEntry + (*v1.RelationReference)(nil), // 31: core.v1.RelationReference + (*v1.ObjectAndRelation)(nil), // 32: core.v1.ObjectAndRelation + (*v1.CaveatExpression)(nil), // 33: core.v1.CaveatExpression + (*structpb.Struct)(nil), // 34: google.protobuf.Struct + (*v1.RelationTupleTreeNode)(nil), // 35: core.v1.RelationTupleTreeNode + (*durationpb.Duration)(nil), // 36: google.protobuf.Duration } var file_dispatch_v1_dispatch_proto_depIdxs = []int32{ - 22, // 0: dispatch.v1.DispatchCheckRequest.metadata:type_name -> dispatch.v1.ResolverMeta - 29, // 1: dispatch.v1.DispatchCheckRequest.resource_relation:type_name -> core.v1.RelationReference - 30, // 2: dispatch.v1.DispatchCheckRequest.subject:type_name -> core.v1.ObjectAndRelation + 24, // 0: dispatch.v1.DispatchCheckRequest.metadata:type_name -> dispatch.v1.ResolverMeta + 31, // 1: dispatch.v1.DispatchCheckRequest.resource_relation:type_name -> core.v1.RelationReference + 32, // 2: dispatch.v1.DispatchCheckRequest.subject:type_name -> core.v1.ObjectAndRelation 1, // 3: dispatch.v1.DispatchCheckRequest.results_setting:type_name -> dispatch.v1.DispatchCheckRequest.ResultsSetting 0, // 4: dispatch.v1.DispatchCheckRequest.debug:type_name -> dispatch.v1.DispatchCheckRequest.DebugSetting - 6, // 5: dispatch.v1.DispatchCheckRequest.check_hints:type_name -> dispatch.v1.CheckHint - 30, // 6: dispatch.v1.CheckHint.resource:type_name -> core.v1.ObjectAndRelation - 30, // 7: dispatch.v1.CheckHint.subject:type_name -> core.v1.ObjectAndRelation - 8, // 8: dispatch.v1.CheckHint.result:type_name -> dispatch.v1.ResourceCheckResult - 23, // 9: dispatch.v1.DispatchCheckResponse.metadata:type_name -> dispatch.v1.ResponseMeta - 26, // 10: dispatch.v1.DispatchCheckResponse.results_by_resource_id:type_name -> dispatch.v1.DispatchCheckResponse.ResultsByResourceIdEntry + 7, // 5: dispatch.v1.DispatchCheckRequest.check_hints:type_name -> dispatch.v1.CheckHint + 32, // 6: dispatch.v1.CheckHint.resource:type_name -> core.v1.ObjectAndRelation + 32, // 7: dispatch.v1.CheckHint.subject:type_name -> core.v1.ObjectAndRelation + 9, // 8: dispatch.v1.CheckHint.result:type_name -> dispatch.v1.ResourceCheckResult + 25, // 9: dispatch.v1.DispatchCheckResponse.metadata:type_name -> dispatch.v1.ResponseMeta + 28, // 10: dispatch.v1.DispatchCheckResponse.results_by_resource_id:type_name -> dispatch.v1.DispatchCheckResponse.ResultsByResourceIdEntry 2, // 11: dispatch.v1.ResourceCheckResult.membership:type_name -> dispatch.v1.ResourceCheckResult.Membership - 31, // 12: dispatch.v1.ResourceCheckResult.expression:type_name -> core.v1.CaveatExpression - 22, // 13: dispatch.v1.DispatchExpandRequest.metadata:type_name -> dispatch.v1.ResolverMeta - 30, // 14: dispatch.v1.DispatchExpandRequest.resource_and_relation:type_name -> core.v1.ObjectAndRelation - 3, // 15: dispatch.v1.DispatchExpandRequest.expansion_mode:type_name -> dispatch.v1.DispatchExpandRequest.ExpansionMode - 23, // 16: dispatch.v1.DispatchExpandResponse.metadata:type_name -> dispatch.v1.ResponseMeta - 32, // 17: dispatch.v1.DispatchExpandResponse.tree_node:type_name -> core.v1.RelationTupleTreeNode - 22, // 18: dispatch.v1.DispatchLookupResources2Request.metadata:type_name -> dispatch.v1.ResolverMeta - 29, // 19: dispatch.v1.DispatchLookupResources2Request.resource_relation:type_name -> core.v1.RelationReference - 29, // 20: dispatch.v1.DispatchLookupResources2Request.subject_relation:type_name -> core.v1.RelationReference - 30, // 21: dispatch.v1.DispatchLookupResources2Request.terminal_subject:type_name -> core.v1.ObjectAndRelation - 33, // 22: dispatch.v1.DispatchLookupResources2Request.context:type_name -> google.protobuf.Struct - 11, // 23: dispatch.v1.DispatchLookupResources2Request.optional_cursor:type_name -> dispatch.v1.Cursor - 13, // 24: dispatch.v1.DispatchLookupResources2Response.resource:type_name -> dispatch.v1.PossibleResource - 23, // 25: dispatch.v1.DispatchLookupResources2Response.metadata:type_name -> dispatch.v1.ResponseMeta - 11, // 26: dispatch.v1.DispatchLookupResources2Response.after_response_cursor:type_name -> dispatch.v1.Cursor - 22, // 27: dispatch.v1.DispatchLookupResources3Request.metadata:type_name -> dispatch.v1.ResolverMeta - 29, // 28: dispatch.v1.DispatchLookupResources3Request.resource_relation:type_name -> core.v1.RelationReference - 29, // 29: dispatch.v1.DispatchLookupResources3Request.subject_relation:type_name -> core.v1.RelationReference - 30, // 30: dispatch.v1.DispatchLookupResources3Request.terminal_subject:type_name -> core.v1.ObjectAndRelation - 33, // 31: dispatch.v1.DispatchLookupResources3Request.context:type_name -> google.protobuf.Struct - 17, // 32: dispatch.v1.DispatchLookupResources3Response.items:type_name -> dispatch.v1.LR3Item - 22, // 33: dispatch.v1.DispatchLookupSubjectsRequest.metadata:type_name -> dispatch.v1.ResolverMeta - 29, // 34: dispatch.v1.DispatchLookupSubjectsRequest.resource_relation:type_name -> core.v1.RelationReference - 29, // 35: dispatch.v1.DispatchLookupSubjectsRequest.subject_relation:type_name -> core.v1.RelationReference - 31, // 36: dispatch.v1.FoundSubject.caveat_expression:type_name -> core.v1.CaveatExpression - 19, // 37: dispatch.v1.FoundSubject.excluded_subjects:type_name -> dispatch.v1.FoundSubject - 19, // 38: dispatch.v1.FoundSubjects.found_subjects:type_name -> dispatch.v1.FoundSubject - 27, // 39: dispatch.v1.DispatchLookupSubjectsResponse.found_subjects_by_resource_id:type_name -> dispatch.v1.DispatchLookupSubjectsResponse.FoundSubjectsByResourceIdEntry - 23, // 40: dispatch.v1.DispatchLookupSubjectsResponse.metadata:type_name -> dispatch.v1.ResponseMeta - 24, // 41: dispatch.v1.ResponseMeta.debug_info:type_name -> dispatch.v1.DebugInformation - 25, // 42: dispatch.v1.DebugInformation.check:type_name -> dispatch.v1.CheckDebugTrace - 5, // 43: dispatch.v1.CheckDebugTrace.request:type_name -> dispatch.v1.DispatchCheckRequest - 4, // 44: dispatch.v1.CheckDebugTrace.resource_relation_type:type_name -> dispatch.v1.CheckDebugTrace.RelationType - 28, // 45: dispatch.v1.CheckDebugTrace.results:type_name -> dispatch.v1.CheckDebugTrace.ResultsEntry - 25, // 46: dispatch.v1.CheckDebugTrace.sub_problems:type_name -> dispatch.v1.CheckDebugTrace - 34, // 47: dispatch.v1.CheckDebugTrace.duration:type_name -> google.protobuf.Duration - 8, // 48: dispatch.v1.DispatchCheckResponse.ResultsByResourceIdEntry.value:type_name -> dispatch.v1.ResourceCheckResult - 20, // 49: dispatch.v1.DispatchLookupSubjectsResponse.FoundSubjectsByResourceIdEntry.value:type_name -> dispatch.v1.FoundSubjects - 8, // 50: dispatch.v1.CheckDebugTrace.ResultsEntry.value:type_name -> dispatch.v1.ResourceCheckResult - 5, // 51: dispatch.v1.DispatchService.DispatchCheck:input_type -> dispatch.v1.DispatchCheckRequest - 9, // 52: dispatch.v1.DispatchService.DispatchExpand:input_type -> dispatch.v1.DispatchExpandRequest - 18, // 53: dispatch.v1.DispatchService.DispatchLookupSubjects:input_type -> dispatch.v1.DispatchLookupSubjectsRequest - 12, // 54: dispatch.v1.DispatchService.DispatchLookupResources2:input_type -> dispatch.v1.DispatchLookupResources2Request - 15, // 55: dispatch.v1.DispatchService.DispatchLookupResources3:input_type -> dispatch.v1.DispatchLookupResources3Request - 7, // 56: dispatch.v1.DispatchService.DispatchCheck:output_type -> dispatch.v1.DispatchCheckResponse - 10, // 57: dispatch.v1.DispatchService.DispatchExpand:output_type -> dispatch.v1.DispatchExpandResponse - 21, // 58: dispatch.v1.DispatchService.DispatchLookupSubjects:output_type -> dispatch.v1.DispatchLookupSubjectsResponse - 14, // 59: dispatch.v1.DispatchService.DispatchLookupResources2:output_type -> dispatch.v1.DispatchLookupResources2Response - 16, // 60: dispatch.v1.DispatchService.DispatchLookupResources3:output_type -> dispatch.v1.DispatchLookupResources3Response - 56, // [56:61] is the sub-list for method output_type - 51, // [51:56] is the sub-list for method input_type - 51, // [51:51] is the sub-list for extension type_name - 51, // [51:51] is the sub-list for extension extendee - 0, // [0:51] is the sub-list for field type_name + 33, // 12: dispatch.v1.ResourceCheckResult.expression:type_name -> core.v1.CaveatExpression + 10, // 13: dispatch.v1.ResourceCheckResult.caveat_eval_info:type_name -> dispatch.v1.CaveatEvalResult + 3, // 14: dispatch.v1.CaveatEvalResult.result:type_name -> dispatch.v1.CaveatEvalResult.Result + 34, // 15: dispatch.v1.CaveatEvalResult.context:type_name -> google.protobuf.Struct + 24, // 16: dispatch.v1.DispatchExpandRequest.metadata:type_name -> dispatch.v1.ResolverMeta + 32, // 17: dispatch.v1.DispatchExpandRequest.resource_and_relation:type_name -> core.v1.ObjectAndRelation + 4, // 18: dispatch.v1.DispatchExpandRequest.expansion_mode:type_name -> dispatch.v1.DispatchExpandRequest.ExpansionMode + 25, // 19: dispatch.v1.DispatchExpandResponse.metadata:type_name -> dispatch.v1.ResponseMeta + 35, // 20: dispatch.v1.DispatchExpandResponse.tree_node:type_name -> core.v1.RelationTupleTreeNode + 24, // 21: dispatch.v1.DispatchLookupResources2Request.metadata:type_name -> dispatch.v1.ResolverMeta + 31, // 22: dispatch.v1.DispatchLookupResources2Request.resource_relation:type_name -> core.v1.RelationReference + 31, // 23: dispatch.v1.DispatchLookupResources2Request.subject_relation:type_name -> core.v1.RelationReference + 32, // 24: dispatch.v1.DispatchLookupResources2Request.terminal_subject:type_name -> core.v1.ObjectAndRelation + 34, // 25: dispatch.v1.DispatchLookupResources2Request.context:type_name -> google.protobuf.Struct + 13, // 26: dispatch.v1.DispatchLookupResources2Request.optional_cursor:type_name -> dispatch.v1.Cursor + 15, // 27: dispatch.v1.DispatchLookupResources2Response.resource:type_name -> dispatch.v1.PossibleResource + 25, // 28: dispatch.v1.DispatchLookupResources2Response.metadata:type_name -> dispatch.v1.ResponseMeta + 13, // 29: dispatch.v1.DispatchLookupResources2Response.after_response_cursor:type_name -> dispatch.v1.Cursor + 24, // 30: dispatch.v1.DispatchLookupResources3Request.metadata:type_name -> dispatch.v1.ResolverMeta + 31, // 31: dispatch.v1.DispatchLookupResources3Request.resource_relation:type_name -> core.v1.RelationReference + 31, // 32: dispatch.v1.DispatchLookupResources3Request.subject_relation:type_name -> core.v1.RelationReference + 32, // 33: dispatch.v1.DispatchLookupResources3Request.terminal_subject:type_name -> core.v1.ObjectAndRelation + 34, // 34: dispatch.v1.DispatchLookupResources3Request.context:type_name -> google.protobuf.Struct + 19, // 35: dispatch.v1.DispatchLookupResources3Response.items:type_name -> dispatch.v1.LR3Item + 24, // 36: dispatch.v1.DispatchLookupSubjectsRequest.metadata:type_name -> dispatch.v1.ResolverMeta + 31, // 37: dispatch.v1.DispatchLookupSubjectsRequest.resource_relation:type_name -> core.v1.RelationReference + 31, // 38: dispatch.v1.DispatchLookupSubjectsRequest.subject_relation:type_name -> core.v1.RelationReference + 33, // 39: dispatch.v1.FoundSubject.caveat_expression:type_name -> core.v1.CaveatExpression + 21, // 40: dispatch.v1.FoundSubject.excluded_subjects:type_name -> dispatch.v1.FoundSubject + 21, // 41: dispatch.v1.FoundSubjects.found_subjects:type_name -> dispatch.v1.FoundSubject + 29, // 42: dispatch.v1.DispatchLookupSubjectsResponse.found_subjects_by_resource_id:type_name -> dispatch.v1.DispatchLookupSubjectsResponse.FoundSubjectsByResourceIdEntry + 25, // 43: dispatch.v1.DispatchLookupSubjectsResponse.metadata:type_name -> dispatch.v1.ResponseMeta + 26, // 44: dispatch.v1.ResponseMeta.debug_info:type_name -> dispatch.v1.DebugInformation + 27, // 45: dispatch.v1.DebugInformation.check:type_name -> dispatch.v1.CheckDebugTrace + 6, // 46: dispatch.v1.CheckDebugTrace.request:type_name -> dispatch.v1.DispatchCheckRequest + 5, // 47: dispatch.v1.CheckDebugTrace.resource_relation_type:type_name -> dispatch.v1.CheckDebugTrace.RelationType + 30, // 48: dispatch.v1.CheckDebugTrace.results:type_name -> dispatch.v1.CheckDebugTrace.ResultsEntry + 27, // 49: dispatch.v1.CheckDebugTrace.sub_problems:type_name -> dispatch.v1.CheckDebugTrace + 36, // 50: dispatch.v1.CheckDebugTrace.duration:type_name -> google.protobuf.Duration + 9, // 51: dispatch.v1.DispatchCheckResponse.ResultsByResourceIdEntry.value:type_name -> dispatch.v1.ResourceCheckResult + 22, // 52: dispatch.v1.DispatchLookupSubjectsResponse.FoundSubjectsByResourceIdEntry.value:type_name -> dispatch.v1.FoundSubjects + 9, // 53: dispatch.v1.CheckDebugTrace.ResultsEntry.value:type_name -> dispatch.v1.ResourceCheckResult + 6, // 54: dispatch.v1.DispatchService.DispatchCheck:input_type -> dispatch.v1.DispatchCheckRequest + 11, // 55: dispatch.v1.DispatchService.DispatchExpand:input_type -> dispatch.v1.DispatchExpandRequest + 20, // 56: dispatch.v1.DispatchService.DispatchLookupSubjects:input_type -> dispatch.v1.DispatchLookupSubjectsRequest + 14, // 57: dispatch.v1.DispatchService.DispatchLookupResources2:input_type -> dispatch.v1.DispatchLookupResources2Request + 17, // 58: dispatch.v1.DispatchService.DispatchLookupResources3:input_type -> dispatch.v1.DispatchLookupResources3Request + 8, // 59: dispatch.v1.DispatchService.DispatchCheck:output_type -> dispatch.v1.DispatchCheckResponse + 12, // 60: dispatch.v1.DispatchService.DispatchExpand:output_type -> dispatch.v1.DispatchExpandResponse + 23, // 61: dispatch.v1.DispatchService.DispatchLookupSubjects:output_type -> dispatch.v1.DispatchLookupSubjectsResponse + 16, // 62: dispatch.v1.DispatchService.DispatchLookupResources2:output_type -> dispatch.v1.DispatchLookupResources2Response + 18, // 63: dispatch.v1.DispatchService.DispatchLookupResources3:output_type -> dispatch.v1.DispatchLookupResources3Response + 59, // [59:64] is the sub-list for method output_type + 54, // [54:59] is the sub-list for method input_type + 54, // [54:54] is the sub-list for extension type_name + 54, // [54:54] is the sub-list for extension extendee + 0, // [0:54] is the sub-list for field type_name } func init() { file_dispatch_v1_dispatch_proto_init() } @@ -1933,8 +2105,8 @@ func file_dispatch_v1_dispatch_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_dispatch_v1_dispatch_proto_rawDesc), len(file_dispatch_v1_dispatch_proto_rawDesc)), - NumEnums: 5, - NumMessages: 24, + NumEnums: 6, + NumMessages: 25, NumExtensions: 0, NumServices: 1, }, diff --git a/pkg/proto/dispatch/v1/dispatch.pb.validate.go b/pkg/proto/dispatch/v1/dispatch.pb.validate.go index 265bb06cc..3239f870c 100644 --- a/pkg/proto/dispatch/v1/dispatch.pb.validate.go +++ b/pkg/proto/dispatch/v1/dispatch.pb.validate.go @@ -713,6 +713,40 @@ func (m *ResourceCheckResult) validate(all bool) error { } } + for idx, item := range m.GetCaveatEvalInfo() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ResourceCheckResultValidationError{ + field: fmt.Sprintf("CaveatEvalInfo[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ResourceCheckResultValidationError{ + field: fmt.Sprintf("CaveatEvalInfo[%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 ResourceCheckResultValidationError{ + field: fmt.Sprintf("CaveatEvalInfo[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + if len(errors) > 0 { return ResourceCheckResultMultiError(errors) } @@ -793,6 +827,141 @@ var _ interface { ErrorName() string } = ResourceCheckResultValidationError{} +// Validate checks the field values on CaveatEvalResult 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 *CaveatEvalResult) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on CaveatEvalResult 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 +// CaveatEvalResultMultiError, or nil if none found. +func (m *CaveatEvalResult) ValidateAll() error { + return m.validate(true) +} + +func (m *CaveatEvalResult) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for CaveatName + + // no validation rules for Result + + if all { + switch v := interface{}(m.GetContext()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, CaveatEvalResultValidationError{ + field: "Context", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, CaveatEvalResultValidationError{ + field: "Context", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetContext()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return CaveatEvalResultValidationError{ + field: "Context", + reason: "embedded message failed validation", + cause: err, + } + } + } + + // no validation rules for ExpressionString + + if len(errors) > 0 { + return CaveatEvalResultMultiError(errors) + } + + return nil +} + +// CaveatEvalResultMultiError is an error wrapping multiple validation errors +// returned by CaveatEvalResult.ValidateAll() if the designated constraints +// aren't met. +type CaveatEvalResultMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m CaveatEvalResultMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m CaveatEvalResultMultiError) AllErrors() []error { return m } + +// CaveatEvalResultValidationError is the validation error returned by +// CaveatEvalResult.Validate if the designated constraints aren't met. +type CaveatEvalResultValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e CaveatEvalResultValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e CaveatEvalResultValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e CaveatEvalResultValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e CaveatEvalResultValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e CaveatEvalResultValidationError) ErrorName() string { return "CaveatEvalResultValidationError" } + +// Error satisfies the builtin error interface +func (e CaveatEvalResultValidationError) 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 %sCaveatEvalResult.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = CaveatEvalResultValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = CaveatEvalResultValidationError{} + // Validate checks the field values on DispatchExpandRequest 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/pkg/proto/dispatch/v1/dispatch_vtproto.pb.go b/pkg/proto/dispatch/v1/dispatch_vtproto.pb.go index e03bb3ac8..506ccb8cf 100644 --- a/pkg/proto/dispatch/v1/dispatch_vtproto.pb.go +++ b/pkg/proto/dispatch/v1/dispatch_vtproto.pb.go @@ -143,6 +143,13 @@ func (m *ResourceCheckResult) CloneVT() *ResourceCheckResult { copy(tmpContainer, rhs) r.MissingExprFields = tmpContainer } + if rhs := m.CaveatEvalInfo; rhs != nil { + tmpContainer := make([]*CaveatEvalResult, len(rhs)) + for k, v := range rhs { + tmpContainer[k] = v.CloneVT() + } + r.CaveatEvalInfo = tmpContainer + } if len(m.unknownFields) > 0 { r.unknownFields = make([]byte, len(m.unknownFields)) copy(r.unknownFields, m.unknownFields) @@ -154,6 +161,31 @@ func (m *ResourceCheckResult) CloneMessageVT() proto.Message { return m.CloneVT() } +func (m *CaveatEvalResult) CloneVT() *CaveatEvalResult { + if m == nil { + return (*CaveatEvalResult)(nil) + } + r := new(CaveatEvalResult) + r.CaveatName = m.CaveatName + r.Result = m.Result + r.Context = (*structpb.Struct)((*structpb1.Struct)(m.Context).CloneVT()) + r.ExpressionString = m.ExpressionString + if rhs := m.MissingContextParams; rhs != nil { + tmpContainer := make([]string, len(rhs)) + copy(tmpContainer, rhs) + r.MissingContextParams = tmpContainer + } + if len(m.unknownFields) > 0 { + r.unknownFields = make([]byte, len(m.unknownFields)) + copy(r.unknownFields, m.unknownFields) + } + return r +} + +func (m *CaveatEvalResult) CloneMessageVT() proto.Message { + return m.CloneVT() +} + func (m *DispatchExpandRequest) CloneVT() *DispatchExpandRequest { if m == nil { return (*DispatchExpandRequest)(nil) @@ -810,6 +842,23 @@ func (this *ResourceCheckResult) EqualVT(that *ResourceCheckResult) bool { return false } } + if len(this.CaveatEvalInfo) != len(that.CaveatEvalInfo) { + return false + } + for i, vx := range this.CaveatEvalInfo { + vy := that.CaveatEvalInfo[i] + if p, q := vx, vy; p != q { + if p == nil { + p = &CaveatEvalResult{} + } + if q == nil { + q = &CaveatEvalResult{} + } + if !p.EqualVT(q) { + return false + } + } + } return string(this.unknownFields) == string(that.unknownFields) } @@ -820,6 +869,43 @@ func (this *ResourceCheckResult) EqualMessageVT(thatMsg proto.Message) bool { } return this.EqualVT(that) } +func (this *CaveatEvalResult) EqualVT(that *CaveatEvalResult) bool { + if this == that { + return true + } else if this == nil || that == nil { + return false + } + if this.CaveatName != that.CaveatName { + return false + } + if this.Result != that.Result { + return false + } + if !(*structpb1.Struct)(this.Context).EqualVT((*structpb1.Struct)(that.Context)) { + return false + } + if this.ExpressionString != that.ExpressionString { + return false + } + if len(this.MissingContextParams) != len(that.MissingContextParams) { + return false + } + for i, vx := range this.MissingContextParams { + vy := that.MissingContextParams[i] + if vx != vy { + return false + } + } + return string(this.unknownFields) == string(that.unknownFields) +} + +func (this *CaveatEvalResult) EqualMessageVT(thatMsg proto.Message) bool { + that, ok := thatMsg.(*CaveatEvalResult) + if !ok { + return false + } + return this.EqualVT(that) +} func (this *DispatchExpandRequest) EqualVT(that *DispatchExpandRequest) bool { if this == that { return true @@ -1798,6 +1884,18 @@ func (m *ResourceCheckResult) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if len(m.CaveatEvalInfo) > 0 { + for iNdEx := len(m.CaveatEvalInfo) - 1; iNdEx >= 0; iNdEx-- { + size, err := m.CaveatEvalInfo[iNdEx].MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x22 + } + } if len(m.MissingExprFields) > 0 { for iNdEx := len(m.MissingExprFields) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.MissingExprFields[iNdEx]) @@ -1837,6 +1935,77 @@ func (m *ResourceCheckResult) MarshalToSizedBufferVT(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *CaveatEvalResult) 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 *CaveatEvalResult) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *CaveatEvalResult) 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.MissingContextParams) > 0 { + for iNdEx := len(m.MissingContextParams) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.MissingContextParams[iNdEx]) + copy(dAtA[i:], m.MissingContextParams[iNdEx]) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.MissingContextParams[iNdEx]))) + i-- + dAtA[i] = 0x2a + } + } + if len(m.ExpressionString) > 0 { + i -= len(m.ExpressionString) + copy(dAtA[i:], m.ExpressionString) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ExpressionString))) + i-- + dAtA[i] = 0x22 + } + if m.Context != nil { + size, err := (*structpb1.Struct)(m.Context).MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x1a + } + if m.Result != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Result)) + i-- + dAtA[i] = 0x10 + } + if len(m.CaveatName) > 0 { + i -= len(m.CaveatName) + copy(dAtA[i:], m.CaveatName) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.CaveatName))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *DispatchExpandRequest) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil @@ -3235,6 +3404,43 @@ func (m *ResourceCheckResult) SizeVT() (n int) { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } } + if len(m.CaveatEvalInfo) > 0 { + for _, e := range m.CaveatEvalInfo { + l = e.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } + n += len(m.unknownFields) + return n +} + +func (m *CaveatEvalResult) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.CaveatName) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Result != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Result)) + } + if m.Context != nil { + l = (*structpb1.Struct)(m.Context).SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.ExpressionString) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if len(m.MissingContextParams) > 0 { + for _, s := range m.MissingContextParams { + l = len(s) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + } n += len(m.unknownFields) return n } @@ -4581,6 +4787,242 @@ func (m *ResourceCheckResult) UnmarshalVT(dAtA []byte) error { } m.MissingExprFields = append(m.MissingExprFields, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CaveatEvalInfo", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CaveatEvalInfo = append(m.CaveatEvalInfo, &CaveatEvalResult{}) + if err := m.CaveatEvalInfo[len(m.CaveatEvalInfo)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.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 *CaveatEvalResult) 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 protohelpers.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: CaveatEvalResult: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CaveatEvalResult: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CaveatName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.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 protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CaveatName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + m.Result = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Result |= CaveatEvalResult_Result(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Context", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Context == nil { + m.Context = &structpb.Struct{} + } + if err := (*structpb1.Struct)(m.Context).UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ExpressionString", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.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 protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ExpressionString = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MissingContextParams", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.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 protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MissingContextParams = append(m.MissingContextParams, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) diff --git a/proto/internal/dispatch/v1/dispatch.proto b/proto/internal/dispatch/v1/dispatch.proto index 16e2a6c29..615dece31 100644 --- a/proto/internal/dispatch/v1/dispatch.proto +++ b/proto/internal/dispatch/v1/dispatch.proto @@ -73,6 +73,42 @@ message ResourceCheckResult { Membership membership = 1; core.v1.CaveatExpression expression = 2; repeated string missing_expr_fields = 3; + + // caveat_eval_info contains information about caveats that were evaluated + // during the permission check. When a caveated permission check results in + // NOT_MEMBER because a caveat evaluated to false, this field identifies which + // caveat(s) failed and provides their evaluation context. + // This addresses https://github.com/authzed/spicedb/issues/2802 + repeated CaveatEvalResult caveat_eval_info = 4; +} + +// CaveatEvalResult contains the evaluation result of a single caveat during +// a permission check. This enables applications to identify which specific +// caveat caused a permission denial. +message CaveatEvalResult { + enum Result { + RESULT_UNSPECIFIED = 0; + RESULT_UNEVALUATED = 1; + RESULT_FALSE = 2; + RESULT_TRUE = 3; + RESULT_MISSING_SOME_CONTEXT = 4; + } + + // caveat_name is the name of the caveat that was evaluated. + string caveat_name = 1; + + // result is the evaluation result of the caveat. + Result result = 2; + + // context contains the context values that were used during evaluation. + google.protobuf.Struct context = 3; + + // expression_string is the human-readable CEL expression of the caveat. + string expression_string = 4; + + // missing_context_params lists parameter names that were missing during + // evaluation, resulting in a partial/conditional result. + repeated string missing_context_params = 5; } message DispatchExpandRequest {