cedar_policy_validator/
err.rs1use std::collections::HashSet;
18
19use cedar_policy_core::{
20 ast::{EntityUID, Name},
21 parser::err::{ParseError, ParseErrors},
22 transitive_closure,
23};
24use itertools::Itertools;
25use thiserror::Error;
26
27#[derive(Debug, Error)]
28pub enum SchemaError {
29 #[error("failed to parse schema: {0}")]
31 Serde(#[from] serde_json::Error),
32 #[error("transitive closure computation/enforcement error on action hierarchy: {0}")]
35 ActionTransitiveClosure(Box<transitive_closure::TcError<EntityUID>>),
36 #[error("transitive closure computation/enforcement error on entity type hierarchy: {0}")]
39 EntityTypeTransitiveClosure(#[from] transitive_closure::TcError<Name>),
40 #[error("unsupported feature used in schema: {0}")]
42 UnsupportedFeature(UnsupportedFeature),
43 #[error("undeclared entity type(s): {0:?}")]
48 UndeclaredEntityTypes(HashSet<String>),
49 #[error("undeclared action(s): {0:?}")]
51 UndeclaredActions(HashSet<String>),
52 #[error("undeclared common type(s): {0:?}")]
54 UndeclaredCommonTypes(HashSet<String>),
55 #[error("duplicate entity type: {0}")]
58 DuplicateEntityType(String),
59 #[error("duplicate action: {0}")]
62 DuplicateAction(String),
63 #[error("duplicate common type: {0}")]
65 DuplicateCommonType(String),
66 #[error("cycle in action hierarchy")]
68 CycleInActionHierarchy,
69 #[error("parse error in entity type: {}", Self::format_parse_errs(.0))]
71 EntityTypeParseError(ParseErrors),
72 #[error("parse error in namespace identifier: {}", Self::format_parse_errs(.0))]
74 NamespaceParseError(ParseErrors),
75 #[error("parse error in extension type: {}", Self::format_parse_errs(.0))]
77 ExtensionTypeParseError(ParseErrors),
78 #[error("parse error in common type identifier: {}", Self::format_parse_errs(.0))]
81 CommonTypeParseError(ParseErrors),
82 #[error("entity type `Action` declared in `entityTypes` list")]
87 ActionEntityTypeDeclared,
88 #[error("action declared with `attribute`: [{}]", .0.iter().join(", "))]
91 ActionHasAttributes(Vec<String>),
92 #[error("{0} is declared with a type other than `Record`")]
94 ContextOrShapeNotRecord(ContextOrShape),
95 #[error("action `{0}` has an attribute that is an empty set")]
98 ActionAttributesContainEmptySet(EntityUID),
99 #[error(
102 "action `{0}` has an attribute with unsupported type: (escaped expression, entity or extension)"
103 )]
104 UnsupportedActionAttributeType(EntityUID),
105}
106
107impl From<transitive_closure::TcError<EntityUID>> for SchemaError {
108 fn from(e: transitive_closure::TcError<EntityUID>) -> Self {
109 match e {
113 transitive_closure::TcError::MissingTcEdge { .. } => {
114 SchemaError::ActionTransitiveClosure(Box::new(e))
115 }
116 transitive_closure::TcError::HasCycle { .. } => SchemaError::CycleInActionHierarchy,
117 }
118 }
119}
120
121pub type Result<T> = std::result::Result<T, SchemaError>;
122
123impl SchemaError {
124 fn format_parse_errs(errs: &[ParseError]) -> String {
125 errs.iter().map(|e| e.to_string()).join(", ")
126 }
127}
128
129#[derive(Debug)]
130pub enum ContextOrShape {
131 ActionContext(EntityUID),
132 EntityTypeShape(Name),
133}
134
135impl std::fmt::Display for ContextOrShape {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 match self {
138 ContextOrShape::ActionContext(action) => write!(f, "Context for action {}", action),
139 ContextOrShape::EntityTypeShape(entity_type) => {
140 write!(f, "Shape for entity type {}", entity_type)
141 }
142 }
143 }
144}
145
146#[derive(Debug)]
147pub enum UnsupportedFeature {
148 OpenRecordsAndEntities,
149}
150
151impl std::fmt::Display for UnsupportedFeature {
152 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153 match self {
154 UnsupportedFeature::OpenRecordsAndEntities => write!(
155 f,
156 "Records and entities with additional attributes are not yet implemented."
157 ),
158 }
159 }
160}