14
14
* limitations under the License.
15
15
*/
16
16
17
+ use std:: collections:: BTreeMap ;
18
+
17
19
use miette:: { miette, Result , WrapErr } ;
18
20
19
- use cedar_policy_core:: ast:: { PolicySet , Template } ;
21
+ use cedar_policy_core:: ast:: PolicySet ;
20
22
use cedar_policy_core:: parser:: parse_policyset;
21
23
use cedar_policy_core:: parser:: { err:: ParseErrors , text_to_cst:: parse_policies} ;
24
+ use smol_str:: ToSmolStr ;
22
25
23
26
use crate :: token:: get_comment;
24
27
@@ -40,24 +43,42 @@ fn tree_to_pretty<T: Doc>(t: &T, context: &mut config::Context<'_>) -> Result<St
40
43
}
41
44
42
45
fn soundness_check ( ps : & str , ast : & PolicySet ) -> Result < ( ) > {
43
- let formatted_ast = parse_policyset ( ps) . wrap_err ( "formatter produces invalid policies" ) ?;
46
+ let formatted_ast =
47
+ parse_policyset ( ps) . wrap_err ( format ! ( "formatter produced an invalid policy set:\n {ps}" ) ) ?;
44
48
let ( formatted_policies, policies) = (
45
- formatted_ast. templates ( ) . collect :: < Vec < & Template > > ( ) ,
46
- ast. templates ( ) . collect :: < Vec < & Template > > ( ) ,
49
+ formatted_ast
50
+ . policies ( )
51
+ . map ( |p| ( p. id ( ) . to_smolstr ( ) , p) )
52
+ . collect :: < BTreeMap < _ , _ > > ( ) ,
53
+ ast. policies ( )
54
+ . map ( |p| ( p. id ( ) . to_smolstr ( ) , p) )
55
+ . collect :: < BTreeMap < _ , _ > > ( ) ,
47
56
) ;
48
57
49
58
if formatted_policies. len ( ) != policies. len ( ) {
50
- return Err ( miette ! ( "missing formatted policies" ) ) ;
59
+ return Err ( miette ! (
60
+ "formatter changed the number of policies from {} to {}" ,
61
+ policies. len( ) ,
62
+ formatted_policies. len( )
63
+ ) ) ;
51
64
}
52
-
53
- for ( f_p, p) in formatted_policies. into_iter ( ) . zip ( policies. into_iter ( ) ) {
65
+ for ( ( f_p_id, f_p) , ( p_id, p) ) in formatted_policies. into_iter ( ) . zip ( policies. into_iter ( ) ) {
66
+ if f_p_id != p_id {
67
+ return Err ( miette ! (
68
+ "formatter changed the policy id from {p_id} to {f_p_id}"
69
+ ) ) ;
70
+ }
54
71
let ( f_anno, anno) = (
55
72
f_p. annotations ( )
56
73
. collect :: < std:: collections:: HashMap < _ , _ > > ( ) ,
57
74
p. annotations ( ) . collect :: < std:: collections:: HashMap < _ , _ > > ( ) ,
58
75
) ;
59
- if !( f_anno == anno
60
- && f_p. effect ( ) == p. effect ( )
76
+ if f_anno != anno {
77
+ return Err ( miette ! (
78
+ "formatter changed the annotations from {anno:?} to {f_anno:?}"
79
+ ) ) ;
80
+ }
81
+ if !( f_p. effect ( ) == p. effect ( )
61
82
&& f_p. principal_constraint ( ) == p. principal_constraint ( )
62
83
&& f_p. action_constraint ( ) == p. action_constraint ( )
63
84
&& f_p. resource_constraint ( ) == p. resource_constraint ( )
@@ -66,9 +87,7 @@ fn soundness_check(ps: &str, ast: &PolicySet) -> Result<()> {
66
87
. eq_shape ( p. non_head_constraints ( ) ) )
67
88
{
68
89
return Err ( miette ! (
69
- "policies differ:\n formatted: {}\n input: {}" ,
70
- f_p,
71
- p
90
+ "formatter changed the policy structure:\n original:\n {p}\n formatted:\n {f_p}"
72
91
) ) ;
73
92
}
74
93
}
@@ -123,7 +142,9 @@ pub fn policies_str_to_pretty(ps: &str, config: &Config) -> Result<String> {
123
142
}
124
143
} ;
125
144
// add soundness check to make sure formatting doesn't alter policy ASTs
126
- soundness_check ( & formatted_policies, & ast) ?;
145
+ soundness_check ( & formatted_policies, & ast) . wrap_err (
146
+ "internal error: please file an issue at <https://github.com/cedar-policy/cedar/issues>" ,
147
+ ) ?;
127
148
Ok ( formatted_policies)
128
149
}
129
150
@@ -166,6 +187,49 @@ mod tests {
166
187
) ;
167
188
}
168
189
190
+ #[ test]
191
+ fn test_soundness_check ( ) {
192
+ let p1 = r#"permit (principal, action, resource)
193
+ when { "
194
+
195
+ a
196
+ " };"# ;
197
+ let p2 = r#"permit (principal, action, resource)
198
+ when { "
199
+ a
200
+ " };"# ;
201
+ assert ! ( soundness_check( p2, & parse_policyset( p1) . unwrap( ) ) . is_err( ) ) ;
202
+
203
+ let p1 = r#"
204
+ permit (principal, action, resource)
205
+ when { "a"};
206
+ permit (principal, action, resource)
207
+ when { "
208
+
209
+ a
210
+ " };"# ;
211
+ let p2 = r#"
212
+ permit (principal, action, resource)
213
+ when { "
214
+ a
215
+ " };
216
+ permit (principal, action, resource)
217
+ when { "a"};"# ;
218
+ assert ! ( soundness_check( p2, & parse_policyset( p1) . unwrap( ) ) . is_err( ) ) ;
219
+
220
+ let p1 = r#"
221
+ permit (principal, action, resource)
222
+ when { "a" };
223
+ permit (principal, action, resource)
224
+ when { "b" };"# ;
225
+ let p2 = r#"
226
+ permit (principal, action, resource)
227
+ when { "a" };
228
+ permit (principal, action, resource)
229
+ when { "b"};"# ;
230
+ assert ! ( soundness_check( p2, & parse_policyset( p1) . unwrap( ) ) . is_ok( ) ) ;
231
+ }
232
+
169
233
#[ test]
170
234
fn test_format_files ( ) {
171
235
use std:: fs:: read_to_string;
0 commit comments