cedar_policy_validator/
err.rs1use std::collections::HashSet;
18
19use cedar_policy_core::{
20 ast::{EntityAttrEvaluationError, EntityUID, Name},
21 transitive_closure,
22};
23use itertools::Itertools;
24use miette::Diagnostic;
25use thiserror::Error;
26
27use crate::human_schema::parser::HumanSyntaxParseErrors;
28
29#[derive(Debug, Error, Diagnostic)]
30pub enum HumanSchemaError {
31 #[error("{0}")]
32 #[diagnostic(transparent)]
33 Core(#[from] SchemaError),
34 #[error("{0}")]
35 IO(#[from] std::io::Error),
36 #[error("{0}")]
37 #[diagnostic(transparent)]
38 Parsing(#[from] HumanSyntaxParseErrors),
39}
40
41#[derive(Debug, Diagnostic, Error)]
42pub enum SchemaError {
43 #[error("failed to parse schema: {0}")]
45 Serde(#[from] serde_json::Error),
46 #[error("transitive closure computation/enforcement error on action hierarchy: {0}")]
49 #[diagnostic(transparent)]
50 ActionTransitiveClosure(Box<transitive_closure::TcError<EntityUID>>),
51 #[error("transitive closure computation/enforcement error on entity type hierarchy: {0}")]
54 #[diagnostic(transparent)]
55 EntityTypeTransitiveClosure(#[from] transitive_closure::TcError<Name>),
56 #[error("unsupported feature used in schema: {0}")]
58 #[diagnostic(transparent)]
59 UnsupportedFeature(UnsupportedFeature),
60 #[error("undeclared entity type(s): {0:?}")]
65 #[diagnostic(help(
66 "any entity types appearing anywhere in a schema need to be declared in `entityTypes`"
67 ))]
68 UndeclaredEntityTypes(HashSet<String>),
69 #[error("undeclared action(s): {0:?}")]
71 #[diagnostic(help("any actions appearing in `memberOf` need to be declared in `actions`"))]
72 UndeclaredActions(HashSet<String>),
73 #[error("undeclared common type(s), or common type(s) used in the declaration of another common type: {0:?}")]
77 #[diagnostic(help("any common types used in entity or context attributes need to be declared in `commonTypes`, and currently, common types may not reference other common types"))]
78 UndeclaredCommonTypes(HashSet<String>),
79 #[error("duplicate entity type `{0}`")]
82 DuplicateEntityType(String),
83 #[error("duplicate action `{0}`")]
86 DuplicateAction(String),
87 #[error("duplicate common type `{0}`")]
89 DuplicateCommonType(String),
90 #[error("cycle in action hierarchy containing `{0}`")]
92 CycleInActionHierarchy(EntityUID),
93 #[error("cycle in common type references containing `{0}`")]
95 CycleInCommonTypeReferences(Name),
96 #[error("entity type `Action` declared in `entityTypes` list")]
101 ActionEntityTypeDeclared,
102 #[error("{0} is declared with a type other than `Record`")]
104 #[diagnostic(help("{}", match .0 {
105 ContextOrShape::ActionContext(_) => "action contexts must have type `Record`",
106 ContextOrShape::EntityTypeShape(_) => "entity type shapes must have type `Record`",
107 }))]
108 ContextOrShapeNotRecord(ContextOrShape),
109 #[error("action `{0}` has an attribute that is an empty set")]
113 #[diagnostic(help(
114 "actions are not currently allowed to have attributes whose value is an empty set"
115 ))]
116 ActionAttributesContainEmptySet(EntityUID),
117 #[error("action `{0}` has an attribute with unsupported JSON representation: {1}")]
120 UnsupportedActionAttribute(EntityUID, String),
121 #[error(transparent)]
123 #[diagnostic(transparent)]
124 ActionAttrEval(EntityAttrEvaluationError),
125 #[error("the `__expr` escape is no longer supported")]
128 #[diagnostic(help("to create an entity reference, use `__entity`; to create an extension value, use `__extn`; and for all other values, use JSON directly"))]
129 ExprEscapeUsed,
130}
131
132impl From<transitive_closure::TcError<EntityUID>> for SchemaError {
133 fn from(e: transitive_closure::TcError<EntityUID>) -> Self {
134 match e {
138 transitive_closure::TcError::MissingTcEdge { .. } => {
139 SchemaError::ActionTransitiveClosure(Box::new(e))
140 }
141 transitive_closure::TcError::HasCycle { vertex_with_loop } => {
142 SchemaError::CycleInActionHierarchy(vertex_with_loop)
143 }
144 }
145 }
146}
147
148pub type Result<T> = std::result::Result<T, SchemaError>;
149
150#[derive(Debug)]
151pub enum ContextOrShape {
152 ActionContext(EntityUID),
153 EntityTypeShape(Name),
154}
155
156impl std::fmt::Display for ContextOrShape {
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 match self {
159 ContextOrShape::ActionContext(action) => write!(f, "Context for action {}", action),
160 ContextOrShape::EntityTypeShape(entity_type) => {
161 write!(f, "Shape for entity type {}", entity_type)
162 }
163 }
164 }
165}
166
167#[derive(Debug, Diagnostic, Error)]
168pub enum UnsupportedFeature {
169 #[error("records and entities with `additionalAttributes` are experimental, but the experimental `partial-validate` feature is not enabled")]
170 OpenRecordsAndEntities,
171 #[error("action declared with attributes: [{}]", .0.iter().join(", "))]
173 ActionAttributes(Vec<String>),
174}