Skip to main content

cedar_policy/api/
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 defines the publicly exported error types.
18
19use crate::{EntityUid, PolicyId};
20pub use cedar_policy_core::ast::{
21    expression_construction_errors, restricted_expr_errors, ContainsUnknown,
22    ExpressionConstructionError, PartialValueToValueError, RestrictedExpressionError,
23};
24#[cfg(feature = "tpe")]
25use cedar_policy_core::entities::conformance::err::EntitySchemaConformanceError;
26#[cfg(feature = "entity-manifest")]
27use cedar_policy_core::entities::err::EntitiesError;
28pub use cedar_policy_core::evaluator::{evaluation_errors, EvaluationError};
29pub use cedar_policy_core::extensions::{
30    extension_function_lookup_errors, ExtensionFunctionLookupError,
31};
32pub use cedar_policy_core::validator::cedar_schema::{schema_warnings, SchemaWarning};
33#[cfg(feature = "entity-manifest")]
34pub use cedar_policy_core::validator::entity_manifest::slicing::EntitySliceError;
35#[cfg(feature = "entity-manifest")]
36use cedar_policy_core::validator::entity_manifest::{
37    self, PartialExpressionError, PartialRequestError, UnsupportedCedarFeatureError,
38};
39pub use cedar_policy_core::validator::{schema_errors, SchemaError};
40use cedar_policy_core::{ast, authorizer, est, pst};
41use miette::Diagnostic;
42use ref_cast::RefCast;
43use serde::ser::Error;
44use smol_str::SmolStr;
45use thiserror::Error;
46use to_cedar_syntax_errors::NameCollisionsError;
47use to_cedar_syntax_errors::UnconvertibleEntityTypeShapeError;
48
49#[cfg(feature = "entity-manifest")]
50use super::ValidationResult;
51
52#[cfg(feature = "tpe")]
53pub use cedar_policy_core::tpe::err as tpe_err;
54
55/// Errors related to [`crate::Entities`]
56pub mod entities_errors {
57    pub use cedar_policy_core::entities::err::{Duplicate, EntitiesError, TransitiveClosureError};
58}
59
60/// Errors related to serializing/deserializing entities or contexts to/from JSON
61pub mod entities_json_errors {
62    pub use cedar_policy_core::entities::json::err::{
63        ActionParentIsNotAction, DuplicateKey, ExpectedExtnValue, ExpectedLiteralEntityRef,
64        ExtnCall0Arguments, ExtnCall2OrMoreArguments, JsonDeserializationError, JsonError,
65        JsonSerializationError, MissingImpliedConstructor, MissingRequiredRecordAttr, ParseEscape,
66        ReservedKey, Residual, TypeMismatch, UnexpectedRecordAttr, UnexpectedRestrictedExprKind,
67    };
68}
69
70/// Errors related to schema conformance checking for entities
71pub mod conformance_errors {
72    pub use cedar_policy_core::entities::conformance::err::{
73        ActionDeclarationMismatch, EntitySchemaConformanceError, ExtensionFunctionLookup,
74        InvalidAncestorType, MissingRequiredEntityAttr, TypeMismatch, UndeclaredAction,
75        UnexpectedEntityAttr, UnexpectedEntityTag, UnexpectedEntityTypeError,
76    };
77}
78
79/// Errors that can occur during authorization
80#[derive(Debug, Diagnostic, PartialEq, Eq, Error, Clone)]
81pub enum AuthorizationError {
82    /// An error occurred when evaluating a policy.
83    #[error(transparent)]
84    #[diagnostic(transparent)]
85    PolicyEvaluationError(#[from] authorization_errors::PolicyEvaluationError),
86}
87
88/// Error subtypes for [`AuthorizationError`]
89pub mod authorization_errors {
90    use crate::{EvaluationError, PolicyId};
91    use cedar_policy_core::{ast, authorizer};
92    use miette::Diagnostic;
93    use ref_cast::RefCast;
94    use thiserror::Error;
95
96    /// An error occurred when evaluating a policy
97    #[derive(Debug, Diagnostic, PartialEq, Eq, Error, Clone)]
98    #[error("error while evaluating policy `{id}`: {error}")]
99    #[diagnostic(forward(error))]
100    pub struct PolicyEvaluationError {
101        /// Id of the policy with an error
102        id: ast::PolicyID,
103        /// Underlying evaluation error
104        error: EvaluationError,
105    }
106
107    impl PolicyEvaluationError {
108        /// Get the [`PolicyId`] of the erroring policy
109        pub fn policy_id(&self) -> &PolicyId {
110            PolicyId::ref_cast(&self.id)
111        }
112
113        /// Get the underlying [`EvaluationError`]
114        pub fn inner(&self) -> &EvaluationError {
115            &self.error
116        }
117
118        /// Consume this error, producing the underlying [`EvaluationError`]
119        pub fn into_inner(self) -> EvaluationError {
120            self.error
121        }
122    }
123
124    #[doc(hidden)]
125    impl From<authorizer::AuthorizationError> for PolicyEvaluationError {
126        fn from(e: authorizer::AuthorizationError) -> Self {
127            match e {
128                authorizer::AuthorizationError::PolicyEvaluationError { id, error } => {
129                    Self { id, error }
130                }
131            }
132        }
133    }
134}
135
136#[doc(hidden)]
137impl From<authorizer::AuthorizationError> for AuthorizationError {
138    fn from(value: authorizer::AuthorizationError) -> Self {
139        Self::PolicyEvaluationError(value.into())
140    }
141}
142
143/// Errors that occur during concretizing a partial request
144#[derive(Debug, Diagnostic, Error)]
145#[error(transparent)]
146#[diagnostic(transparent)]
147pub struct ConcretizationError(pub(crate) cedar_policy_core::authorizer::ConcretizationError);
148
149/// Errors that can be encountered when re-evaluating a partial response
150#[derive(Debug, Diagnostic, Error)]
151pub enum ReauthorizationError {
152    /// An evaluation error was encountered
153    #[error(transparent)]
154    #[diagnostic(transparent)]
155    Evaluation(#[from] EvaluationError),
156    /// A policy set error was encountered
157    #[error(transparent)]
158    #[diagnostic(transparent)]
159    PolicySet(#[from] PolicySetError),
160    /// A request concretization error was encountered
161    #[error(transparent)]
162    #[diagnostic(transparent)]
163    Concretization(#[from] ConcretizationError),
164}
165
166#[doc(hidden)]
167impl From<cedar_policy_core::authorizer::ReauthorizationError> for ReauthorizationError {
168    fn from(e: cedar_policy_core::authorizer::ReauthorizationError) -> Self {
169        match e {
170            cedar_policy_core::authorizer::ReauthorizationError::PolicySetError(err) => {
171                Self::PolicySet(err.into())
172            }
173            cedar_policy_core::authorizer::ReauthorizationError::ConcretizationError(err) => {
174                Self::Concretization(ConcretizationError(err))
175            }
176        }
177    }
178}
179
180/// Errors serializing Schemas to the Cedar syntax
181#[derive(Debug, Error, Diagnostic)]
182#[non_exhaustive]
183pub enum ToCedarSchemaError {
184    /// Duplicate names were found in the schema
185    #[error(transparent)]
186    #[diagnostic(transparent)]
187    NameCollisions(#[from] to_cedar_syntax_errors::NameCollisionsError),
188    /// Entity type definitions with shapes not supported in Cedar schema syntax were found in the schema
189    #[diagnostic(transparent)]
190    #[error(transparent)]
191    UnconvertibleEntityTypeShape(#[from] to_cedar_syntax_errors::UnconvertibleEntityTypeShapeError),
192}
193
194/// Error subtypes for [`ToCedarSchemaError`]
195pub mod to_cedar_syntax_errors {
196    use miette::Diagnostic;
197    use thiserror::Error;
198
199    /// Duplicate names were found in the schema
200    #[derive(Debug, Error, Diagnostic)]
201    #[error("{err}")]
202    #[diagnostic(forward(err))]
203    pub struct NameCollisionsError {
204        pub(super) err: cedar_policy_core::validator::cedar_schema::fmt::NameCollisionsError,
205        // because `.names()` needs to return borrowed `&str`, we need somewhere to borrow from, hence here
206        pub(super) names_as_strings: Vec<String>,
207    }
208
209    impl NameCollisionsError {
210        /// Get the names that had collisions
211        pub fn names(&self) -> impl Iterator<Item = &str> {
212            self.names_as_strings
213                .iter()
214                .map(std::string::String::as_str)
215        }
216    }
217
218    /// Entity type definitions with shapes not supported in Cedar schema syntax were found in the schema
219    #[derive(Debug, Error, Diagnostic)]
220    #[error("{err}")]
221    #[diagnostic(forward(err))]
222    pub struct UnconvertibleEntityTypeShapeError {
223        pub(super) err:
224            cedar_policy_core::validator::cedar_schema::fmt::UnconvertibleEntityTypeShapeError,
225        // because `.names()` needs to return borrowed `&str`, we need somewhere to borrow from, hence here
226        pub(super) names_as_strings: Vec<String>,
227    }
228
229    impl UnconvertibleEntityTypeShapeError {
230        /// Get the names of the type definitions with shapes not supported in Cedar schema syntax.
231        pub fn names(&self) -> impl Iterator<Item = &str> {
232            self.names_as_strings
233                .iter()
234                .map(std::string::String::as_str)
235        }
236    }
237}
238
239#[doc(hidden)]
240impl From<cedar_policy_core::validator::cedar_schema::fmt::ToCedarSchemaSyntaxError>
241    for ToCedarSchemaError
242{
243    fn from(
244        value: cedar_policy_core::validator::cedar_schema::fmt::ToCedarSchemaSyntaxError,
245    ) -> Self {
246        match value {
247            cedar_policy_core::validator::cedar_schema::fmt::ToCedarSchemaSyntaxError::NameCollisions(
248                name_collision_err,
249            ) => NameCollisionsError {
250                names_as_strings: name_collision_err
251                    .names()
252                    .map(ToString::to_string)
253                    .collect(),
254                err: name_collision_err,
255            }
256            .into(),
257            cedar_policy_core::validator::cedar_schema::fmt::ToCedarSchemaSyntaxError::UnconvertibleEntityTypeShape(err) => UnconvertibleEntityTypeShapeError {
258                names_as_strings: err
259                    .names()
260                    .map(ToString::to_string)
261                    .collect(),
262                err,
263            }.into(),
264        }
265    }
266}
267
268/// Error subtypes for [`CedarSchemaError`]
269pub mod cedar_schema_errors {
270    use miette::Diagnostic;
271    use thiserror::Error;
272
273    pub use cedar_policy_core::validator::CedarSchemaParseError as ParseError;
274
275    /// IO error while parsing a Cedar schema
276    #[derive(Debug, Error, Diagnostic)]
277    #[error(transparent)]
278    pub struct IoError(#[from] pub(super) std::io::Error);
279}
280
281/// Errors when parsing schemas
282#[derive(Debug, Diagnostic, Error)]
283#[non_exhaustive]
284pub enum CedarSchemaError {
285    /// Error parsing a schema in the Cedar syntax
286    #[error(transparent)]
287    #[diagnostic(transparent)]
288    Parse(#[from] cedar_schema_errors::ParseError),
289    /// IO error while parsing a Cedar schema
290    #[error(transparent)]
291    #[diagnostic(transparent)]
292    Io(#[from] cedar_schema_errors::IoError),
293    /// Encountered a `SchemaError` while parsing a Cedar schema
294    #[error(transparent)]
295    #[diagnostic(transparent)]
296    Schema(#[from] SchemaError),
297}
298
299#[doc(hidden)]
300impl From<cedar_policy_core::validator::CedarSchemaError> for CedarSchemaError {
301    fn from(value: cedar_policy_core::validator::CedarSchemaError) -> Self {
302        match value {
303            cedar_policy_core::validator::CedarSchemaError::Schema(e) => e.into(),
304            cedar_policy_core::validator::CedarSchemaError::IO(e) => {
305                cedar_schema_errors::IoError(e).into()
306            }
307            cedar_policy_core::validator::CedarSchemaError::Parsing(e) => e.into(),
308        }
309    }
310}
311
312/// Error when evaluating an entity attribute or tag
313#[derive(Debug, Diagnostic, Error)]
314#[error("in {} `{attr_or_tag}` of `{uid}`: {err}", if *.was_attr { "attribute" } else { "tag" })]
315#[diagnostic(forward(err))]
316pub struct EntityAttrEvaluationError {
317    /// Action that had the attribute or tag with the error
318    uid: EntityUid,
319    /// Attribute or tag that had the error
320    attr_or_tag: SmolStr,
321    /// Is `attr_or_tag` an attribute (`true`) or a tag (`false`)
322    was_attr: bool,
323    /// Underlying evaluation error
324    err: EvaluationError,
325}
326
327impl EntityAttrEvaluationError {
328    /// Get the [`EntityUid`] of the action that had the attribute with the error
329    pub fn action(&self) -> &EntityUid {
330        &self.uid
331    }
332
333    /// Get the name of the attribute or tag that had the error
334    //
335    // Method is named `.attr()` and not `.attr_or_tag()` for historical / backwards-compatibility reasons
336    pub fn attr(&self) -> &SmolStr {
337        &self.attr_or_tag
338    }
339
340    /// Get the underlying evaluation error
341    pub fn inner(&self) -> &EvaluationError {
342        &self.err
343    }
344}
345
346#[doc(hidden)]
347impl From<ast::EntityAttrEvaluationError> for EntityAttrEvaluationError {
348    fn from(err: ast::EntityAttrEvaluationError) -> Self {
349        Self {
350            uid: err.uid.into(),
351            attr_or_tag: err.attr_or_tag,
352            was_attr: err.was_attr,
353            err: err.err,
354        }
355    }
356}
357
358/// Errors while trying to create a `Context`
359#[derive(Debug, Diagnostic, Error)]
360pub enum ContextCreationError {
361    /// Tried to create a `Context` out of something other than a record
362    #[error(transparent)]
363    #[diagnostic(transparent)]
364    NotARecord(context_creation_errors::NotARecord),
365    /// Error evaluating the expression given for the `Context`
366    #[error(transparent)]
367    #[diagnostic(transparent)]
368    Evaluation(#[from] EvaluationError),
369    /// Error constructing the expression given for the `Context`.
370    /// Only returned by `Context::from_pairs()`
371    #[error(transparent)]
372    #[diagnostic(transparent)]
373    ExpressionConstruction(#[from] ExpressionConstructionError),
374}
375
376#[doc(hidden)]
377impl From<ast::ContextCreationError> for ContextCreationError {
378    fn from(e: ast::ContextCreationError) -> Self {
379        match e {
380            ast::ContextCreationError::NotARecord(nre) => Self::NotARecord(nre),
381            ast::ContextCreationError::Evaluation(e) => Self::Evaluation(e),
382            ast::ContextCreationError::ExpressionConstruction(ece) => {
383                Self::ExpressionConstruction(ece)
384            }
385        }
386    }
387}
388
389/// Error subtypes for [`ContextCreationError`]
390mod context_creation_errors {
391    pub use cedar_policy_core::ast::context_creation_errors::NotARecord;
392}
393
394/// Error subtypes for [`ValidationError`].
395///
396/// Errors are primarily documented on their variants in [`ValidationError`].
397pub mod validation_errors;
398
399/// An error generated by the validator when it finds a potential problem in a
400/// policy.
401#[derive(Debug, Clone, Error, Diagnostic)]
402#[non_exhaustive]
403pub enum ValidationError {
404    /// A policy contains an entity type that is not declared in the schema.
405    #[error(transparent)]
406    #[diagnostic(transparent)]
407    UnrecognizedEntityType(#[from] validation_errors::UnrecognizedEntityType),
408    /// A policy contains an action that is not declared in the schema.
409    #[error(transparent)]
410    #[diagnostic(transparent)]
411    UnrecognizedActionId(#[from] validation_errors::UnrecognizedActionId),
412    /// There is no action satisfying the action scope constraint that can be
413    /// applied to a principal and resources that both satisfy their respective
414    /// scope conditions.
415    ///
416    /// This error type is no longer ever returned; it is now reported as
417    /// [`ValidationWarning::InvalidActionApplication`] instead. It remains here
418    /// for backwards-compatibility.
419    #[error(transparent)]
420    #[diagnostic(transparent)]
421    InvalidActionApplication(#[from] validation_errors::InvalidActionApplication),
422    /// The typechecker expected to see a subtype of one of the types in
423    /// `expected`, but saw `actual`.
424    #[error(transparent)]
425    #[diagnostic(transparent)]
426    UnexpectedType(#[from] validation_errors::UnexpectedType),
427    /// The typechecker could not compute a least upper bound for `types`.
428    #[error(transparent)]
429    #[diagnostic(transparent)]
430    IncompatibleTypes(#[from] validation_errors::IncompatibleTypes),
431    /// The typechecker detected an access to a record or entity attribute
432    /// that it could not statically guarantee would be present.
433    #[error(transparent)]
434    #[diagnostic(transparent)]
435    UnsafeAttributeAccess(#[from] validation_errors::UnsafeAttributeAccess),
436    /// The typechecker could not conclude that an access to an optional
437    /// attribute was safe.
438    #[error(transparent)]
439    #[diagnostic(transparent)]
440    UnsafeOptionalAttributeAccess(#[from] validation_errors::UnsafeOptionalAttributeAccess),
441    /// The typechecker could not conclude that an access to a tag was safe.
442    #[error(transparent)]
443    #[diagnostic(transparent)]
444    UnsafeTagAccess(#[from] validation_errors::UnsafeTagAccess),
445    /// `.getTag()` on an entity type which cannot have tags according to the schema.
446    #[error(transparent)]
447    #[diagnostic(transparent)]
448    NoTagsAllowed(#[from] validation_errors::NoTagsAllowed),
449    /// Undefined extension function.
450    #[error(transparent)]
451    #[diagnostic(transparent)]
452    UndefinedFunction(#[from] validation_errors::UndefinedFunction),
453    /// Incorrect number of arguments in an extension function application.
454    #[error(transparent)]
455    #[diagnostic(transparent)]
456    WrongNumberArguments(#[from] validation_errors::WrongNumberArguments),
457    /// Error returned by custom extension function argument validation
458    #[diagnostic(transparent)]
459    #[error(transparent)]
460    FunctionArgumentValidation(#[from] validation_errors::FunctionArgumentValidation),
461    /// Error returned when an empty set literal is found in a policy.
462    #[diagnostic(transparent)]
463    #[error(transparent)]
464    EmptySetForbidden(#[from] validation_errors::EmptySetForbidden),
465    /// Error returned when an extension constructor is applied to an non-literal expression.
466    #[diagnostic(transparent)]
467    #[error(transparent)]
468    NonLitExtConstructor(#[from] validation_errors::NonLitExtConstructor),
469    /// This error type is no longer ever returned, but remains here for
470    /// backwards-compatibility (removing the variant entirely would be a
471    /// breaking change).
472    #[error(transparent)]
473    #[diagnostic(transparent)]
474    HierarchyNotRespected(#[from] validation_errors::HierarchyNotRespected),
475    /// Returned when an internal invariant is violated (should not happen; if
476    /// this is ever returned, please file an issue)
477    #[error(transparent)]
478    #[diagnostic(transparent)]
479    InternalInvariantViolation(#[from] validation_errors::InternalInvariantViolation),
480    /// Entity level violation
481    #[error(transparent)]
482    #[diagnostic(transparent)]
483    EntityDerefLevelViolation(#[from] validation_errors::EntityDerefLevelViolation),
484    /// Returned when an entity is of an enumerated entity type but has invalid EID
485    #[error(transparent)]
486    #[diagnostic(transparent)]
487    InvalidEnumEntity(#[from] validation_errors::InvalidEnumEntity),
488}
489
490impl ValidationError {
491    /// Extract the policy id of the policy where the validator found the issue.
492    pub fn policy_id(&self) -> &crate::PolicyId {
493        match self {
494            Self::UnrecognizedEntityType(e) => e.policy_id(),
495            Self::UnrecognizedActionId(e) => e.policy_id(),
496            Self::InvalidActionApplication(e) => e.policy_id(),
497            Self::UnexpectedType(e) => e.policy_id(),
498            Self::IncompatibleTypes(e) => e.policy_id(),
499            Self::UnsafeAttributeAccess(e) => e.policy_id(),
500            Self::UnsafeOptionalAttributeAccess(e) => e.policy_id(),
501            Self::UnsafeTagAccess(e) => e.policy_id(),
502            Self::NoTagsAllowed(e) => e.policy_id(),
503            Self::UndefinedFunction(e) => e.policy_id(),
504            Self::WrongNumberArguments(e) => e.policy_id(),
505            Self::FunctionArgumentValidation(e) => e.policy_id(),
506            Self::EmptySetForbidden(e) => e.policy_id(),
507            Self::NonLitExtConstructor(e) => e.policy_id(),
508            Self::HierarchyNotRespected(e) => e.policy_id(),
509            Self::InternalInvariantViolation(e) => e.policy_id(),
510            Self::EntityDerefLevelViolation(e) => e.policy_id(),
511            Self::InvalidEnumEntity(e) => e.policy_id(),
512        }
513    }
514}
515
516#[doc(hidden)]
517impl From<cedar_policy_core::validator::ValidationError> for ValidationError {
518    fn from(error: cedar_policy_core::validator::ValidationError) -> Self {
519        match error {
520            cedar_policy_core::validator::ValidationError::UnrecognizedEntityType(e) => {
521                Self::UnrecognizedEntityType(e.into())
522            }
523            cedar_policy_core::validator::ValidationError::UnrecognizedActionId(e) => {
524                Self::UnrecognizedActionId(e.into())
525            }
526            cedar_policy_core::validator::ValidationError::UnexpectedType(e) => {
527                Self::UnexpectedType(e.into())
528            }
529            cedar_policy_core::validator::ValidationError::IncompatibleTypes(e) => {
530                Self::IncompatibleTypes(e.into())
531            }
532            cedar_policy_core::validator::ValidationError::UnsafeAttributeAccess(e) => {
533                Self::UnsafeAttributeAccess(e.into())
534            }
535            cedar_policy_core::validator::ValidationError::UnsafeOptionalAttributeAccess(e) => {
536                Self::UnsafeOptionalAttributeAccess(e.into())
537            }
538            cedar_policy_core::validator::ValidationError::UnsafeTagAccess(e) => {
539                Self::UnsafeTagAccess(e.into())
540            }
541            cedar_policy_core::validator::ValidationError::NoTagsAllowed(e) => {
542                Self::NoTagsAllowed(e.into())
543            }
544            cedar_policy_core::validator::ValidationError::UndefinedFunction(e) => {
545                Self::UndefinedFunction(e.into())
546            }
547            cedar_policy_core::validator::ValidationError::WrongNumberArguments(e) => {
548                Self::WrongNumberArguments(e.into())
549            }
550            cedar_policy_core::validator::ValidationError::FunctionArgumentValidation(e) => {
551                Self::FunctionArgumentValidation(e.into())
552            }
553            cedar_policy_core::validator::ValidationError::EmptySetForbidden(e) => {
554                Self::EmptySetForbidden(e.into())
555            }
556            cedar_policy_core::validator::ValidationError::NonLitExtConstructor(e) => {
557                Self::NonLitExtConstructor(e.into())
558            }
559            cedar_policy_core::validator::ValidationError::InternalInvariantViolation(e) => {
560                Self::InternalInvariantViolation(e.into())
561            }
562            cedar_policy_core::validator::ValidationError::InvalidEnumEntity(e) => {
563                Self::InvalidEnumEntity(e.into())
564            }
565            cedar_policy_core::validator::ValidationError::EntityDerefLevelViolation(e) => {
566                Self::EntityDerefLevelViolation(e.into())
567            }
568        }
569    }
570}
571
572/// Error subtypes for [`ValidationWarning`].
573///
574/// Validation warnings are primarily documented on their variants in [`ValidationWarning`].
575pub mod validation_warnings;
576
577/// Represents the different kinds of validation warnings and information
578/// specific to that warning.
579///
580/// Marked as `non_exhaustive` to allow adding additional warnings in the future
581/// as a non-breaking change.
582#[derive(Debug, Clone, Error, Diagnostic)]
583#[non_exhaustive]
584pub enum ValidationWarning {
585    /// A string contains a mix of characters for different scripts (e.g., latin
586    /// and cyrillic alphabets). Different scripts can contain visually similar
587    /// characters which may be confused for each other.
588    #[diagnostic(transparent)]
589    #[error(transparent)]
590    MixedScriptString(#[from] validation_warnings::MixedScriptString),
591    /// A string contains bidirectional text control characters. These can be used to create crafted pieces of code that obfuscate true control flow.
592    #[diagnostic(transparent)]
593    #[error(transparent)]
594    BidiCharsInString(#[from] validation_warnings::BidiCharsInString),
595    /// An id contains bidirectional text control characters. These can be used to create crafted pieces of code that obfuscate true control flow.
596    #[diagnostic(transparent)]
597    #[error(transparent)]
598    BidiCharsInIdentifier(#[from] validation_warnings::BidiCharsInIdentifier),
599    /// An id contains a mix of characters for different scripts (e.g., latin and
600    /// cyrillic alphabets). Different scripts can contain visually similar
601    /// characters which may be confused for each other.
602    #[diagnostic(transparent)]
603    #[error(transparent)]
604    MixedScriptIdentifier(#[from] validation_warnings::MixedScriptIdentifier),
605    /// An id contains characters that is not a [graphical ASCII character](https://doc.rust-lang.org/std/primitive.char.html#method.is_ascii_graphic),
606    /// not the space character (`U+0020`), and falls outside of the General
607    /// Security Profile for Identifiers. We recommend adhering to this if
608    /// possible. See [Unicode® Technical Standard #39](https://unicode.org/reports/tr39/#General_Security_Profile) for more information.
609    #[diagnostic(transparent)]
610    #[error(transparent)]
611    ConfusableIdentifier(#[from] validation_warnings::ConfusableIdentifier),
612    /// The typechecker found that a policy condition will always evaluate to false.
613    #[diagnostic(transparent)]
614    #[error(transparent)]
615    ImpossiblePolicy(#[from] validation_warnings::ImpossiblePolicy),
616    /// There is no action satisfying the action scope constraint that can be
617    /// applied to a principal and resources that both satisfy their respective
618    /// scope conditions, so the policy can never apply to any request.
619    #[diagnostic(transparent)]
620    #[error(transparent)]
621    InvalidActionApplication(#[from] validation_warnings::InvalidActionApplication),
622}
623
624impl ValidationWarning {
625    /// Extract the policy id of the policy where the validator found the issue.
626    pub fn policy_id(&self) -> &PolicyId {
627        match self {
628            Self::MixedScriptString(w) => w.policy_id(),
629            Self::BidiCharsInString(w) => w.policy_id(),
630            Self::BidiCharsInIdentifier(w) => w.policy_id(),
631            Self::MixedScriptIdentifier(w) => w.policy_id(),
632            Self::ConfusableIdentifier(w) => w.policy_id(),
633            Self::ImpossiblePolicy(w) => w.policy_id(),
634            Self::InvalidActionApplication(w) => w.policy_id(),
635        }
636    }
637}
638
639#[doc(hidden)]
640impl From<cedar_policy_core::validator::ValidationWarning> for ValidationWarning {
641    fn from(warning: cedar_policy_core::validator::ValidationWarning) -> Self {
642        match warning {
643            cedar_policy_core::validator::ValidationWarning::MixedScriptString(w) => {
644                Self::MixedScriptString(w.into())
645            }
646            cedar_policy_core::validator::ValidationWarning::BidiCharsInString(w) => {
647                Self::BidiCharsInString(w.into())
648            }
649            cedar_policy_core::validator::ValidationWarning::BidiCharsInIdentifier(w) => {
650                Self::BidiCharsInIdentifier(w.into())
651            }
652            cedar_policy_core::validator::ValidationWarning::MixedScriptIdentifier(w) => {
653                Self::MixedScriptIdentifier(w.into())
654            }
655            cedar_policy_core::validator::ValidationWarning::ConfusableIdentifier(w) => {
656                Self::ConfusableIdentifier(w.into())
657            }
658            cedar_policy_core::validator::ValidationWarning::ImpossiblePolicy(w) => {
659                Self::ImpossiblePolicy(w.into())
660            }
661            cedar_policy_core::validator::ValidationWarning::InvalidActionApplication(w) => {
662                Self::InvalidActionApplication(w.into())
663            }
664        }
665    }
666}
667
668/// Error subtypes for [`PolicySetError`]
669pub mod policy_set_errors {
670    use super::Error;
671    use crate::PolicyId;
672    use cedar_policy_core::ast;
673    use miette::Diagnostic;
674
675    /// There was a duplicate [`PolicyId`] encountered in either the set of
676    /// templates or the set of policies.
677    #[derive(Debug, Diagnostic, Error)]
678    #[error("duplicate template or policy id `{id}`")]
679    pub struct AlreadyDefined {
680        pub(crate) id: PolicyId,
681    }
682
683    impl AlreadyDefined {
684        /// Get the [`PolicyId`] for which there was a duplicate
685        pub fn duplicate_id(&self) -> &PolicyId {
686            &self.id
687        }
688    }
689
690    /// Error when linking a template
691    #[derive(Debug, Diagnostic, Error)]
692    #[error("unable to link template")]
693    #[diagnostic(transparent)]
694    pub struct LinkingError {
695        #[from]
696        pub(crate) inner: ast::LinkingError,
697    }
698
699    /// Expected a static policy, but a template-linked policy was provided
700    #[derive(Debug, Diagnostic, Error)]
701    #[error("expected a static policy, but a template-linked policy was provided")]
702    pub struct ExpectedStatic {
703        /// A private field, just so the public interface notes this as a
704        /// private-fields struct and not a empty-fields struct for semver
705        /// purposes (e.g., consumers cannot construct this type with
706        /// `ExpectedStatic {}`)
707        _dummy: (),
708    }
709
710    impl ExpectedStatic {
711        pub(crate) fn new() -> Self {
712            Self { _dummy: () }
713        }
714    }
715
716    /// Expected a template, but a static policy was provided.
717    #[derive(Debug, Diagnostic, Error)]
718    #[error("expected a template, but a static policy was provided")]
719    pub struct ExpectedTemplate {
720        /// A private field, just so the public interface notes this as a
721        /// private-fields struct and not a empty-fields struct for semver
722        /// purposes (e.g., consumers cannot construct this type with
723        /// `ExpectedTemplate {}`)
724        _dummy: (),
725    }
726
727    impl ExpectedTemplate {
728        pub(crate) fn new() -> Self {
729            Self { _dummy: () }
730        }
731    }
732
733    /// Error when removing a static policy that doesn't exist
734    #[derive(Debug, Diagnostic, Error)]
735    #[error("unable to remove static policy `{policy_id}` because it does not exist")]
736    pub struct PolicyNonexistentError {
737        pub(crate) policy_id: PolicyId,
738    }
739
740    impl PolicyNonexistentError {
741        /// Get the [`PolicyId`] of the policy which didn't exist
742        pub fn policy_id(&self) -> &PolicyId {
743            &self.policy_id
744        }
745    }
746
747    /// Error when removing a template that doesn't exist
748    #[derive(Debug, Diagnostic, Error)]
749    #[error("unable to remove template `{template_id}` because it does not exist")]
750    pub struct TemplateNonexistentError {
751        pub(crate) template_id: PolicyId,
752    }
753
754    impl TemplateNonexistentError {
755        /// Get the [`PolicyId`] of the template which didn't exist
756        pub fn template_id(&self) -> &PolicyId {
757            &self.template_id
758        }
759    }
760
761    /// Error when removing a template with active links
762    #[derive(Debug, Diagnostic, Error)]
763    #[error("unable to remove policy template `{template_id}` because it has active links")]
764    pub struct RemoveTemplateWithActiveLinksError {
765        pub(crate) template_id: PolicyId,
766    }
767
768    impl RemoveTemplateWithActiveLinksError {
769        /// Get the [`PolicyId`] of the template which had active links
770        pub fn template_id(&self) -> &PolicyId {
771            &self.template_id
772        }
773    }
774
775    /// Error when removing a template that is not a template
776    #[derive(Debug, Diagnostic, Error)]
777    #[error("unable to remove policy template `{template_id}` because it is not a template")]
778    pub struct RemoveTemplateNotTemplateError {
779        pub(crate) template_id: PolicyId,
780    }
781
782    impl RemoveTemplateNotTemplateError {
783        /// Get the [`PolicyId`] of the template which is not a template
784        pub fn template_id(&self) -> &PolicyId {
785            &self.template_id
786        }
787    }
788
789    /// Error when unlinking a template-linked policy
790    #[derive(Debug, Diagnostic, Error)]
791    #[error("unable to unlink policy `{policy_id}` because it does not exist")]
792    pub struct LinkNonexistentError {
793        pub(crate) policy_id: PolicyId,
794    }
795
796    impl LinkNonexistentError {
797        /// Get the [`PolicyId`] of the link which does not exist
798        pub fn policy_id(&self) -> &PolicyId {
799            &self.policy_id
800        }
801    }
802
803    /// Error when removing a link that is not a link
804    #[derive(Debug, Diagnostic, Error)]
805    #[error("unable to unlink `{policy_id}` because it is not a link")]
806    pub struct UnlinkLinkNotLinkError {
807        pub(crate) policy_id: PolicyId,
808    }
809
810    impl UnlinkLinkNotLinkError {
811        /// Get the [`PolicyId`] of the link which is not a link
812        pub fn policy_id(&self) -> &PolicyId {
813            &self.policy_id
814        }
815    }
816
817    /// Error during JSON ser/de of the policy set (as opposed to individual policies)
818    #[derive(Debug, Diagnostic, Error)]
819    #[error("error serializing/deserializing policy set to/from JSON")]
820    pub struct JsonPolicySetError {
821        #[from]
822        pub(crate) inner: serde_json::Error,
823    }
824
825    /// Error when a PST `PolicySet` map key doesn't match the inner
826    /// template/policy id
827    #[derive(Debug, Diagnostic, Error)]
828    #[error(
829        "policy set map key `{map_key}` does not match the inner policy/template id `{inner_id}`"
830    )]
831    pub struct InconsistentPolicyId {
832        pub(crate) map_key: PolicyId,
833        pub(crate) inner_id: PolicyId,
834    }
835
836    impl InconsistentPolicyId {
837        /// Get the map key that was used in the PST `PolicySet`
838        pub fn map_key(&self) -> &PolicyId {
839            &self.map_key
840        }
841
842        /// Get the inner id from the template/policy
843        pub fn inner_id(&self) -> &PolicyId {
844            &self.inner_id
845        }
846    }
847}
848
849/// Potential errors when adding to a `PolicySet`.
850#[derive(Debug, Diagnostic, Error)]
851#[non_exhaustive]
852pub enum PolicySetError {
853    /// There was a duplicate [`PolicyId`] encountered in either the set of
854    /// templates or the set of policies.
855    #[error(transparent)]
856    #[diagnostic(transparent)]
857    AlreadyDefined(#[from] policy_set_errors::AlreadyDefined),
858    /// Error when linking a template
859    #[error(transparent)]
860    #[diagnostic(transparent)]
861    Linking(#[from] policy_set_errors::LinkingError),
862    /// Expected a static policy, but a template-linked policy was provided
863    #[error(transparent)]
864    #[diagnostic(transparent)]
865    ExpectedStatic(#[from] policy_set_errors::ExpectedStatic),
866    /// Expected a template, but a static policy was provided.
867    #[error(transparent)]
868    #[diagnostic(transparent)]
869    ExpectedTemplate(#[from] policy_set_errors::ExpectedTemplate),
870    /// Error when removing a static policy that doesn't exist
871    #[error(transparent)]
872    #[diagnostic(transparent)]
873    PolicyNonexistent(#[from] policy_set_errors::PolicyNonexistentError),
874    /// Error when removing a template that doesn't exist
875    #[error(transparent)]
876    #[diagnostic(transparent)]
877    TemplateNonexistent(#[from] policy_set_errors::TemplateNonexistentError),
878    /// Error when removing a template with active links
879    #[error(transparent)]
880    #[diagnostic(transparent)]
881    RemoveTemplateWithActiveLinks(#[from] policy_set_errors::RemoveTemplateWithActiveLinksError),
882    /// Error when removing a template that is not a template
883    #[error(transparent)]
884    #[diagnostic(transparent)]
885    RemoveTemplateNotTemplate(#[from] policy_set_errors::RemoveTemplateNotTemplateError),
886    /// Error when unlinking a linked policy
887    #[error(transparent)]
888    #[diagnostic(transparent)]
889    LinkNonexistent(#[from] policy_set_errors::LinkNonexistentError),
890    /// Error when removing a link that is not a link
891    #[error(transparent)]
892    #[diagnostic(transparent)]
893    UnlinkLinkNotLink(#[from] policy_set_errors::UnlinkLinkNotLinkError),
894    /// Error when converting a policy/template from JSON format
895    #[error(transparent)]
896    #[diagnostic(transparent)]
897    FromJson(#[from] PolicyFromJsonError),
898    /// Error when converting a policy/template to JSON format
899    #[error("Error serializing a policy/template to JSON")]
900    #[diagnostic(transparent)]
901    ToJson(#[from] PolicyToJsonError),
902    /// Error during JSON ser/de of the policy set (as opposed to individual policies)
903    #[error(transparent)]
904    #[diagnostic(transparent)]
905    JsonPolicySet(#[from] policy_set_errors::JsonPolicySetError),
906    /// Error when converting from PST representation
907    #[error(transparent)]
908    #[diagnostic(transparent)]
909    PstConversion(#[from] pst::PstConstructionError),
910    /// Error when a PST `PolicySet` map key doesn't match the inner
911    /// template/policy id
912    #[error(transparent)]
913    #[diagnostic(transparent)]
914    InconsistentPolicyId(#[from] policy_set_errors::InconsistentPolicyId),
915}
916
917#[doc(hidden)]
918impl From<ast::PolicySetError> for PolicySetError {
919    fn from(e: ast::PolicySetError) -> Self {
920        match e {
921            ast::PolicySetError::Occupied { id } => {
922                Self::AlreadyDefined(policy_set_errors::AlreadyDefined {
923                    id: PolicyId::new(id),
924                })
925            }
926        }
927    }
928}
929
930#[doc(hidden)]
931impl From<ast::LinkingError> for PolicySetError {
932    fn from(e: ast::LinkingError) -> Self {
933        Self::Linking(e.into())
934    }
935}
936
937#[doc(hidden)]
938impl From<ast::UnexpectedSlotError> for PolicySetError {
939    fn from(_: ast::UnexpectedSlotError) -> Self {
940        Self::ExpectedStatic(policy_set_errors::ExpectedStatic::new())
941    }
942}
943
944#[doc(hidden)]
945impl From<est::PolicySetFromJsonError> for PolicySetError {
946    fn from(e: est::PolicySetFromJsonError) -> Self {
947        match e {
948            est::PolicySetFromJsonError::PolicySet(e) => e.into(),
949            est::PolicySetFromJsonError::Linking(e) => e.into(),
950            est::PolicySetFromJsonError::FromJsonError(e) => Self::FromJson(e.into()),
951        }
952    }
953}
954
955/// Represents one or more [`ParseError`]s encountered when parsing a policy or
956/// expression.
957///
958/// By default, the `Diagnostic` and `Error` implementations will only print the
959/// first error. If you want to see all errors, use `.iter()` or `.into_iter()`.
960#[derive(Debug, Diagnostic, Error)]
961#[error(transparent)]
962#[diagnostic(transparent)]
963pub struct ParseErrors(#[from] cedar_policy_core::parser::err::ParseErrors);
964
965impl ParseErrors {
966    /// Get every [`ParseError`] associated with this [`ParseErrors`] object.
967    /// The returned iterator is guaranteed to be nonempty.
968    pub fn iter(&self) -> impl Iterator<Item = &ParseError> {
969        self.0.iter().map(ParseError::ref_cast)
970    }
971}
972
973/// Errors that can occur when parsing policies or expressions.
974///
975/// Marked as `non_exhaustive` to support adding additional error information
976/// in the future without a major version bump.
977#[derive(Debug, Diagnostic, Error, RefCast)]
978#[repr(transparent)]
979#[error(transparent)]
980#[diagnostic(transparent)]
981#[non_exhaustive]
982pub struct ParseError {
983    #[from]
984    inner: cedar_policy_core::parser::err::ParseError,
985}
986
987/// Errors that can happen when getting the JSON representation of a policy
988#[derive(Debug, Diagnostic, Error)]
989pub enum PolicyToJsonError {
990    /// Parse error in the policy text
991    #[error(transparent)]
992    #[diagnostic(transparent)]
993    Parse(#[from] ParseErrors),
994    /// For linked policies, error linking the JSON representation
995    #[error(transparent)]
996    #[diagnostic(transparent)]
997    Link(#[from] policy_to_json_errors::JsonLinkError),
998    /// Error in the JSON serialization
999    #[error(transparent)]
1000    JsonSerialization(#[from] policy_to_json_errors::PolicyJsonSerializationError),
1001}
1002
1003#[doc(hidden)]
1004impl From<est::LinkingError> for PolicyToJsonError {
1005    fn from(e: est::LinkingError) -> Self {
1006        policy_to_json_errors::JsonLinkError::from(e).into()
1007    }
1008}
1009
1010impl From<serde_json::Error> for PolicyToJsonError {
1011    fn from(e: serde_json::Error) -> Self {
1012        policy_to_json_errors::PolicyJsonSerializationError::from(e).into()
1013    }
1014}
1015
1016impl From<pst::PstConstructionError> for PolicyToJsonError {
1017    fn from(e: pst::PstConstructionError) -> Self {
1018        Self::JsonSerialization(serde_json::Error::custom(e.to_string()).into())
1019    }
1020}
1021
1022/// Error subtypes for [`PolicyToJsonError`]
1023pub mod policy_to_json_errors {
1024    use cedar_policy_core::est;
1025    use miette::Diagnostic;
1026    use thiserror::Error;
1027
1028    /// Error linking the JSON representation of a linked policy
1029    #[derive(Debug, Diagnostic, Error)]
1030    #[error(transparent)]
1031    #[diagnostic(transparent)]
1032    pub struct JsonLinkError {
1033        /// Underlying error
1034        #[from]
1035        err: est::LinkingError,
1036    }
1037
1038    /// Error serializing a policy as JSON
1039    #[derive(Debug, Diagnostic, Error)]
1040    #[error(transparent)]
1041    pub struct PolicyJsonSerializationError {
1042        /// Underlying error
1043        #[from]
1044        err: serde_json::Error,
1045    }
1046}
1047
1048/// Error when converting a policy or template from JSON format
1049#[derive(Debug, Diagnostic, Error)]
1050#[error("error deserializing a policy/template from JSON")]
1051#[diagnostic(transparent)]
1052pub struct PolicyFromJsonError {
1053    #[from]
1054    pub(crate) inner: cedar_policy_core::est::FromJsonError,
1055}
1056
1057/// Error type for parsing `Context` from JSON
1058#[derive(Debug, Diagnostic, Error)]
1059pub enum ContextJsonError {
1060    /// Error deserializing the JSON into a [`crate::Context`]
1061    #[error(transparent)]
1062    #[diagnostic(transparent)]
1063    JsonDeserialization(#[from] entities_json_errors::JsonDeserializationError),
1064    /// Error constructing the [`crate::Context`] itself
1065    #[error(transparent)]
1066    #[diagnostic(transparent)]
1067    ContextCreation(#[from] ContextCreationError),
1068    /// The supplied action doesn't exist in the supplied schema
1069    #[error(transparent)]
1070    #[diagnostic(transparent)]
1071    MissingAction(#[from] context_json_errors::MissingActionError),
1072}
1073
1074impl ContextJsonError {
1075    /// Construct a `ContextJsonError::MissingAction`
1076    pub(crate) fn missing_action(action: EntityUid) -> Self {
1077        Self::MissingAction(context_json_errors::MissingActionError { action })
1078    }
1079}
1080
1081#[doc(hidden)]
1082impl From<cedar_policy_core::entities::json::ContextJsonDeserializationError> for ContextJsonError {
1083    fn from(e: cedar_policy_core::entities::json::ContextJsonDeserializationError) -> Self {
1084        match e {
1085            cedar_policy_core::entities::json::ContextJsonDeserializationError::JsonDeserialization(e) => Self::JsonDeserialization(e),
1086            cedar_policy_core::entities::json::ContextJsonDeserializationError::ContextCreation(e) => Self::ContextCreation(e.into())
1087        }
1088    }
1089}
1090
1091/// Error subtypes for [`ContextJsonError`]
1092pub mod context_json_errors {
1093    use super::EntityUid;
1094    use miette::Diagnostic;
1095    use thiserror::Error;
1096
1097    /// The supplied action doesn't exist in the supplied schema
1098    #[derive(Debug, Diagnostic, Error)]
1099    #[error("action `{action}` does not exist in the supplied schema")]
1100    pub struct MissingActionError {
1101        /// UID of the action which doesn't exist
1102        pub(super) action: EntityUid,
1103    }
1104
1105    impl MissingActionError {
1106        /// Get the [`EntityUid`] of the action which doesn't exist
1107        pub fn action(&self) -> &EntityUid {
1108            &self.action
1109        }
1110    }
1111}
1112
1113/// Error type for parsing a `RestrictedExpression`
1114#[derive(Debug, Diagnostic, Error)]
1115#[non_exhaustive]
1116pub enum RestrictedExpressionParseError {
1117    /// Failed to parse the expression
1118    #[error(transparent)]
1119    #[diagnostic(transparent)]
1120    Parse(#[from] ParseErrors),
1121    /// Parsed successfully as an expression, but failed to construct a
1122    /// restricted expression, for the reason indicated in the underlying error
1123    #[error(transparent)]
1124    #[diagnostic(transparent)]
1125    InvalidRestrictedExpression(#[from] RestrictedExpressionError),
1126}
1127
1128#[doc(hidden)]
1129impl From<cedar_policy_core::ast::RestrictedExpressionParseError>
1130    for RestrictedExpressionParseError
1131{
1132    fn from(e: cedar_policy_core::ast::RestrictedExpressionParseError) -> Self {
1133        match e {
1134            cedar_policy_core::ast::RestrictedExpressionParseError::Parse(e) => {
1135                Self::Parse(e.into())
1136            }
1137            cedar_policy_core::ast::RestrictedExpressionParseError::InvalidRestrictedExpression(
1138                e,
1139            ) => e.into(),
1140        }
1141    }
1142}
1143
1144/// The request does not conform to the schema
1145#[derive(Debug, Diagnostic, Error)]
1146#[non_exhaustive]
1147pub enum RequestValidationError {
1148    /// Request action is not declared in the schema
1149    #[error(transparent)]
1150    #[diagnostic(transparent)]
1151    UndeclaredAction(#[from] request_validation_errors::UndeclaredActionError),
1152    /// Request principal is of a type not declared in the schema
1153    #[error(transparent)]
1154    #[diagnostic(transparent)]
1155    UndeclaredPrincipalType(#[from] request_validation_errors::UndeclaredPrincipalTypeError),
1156    /// Request resource is of a type not declared in the schema
1157    #[error(transparent)]
1158    #[diagnostic(transparent)]
1159    UndeclaredResourceType(#[from] request_validation_errors::UndeclaredResourceTypeError),
1160    /// Request principal is of a type that is declared in the schema, but is
1161    /// not valid for the request action
1162    #[error(transparent)]
1163    #[diagnostic(transparent)]
1164    InvalidPrincipalType(#[from] request_validation_errors::InvalidPrincipalTypeError),
1165    /// Request resource is of a type that is declared in the schema, but is
1166    /// not valid for the request action
1167    #[error(transparent)]
1168    #[diagnostic(transparent)]
1169    InvalidResourceType(#[from] request_validation_errors::InvalidResourceTypeError),
1170    /// Context does not comply with the shape specified for the request action
1171    #[error(transparent)]
1172    #[diagnostic(transparent)]
1173    InvalidContext(#[from] request_validation_errors::InvalidContextError),
1174    /// Error computing the type of the `Context`
1175    #[error(transparent)]
1176    #[diagnostic(transparent)]
1177    TypeOfContext(#[from] request_validation_errors::TypeOfContextError),
1178    /// Error when a principal or resource entity is of an enumerated entity
1179    /// type but has an invalid EID
1180    #[error(transparent)]
1181    #[diagnostic(transparent)]
1182    InvalidEnumEntity(#[from] request_validation_errors::InvalidEnumEntityError),
1183}
1184
1185#[doc(hidden)]
1186impl From<cedar_policy_core::validator::RequestValidationError> for RequestValidationError {
1187    fn from(e: cedar_policy_core::validator::RequestValidationError) -> Self {
1188        match e {
1189            cedar_policy_core::validator::RequestValidationError::UndeclaredAction(e) => {
1190                Self::UndeclaredAction(e.into())
1191            }
1192            cedar_policy_core::validator::RequestValidationError::UndeclaredPrincipalType(e) => {
1193                Self::UndeclaredPrincipalType(e.into())
1194            }
1195            cedar_policy_core::validator::RequestValidationError::UndeclaredResourceType(e) => {
1196                Self::UndeclaredResourceType(e.into())
1197            }
1198            cedar_policy_core::validator::RequestValidationError::InvalidPrincipalType(e) => {
1199                Self::InvalidPrincipalType(e.into())
1200            }
1201            cedar_policy_core::validator::RequestValidationError::InvalidResourceType(e) => {
1202                Self::InvalidResourceType(e.into())
1203            }
1204            cedar_policy_core::validator::RequestValidationError::InvalidContext(e) => {
1205                Self::InvalidContext(e.into())
1206            }
1207            cedar_policy_core::validator::RequestValidationError::TypeOfContext(e) => {
1208                Self::TypeOfContext(e.into())
1209            }
1210            cedar_policy_core::validator::RequestValidationError::InvalidEnumEntity(e) => {
1211                Self::InvalidEnumEntity(e.into())
1212            }
1213        }
1214    }
1215}
1216
1217/// Error subtypes for [`RequestValidationError`]
1218pub mod request_validation_errors {
1219    use cedar_policy_core::extensions::ExtensionFunctionLookupError;
1220    use miette::Diagnostic;
1221    use ref_cast::RefCast;
1222    use thiserror::Error;
1223
1224    use crate::{Context, EntityTypeName, EntityUid};
1225
1226    /// Request action is not declared in the schema
1227    #[derive(Debug, Diagnostic, Error)]
1228    #[error(transparent)]
1229    #[diagnostic(transparent)]
1230    pub struct UndeclaredActionError(
1231        #[from] cedar_policy_core::validator::request_validation_errors::UndeclaredActionError,
1232    );
1233
1234    impl UndeclaredActionError {
1235        /// The action which was not declared in the schema
1236        pub fn action(&self) -> &EntityUid {
1237            RefCast::ref_cast(self.0.action())
1238        }
1239    }
1240
1241    /// Request principal is of a type not declared in the schema
1242    #[derive(Debug, Diagnostic, Error)]
1243    #[error(transparent)]
1244    #[diagnostic(transparent)]
1245    pub struct UndeclaredPrincipalTypeError(
1246        #[from]
1247        cedar_policy_core::validator::request_validation_errors::UndeclaredPrincipalTypeError,
1248    );
1249
1250    impl UndeclaredPrincipalTypeError {
1251        /// The principal type which was not declared in the schema
1252        pub fn principal_ty(&self) -> &EntityTypeName {
1253            RefCast::ref_cast(self.0.principal_ty())
1254        }
1255    }
1256
1257    /// Request resource is of a type not declared in the schema
1258    #[derive(Debug, Diagnostic, Error)]
1259    #[error(transparent)]
1260    #[diagnostic(transparent)]
1261    pub struct UndeclaredResourceTypeError(
1262        #[from]
1263        cedar_policy_core::validator::request_validation_errors::UndeclaredResourceTypeError,
1264    );
1265
1266    impl UndeclaredResourceTypeError {
1267        /// The resource type which was not declared in the schema
1268        pub fn resource_ty(&self) -> &EntityTypeName {
1269            RefCast::ref_cast(self.0.resource_ty())
1270        }
1271    }
1272
1273    /// Request principal is of a type that is declared in the schema, but is
1274    /// not valid for the request action
1275    #[derive(Debug, Diagnostic, Error)]
1276    #[error(transparent)]
1277    #[diagnostic(transparent)]
1278    pub struct InvalidPrincipalTypeError(
1279        #[from] cedar_policy_core::validator::request_validation_errors::InvalidPrincipalTypeError,
1280    );
1281
1282    impl InvalidPrincipalTypeError {
1283        /// The principal type which is not valid
1284        pub fn principal_ty(&self) -> &EntityTypeName {
1285            RefCast::ref_cast(self.0.principal_ty())
1286        }
1287
1288        /// The action which it is not valid for
1289        pub fn action(&self) -> &EntityUid {
1290            RefCast::ref_cast(self.0.action())
1291        }
1292    }
1293
1294    /// Request resource is of a type that is declared in the schema, but is
1295    /// not valid for the request action
1296    #[derive(Debug, Diagnostic, Error)]
1297    #[error(transparent)]
1298    #[diagnostic(transparent)]
1299    pub struct InvalidResourceTypeError(
1300        #[from] cedar_policy_core::validator::request_validation_errors::InvalidResourceTypeError,
1301    );
1302
1303    impl InvalidResourceTypeError {
1304        /// The resource type which is not valid
1305        pub fn resource_ty(&self) -> &EntityTypeName {
1306            RefCast::ref_cast(self.0.resource_ty())
1307        }
1308
1309        /// The action which it is not valid for
1310        pub fn action(&self) -> &EntityUid {
1311            RefCast::ref_cast(self.0.action())
1312        }
1313    }
1314
1315    /// Context does not comply with the shape specified for the request action
1316    #[derive(Debug, Diagnostic, Error)]
1317    #[error(transparent)]
1318    #[diagnostic(transparent)]
1319    pub struct InvalidContextError(
1320        #[from] cedar_policy_core::validator::request_validation_errors::InvalidContextError,
1321    );
1322
1323    impl InvalidContextError {
1324        /// The context which is not valid
1325        pub fn context(&self) -> &Context {
1326            RefCast::ref_cast(self.0.context())
1327        }
1328
1329        /// The action which it is not valid for
1330        pub fn action(&self) -> &EntityUid {
1331            RefCast::ref_cast(self.0.action())
1332        }
1333    }
1334
1335    /// Error computing the type of the `Context`
1336    #[derive(Debug, Diagnostic, Error)]
1337    #[error(transparent)]
1338    #[diagnostic(transparent)]
1339    pub struct TypeOfContextError(#[from] ExtensionFunctionLookupError);
1340
1341    /// Error when a principal or resource entity is of an enumerated entity
1342    /// type but has an invalid EID
1343    #[derive(Debug, Diagnostic, Error)]
1344    #[error(transparent)]
1345    #[diagnostic(transparent)]
1346    pub struct InvalidEnumEntityError(
1347        #[from] cedar_policy_core::entities::conformance::err::InvalidEnumEntityError,
1348    );
1349}
1350
1351/// An error generated by entity slicing.
1352#[derive(Debug, Error, Diagnostic)]
1353#[non_exhaustive]
1354#[cfg(feature = "entity-manifest")]
1355pub enum EntityManifestError {
1356    /// A validation error was encountered
1357    #[error(transparent)]
1358    #[diagnostic(transparent)]
1359    Validation(#[from] ValidationResult),
1360    /// A entities error was encountered
1361    #[error(transparent)]
1362    #[diagnostic(transparent)]
1363    Entities(#[from] EntitiesError),
1364
1365    /// The request was partial
1366    #[error(transparent)]
1367    #[diagnostic(transparent)]
1368    PartialRequest(#[from] PartialRequestError),
1369    /// A policy was partial
1370    #[error(transparent)]
1371    #[diagnostic(transparent)]
1372    PartialExpression(#[from] PartialExpressionError),
1373    /// Encounters unsupported Cedar feature
1374    #[error(transparent)]
1375    #[diagnostic(transparent)]
1376    UnsupportedCedarFeature(#[from] UnsupportedCedarFeatureError),
1377}
1378
1379#[cfg(feature = "entity-manifest")]
1380impl From<entity_manifest::EntityManifestError> for EntityManifestError {
1381    fn from(e: entity_manifest::EntityManifestError) -> Self {
1382        match e {
1383            entity_manifest::EntityManifestError::Validation(e) => Self::Validation(e.into()),
1384            entity_manifest::EntityManifestError::Entities(e) => Self::Entities(e),
1385            entity_manifest::EntityManifestError::PartialRequest(e) => Self::PartialRequest(e),
1386            entity_manifest::EntityManifestError::PartialExpression(e) => {
1387                Self::PartialExpression(e)
1388            }
1389            entity_manifest::EntityManifestError::UnsupportedCedarFeature(e) => {
1390                Self::UnsupportedCedarFeature(e)
1391            }
1392        }
1393    }
1394}
1395
1396#[cfg(feature = "tpe")]
1397/// Error thrown when creating a `PartialRequest`
1398#[doc = include_str!("../../experimental_warning.md")]
1399#[derive(Debug, Error, Diagnostic)]
1400pub enum PartialRequestCreationError {
1401    /// When the context contains unknowns
1402    #[error("Context contains unknowns")]
1403    ContextContainsUnknowns,
1404    /// When the request does not pass validation
1405    #[error(transparent)]
1406    #[diagnostic(transparent)]
1407    Validation(#[from] RequestValidationError),
1408}
1409
1410#[cfg(feature = "tpe")]
1411/// Errors that can be encountered when re-evaluating a partial response
1412#[doc = include_str!("../../experimental_warning.md")]
1413#[derive(Debug, Error)]
1414pub enum TpeReauthorizationError {
1415    /// `Request` cannot be validated
1416    #[error(transparent)]
1417    RequestValidation(#[from] RequestValidationError),
1418    /// `Entities` cannot be validated
1419    #[error(transparent)]
1420    EntityValidation(#[from] EntitySchemaConformanceError),
1421    /// Inconsistent entities
1422    #[error(transparent)]
1423    InconsistentEntities(#[from] tpe_err::EntitiesConsistencyError),
1424    /// Inconsistent requests
1425    #[error(transparent)]
1426    InconsistentRequests(#[from] tpe_err::RequestConsistencyError),
1427}
1428
1429#[cfg(feature = "tpe")]
1430impl From<tpe_err::ReauthorizationError> for TpeReauthorizationError {
1431    fn from(value: tpe_err::ReauthorizationError) -> Self {
1432        match value {
1433            tpe_err::ReauthorizationError::EntitiesConsistency(e) => Self::InconsistentEntities(e),
1434            tpe_err::ReauthorizationError::EntityValidation(e) => Self::EntityValidation(e),
1435            tpe_err::ReauthorizationError::RequestConsistency(e) => Self::InconsistentRequests(e),
1436            tpe_err::ReauthorizationError::RequestValidation(e) => {
1437                Self::RequestValidation(e.into())
1438            }
1439        }
1440    }
1441}
1442
1443#[cfg(feature = "tpe")]
1444/// Errors that can be encountered when performing a permission query
1445#[doc = include_str!("../../experimental_warning.md")]
1446#[derive(Debug, Error)]
1447pub enum PermissionQueryError {
1448    /// When concrete entities fail to validate or contain unknowns
1449    #[error(transparent)]
1450    Entities(#[from] tpe_err::EntitiesError),
1451    /// When TPE fails
1452    #[error(transparent)]
1453    TPE(#[from] tpe_err::TpeError),
1454}
1455
1456#[cfg(feature = "tpe")]
1457#[doc = include_str!("../../experimental_warning.md")]
1458/// Error when constructing [`crate::PartialEntity`]
1459#[derive(Debug, Error)]
1460pub enum PartialEntityError {
1461    /// An evaluation error was encountered
1462    #[error(transparent)]
1463    Evaluation(#[from] EvaluationError),
1464    /// Fail to construct a [`crate::PartialEntity`]
1465    #[error(transparent)]
1466    Entities(#[from] tpe_err::EntitiesError),
1467}