cedar_policy_validator/
err.rs1use std::collections::HashSet;
18
19use cedar_policy_core::{
20 ast::{EntityUID, Name},
21 parser::err::ParseError,
22 transitive_closure,
23};
24use itertools::Itertools;
25
26#[derive(Debug)]
27pub enum SchemaError {
28 ParseFileFormat(serde_json::Error),
30 ActionTransitiveClosureError(Box<transitive_closure::Err<EntityUID>>),
33 EntityTransitiveClosureError(transitive_closure::Err<Name>),
36 UnsupportedSchemaFeature(UnsupportedFeature),
39 UndeclaredEntityTypes(HashSet<String>),
44 UndeclaredActions(HashSet<String>),
46 UndeclaredCommonType(HashSet<String>),
48 DuplicateEntityType(String),
51 DuplicateAction(String),
54 DuplicateCommonType(String),
56 CycleInActionHierarchy,
58 EntityTypeParseError(Vec<ParseError>),
60 NamespaceParseError(Vec<ParseError>),
62 ExtensionTypeParseError(Vec<ParseError>),
64 CommonTypeParseError(Vec<ParseError>),
67 ActionEntityTypeDeclared,
72 ActionEntityAttributes(Vec<String>),
75 ContextOrShapeNotRecord,
76 ActionEntityAttributeEmptySet,
78 ActionEntityAttributeUnsupportedType,
80}
81
82impl std::error::Error for SchemaError {}
83
84impl From<transitive_closure::Err<EntityUID>> for SchemaError {
85 fn from(e: transitive_closure::Err<EntityUID>) -> Self {
86 match e {
90 transitive_closure::Err::TCEnforcementError { .. } => {
91 SchemaError::ActionTransitiveClosureError(Box::new(e))
92 }
93 transitive_closure::Err::HasCycle { .. } => SchemaError::CycleInActionHierarchy,
94 }
95 }
96}
97
98impl From<serde_json::Error> for SchemaError {
99 fn from(e: serde_json::Error) -> Self {
100 SchemaError::ParseFileFormat(e)
101 }
102}
103
104impl From<transitive_closure::Err<Name>> for SchemaError {
105 fn from(e: transitive_closure::Err<Name>) -> Self {
106 SchemaError::EntityTransitiveClosureError(e)
107 }
108}
109
110pub type Result<T> = std::result::Result<T, SchemaError>;
111
112impl SchemaError {
113 fn format_parse_errs(errs: &[ParseError]) -> String {
114 errs.iter()
115 .map(|e| e.to_string())
116 .collect::<Vec<_>>()
117 .join(", ")
118 }
119}
120
121impl std::fmt::Display for SchemaError {
122 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123 match self {
124 SchemaError::ParseFileFormat(e) => {
125 write!(f, "JSON Schema file could not be parsed: {e}")
126 }
127 SchemaError::ActionTransitiveClosureError(e) => {
128 write!(f, "Transitive closure error on action hierarchy: {}", e)
129 }
130 SchemaError::EntityTransitiveClosureError(e) => {
131 write!(f, "Transitive closure error on entity hierarchy: {}", e)
132 }
133 SchemaError::UnsupportedSchemaFeature(feat) => {
134 write!(f, "Unsupported feature used in schema: {feat}")
135 }
136 SchemaError::UndeclaredEntityTypes(e) => {
137 write!(f, "Undeclared entity types: {:?}", e)
138 }
139 SchemaError::UndeclaredActions(a) => {
140 write!(f, "Undeclared actions {:?}", a)
141 }
142 SchemaError::UndeclaredCommonType(t) => {
143 write!(f, "Undeclared common types {:?}", t)
144 }
145 SchemaError::DuplicateEntityType(e) => {
146 write!(f, "Duplicate entity type {e}")
147 }
148 SchemaError::DuplicateAction(a) => {
149 write!(f, "Duplicate action {}", a)
150 }
151 SchemaError::DuplicateCommonType(t) => {
152 write!(f, "Duplicate common type {t}")
153 }
154 SchemaError::CycleInActionHierarchy => {
155 write!(f, "Cycle in action hierarchy")
156 }
157 SchemaError::EntityTypeParseError(parse_errs) => {
158 write!(
159 f,
160 "Parse error in entity type: {}",
161 Self::format_parse_errs(parse_errs),
162 )
163 }
164 SchemaError::NamespaceParseError(parse_errs) => {
165 write!(
166 f,
167 "Parse error in namespace identifier: {}",
168 Self::format_parse_errs(parse_errs),
169 )
170 }
171 SchemaError::CommonTypeParseError(parse_errs) => {
172 write!(
173 f,
174 "Parse error in common type identifier: {}",
175 Self::format_parse_errs(parse_errs),
176 )
177 }
178 SchemaError::ExtensionTypeParseError(parse_errs) => {
179 write!(
180 f,
181 "Parse error in extension type: {}",
182 Self::format_parse_errs(parse_errs),
183 )
184 }
185 SchemaError::ActionEntityTypeDeclared => {
186 write!(f, "Entity type `Action` declared in `entityTypes` list.")
187 }
188 SchemaError::ActionEntityAttributes(actions) => {
189 write!(
190 f,
191 "Actions declared with `attributes`: [{}]",
192 actions.iter().join(", ")
193 )
194 }
195 SchemaError::ContextOrShapeNotRecord => {
196 write!(
197 f,
198 "An entity shape or action context is declared with a type other than `Record`"
199 )
200 }
201 SchemaError::ActionEntityAttributeEmptySet => {
202 write!(f, "An action entity has an attribute that is an empty set")
203 }
204 SchemaError::ActionEntityAttributeUnsupportedType => {
205 write!(
206 f,
207 "An action entity has attribute with unsupported type: (escaped expression, entity or extension)"
208 )
209 }
210 }
211 }
212}
213
214#[derive(Debug)]
215pub enum UnsupportedFeature {
216 OpenRecordsAndEntities,
217}
218
219impl std::fmt::Display for UnsupportedFeature {
220 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
221 match self {
222 UnsupportedFeature::OpenRecordsAndEntities => write!(
223 f,
224 "Records and entities with additional attributes are not yet implemented."
225 ),
226 }
227 }
228}