diff --git a/stix2/properties.py b/stix2/properties.py index 80c9e0a..735bc79 100644 --- a/stix2/properties.py +++ b/stix2/properties.py @@ -8,10 +8,7 @@ import re import uuid from .base import _STIXBase -from .exceptions import ( - CustomContentError, DictionaryKeyError, MissingPropertiesError, - MutuallyExclusivePropertiesError, STIXError, -) +from .exceptions import CustomContentError, DictionaryKeyError, STIXError from .parsing import parse, parse_observable from .registry import STIX2_OBJ_MAPS from .utils import _get_dict, get_class_hierarchy_names, parse_into_datetime @@ -503,7 +500,7 @@ class ReferenceProperty(Property): (valid_types is None and invalid_types is None): raise ValueError( "Exactly one of 'valid_types' and 'invalid_types' must be " - "given" + "given", ) if valid_types and not isinstance(valid_types, list): @@ -517,21 +514,6 @@ class ReferenceProperty(Property): self.types = set(valid_types or invalid_types) self.auth_type = self._WHITELIST if valid_types else self._BLACKLIST - # Handling both generic and non-generic types in the same constraint - # complicates life... let's keep it simple unless we really need the - # complexity. - self.generic_constraint = any( - t in self._OBJECT_CATEGORIES for t in self.types - ) - - if self.generic_constraint and any( - t not in self._OBJECT_CATEGORIES for t in self.types - ): - raise ValueError( - "Generic type categories and specific types may not both be " - "given" - ) - super(ReferenceProperty, self).__init__(**kwargs) def clean(self, value, allow_custom): @@ -543,10 +525,19 @@ class ReferenceProperty(Property): obj_type = value[:value.index('--')] - types = self.types + # Only comes into play when inverting a hybrid whitelist. + # E.g. if the possible generic categories are A, B, C, then the + # inversion of whitelist constraint "A or x" (where x is a specific + # type) is something like "[not (B or C)] or x". In other words, we + # invert the generic categories to produce a blacklist, but leave the + # specific categories alone; they essentially become exceptions to our + # blacklist. + blacklist_exceptions = set() + + generics = self.types & self._OBJECT_CATEGORIES + specifics = self.types - generics auth_type = self.auth_type - if allow_custom and auth_type == self._WHITELIST and \ - self.generic_constraint: + if allow_custom and auth_type == self._WHITELIST and generics: # If allowing customization and using a whitelist, and if generic # "category" types were given, we need to allow custom object types # of those categories. Unless registered, it's impossible to know @@ -554,60 +545,40 @@ class ReferenceProperty(Property): # permissive approach and allow any type which is not known to be # in the wrong category. I.e. flip the whitelist set to a # blacklist of a complementary set. - types = self._OBJECT_CATEGORIES - types auth_type = self._BLACKLIST + generics = self._OBJECT_CATEGORIES - generics + blacklist_exceptions, specifics = specifics, blacklist_exceptions if auth_type == self._WHITELIST: - # allow_custom is not applicable to "whitelist" style object type - # constraints, so we ignore it. - has_custom = False - - if self.generic_constraint: - type_ok = _type_in_generic_set( - obj_type, types, self.spec_version - ) - else: - type_ok = obj_type in types - - if not type_ok: - raise ValueError( - "The type-specifying prefix '%s' for this property is not " - "valid" % obj_type - ) + type_ok = _type_in_generic_set( + obj_type, generics, self.spec_version + ) or obj_type in specifics else: - # A type "blacklist" was used to describe legal object types. We - # must enforce the type blacklist regardless of allow_custom. - if self.generic_constraint: - type_ok = not _type_in_generic_set( - obj_type, types, self.spec_version + type_ok = ( + not _type_in_generic_set( + obj_type, generics, self.spec_version, ) - else: - type_ok = obj_type not in types + and obj_type not in specifics + ) or obj_type in blacklist_exceptions - if not type_ok: - raise ValueError( - "The type-specifying prefix '%s' for this property is not " - "valid" % obj_type - ) + if not type_ok: + raise ValueError( + "The type-specifying prefix '%s' for this property is not " + "valid" % obj_type, + ) - # allow_custom=True only allows references to custom objects which - # are not otherwise blacklisted. We need to figure out whether - # the referenced object is custom or not. No good way to do that - # at present... just check if unregistered and for the "x-" type - # prefix, for now? - type_maps = STIX2_OBJ_MAPS[self.spec_version] + # We need to figure out whether the referenced object is custom or + # not. No good way to do that at present... just check if + # unregistered and for the "x-" type prefix, for now? + has_custom = not _type_in_generic_set( + obj_type, self._OBJECT_CATEGORIES, self.spec_version, + ) or obj_type.startswith("x-") - has_custom = obj_type not in type_maps["objects"] \ - and obj_type not in type_maps["observables"] \ - and obj_type not in ["relationship", "sighting"] - - has_custom = has_custom or obj_type.startswith("x-") - - if not allow_custom and has_custom: - raise CustomContentError( - "reference to custom object type: " + obj_type, - ) + if not allow_custom and has_custom: + raise CustomContentError( + "reference to custom object type: " + obj_type, + ) return value, has_custom @@ -624,7 +595,9 @@ def _type_in_generic_set(type_, type_set, spec_version): result = False for type_id in type_set: if type_id == "SDO": - result = type_ in type_maps["objects"] + result = type_ in type_maps["objects"] and type_ not in [ + "relationship", "sighting", + ] # sigh elif type_id == "SCO": result = type_ in type_maps["observables"] elif type_id == "SRO": diff --git a/stix2/test/v20/test_properties.py b/stix2/test/v20/test_properties.py index af1ffec..4dbc437 100644 --- a/stix2/test/v20/test_properties.py +++ b/stix2/test/v20/test_properties.py @@ -84,19 +84,21 @@ def test_id_property_default(): assert ID_PROP.clean(default) == (default, False) -def test_reference_property(): - ref_prop = ReferenceProperty(valid_types="my-type", spec_version="2.0") +def test_reference_property_whitelist_standard_type(): + ref_prop = ReferenceProperty(valid_types="identity", spec_version="2.0") + result = ref_prop.clean( + "identity--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False, + ) + assert result == ("identity--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) - assert ref_prop.clean("my-type--00000000-0000-4000-8000-000000000000", False) with pytest.raises(ValueError): - ref_prop.clean("foo", False) + ref_prop.clean("foo--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) - # This is not a valid V4 UUID with pytest.raises(ValueError): - ref_prop.clean("my-type--00000000-0000-0000-0000-000000000000", False) + ref_prop.clean("foo--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) -def test_reference_property_whitelist_type(): +def test_reference_property_whitelist_custom_type(): ref_prop = ReferenceProperty(valid_types="my-type", spec_version="2.0") with pytest.raises(ValueError): @@ -105,16 +107,18 @@ def test_reference_property_whitelist_type(): with pytest.raises(ValueError): ref_prop.clean("not-my-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) - result = ref_prop.clean("my-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) - assert result == ("my-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + with pytest.raises(CustomContentError): + # This is the whitelisted type, but it's still custom, and + # customization is disallowed here. + ref_prop.clean("my-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) - result = ref_prop.clean("my-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) - assert result == ("my-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + result = ref_prop.clean("my-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) + assert result == ("my-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) def test_reference_property_whitelist_generic_type(): ref_prop = ReferenceProperty( - valid_types=["SCO", "SRO"], spec_version="2.0" + valid_types=["SCO", "SRO"], spec_version="2.0", ) result = ref_prop.clean("file--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) @@ -124,12 +128,19 @@ def test_reference_property_whitelist_generic_type(): assert result == ("file--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) result = ref_prop.clean( - "sighting--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False + "sighting--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False, ) assert result == ("sighting--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) result = ref_prop.clean( - "some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True + "sighting--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True, + ) + assert result == ("sighting--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + + # The prop assumes some-type is a custom type of one of the generic + # type categories. + result = ref_prop.clean( + "some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True, ) assert result == ("some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) @@ -143,7 +154,7 @@ def test_reference_property_whitelist_generic_type(): ref_prop.clean("identity--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) -def test_reference_property_blacklist_type(): +def test_reference_property_blacklist_standard_type(): ref_prop = ReferenceProperty(invalid_types="identity", spec_version="2.0") result = ref_prop.clean( "malware--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False, @@ -155,6 +166,11 @@ def test_reference_property_blacklist_type(): ) assert result == ("malware--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + with pytest.raises(CustomContentError): + ref_prop.clean( + "some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False, + ) + result = ref_prop.clean( "some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True, ) @@ -170,15 +186,10 @@ def test_reference_property_blacklist_type(): "identity--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True, ) - with pytest.raises(CustomContentError): - ref_prop.clean( - "some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False, - ) - def test_reference_property_blacklist_generic_type(): ref_prop = ReferenceProperty( - invalid_types=["SDO", "SRO"], spec_version="2.0" + invalid_types=["SDO", "SRO"], spec_version="2.0", ) result = ref_prop.clean( @@ -191,16 +202,16 @@ def test_reference_property_blacklist_generic_type(): ) assert result == ("file--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + with pytest.raises(CustomContentError): + ref_prop.clean( + "some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False, + ) + result = ref_prop.clean( "some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True, ) assert result == ("some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) - with pytest.raises(ValueError): - ref_prop.clean( - "identity--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True, - ) - with pytest.raises(ValueError): ref_prop.clean( "identity--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False, @@ -208,7 +219,7 @@ def test_reference_property_blacklist_generic_type(): with pytest.raises(ValueError): ref_prop.clean( - "relationship--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True, + "identity--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True, ) with pytest.raises(ValueError): @@ -216,18 +227,57 @@ def test_reference_property_blacklist_generic_type(): "relationship--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False, ) - with pytest.raises(CustomContentError): + with pytest.raises(ValueError): ref_prop.clean( - "some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False, + "relationship--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True, ) -def test_reference_property_hybrid_constraint_type(): - with pytest.raises(ValueError): - ReferenceProperty(valid_types=["a", "SCO"], spec_version="2.0") +def test_reference_property_whitelist_hybrid_type(): + p = ReferenceProperty(valid_types=["a", "SCO"], spec_version="2.0") + + result = p.clean("file--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + assert result == ("file--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + + result = p.clean("file--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) + assert result == ("file--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + + with pytest.raises(CustomContentError): + # although whitelisted, "a" is a custom type + p.clean("a--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + + result = p.clean("a--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) + assert result == ("a--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) with pytest.raises(ValueError): - ReferenceProperty(invalid_types=["a", "SCO"], spec_version="2.0") + p.clean("b--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + + # should just assume "b" is a custom SCO type. + result = p.clean("b--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) + assert result == ("b--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) + + +def test_reference_property_blacklist_hybrid_type(): + p = ReferenceProperty(invalid_types=["a", "SCO"], spec_version="2.0") + + with pytest.raises(ValueError): + p.clean("file--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + + with pytest.raises(ValueError): + p.clean("file--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) + + with pytest.raises(ValueError): + p.clean("a--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + + with pytest.raises(ValueError): + p.clean("a--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) + + with pytest.raises(CustomContentError): + p.clean("b--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + + # should just assume "b" is a custom type which is not an SCO + result = p.clean("b--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) + assert result == ("b--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) def test_reference_property_impossible_constraint(): diff --git a/stix2/test/v20/test_report.py b/stix2/test/v20/test_report.py index 2de9363..29d181c 100644 --- a/stix2/test/v20/test_report.py +++ b/stix2/test/v20/test_report.py @@ -144,8 +144,8 @@ def test_report_on_custom(): published="2016-01-20T17:00:00Z", object_refs=[ "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", - "some-type--2672975a-ce1e-4473-a1c6-0d79868930c7" - ] + "some-type--2672975a-ce1e-4473-a1c6-0d79868930c7", + ], ) report = stix2.v20.Report( @@ -154,10 +154,10 @@ def test_report_on_custom(): published="2016-01-20T17:00:00Z", object_refs=[ "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", - "some-type--2672975a-ce1e-4473-a1c6-0d79868930c7" + "some-type--2672975a-ce1e-4473-a1c6-0d79868930c7", ], allow_custom=True, ) assert "some-type--2672975a-ce1e-4473-a1c6-0d79868930c7" \ - in report.object_refs + in report.object_refs diff --git a/stix2/test/v21/test_malware_analysis.py b/stix2/test/v21/test_malware_analysis.py index e5ad628..ed8cce5 100644 --- a/stix2/test/v21/test_malware_analysis.py +++ b/stix2/test/v21/test_malware_analysis.py @@ -91,7 +91,7 @@ def test_malware_analysis_custom_sco_refs(): product="super scanner", analysis_sco_refs=[ "file--6e8c78cf-4bcc-4729-9265-86a97bfc91ba", - "some-object--f6bfc147-e844-4578-ae01-847979890239" + "some-object--f6bfc147-e844-4578-ae01-847979890239", ], allow_custom=True, ) @@ -105,8 +105,8 @@ def test_malware_analysis_custom_sco_refs(): product="super scanner", analysis_sco_refs=[ "file--6e8c78cf-4bcc-4729-9265-86a97bfc91ba", - "some-object--f6bfc147-e844-4578-ae01-847979890239" - ] + "some-object--f6bfc147-e844-4578-ae01-847979890239", + ], ) with pytest.raises(stix2.exceptions.InvalidValueError): @@ -115,7 +115,7 @@ def test_malware_analysis_custom_sco_refs(): analysis_sco_refs=[ "file--6e8c78cf-4bcc-4729-9265-86a97bfc91ba", # standard object type; wrong category (not SCO) - "identity--56977a19-49ef-49d7-b259-f733fa4b7bbc" + "identity--56977a19-49ef-49d7-b259-f733fa4b7bbc", ], allow_custom=True, ) diff --git a/stix2/test/v21/test_properties.py b/stix2/test/v21/test_properties.py index aa3624b..413aa0d 100644 --- a/stix2/test/v21/test_properties.py +++ b/stix2/test/v21/test_properties.py @@ -8,7 +8,7 @@ from stix2.exceptions import ( from stix2.properties import ( DictionaryProperty, EmbeddedObjectProperty, ExtensionsProperty, HashesProperty, IDProperty, ListProperty, ObservableProperty, - ReferenceProperty, STIXObjectProperty, StringProperty, TypeProperty, + ReferenceProperty, STIXObjectProperty, StringProperty, ) from stix2.v21.common import MarkingProperty @@ -87,19 +87,21 @@ def test_id_property_default(): assert ID_PROP.clean(default) == (default, False) -def test_reference_property(): - ref_prop = ReferenceProperty(valid_types="my-type", spec_version="2.1") +def test_reference_property_whitelist_standard_type(): + ref_prop = ReferenceProperty(valid_types="identity", spec_version="2.1") + result = ref_prop.clean( + "identity--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False, + ) + assert result == ("identity--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) - assert ref_prop.clean("my-type--00000000-0000-4000-8000-000000000000", False) with pytest.raises(ValueError): - ref_prop.clean("foo", False) + ref_prop.clean("foo--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) - # This is not a valid RFC 4122 UUID with pytest.raises(ValueError): - ref_prop.clean("my-type--00000000-0000-0000-0000-000000000000", False) + ref_prop.clean("foo--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) -def test_reference_property_whitelist_type(): +def test_reference_property_whitelist_custom_type(): ref_prop = ReferenceProperty(valid_types="my-type", spec_version="2.1") with pytest.raises(ValueError): @@ -108,16 +110,18 @@ def test_reference_property_whitelist_type(): with pytest.raises(ValueError): ref_prop.clean("not-my-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) - result = ref_prop.clean("my-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) - assert result == ("my-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + with pytest.raises(CustomContentError): + # This is the whitelisted type, but it's still custom, and + # customization is disallowed here. + ref_prop.clean("my-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) - result = ref_prop.clean("my-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) - assert result == ("my-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + result = ref_prop.clean("my-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) + assert result == ("my-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) def test_reference_property_whitelist_generic_type(): ref_prop = ReferenceProperty( - valid_types=["SCO", "SRO"], spec_version="2.1" + valid_types=["SCO", "SRO"], spec_version="2.1", ) result = ref_prop.clean("file--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) @@ -127,12 +131,19 @@ def test_reference_property_whitelist_generic_type(): assert result == ("file--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) result = ref_prop.clean( - "sighting--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False + "sighting--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False, ) assert result == ("sighting--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) result = ref_prop.clean( - "some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True + "sighting--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True, + ) + assert result == ("sighting--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + + # The prop assumes some-type is a custom type of one of the generic + # type categories. + result = ref_prop.clean( + "some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True, ) assert result == ("some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) @@ -146,7 +157,7 @@ def test_reference_property_whitelist_generic_type(): ref_prop.clean("identity--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) -def test_reference_property_blacklist_type(): +def test_reference_property_blacklist_standard_type(): ref_prop = ReferenceProperty(invalid_types="identity", spec_version="2.1") result = ref_prop.clean( "location--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False, @@ -158,6 +169,11 @@ def test_reference_property_blacklist_type(): ) assert result == ("location--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + with pytest.raises(CustomContentError): + ref_prop.clean( + "some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False, + ) + result = ref_prop.clean( "some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True, ) @@ -173,15 +189,10 @@ def test_reference_property_blacklist_type(): "identity--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True, ) - with pytest.raises(CustomContentError): - ref_prop.clean( - "some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False, - ) - def test_reference_property_blacklist_generic_type(): ref_prop = ReferenceProperty( - invalid_types=["SDO", "SRO"], spec_version="2.1" + invalid_types=["SDO", "SRO"], spec_version="2.1", ) result = ref_prop.clean( @@ -194,16 +205,16 @@ def test_reference_property_blacklist_generic_type(): ) assert result == ("file--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + with pytest.raises(CustomContentError): + ref_prop.clean( + "some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False, + ) + result = ref_prop.clean( "some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True, ) assert result == ("some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) - with pytest.raises(ValueError): - ref_prop.clean( - "identity--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True, - ) - with pytest.raises(ValueError): ref_prop.clean( "identity--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False, @@ -211,7 +222,7 @@ def test_reference_property_blacklist_generic_type(): with pytest.raises(ValueError): ref_prop.clean( - "relationship--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True, + "identity--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True, ) with pytest.raises(ValueError): @@ -219,18 +230,57 @@ def test_reference_property_blacklist_generic_type(): "relationship--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False, ) - with pytest.raises(CustomContentError): + with pytest.raises(ValueError): ref_prop.clean( - "some-type--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False, + "relationship--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True, ) -def test_reference_property_hybrid_constraint_type(): - with pytest.raises(ValueError): - ReferenceProperty(valid_types=["a", "SCO"], spec_version="2.1") +def test_reference_property_whitelist_hybrid_type(): + p = ReferenceProperty(valid_types=["a", "SCO"], spec_version="2.1") + + result = p.clean("file--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + assert result == ("file--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + + result = p.clean("file--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) + assert result == ("file--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + + with pytest.raises(CustomContentError): + # although whitelisted, "a" is a custom type + p.clean("a--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + + result = p.clean("a--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) + assert result == ("a--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) with pytest.raises(ValueError): - ReferenceProperty(invalid_types=["a", "SCO"], spec_version="2.1") + p.clean("b--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + + # should just assume "b" is a custom SCO type. + result = p.clean("b--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) + assert result == ("b--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) + + +def test_reference_property_blacklist_hybrid_type(): + p = ReferenceProperty(invalid_types=["a", "SCO"], spec_version="2.1") + + with pytest.raises(ValueError): + p.clean("file--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + + with pytest.raises(ValueError): + p.clean("file--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) + + with pytest.raises(ValueError): + p.clean("a--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + + with pytest.raises(ValueError): + p.clean("a--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) + + with pytest.raises(CustomContentError): + p.clean("b--8a8e8758-f92c-4058-ba38-f061cd42a0cf", False) + + # should just assume "b" is a custom type which is not an SCO + result = p.clean("b--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) + assert result == ("b--8a8e8758-f92c-4058-ba38-f061cd42a0cf", True) def test_reference_property_impossible_constraint(): diff --git a/stix2/test/v21/test_report.py b/stix2/test/v21/test_report.py index 69af096..1dc55be 100644 --- a/stix2/test/v21/test_report.py +++ b/stix2/test/v21/test_report.py @@ -4,12 +4,12 @@ import pytest import pytz import stix2 +from stix2.exceptions import InvalidValueError from .constants import ( CAMPAIGN_ID, IDENTITY_ID, INDICATOR_ID, INDICATOR_KWARGS, RELATIONSHIP_ID, REPORT_ID, ) -from stix2.exceptions import InvalidValueError EXPECTED = """{ "type": "report", @@ -144,8 +144,8 @@ def test_report_on_custom(): published="2016-01-20T17:00:00Z", object_refs=[ "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", - "some-type--2672975a-ce1e-4473-a1c6-0d79868930c7" - ] + "some-type--2672975a-ce1e-4473-a1c6-0d79868930c7", + ], ) report = stix2.v21.Report( @@ -153,10 +153,10 @@ def test_report_on_custom(): published="2016-01-20T17:00:00Z", object_refs=[ "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", - "some-type--2672975a-ce1e-4473-a1c6-0d79868930c7" + "some-type--2672975a-ce1e-4473-a1c6-0d79868930c7", ], allow_custom=True, ) assert "some-type--2672975a-ce1e-4473-a1c6-0d79868930c7" \ - in report.object_refs + in report.object_refs