@@ -561,7 +561,7 @@ impl ASTNode<Option<cst::VariableDef>> {
561
561
}
562
562
( cst:: RelOp :: In , None ) => Some ( PrincipalOrResourceConstraint :: In ( eref) ) ,
563
563
( cst:: RelOp :: In , Some ( entity_type) ) => Some ( PrincipalOrResourceConstraint :: IsIn (
564
- entity_type. to_name ( errs) ?,
564
+ entity_type. to_expr_or_special ( errs ) ? . into_name ( errs) ?,
565
565
eref,
566
566
) ) ,
567
567
( op, _) => {
@@ -571,7 +571,7 @@ impl ASTNode<Option<cst::VariableDef>> {
571
571
}
572
572
} else if let Some ( entity_type) = & vardef. entity_type {
573
573
Some ( PrincipalOrResourceConstraint :: Is (
574
- entity_type. to_name ( errs) ?,
574
+ entity_type. to_expr_or_special ( errs ) ? . into_name ( errs) ?,
575
575
) )
576
576
} else {
577
577
Some ( PrincipalOrResourceConstraint :: Any )
@@ -890,6 +890,24 @@ impl ExprOrSpecial<'_> {
890
890
}
891
891
}
892
892
}
893
+
894
+ fn into_name ( self , errs : & mut ParseErrors ) -> Option < ast:: Name > {
895
+ match self {
896
+ Self :: StrLit ( s, _) => {
897
+ errs. push ( self . to_ast_err ( ToASTErrorKind :: IsInvalidName ( s. to_string ( ) ) ) ) ;
898
+ None
899
+ }
900
+ Self :: Var ( var, _) => {
901
+ errs. push ( self . to_ast_err ( ToASTErrorKind :: IsInvalidName ( var. to_string ( ) ) ) ) ;
902
+ None
903
+ }
904
+ Self :: Name ( name, _) => Some ( name) ,
905
+ Self :: Expr ( ref e, _) => {
906
+ errs. push ( self . to_ast_err ( ToASTErrorKind :: IsInvalidName ( e. to_string ( ) ) ) ) ;
907
+ None
908
+ }
909
+ }
910
+ }
893
911
}
894
912
895
913
impl ASTNode < Option < cst:: Expr > > {
@@ -1252,7 +1270,10 @@ impl ASTNode<Option<cst::Relation>> {
1252
1270
target,
1253
1271
entity_type,
1254
1272
in_entity,
1255
- } => match ( target. to_expr ( errs) , entity_type. to_name ( errs) ) {
1273
+ } => match (
1274
+ target. to_expr ( errs) ,
1275
+ entity_type. to_expr_or_special ( errs) ?. into_name ( errs) ,
1276
+ ) {
1256
1277
( Some ( t) , Some ( n) ) => match in_entity {
1257
1278
Some ( in_entity) => in_entity. to_expr ( errs) . map ( |in_entity| {
1258
1279
ExprOrSpecial :: Expr (
@@ -3878,6 +3899,26 @@ mod tests {
3878
3899
) ,
3879
3900
) ,
3880
3901
) ,
3902
+ (
3903
+ r#"principal is User && principal in Group::"friends""# ,
3904
+ Expr :: and (
3905
+ Expr :: is_entity_type ( Expr :: var ( ast:: Var :: Principal ) , "User" . parse ( ) . unwrap ( ) ) ,
3906
+ Expr :: is_in (
3907
+ Expr :: var ( ast:: Var :: Principal ) ,
3908
+ Expr :: val ( r#"Group::"friends""# . parse :: < EntityUID > ( ) . unwrap ( ) ) ,
3909
+ ) ,
3910
+ ) ,
3911
+ ) ,
3912
+ (
3913
+ r#"principal is User || principal in Group::"friends""# ,
3914
+ Expr :: or (
3915
+ Expr :: is_entity_type ( Expr :: var ( ast:: Var :: Principal ) , "User" . parse ( ) . unwrap ( ) ) ,
3916
+ Expr :: is_in (
3917
+ Expr :: var ( ast:: Var :: Principal ) ,
3918
+ Expr :: val ( r#"Group::"friends""# . parse :: < EntityUID > ( ) . unwrap ( ) ) ,
3919
+ ) ,
3920
+ ) ,
3921
+ ) ,
3881
3922
(
3882
3923
r#"true && principal is User in principal"# ,
3883
3924
Expr :: and (
@@ -3930,6 +3971,31 @@ mod tests {
3930
3971
) ,
3931
3972
) ,
3932
3973
) ,
3974
+ (
3975
+ r#"if principal is User then 1 else 2"# ,
3976
+ Expr :: ite (
3977
+ Expr :: is_entity_type ( Expr :: var ( ast:: Var :: Principal ) , "User" . parse ( ) . unwrap ( ) ) ,
3978
+ Expr :: val ( 1 ) ,
3979
+ Expr :: val ( 2 ) ,
3980
+ ) ,
3981
+ ) ,
3982
+ (
3983
+ r#"if principal is User in Group::"friends" then 1 else 2"# ,
3984
+ Expr :: ite (
3985
+ Expr :: and (
3986
+ Expr :: is_entity_type (
3987
+ Expr :: var ( ast:: Var :: Principal ) ,
3988
+ "User" . parse ( ) . unwrap ( ) ,
3989
+ ) ,
3990
+ Expr :: is_in (
3991
+ Expr :: var ( ast:: Var :: Principal ) ,
3992
+ Expr :: val ( r#"Group::"friends""# . parse :: < EntityUID > ( ) . unwrap ( ) ) ,
3993
+ ) ,
3994
+ ) ,
3995
+ Expr :: val ( 1 ) ,
3996
+ Expr :: val ( 2 ) ,
3997
+ ) ,
3998
+ ) ,
3933
3999
] {
3934
4000
let e = parse_expr ( es) . unwrap ( ) ;
3935
4001
assert ! (
@@ -4012,14 +4078,6 @@ mod tests {
4012
4078
#[ test]
4013
4079
fn is_err ( ) {
4014
4080
let invalid_is_policies = [
4015
- (
4016
- r#"permit(principal == ?resource, action, resource);"# ,
4017
- ExpectedErrorMessage :: error ( "expected an entity uid or matching template slot, found ?resource instead of ?principal" ) ,
4018
- ) ,
4019
- (
4020
- r#"permit(principal, action, resource == ?principal);"# ,
4021
- ExpectedErrorMessage :: error ( "expected an entity uid or matching template slot, found ?principal instead of ?resource" ) ,
4022
- ) ,
4023
4081
(
4024
4082
r#"permit(principal in Group::"friends" is User, action, resource);"# ,
4025
4083
ExpectedErrorMessage :: error ( "expected an entity uid or matching template slot, found an `is` expression" ) ,
@@ -4030,23 +4088,31 @@ mod tests {
4030
4088
) ,
4031
4089
(
4032
4090
r#"permit(principal is User == User::"Alice", action, resource);"# ,
4033
- ExpectedErrorMessage :: error (
4091
+ ExpectedErrorMessage :: error_and_help (
4034
4092
"`is` cannot appear in the scope at the same time as `==`" ,
4093
+ "try moving `is` into a `when` condition"
4035
4094
) ,
4036
4095
) ,
4037
4096
(
4038
4097
r#"permit(principal, action, resource is Doc == Doc::"a");"# ,
4039
- ExpectedErrorMessage :: error (
4098
+ ExpectedErrorMessage :: error_and_help (
4040
4099
"`is` cannot appear in the scope at the same time as `==`" ,
4100
+ "try moving `is` into a `when` condition"
4041
4101
) ,
4042
4102
) ,
4043
4103
(
4044
4104
r#"permit(principal is User::"alice", action, resource);"# ,
4045
- ExpectedErrorMessage :: error ( r#"unexpected token `"alice"`"# ) ,
4105
+ ExpectedErrorMessage :: error_and_help (
4106
+ r#"right hand side of an `is` expression must be an entity type name, but got `User::"alice"`"# ,
4107
+ "try using `==` to test for equality"
4108
+ ) ,
4046
4109
) ,
4047
4110
(
4048
4111
r#"permit(principal, action, resource is File::"f");"# ,
4049
- ExpectedErrorMessage :: error ( r#"unexpected token `"f"`"# ) ,
4112
+ ExpectedErrorMessage :: error_and_help (
4113
+ r#"right hand side of an `is` expression must be an entity type name, but got `File::"f"`"# ,
4114
+ "try using `==` to test for equality"
4115
+ ) ,
4050
4116
) ,
4051
4117
(
4052
4118
r#"permit(principal is User in 1, action, resource);"# ,
@@ -4066,27 +4132,88 @@ mod tests {
4066
4132
"expected an entity uid or matching template slot, found name `User`" ,
4067
4133
) ,
4068
4134
) ,
4135
+ (
4136
+ r#"permit(principal is User::"Alice" in Group::"f", action, resource);"# ,
4137
+ ExpectedErrorMessage :: error_and_help (
4138
+ r#"right hand side of an `is` expression must be an entity type name, but got `User::"Alice"`"# ,
4139
+ "try using `==` to test for equality"
4140
+ ) ,
4141
+ ) ,
4069
4142
(
4070
4143
r#"permit(principal, action, resource is File in File);"# ,
4071
4144
ExpectedErrorMessage :: error (
4072
4145
"expected an entity uid or matching template slot, found name `File`" ,
4073
4146
) ,
4074
4147
) ,
4148
+ (
4149
+ r#"permit(principal, action, resource is File::"file" in Folder::"folder");"# ,
4150
+ ExpectedErrorMessage :: error_and_help (
4151
+ r#"right hand side of an `is` expression must be an entity type name, but got `File::"file"`"# ,
4152
+ "try using `==` to test for equality"
4153
+ ) ,
4154
+ ) ,
4075
4155
(
4076
4156
r#"permit(principal is 1, action, resource);"# ,
4077
- ExpectedErrorMessage :: error ( "unexpected token `1`" ) ,
4157
+ ExpectedErrorMessage :: error_and_help (
4158
+ r#"right hand side of an `is` expression must be an entity type name, but got `1`"# ,
4159
+ "try using `==` to test for equality"
4160
+ ) ,
4078
4161
) ,
4079
4162
(
4080
4163
r#"permit(principal, action, resource is 1);"# ,
4081
- ExpectedErrorMessage :: error ( "unexpected token `1`" ) ,
4164
+ ExpectedErrorMessage :: error_and_help (
4165
+ r#"right hand side of an `is` expression must be an entity type name, but got `1`"# ,
4166
+ "try using `==` to test for equality"
4167
+ ) ,
4082
4168
) ,
4083
4169
(
4084
4170
r#"permit(principal, action is Action, resource);"# ,
4085
- ExpectedErrorMessage :: error ( "`is` cannot appear in the action scope" ) ,
4171
+ ExpectedErrorMessage :: error_and_help (
4172
+ "`is` cannot appear in the action scope" ,
4173
+ "try moving `action is ..` into a `when` condition"
4174
+ ) ,
4175
+ ) ,
4176
+ (
4177
+ r#"permit(principal, action is Action::"a", resource);"# ,
4178
+ ExpectedErrorMessage :: error_and_help (
4179
+ "`is` cannot appear in the action scope" ,
4180
+ "try moving `action is ..` into a `when` condition"
4181
+ ) ,
4086
4182
) ,
4087
4183
(
4088
4184
r#"permit(principal, action is Action in Action::"A", resource);"# ,
4089
- ExpectedErrorMessage :: error ( "`is` cannot appear in the action scope" ) ,
4185
+ ExpectedErrorMessage :: error_and_help (
4186
+ "`is` cannot appear in the action scope" ,
4187
+ "try moving `action is ..` into a `when` condition"
4188
+ ) ,
4189
+ ) ,
4190
+ (
4191
+ r#"permit(principal, action is Action in Action, resource);"# ,
4192
+ ExpectedErrorMessage :: error_and_help (
4193
+ "`is` cannot appear in the action scope" ,
4194
+ "try moving `action is ..` into a `when` condition"
4195
+ ) ,
4196
+ ) ,
4197
+ (
4198
+ r#"permit(principal, action is Action::"a" in Action::"b", resource);"# ,
4199
+ ExpectedErrorMessage :: error_and_help (
4200
+ "`is` cannot appear in the action scope" ,
4201
+ "try moving `action is ..` into a `when` condition"
4202
+ ) ,
4203
+ ) ,
4204
+ (
4205
+ r#"permit(principal, action is Action in ?action, resource);"# ,
4206
+ ExpectedErrorMessage :: error_and_help (
4207
+ "`is` cannot appear in the action scope" ,
4208
+ "try moving `action is ..` into a `when` condition"
4209
+ ) ,
4210
+ ) ,
4211
+ (
4212
+ r#"permit(principal, action is ?action, resource);"# ,
4213
+ ExpectedErrorMessage :: error_and_help (
4214
+ "`is` cannot appear in the action scope" ,
4215
+ "try moving `action is ..` into a `when` condition"
4216
+ ) ,
4090
4217
) ,
4091
4218
(
4092
4219
r#"permit(principal is User in ?resource, action, resource);"# ,
@@ -4096,9 +4223,59 @@ mod tests {
4096
4223
r#"permit(principal, action, resource is Folder in ?principal);"# ,
4097
4224
ExpectedErrorMessage :: error ( "expected an entity uid or matching template slot, found ?principal instead of ?resource" ) ,
4098
4225
) ,
4226
+ (
4227
+ r#"permit(principal is ?principal, action, resource);"# ,
4228
+ ExpectedErrorMessage :: error_and_help (
4229
+ "right hand side of an `is` expression must be an entity type name, but got `?principal`" ,
4230
+ "try using `==` to test for equality"
4231
+ ) ,
4232
+ ) ,
4233
+ (
4234
+ r#"permit(principal, action, resource is ?resource);"# ,
4235
+ ExpectedErrorMessage :: error_and_help (
4236
+ "right hand side of an `is` expression must be an entity type name, but got `?resource`" ,
4237
+ "try using `==` to test for equality"
4238
+ ) ,
4239
+ ) ,
4099
4240
(
4100
4241
r#"permit(principal, action, resource) when { principal is 1 };"# ,
4101
- ExpectedErrorMessage :: error ( "unexpected token `1`" ) ,
4242
+ ExpectedErrorMessage :: error_and_help (
4243
+ r#"right hand side of an `is` expression must be an entity type name, but got `1`"# ,
4244
+ "try using `==` to test for equality"
4245
+ ) ,
4246
+ ) ,
4247
+ (
4248
+ r#"permit(principal, action, resource) when { principal is User::"alice" in Group::"friends" };"# ,
4249
+ ExpectedErrorMessage :: error_and_help (
4250
+ r#"right hand side of an `is` expression must be an entity type name, but got `User::"alice"`"# ,
4251
+ "try using `==` to test for equality"
4252
+ ) ,
4253
+ ) ,
4254
+ (
4255
+ r#"permit(principal, action, resource) when { principal is ! User::"alice" in Group::"friends" };"# ,
4256
+ ExpectedErrorMessage :: error_and_help (
4257
+ r#"right hand side of an `is` expression must be an entity type name, but got `!User::"alice"`"# ,
4258
+ "try using `==` to test for equality"
4259
+ ) ,
4260
+ ) ,
4261
+ (
4262
+ r#"permit(principal, action, resource) when { principal is User::"alice" + User::"alice" in Group::"friends" };"# ,
4263
+ ExpectedErrorMessage :: error_and_help (
4264
+ r#"right hand side of an `is` expression must be an entity type name, but got `User::"alice" + User::"alice"`"# ,
4265
+ "try using `==` to test for equality"
4266
+ ) ,
4267
+ ) ,
4268
+ (
4269
+ r#"permit(principal, action, resource) when { principal is User in User::"alice" in Group::"friends" };"# ,
4270
+ ExpectedErrorMessage :: error (
4271
+ "unexpected token `in`"
4272
+ ) ,
4273
+ ) ,
4274
+ (
4275
+ r#"permit(principal, action, resource) when { principal is User == User::"alice" in Group::"friends" };"# ,
4276
+ ExpectedErrorMessage :: error (
4277
+ "unexpected token `==`"
4278
+ ) ,
4102
4279
) ,
4103
4280
] ;
4104
4281
for ( p_src, expected) in invalid_is_policies {
@@ -4199,6 +4376,14 @@ mod tests {
4199
4376
#[ test]
4200
4377
fn invalid_slot ( ) {
4201
4378
let invalid_policies = [
4379
+ (
4380
+ r#"permit(principal == ?resource, action, resource);"# ,
4381
+ ExpectedErrorMessage :: error ( "expected an entity uid or matching template slot, found ?resource instead of ?principal" ) ,
4382
+ ) ,
4383
+ (
4384
+ r#"permit(principal, action, resource == ?principal);"# ,
4385
+ ExpectedErrorMessage :: error ( "expected an entity uid or matching template slot, found ?principal instead of ?resource" ) ,
4386
+ ) ,
4202
4387
(
4203
4388
r#"permit(principal, action, resource) when { principal == ?foo};"# ,
4204
4389
ExpectedErrorMessage :: error_and_help (
0 commit comments