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,17 +43,31 @@ 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
. map ( |( k, v) | ( k, & v. val ) )
@@ -59,8 +76,12 @@ fn soundness_check(ps: &str, ast: &PolicySet) -> Result<()> {
59
76
. map ( |( k, v) | ( k, & v. val ) )
60
77
. collect :: < std:: collections:: BTreeMap < _ , _ > > ( ) ,
61
78
) ;
62
- if !( f_anno == anno
63
- && f_p. effect ( ) == p. effect ( )
79
+ if f_anno != anno {
80
+ return Err ( miette ! (
81
+ "formatter changed the annotations from {anno:?} to {f_anno:?}"
82
+ ) ) ;
83
+ }
84
+ if !( f_p. effect ( ) == p. effect ( )
64
85
&& f_p. principal_constraint ( ) == p. principal_constraint ( )
65
86
&& f_p. action_constraint ( ) == p. action_constraint ( )
66
87
&& f_p. resource_constraint ( ) == p. resource_constraint ( )
@@ -69,7 +90,7 @@ fn soundness_check(ps: &str, ast: &PolicySet) -> Result<()> {
69
90
. eq_shape ( p. non_head_constraints ( ) ) )
70
91
{
71
92
return Err ( miette ! (
72
- "policies differ in meaning or annotations :\n original: {p}\n formatted: {f_p}"
93
+ "formatter changed the policy structure :\n original:\n {p}\n formatted:\n {f_p}"
73
94
) ) ;
74
95
}
75
96
}
@@ -124,7 +145,9 @@ pub fn policies_str_to_pretty(ps: &str, config: &Config) -> Result<String> {
124
145
}
125
146
} ;
126
147
// add soundness check to make sure formatting doesn't alter policy ASTs
127
- soundness_check ( & formatted_policies, & ast) ?;
148
+ soundness_check ( & formatted_policies, & ast) . wrap_err (
149
+ "internal error: please file an issue at <https://github.com/cedar-policy/cedar/issues>" ,
150
+ ) ?;
128
151
Ok ( formatted_policies)
129
152
}
130
153
@@ -167,6 +190,49 @@ mod tests {
167
190
) ;
168
191
}
169
192
193
+ #[ test]
194
+ fn test_soundness_check ( ) {
195
+ let p1 = r#"permit (principal, action, resource)
196
+ when { "
197
+
198
+ a
199
+ " };"# ;
200
+ let p2 = r#"permit (principal, action, resource)
201
+ when { "
202
+ a
203
+ " };"# ;
204
+ assert ! ( soundness_check( p2, & parse_policyset( p1) . unwrap( ) ) . is_err( ) ) ;
205
+
206
+ let p1 = r#"
207
+ permit (principal, action, resource)
208
+ when { "a"};
209
+ permit (principal, action, resource)
210
+ when { "
211
+
212
+ a
213
+ " };"# ;
214
+ let p2 = r#"
215
+ permit (principal, action, resource)
216
+ when { "
217
+ a
218
+ " };
219
+ permit (principal, action, resource)
220
+ when { "a"};"# ;
221
+ assert ! ( soundness_check( p2, & parse_policyset( p1) . unwrap( ) ) . is_err( ) ) ;
222
+
223
+ let p1 = r#"
224
+ permit (principal, action, resource)
225
+ when { "a" };
226
+ permit (principal, action, resource)
227
+ when { "b" };"# ;
228
+ let p2 = r#"
229
+ permit (principal, action, resource)
230
+ when { "a" };
231
+ permit (principal, action, resource)
232
+ when { "b"};"# ;
233
+ assert ! ( soundness_check( p2, & parse_policyset( p1) . unwrap( ) ) . is_ok( ) ) ;
234
+ }
235
+
170
236
#[ test]
171
237
fn test_format_files ( ) {
172
238
use std:: fs:: read_to_string;
0 commit comments