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