cedar_policy_validator/
validation_result.rs1use cedar_policy_core::{ast::PolicyID, parser::SourceInfo};
18use thiserror::Error;
19
20use crate::TypeErrorKind;
21
22#[derive(Debug)]
27pub struct ValidationResult<'a> {
28 validation_errors: Vec<ValidationError<'a>>,
29}
30
31impl<'a> ValidationResult<'a> {
32 pub(crate) fn new(validation_errors: impl Iterator<Item = ValidationError<'a>>) -> Self {
33 Self {
34 validation_errors: validation_errors.collect::<Vec<_>>(),
35 }
36 }
37
38 pub fn validation_passed(&self) -> bool {
40 self.validation_errors.is_empty()
41 }
42
43 pub fn validation_errors(&self) -> impl Iterator<Item = &ValidationError> {
45 self.validation_errors.iter()
46 }
47
48 pub fn into_validation_errors(self) -> impl Iterator<Item = ValidationError<'a>> {
50 self.validation_errors.into_iter()
51 }
52}
53
54#[derive(Debug)]
59#[cfg_attr(test, derive(Eq, PartialEq))]
60pub struct ValidationError<'a> {
61 location: SourceLocation<'a>,
62 error_kind: ValidationErrorKind,
63}
64
65impl<'a> ValidationError<'a> {
66 pub(crate) fn with_policy_id(
67 id: &'a PolicyID,
68 source_info: Option<SourceInfo>,
69 error_kind: ValidationErrorKind,
70 ) -> Self {
71 Self {
72 error_kind,
73 location: SourceLocation::new(id, source_info),
74 }
75 }
76
77 pub fn into_location_and_error_kind(self) -> (SourceLocation<'a>, ValidationErrorKind) {
79 (self.location, self.error_kind)
80 }
81
82 pub fn error_kind(&self) -> &ValidationErrorKind {
84 &self.error_kind
85 }
86
87 pub fn location(&self) -> &SourceLocation {
89 &self.location
90 }
91}
92
93#[derive(Debug, Eq, PartialEq)]
95pub struct SourceLocation<'a> {
96 policy_id: &'a PolicyID,
97 source_info: Option<SourceInfo>,
98}
99
100impl<'a> SourceLocation<'a> {
101 fn new(policy_id: &'a PolicyID, source_info: Option<SourceInfo>) -> Self {
102 Self {
103 policy_id,
104 source_info,
105 }
106 }
107
108 pub fn policy_id(&self) -> &'a PolicyID {
110 self.policy_id
111 }
112
113 pub fn source_info(&self) -> &Option<SourceInfo> {
114 &self.source_info
115 }
116
117 pub fn into_source_info(self) -> Option<SourceInfo> {
118 self.source_info
119 }
120}
121
122#[derive(Debug, Error)]
125#[cfg_attr(test, derive(Eq, PartialEq))]
126#[non_exhaustive]
127pub enum ValidationErrorKind {
128 #[error(
130 "Unrecognized entity type {}{}",
131 .0.actual_entity_type,
132 match &.0.suggested_entity_type {
133 Some(s) => format!(", did you mean {}?", s),
134 None => "".to_string()
135 }
136 )]
137 UnrecognizedEntityType(UnrecognizedEntityType),
138 #[error(
140 "Unrecognized action id {}{}",
141 .0.actual_action_id,
142 match &.0.suggested_action_id {
143 Some(s) => format!(", did you mean {}?", s),
144 None => "".to_string()
145 }
146 )]
147 UnrecognizedActionId(UnrecognizedActionId),
148 #[error(
152 "Unable to find an applicable action given the policy head constraints{}{}",
153 if .0.would_in_fix_principal { ". Note: Try replacing `==` with `in` in the principal clause" } else { "" },
154 if .0.would_in_fix_resource { ". Note: Try replacing `==` with `in` in the resource clause" } else { "" }
155 )]
156 InvalidActionApplication(InvalidActionApplication),
157 #[error(transparent)]
159 TypeError(TypeErrorKind),
160 #[error(
163 "Unspecified entity with eid {}. Unspecified entities cannot be used in policies",
164 .0.entity_id,
165 )]
166 UnspecifiedEntity(UnspecifiedEntity),
167}
168
169impl ValidationErrorKind {
170 pub(crate) fn unrecognized_entity_type(
171 actual_entity_type: String,
172 suggested_entity_type: Option<String>,
173 ) -> ValidationErrorKind {
174 Self::UnrecognizedEntityType(UnrecognizedEntityType {
175 actual_entity_type,
176 suggested_entity_type,
177 })
178 }
179
180 pub(crate) fn unrecognized_action_id(
181 actual_action_id: String,
182 suggested_action_id: Option<String>,
183 ) -> ValidationErrorKind {
184 Self::UnrecognizedActionId(UnrecognizedActionId {
185 actual_action_id,
186 suggested_action_id,
187 })
188 }
189
190 pub(crate) fn invalid_action_application(
191 would_in_fix_principal: bool,
192 would_in_fix_resource: bool,
193 ) -> ValidationErrorKind {
194 Self::InvalidActionApplication(InvalidActionApplication {
195 would_in_fix_principal,
196 would_in_fix_resource,
197 })
198 }
199
200 pub(crate) fn type_error(type_error: TypeErrorKind) -> ValidationErrorKind {
201 Self::TypeError(type_error)
202 }
203
204 pub(crate) fn unspecified_entity(entity_id: String) -> ValidationErrorKind {
205 Self::UnspecifiedEntity(UnspecifiedEntity { entity_id })
206 }
207}
208
209#[derive(Debug)]
211#[cfg_attr(test, derive(Eq, PartialEq))]
212pub struct UnrecognizedEntityType {
213 pub(crate) actual_entity_type: String,
215 pub(crate) suggested_entity_type: Option<String>,
218}
219
220#[derive(Debug)]
222#[cfg_attr(test, derive(Eq, PartialEq))]
223pub struct UnrecognizedActionId {
224 pub(crate) actual_action_id: String,
226 pub(crate) suggested_action_id: Option<String>,
229}
230
231#[derive(Debug)]
233#[cfg_attr(test, derive(Eq, PartialEq))]
234pub struct InvalidActionApplication {
235 pub(crate) would_in_fix_principal: bool,
236 pub(crate) would_in_fix_resource: bool,
237}
238
239#[derive(Debug)]
241#[cfg_attr(test, derive(Eq, PartialEq))]
242pub struct UnspecifiedEntity {
243 pub(crate) entity_id: String,
245}