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    #[error(transparent)]
416    #[diagnostic(transparent)]
417    InvalidActionApplication(#[from] validation_errors::InvalidActionApplication),
418    /// The typechecker expected to see a subtype of one of the types in
419    /// `expected`, but saw `actual`.
420    #[error(transparent)]
421    #[diagnostic(transparent)]
422    UnexpectedType(#[from] validation_errors::UnexpectedType),
423    /// The typechecker could not compute a least upper bound for `types`.
424    #[error(transparent)]
425    #[diagnostic(transparent)]
426    IncompatibleTypes(#[from] validation_errors::IncompatibleTypes),
427    /// The typechecker detected an access to a record or entity attribute
428    /// that it could not statically guarantee would be present.
429    #[error(transparent)]
430    #[diagnostic(transparent)]
431    UnsafeAttributeAccess(#[from] validation_errors::UnsafeAttributeAccess),
432    /// The typechecker could not conclude that an access to an optional
433    /// attribute was safe.
434    #[error(transparent)]
435    #[diagnostic(transparent)]
436    UnsafeOptionalAttributeAccess(#[from] validation_errors::UnsafeOptionalAttributeAccess),
437    /// The typechecker could not conclude that an access to a tag was safe.
438    #[error(transparent)]
439    #[diagnostic(transparent)]
440    UnsafeTagAccess(#[from] validation_errors::UnsafeTagAccess),
441    /// `.getTag()` on an entity type which cannot have tags according to the schema.
442    #[error(transparent)]
443    #[diagnostic(transparent)]
444    NoTagsAllowed(#[from] validation_errors::NoTagsAllowed),
445    /// Undefined extension function.
446    #[error(transparent)]
447    #[diagnostic(transparent)]
448    UndefinedFunction(#[from] validation_errors::UndefinedFunction),
449    /// Incorrect number of arguments in an extension function application.
450    #[error(transparent)]
451    #[diagnostic(transparent)]
452    WrongNumberArguments(#[from] validation_errors::WrongNumberArguments),
453    /// Error returned by custom extension function argument validation
454    #[diagnostic(transparent)]
455    #[error(transparent)]
456    FunctionArgumentValidation(#[from] validation_errors::FunctionArgumentValidation),
457    /// Error returned when an empty set literal is found in a policy.
458    #[diagnostic(transparent)]
459    #[error(transparent)]
460    EmptySetForbidden(#[from] validation_errors::EmptySetForbidden),
461    /// Error returned when an extension constructor is applied to an non-literal expression.
462    #[diagnostic(transparent)]
463    #[error(transparent)]
464    NonLitExtConstructor(#[from] validation_errors::NonLitExtConstructor),
465    /// This error type is no longer ever returned, but remains here for
466    /// backwards-compatibility (removing the variant entirely would be a
467    /// breaking change).
468    #[error(transparent)]
469    #[diagnostic(transparent)]
470    HierarchyNotRespected(#[from] validation_errors::HierarchyNotRespected),
471    /// Returned when an internal invariant is violated (should not happen; if
472    /// this is ever returned, please file an issue)
473    #[error(transparent)]
474    #[diagnostic(transparent)]
475    InternalInvariantViolation(#[from] validation_errors::InternalInvariantViolation),
476    /// Entity level violation
477    #[error(transparent)]
478    #[diagnostic(transparent)]
479    EntityDerefLevelViolation(#[from] validation_errors::EntityDerefLevelViolation),
480    /// Returned when an entity is of an enumerated entity type but has invalid EID
481    #[error(transparent)]
482    #[diagnostic(transparent)]
483    InvalidEnumEntity(#[from] validation_errors::InvalidEnumEntity),
484}
485
486impl ValidationError {
487    /// Extract the policy id of the policy where the validator found the issue.
488    pub fn policy_id(&self) -> &crate::PolicyId {
489        match self {
490            Self::UnrecognizedEntityType(e) => e.policy_id(),
491            Self::UnrecognizedActionId(e) => e.policy_id(),
492            Self::InvalidActionApplication(e) => e.policy_id(),
493            Self::UnexpectedType(e) => e.policy_id(),
494            Self::IncompatibleTypes(e) => e.policy_id(),
495            Self::UnsafeAttributeAccess(e) => e.policy_id(),
496            Self::UnsafeOptionalAttributeAccess(e) => e.policy_id(),
497            Self::UnsafeTagAccess(e) => e.policy_id(),
498            Self::NoTagsAllowed(e) => e.policy_id(),
499            Self::UndefinedFunction(e) => e.policy_id(),
500            Self::WrongNumberArguments(e) => e.policy_id(),
501            Self::FunctionArgumentValidation(e) => e.policy_id(),
502            Self::EmptySetForbidden(e) => e.policy_id(),
503            Self::NonLitExtConstructor(e) => e.policy_id(),
504            Self::HierarchyNotRespected(e) => e.policy_id(),
505            Self::InternalInvariantViolation(e) => e.policy_id(),
506            Self::EntityDerefLevelViolation(e) => e.policy_id(),
507            Self::InvalidEnumEntity(e) => e.policy_id(),
508        }
509    }
510}
511
512#[doc(hidden)]
513impl From<cedar_policy_core::validator::ValidationError> for ValidationError {
514    fn from(error: cedar_policy_core::validator::ValidationError) -> Self {
515        match error {
516            cedar_policy_core::validator::ValidationError::UnrecognizedEntityType(e) => {
517                Self::UnrecognizedEntityType(e.into())
518            }
519            cedar_policy_core::validator::ValidationError::UnrecognizedActionId(e) => {
520                Self::UnrecognizedActionId(e.into())
521            }
522            cedar_policy_core::validator::ValidationError::InvalidActionApplication(e) => {
523                Self::InvalidActionApplication(e.into())
524            }
525            cedar_policy_core::validator::ValidationError::UnexpectedType(e) => {
526                Self::UnexpectedType(e.into())
527            }
528            cedar_policy_core::validator::ValidationError::IncompatibleTypes(e) => {
529                Self::IncompatibleTypes(e.into())
530            }
531            cedar_policy_core::validator::ValidationError::UnsafeAttributeAccess(e) => {
532                Self::UnsafeAttributeAccess(e.into())
533            }
534            cedar_policy_core::validator::ValidationError::UnsafeOptionalAttributeAccess(e) => {
535                Self::UnsafeOptionalAttributeAccess(e.into())
536            }
537            cedar_policy_core::validator::ValidationError::UnsafeTagAccess(e) => {
538                Self::UnsafeTagAccess(e.into())
539            }
540            cedar_policy_core::validator::ValidationError::NoTagsAllowed(e) => {
541                Self::NoTagsAllowed(e.into())
542            }
543            cedar_policy_core::validator::ValidationError::UndefinedFunction(e) => {
544                Self::UndefinedFunction(e.into())
545            }
546            cedar_policy_core::validator::ValidationError::WrongNumberArguments(e) => {
547                Self::WrongNumberArguments(e.into())
548            }
549            cedar_policy_core::validator::ValidationError::FunctionArgumentValidation(e) => {
550                Self::FunctionArgumentValidation(e.into())
551            }
552            cedar_policy_core::validator::ValidationError::EmptySetForbidden(e) => {
553                Self::EmptySetForbidden(e.into())
554            }
555            cedar_policy_core::validator::ValidationError::NonLitExtConstructor(e) => {
556                Self::NonLitExtConstructor(e.into())
557            }
558            cedar_policy_core::validator::ValidationError::InternalInvariantViolation(e) => {
559                Self::InternalInvariantViolation(e.into())
560            }
561            cedar_policy_core::validator::ValidationError::InvalidEnumEntity(e) => {
562                Self::InvalidEnumEntity(e.into())
563            }
564            cedar_policy_core::validator::ValidationError::EntityDerefLevelViolation(e) => {
565                Self::EntityDerefLevelViolation(e.into())
566            }
567        }
568    }
569}
570
571/// Error subtypes for [`ValidationWarning`].
572///
573/// Validation warnings are primarily documented on their variants in [`ValidationWarning`].
574pub mod validation_warnings;
575
576/// Represents the different kinds of validation warnings and information
577/// specific to that warning.
578///
579/// Marked as `non_exhaustive` to allow adding additional warnings in the future
580/// as a non-breaking change.
581#[derive(Debug, Clone, Error, Diagnostic)]
582#[non_exhaustive]
583pub enum ValidationWarning {
584    /// A string contains a mix of characters for different scripts (e.g., latin
585    /// and cyrillic alphabets). Different scripts can contain visually similar
586    /// characters which may be confused for each other.
587    #[diagnostic(transparent)]
588    #[error(transparent)]
589    MixedScriptString(#[from] validation_warnings::MixedScriptString),
590    /// A string contains bidirectional text control characters. These can be used to create crafted pieces of code that obfuscate true control flow.
591    #[diagnostic(transparent)]
592    #[error(transparent)]
593    BidiCharsInString(#[from] validation_warnings::BidiCharsInString),
594    /// An id contains bidirectional text control characters. These can be used to create crafted pieces of code that obfuscate true control flow.
595    #[diagnostic(transparent)]
596    #[error(transparent)]
597    BidiCharsInIdentifier(#[from] validation_warnings::BidiCharsInIdentifier),
598    /// An id contains a mix of characters for different scripts (e.g., latin and
599    /// cyrillic alphabets). Different scripts can contain visually similar
600    /// characters which may be confused for each other.
601    #[diagnostic(transparent)]
602    #[error(transparent)]
603    MixedScriptIdentifier(#[from] validation_warnings::MixedScriptIdentifier),
604    /// An id contains characters that is not a [graphical ASCII character](https://doc.rust-lang.org/std/primitive.char.html#method.is_ascii_graphic),
605    /// not the space character (`U+0020`), and falls outside of the General
606    /// Security Profile for Identifiers. We recommend adhering to this if
607    /// possible. See [Unicode® Technical Standard #39](https://unicode.org/reports/tr39/#General_Security_Profile) for more information.
608    #[diagnostic(transparent)]
609    #[error(transparent)]
610    ConfusableIdentifier(#[from] validation_warnings::ConfusableIdentifier),
611    /// The typechecker found that a policy condition will always evaluate to false.
612    #[diagnostic(transparent)]
613    #[error(transparent)]
614    ImpossiblePolicy(#[from] validation_warnings::ImpossiblePolicy),
615}
616
617impl ValidationWarning {
618    /// Extract the policy id of the policy where the validator found the issue.
619    pub fn policy_id(&self) -> &PolicyId {
620        match self {
621            Self::MixedScriptString(w) => w.policy_id(),
622            Self::BidiCharsInString(w) => w.policy_id(),
623            Self::BidiCharsInIdentifier(w) => w.policy_id(),
624            Self::MixedScriptIdentifier(w) => w.policy_id(),
625            Self::ConfusableIdentifier(w) => w.policy_id(),
626            Self::ImpossiblePolicy(w) => w.policy_id(),
627        }
628    }
629}
630
631#[doc(hidden)]
632impl From<cedar_policy_core::validator::ValidationWarning> for ValidationWarning {
633    fn from(warning: cedar_policy_core::validator::ValidationWarning) -> Self {
634        match warning {
635            cedar_policy_core::validator::ValidationWarning::MixedScriptString(w) => {
636                Self::MixedScriptString(w.into())
637            }
638            cedar_policy_core::validator::ValidationWarning::BidiCharsInString(w) => {
639                Self::BidiCharsInString(w.into())
640            }
641            cedar_policy_core::validator::ValidationWarning::BidiCharsInIdentifier(w) => {
642                Self::BidiCharsInIdentifier(w.into())
643            }
644            cedar_policy_core::validator::ValidationWarning::MixedScriptIdentifier(w) => {
645                Self::MixedScriptIdentifier(w.into())
646            }
647            cedar_policy_core::validator::ValidationWarning::ConfusableIdentifier(w) => {
648                Self::ConfusableIdentifier(w.into())
649            }
650            cedar_policy_core::validator::ValidationWarning::ImpossiblePolicy(w) => {
651                Self::ImpossiblePolicy(w.into())
652            }
653        }
654    }
655}
656
657/// Error subtypes for [`PolicySetError`]
658pub mod policy_set_errors {
659    use super::Error;
660    use crate::PolicyId;
661    use cedar_policy_core::ast;
662    use miette::Diagnostic;
663
664    /// There was a duplicate [`PolicyId`] encountered in either the set of
665    /// templates or the set of policies.
666    #[derive(Debug, Diagnostic, Error)]
667    #[error("duplicate template or policy id `{id}`")]
668    pub struct AlreadyDefined {
669        pub(crate) id: PolicyId,
670    }
671
672    impl AlreadyDefined {
673        /// Get the [`PolicyId`] for which there was a duplicate
674        pub fn duplicate_id(&self) -> &PolicyId {
675            &self.id
676        }
677    }
678
679    /// Error when linking a template
680    #[derive(Debug, Diagnostic, Error)]
681    #[error("unable to link template")]
682    #[diagnostic(transparent)]
683    pub struct LinkingError {
684        #[from]
685        pub(crate) inner: ast::LinkingError,
686    }
687
688    /// Expected a static policy, but a template-linked policy was provided
689    #[derive(Debug, Diagnostic, Error)]
690    #[error("expected a static policy, but a template-linked policy was provided")]
691    pub struct ExpectedStatic {
692        /// A private field, just so the public interface notes this as a
693        /// private-fields struct and not a empty-fields struct for semver
694        /// purposes (e.g., consumers cannot construct this type with
695        /// `ExpectedStatic {}`)
696        _dummy: (),
697    }
698
699    impl ExpectedStatic {
700        pub(crate) fn new() -> Self {
701            Self { _dummy: () }
702        }
703    }
704
705    /// Expected a template, but a static policy was provided.
706    #[derive(Debug, Diagnostic, Error)]
707    #[error("expected a template, but a static policy was provided")]
708    pub struct ExpectedTemplate {
709        /// A private field, just so the public interface notes this as a
710        /// private-fields struct and not a empty-fields struct for semver
711        /// purposes (e.g., consumers cannot construct this type with
712        /// `ExpectedTemplate {}`)
713        _dummy: (),
714    }
715
716    impl ExpectedTemplate {
717        pub(crate) fn new() -> Self {
718            Self { _dummy: () }
719        }
720    }
721
722    /// Error when removing a static policy that doesn't exist
723    #[derive(Debug, Diagnostic, Error)]
724    #[error("unable to remove static policy `{policy_id}` because it does not exist")]
725    pub struct PolicyNonexistentError {
726        pub(crate) policy_id: PolicyId,
727    }
728
729    impl PolicyNonexistentError {
730        /// Get the [`PolicyId`] of the policy which didn't exist
731        pub fn policy_id(&self) -> &PolicyId {
732            &self.policy_id
733        }
734    }
735
736    /// Error when removing a template that doesn't exist
737    #[derive(Debug, Diagnostic, Error)]
738    #[error("unable to remove template `{template_id}` because it does not exist")]
739    pub struct TemplateNonexistentError {
740        pub(crate) template_id: PolicyId,
741    }
742
743    impl TemplateNonexistentError {
744        /// Get the [`PolicyId`] of the template which didn't exist
745        pub fn template_id(&self) -> &PolicyId {
746            &self.template_id
747        }
748    }
749
750    /// Error when removing a template with active links
751    #[derive(Debug, Diagnostic, Error)]
752    #[error("unable to remove policy template `{template_id}` because it has active links")]
753    pub struct RemoveTemplateWithActiveLinksError {
754        pub(crate) template_id: PolicyId,
755    }
756
757    impl RemoveTemplateWithActiveLinksError {
758        /// Get the [`PolicyId`] of the template which had active links
759        pub fn template_id(&self) -> &PolicyId {
760            &self.template_id
761        }
762    }
763
764    /// Error when removing a template that is not a template
765    #[derive(Debug, Diagnostic, Error)]
766    #[error("unable to remove policy template `{template_id}` because it is not a template")]
767    pub struct RemoveTemplateNotTemplateError {
768        pub(crate) template_id: PolicyId,
769    }
770
771    impl RemoveTemplateNotTemplateError {
772        /// Get the [`PolicyId`] of the template which is not a template
773        pub fn template_id(&self) -> &PolicyId {
774            &self.template_id
775        }
776    }
777
778    /// Error when unlinking a template-linked policy
779    #[derive(Debug, Diagnostic, Error)]
780    #[error("unable to unlink policy `{policy_id}` because it does not exist")]
781    pub struct LinkNonexistentError {
782        pub(crate) policy_id: PolicyId,
783    }
784
785    impl LinkNonexistentError {
786        /// Get the [`PolicyId`] of the link which does not exist
787        pub fn policy_id(&self) -> &PolicyId {
788            &self.policy_id
789        }
790    }
791
792    /// Error when removing a link that is not a link
793    #[derive(Debug, Diagnostic, Error)]
794    #[error("unable to unlink `{policy_id}` because it is not a link")]
795    pub struct UnlinkLinkNotLinkError {
796        pub(crate) policy_id: PolicyId,
797    }
798
799    impl UnlinkLinkNotLinkError {
800        /// Get the [`PolicyId`] of the link which is not a link
801        pub fn policy_id(&self) -> &PolicyId {
802            &self.policy_id
803        }
804    }
805
806    /// Error during JSON ser/de of the policy set (as opposed to individual policies)
807    #[derive(Debug, Diagnostic, Error)]
808    #[error("error serializing/deserializing policy set to/from JSON")]
809    pub struct JsonPolicySetError {
810        #[from]
811        pub(crate) inner: serde_json::Error,
812    }
813
814    /// Error when a PST `PolicySet` map key doesn't match the inner
815    /// template/policy id
816    #[derive(Debug, Diagnostic, Error)]
817    #[error(
818        "policy set map key `{map_key}` does not match the inner policy/template id `{inner_id}`"
819    )]
820    pub struct InconsistentPolicyId {
821        pub(crate) map_key: PolicyId,
822        pub(crate) inner_id: PolicyId,
823    }
824
825    impl InconsistentPolicyId {
826        /// Get the map key that was used in the PST `PolicySet`
827        pub fn map_key(&self) -> &PolicyId {
828            &self.map_key
829        }
830
831        /// Get the inner id from the template/policy
832        pub fn inner_id(&self) -> &PolicyId {
833            &self.inner_id
834        }
835    }
836}
837
838/// Potential errors when adding to a `PolicySet`.
839#[derive(Debug, Diagnostic, Error)]
840#[non_exhaustive]
841pub enum PolicySetError {
842    /// There was a duplicate [`PolicyId`] encountered in either the set of
843    /// templates or the set of policies.
844    #[error(transparent)]
845    #[diagnostic(transparent)]
846    AlreadyDefined(#[from] policy_set_errors::AlreadyDefined),
847    /// Error when linking a template
848    #[error(transparent)]
849    #[diagnostic(transparent)]
850    Linking(#[from] policy_set_errors::LinkingError),
851    /// Expected a static policy, but a template-linked policy was provided
852    #[error(transparent)]
853    #[diagnostic(transparent)]
854    ExpectedStatic(#[from] policy_set_errors::ExpectedStatic),
855    /// Expected a template, but a static policy was provided.
856    #[error(transparent)]
857    #[diagnostic(transparent)]
858    ExpectedTemplate(#[from] policy_set_errors::ExpectedTemplate),
859    /// Error when removing a static policy that doesn't exist
860    #[error(transparent)]
861    #[diagnostic(transparent)]
862    PolicyNonexistent(#[from] policy_set_errors::PolicyNonexistentError),
863    /// Error when removing a template that doesn't exist
864    #[error(transparent)]
865    #[diagnostic(transparent)]
866    TemplateNonexistent(#[from] policy_set_errors::TemplateNonexistentError),
867    /// Error when removing a template with active links
868    #[error(transparent)]
869    #[diagnostic(transparent)]
870    RemoveTemplateWithActiveLinks(#[from] policy_set_errors::RemoveTemplateWithActiveLinksError),
871    /// Error when removing a template that is not a template
872    #[error(transparent)]
873    #[diagnostic(transparent)]
874    RemoveTemplateNotTemplate(#[from] policy_set_errors::RemoveTemplateNotTemplateError),
875    /// Error when unlinking a linked policy
876    #[error(transparent)]
877    #[diagnostic(transparent)]
878    LinkNonexistent(#[from] policy_set_errors::LinkNonexistentError),
879    /// Error when removing a link that is not a link
880    #[error(transparent)]
881    #[diagnostic(transparent)]
882    UnlinkLinkNotLink(#[from] policy_set_errors::UnlinkLinkNotLinkError),
883    /// Error when converting a policy/template from JSON format
884    #[error(transparent)]
885    #[diagnostic(transparent)]
886    FromJson(#[from] PolicyFromJsonError),
887    /// Error when converting a policy/template to JSON format
888    #[error("Error serializing a policy/template to JSON")]
889    #[diagnostic(transparent)]
890    ToJson(#[from] PolicyToJsonError),
891    /// Error during JSON ser/de of the policy set (as opposed to individual policies)
892    #[error(transparent)]
893    #[diagnostic(transparent)]
894    JsonPolicySet(#[from] policy_set_errors::JsonPolicySetError),
895    /// Error when converting from PST representation
896    #[error(transparent)]
897    #[diagnostic(transparent)]
898    PstConversion(#[from] pst::PstConstructionError),
899    /// Error when a PST `PolicySet` map key doesn't match the inner
900    /// template/policy id
901    #[error(transparent)]
902    #[diagnostic(transparent)]
903    InconsistentPolicyId(#[from] policy_set_errors::InconsistentPolicyId),
904}
905
906#[doc(hidden)]
907impl From<ast::PolicySetError> for PolicySetError {
908    fn from(e: ast::PolicySetError) -> Self {
909        match e {
910            ast::PolicySetError::Occupied { id } => {
911                Self::AlreadyDefined(policy_set_errors::AlreadyDefined {
912                    id: PolicyId::new(id),
913                })
914            }
915        }
916    }
917}
918
919#[doc(hidden)]
920impl From<ast::LinkingError> for PolicySetError {
921    fn from(e: ast::LinkingError) -> Self {
922        Self::Linking(e.into())
923    }
924}
925
926#[doc(hidden)]
927impl From<ast::UnexpectedSlotError> for PolicySetError {
928    fn from(_: ast::UnexpectedSlotError) -> Self {
929        Self::ExpectedStatic(policy_set_errors::ExpectedStatic::new())
930    }
931}
932
933#[doc(hidden)]
934impl From<est::PolicySetFromJsonError> for PolicySetError {
935    fn from(e: est::PolicySetFromJsonError) -> Self {
936        match e {
937            est::PolicySetFromJsonError::PolicySet(e) => e.into(),
938            est::PolicySetFromJsonError::Linking(e) => e.into(),
939            est::PolicySetFromJsonError::FromJsonError(e) => Self::FromJson(e.into()),
940        }
941    }
942}
943
944/// Represents one or more [`ParseError`]s encountered when parsing a policy or
945/// expression.
946///
947/// By default, the `Diagnostic` and `Error` implementations will only print the
948/// first error. If you want to see all errors, use `.iter()` or `.into_iter()`.
949#[derive(Debug, Diagnostic, Error)]
950#[error(transparent)]
951#[diagnostic(transparent)]
952pub struct ParseErrors(#[from] cedar_policy_core::parser::err::ParseErrors);
953
954impl ParseErrors {
955    /// Get every [`ParseError`] associated with this [`ParseErrors`] object.
956    /// The returned iterator is guaranteed to be nonempty.
957    pub fn iter(&self) -> impl Iterator<Item = &ParseError> {
958        self.0.iter().map(ParseError::ref_cast)
959    }
960}
961
962/// Errors that can occur when parsing policies or expressions.
963///
964/// Marked as `non_exhaustive` to support adding additional error information
965/// in the future without a major version bump.
966#[derive(Debug, Diagnostic, Error, RefCast)]
967#[repr(transparent)]
968#[error(transparent)]
969#[diagnostic(transparent)]
970#[non_exhaustive]
971pub struct ParseError {
972    #[from]
973    inner: cedar_policy_core::parser::err::ParseError,
974}
975
976/// Errors that can happen when getting the JSON representation of a policy
977#[derive(Debug, Diagnostic, Error)]
978pub enum PolicyToJsonError {
979    /// Parse error in the policy text
980    #[error(transparent)]
981    #[diagnostic(transparent)]
982    Parse(#[from] ParseErrors),
983    /// For linked policies, error linking the JSON representation
984    #[error(transparent)]
985    #[diagnostic(transparent)]
986    Link(#[from] policy_to_json_errors::JsonLinkError),
987    /// Error in the JSON serialization
988    #[error(transparent)]
989    JsonSerialization(#[from] policy_to_json_errors::PolicyJsonSerializationError),
990}
991
992#[doc(hidden)]
993impl From<est::LinkingError> for PolicyToJsonError {
994    fn from(e: est::LinkingError) -> Self {
995        policy_to_json_errors::JsonLinkError::from(e).into()
996    }
997}
998
999impl From<serde_json::Error> for PolicyToJsonError {
1000    fn from(e: serde_json::Error) -> Self {
1001        policy_to_json_errors::PolicyJsonSerializationError::from(e).into()
1002    }
1003}
1004
1005impl From<pst::PstConstructionError> for PolicyToJsonError {
1006    fn from(e: pst::PstConstructionError) -> Self {
1007        Self::JsonSerialization(serde_json::Error::custom(e.to_string()).into())
1008    }
1009}
1010
1011/// Error subtypes for [`PolicyToJsonError`]
1012pub mod policy_to_json_errors {
1013    use cedar_policy_core::est;
1014    use miette::Diagnostic;
1015    use thiserror::Error;
1016
1017    /// Error linking the JSON representation of a linked policy
1018    #[derive(Debug, Diagnostic, Error)]
1019    #[error(transparent)]
1020    #[diagnostic(transparent)]
1021    pub struct JsonLinkError {
1022        /// Underlying error
1023        #[from]
1024        err: est::LinkingError,
1025    }
1026
1027    /// Error serializing a policy as JSON
1028    #[derive(Debug, Diagnostic, Error)]
1029    #[error(transparent)]
1030    pub struct PolicyJsonSerializationError {
1031        /// Underlying error
1032        #[from]
1033        err: serde_json::Error,
1034    }
1035}
1036
1037/// Error when converting a policy or template from JSON format
1038#[derive(Debug, Diagnostic, Error)]
1039#[error("error deserializing a policy/template from JSON")]
1040#[diagnostic(transparent)]
1041pub struct PolicyFromJsonError {
1042    #[from]
1043    pub(crate) inner: cedar_policy_core::est::FromJsonError,
1044}
1045
1046/// Error type for parsing `Context` from JSON
1047#[derive(Debug, Diagnostic, Error)]
1048pub enum ContextJsonError {
1049    /// Error deserializing the JSON into a [`crate::Context`]
1050    #[error(transparent)]
1051    #[diagnostic(transparent)]
1052    JsonDeserialization(#[from] entities_json_errors::JsonDeserializationError),
1053    /// Error constructing the [`crate::Context`] itself
1054    #[error(transparent)]
1055    #[diagnostic(transparent)]
1056    ContextCreation(#[from] ContextCreationError),
1057    /// The supplied action doesn't exist in the supplied schema
1058    #[error(transparent)]
1059    #[diagnostic(transparent)]
1060    MissingAction(#[from] context_json_errors::MissingActionError),
1061}
1062
1063impl ContextJsonError {
1064    /// Construct a `ContextJsonError::MissingAction`
1065    pub(crate) fn missing_action(action: EntityUid) -> Self {
1066        Self::MissingAction(context_json_errors::MissingActionError { action })
1067    }
1068}
1069
1070#[doc(hidden)]
1071impl From<cedar_policy_core::entities::json::ContextJsonDeserializationError> for ContextJsonError {
1072    fn from(e: cedar_policy_core::entities::json::ContextJsonDeserializationError) -> Self {
1073        match e {
1074            cedar_policy_core::entities::json::ContextJsonDeserializationError::JsonDeserialization(e) => Self::JsonDeserialization(e),
1075            cedar_policy_core::entities::json::ContextJsonDeserializationError::ContextCreation(e) => Self::ContextCreation(e.into())
1076        }
1077    }
1078}
1079
1080/// Error subtypes for [`ContextJsonError`]
1081pub mod context_json_errors {
1082    use super::EntityUid;
1083    use miette::Diagnostic;
1084    use thiserror::Error;
1085
1086    /// The supplied action doesn't exist in the supplied schema
1087    #[derive(Debug, Diagnostic, Error)]
1088    #[error("action `{action}` does not exist in the supplied schema")]
1089    pub struct MissingActionError {
1090        /// UID of the action which doesn't exist
1091        pub(super) action: EntityUid,
1092    }
1093
1094    impl MissingActionError {
1095        /// Get the [`EntityUid`] of the action which doesn't exist
1096        pub fn action(&self) -> &EntityUid {
1097            &self.action
1098        }
1099    }
1100}
1101
1102/// Error type for parsing a `RestrictedExpression`
1103#[derive(Debug, Diagnostic, Error)]
1104#[non_exhaustive]
1105pub enum RestrictedExpressionParseError {
1106    /// Failed to parse the expression
1107    #[error(transparent)]
1108    #[diagnostic(transparent)]
1109    Parse(#[from] ParseErrors),
1110    /// Parsed successfully as an expression, but failed to construct a
1111    /// restricted expression, for the reason indicated in the underlying error
1112    #[error(transparent)]
1113    #[diagnostic(transparent)]
1114    InvalidRestrictedExpression(#[from] RestrictedExpressionError),
1115}
1116
1117#[doc(hidden)]
1118impl From<cedar_policy_core::ast::RestrictedExpressionParseError>
1119    for RestrictedExpressionParseError
1120{
1121    fn from(e: cedar_policy_core::ast::RestrictedExpressionParseError) -> Self {
1122        match e {
1123            cedar_policy_core::ast::RestrictedExpressionParseError::Parse(e) => {
1124                Self::Parse(e.into())
1125            }
1126            cedar_policy_core::ast::RestrictedExpressionParseError::InvalidRestrictedExpression(
1127                e,
1128            ) => e.into(),
1129        }
1130    }
1131}
1132
1133/// The request does not conform to the schema
1134#[derive(Debug, Diagnostic, Error)]
1135#[non_exhaustive]
1136pub enum RequestValidationError {
1137    /// Request action is not declared in the schema
1138    #[error(transparent)]
1139    #[diagnostic(transparent)]
1140    UndeclaredAction(#[from] request_validation_errors::UndeclaredActionError),
1141    /// Request principal is of a type not declared in the schema
1142    #[error(transparent)]
1143    #[diagnostic(transparent)]
1144    UndeclaredPrincipalType(#[from] request_validation_errors::UndeclaredPrincipalTypeError),
1145    /// Request resource is of a type not declared in the schema
1146    #[error(transparent)]
1147    #[diagnostic(transparent)]
1148    UndeclaredResourceType(#[from] request_validation_errors::UndeclaredResourceTypeError),
1149    /// Request principal is of a type that is declared in the schema, but is
1150    /// not valid for the request action
1151    #[error(transparent)]
1152    #[diagnostic(transparent)]
1153    InvalidPrincipalType(#[from] request_validation_errors::InvalidPrincipalTypeError),
1154    /// Request resource is of a type that is declared in the schema, but is
1155    /// not valid for the request action
1156    #[error(transparent)]
1157    #[diagnostic(transparent)]
1158    InvalidResourceType(#[from] request_validation_errors::InvalidResourceTypeError),
1159    /// Context does not comply with the shape specified for the request action
1160    #[error(transparent)]
1161    #[diagnostic(transparent)]
1162    InvalidContext(#[from] request_validation_errors::InvalidContextError),
1163    /// Error computing the type of the `Context`
1164    #[error(transparent)]
1165    #[diagnostic(transparent)]
1166    TypeOfContext(#[from] request_validation_errors::TypeOfContextError),
1167    /// Error when a principal or resource entity is of an enumerated entity
1168    /// type but has an invalid EID
1169    #[error(transparent)]
1170    #[diagnostic(transparent)]
1171    InvalidEnumEntity(#[from] request_validation_errors::InvalidEnumEntityError),
1172}
1173
1174#[doc(hidden)]
1175impl From<cedar_policy_core::validator::RequestValidationError> for RequestValidationError {
1176    fn from(e: cedar_policy_core::validator::RequestValidationError) -> Self {
1177        match e {
1178            cedar_policy_core::validator::RequestValidationError::UndeclaredAction(e) => {
1179                Self::UndeclaredAction(e.into())
1180            }
1181            cedar_policy_core::validator::RequestValidationError::UndeclaredPrincipalType(e) => {
1182                Self::UndeclaredPrincipalType(e.into())
1183            }
1184            cedar_policy_core::validator::RequestValidationError::UndeclaredResourceType(e) => {
1185                Self::UndeclaredResourceType(e.into())
1186            }
1187            cedar_policy_core::validator::RequestValidationError::InvalidPrincipalType(e) => {
1188                Self::InvalidPrincipalType(e.into())
1189            }
1190            cedar_policy_core::validator::RequestValidationError::InvalidResourceType(e) => {
1191                Self::InvalidResourceType(e.into())
1192            }
1193            cedar_policy_core::validator::RequestValidationError::InvalidContext(e) => {
1194                Self::InvalidContext(e.into())
1195            }
1196            cedar_policy_core::validator::RequestValidationError::TypeOfContext(e) => {
1197                Self::TypeOfContext(e.into())
1198            }
1199            cedar_policy_core::validator::RequestValidationError::InvalidEnumEntity(e) => {
1200                Self::InvalidEnumEntity(e.into())
1201            }
1202        }
1203    }
1204}
1205
1206/// Error subtypes for [`RequestValidationError`]
1207pub mod request_validation_errors {
1208    use cedar_policy_core::extensions::ExtensionFunctionLookupError;
1209    use miette::Diagnostic;
1210    use ref_cast::RefCast;
1211    use thiserror::Error;
1212
1213    use crate::{Context, EntityTypeName, EntityUid};
1214
1215    /// Request action is not declared in the schema
1216    #[derive(Debug, Diagnostic, Error)]
1217    #[error(transparent)]
1218    #[diagnostic(transparent)]
1219    pub struct UndeclaredActionError(
1220        #[from] cedar_policy_core::validator::request_validation_errors::UndeclaredActionError,
1221    );
1222
1223    impl UndeclaredActionError {
1224        /// The action which was not declared in the schema
1225        pub fn action(&self) -> &EntityUid {
1226            RefCast::ref_cast(self.0.action())
1227        }
1228    }
1229
1230    /// Request principal is of a type not declared in the schema
1231    #[derive(Debug, Diagnostic, Error)]
1232    #[error(transparent)]
1233    #[diagnostic(transparent)]
1234    pub struct UndeclaredPrincipalTypeError(
1235        #[from]
1236        cedar_policy_core::validator::request_validation_errors::UndeclaredPrincipalTypeError,
1237    );
1238
1239    impl UndeclaredPrincipalTypeError {
1240        /// The principal type which was not declared in the schema
1241        pub fn principal_ty(&self) -> &EntityTypeName {
1242            RefCast::ref_cast(self.0.principal_ty())
1243        }
1244    }
1245
1246    /// Request resource is of a type not declared in the schema
1247    #[derive(Debug, Diagnostic, Error)]
1248    #[error(transparent)]
1249    #[diagnostic(transparent)]
1250    pub struct UndeclaredResourceTypeError(
1251        #[from]
1252        cedar_policy_core::validator::request_validation_errors::UndeclaredResourceTypeError,
1253    );
1254
1255    impl UndeclaredResourceTypeError {
1256        /// The resource type which was not declared in the schema
1257        pub fn resource_ty(&self) -> &EntityTypeName {
1258            RefCast::ref_cast(self.0.resource_ty())
1259        }
1260    }
1261
1262    /// Request principal is of a type that is declared in the schema, but is
1263    /// not valid for the request action
1264    #[derive(Debug, Diagnostic, Error)]
1265    #[error(transparent)]
1266    #[diagnostic(transparent)]
1267    pub struct InvalidPrincipalTypeError(
1268        #[from] cedar_policy_core::validator::request_validation_errors::InvalidPrincipalTypeError,
1269    );
1270
1271    impl InvalidPrincipalTypeError {
1272        /// The principal type which is not valid
1273        pub fn principal_ty(&self) -> &EntityTypeName {
1274            RefCast::ref_cast(self.0.principal_ty())
1275        }
1276
1277        /// The action which it is not valid for
1278        pub fn action(&self) -> &EntityUid {
1279            RefCast::ref_cast(self.0.action())
1280        }
1281    }
1282
1283    /// Request resource is of a type that is declared in the schema, but is
1284    /// not valid for the request action
1285    #[derive(Debug, Diagnostic, Error)]
1286    #[error(transparent)]
1287    #[diagnostic(transparent)]
1288    pub struct InvalidResourceTypeError(
1289        #[from] cedar_policy_core::validator::request_validation_errors::InvalidResourceTypeError,
1290    );
1291
1292    impl InvalidResourceTypeError {
1293        /// The resource type which is not valid
1294        pub fn resource_ty(&self) -> &EntityTypeName {
1295            RefCast::ref_cast(self.0.resource_ty())
1296        }
1297
1298        /// The action which it is not valid for
1299        pub fn action(&self) -> &EntityUid {
1300            RefCast::ref_cast(self.0.action())
1301        }
1302    }
1303
1304    /// Context does not comply with the shape specified for the request action
1305    #[derive(Debug, Diagnostic, Error)]
1306    #[error(transparent)]
1307    #[diagnostic(transparent)]
1308    pub struct InvalidContextError(
1309        #[from] cedar_policy_core::validator::request_validation_errors::InvalidContextError,
1310    );
1311
1312    impl InvalidContextError {
1313        /// The context which is not valid
1314        pub fn context(&self) -> &Context {
1315            RefCast::ref_cast(self.0.context())
1316        }
1317
1318        /// The action which it is not valid for
1319        pub fn action(&self) -> &EntityUid {
1320            RefCast::ref_cast(self.0.action())
1321        }
1322    }
1323
1324    /// Error computing the type of the `Context`
1325    #[derive(Debug, Diagnostic, Error)]
1326    #[error(transparent)]
1327    #[diagnostic(transparent)]
1328    pub struct TypeOfContextError(#[from] ExtensionFunctionLookupError);
1329
1330    /// Error when a principal or resource entity is of an enumerated entity
1331    /// type but has an invalid EID
1332    #[derive(Debug, Diagnostic, Error)]
1333    #[error(transparent)]
1334    #[diagnostic(transparent)]
1335    pub struct InvalidEnumEntityError(
1336        #[from] cedar_policy_core::entities::conformance::err::InvalidEnumEntityError,
1337    );
1338}
1339
1340/// An error generated by entity slicing.
1341#[derive(Debug, Error, Diagnostic)]
1342#[non_exhaustive]
1343#[cfg(feature = "entity-manifest")]
1344pub enum EntityManifestError {
1345    /// A validation error was encountered
1346    #[error(transparent)]
1347    #[diagnostic(transparent)]
1348    Validation(#[from] ValidationResult),
1349    /// A entities error was encountered
1350    #[error(transparent)]
1351    #[diagnostic(transparent)]
1352    Entities(#[from] EntitiesError),
1353
1354    /// The request was partial
1355    #[error(transparent)]
1356    #[diagnostic(transparent)]
1357    PartialRequest(#[from] PartialRequestError),
1358    /// A policy was partial
1359    #[error(transparent)]
1360    #[diagnostic(transparent)]
1361    PartialExpression(#[from] PartialExpressionError),
1362    /// Encounters unsupported Cedar feature
1363    #[error(transparent)]
1364    #[diagnostic(transparent)]
1365    UnsupportedCedarFeature(#[from] UnsupportedCedarFeatureError),
1366}
1367
1368#[cfg(feature = "entity-manifest")]
1369impl From<entity_manifest::EntityManifestError> for EntityManifestError {
1370    fn from(e: entity_manifest::EntityManifestError) -> Self {
1371        match e {
1372            entity_manifest::EntityManifestError::Validation(e) => Self::Validation(e.into()),
1373            entity_manifest::EntityManifestError::Entities(e) => Self::Entities(e),
1374            entity_manifest::EntityManifestError::PartialRequest(e) => Self::PartialRequest(e),
1375            entity_manifest::EntityManifestError::PartialExpression(e) => {
1376                Self::PartialExpression(e)
1377            }
1378            entity_manifest::EntityManifestError::UnsupportedCedarFeature(e) => {
1379                Self::UnsupportedCedarFeature(e)
1380            }
1381        }
1382    }
1383}
1384
1385#[cfg(feature = "tpe")]
1386/// Error thrown when creating a `PartialRequest`
1387#[doc = include_str!("../../experimental_warning.md")]
1388#[derive(Debug, Error, Diagnostic)]
1389pub enum PartialRequestCreationError {
1390    /// When the context contains unknowns
1391    #[error("Context contains unknowns")]
1392    ContextContainsUnknowns,
1393    /// When the request does not pass validation
1394    #[error(transparent)]
1395    #[diagnostic(transparent)]
1396    Validation(#[from] RequestValidationError),
1397}
1398
1399#[cfg(feature = "tpe")]
1400/// Errors that can be encountered when re-evaluating a partial response
1401#[doc = include_str!("../../experimental_warning.md")]
1402#[derive(Debug, Error)]
1403pub enum TpeReauthorizationError {
1404    /// `Request` cannot be validated
1405    #[error(transparent)]
1406    RequestValidation(#[from] RequestValidationError),
1407    /// `Entities` cannot be validated
1408    #[error(transparent)]
1409    EntityValidation(#[from] EntitySchemaConformanceError),
1410    /// Inconsistent entities
1411    #[error(transparent)]
1412    InconsistentEntities(#[from] tpe_err::EntitiesConsistencyError),
1413    /// Inconsistent requests
1414    #[error(transparent)]
1415    InconsistentRequests(#[from] tpe_err::RequestConsistencyError),
1416}
1417
1418#[cfg(feature = "tpe")]
1419impl From<tpe_err::ReauthorizationError> for TpeReauthorizationError {
1420    fn from(value: tpe_err::ReauthorizationError) -> Self {
1421        match value {
1422            tpe_err::ReauthorizationError::EntitiesConsistency(e) => Self::InconsistentEntities(e),
1423            tpe_err::ReauthorizationError::EntityValidation(e) => Self::EntityValidation(e),
1424            tpe_err::ReauthorizationError::RequestConsistency(e) => Self::InconsistentRequests(e),
1425            tpe_err::ReauthorizationError::RequestValidation(e) => {
1426                Self::RequestValidation(e.into())
1427            }
1428        }
1429    }
1430}
1431
1432#[cfg(feature = "tpe")]
1433/// Errors that can be encountered when performing a permission query
1434#[doc = include_str!("../../experimental_warning.md")]
1435#[derive(Debug, Error)]
1436pub enum PermissionQueryError {
1437    /// When concrete entities fail to validate or contain unknowns
1438    #[error(transparent)]
1439    Entities(#[from] tpe_err::EntitiesError),
1440    /// When TPE fails
1441    #[error(transparent)]
1442    TPE(#[from] tpe_err::TpeError),
1443}
1444
1445#[cfg(feature = "tpe")]
1446#[doc = include_str!("../../experimental_warning.md")]
1447/// Error when constructing [`crate::PartialEntity`]
1448#[derive(Debug, Error)]
1449pub enum PartialEntityError {
1450    /// An evaluation error was encountered
1451    #[error(transparent)]
1452    Evaluation(#[from] EvaluationError),
1453    /// Fail to construct a [`crate::PartialEntity`]
1454    #[error(transparent)]
1455    Entities(#[from] tpe_err::EntitiesError),
1456}