From ef2ef95c3a79fdc296ba3eacd8da6321e1778c74 Mon Sep 17 00:00:00 2001 From: Emmanuelle Vargas-Gonzalez Date: Tue, 22 Dec 2020 21:59:18 -0500 Subject: [PATCH] `stix-extension` to `extension-definition` --- stix2/base.py | 2 +- stix2/parsing.py | 6 +-- stix2/properties.py | 4 +- stix2/test/v21/test_custom.py | 86 +++++++++++++++++++---------------- stix2/v21/__init__.py | 14 +++--- stix2/v21/common.py | 4 +- 6 files changed, 61 insertions(+), 55 deletions(-) diff --git a/stix2/base.py b/stix2/base.py index 1ff4608..bd59fc5 100644 --- a/stix2/base.py +++ b/stix2/base.py @@ -134,7 +134,7 @@ class _STIXBase(Mapping): if extra_kwargs and not self._allow_custom: ext_found = False for key_id, ext_def in kwargs.get('extensions', {}).items(): - if key_id.startswith('stix-extension--'): + if key_id.startswith('extension-definition--'): ext_found = True break if ext_found is False: diff --git a/stix2/parsing.py b/stix2/parsing.py index ad66665..77a04d9 100644 --- a/stix2/parsing.py +++ b/stix2/parsing.py @@ -144,7 +144,7 @@ def dict_to_stix2(stix_dict, allow_custom=False, version=None): # be parsed into STIX object, returned as is return stix_dict for key_id, ext_def in stix_dict.get('extensions', {}).items(): - if key_id.startswith('stix-extension--') and ext_def.get('extension_type', None): + if key_id.startswith('extension-definition--') and ext_def.get('extension_type', None): # prevents ParseError for unregistered objects when # 'is_new_object' or 'is_extension_so' are set to True and allow_custom=False return stix_dict @@ -352,9 +352,9 @@ def _register_extension( ) if version == "2.1": - if not (ext_type.endswith('-ext') or ext_type.startswith('stix-extension--')): + if not (ext_type.endswith('-ext') or ext_type.startswith('extension-definition--')): raise ValueError( - "Invalid extension type name '%s': must end with '-ext' or start with 'stix-extension--'." % + "Invalid extension type name '%s': must end with '-ext' or start with 'extension-definition--'." % ext_type, ) diff --git a/stix2/properties.py b/stix2/properties.py index cea664f..732a7dd 100644 --- a/stix2/properties.py +++ b/stix2/properties.py @@ -672,8 +672,8 @@ class ExtensionsProperty(DictionaryProperty): else: if self.allow_custom: dictified[key] = subvalue - elif key.startswith('stix-extension--'): - _validate_id(key, '2.1', 'stix-extension') + elif key.startswith('extension-definition--'): + _validate_id(key, '2.1', 'extension-definition') dictified[key] = subvalue else: raise CustomContentError("Can't parse unknown extension type: {}".format(key)) diff --git a/stix2/test/v21/test_custom.py b/stix2/test/v21/test_custom.py index aecbb0f..a2e41b2 100644 --- a/stix2/test/v21/test_custom.py +++ b/stix2/test/v21/test_custom.py @@ -1314,15 +1314,16 @@ def test_unregistered_top_level_extension_passes_with_allow_custom_false(): pattern_type='stix', valid_from='2014-02-20T09:00:00.000000Z', extensions={ - 'stix-extension--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e': { - 'extends_stix_object_definition': True, + 'extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e': { + 'extension_type': 'toplevel-property-extension', }, }, allow_custom=False, ) assert indicator.rank == 5 assert indicator.toxicity == 8 - assert isinstance(indicator.extensions['stix-extension--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e'], dict) + assert indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e']['extension_type'] == 'toplevel-property-extension' + assert isinstance(indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e'], dict) def test_unregistered_embedded_extension_passes_with_allow_custom_false(): @@ -1339,27 +1340,29 @@ def test_unregistered_embedded_extension_passes_with_allow_custom_false(): pattern_type='stix', valid_from='2014-02-20T09:00:00.000000Z', extensions={ - 'stix-extension--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e': { + 'extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e': { + 'extension_type': 'property-extension', 'rank': 5, 'toxicity': 8, }, }, allow_custom=False, ) - assert indicator.extensions['stix-extension--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e']['rank'] == 5 - assert indicator.extensions['stix-extension--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e']['toxicity'] == 8 - assert isinstance(indicator.extensions['stix-extension--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e'], dict) + assert indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e']['rank'] == 5 + assert indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e']['toxicity'] == 8 + assert indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e']['extension_type'] == 'property-extension' + assert isinstance(indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e'], dict) def test_registered_top_level_extension_passes_with_allow_custom_false(): @stix2.v21.CustomExtension( - 'stix-extension--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e', [ - ('rank', stix2.properties.IntegerProperty(required=True)), - ('toxicity', stix2.properties.IntegerProperty(required=True)), + 'extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e', [ + ('rank', stix2.properties.IntegerProperty(required=True)), + ('toxicity', stix2.properties.IntegerProperty(required=True)), ], ) class ExtensionFoo1: - extends_stix_object_definition = True + extension_type = 'toplevel-property-extension' indicator = stix2.v21.Indicator( id='indicator--e97bfccf-8970-4a3c-9cd1-5b5b97ed5d0c', @@ -1376,22 +1379,23 @@ def test_registered_top_level_extension_passes_with_allow_custom_false(): pattern_type='stix', valid_from='2014-02-20T09:00:00.000000Z', extensions={ - 'stix-extension--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e': { - 'extends_stix_object_definition': True, + 'extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e': { + 'extension_type': 'toplevel-property-extension', }, }, allow_custom=False, ) assert indicator.rank == 5 assert indicator.toxicity == 8 - assert isinstance(indicator.extensions['stix-extension--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e'], ExtensionFoo1) + assert indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e']['extension_type'] == 'toplevel-property-extension' + assert isinstance(indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e98c6e'], ExtensionFoo1) def test_registered_embedded_extension_passes_with_allow_custom_false(): @stix2.v21.CustomExtension( - 'stix-extension--d83fce45-ef58-4c6c-a3ff-1fbc32e98c6e', [ - ('rank', stix2.properties.IntegerProperty(required=True)), - ('toxicity', stix2.properties.IntegerProperty(required=True)), + 'extension-definition--d83fce45-ef58-4c6c-a3ff-1fbc32e98c6e', [ + ('rank', stix2.properties.IntegerProperty(required=True)), + ('toxicity', stix2.properties.IntegerProperty(required=True)), ], ) class ExtensionFoo1: @@ -1410,16 +1414,18 @@ def test_registered_embedded_extension_passes_with_allow_custom_false(): pattern_type='stix', valid_from='2014-02-20T09:00:00.000000Z', extensions={ - 'stix-extension--d83fce45-ef58-4c6c-a3ff-1fbc32e98c6e': { + 'extension-definition--d83fce45-ef58-4c6c-a3ff-1fbc32e98c6e': { + 'extension_type': 'property-extension', 'rank': 5, 'toxicity': 8, }, }, allow_custom=False, ) - assert indicator.extensions['stix-extension--d83fce45-ef58-4c6c-a3ff-1fbc32e98c6e']['rank'] == 5 - assert indicator.extensions['stix-extension--d83fce45-ef58-4c6c-a3ff-1fbc32e98c6e']['toxicity'] == 8 - assert isinstance(indicator.extensions['stix-extension--d83fce45-ef58-4c6c-a3ff-1fbc32e98c6e'], ExtensionFoo1) + assert indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3ff-1fbc32e98c6e']['rank'] == 5 + assert indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3ff-1fbc32e98c6e']['toxicity'] == 8 + assert indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3ff-1fbc32e98c6e']['extension_type'] == 'property-extension' + assert isinstance(indicator.extensions['extension-definition--d83fce45-ef58-4c6c-a3ff-1fbc32e98c6e'], ExtensionFoo1) def test_registered_new_extension_sdo_allow_custom_false(): @@ -1428,7 +1434,7 @@ def test_registered_new_extension_sdo_allow_custom_false(): ('name', stix2.properties.StringProperty(required=True)), ('some_property_name1', stix2.properties.StringProperty(required=True)), ('some_property_name2', stix2.properties.StringProperty()), - ], 'stix-extension--d83fce45-ef58-4c6c-a3f4-1fbc32e9999', + ], 'extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e9999', ) class MyFavSDO: pass @@ -1443,18 +1449,18 @@ def test_registered_new_extension_sdo_allow_custom_false(): 'some_property_name1': 'value1', 'some_property_name2': 'value2', # 'extensions': { - # 'stix-extension--d83fce45-ef58-4c6c-a3f4-1fbc32e9999': STIXExtensiond83fce45ef584c6ca3f41fbc32e98c6e() + # 'extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e9999': STIXExtensiond83fce45ef584c6ca3f41fbc32e98c6e() # } } sdo_object = stix2.parse(my_favorite_sdo) assert isinstance(sdo_object, MyFavSDO) assert isinstance( - sdo_object.extensions['stix-extension--d83fce45-ef58-4c6c-a3f4-1fbc32e9999'], - stix2.v21.EXT_MAP['stix-extension--d83fce45-ef58-4c6c-a3f4-1fbc32e9999'], + sdo_object.extensions['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e9999'], + stix2.v21.EXT_MAP['extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e9999'], ) sdo_serialized = sdo_object.serialize() - assert '"extensions": {"stix-extension--d83fce45-ef58-4c6c-a3f4-1fbc32e9999": {"is_new_object": true}}' in sdo_serialized + assert '"extensions": {"extension-definition--d83fce45-ef58-4c6c-a3f4-1fbc32e9999": {"extension_type": "new-sdo"}}' in sdo_serialized def test_registered_new_extension_sco_allow_custom_false(): @@ -1462,7 +1468,7 @@ def test_registered_new_extension_sco_allow_custom_false(): 'my-favorite-sco', [ ('name', stix2.properties.StringProperty(required=True)), ('some_network_protocol_field', stix2.properties.StringProperty(required=True)), - ], ['name', 'some_network_protocol_field'], 'stix-extension--a932fcc6-e032-177c-126f-cb970a5a1fff', + ], ['name', 'some_network_protocol_field'], 'extension-definition--a932fcc6-e032-177c-126f-cb970a5a1fff', ) class MyFavSCO: pass @@ -1474,7 +1480,7 @@ def test_registered_new_extension_sco_allow_custom_false(): 'name': 'This is the name of my favorite SCO', 'some_network_protocol_field': 'value', # 'extensions': { - # 'stix-extension--a932fcc6-e032-177c-126f-cb970a5a1fff': { + # 'extension-definition--a932fcc6-e032-177c-126f-cb970a5a1fff': { # 'is_extension_so': true # } # } @@ -1483,20 +1489,19 @@ def test_registered_new_extension_sco_allow_custom_false(): sco_object = stix2.parse(my_favorite_sco) assert isinstance(sco_object, MyFavSCO) assert isinstance( - sco_object.extensions['stix-extension--a932fcc6-e032-177c-126f-cb970a5a1fff'], - stix2.v21.EXT_MAP['stix-extension--a932fcc6-e032-177c-126f-cb970a5a1fff'], + sco_object.extensions['extension-definition--a932fcc6-e032-177c-126f-cb970a5a1fff'], + stix2.v21.EXT_MAP['extension-definition--a932fcc6-e032-177c-126f-cb970a5a1fff'], ) sco_serialized = sco_object.serialize() - assert '"extensions": {"stix-extension--a932fcc6-e032-177c-126f-cb970a5a1fff": {"is_extension_so": true}}' in sco_serialized + assert '"extensions": {"extension-definition--a932fcc6-e032-177c-126f-cb970a5a1fff": {"extension_type": "new-sco"}}' in sco_serialized def test_registered_new_extension_marking_allow_custom_false(): @stix2.v21.CustomMarking( 'my-favorite-marking', [ - ('name', stix2.properties.StringProperty(required=True)), ('some_marking_field', stix2.properties.StringProperty(required=True)), - ], 'stix-extension--a932fcc6-e032-176c-126f-cb970a5a1fff', + ], 'extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff', ) class MyFavMarking: pass @@ -1506,10 +1511,10 @@ def test_registered_new_extension_marking_allow_custom_false(): 'spec_version': '2.1', 'id': 'marking-definition--f9dbe89c-0030-4a9d-8b78-0dcd0a0de874', 'name': 'This is the name of my favorite Marking', - 'some_marking_field': 'value', 'extensions': { - 'stix-extension--a932fcc6-e032-176c-126f-cb970a5a1fff': { - 'extends_stix_object_definition': True, + 'extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff': { + 'extension_type': 'property-extension', + 'some_marking_field': 'value', }, }, } @@ -1517,9 +1522,10 @@ def test_registered_new_extension_marking_allow_custom_false(): marking_object = stix2.parse(my_favorite_marking) assert isinstance(marking_object, stix2.v21.MarkingDefinition) assert isinstance( - marking_object.extensions['stix-extension--a932fcc6-e032-176c-126f-cb970a5a1fff'], - stix2.v21.EXT_MAP['stix-extension--a932fcc6-e032-176c-126f-cb970a5a1fff'], + marking_object.extensions['extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff'], + stix2.v21.EXT_MAP['extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff'], ) - marking_serialized = marking_object.serialize() - assert '"extensions": {"stix-extension--a932fcc6-e032-176c-126f-cb970a5a1fff": {"extends_stix_object_definition": true}}' in marking_serialized + marking_serialized = marking_object.serialize(sort_keys=True) + assert '"extensions": {"extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff": ' \ + '{"extension_type": "property-extension", "some_marking_field": "value"}}' in marking_serialized diff --git a/stix2/v21/__init__.py b/stix2/v21/__init__.py index be7e343..977fdf7 100644 --- a/stix2/v21/__init__.py +++ b/stix2/v21/__init__.py @@ -19,9 +19,9 @@ from .base import ( ) from .bundle import Bundle from .common import ( - TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, ExternalReference, - GranularMarking, KillChainPhase, LanguageContent, MarkingDefinition, - StatementMarking, STIXExtension, TLPMarking, + TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, + ExtensionDefinition, ExternalReference, GranularMarking, KillChainPhase, + LanguageContent, MarkingDefinition, StatementMarking, TLPMarking, ) from .observables import ( URL, AlternateDataStream, ArchiveExt, Artifact, AutonomousSystem, @@ -66,7 +66,7 @@ OBJ_MAP = { 'threat-actor': ThreatActor, 'tool': Tool, 'sighting': Sighting, - 'stix-extension': STIXExtension, + 'extension-definition': ExtensionDefinition, 'vulnerability': Vulnerability, } @@ -112,9 +112,9 @@ EXT_MAP = { __all__ = """ Bundle, - TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, ExternalReference, - GranularMarking, KillChainPhase, LanguageContent, MarkingDefinition, - StatementMarking, STIXExtension, TLPMarking, + TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, ExtensionDefinition, + ExternalReference, GranularMarking, KillChainPhase, LanguageContent, + MarkingDefinition, StatementMarking, TLPMarking, URL, AlternateDataStream, ArchiveExt, Artifact, AutonomousSystem, CustomExtension, CustomObservable, Directory, DomainName, EmailAddress, diff --git a/stix2/v21/common.py b/stix2/v21/common.py index 06d9c43..4410975 100644 --- a/stix2/v21/common.py +++ b/stix2/v21/common.py @@ -105,12 +105,12 @@ class LanguageContent(_STIXBase21): ]) -class STIXExtension(_STIXBase21): +class ExtensionDefinition(_STIXBase21): """For more detailed information on this object's properties, see `the STIX 2.1 specification `__. """ - _type = 'stix-extension' + _type = 'extension-definition' _properties = OrderedDict([ ('type', TypeProperty(_type, spec_version='2.1')), ('spec_version', StringProperty(fixed='2.1')),