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 std::fmt::Display;
21
22use smol_str::SmolStr;
23use thiserror::Error;
24
25use crate::{
26    ast::{Eid, EntityType, EntityUID, PartialValueToValueError},
27    entities::{
28        conformance::err::{EntitySchemaConformanceError, InvalidEnumEntityError},
29        err::Duplicate,
30    },
31    evaluator::{evaluation_errors::UnlinkedSlotError, EvaluationError},
32    transitive_closure::TcError,
33    validator::{RequestValidationError, ValidationError},
34};
35
36/// Error thrown when encountered an action
37#[derive(Debug, Error)]
38#[error("Unexpected action: `{}`", .action)]
39pub struct UnexpectedActionError {
40    pub(super) action: EntityUID,
41}
42
43/// Error thrown when deserializing a [`crate::tpe::entities::PartialEntity`]
44#[derive(Debug, Error)]
45pub enum JsonDeserializationError {
46    /// Error thrown when deserializing concrete components
47    #[error(transparent)]
48    Concrete(#[from] crate::entities::json::err::JsonDeserializationError),
49    /// Error thrown when encountered an action
50    /// Actions are automatically inserted from a schema
51    #[error(transparent)]
52    UnexpectedAction(#[from] UnexpectedActionError),
53    /// Error thrown when a restricted expression does not evaluate to a value
54    #[error(transparent)]
55    RestrictedExprEvaluation(#[from] EvaluationError),
56}
57
58/// Error thrown when validating a [`crate::tpe::entities::PartialEntity`]
59#[derive(Debug, Error)]
60pub enum EntityValidationError {
61    /// Error thrown when validating concrete components
62    #[error(transparent)]
63    Concrete(#[from] EntitySchemaConformanceError),
64    /// Error thrown when an action component is unknown
65    #[error(transparent)]
66    UnknownActionComponent(#[from] UnknownActionComponentError),
67    /// Error thrown when an action's ancestors do not match the schema
68    #[error(transparent)]
69    MismatchedActionAncestors(#[from] MismatchedActionAncestorsError),
70}
71
72/// Error thrown when an action has unknown ancestors/attrs/tags
73#[derive(Debug, Error)]
74#[error("action `{}` has unknown ancestors/attrs/tags", .action)]
75pub struct UnknownActionComponentError {
76    pub(super) action: EntityUID,
77}
78
79/// Error thrown when an action's ancestors do not match the schema
80#[derive(Debug, Error)]
81#[error("action `{}`'s ancestors do not match the schema", .action)]
82pub struct MismatchedActionAncestorsError {
83    pub(super) action: EntityUID,
84}
85
86/// Error thrown when an ancestor of an ancestor is unknown
87#[derive(Debug, Error)]
88#[error("`{}`'s ancestor `{}` has unknown ancestors", .uid, .ancestor)]
89pub struct AncestorValidationError {
90    pub(crate) uid: EntityUID,
91    pub(crate) ancestor: EntityUID,
92}
93
94/// Errors for TPE
95#[derive(Debug, Error)]
96pub enum TpeError {
97    /// Error thrown when there is no matching request environment according to
98    /// a schema
99    #[error(transparent)]
100    NoMatchingReqEnv(#[from] NoMatchingReqEnvError),
101    /// Error thrown when TPE is applied to a non-static policy
102    #[error(transparent)]
103    NonstaticPolicy(#[from] NonstaticPolicyError),
104    /// Error thrown when the typechecker fails to typecheck a policy
105    #[error("Failed validation: {:#?}", .0)]
106    Validation(Vec<ValidationError>),
107    /// Error when an expression is not supported by batched evaluation
108    #[error(transparent)]
109    ExprToResidualError(#[from] ExprToResidualError),
110}
111
112/// Residuals require fully typed expressions without
113/// unknowns or parse errors.
114#[derive(Debug, Error)]
115#[non_exhaustive]
116pub enum ExprToResidualError {
117    /// Expression is missing type annotation
118    #[error(transparent)]
119    MissingTypeAnnotation(#[from] MissingTypeAnnotationError),
120    /// Expression contains a slot which is not supported in residuals
121    #[error(transparent)]
122    UnlinkedSlotError(#[from] UnlinkedSlotError),
123    /// Expression contains an unknown which is not supported in residuals
124    #[error(transparent)]
125    UnknownNotSupported(#[from] UnknownNotSupportedError),
126    /// Expression contains an error which is not supported in residuals
127    #[error(transparent)]
128    ErrorNotSupported(#[from] ErrorNotSupportedError),
129}
130
131/// Error thrown when expression is missing type annotation
132#[derive(Debug, Error)]
133#[error("Expression is missing type annotation")]
134pub struct MissingTypeAnnotationError;
135
136/// Error thrown when expression contains an unknown which is not supported in residuals
137#[derive(Debug, Error)]
138#[error("Expression contains an unknown which is not supported in residuals")]
139pub struct UnknownNotSupportedError;
140
141/// Error thrown when expression contains an error which is not supported in residuals
142#[derive(Debug, Error)]
143#[error("Expression contains an error which is not supported in residuals")]
144pub struct ErrorNotSupportedError;
145
146/// Error when a request was expected to be concrete
147#[derive(Debug, Error)]
148#[error("Found a partial request when a concrete request was expected")]
149pub struct PartialRequestError {}
150
151/// Error thrown when there is no matching request environment according to a
152/// schema
153#[derive(Debug, Error)]
154#[error("Can't find a matching request environment")]
155pub struct NoMatchingReqEnvError;
156
157/// Error thrown when TPE is applied to a non-static policy
158#[derive(Debug, Error)]
159#[error("Found a non-static policy")]
160pub struct NonstaticPolicyError;
161
162/// Error thrown when using a [`crate::tpe::request::RequestBuilder`]
163#[derive(Debug, Error)]
164pub enum RequestBuilderError {
165    /// Error thrown when the request cannot be validated
166    #[error(transparent)]
167    Validation(#[from] RequestValidationError),
168    /// Error thrown when attempting to add a principal when one exists
169    #[error(transparent)]
170    ExistingPrincipal(#[from] ExistingPrincipalError),
171    /// Error thrown when attempting to add a resource when one exists
172    #[error(transparent)]
173    ExistingResource(#[from] ExistingResourceError),
174    /// Error thrown when attempting to add a context when one exists
175    #[error("Context already exists")]
176    ExistingContext,
177    /// Error thrown when attempting to add a principal with an incorrect
178    /// entity type
179    #[error(transparent)]
180    IncorrectPrincipalEntityType(#[from] IncorrectPrincipalEntityTypeError),
181    /// Error thrown when attempting to add a resource with an incorrect
182    /// entity type
183    #[error(transparent)]
184    IncorrectResourceEntityType(#[from] IncorrectResourceEntityTypeError),
185    /// Error thrown when the principal candidate is invalid
186    #[error("invalid principal candidate: {}", .0)]
187    InvalidPrincipalCandidate(InvalidEnumEntityError),
188    /// Error thrown when the resource candidate is invalid
189    #[error("invalid resource candidate: {}", .0)]
190    InvalidResourceCandidate(InvalidEnumEntityError),
191    /// Error thrown when the context candidate is invalid
192    #[error("context candidate doesn't validate: {}", .0)]
193    IllTypedContextCandidate(RequestValidationError),
194    /// Error thrown when the context candidate contains unknowns
195    #[error("context candidate contains unknowns")]
196    UnknownContextCandidate,
197}
198
199/// Error thrown when attempting to add a principal with an incorrect
200/// entity type
201#[derive(Debug, Error)]
202#[error("Principal `{}` already exists", .principal)]
203pub struct ExistingPrincipalError {
204    pub(super) principal: EntityUID,
205}
206
207/// Error thrown when attempting to add a resource with an incorrect
208/// entity type
209#[derive(Debug, Error)]
210#[error("Resource `{}` already exists", .resource)]
211pub struct ExistingResourceError {
212    pub(super) resource: EntityUID,
213}
214
215/// Error thrown when attempting to add a principal with an incorrect
216/// entity type
217#[derive(Debug, Error)]
218#[error("Principal type `{}` is inconsistent with the partial request's `{}`", .ty, .expected)]
219pub struct IncorrectPrincipalEntityTypeError {
220    pub(super) ty: EntityType,
221    pub(super) expected: EntityType,
222}
223
224/// Error thrown when attempting to add a resource with an incorrect
225/// entity type
226#[derive(Debug, Error)]
227#[error("Resource type `{}` is inconsistent with the partial request's `{}`", .ty, .expected)]
228pub struct IncorrectResourceEntityTypeError {
229    pub(super) ty: EntityType,
230    pub(super) expected: EntityType,
231}
232
233/// Error thrown when constructing [`crate::tpe::entities::PartialEntities`]
234#[derive(Debug, Error)]
235pub enum EntitiesError {
236    /// Error thrown when validating concrete components
237    #[error(transparent)]
238    Deserialization(#[from] JsonDeserializationError),
239    /// Error thrown when validating a [`crate::tpe::entities::PartialEntity`]
240    #[error(transparent)]
241    Validation(#[from] EntityValidationError),
242    /// Error thrown when validating the ancestors of a [`crate::tpe::entities::PartialEntity`]
243    #[error(transparent)]
244    AncestorValidation(#[from] AncestorValidationError),
245    /// Error thrown when computing TC
246    #[error(transparent)]
247    TCComputation(#[from] TcError<EntityUID>),
248    /// Error constructing the Entities collection due to encountering two
249    /// different entities with the same Entity UID
250    #[error(transparent)]
251    Duplicate(#[from] Duplicate),
252    /// Errors encountered when converting `PartialValue` to `Value`
253    #[error(transparent)]
254    PartialValueToValue(#[from] PartialValueToValueError),
255}
256
257/// Error thrown when checking the consistency between [`crate::tpe::entities::PartialEntities`] and
258/// [`crate::entities::Entities`]
259#[derive(Debug, Error)]
260pub enum EntitiesConsistencyError {
261    /// Error thrown when there is an entity missing in the concrete entities
262    #[error(transparent)]
263    MissingEntity(#[from] MissingEntityError),
264    /// Error thrown when concrete entities contain unknown entities
265    #[error(transparent)]
266    UnknownEntity(#[from] UnknownEntityError),
267    /// Error thrown when a concrete entity and a partial entity are
268    /// inconsistent
269    #[error(transparent)]
270    InconsistentEntity(#[from] EntityConsistencyError),
271}
272
273/// Error thrown when checking the consistency between [`crate::tpe::entities::PartialEntity`] and
274/// [`crate::ast::Entity`]
275#[derive(Debug, Error)]
276pub enum EntityConsistencyError {
277    /// Error thrown when the concrete entity contains unknown attribute
278    #[error(transparent)]
279    UnknownAttribute(#[from] UnknownAttributeError),
280    /// Error thrown when attributes mismatch
281    #[error(transparent)]
282    MismatchedAttribute(#[from] MismatchedAttributeError),
283    /// Error thrown when ancestors do not match
284    #[error(transparent)]
285    MismatchedAncestor(#[from] MismatchedAncestorError),
286    /// Error thrown when the concrete entity contains unknown tag
287    #[error(transparent)]
288    UnknownTag(#[from] UnknownTagError),
289    /// Error thrown when tags mismatch
290    #[error(transparent)]
291    MismatchedTag(#[from] MismatchedTagError),
292}
293
294/// Error thrown when the concrete entity contains unknown attribute
295#[derive(Debug, Error)]
296#[error("Concrete entity `{uid}` contains unknown attribute `{attr}`")]
297pub struct UnknownAttributeError {
298    pub(super) uid: EntityUID,
299    pub(super) attr: SmolStr,
300}
301
302/// Error thrown when attributes mismatch
303#[derive(Debug, Error)]
304#[error("Entity `{uid}`'s attributes do not match")]
305pub struct MismatchedAttributeError {
306    pub(super) uid: EntityUID,
307}
308
309/// Error thrown when the concrete entity contains unknown tag
310#[derive(Debug, Error)]
311#[error("Concrete entity `{uid}` contains unknown tag `{tag}`")]
312pub struct UnknownTagError {
313    pub(super) uid: EntityUID,
314    pub(super) tag: SmolStr,
315}
316
317/// Error thrown when tags mismatch
318#[derive(Debug, Error)]
319#[error("Entity `{uid}`'s tags do not match")]
320pub struct MismatchedTagError {
321    pub(super) uid: EntityUID,
322}
323
324/// Error thrown when ancestors do not match
325#[derive(Debug, Error)]
326#[error("Entity `{uid}`'s ancestors do not match")]
327pub struct MismatchedAncestorError {
328    pub(super) uid: EntityUID,
329}
330
331/// Error thrown when when there is an entity missing in the concrete entities
332#[derive(Debug, Error)]
333#[error("Concrete entities does not include `{uid}`")]
334pub struct MissingEntityError {
335    pub(super) uid: EntityUID,
336}
337
338/// Error thrown when concrete entities contain unknown entities
339#[derive(Debug, Error)]
340#[error("Concrete entities contains unknown entity `{uid}`")]
341pub struct UnknownEntityError {
342    pub(super) uid: EntityUID,
343}
344
345/// Error thrown when some requested entities were not loaded
346#[derive(Debug, Error)]
347pub struct MissingEntitiesError {
348    pub(super) missing_entities: Vec<EntityUID>,
349}
350
351impl MissingEntitiesError {
352    /// Construct a new [`MissingEntitiesError`]
353    pub fn new(missing_entities: Vec<EntityUID>) -> Self {
354        Self { missing_entities }
355    }
356}
357
358impl Display for MissingEntitiesError {
359    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
360        write!(
361            f,
362            "Failed to load entities: {}",
363            self.missing_entities
364                .iter()
365                .map(|uid| uid.to_string())
366                .collect::<Vec<_>>()
367                .join(", ")
368        )
369    }
370}
371
372/// Error thrown when a [`crate::tpe::request::PartialRequest`] is consistent with a [`crate::ast::Request`]
373#[derive(Debug, Error)]
374pub enum RequestConsistencyError {
375    /// Error thrown when the concrete principal is unknown
376    #[error("Concrete principal is unknown")]
377    UnknownPrincipal,
378    /// Error thrown when the concrete resource is unknown
379    #[error("Concrete resource is unknown")]
380    UnknownResource,
381    /// Error thrown when the concrete action is unknown
382    #[error("Concrete action is unknown")]
383    UnknownAction,
384    /// Error thrown when the concrete context is unknown
385    #[error("Concrete context is unknown")]
386    UnknownContext,
387    /// Error thrown when principal types are inconsistent
388    #[error(transparent)]
389    InconsistentPrincipalType(#[from] InconsistentPrincipalTypeError),
390    /// Error thrown when principal eids are inconsistent
391    #[error(transparent)]
392    InconsistentPrincipalEid(#[from] InconsistentPrincipalEidError),
393    /// Error thrown when resource types are inconsistent
394    #[error(transparent)]
395    InconsistentResourceType(#[from] InconsistentResourceTypeError),
396    /// Error thrown when resource eids are inconsistent
397    #[error(transparent)]
398    InconsistentResourceEid(#[from] InconsistentResourceEidError),
399    /// Error thrown when actions are inconsistent
400    #[error(transparent)]
401    InconsistentAction(#[from] InconsistentActionError),
402    /// Error thrown when contexts are inconsistent
403    #[error("Contexts are inconsistent")]
404    InconsistentContext,
405    /// Error thrown when the concrete context contains unknowns
406    #[error("Concrete context contains unknowns")]
407    ConcreteContextContainsUnknowns,
408}
409
410/// Error thrown when principal types are inconsistent
411#[derive(Debug, Error)]
412#[error("Principal types `{partial}` and `{concrete}` do not match")]
413pub struct InconsistentPrincipalTypeError {
414    pub(super) partial: EntityType,
415    pub(super) concrete: EntityType,
416}
417
418/// Error thrown when principal eids are inconsistent
419#[derive(Debug, Error)]
420#[error("Principal eid `{}` and `{}` do not match", .partial.escaped(), .concrete.escaped())]
421pub struct InconsistentPrincipalEidError {
422    pub(super) partial: Eid,
423    pub(super) concrete: Eid,
424}
425
426/// Error thrown when resource types are inconsistent
427#[derive(Debug, Error)]
428#[error("Resource types `{partial}` and `{concrete}` do not match")]
429pub struct InconsistentResourceTypeError {
430    pub(super) partial: EntityType,
431    pub(super) concrete: EntityType,
432}
433
434/// Error thrown when resource eids are inconsistent
435#[derive(Debug, Error)]
436#[error("Resource eid `{}` and `{}` do not match", .partial.escaped(), .concrete.escaped())]
437pub struct InconsistentResourceEidError {
438    pub(super) partial: Eid,
439    pub(super) concrete: Eid,
440}
441
442/// Error thrown when actions are inconsistent
443#[derive(Debug, Error)]
444#[error("Actions `{}` and `{}` do not match", .partial, .concrete)]
445pub struct InconsistentActionError {
446    pub(super) partial: EntityUID,
447    pub(super) concrete: EntityUID,
448}
449
450/// Error thrown during reauthorization
451#[derive(Debug, Error)]
452pub enum ReauthorizationError {
453    /// Error thrown when request validation fails
454    #[error(transparent)]
455    RequestValidation(#[from] RequestValidationError),
456    /// Error thrown when entity validation fails
457    #[error(transparent)]
458    EntityValidation(#[from] EntitySchemaConformanceError),
459    /// Error thrown when entities and partial entities are inconsistent
460    #[error(transparent)]
461    EntitiesConsistentcy(#[from] EntitiesConsistencyError),
462    /// Error thrown when request and partial request are inconsistent
463    #[error(transparent)]
464    RequestConsistentcy(#[from] RequestConsistencyError),
465}