From a3c3715cde35510f8c5586b6aaba2930adf69611 Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Tue, 5 Sep 2017 17:38:26 -0400 Subject: [PATCH] Fixes for the behavior of the 'NOT' qualifier on the 'LIKE', 'ISSUBSET', and 'ISSUPERSET' operators. Before, type-mismatched comparisons would always evaluate to false. Now, comparisons including the 'NOT' operator, eval to true. This issue also affects the 'MATCHES' operator, but is not addressed here, because I have fixes in another branch, and don't want to create needless merge conflicts. Updated tests in test_basic_ops.py according to the above pattern matching changes. Also added some type-mismatched tests of the 'ISSUBSET' and 'ISSUPERSET' operators, which were missing before. --- stix2matcher/matcher.py | 23 +++++++++++++---------- stix2matcher/test/test_basic_ops.py | 18 +++++++++++++++--- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/stix2matcher/matcher.py b/stix2matcher/matcher.py index 6b036ae..859534d 100644 --- a/stix2matcher/matcher.py +++ b/stix2matcher/matcher.py @@ -1689,11 +1689,12 @@ def exitPropTestLike(self, ctx): def like_pred(value): # non-strings can't match - if not isinstance(value, six.text_type): - return False + if isinstance(value, six.text_type): + value = unicodedata.normalize("NFC", value) + result = compiled_re.match(value) + else: + result = False - value = unicodedata.normalize("NFC", value) - result = compiled_re.match(value) if ctx.NOT(): result = not result @@ -1787,10 +1788,11 @@ def exitPropTestIsSubset(self, ctx): obs_values = self.__pop(debug_label) def subnet_pred(value): - if not isinstance(value, six.text_type): - return False + if isinstance(value, six.text_type): + result = _ip_or_cidr_in_subnet(value, subnet_str) + else: + result = False - result = _ip_or_cidr_in_subnet(value, subnet_str) if ctx.NOT(): result = not result @@ -1822,10 +1824,11 @@ def exitPropTestIsSuperset(self, ctx): obs_values = self.__pop(debug_label) def contains_pred(value): - if not isinstance(value, six.text_type): - return False + if isinstance(value, six.text_type): + result = _ip_or_cidr_in_subnet(ip_or_subnet_str, value) + else: + result = False - result = _ip_or_cidr_in_subnet(ip_or_subnet_str, value) if ctx.NOT(): result = not result diff --git a/stix2matcher/test/test_basic_ops.py b/stix2matcher/test/test_basic_ops.py index 603a917..7021295 100644 --- a/stix2matcher/test/test_basic_ops.py +++ b/stix2matcher/test/test_basic_ops.py @@ -47,6 +47,7 @@ "[test:int in (-4, 5, 6.6)]", "[test:int not in ('a', 'b', 'c')]", "[test:int not matches 'l+']", + "[test:int not like 'he%']", ]) def test_basic_ops_int_match(pattern): assert match(pattern, _observations) @@ -69,7 +70,6 @@ def test_basic_ops_int_match(pattern): "[test:int = t'1965-07-19T22:41:38Z']", "[test:int > t'1965-07-19T22:41:38Z']", "[test:int like 'he%']", - "[test:int not like 'he%']", "[test:int matches 'l+']", "[test:int not in (-4, 5, 6)]", "[test:int not in (-4, 5, 6.6)]", @@ -100,6 +100,7 @@ def test_basic_ops_int_nomatch(pattern): "[test:float_int in (11.1, 12, 13)]", "[test:float not in ('a', 'b', 'c')]", "[test:float not matches 'l+']", + "[test:float not like 'he%']", ]) def test_basic_ops_float_match(pattern): assert match(pattern, _observations) @@ -123,7 +124,6 @@ def test_basic_ops_float_match(pattern): "[test:float = t'1965-07-19T22:41:38Z']", "[test:float > t'1965-07-19T22:41:38Z']", "[test:float like 'he%']", - "[test:float not like 'he%']", "[test:float matches 'l+']", "[test:float not in (-4.21, 12.658, 964.321)]", "[test:float_int not in (11, 12, 13)]", @@ -148,6 +148,7 @@ def test_basic_ops_float_nomatch(pattern): "[test:bool in (false, true, false)]", "[test:bool not in ('a', 'b', 'c')]", "[test:bool not matches 'l+']", + "[test:bool not like 'he%']", ]) def test_basic_ops_bool_match(pattern): assert match(pattern, _observations) @@ -165,7 +166,6 @@ def test_basic_ops_bool_match(pattern): "[test:bool = b'AQIDBA==']", "[test:bool = t'1965-07-19T22:41:38Z']", "[test:bool like 'he%']", - "[test:bool not like 'he%']", "[test:bool matches 'l+']", "[test:bool not in (false, true, false)]", "[test:bool in ('a', 'b', 'c')]" @@ -251,6 +251,12 @@ def test_basic_ops_string_err(pattern): "[test:cidr issuperset '11.22.41.123/29']", "[test:cidr not issuperset '11.22.33.44/13']", "[test:cidr not issuperset '11.22.123.41/29']", + "[test:int not issuperset '11.22.33.44']", + "[test:int not issubset '11.22.33.44']", + "[test:float not issuperset '11.22.33.44']", + "[test:float not issubset '11.22.33.44']", + "[test:bool not issuperset '11.22.33.44']", + "[test:bool not issubset '11.22.33.44']", ]) def test_basic_ops_ip_match(pattern): assert match(pattern, _observations) @@ -263,6 +269,12 @@ def test_basic_ops_ip_match(pattern): "[test:cidr not issuperset '11.22.41.123/29']", "[test:cidr issuperset '11.22.33.44/13']", "[test:cidr issuperset '11.22.123.41/29']", + "[test:int issuperset '11.22.33.44']", + "[test:int issubset '11.22.33.44']", + "[test:float issuperset '11.22.33.44']", + "[test:float issubset '11.22.33.44']", + "[test:bool issuperset '11.22.33.44']", + "[test:bool issubset '11.22.33.44']", ]) def test_basic_ops_ip_nomatch(pattern): assert not match(pattern, _observations)