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::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    SlotNotSupported(#[from] SlotNotSupportedError),
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 a slot which is not supported in residuals
137#[derive(Debug, Error)]
138#[error("Expression contains a slot which is not supported in residuals")]
139pub struct SlotNotSupportedError;
140
141/// Error thrown when expression contains an unknown which is not supported in residuals
142#[derive(Debug, Error)]
143#[error("Expression contains an unknown which is not supported in residuals")]
144pub struct UnknownNotSupportedError;
145
146/// Error thrown when expression contains an error which is not supported in residuals
147#[derive(Debug, Error)]
148#[error("Expression contains an error which is not supported in residuals")]
149pub struct ErrorNotSupportedError;
150
151/// Error when a request was expected to be concrete
152#[derive(Debug, Error)]
153#[error("Found a partial request when a concrete request was expected")]
154pub struct PartialRequestError {}
155
156/// Error thrown when there is no matching request environment according to a
157/// schema
158#[derive(Debug, Error)]
159#[error("Can't find a matching request environment")]
160pub struct NoMatchingReqEnvError;
161
162/// Error thrown when TPE is applied to a non-static policy
163#[derive(Debug, Error)]
164#[error("Found a non-static policy")]
165pub struct NonstaticPolicyError;
166
167/// Error thrown when using a [`crate::tpe::request::RequestBuilder`]
168#[derive(Debug, Error)]
169pub enum RequestBuilderError {
170    /// Error thrown when the request cannot be validated
171    #[error(transparent)]
172    Validation(#[from] RequestValidationError),
173    /// Error thrown when attempting to add a principal when one exists
174    #[error(transparent)]
175    ExistingPrincipal(#[from] ExistingPrincipalError),
176    /// Error thrown when attempting to add a resource when one exists
177    #[error(transparent)]
178    ExistingResource(#[from] ExistingResourceError),
179    /// Error thrown when attempting to add a context when one exists
180    #[error("Context already exists")]
181    ExistingContext,
182    /// Error thrown when attempting to add a principal with an incorrect
183    /// entity type
184    #[error(transparent)]
185    IncorrectPrincipalEntityType(#[from] IncorrectPrincipalEntityTypeError),
186    /// Error thrown when attempting to add a resource with an incorrect
187    /// entity type
188    #[error(transparent)]
189    IncorrectResourceEntityType(#[from] IncorrectResourceEntityTypeError),
190    /// Error thrown when the principal candidate is invalid
191    #[error("invalid principal candidate: {}", .0)]
192    InvalidPrincipalCandidate(InvalidEnumEntityError),
193    /// Error thrown when the resource candidate is invalid
194    #[error("invalid resource candidate: {}", .0)]
195    InvalidResourceCandidate(InvalidEnumEntityError),
196    /// Error thrown when the context candidate is invalid
197    #[error("context candidate doesn't validate: {}", .0)]
198    IllTypedContextCandidate(RequestValidationError),
199    /// Error thrown when the context candidate contains unknowns
200    #[error("context candidate contains unknowns")]
201    UnknownContextCandidate,
202}
203
204/// Error thrown when attempting to add a principal with an incorrect
205/// entity type
206#[derive(Debug, Error)]
207#[error("Principal `{}` already exists", .principal)]
208pub struct ExistingPrincipalError {
209    pub(super) principal: EntityUID,
210}
211
212/// Error thrown when attempting to add a resource with an incorrect
213/// entity type
214#[derive(Debug, Error)]
215#[error("Resource `{}` already exists", .resource)]
216pub struct ExistingResourceError {
217    pub(super) resource: EntityUID,
218}
219
220/// Error thrown when attempting to add a principal with an incorrect
221/// entity type
222#[derive(Debug, Error)]
223#[error("Principal type `{}` is inconsistent with the partial request's `{}`", .ty, .expected)]
224pub struct IncorrectPrincipalEntityTypeError {
225    pub(super) ty: EntityType,
226    pub(super) expected: EntityType,
227}
228
229/// Error thrown when attempting to add a resource with an incorrect
230/// entity type
231#[derive(Debug, Error)]
232#[error("Resource type `{}` is inconsistent with the partial request's `{}`", .ty, .expected)]
233pub struct IncorrectResourceEntityTypeError {
234    pub(super) ty: EntityType,
235    pub(super) expected: EntityType,
236}
237
238/// Error thrown when constructing [`crate::tpe::entities::PartialEntities`]
239#[derive(Debug, Error)]
240pub enum EntitiesError {
241    /// Error thrown when validating concrete components
242    #[error(transparent)]
243    Deserialization(#[from] JsonDeserializationError),
244    /// Error thrown when validating a [`crate::tpe::entities::PartialEntity`]
245    #[error(transparent)]
246    Validation(#[from] EntityValidationError),
247    /// Error thrown when validating the ancestors of a [`crate::tpe::entities::PartialEntity`]
248    #[error(transparent)]
249    AncestorValidation(#[from] AncestorValidationError),
250    /// Error thrown when computing TC
251    #[error(transparent)]
252    TCComputation(#[from] TcError<EntityUID>),
253    /// Error constructing the Entities collection due to encountering two
254    /// different entities with the same Entity UID
255    #[error(transparent)]
256    Duplicate(#[from] Duplicate),
257    /// Errors encountered when converting `PartialValue` to `Value`
258    #[error(transparent)]
259    PartialValueToValue(#[from] PartialValueToValueError),
260}
261
262/// Error thrown when checking the consistency between [`crate::tpe::entities::PartialEntities`] and
263/// [`crate::entities::Entities`]
264#[derive(Debug, Error)]
265pub enum EntitiesConsistencyError {
266    /// Error thrown when there is an entity missing in the concrete entities
267    #[error(transparent)]
268    MissingEntity(#[from] MissingEntityError),
269    /// Error thrown when concrete entities contain unknown entities
270    #[error(transparent)]
271    UnknownEntity(#[from] UnknownEntityError),
272    /// Error thrown when a concrete entity and a partial entity are
273    /// inconsistent
274    #[error(transparent)]
275    InconsistentEntity(#[from] EntityConsistencyError),
276}
277
278/// Error thrown when checking the consistency between [`crate::tpe::entities::PartialEntity`] and
279/// [`crate::ast::Entity`]
280#[derive(Debug, Error)]
281pub enum EntityConsistencyError {
282    /// Error thrown when the concrete entity contains unknown attribute
283    #[error(transparent)]
284    UnknownAttribute(#[from] UnknownAttributeError),
285    /// Error thrown when attributes mismatch
286    #[error(transparent)]
287    MismatchedAttribute(#[from] MismatchedAttributeError),
288    /// Error thrown when ancestors do not match
289    #[error(transparent)]
290    MismatchedAncestor(#[from] MismatchedAncestorError),
291    /// Error thrown when the concrete entity contains unknown tag
292    #[error(transparent)]
293    UnknownTag(#[from] UnknownTagError),
294    /// Error thrown when tags mismatch
295    #[error(transparent)]
296    MismatchedTag(#[from] MismatchedTagError),
297}
298
299/// Error thrown when the concrete entity contains unknown attribute
300#[derive(Debug, Error)]
301#[error("Concrete entity `{uid}` contains unknown attribute `{attr}`")]
302pub struct UnknownAttributeError {
303    pub(super) uid: EntityUID,
304    pub(super) attr: SmolStr,
305}
306
307/// Error thrown when attributes mismatch
308#[derive(Debug, Error)]
309#[error("Entity `{uid}`'s attributes do not match")]
310pub struct MismatchedAttributeError {
311    pub(super) uid: EntityUID,
312}
313
314/// Error thrown when the concrete entity contains unknown tag
315#[derive(Debug, Error)]
316#[error("Concrete entity `{uid}` contains unknown tag `{tag}`")]
317pub struct UnknownTagError {
318    pub(super) uid: EntityUID,
319    pub(super) tag: SmolStr,
320}
321
322/// Error thrown when tags mismatch
323#[derive(Debug, Error)]
324#[error("Entity `{uid}`'s tags do not match")]
325pub struct MismatchedTagError {
326    pub(super) uid: EntityUID,
327}
328
329/// Error thrown when ancestors do not match
330#[derive(Debug, Error)]
331#[error("Entity `{uid}`'s ancestors do not match")]
332pub struct MismatchedAncestorError {
333    pub(super) uid: EntityUID,
334}
335
336/// Error thrown when when there is an entity missing in the concrete entities
337#[derive(Debug, Error)]
338#[error("Concrete entities does not include `{uid}`")]
339pub struct MissingEntityError {
340    pub(super) uid: EntityUID,
341}
342
343/// Error thrown when concrete entities contain unknown entities
344#[derive(Debug, Error)]
345#[error("Concrete entities contains unknown entity `{uid}`")]
346pub struct UnknownEntityError {
347    pub(super) uid: EntityUID,
348}
349
350/// Error thrown when some requested entities were not loaded
351#[derive(Debug, Error)]
352pub struct MissingEntitiesError {
353    pub(super) missing_entities: Vec<EntityUID>,
354}
355
356impl MissingEntitiesError {
357    /// Construct a new [`MissingEntitiesError`]
358    pub fn new(missing_entities: Vec<EntityUID>) -> Self {
359        Self { missing_entities }
360    }
361}
362
363impl Display for MissingEntitiesError {
364    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
365        write!(
366            f,
367            "Failed to load entities: {}",
368            self.missing_entities
369                .iter()
370                .map(|uid| uid.to_string())
371                .collect::<Vec<_>>()
372                .join(", ")
373        )
374    }
375}
376
377/// Error thrown when a [`crate::tpe::request::PartialRequest`] is consistent with a [`crate::ast::Request`]
378#[derive(Debug, Error)]
379pub enum RequestConsistencyError {
380    /// Error thrown when the concrete principal is unknown
381    #[error("Concrete principal is unknown")]
382    UnknownPrincipal,
383    /// Error thrown when the concrete resource is unknown
384    #[error("Concrete resource is unknown")]
385    UnknownResource,
386    /// Error thrown when the concrete action is unknown
387    #[error("Concrete action is unknown")]
388    UnknownAction,
389    /// Error thrown when the concrete context is unknown
390    #[error("Concrete context is unknown")]
391    UnknownContext,
392    /// Error thrown when principal types are inconsistent
393    #[error(transparent)]
394    InconsistentPrincipalType(#[from] InconsistentPrincipalTypeError),
395    /// Error thrown when principal eids are inconsistent
396    #[error(transparent)]
397    InconsistentPrincipalEid(#[from] InconsistentPrincipalEidError),
398    /// Error thrown when resource types are inconsistent
399    #[error(transparent)]
400    InconsistentResourceType(#[from] InconsistentResourceTypeError),
401    /// Error thrown when resource eids are inconsistent
402    #[error(transparent)]
403    InconsistentResourceEid(#[from] InconsistentResourceEidError),
404    /// Error thrown when actions are inconsistent
405    #[error(transparent)]
406    InconsistentAction(#[from] InconsistentActionError),
407    /// Error thrown when contexts are inconsistent
408    #[error("Contexts are inconsistent")]
409    InconsistentContext,
410    /// Error thrown when the concrete context contains unknowns
411    #[error("Concrete context contains unknowns")]
412    ConcreteContextContainsUnknowns,
413}
414
415/// Error thrown when principal types are inconsistent
416#[derive(Debug, Error)]
417#[error("Principal types `{partial}` and `{concrete}` do not match")]
418pub struct InconsistentPrincipalTypeError {
419    pub(super) partial: EntityType,
420    pub(super) concrete: EntityType,
421}
422
423/// Error thrown when principal eids are inconsistent
424#[derive(Debug, Error)]
425#[error("Principal eid `{}` and `{}` do not match", .partial.escaped(), .concrete.escaped())]
426pub struct InconsistentPrincipalEidError {
427    pub(super) partial: Eid,
428    pub(super) concrete: Eid,
429}
430
431/// Error thrown when resource types are inconsistent
432#[derive(Debug, Error)]
433#[error("Resource types `{partial}` and `{concrete}` do not match")]
434pub struct InconsistentResourceTypeError {
435    pub(super) partial: EntityType,
436    pub(super) concrete: EntityType,
437}
438
439/// Error thrown when resource eids are inconsistent
440#[derive(Debug, Error)]
441#[error("Resource eid `{}` and `{}` do not match", .partial.escaped(), .concrete.escaped())]
442pub struct InconsistentResourceEidError {
443    pub(super) partial: Eid,
444    pub(super) concrete: Eid,
445}
446
447/// Error thrown when actions are inconsistent
448#[derive(Debug, Error)]
449#[error("Actions `{}` and `{}` do not match", .partial, .concrete)]
450pub struct InconsistentActionError {
451    pub(super) partial: EntityUID,
452    pub(super) concrete: EntityUID,
453}
454
455/// Error thrown during reauthorization
456#[derive(Debug, Error)]
457pub enum ReauthorizationError {
458    /// Error thrown when request validation fails
459    #[error(transparent)]
460    RequestValidation(#[from] RequestValidationError),
461    /// Error thrown when entity validation fails
462    #[error(transparent)]
463    EntityValidation(#[from] EntitySchemaConformanceError),
464    /// Error thrown when entities and partial entities are inconsistent
465    #[error(transparent)]
466    EntitiesConsistentcy(#[from] EntitiesConsistencyError),
467    /// Error thrown when request and partial request are inconsistent
468    #[error(transparent)]
469    RequestConsistentcy(#[from] RequestConsistencyError),
470}