cedar_policy_core/evaluator/err.rs
1/*
2 * Copyright 2022-2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use crate::ast::*;
18use smol_str::SmolStr;
19use std::sync::Arc;
20use thiserror::Error;
21
22/// Error type for various kinds of errors that can be raised by the policy
23/// evaluator.
24#[derive(Debug, PartialEq, Clone, Error)]
25pub enum EvaluationError {
26 /// Tried to lookup this entity UID, but it didn't exist in the provided
27 /// entities
28 #[error("entity does not exist: {0}")]
29 EntityDoesNotExist(Arc<EntityUID>),
30
31 /// Tried to get this attribute, but the specified entity didn't
32 /// have that attribute
33 #[error("{} does not have the required attribute: {}", &.entity, &.attr)]
34 EntityAttrDoesNotExist {
35 /// Entity which didn't have the attribute
36 entity: Arc<EntityUID>,
37 /// Name of the attribute it didn't have
38 attr: SmolStr,
39 },
40
41 /// Tried to access an attribute of an unspecified entity
42 #[error("cannot access attribute of unspecified entity: {0}")]
43 UnspecifiedEntityAccess(SmolStr),
44
45 /// Tried to get this attribute of a (non-entity) record, but that record
46 /// didn't have that attribute
47 #[error("record does not have the required attribute: {0}")]
48 RecordAttrDoesNotExist(SmolStr),
49
50 /// Error thown by an operation on `Extensions`
51 /// (not to be confused with `ExtensionError`, which is an error thrown by
52 /// an individual extension function)
53 #[error(transparent)]
54 ExtensionsError(#[from] crate::extensions::ExtensionsError),
55
56 /// Type error, showing the expected type and actual type
57 #[error("{}", pretty_type_error(expected, actual))]
58 TypeError {
59 /// Expected (one of) these types
60 expected: Vec<Type>,
61 /// Encountered this type instead
62 actual: Type,
63 },
64
65 /// Wrong number of arguments to an extension function
66 #[error("wrong number of arguments to {op}: expected {expected}, got {actual}")]
67 WrongNumArguments {
68 /// arguments to this function
69 op: ExtensionFunctionOp,
70 /// expected number of arguments
71 expected: usize,
72 /// actual number of arguments
73 actual: usize,
74 },
75
76 /// Overflow during an integer operation
77 #[error(transparent)]
78 IntegerOverflow(#[from] IntegerOverflowError),
79
80 /// Error with the use of "restricted" expressions
81 #[error(transparent)]
82 InvalidRestrictedExpression(#[from] RestrictedExpressionError),
83
84 /// Thrown when a policy is evaluated with an un-filled slot
85 #[error("Template slot {0} was not instantiated")]
86 TemplateInstantiationError(SlotId),
87
88 /// Evaluation error thrown by an extension function
89 #[error("error from {extension_name} extension: {msg}")]
90 ExtensionError {
91 /// Name of the extension throwing the error
92 extension_name: Name,
93 /// Error message from the extension
94 msg: String,
95 },
96
97 /// Error raised if an expression did not reduce to a value when it was supposed to
98 #[error("The expression evaluated to a residual: {0}")]
99 NonValue(Expr),
100
101 /// Maximum recursion limit reached for expression evaluation
102 #[error("Recursion Limit Reached")]
103 RecursionLimit,
104}
105
106/// helper function for pretty-printing type errors
107fn pretty_type_error(expected: &[Type], actual: &Type) -> String {
108 match expected.len() {
109 0 => panic!("should expect at least one type"),
110 1 => format!("type error: expected {}, got {}", expected[0], actual),
111 _ => {
112 use itertools::Itertools;
113 format!(
114 "type error: expected one of [{}], got {actual}",
115 expected.iter().join(", ")
116 )
117 }
118 }
119}
120
121#[derive(Debug, PartialEq, Clone, Error)]
122pub enum IntegerOverflowError {
123 #[error("integer overflow while attempting to {} the values {arg1} and {arg2}", match .op { BinaryOp::Add => "add", BinaryOp::Sub => "subtract", _ => "perform an operation on" })]
124 BinaryOp {
125 /// overflow while evaluating this operator
126 op: BinaryOp,
127 /// first argument to that operator
128 arg1: Value,
129 /// second argument to that operator
130 arg2: Value,
131 },
132
133 #[error("integer overflow while attempting to multiply {arg} by {constant}")]
134 Multiplication {
135 /// first argument, which wasn't necessarily a constant in the policy
136 arg: Value,
137 /// second argument, which was a constant in the policy
138 constant: i64,
139 },
140
141 /// Overflow during an integer negation operation
142 #[error("integer overflow while attempting to {} the value {arg}", match .op { UnaryOp::Neg => "negate", _ => "perform an operation on" })]
143 UnaryOp {
144 /// overflow while evaluating this operator
145 op: UnaryOp,
146 /// argument to that operator
147 arg: Value,
148 },
149}
150
151/// Type alias for convenience
152pub type Result<T> = std::result::Result<T, EvaluationError>;