cedar_policy_core/entities/conformance/
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//! This module cotnains errors around entities not conforming to schemas
17use super::TypeMismatchError;
18use crate::ast::{EntityType, EntityUID};
19use crate::extensions::ExtensionFunctionLookupError;
20use miette::Diagnostic;
21use smol_str::SmolStr;
22use thiserror::Error;
23
24/// Errors raised when entities do not conform to the schema
25//
26// CAUTION: this type is publicly exported in `cedar-policy`.
27// Don't make fields `pub`, don't make breaking changes, and use caution
28// when adding public methods.
29#[derive(Debug, Diagnostic, Error)]
30#[non_exhaustive]
31pub enum EntitySchemaConformanceError {
32    /// Encountered attribute that shouldn't exist on entities of this type
33    #[error(transparent)]
34    #[diagnostic(transparent)]
35    UnexpectedEntityAttr(UnexpectedEntityAttr),
36    /// Encountered tag, but no tags should exist on entities of this type
37    #[error(transparent)]
38    #[diagnostic(transparent)]
39    UnexpectedEntityTag(UnexpectedEntityTag),
40    /// Didn't encounter attribute that should exist
41    #[error(transparent)]
42    #[diagnostic(transparent)]
43    MissingRequiredEntityAttr(MissingRequiredEntityAttr),
44    /// The given attribute on the given entity had a different type than the
45    /// schema indicated
46    #[error(transparent)]
47    #[diagnostic(transparent)]
48    TypeMismatch(TypeMismatch),
49    /// Found an ancestor of a type that's not allowed for that entity
50    #[error(transparent)]
51    #[diagnostic(transparent)]
52    InvalidAncestorType(InvalidAncestorType),
53    /// Encountered an entity of a type which is not declared in the schema.
54    /// Note that this error is only used for non-Action entity types.
55    #[error(transparent)]
56    #[diagnostic(transparent)]
57    UnexpectedEntityType(#[from] UnexpectedEntityTypeError),
58    /// Encountered an action which was not declared in the schema
59    #[error(transparent)]
60    #[diagnostic(transparent)]
61    UndeclaredAction(UndeclaredAction),
62    /// Encountered an action whose definition doesn't precisely match the
63    /// schema's declaration of that action
64    #[error(transparent)]
65    #[diagnostic(transparent)]
66    ActionDeclarationMismatch(ActionDeclarationMismatch),
67    /// Error looking up an extension function. This error can occur when
68    /// checking entity conformance because that may require getting information
69    /// about any extension functions referenced in entity attribute values.
70    #[error(transparent)]
71    #[diagnostic(transparent)]
72    ExtensionFunctionLookup(ExtensionFunctionLookup),
73}
74
75impl EntitySchemaConformanceError {
76    pub(crate) fn unexpected_entity_attr(uid: EntityUID, attr: impl Into<SmolStr>) -> Self {
77        Self::UnexpectedEntityAttr(UnexpectedEntityAttr {
78            uid,
79            attr: attr.into(),
80        })
81    }
82
83    pub(crate) fn unexpected_entity_tag(uid: EntityUID, tag: impl Into<SmolStr>) -> Self {
84        Self::UnexpectedEntityTag(UnexpectedEntityTag {
85            uid,
86            tag: tag.into(),
87        })
88    }
89
90    pub(crate) fn missing_entity_attr(uid: EntityUID, attr: impl Into<SmolStr>) -> Self {
91        Self::MissingRequiredEntityAttr(MissingRequiredEntityAttr {
92            uid,
93            attr: attr.into(),
94        })
95    }
96
97    pub(crate) fn type_mismatch(
98        uid: EntityUID,
99        attr: impl Into<SmolStr>,
100        err: TypeMismatchError,
101    ) -> Self {
102        Self::TypeMismatch(TypeMismatch {
103            uid,
104            attr: attr.into(),
105            err,
106        })
107    }
108
109    pub(crate) fn invalid_ancestor_type(uid: EntityUID, ancestor_type: EntityType) -> Self {
110        Self::InvalidAncestorType(InvalidAncestorType {
111            uid,
112            ancestor_ty: Box::new(ancestor_type),
113        })
114    }
115
116    pub(crate) fn undeclared_action(uid: EntityUID) -> Self {
117        Self::UndeclaredAction(UndeclaredAction { uid })
118    }
119
120    pub(crate) fn action_declaration_mismatch(uid: EntityUID) -> Self {
121        Self::ActionDeclarationMismatch(ActionDeclarationMismatch { uid })
122    }
123
124    pub(crate) fn extension_function_lookup(
125        uid: EntityUID,
126        attr: impl Into<SmolStr>,
127        err: ExtensionFunctionLookupError,
128    ) -> Self {
129        Self::ExtensionFunctionLookup(ExtensionFunctionLookup {
130            uid,
131            attr: attr.into(),
132            err,
133        })
134    }
135}
136
137/// Error looking up an extension function. This error can occur when
138/// checking entity conformance because that may require getting information
139/// about any extension functions referenced in entity attribute values.
140//
141// CAUTION: this type is publicly exported in `cedar-policy`.
142// Don't make fields `pub`, don't make breaking changes, and use caution
143// when adding public methods.
144#[derive(Debug, Error, Diagnostic)]
145#[error("in attribute `{attr}` on `{uid}`, {err}")]
146pub struct ExtensionFunctionLookup {
147    /// Entity where the error occurred
148    uid: EntityUID,
149    /// Name of the attribute where the error occurred
150    attr: SmolStr,
151    /// Underlying error
152    #[diagnostic(transparent)]
153    err: ExtensionFunctionLookupError,
154}
155
156/// Encountered an action whose definition doesn't precisely match the
157/// schema's declaration of that action
158//
159// CAUTION: this type is publicly exported in `cedar-policy`.
160// Don't make fields `pub`, don't make breaking changes, and use caution
161// when adding public methods.
162#[derive(Debug, Error, Diagnostic)]
163#[error("definition of action `{uid}` does not match its schema declaration")]
164#[diagnostic(help(
165    "to use the schema's definition of `{uid}`, simply omit it from the entities input data"
166))]
167pub struct ActionDeclarationMismatch {
168    /// Action whose definition mismatched between entity data and schema
169    uid: EntityUID,
170}
171
172/// Encountered an action which was not declared in the schema
173//
174// CAUTION: this type is publicly exported in `cedar-policy`.
175// Don't make fields `pub`, don't make breaking changes, and use caution
176// when adding public methods.
177#[derive(Debug, Error, Diagnostic)]
178#[error("found action entity `{uid}`, but it was not declared as an action in the schema")]
179pub struct UndeclaredAction {
180    /// Action which was not declared in the schema
181    uid: EntityUID,
182}
183
184/// Found an ancestor of a type that's not allowed for that entity
185//
186// CAUTION: this type is publicly exported in `cedar-policy`.
187// Don't make fields `pub`, don't make breaking changes, and use caution
188// when adding public methods.
189#[derive(Debug, Error, Diagnostic)]
190#[error(
191    "`{uid}` is not allowed to have an ancestor of type `{ancestor_ty}` according to the schema"
192)]
193pub struct InvalidAncestorType {
194    /// Entity that has an invalid ancestor type
195    uid: EntityUID,
196    /// Ancestor type which was invalid
197    ancestor_ty: Box<EntityType>, // boxed to avoid this variant being very large (and thus all EntitySchemaConformanceErrors being large)
198}
199
200/// Encountered attribute that shouldn't exist on entities of this type
201//
202// CAUTION: this type is publicly exported in `cedar-policy`.
203// Don't make fields `pub`, don't make breaking changes, and use caution
204// when adding public methods.
205#[derive(Debug, Error, Diagnostic)]
206#[error("attribute `{attr}` on `{uid}` should not exist according to the schema")]
207pub struct UnexpectedEntityAttr {
208    uid: EntityUID,
209    attr: SmolStr,
210}
211
212/// Encountered tag, but no tags should exist on entities of this type
213//
214// CAUTION: this type is publicly exported in `cedar-policy`.
215// Don't make fields `pub`, don't make breaking changes, and use caution
216// when adding public methods.
217#[derive(Debug, Error, Diagnostic)]
218#[error(
219    "found a tag `{tag}` on `{uid}`, but no tags should exist on `{uid}` according to the schema"
220)]
221pub struct UnexpectedEntityTag {
222    uid: EntityUID,
223    tag: SmolStr,
224}
225
226/// Didn't encounter attribute that should exist
227//
228// CAUTION: this type is publicly exported in `cedar-policy`.
229// Don't make fields `pub`, don't make breaking changes, and use caution
230// when adding public methods.
231#[derive(Debug, Error, Diagnostic)]
232#[error("expected entity `{uid}` to have attribute `{attr}`, but it does not")]
233pub struct MissingRequiredEntityAttr {
234    uid: EntityUID,
235    attr: SmolStr,
236}
237
238/// The given attribute on the given entity had a different type than the
239/// schema indicated
240//
241// CAUTION: this type is publicly exported in `cedar-policy`.
242// Don't make fields `pub`, don't make breaking changes, and use caution
243// when adding public methods.
244#[derive(Debug, Error, Diagnostic)]
245#[error("in attribute `{attr}` on `{uid}`, {err}")]
246pub struct TypeMismatch {
247    uid: EntityUID,
248    attr: SmolStr,
249    #[diagnostic(transparent)]
250    err: TypeMismatchError,
251}
252
253/// Encountered an entity of a type which is not declared in the schema.
254/// Note that this error is only used for non-Action entity types.
255//
256// CAUTION: this type is publicly exported in `cedar-policy`.
257// Don't make fields `pub`, don't make breaking changes, and use caution
258// when adding public methods.
259#[derive(Debug, Error)]
260#[error("entity `{uid}` has type `{}` which is not declared in the schema", .uid.entity_type())]
261pub struct UnexpectedEntityTypeError {
262    /// Entity that had the unexpected type
263    pub uid: EntityUID,
264    /// Suggested similar entity types that actually are declared in the schema (if any)
265    pub suggested_types: Vec<EntityType>,
266}
267
268impl Diagnostic for UnexpectedEntityTypeError {
269    fn help<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
270        match self.suggested_types.as_slice() {
271            [] => None,
272            [ty] => Some(Box::new(format!("did you mean `{ty}`?"))),
273            tys => Some(Box::new(format!(
274                "did you mean one of {:?}?",
275                tys.iter().map(ToString::to_string).collect::<Vec<String>>()
276            ))),
277        }
278    }
279}