cedar_policy_core/entities/json/err.rs
1/*
2 * Copyright 2022-2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
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
17use super::SchemaType;
18use crate::ast::{EntityUID, Expr, ExprKind, Name, RestrictedExpr, RestrictedExpressionError};
19use crate::extensions::ExtensionsError;
20use smol_str::SmolStr;
21use thiserror::Error;
22
23/// Errors thrown during deserialization from JSON
24#[derive(Debug, Error)]
25pub enum JsonDeserializationError {
26 /// Error thrown by `serde_json`
27 #[error("{0}")]
28 Serde(#[from] serde_json::Error),
29 /// Contents of an `__expr` escape failed to parse as a Cedar expression.
30 ///
31 /// `__expr` is deprecated (starting with the 1.2 release), and once it is
32 /// removed, this error will also be removed.
33 #[error(transparent)]
34 ExprParseError(crate::parser::err::ParseError),
35 /// Contents of an `__entity` escape failed to parse as an entity reference
36 #[error(transparent)]
37 EntityParseError(crate::parser::err::ParseError),
38 /// Function name in an `__extn` escape failed to parse as an extension function name
39 #[error(transparent)]
40 ExtnParseError(crate::parser::err::ParseError),
41 /// Restricted expression error
42 #[error(transparent)]
43 RestrictedExpressionError(#[from] RestrictedExpressionError),
44 /// Error thrown by an operation on `Extensions`
45 #[error(transparent)]
46 ExtensionsError(#[from] ExtensionsError),
47 /// A field that needs to be a literal entity reference, was some other JSON value
48 #[error("{ctx}, expected a literal entity reference, but got {got}")]
49 ExpectedLiteralEntityRef {
50 /// Context of this error
51 ctx: JsonDeserializationErrorContext,
52 /// the expression we got instead
53 got: Box<Expr>,
54 },
55 /// A field that needs to be an extension value, was some other JSON value
56 #[error("{ctx}, expected an extension value, but got {got}")]
57 ExpectedExtnValue {
58 /// Context of this error
59 ctx: JsonDeserializationErrorContext,
60 /// the expression we got instead
61 got: Box<Expr>,
62 },
63 /// Contexts need to be records, but we got some other JSON value
64 #[error("Expected Context to be a record, but got {got}")]
65 ExpectedContextToBeRecord {
66 /// Expression we got instead
67 got: Box<RestrictedExpr>,
68 },
69 /// Schema-based parsing needed an implicit extension constructor, but no suitable
70 /// constructor was found
71 #[error("Extension constructor for {arg_type} -> {return_type} not found")]
72 ImpliedConstructorNotFound {
73 /// return type of the constructor we were looking for
74 return_type: Box<SchemaType>,
75 /// argument type of the constructor we were looking for
76 arg_type: Box<SchemaType>,
77 },
78 /// During schema-based parsing, encountered this attribute on this entity, but that
79 /// attribute shouldn't exist on entities of this type
80 #[error("Attribute {:?} on {uid} shouldn't exist according to the schema", &.attr)]
81 UnexpectedEntityAttr {
82 /// Entity that had the unexpected attribute
83 uid: EntityUID,
84 /// Name of the attribute that was unexpected
85 attr: SmolStr,
86 },
87 /// During schema-based parsing, encountered this attribute on a record, but
88 /// that attribute shouldn't exist on that record
89 #[error("{ctx}, record attribute {record_attr:?} shouldn't exist according to the schema")]
90 UnexpectedRecordAttr {
91 /// Context of this error
92 ctx: JsonDeserializationErrorContext,
93 /// Name of the (Record) attribute which was unexpected
94 record_attr: SmolStr,
95 },
96 /// During schema-based parsing, didn't encounter this attribute of a
97 /// record, but that attribute should have existed
98 #[error("Expected {uid} to have an attribute {attr:?}, but it didn't")]
99 MissingRequiredEntityAttr {
100 /// Entity that is missing a required attribute
101 uid: EntityUID,
102 /// Name of the attribute which was expected
103 attr: SmolStr,
104 },
105 /// During schema-based parsing, didn't encounter this attribute of a
106 /// record, but that attribute should have existed
107 #[error("{ctx}, expected the record to have an attribute {record_attr:?}, but it didn't")]
108 MissingRequiredRecordAttr {
109 /// Context of this error
110 ctx: JsonDeserializationErrorContext,
111 /// Name of the (Record) attribute which was expected
112 record_attr: SmolStr,
113 },
114 /// During schema-based parsing, the given attribute on the given entity had
115 /// a different type than the schema indicated to expect
116 #[error("{ctx}, type mismatch: attribute was expected to have type {expected}, but actually has type {actual}")]
117 TypeMismatch {
118 /// Context of this error
119 ctx: JsonDeserializationErrorContext,
120 /// Type which was expected
121 expected: Box<SchemaType>,
122 /// Type which was encountered instead
123 actual: Box<SchemaType>,
124 },
125 /// During schema-based parsing, found a set whose elements don't all have the
126 /// same type. This doesn't match any possible schema.
127 #[error("{ctx}, set elements have different types: {ty1} and {ty2}")]
128 HeterogeneousSet {
129 /// Context of this error
130 ctx: JsonDeserializationErrorContext,
131 /// First element type which was found
132 ty1: Box<SchemaType>,
133 /// Second element type which was found
134 ty2: Box<SchemaType>,
135 },
136}
137
138/// Errors thrown during serialization to JSON
139#[derive(Debug, Error)]
140pub enum JsonSerializationError {
141 /// Error thrown by `serde_json`
142 #[error("{0}")]
143 Serde(#[from] serde_json::Error),
144 /// Extension-function calls with 0 arguments are not currently supported in
145 /// our JSON format.
146 #[error("extension-function calls with 0 arguments are not currently supported in our JSON format. found call of {func}")]
147 ExtnCall0Arguments {
148 /// Name of the function which was called with 0 arguments
149 func: Name,
150 },
151 /// Extension-function calls with 2 or more arguments are not currently
152 /// supported in our JSON format.
153 #[error("extension-function calls with 2 or more arguments are not currently supported in our JSON format. found call of {func}")]
154 ExtnCall2OrMoreArguments {
155 /// Name of the function which was called with 2 or more arguments
156 func: Name,
157 },
158 /// Encountered a `Record` which can't be serialized to JSON because it
159 /// contains a key which is reserved as a JSON escape.
160 #[error("record uses reserved key: {key}")]
161 ReservedKey {
162 /// Reserved key which was used by the `Record`
163 key: SmolStr,
164 },
165 /// Encountered an `ExprKind` which we didn't expect. Either a case is
166 /// missing in `JSONValue::from_expr()`, or an internal invariant was
167 /// violated and there is a non-restricted expression in `RestrictedExpr`
168 #[error("unexpected restricted expression: {kind:?}")]
169 UnexpectedRestrictedExprKind {
170 /// `ExprKind` which we didn't expect to find
171 kind: ExprKind,
172 },
173}
174
175/// Gives information about the context of a JSON deserialization error (e.g.,
176/// where we were in the JSON document).
177#[derive(Debug, Clone)]
178pub enum JsonDeserializationErrorContext {
179 /// The error occurred while deserializing the attribute `attr` of an entity.
180 EntityAttribute {
181 /// Entity where the error occurred
182 uid: EntityUID,
183 /// Attribute where the error occurred
184 attr: SmolStr,
185 },
186 /// The error occurred while deserializing the `parents` field of an entity.
187 EntityParents {
188 /// Entity where the error occurred
189 uid: EntityUID,
190 },
191 /// The error occurred while deserializing the `uid` field of an entity.
192 EntityUid,
193 /// The error occurred while deserializing the `Context`.
194 Context,
195}
196
197impl std::fmt::Display for JsonDeserializationErrorContext {
198 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199 match self {
200 Self::EntityAttribute { uid, attr } => write!(f, "In attribute {attr:?} on {uid}"),
201 Self::EntityParents { uid } => write!(f, "In parents field of {uid}"),
202 Self::EntityUid => write!(f, "In uid field of <unknown entity>"),
203 Self::Context => write!(f, "While parsing Context"),
204 }
205 }
206}