github.com/rajeev159/opa@v0.45.0/topdown/errors.go (about)

     1  // Copyright 2017 The OPA Authors.  All rights reserved.
     2  // Use of this source code is governed by an Apache2
     3  // license that can be found in the LICENSE file.
     4  
     5  package topdown
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  
    11  	"github.com/open-policy-agent/opa/ast"
    12  )
    13  
    14  // Halt is a special error type that built-in function implementations return to indicate
    15  // that policy evaluation should stop immediately.
    16  type Halt struct {
    17  	Err error
    18  }
    19  
    20  func (h Halt) Error() string {
    21  	return h.Err.Error()
    22  }
    23  
    24  func (h Halt) Unwrap() error { return h.Err }
    25  
    26  // Error is the error type returned by the Eval and Query functions when
    27  // an evaluation error occurs.
    28  type Error struct {
    29  	Code     string        `json:"code"`
    30  	Message  string        `json:"message"`
    31  	Location *ast.Location `json:"location,omitempty"`
    32  }
    33  
    34  const (
    35  
    36  	// InternalErr represents an unknown evaluation error.
    37  	InternalErr string = "eval_internal_error"
    38  
    39  	// CancelErr indicates the evaluation process was cancelled.
    40  	CancelErr string = "eval_cancel_error"
    41  
    42  	// ConflictErr indicates a conflict was encountered during evaluation. For
    43  	// instance, a conflict occurs if a rule produces multiple, differing values
    44  	// for the same key in an object. Conflict errors indicate the policy does
    45  	// not account for the data loaded into the policy engine.
    46  	ConflictErr string = "eval_conflict_error"
    47  
    48  	// TypeErr indicates evaluation stopped because an expression was applied to
    49  	// a value of an inappropriate type.
    50  	TypeErr string = "eval_type_error"
    51  
    52  	// BuiltinErr indicates a built-in function received a semantically invalid
    53  	// input or encountered some kind of runtime error, e.g., connection
    54  	// timeout, connection refused, etc.
    55  	BuiltinErr string = "eval_builtin_error"
    56  
    57  	// WithMergeErr indicates that the real and replacement data could not be merged.
    58  	WithMergeErr string = "eval_with_merge_error"
    59  )
    60  
    61  // IsError returns true if the err is an Error.
    62  func IsError(err error) bool {
    63  	var e *Error
    64  	return errors.As(err, &e)
    65  }
    66  
    67  // IsCancel returns true if err was caused by cancellation.
    68  func IsCancel(err error) bool {
    69  	return errors.Is(err, &Error{Code: CancelErr})
    70  }
    71  
    72  // Is allows matching topdown errors using errors.Is (see IsCancel).
    73  func (e *Error) Is(target error) bool {
    74  	var t *Error
    75  	if errors.As(target, &t) {
    76  		return (t.Code == "" || e.Code == t.Code) &&
    77  			(t.Message == "" || e.Message == t.Message) &&
    78  			(t.Location == nil || t.Location.Compare(e.Location) == 0)
    79  	}
    80  	return false
    81  }
    82  
    83  func (e *Error) Error() string {
    84  	msg := fmt.Sprintf("%v: %v", e.Code, e.Message)
    85  
    86  	if e.Location != nil {
    87  		msg = e.Location.String() + ": " + msg
    88  	}
    89  
    90  	return msg
    91  }
    92  
    93  func functionConflictErr(loc *ast.Location) error {
    94  	return &Error{
    95  		Code:     ConflictErr,
    96  		Location: loc,
    97  		Message:  "functions must not produce multiple outputs for same inputs",
    98  	}
    99  }
   100  
   101  func completeDocConflictErr(loc *ast.Location) error {
   102  	return &Error{
   103  		Code:     ConflictErr,
   104  		Location: loc,
   105  		Message:  "complete rules must not produce multiple outputs",
   106  	}
   107  }
   108  
   109  func objectDocKeyConflictErr(loc *ast.Location) error {
   110  	return &Error{
   111  		Code:     ConflictErr,
   112  		Location: loc,
   113  		Message:  "object keys must be unique",
   114  	}
   115  }
   116  
   117  func unsupportedBuiltinErr(loc *ast.Location) error {
   118  	return &Error{
   119  		Code:     InternalErr,
   120  		Location: loc,
   121  		Message:  "unsupported built-in",
   122  	}
   123  }
   124  
   125  func mergeConflictErr(loc *ast.Location) error {
   126  	return &Error{
   127  		Code:     WithMergeErr,
   128  		Location: loc,
   129  		Message:  "real and replacement data could not be merged",
   130  	}
   131  }
   132  
   133  func internalErr(loc *ast.Location, msg string) error {
   134  	return &Error{
   135  		Code:     InternalErr,
   136  		Location: loc,
   137  		Message:  msg,
   138  	}
   139  }