@@ -66,15 +66,24 @@ def _evaluate_condition(self, value, condition, field_exists: bool):
66
66
return must_exist == field_exists
67
67
elif anything_but := condition .get ("anything-but" ):
68
68
if isinstance (anything_but , dict ):
69
- if not_prefix := anything_but .get ("prefix" ):
70
- return not value .startswith (not_prefix )
71
- elif not_suffix := anything_but .get ("suffix" ):
72
- return not value .endswith (not_suffix )
73
- elif not_equal_ignore_case := anything_but .get ("equals-ignore-case" ):
74
- if isinstance (not_equal_ignore_case , str ):
75
- return not_equal_ignore_case .lower () != value .lower ()
76
- elif isinstance (not_equal_ignore_case , list ):
77
- return all (value .lower () != v .lower () for v in not_equal_ignore_case )
69
+ if not_condition := anything_but .get ("prefix" ):
70
+ predicate = self ._evaluate_prefix
71
+ elif not_condition := anything_but .get ("suffix" ):
72
+ predicate = self ._evaluate_suffix
73
+ elif not_condition := anything_but .get ("equals-ignore-case" ):
74
+ predicate = self ._evaluate_equal_ignore_case
75
+ elif not_condition := anything_but .get ("wildcard" ):
76
+ predicate = self ._evaluate_wildcard
77
+ else :
78
+ # this should not happen as we validate the EventPattern before
79
+ return False
80
+
81
+ if isinstance (not_condition , str ):
82
+ return not predicate (not_condition , value )
83
+ elif isinstance (not_condition , list ):
84
+ return all (
85
+ not predicate (sub_condition , value ) for sub_condition in not_condition
86
+ )
78
87
79
88
elif isinstance (anything_but , list ):
80
89
return value not in anything_but
@@ -87,19 +96,19 @@ def _evaluate_condition(self, value, condition, field_exists: bool):
87
96
elif prefix := condition .get ("prefix" ):
88
97
if isinstance (prefix , dict ):
89
98
if prefix_equal_ignore_case := prefix .get ("equals-ignore-case" ):
90
- return value . lower (). startswith ( prefix_equal_ignore_case .lower ())
91
-
92
- return value . startswith (prefix )
99
+ return self . _evaluate_prefix ( prefix_equal_ignore_case . lower (), value .lower ())
100
+ else :
101
+ return self . _evaluate_prefix (prefix , value )
93
102
94
103
elif suffix := condition .get ("suffix" ):
95
104
if isinstance (suffix , dict ):
96
105
if suffix_equal_ignore_case := suffix .get ("equals-ignore-case" ):
97
- return value . lower (). endswith ( suffix_equal_ignore_case .lower ())
98
-
99
- return value . endswith (suffix )
106
+ return self . _evaluate_suffix ( suffix_equal_ignore_case . lower (), value .lower ())
107
+ else :
108
+ return self . _evaluate_suffix (suffix , value )
100
109
101
110
elif equal_ignore_case := condition .get ("equals-ignore-case" ):
102
- return equal_ignore_case . lower () == value . lower ( )
111
+ return self . _evaluate_equal_ignore_case ( equal_ignore_case , value )
103
112
elif numeric_condition := condition .get ("numeric" ):
104
113
return self ._evaluate_numeric_condition (numeric_condition , value )
105
114
@@ -108,12 +117,28 @@ def _evaluate_condition(self, value, condition, field_exists: bool):
108
117
return value in ips
109
118
110
119
elif wildcard := condition .get ("wildcard" ):
111
- return re . match ( re . escape ( wildcard ). replace ( " \\ *" , ".+" ) + "$" , value )
120
+ return self . _evaluate_wildcard ( wildcard , value )
112
121
113
122
return False
114
123
115
124
@staticmethod
116
- def _evaluate_numeric_condition (conditions , value ):
125
+ def _evaluate_prefix (condition : str | list , value : str ) -> bool :
126
+ return value .startswith (condition )
127
+
128
+ @staticmethod
129
+ def _evaluate_suffix (condition : str | list , value : str ) -> bool :
130
+ return value .endswith (condition )
131
+
132
+ @staticmethod
133
+ def _evaluate_equal_ignore_case (condition : str , value : str ) -> bool :
134
+ return condition .lower () == value .lower ()
135
+
136
+ @staticmethod
137
+ def _evaluate_wildcard (condition : str , value : str ) -> bool :
138
+ return re .match (re .escape (condition ).replace ("\\ *" , ".+" ) + "$" , value )
139
+
140
+ @staticmethod
141
+ def _evaluate_numeric_condition (conditions , value ) -> bool :
117
142
try :
118
143
# try if the value is numeric
119
144
value = float (value )
@@ -362,7 +387,18 @@ def _validate_rule(self, rule: t.Any, from_: str | None = None) -> None:
362
387
"prefix" ,
363
388
"suffix" ,
364
389
):
365
- if isinstance (value , dict ):
390
+ if from_ == "anything-but" :
391
+ if isinstance (value , dict ):
392
+ raise InvalidEventPatternException (
393
+ f"{ self .error_prefix } Value of { from_ } must be an array or single string/number value."
394
+ )
395
+
396
+ if not self ._is_str_or_list_of_str (value ):
397
+ raise InvalidEventPatternException (
398
+ f"{ self .error_prefix } prefix/suffix match pattern must be a string"
399
+ )
400
+
401
+ elif isinstance (value , dict ):
366
402
for inner_operator in value .keys ():
367
403
if inner_operator != "equals-ignore-case" :
368
404
raise InvalidEventPatternException (
@@ -377,9 +413,7 @@ def _validate_rule(self, rule: t.Any, from_: str | None = None) -> None:
377
413
378
414
elif operator == "equals-ignore-case" :
379
415
if from_ == "anything-but" :
380
- if (not isinstance (value , (str , list ))) or (
381
- isinstance (value , list ) and not all (isinstance (v , str ) for v in value )
382
- ):
416
+ if not self ._is_str_or_list_of_str (value ):
383
417
raise InvalidEventPatternException (
384
418
f"{ self .error_prefix } Inside { from_ } /{ operator } list, number|start|null|boolean is not supported."
385
419
)
@@ -400,7 +434,12 @@ def _validate_rule(self, rule: t.Any, from_: str | None = None) -> None:
400
434
# or have a nested `prefix`, `suffix` or `equals-ignore-case` pattern
401
435
elif isinstance (value , dict ):
402
436
for inner_operator in v
E377
alue .keys ():
403
- if inner_operator not in ("prefix" , "equals-ignore-case" , "suffix" ):
437
+ if inner_operator not in (
438
+ "prefix" ,
439
+ "equals-ignore-case" ,
440
+ "suffix" ,
441
+ "wildcard" ,
442
+ ):
404
443
raise InvalidEventPatternException (
405
444
f"{ self .error_prefix } Unsupported anything-but pattern: { inner_operator } "
406
445
)
@@ -426,7 +465,11 @@ def _validate_rule(self, rule: t.Any, from_: str | None = None) -> None:
426
465
f"{ self .error_prefix } Malformed CIDR, one '/' required"
427
466
)
428
467
elif operator == "wildcard" :
429
- self ._validate_wildcard (value )
468
+ if from_ == "anything-but" and isinstance (value , list ):
469
+ for v in value :
470
+ self ._validate_wildcard (v )
471
+ else :
472
+ self ._validate_wildcard (value )
430
473
431
474
else :
432
475
raise InvalidEventPatternException (
@@ -512,3 +555,12 @@ def _validate_wildcard(self, value: t.Any):
512
555
raise InvalidEventPatternException (
513
556
f"{ self .error_prefix } Rule is too complex - try using fewer wildcard characters or fewer repeating character sequences after a wildcard character"
514
557
)
558
+
559
+ @staticmethod
560
+ def _is_str_or_list_of_str (value : t .Any ) -> bool :
561
+ if not isinstance (value , (str , list )):
562
+ return False
563
+ if isinstance (value , list ) and not all (isinstance (v , str ) for v in value ):
564
+ return False
565
+
566
+ return True
0 commit comments