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>;