Skip to main content

cedar_policy_core/tpe/
err.rs

1/*
2 * Copyright Cedar Contributors
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
17//! This module contains possible errors thrown by various components of the
18//! type-aware partial evaluator.
19
20use miette::Diagnostic;
21use smol_str::SmolStr;
22use thiserror::Error;
23
24use crate::{
25    ast::{Eid, EntityType, EntityUID, PartialValueToValueError},
26    entities::{conformance::err::EntitySchemaConformanceError, err::Duplicate},
27    evaluator::{evaluation_errors::UnlinkedSlotError, EvaluationError},
28    transitive_closure::TcError,
29    validator::{RequestValidationError, ValidationError},
30};
31
32/// Error thrown when encountered an action
33#[derive(Debug, Error, Diagnostic)]
34#[error("Unexpected action: `{}`", .action)]
35pub struct UnexpectedActionError {
36    pub(super) action: EntityUID,
37}
38
39/// Error thrown when deserializing a [`crate::tpe::entities::PartialEntity`]
40#[derive(Debug, Error, Diagnostic)]
41pub enum JsonDeserializationError {
42    /// Error thrown when deserializing concrete components
43    #[error(transparent)]
44    #[diagnostic(transparent)]
45    Concrete(#[from] crate::entities::json::err::JsonDeserializationError),
46    /// Error thrown when encountered an action
47    /// Actions are automatically inserted from a schema
48    #[error(transparent)]
49    #[diagnostic(transparent)]
50    UnexpectedAction(#[from] UnexpectedActionError),
51    /// Error thrown when a restricted expression does not evaluate to a value
52    #[error(transparent)]
53    #[diagnostic(transparent)]
54    RestrictedExprEvaluation(#[from] EvaluationError),
55}
56
57/// Error thrown when validating a [`crate::tpe::entities::PartialEntity`]
58#[derive(Debug, Error, Diagnostic)]
59pub enum EntityValidationError {
60    /// Error thrown when validating concrete components
61    #[error(transparent)]
62    #[diagnostic(transparent)]
63    Concrete(#[from] EntitySchemaConformanceError),
64    /// Error thrown when an action's ancestors do not match the schema
65    #[error(transparent)]
66    #[diagnostic(transparent)]
67    MismatchedActionAncestors(#[from] MismatchedActionAncestorsError),
68}
69
70/// Error thrown when an action's ancestors do not match the schema
71#[derive(Debug, Error, Diagnostic)]
72#[error("action `{}`'s ancestors do not match the schema", .action)]
73pub struct MismatchedActionAncestorsError {
74    pub(super) action: EntityUID,
75}
76
77/// Error thrown when an ancestor of an ancestor is unknown
78#[derive(Debug, Error, Diagnostic)]
79#[error("ancestor `{ancestor}` of `{uid}` has unknown ancestors")]
80#[diagnostic(help(
81    "an entity with known ancestors cannot have an ancestor whose own ancestors are unknown"
82))]
83pub struct AncestorValidationError {
84    pub(crate) uid: EntityUID,
85    pub(crate) ancestor: EntityUID,
86}
87
88/// Errors for TPE
89#[derive(Debug, Error, Diagnostic)]
90pub enum TpeError {
91    /// Error thrown when there is no matching request environment according to
92    /// a schema
93    #[error(transparent)]
94    #[diagnostic(transparent)]
95    NoMatchingReqEnv(#[from] NoMatchingReqEnvError),
96    /// Error thrown when the policy does not typecheck against the schema
97    #[error(transparent)]
98    #[diagnostic(transparent)]
99    Validation(#[from] PolicyValidationError),
100    /// Error when an expression is not supported by batched evaluation
101    #[error(transparent)]
102    #[diagnostic(transparent)]
103    ExprToResidualError(#[from] ExprToResidualError),
104}
105
106/// Error thrown when a policy fails to typecheck against the schema during
107/// type-aware partial evaluation
108#[derive(Debug, Error, Diagnostic)]
109#[error("policy failed to validate against the schema")]
110pub struct PolicyValidationError {
111    #[related]
112    pub(super) errors: Vec<ValidationError>,
113}
114
115impl PolicyValidationError {
116    pub(crate) fn new(errors: Vec<ValidationError>) -> Self {
117        Self { errors }
118    }
119
120    /// The underlying validation errors
121    pub fn errors(&self) -> impl Iterator<Item = &ValidationError> {
122        self.errors.iter()
123    }
124}
125
126/// Residuals require fully typed expressions without
127/// unknowns or parse errors.
128#[derive(Debug, Error, Diagnostic)]
129#[non_exhaustive]
130pub enum ExprToResidualError {
131    /// Expression is missing type annotation
132    #[error(transparent)]
133    #[diagnostic(transparent)]
134    MissingTypeAnnotation(#[from] MissingTypeAnnotationError),
135    /// Expression contains a slot which is not supported in residuals
136    #[error(transparent)]
137    #[diagnostic(transparent)]
138    UnlinkedSlotError(#[from] UnlinkedSlotError),
139    /// Expression contains an unknown which is not supported in residuals
140    #[error(transparent)]
141    #[diagnostic(transparent)]
142    UnknownNotSupported(#[from] UnknownNotSupportedError),
143    /// Expression contains an error which is not supported in residuals
144    #[error(transparent)]
145    #[diagnostic(transparent)]
146    ErrorNotSupported(#[from] ErrorNotSupportedError),
147}
148
149/// Error thrown when expression is missing type annotation
150#[derive(Debug, Error, Diagnostic)]
151#[error("expression is missing a type annotation")]
152#[diagnostic(help(
153    "expressions must be typechecked by the policy validator before partial evaluation"
154))]
155pub struct MissingTypeAnnotationError;
156
157/// Error thrown when expression contains an unknown which is not supported in residuals
158#[derive(Debug, Error, Diagnostic)]
159#[error("expression contains an unknown, which is not supported in residuals")]
160pub struct UnknownNotSupportedError;
161
162/// Error thrown when expression contains an error which is not supported in residuals
163#[derive(Debug, Error, Diagnostic)]
164#[error("expression contains an error node, which is not supported in residuals")]
165pub struct ErrorNotSupportedError;
166
167/// Error when a request was expected to be concrete
168#[derive(Debug, Error, Diagnostic)]
169#[error("expected a concrete request, but found a partial request")]
170pub struct PartialRequestError {}
171
172/// Error thrown when there is no matching request environment according to a
173/// schema
174#[derive(Debug, Error, Diagnostic)]
175#[error("no request environment in the schema matches the given request")]
176pub struct NoMatchingReqEnvError;
177
178/// Error thrown when constructing [`crate::tpe::entities::PartialEntities`]
179#[derive(Debug, Error, Diagnostic)]
180pub enum EntitiesError {
181    /// Error thrown when validating concrete components
182    #[error(transparent)]
183    #[diagnostic(transparent)]
184    Deserialization(#[from] JsonDeserializationError),
185    /// Error thrown when validating a [`crate::tpe::entities::PartialEntity`]
186    #[error(transparent)]
187    #[diagnostic(transparent)]
188    Validation(#[from] EntityValidationError),
189    /// Error thrown when validating the ancestors of a [`crate::tpe::entities::PartialEntity`]
190    #[error(transparent)]
191    #[diagnostic(transparent)]
192    AncestorValidation(#[from] AncestorValidationError),
193    /// Error thrown when computing TC
194    #[error(transparent)]
195    #[diagnostic(transparent)]
196    TCComputation(#[from] TcError<EntityUID>),
197    /// Error constructing the Entities collection due to encountering two
198    /// different entities with the same Entity UID
199    #[error(transparent)]
200    #[diagnostic(transparent)]
201    Duplicate(#[from] Duplicate),
202    /// Errors encountered when converting `PartialValue` to `Value`
203    #[error(transparent)]
204    #[diagnostic(transparent)]
205    PartialValueToValue(#[from] PartialValueToValueError),
206}
207
208/// Error thrown when checking the consistency between [`crate::tpe::entities::PartialEntities`] and
209/// [`crate::entities::Entities`]
210#[derive(Debug, Error, Diagnostic)]
211pub enum EntitiesConsistencyError {
212    /// Error thrown when there is an entity missing in the concrete entities
213    #[error(transparent)]
214    #[diagnostic(transparent)]
215    MissingEntity(#[from] MissingEntityError),
216    /// Error thrown when concrete entities contain unknown entities
217    #[error(transparent)]
218    #[diagnostic(transparent)]
219    UnknownEntity(#[from] UnknownEntityError),
220    /// Error thrown when a concrete entity and a partial entity are
221    /// inconsistent
222    #[error(transparent)]
223    #[diagnostic(transparent)]
224    InconsistentEntity(#[from] EntityConsistencyError),
225}
226
227/// Error thrown when checking the consistency between [`crate::tpe::entities::PartialEntity`] and
228/// [`crate::ast::Entity`]
229#[derive(Debug, Error, Diagnostic)]
230pub enum EntityConsistencyError {
231    /// Error thrown when the concrete entity contains unknown attribute
232    #[error(transparent)]
233    #[diagnostic(transparent)]
234    UnknownAttribute(#[from] UnknownAttributeError),
235    /// Error thrown when attributes mismatch
236    #[error(transparent)]
237    #[diagnostic(transparent)]
238    MismatchedAttribute(#[from] MismatchedAttributeError),
239    /// Error thrown when ancestors do not match
240    #[error(transparent)]
241    #[diagnostic(transparent)]
242    MismatchedAncestor(#[from] MismatchedAncestorError),
243    /// Error thrown when the concrete entity contains unknown tag
244    #[error(transparent)]
245    #[diagnostic(transparent)]
246    UnknownTag(#[from] UnknownTagError),
247    /// Error thrown when tags mismatch
248    #[error(transparent)]
249    #[diagnostic(transparent)]
250    MismatchedTag(#[from] MismatchedTagError),
251}
252
253/// Error thrown when the concrete entity contains unknown attribute
254#[derive(Debug, Error, Diagnostic)]
255#[error("concrete entity `{uid}` has attribute `{attr}` not present in the partial entity")]
256pub struct UnknownAttributeError {
257    pub(super) uid: EntityUID,
258    pub(super) attr: SmolStr,
259}
260
261/// Error thrown when attributes mismatch
262#[derive(Debug, Error, Diagnostic)]
263#[error("concrete entity `{uid}` has attribute values that do not match the partial entity")]
264pub struct MismatchedAttributeError {
265    pub(super) uid: EntityUID,
266}
267
268/// Error thrown when the concrete entity contains unknown tag
269#[derive(Debug, Error, Diagnostic)]
270#[error("concrete entity `{uid}` has tag `{tag}` not present in the partial entity")]
271pub struct UnknownTagError {
272    pub(super) uid: EntityUID,
273    pub(super) tag: SmolStr,
274}
275
276/// Error thrown when tags mismatch
277#[derive(Debug, Error, Diagnostic)]
278#[error("concrete entity `{uid}` has tag values that do not match the partial entity")]
279pub struct MismatchedTagError {
280    pub(super) uid: EntityUID,
281}
282
283/// Error thrown when ancestors do not match
284#[derive(Debug, Error, Diagnostic)]
285#[error("concrete entity `{uid}` has ancestors that do not match the partial entity")]
286pub struct MismatchedAncestorError {
287    pub(super) uid: EntityUID,
288}
289
290/// Error thrown when when there is an entity missing in the concrete entities
291#[derive(Debug, Error, Diagnostic)]
292#[error("entity `{uid}` is present in the partial entities but missing from the concrete entities")]
293pub struct MissingEntityError {
294    pub(super) uid: EntityUID,
295}
296
297/// Error thrown when concrete entities contain unknown entities
298#[derive(Debug, Error, Diagnostic)]
299#[error("concrete entities contain unknown entity `{uid}`")]
300pub struct UnknownEntityError {
301    pub(super) uid: EntityUID,
302}
303
304/// Error thrown when a [`crate::tpe::request::PartialRequest`] is inconsistent with a [`crate::ast::Request`]
305#[derive(Debug, Error, Diagnostic)]
306pub enum RequestConsistencyError {
307    /// Error thrown when the concrete principal is unknown
308    #[error("the concrete request's principal is unknown")]
309    UnknownPrincipal,
310    /// Error thrown when the concrete resource is unknown
311    #[error("the concrete request's resource is unknown")]
312    UnknownResource,
313    /// Error thrown when the concrete action is unknown
314    #[error("the concrete request's action is unknown")]
315    UnknownAction,
316    /// Error thrown when the concrete context is unknown
317    #[error("the concrete request's context is unknown")]
318    UnknownContext,
319    /// Error thrown when principal types are inconsistent
320    #[error(transparent)]
321    #[diagnostic(transparent)]
322    InconsistentPrincipalType(#[from] InconsistentPrincipalTypeError),
323    /// Error thrown when principal eids are inconsistent
324    #[error(transparent)]
325    #[diagnostic(transparent)]
326    InconsistentPrincipalEid(#[from] InconsistentPrincipalEidError),
327    /// Error thrown when resource types are inconsistent
328    #[error(transparent)]
329    #[diagnostic(transparent)]
330    InconsistentResourceType(#[from] InconsistentResourceTypeError),
331    /// Error thrown when resource eids are inconsistent
332    #[error(transparent)]
333    #[diagnostic(transparent)]
334    InconsistentResourceEid(#[from] InconsistentResourceEidError),
335    /// Error thrown when actions are inconsistent
336    #[error(transparent)]
337    #[diagnostic(transparent)]
338    InconsistentAction(#[from] InconsistentActionError),
339    /// Error thrown when contexts are inconsistent
340    #[error("the partial and concrete request contexts do not match")]
341    InconsistentContext,
342    /// Error thrown when the concrete context contains unknowns
343    #[error("the concrete request's context contains unknowns")]
344    ConcreteContextContainsUnknowns,
345}
346
347/// Error thrown when principal types are inconsistent
348#[derive(Debug, Error, Diagnostic)]
349#[error("partial request principal type `{partial}` does not match concrete request principal type `{concrete}`")]
350pub struct InconsistentPrincipalTypeError {
351    pub(super) partial: EntityType,
352    pub(super) concrete: EntityType,
353}
354
355/// Error thrown when principal eids are inconsistent
356#[derive(Debug, Error, Diagnostic)]
357#[error("partial request principal id `{}` does not match concrete request principal id `{}`", .partial.escaped(), .concrete.escaped())]
358pub struct InconsistentPrincipalEidError {
359    pub(super) partial: Eid,
360    pub(super) concrete: Eid,
361}
362
363/// Error thrown when resource types are inconsistent
364#[derive(Debug, Error, Diagnostic)]
365#[error("partial request resource type `{partial}` does not match concrete request resource type `{concrete}`")]
366pub struct InconsistentResourceTypeError {
367    pub(super) partial: EntityType,
368    pub(super) concrete: EntityType,
369}
370
371/// Error thrown when resource eids are inconsistent
372#[derive(Debug, Error, Diagnostic)]
373#[error("partial request resource id `{}` does not match concrete request resource id `{}`", .partial.escaped(), .concrete.escaped())]
374pub struct InconsistentResourceEidError {
375    pub(super) partial: Eid,
376    pub(super) concrete: Eid,
377}
378
379/// Error thrown when actions are inconsistent
380#[derive(Debug, Error, Diagnostic)]
381#[error("partial request action `{partial}` does not match concrete request action `{concrete}`")]
382pub struct InconsistentActionError {
383    pub(super) partial: EntityUID,
384    pub(super) concrete: EntityUID,
385}
386
387/// Error thrown during reauthorization
388#[derive(Debug, Error, Diagnostic)]
389pub enum ReauthorizationError {
390    /// Error thrown when request validation fails
391    #[error(transparent)]
392    #[diagnostic(transparent)]
393    RequestValidation(#[from] RequestValidationError),
394    /// Error thrown when entity validation fails
395    #[error(transparent)]
396    #[diagnostic(transparent)]
397    EntityValidation(#[from] EntitySchemaConformanceError),
398    /// Error thrown when entities and partial entities are inconsistent
399    #[error(transparent)]
400    #[diagnostic(transparent)]
401    EntitiesConsistency(#[from] EntitiesConsistencyError),
402    /// Error thrown when request and partial request are inconsistent
403    #[error(transparent)]
404    #[diagnostic(transparent)]
405    RequestConsistency(#[from] RequestConsistencyError),
406}