From 1260c7b45eaa351442015212f92904ee83047be3 Mon Sep 17 00:00:00 2001 From: "Desai, Kartikey H" Date: Fri, 20 Mar 2020 16:49:20 -0400 Subject: [PATCH 1/7] Fix existing tests and add new tests. Fixes #363 --- stix2/core.py | 6 +- stix2/test/v20/test_core.py | 49 --------------- stix2/test/v20/test_custom.py | 69 ++++++++++++++++++++- stix2/test/v20/test_datastore_filesystem.py | 6 +- stix2/test/v20/test_datastore_memory.py | 2 +- stix2/test/v20/test_properties.py | 2 +- stix2/test/v21/test_core.py | 47 -------------- stix2/test/v21/test_custom.py | 67 +++++++++++++++++++- stix2/test/v21/test_datastore_filesystem.py | 4 +- stix2/test/v21/test_datastore_memory.py | 2 +- stix2/test/v21/test_properties.py | 2 +- 11 files changed, 149 insertions(+), 107 deletions(-) diff --git a/stix2/core.py b/stix2/core.py index 0d1fee5..c9282d2 100644 --- a/stix2/core.py +++ b/stix2/core.py @@ -8,7 +8,7 @@ import re import stix2 from .base import _STIXBase -from .exceptions import ParseError +from .exceptions import DuplicateObjectRegistrationError, ParseError from .markings import _MarkingsMixin from .utils import _get_dict @@ -217,6 +217,8 @@ def _register_object(new_type, version=None): v = 'v' + stix2.DEFAULT_VERSION.replace('.', '') OBJ_MAP = STIX2_OBJ_MAPS[v]['objects'] + if new_type._type in OBJ_MAP.keys(): + raise DuplicateObjectRegistrationError("An object with type '%s' already exists and cannot be created again." % new_type._type) OBJ_MAP[new_type._type] = new_type @@ -255,6 +257,8 @@ def _register_observable(new_observable, version=None): v = 'v' + stix2.DEFAULT_VERSION.replace('.', '') OBJ_MAP_OBSERVABLE = STIX2_OBJ_MAPS[v]['observables'] + if new_observable._type in OBJ_MAP_OBSERVABLE.keys(): + raise DuplicateObjectRegistrationError("An observable with type '%s' already exists and cannot be created again." % new_observable._type) OBJ_MAP_OBSERVABLE[new_observable._type] = new_observable diff --git a/stix2/test/v20/test_core.py b/stix2/test/v20/test_core.py index d2efa22..2808ba5 100644 --- a/stix2/test/v20/test_core.py +++ b/stix2/test/v20/test_core.py @@ -68,17 +68,6 @@ def test_parse_observable_with_no_version(): assert v in str(obs_obj.__class__) -def test_register_object_with_version(): - bundle = core.dict_to_stix2(BUNDLE, version='2.0') - core._register_object(bundle.objects[0].__class__, version='2.0') - v = 'v20' - - assert bundle.objects[0].type in core.STIX2_OBJ_MAPS[v]['objects'] - # spec_version is not in STIX 2.0, and is required in 2.1, so this - # suffices as a test for a STIX 2.0 object. - assert "spec_version" not in bundle.objects[0] - - def test_register_marking_with_version(): core._register_marking(stix2.v20.TLP_WHITE.__class__, version='2.0') v = 'v20' @@ -97,44 +86,6 @@ def test_register_marking_with_no_version(): assert v in str(stix2.v20.TLP_WHITE.__class__) -def test_register_observable_with_version(): - observed_data = stix2.v20.ObservedData( - id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref=IDENTITY_ID, - created="2016-04-06T19:58:16.000Z", - modified="2016-04-06T19:58:16.000Z", - first_observed="2015-12-21T19:00:00Z", - last_observed="2015-12-21T19:00:00Z", - number_observed=50, - objects={ - "0": { - "name": "foo.exe", - "type": "file", - "extensions": { - "ntfs-ext": { - "alternate_data_streams": [ - { - "name": "second.stream", - "size": 25536, - }, - ], - }, - }, - }, - "1": { - "type": "directory", - "path": "/usr/home", - "contains_refs": ["0"], - }, - }, - ) - core._register_observable(observed_data.objects['0'].__class__, version='2.0') - v = 'v20' - - assert observed_data.objects['0'].type in core.STIX2_OBJ_MAPS[v]['observables'] - assert v in str(observed_data.objects['0'].__class__) - - def test_register_observable_extension_with_version(): observed_data = stix2.v20.ObservedData( id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", diff --git a/stix2/test/v20/test_custom.py b/stix2/test/v20/test_custom.py index ce1aac3..8bc6ddd 100644 --- a/stix2/test/v20/test_custom.py +++ b/stix2/test/v20/test_custom.py @@ -1,6 +1,7 @@ import pytest import stix2 +from stix2 import core import stix2.v20 from ...exceptions import InvalidValueError @@ -449,7 +450,7 @@ def test_custom_observable_raises_exception(): def test_custom_observable_object_no_init_1(): @stix2.v20.CustomObservable( - 'x-new-observable', [ + 'x-new-observable-1', [ ('property1', stix2.properties.StringProperty()), ], ) @@ -1014,3 +1015,69 @@ def test_custom_object_nested_dictionary(data): ) assert data == str(example) + + +@stix2.v20.CustomObject( + 'x-new-type-2', [ + ('property1', stix2.properties.StringProperty()), + ('property2', stix2.properties.IntegerProperty()), + ], +) +class NewType2(object): + pass + + +def test_register_custom_object_with_version(): + custom_obj_1 = { + "type": "x-new-type-2", + "id": "x-new-type-2--00000000-0000-4000-8000-000000000007", + } + + cust_obj_1 = core.dict_to_stix2(custom_obj_1, version='2.0') + v = 'v20' + + assert cust_obj_1.type in core.STIX2_OBJ_MAPS[v]['objects'] + # spec_version is not in STIX 2.0, and is required in 2.1, so this + # suffices as a test for a STIX 2.0 object. + assert "spec_version" not in cust_obj_1 + + +def test_register_duplicate_object_with_version(): + with pytest.raises(stix2.exceptions.DuplicateObjectRegistrationError) as excinfo: + @stix2.v20.CustomObject( + 'x-new-type-2', [ + ('property1', stix2.properties.StringProperty()), + ('property2', stix2.properties.IntegerProperty()), + ], + ) + class NewType2(object): + pass + assert "An object with type 'x-new-type-2' already exists and cannot be created again." in str(excinfo.value) + + +@stix2.v20.CustomObservable( + 'x-new-observable-2', [ + ('property1', stix2.properties.StringProperty()), + ], +) +class NewObservable2(object): + pass + + +def test_register_observable_with_version(): + custom_obs = NewObservable2(property1="Test Observable") + v = 'v20' + + assert custom_obs.type in core.STIX2_OBJ_MAPS[v]['observables'] + + +def test_register_duplicate_observable_with_version(): + with pytest.raises(stix2.exceptions.DuplicateObjectRegistrationError) as excinfo: + @stix2.v20.CustomObservable( + 'x-new-observable-2', [ + ('property1', stix2.properties.StringProperty()), + ], + ) + class NewObservable2(object): + pass + assert "An observable with type 'x-new-observable-2' already exists and cannot be created again." in str(excinfo.value) diff --git a/stix2/test/v20/test_datastore_filesystem.py b/stix2/test/v20/test_datastore_filesystem.py index 317f927..b7e9aca 100644 --- a/stix2/test/v20/test_datastore_filesystem.py +++ b/stix2/test/v20/test_datastore_filesystem.py @@ -501,6 +501,7 @@ def test_filesystem_store_query_single_filter(fs_store): def test_filesystem_store_empty_query(fs_store): results = fs_store.query() # returns all + print (results) assert len(results) == 30 assert "tool--242f3da3-4425-4d11-8f5c-b842886da966" in [obj.id for obj in results] assert "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" in [obj.id for obj in results] @@ -515,6 +516,7 @@ def test_filesystem_store_query_multiple_filters(fs_store): def test_filesystem_store_query_dont_include_type_folder(fs_store): results = fs_store.query(stix2.Filter("type", "!=", "tool")) + print (results) assert len(results) == 28 @@ -635,7 +637,7 @@ def test_filesystem_object_with_custom_property_in_bundle(fs_store): def test_filesystem_custom_object(fs_store): @stix2.v20.CustomObject( - 'x-new-obj', [ + 'x-new-obj-2', [ ('property1', stix2.properties.StringProperty(required=True)), ], ) @@ -650,7 +652,7 @@ def test_filesystem_custom_object(fs_store): assert newobj_r["property1"] == 'something' # remove dir - shutil.rmtree(os.path.join(FS_PATH, "x-new-obj"), True) + shutil.rmtree(os.path.join(FS_PATH, "x-new-obj-2"), True) def test_relationships(rel_fs_store): diff --git a/stix2/test/v20/test_datastore_memory.py b/stix2/test/v20/test_datastore_memory.py index 7852746..28d8e52 100644 --- a/stix2/test/v20/test_datastore_memory.py +++ b/stix2/test/v20/test_datastore_memory.py @@ -329,7 +329,7 @@ def test_memory_store_object_with_custom_property_in_bundle(mem_store): def test_memory_store_custom_object(mem_store): @CustomObject( - 'x-new-obj', [ + 'x-new-obj-3', [ ('property1', properties.StringProperty(required=True)), ], ) diff --git a/stix2/test/v20/test_properties.py b/stix2/test/v20/test_properties.py index f71d829..1d1474a 100644 --- a/stix2/test/v20/test_properties.py +++ b/stix2/test/v20/test_properties.py @@ -392,7 +392,7 @@ def test_dictionary_property_invalid(d): def test_property_list_of_dictionary(): @stix2.v20.CustomObject( - 'x-new-obj', [ + 'x-new-obj-4', [ ('property1', ListProperty(DictionaryProperty(spec_version="2.0"), required=True)), ], ) diff --git a/stix2/test/v21/test_core.py b/stix2/test/v21/test_core.py index 2018395..f9f9de6 100644 --- a/stix2/test/v21/test_core.py +++ b/stix2/test/v21/test_core.py @@ -73,15 +73,6 @@ def test_parse_observable_with_no_version(): assert v in str(obs_obj.__class__) -def test_register_object_with_version(): - bundle = core.dict_to_stix2(BUNDLE, version='2.1') - core._register_object(bundle.objects[0].__class__) - v = 'v21' - - assert bundle.objects[0].type in core.STIX2_OBJ_MAPS[v]['objects'] - assert bundle.objects[0].spec_version == "2.1" - - def test_register_marking_with_version(): core._register_marking(stix2.v21.TLP_WHITE.__class__, version='2.1') v = 'v21' @@ -100,44 +91,6 @@ def test_register_marking_with_no_version(): assert v in str(stix2.v21.TLP_WHITE.__class__) -def test_register_observable_with_default_version(): - observed_data = stix2.v21.ObservedData( - id=OBSERVED_DATA_ID, - created_by_ref=IDENTITY_ID, - created="2016-04-06T19:58:16.000Z", - modified="2016-04-06T19:58:16.000Z", - first_observed="2015-12-21T19:00:00Z", - last_observed="2015-12-21T19:00:00Z", - number_observed=50, - objects={ - "0": { - "name": "foo.exe", - "type": "file", - "extensions": { - "ntfs-ext": { - "alternate_data_streams": [ - { - "name": "second.stream", - "size": 25536, - }, - ], - }, - }, - }, - "1": { - "type": "directory", - "path": "/usr/home", - "contains_refs": ["file--420bc087-8b53-5ae9-8210-20d27d5e96c8"], - }, - }, - ) - core._register_observable(observed_data.objects['0'].__class__) - v = 'v21' - - assert observed_data.objects['0'].type in core.STIX2_OBJ_MAPS[v]['observables'] - assert v in str(observed_data.objects['0'].__class__) - - def test_register_observable_extension_with_default_version(): observed_data = stix2.v21.ObservedData( id=OBSERVED_DATA_ID, diff --git a/stix2/test/v21/test_custom.py b/stix2/test/v21/test_custom.py index b46288d..9bd0afa 100644 --- a/stix2/test/v21/test_custom.py +++ b/stix2/test/v21/test_custom.py @@ -455,7 +455,7 @@ def test_custom_observable_raises_exception(): def test_custom_observable_object_no_init_1(): @stix2.v21.CustomObservable( - 'x-new-observable', [ + 'x-new-observable-2', [ ('property1', stix2.properties.StringProperty()), ], ) @@ -1068,3 +1068,68 @@ def test_custom_object_nested_dictionary(data): ) assert data == str(example) + + +@stix2.v21.CustomObject( + 'x-new-type-2', [ + ('property1', stix2.properties.StringProperty()), + ('property2', stix2.properties.IntegerProperty()), + ], +) +class NewType3(object): + pass + + +def test_register_custom_object_with_version(): + custom_obj_1 = { + "type": "x-new-type-2", + "id": "x-new-type-2--00000000-0000-4000-8000-000000000007", + "spec_version": "2.1", + } + + cust_obj_1 = stix2.core.dict_to_stix2(custom_obj_1, version='2.1') + v = 'v21' + + assert cust_obj_1.type in stix2.core.STIX2_OBJ_MAPS[v]['objects'] + assert cust_obj_1.spec_version == "2.1" + + +def test_register_duplicate_object_with_version(): + with pytest.raises(stix2.exceptions.DuplicateObjectRegistrationError) as excinfo: + @stix2.v21.CustomObject( + 'x-new-type-2', [ + ('property1', stix2.properties.StringProperty()), + ('property2', stix2.properties.IntegerProperty()), + ], + ) + class NewType2(object): + pass + assert "An object with type 'x-new-type-2' already exists and cannot be created again." in str(excinfo.value) + + +@stix2.v21.CustomObservable( + 'x-new-observable-3', [ + ('property1', stix2.properties.StringProperty()), + ], +) +class NewObservable3(object): + pass + + +def test_register_observable_with_version(): + custom_obs = NewObservable3(property1="Test Observable") + v = 'v21' + + assert custom_obs.type in stix2.core.STIX2_OBJ_MAPS[v]['observables'] + + +def test_register_duplicate_observable_with_version(): + with pytest.raises(stix2.exceptions.DuplicateObjectRegistrationError) as excinfo: + @stix2.v21.CustomObservable( + 'x-new-observable-2', [ + ('property1', stix2.properties.StringProperty()), + ], + ) + class NewObservable2(object): + pass + assert "An observable with type 'x-new-observable-2' already exists and cannot be created again." in str(excinfo.value) diff --git a/stix2/test/v21/test_datastore_filesystem.py b/stix2/test/v21/test_datastore_filesystem.py index 3eb8aaa..123fd7a 100644 --- a/stix2/test/v21/test_datastore_filesystem.py +++ b/stix2/test/v21/test_datastore_filesystem.py @@ -656,7 +656,7 @@ def test_filesystem_object_with_custom_property_in_bundle(fs_store): def test_filesystem_custom_object(fs_store): @stix2.v21.CustomObject( - 'x-new-obj', [ + 'x-new-obj-2', [ ('property1', stix2.properties.StringProperty(required=True)), ], ) @@ -671,7 +671,7 @@ def test_filesystem_custom_object(fs_store): assert newobj_r["property1"] == 'something' # remove dir - shutil.rmtree(os.path.join(FS_PATH, "x-new-obj"), True) + shutil.rmtree(os.path.join(FS_PATH, "x-new-obj-2"), True) def test_relationships(rel_fs_store): diff --git a/stix2/test/v21/test_datastore_memory.py b/stix2/test/v21/test_datastore_memory.py index e07943c..60f577e 100644 --- a/stix2/test/v21/test_datastore_memory.py +++ b/stix2/test/v21/test_datastore_memory.py @@ -344,7 +344,7 @@ def test_memory_store_object_with_custom_property_in_bundle(mem_store): def test_memory_store_custom_object(mem_store): @CustomObject( - 'x-new-obj', [ + 'x-new-obj-3', [ ('property1', properties.StringProperty(required=True)), ], ) diff --git a/stix2/test/v21/test_properties.py b/stix2/test/v21/test_properties.py index 50bce17..31dd941 100644 --- a/stix2/test/v21/test_properties.py +++ b/stix2/test/v21/test_properties.py @@ -404,7 +404,7 @@ def test_dictionary_property_invalid(d): def test_property_list_of_dictionary(): @stix2.v21.CustomObject( - 'x-new-obj', [ + 'x-new-obj-4', [ ('property1', ListProperty(DictionaryProperty(spec_version='2.1'), required=True)), ], ) From b06bc1afc128a3f08c2208c229abac3dd2ebe8cc Mon Sep 17 00:00:00 2001 From: "Desai, Kartikey H" Date: Fri, 20 Mar 2020 17:32:18 -0400 Subject: [PATCH 2/7] Fix import issues --- stix2/core.py | 2 +- stix2/exceptions.py | 7 +++++++ stix2/test/v20/test_custom.py | 6 +++--- stix2/test/v21/test_custom.py | 6 +++--- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/stix2/core.py b/stix2/core.py index bb583ba..ffe77f2 100644 --- a/stix2/core.py +++ b/stix2/core.py @@ -8,7 +8,7 @@ import re import stix2 from .base import _Observable, _STIXBase -from .exceptions import ParseError +from .exceptions import DuplicateObjectRegistrationError, ParseError from .markings import _MarkingsMixin from .utils import SCO21_EXT_REGEX, TYPE_REGEX, _get_dict diff --git a/stix2/exceptions.py b/stix2/exceptions.py index d2ec3fc..f65f48b 100644 --- a/stix2/exceptions.py +++ b/stix2/exceptions.py @@ -233,3 +233,10 @@ class STIXDeprecationWarning(DeprecationWarning): Represents usage of a deprecated component of a STIX specification. """ pass + + +class DuplicateObjectRegistrationError(STIXError): + """An object (or observable) with the same type as an existing object (or observable) is being registered""" + + def __init__(self, msg): + super(DuplicateObjectRegistrationError, self).__init__(msg) diff --git a/stix2/test/v20/test_custom.py b/stix2/test/v20/test_custom.py index f3fa59a..19cb28a 100644 --- a/stix2/test/v20/test_custom.py +++ b/stix2/test/v20/test_custom.py @@ -4,7 +4,7 @@ import stix2 from stix2 import core import stix2.v20 -from ...exceptions import InvalidValueError +from ...exceptions import DuplicateObjectRegistrationError, InvalidValueError from .constants import FAKE_TIME, IDENTITY_ID, MARKING_DEFINITION_ID IDENTITY_CUSTOM_PROP = stix2.v20.Identity( @@ -1040,7 +1040,7 @@ def test_register_custom_object_with_version(): def test_register_duplicate_object_with_version(): - with pytest.raises(stix2.exceptions.DuplicateObjectRegistrationError) as excinfo: + with pytest.raises(DuplicateObjectRegistrationError) as excinfo: @stix2.v20.CustomObject( 'x-new-type-2', [ ('property1', stix2.properties.StringProperty()), @@ -1069,7 +1069,7 @@ def test_register_observable_with_version(): def test_register_duplicate_observable_with_version(): - with pytest.raises(stix2.exceptions.DuplicateObjectRegistrationError) as excinfo: + with pytest.raises(DuplicateObjectRegistrationError) as excinfo: @stix2.v20.CustomObservable( 'x-new-observable-2', [ ('property1', stix2.properties.StringProperty()), diff --git a/stix2/test/v21/test_custom.py b/stix2/test/v21/test_custom.py index e2b7f22..92cacf3 100644 --- a/stix2/test/v21/test_custom.py +++ b/stix2/test/v21/test_custom.py @@ -6,7 +6,7 @@ import stix2 import stix2.base import stix2.v21 -from ...exceptions import InvalidValueError +from ...exceptions import DuplicateObjectRegistrationError, InvalidValueError from .constants import FAKE_TIME, IDENTITY_ID, MARKING_DEFINITION_ID IDENTITY_CUSTOM_PROP = stix2.v21.Identity( @@ -1092,7 +1092,7 @@ def test_register_custom_object_with_version(): def test_register_duplicate_object_with_version(): - with pytest.raises(stix2.exceptions.DuplicateObjectRegistrationError) as excinfo: + with pytest.raises(DuplicateObjectRegistrationError) as excinfo: @stix2.v21.CustomObject( 'x-new-type-2', [ ('property1', stix2.properties.StringProperty()), @@ -1121,7 +1121,7 @@ def test_register_observable_with_version(): def test_register_duplicate_observable_with_version(): - with pytest.raises(stix2.exceptions.DuplicateObjectRegistrationError) as excinfo: + with pytest.raises(DuplicateObjectRegistrationError) as excinfo: @stix2.v21.CustomObservable( 'x-new-observable-2', [ ('property1', stix2.properties.StringProperty()), From 1a1ad90388fad847963b2af4db14e2e92a8af71f Mon Sep 17 00:00:00 2001 From: "Desai, Kartikey H" Date: Fri, 20 Mar 2020 17:37:15 -0400 Subject: [PATCH 3/7] Fixes #363 --- stix2/test/v20/test_datastore_filesystem.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/stix2/test/v20/test_datastore_filesystem.py b/stix2/test/v20/test_datastore_filesystem.py index b7e9aca..25207dc 100644 --- a/stix2/test/v20/test_datastore_filesystem.py +++ b/stix2/test/v20/test_datastore_filesystem.py @@ -501,7 +501,6 @@ def test_filesystem_store_query_single_filter(fs_store): def test_filesystem_store_empty_query(fs_store): results = fs_store.query() # returns all - print (results) assert len(results) == 30 assert "tool--242f3da3-4425-4d11-8f5c-b842886da966" in [obj.id for obj in results] assert "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" in [obj.id for obj in results] @@ -516,7 +515,6 @@ def test_filesystem_store_query_multiple_filters(fs_store): def test_filesystem_store_query_dont_include_type_folder(fs_store): results = fs_store.query(stix2.Filter("type", "!=", "tool")) - print (results) assert len(results) == 28 From e8035863b8d7300a2cdba4c0737c49cfadb18bda Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Sat, 21 Mar 2020 23:56:09 -0400 Subject: [PATCH 4/7] Make swid an id-contributing property --- stix2/v21/observables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix2/v21/observables.py b/stix2/v21/observables.py index 8c9a2a1..88f1ff7 100644 --- a/stix2/v21/observables.py +++ b/stix2/v21/observables.py @@ -770,7 +770,7 @@ class Software(_Observable): ('granular_markings', ListProperty(GranularMarking)), ('defanged', BooleanProperty(default=lambda: False)), ]) - _id_contributing_properties = ["name", "cpe", "vendor", "version"] + _id_contributing_properties = ["name", "cpe", "swid", "vendor", "version"] class URL(_Observable): From 46219bf072da0b4d11014ce62565dc61c68d603f Mon Sep 17 00:00:00 2001 From: Rich Piazza Date: Wed, 25 Mar 2020 11:36:29 -0400 Subject: [PATCH 5/7] add 2.1 links --- stix2/v21/bundle.py | 3 +- stix2/v21/common.py | 21 +++----- stix2/v21/observables.py | 107 +++++++++++++-------------------------- stix2/v21/sdo.py | 54 +++++++------------- stix2/v21/sro.py | 6 +-- 5 files changed, 64 insertions(+), 127 deletions(-) diff --git a/stix2/v21/bundle.py b/stix2/v21/bundle.py index 168771f..574ab48 100644 --- a/stix2/v21/bundle.py +++ b/stix2/v21/bundle.py @@ -9,9 +9,8 @@ from ..properties import ( class Bundle(_STIXBase): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'bundle' diff --git a/stix2/v21/common.py b/stix2/v21/common.py index ac8daf1..373a7fc 100644 --- a/stix2/v21/common.py +++ b/stix2/v21/common.py @@ -16,9 +16,8 @@ from ..utils import NOW, _get_dict class ExternalReference(_STIXBase): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _properties = OrderedDict([ @@ -51,9 +50,8 @@ class ExternalReference(_STIXBase): class KillChainPhase(_STIXBase): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _properties = OrderedDict([ @@ -63,9 +61,8 @@ class KillChainPhase(_STIXBase): class GranularMarking(_STIXBase): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _properties = OrderedDict([ @@ -80,9 +77,8 @@ class GranularMarking(_STIXBase): class LanguageContent(_STIXBase): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'language-content' @@ -108,9 +104,8 @@ class LanguageContent(_STIXBase): class TLPMarking(_STIXBase): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'tlp' @@ -120,9 +115,8 @@ class TLPMarking(_STIXBase): class StatementMarking(_STIXBase): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'statement' @@ -151,9 +145,8 @@ class MarkingProperty(Property): class MarkingDefinition(_STIXBase, _MarkingsMixin): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'marking-definition' diff --git a/stix2/v21/observables.py b/stix2/v21/observables.py index 88f1ff7..89de0fc 100644 --- a/stix2/v21/observables.py +++ b/stix2/v21/observables.py @@ -22,9 +22,8 @@ from .common import GranularMarking class Artifact(_Observable): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'artifact' @@ -52,9 +51,8 @@ class Artifact(_Observable): class AutonomousSystem(_Observable): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'autonomous-system' @@ -74,9 +72,8 @@ class AutonomousSystem(_Observable): class Directory(_Observable): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'directory' @@ -100,9 +97,8 @@ class Directory(_Observable): class DomainName(_Observable): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'domain-name' @@ -121,9 +117,8 @@ class DomainName(_Observable): class EmailAddress(_Observable): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'email-addr' @@ -143,9 +138,8 @@ class EmailAddress(_Observable): class EmailMIMEComponent(_STIXBase): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _properties = OrderedDict([ @@ -161,9 +155,8 @@ class EmailMIMEComponent(_STIXBase): class EmailMessage(_Observable): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'email-message' @@ -202,9 +195,8 @@ class EmailMessage(_Observable): class ArchiveExt(_Extension): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'archive-ext' @@ -215,9 +207,8 @@ class ArchiveExt(_Extension): class AlternateDataStream(_STIXBase): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _properties = OrderedDict([ @@ -228,9 +219,8 @@ class AlternateDataStream(_STIXBase): class NTFSExt(_Extension): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'ntfs-ext' @@ -241,9 +231,8 @@ class NTFSExt(_Extension): class PDFExt(_Extension): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'pdf-ext' @@ -257,9 +246,8 @@ class PDFExt(_Extension): class RasterImageExt(_Extension): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'raster-image-ext' @@ -272,9 +260,8 @@ class RasterImageExt(_Extension): class WindowsPEOptionalHeaderType(_STIXBase): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _properties = OrderedDict([ @@ -317,9 +304,8 @@ class WindowsPEOptionalHeaderType(_STIXBase): class WindowsPESection(_STIXBase): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _properties = OrderedDict([ @@ -331,9 +317,8 @@ class WindowsPESection(_STIXBase): class WindowsPEBinaryExt(_Extension): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'windows-pebinary-ext' @@ -354,9 +339,8 @@ class WindowsPEBinaryExt(_Extension): class File(_Observable): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'file' @@ -390,9 +374,8 @@ class File(_Observable): class IPv4Address(_Observable): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'ipv4-addr' @@ -412,9 +395,8 @@ class IPv4Address(_Observable): class IPv6Address(_Observable): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'ipv6-addr' @@ -434,9 +416,8 @@ class IPv6Address(_Observable): class MACAddress(_Observable): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'mac-addr' @@ -454,9 +435,8 @@ class MACAddress(_Observable): class Mutex(_Observable): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'mutex' @@ -474,9 +454,8 @@ class Mutex(_Observable): class HTTPRequestExt(_Extension): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'http-request-ext' @@ -493,7 +472,7 @@ class HTTPRequestExt(_Extension): class ICMPExt(_Extension): # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'icmp-ext' @@ -504,9 +483,8 @@ class ICMPExt(_Extension): class SocketExt(_Extension): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'socket-ext' @@ -566,9 +544,8 @@ class SocketExt(_Extension): class TCPExt(_Extension): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'tcp-ext' @@ -579,9 +556,8 @@ class TCPExt(_Extension): class NetworkTraffic(_Observable): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'network-traffic' @@ -635,9 +611,8 @@ class NetworkTraffic(_Observable): class WindowsProcessExt(_Extension): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'windows-process-ext' @@ -660,9 +635,8 @@ class WindowsProcessExt(_Extension): class WindowsServiceExt(_Extension): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'windows-service-ext' @@ -704,9 +678,8 @@ class WindowsServiceExt(_Extension): class Process(_Observable): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'process' @@ -749,9 +722,8 @@ class Process(_Observable): class Software(_Observable): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'software' @@ -774,9 +746,8 @@ class Software(_Observable): class URL(_Observable): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'url' @@ -794,9 +765,8 @@ class URL(_Observable): class UNIXAccountExt(_Extension): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'unix-account-ext' @@ -809,9 +779,8 @@ class UNIXAccountExt(_Extension): class UserAccount(_Observable): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'user-account' @@ -842,9 +811,8 @@ class UserAccount(_Observable): class WindowsRegistryValueType(_STIXBase): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'windows-registry-value-type' @@ -872,9 +840,8 @@ class WindowsRegistryValueType(_STIXBase): class WindowsRegistryKey(_Observable): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'windows-registry-key' @@ -897,9 +864,8 @@ class WindowsRegistryKey(_Observable): class X509V3ExtenstionsType(_STIXBase): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'x509-v3-extensions-type' @@ -924,9 +890,8 @@ class X509V3ExtenstionsType(_STIXBase): class X509Certificate(_Observable): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'x509-certificate' diff --git a/stix2/v21/sdo.py b/stix2/v21/sdo.py index f2dc0ea..3253a02 100644 --- a/stix2/v21/sdo.py +++ b/stix2/v21/sdo.py @@ -22,9 +22,8 @@ from .common import ExternalReference, GranularMarking, KillChainPhase class AttackPattern(STIXDomainObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'attack-pattern' @@ -50,9 +49,8 @@ class AttackPattern(STIXDomainObject): class Campaign(STIXDomainObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'campaign' @@ -90,9 +88,8 @@ class Campaign(STIXDomainObject): class CourseOfAction(STIXDomainObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'course-of-action' @@ -116,9 +113,8 @@ class CourseOfAction(STIXDomainObject): class Grouping(STIXDomainObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'grouping' @@ -144,9 +140,8 @@ class Grouping(STIXDomainObject): class Identity(STIXDomainObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'identity' @@ -174,9 +169,8 @@ class Identity(STIXDomainObject): class Indicator(STIXDomainObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'indicator' @@ -234,9 +228,8 @@ class Indicator(STIXDomainObject): class Infrastructure(STIXDomainObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'infrastructure' @@ -275,9 +268,8 @@ class Infrastructure(STIXDomainObject): class IntrusionSet(STIXDomainObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'intrusion-set' @@ -318,9 +310,8 @@ class IntrusionSet(STIXDomainObject): class Location(STIXDomainObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'location' @@ -426,9 +417,8 @@ class Location(STIXDomainObject): class Malware(STIXDomainObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'malware' @@ -479,9 +469,8 @@ class Malware(STIXDomainObject): class MalwareAnalysis(STIXDomainObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'malware-analysis' @@ -524,9 +513,8 @@ class MalwareAnalysis(STIXDomainObject): class Note(STIXDomainObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'note' @@ -552,9 +540,8 @@ class Note(STIXDomainObject): class ObservedData(STIXDomainObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'observed-data' @@ -608,9 +595,8 @@ class ObservedData(STIXDomainObject): class Opinion(STIXDomainObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'opinion' @@ -646,9 +632,8 @@ class Opinion(STIXDomainObject): class Report(STIXDomainObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'report' @@ -675,9 +660,8 @@ class Report(STIXDomainObject): class ThreatActor(STIXDomainObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'threat-actor' @@ -722,9 +706,8 @@ class ThreatActor(STIXDomainObject): class Tool(STIXDomainObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'tool' @@ -752,9 +735,8 @@ class Tool(STIXDomainObject): class Vulnerability(STIXDomainObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'vulnerability' diff --git a/stix2/v21/sro.py b/stix2/v21/sro.py index 059bb66..30320b3 100644 --- a/stix2/v21/sro.py +++ b/stix2/v21/sro.py @@ -12,9 +12,8 @@ from .common import ExternalReference, GranularMarking class Relationship(STIXRelationshipObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _invalid_source_target_types = ['bundle', 'language-content', 'marking-definition', 'relationship', 'sighting'] @@ -69,9 +68,8 @@ class Relationship(STIXRelationshipObject): class Sighting(STIXRelationshipObject): - # TODO: Add link """For more detailed information on this object's properties, see - `the STIX 2.1 specification `__. + `the STIX 2.1 specification `__. """ _type = 'sighting' From c911cff97fe9d89855c83e805f0702f2d9bdc02e Mon Sep 17 00:00:00 2001 From: "Desai, Kartikey H" Date: Fri, 27 Mar 2020 14:58:18 -0400 Subject: [PATCH 6/7] Add duplicate checking to markings and observable extensions, and fix some tests and add some tests. Fixes #363 --- stix2/core.py | 13 +++++-- stix2/exceptions.py | 14 +++++--- stix2/test/v20/test_core.py | 53 ---------------------------- stix2/test/v20/test_custom.py | 65 ++++++++++++++++++++++++++++++++--- stix2/test/v21/test_core.py | 43 ----------------------- stix2/test/v21/test_custom.py | 56 ++++++++++++++++++++++++++---- 6 files changed, 129 insertions(+), 115 deletions(-) diff --git a/stix2/core.py b/stix2/core.py index ffe77f2..2f8de3e 100644 --- a/stix2/core.py +++ b/stix2/core.py @@ -8,7 +8,7 @@ import re import stix2 from .base import _Observable, _STIXBase -from .exceptions import DuplicateObjectRegistrationError, ParseError +from .exceptions import DuplicateRegistrationError, ParseError from .markings import _MarkingsMixin from .utils import SCO21_EXT_REGEX, TYPE_REGEX, _get_dict @@ -218,7 +218,7 @@ def _register_object(new_type, version=None): OBJ_MAP = STIX2_OBJ_MAPS[v]['objects'] if new_type._type in OBJ_MAP.keys(): - raise DuplicateObjectRegistrationError("An object with type '%s' already exists and cannot be created again." % new_type._type) + raise DuplicateRegistrationError("STIX Object", new_type._type) OBJ_MAP[new_type._type] = new_type @@ -238,6 +238,8 @@ def _register_marking(new_marking, version=None): v = 'v' + stix2.DEFAULT_VERSION.replace('.', '') OBJ_MAP_MARKING = STIX2_OBJ_MAPS[v]['markings'] + if new_marking._type in OBJ_MAP_MARKING.keys(): + raise DuplicateRegistrationError("STIX Marking", new_marking._type) OBJ_MAP_MARKING[new_marking._type] = new_marking @@ -258,7 +260,7 @@ def _register_observable(new_observable, version=None): OBJ_MAP_OBSERVABLE = STIX2_OBJ_MAPS[v]['observables'] if new_observable._type in OBJ_MAP_OBSERVABLE.keys(): - raise DuplicateObjectRegistrationError("An observable with type '%s' already exists and cannot be created again." % new_observable._type) + raise DuplicateRegistrationError("Cyber Observable", new_observable._type) OBJ_MAP_OBSERVABLE[new_observable._type] = new_observable @@ -323,6 +325,11 @@ def _register_observable_extension( EXT_MAP = STIX2_OBJ_MAPS[v]['observable-extensions'] try: + try: + if ext_type in EXT_MAP[observable_type].keys(): + raise DuplicateRegistrationError("Observable Extension", ext_type) + except AttributeError: + pass EXT_MAP[observable_type][ext_type] = new_extension except KeyError: if observable_type not in OBJ_MAP_OBSERVABLE: diff --git a/stix2/exceptions.py b/stix2/exceptions.py index f65f48b..edcc352 100644 --- a/stix2/exceptions.py +++ b/stix2/exceptions.py @@ -235,8 +235,14 @@ class STIXDeprecationWarning(DeprecationWarning): pass -class DuplicateObjectRegistrationError(STIXError): - """An object (or observable) with the same type as an existing object (or observable) is being registered""" +class DuplicateRegistrationError(STIXError): + """A STIX object with the same type as an existing object is being registered""" - def __init__(self, msg): - super(DuplicateObjectRegistrationError, self).__init__(msg) + def __init__(self, obj_type, reg_obj_type): + super(DuplicateRegistrationError, self).__init__() + self.obj_type = obj_type + self.reg_obj_type = reg_obj_type + + def __str__(self): + msg = "A(n) {0} with type '{1}' already exists and cannot be registered again" + return msg.format(self.obj_type, self.reg_obj_type) diff --git a/stix2/test/v20/test_core.py b/stix2/test/v20/test_core.py index 2808ba5..080c6f6 100644 --- a/stix2/test/v20/test_core.py +++ b/stix2/test/v20/test_core.py @@ -3,8 +3,6 @@ import pytest import stix2 from stix2 import core, exceptions -from .constants import IDENTITY_ID - BUNDLE = { "type": "bundle", "spec_version": "2.0", @@ -74,54 +72,3 @@ def test_register_marking_with_version(): assert stix2.v20.TLP_WHITE.definition._type in core.STIX2_OBJ_MAPS[v]['markings'] assert v in str(stix2.v20.TLP_WHITE.__class__) - - -@pytest.mark.xfail(reason="The default version is no longer 2.0", condition=stix2.DEFAULT_VERSION != "2.0") -def test_register_marking_with_no_version(): - # Uses default version (2.0 in this case) - core._register_marking(stix2.v20.TLP_WHITE.__class__) - v = 'v20' - - assert stix2.v20.TLP_WHITE.definition._type in core.STIX2_OBJ_MAPS[v]['markings'] - assert v in str(stix2.v20.TLP_WHITE.__class__) - - -def test_register_observable_extension_with_version(): - observed_data = stix2.v20.ObservedData( - id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", - created_by_ref=IDENTITY_ID, - created="2016-04-06T19:58:16.000Z", - modified="2016-04-06T19:58:16.000Z", - first_observed="2015-12-21T19:00:00Z", - last_observed="2015-12-21T19:00:00Z", - number_observed=50, - objects={ - "0": { - "name": "foo.exe", - "type": "file", - "extensions": { - "ntfs-ext": { - "alternate_data_streams": [ - { - "name": "second.stream", - "size": 25536, - }, - ], - }, - }, - }, - "1": { - "type": "directory", - "path": "/usr/home", - "contains_refs": ["0"], - }, - }, - ) - core._register_observable_extension(observed_data.objects['0'], observed_data.objects['0'].extensions['ntfs-ext'].__class__, version='2.0') - v = 'v20' - - assert observed_data.objects['0'].type in core.STIX2_OBJ_MAPS[v]['observables'] - assert v in str(observed_data.objects['0'].__class__) - - assert observed_data.objects['0'].extensions['ntfs-ext']._type in core.STIX2_OBJ_MAPS[v]['observable-extensions']['file'] - assert v in str(observed_data.objects['0'].extensions['ntfs-ext'].__class__) diff --git a/stix2/test/v20/test_custom.py b/stix2/test/v20/test_custom.py index 19cb28a..4aee66e 100644 --- a/stix2/test/v20/test_custom.py +++ b/stix2/test/v20/test_custom.py @@ -4,7 +4,7 @@ import stix2 from stix2 import core import stix2.v20 -from ...exceptions import DuplicateObjectRegistrationError, InvalidValueError +from ...exceptions import DuplicateRegistrationError, InvalidValueError from .constants import FAKE_TIME, IDENTITY_ID, MARKING_DEFINITION_ID IDENTITY_CUSTOM_PROP = stix2.v20.Identity( @@ -1040,7 +1040,7 @@ def test_register_custom_object_with_version(): def test_register_duplicate_object_with_version(): - with pytest.raises(DuplicateObjectRegistrationError) as excinfo: + with pytest.raises(DuplicateRegistrationError) as excinfo: @stix2.v20.CustomObject( 'x-new-type-2', [ ('property1', stix2.properties.StringProperty()), @@ -1049,7 +1049,7 @@ def test_register_duplicate_object_with_version(): ) class NewType2(object): pass - assert "An object with type 'x-new-type-2' already exists and cannot be created again." in str(excinfo.value) + assert "cannot be registered again" in str(excinfo.value) @stix2.v20.CustomObservable( @@ -1069,7 +1069,7 @@ def test_register_observable_with_version(): def test_register_duplicate_observable_with_version(): - with pytest.raises(DuplicateObjectRegistrationError) as excinfo: + with pytest.raises(DuplicateRegistrationError) as excinfo: @stix2.v20.CustomObservable( 'x-new-observable-2', [ ('property1', stix2.properties.StringProperty()), @@ -1077,4 +1077,59 @@ def test_register_duplicate_observable_with_version(): ) class NewObservable2(object): pass - assert "An observable with type 'x-new-observable-2' already exists and cannot be created again." in str(excinfo.value) + assert "cannot be registered again" in str(excinfo.value) + + +@pytest.mark.xfail(reason="The default version is no longer 2.0", condition=stix2.DEFAULT_VERSION != "2.0") +def test_register_marking_with_no_version(): + @stix2.v20.CustomMarking( + 'x-new-obj-2', [ + ('property1', stix2.properties.StringProperty(required=True)), + ], + ) + class NewObj2(): + pass + v = 'v20' + + no = NewObj2(property1='something') + assert no._type in core.STIX2_OBJ_MAPS[v]['markings'] + + +def test_register_observable_extension_with_version(): + @stix2.v20.CustomExtension( + stix2.v20.UserAccount, 'some-extension-2', [ + ('keys', stix2.properties.StringProperty(required=True)), + ], + ) + class SomeCustomExtension2: + pass + + v = 'v20' + example = SomeCustomExtension2(keys='test123') + + assert example._type in core.STIX2_OBJ_MAPS[v]['observable-extensions']['user-account'] + + +def test_register_duplicate_observable_extension(): + with pytest.raises(DuplicateRegistrationError) as excinfo: + @stix2.v20.CustomExtension( + stix2.v20.UserAccount, 'some-extension-2', [ + ('property1', stix2.properties.StringProperty(required=True)), + ('property2', stix2.properties.IntegerProperty()), + ], + ) + class NewExtension2(): + pass + assert "cannot be registered again" in str(excinfo.value) + + +def test_register_duplicate_marking(): + with pytest.raises(DuplicateRegistrationError) as excinfo: + @stix2.v20.CustomMarking( + 'x-new-obj-2', [ + ('property1', stix2.properties.StringProperty(required=True)), + ], + ) + class NewObj2(): + pass + assert "cannot be registered again" in str(excinfo.value) diff --git a/stix2/test/v21/test_core.py b/stix2/test/v21/test_core.py index f9f9de6..78e492a 100644 --- a/stix2/test/v21/test_core.py +++ b/stix2/test/v21/test_core.py @@ -3,8 +3,6 @@ import pytest import stix2 from stix2 import core, exceptions -from .constants import IDENTITY_ID, OBSERVED_DATA_ID - BUNDLE = { "type": "bundle", "id": "bundle--00000000-0000-4000-8000-000000000007", @@ -89,44 +87,3 @@ def test_register_marking_with_no_version(): assert stix2.v21.TLP_WHITE.definition._type in core.STIX2_OBJ_MAPS[v]['markings'] assert v in str(stix2.v21.TLP_WHITE.__class__) - - -def test_register_observable_extension_with_default_version(): - observed_data = stix2.v21.ObservedData( - id=OBSERVED_DATA_ID, - created_by_ref=IDENTITY_ID, - created="2016-04-06T19:58:16.000Z", - modified="2016-04-06T19:58:16.000Z", - first_observed="2015-12-21T19:00:00Z", - last_observed="2015-12-21T19:00:00Z", - number_observed=50, - objects={ - "0": { - "name": "foo.exe", - "type": "file", - "extensions": { - "ntfs-ext": { - "alternate_data_streams": [ - { - "name": "second.stream", - "size": 25536, - }, - ], - }, - }, - }, - "1": { - "type": "directory", - "path": "/usr/home", - "contains_refs": ["file--420bc087-8b53-5ae9-8210-20d27d5e96c8"], - }, - }, - ) - core._register_observable_extension(observed_data.objects['0'], observed_data.objects['0'].extensions['ntfs-ext'].__class__) - v = 'v21' - - assert observed_data.objects['0'].type in core.STIX2_OBJ_MAPS[v]['observables'] - assert v in str(observed_data.objects['0'].__class__) - - assert observed_data.objects['0'].extensions['ntfs-ext']._type in core.STIX2_OBJ_MAPS[v]['observable-extensions']['file'] - assert v in str(observed_data.objects['0'].extensions['ntfs-ext'].__class__) diff --git a/stix2/test/v21/test_custom.py b/stix2/test/v21/test_custom.py index 92cacf3..4522463 100644 --- a/stix2/test/v21/test_custom.py +++ b/stix2/test/v21/test_custom.py @@ -6,7 +6,7 @@ import stix2 import stix2.base import stix2.v21 -from ...exceptions import DuplicateObjectRegistrationError, InvalidValueError +from ...exceptions import DuplicateRegistrationError, InvalidValueError from .constants import FAKE_TIME, IDENTITY_ID, MARKING_DEFINITION_ID IDENTITY_CUSTOM_PROP = stix2.v21.Identity( @@ -1092,7 +1092,7 @@ def test_register_custom_object_with_version(): def test_register_duplicate_object_with_version(): - with pytest.raises(DuplicateObjectRegistrationError) as excinfo: + with pytest.raises(DuplicateRegistrationError) as excinfo: @stix2.v21.CustomObject( 'x-new-type-2', [ ('property1', stix2.properties.StringProperty()), @@ -1101,7 +1101,7 @@ def test_register_duplicate_object_with_version(): ) class NewType2(object): pass - assert "An object with type 'x-new-type-2' already exists and cannot be created again." in str(excinfo.value) + assert "cannot be registered again" in str(excinfo.value) @stix2.v21.CustomObservable( @@ -1113,15 +1113,15 @@ class NewObservable3(object): pass -def test_register_observable_with_version(): +def test_register_observable(): custom_obs = NewObservable3(property1="Test Observable") v = 'v21' assert custom_obs.type in stix2.core.STIX2_OBJ_MAPS[v]['observables'] -def test_register_duplicate_observable_with_version(): - with pytest.raises(DuplicateObjectRegistrationError) as excinfo: +def test_register_duplicate_observable(): + with pytest.raises(DuplicateRegistrationError) as excinfo: @stix2.v21.CustomObservable( 'x-new-observable-2', [ ('property1', stix2.properties.StringProperty()), @@ -1129,4 +1129,46 @@ def test_register_duplicate_observable_with_version(): ) class NewObservable2(object): pass - assert "An observable with type 'x-new-observable-2' already exists and cannot be created again." in str(excinfo.value) + assert "cannot be registered again" in str(excinfo.value) + + +def test_register_observable_custom_extension(): + @stix2.v21.CustomExtension( + stix2.v21.DomainName, 'x-new-2-ext', [ + ('property1', stix2.properties.StringProperty(required=True)), + ('property2', stix2.properties.IntegerProperty()), + ], + ) + class NewExtension2(): + pass + + example = NewExtension2(property1="Hi there") + v = 'v21' + + assert 'domain-name' in stix2.core.STIX2_OBJ_MAPS[v]['observables'] + assert example._type in stix2.core.STIX2_OBJ_MAPS[v]['observable-extensions']['domain-name'] + + +def test_register_duplicate_observable_extension(): + with pytest.raises(DuplicateRegistrationError) as excinfo: + @stix2.v21.CustomExtension( + stix2.v21.DomainName, 'x-new-2-ext', [ + ('property1', stix2.properties.StringProperty(required=True)), + ('property2', stix2.properties.IntegerProperty()), + ], + ) + class NewExtension2(): + pass + assert "cannot be registered again" in str(excinfo.value) + + +def test_register_duplicate_marking(): + with pytest.raises(DuplicateRegistrationError) as excinfo: + @stix2.v21.CustomMarking( + 'x-new-obj', [ + ('property1', stix2.properties.StringProperty(required=True)), + ], + ) + class NewObj2(): + pass + assert "cannot be registered again" in str(excinfo.value) From 897e884217e93aa2b3bc76cb6bf242be71400683 Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Thu, 2 Apr 2020 04:46:11 -0400 Subject: [PATCH 7/7] Fix some testing --- .travis.yml | 2 +- stix2/core.py | 7 ++----- stix2/test/v20/test_custom.py | 3 +-- tox.ini | 4 ++-- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 018aefe..81141d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -sudo: false +os: linux language: python cache: pip dist: xenial diff --git a/stix2/core.py b/stix2/core.py index 2f8de3e..dd7aac1 100644 --- a/stix2/core.py +++ b/stix2/core.py @@ -325,11 +325,8 @@ def _register_observable_extension( EXT_MAP = STIX2_OBJ_MAPS[v]['observable-extensions'] try: - try: - if ext_type in EXT_MAP[observable_type].keys(): - raise DuplicateRegistrationError("Observable Extension", ext_type) - except AttributeError: - pass + if ext_type in EXT_MAP[observable_type].keys(): + raise DuplicateRegistrationError("Observable Extension", ext_type) EXT_MAP[observable_type][ext_type] = new_extension except KeyError: if observable_type not in OBJ_MAP_OBSERVABLE: diff --git a/stix2/test/v20/test_custom.py b/stix2/test/v20/test_custom.py index 4aee66e..346f06b 100644 --- a/stix2/test/v20/test_custom.py +++ b/stix2/test/v20/test_custom.py @@ -1080,8 +1080,7 @@ def test_register_duplicate_observable_with_version(): assert "cannot be registered again" in str(excinfo.value) -@pytest.mark.xfail(reason="The default version is no longer 2.0", condition=stix2.DEFAULT_VERSION != "2.0") -def test_register_marking_with_no_version(): +def test_register_marking_with_version(): @stix2.v20.CustomMarking( 'x-new-obj-2', [ ('property1', stix2.properties.StringProperty(required=True)), diff --git a/tox.ini b/tox.ini index d34aac1..aa0472a 100644 --- a/tox.ini +++ b/tox.ini @@ -8,11 +8,11 @@ deps = pytest pytest-cov coverage - taxii2-client + taxii2-client<1.0.0 fuzzywuzzy haversine python-Levenshtein - medallion + medallion<2.0.0 commands = python -m pytest --cov=stix2 stix2/test/ --cov-report term-missing -W ignore::stix2.exceptions.STIXDeprecationWarning