From d27e9e6e557ebf57635bf61dbc955d50ea4c2233 Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Thu, 8 Jul 2021 22:18:28 -0400 Subject: [PATCH 01/11] Back out changes to the CustomMarking decorator and registration, to revert its behavior to what it did before: register a type for old-style non-extension custom markings. --- stix2/custom.py | 5 ----- stix2/v21/common.py | 12 +----------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/stix2/custom.py b/stix2/custom.py index adef7686..7eee49ca 100644 --- a/stix2/custom.py +++ b/stix2/custom.py @@ -53,11 +53,6 @@ class _CustomMarking(cls, base_class): def __init__(self, **kwargs): base_class.__init__(self, **kwargs) _cls_init(cls, self, kwargs) - ext = getattr(self, 'with_extension', None) - if ext and version != '2.0': - if 'extensions' not in self._inner: - self._inner['extensions'] = {} - self._inner['extensions'][ext] = _get_extension_class(ext, version)() _CustomMarking.__name__ = cls.__name__ diff --git a/stix2/v21/common.py b/stix2/v21/common.py index 6ff36b98..55c4a05d 100644 --- a/stix2/v21/common.py +++ b/stix2/v21/common.py @@ -252,7 +252,7 @@ def serialize(self, pretty=False, include_optional_defaults=False, **kwargs): } -def CustomMarking(type='x-custom-marking', properties=None, extension_name=None): +def CustomMarking(type='x-custom-marking', properties=None): """Custom STIX Marking decorator. Example: @@ -267,16 +267,6 @@ def CustomMarking(type='x-custom-marking', properties=None, extension_name=None) """ def wrapper(cls): - if extension_name: - @CustomExtension(type=extension_name, properties=properties) - class NameExtension: - extension_type = 'property-extension' - - extension = extension_name.split('--')[1] - extension = extension.replace('-', '') - NameExtension.__name__ = 'ExtensionDefinition' + extension - cls.with_extension = extension_name - return _custom_marking_builder(cls, type, MarkingDefinition._properties, '2.1', _STIXBase21) return _custom_marking_builder(cls, type, properties, '2.1', _STIXBase21) return wrapper From 34e82e489f8863d0c833bd2341edb8e001e0210d Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Thu, 8 Jul 2021 23:06:57 -0400 Subject: [PATCH 02/11] Fix marking definition extension unit test to use a plain old CustomExtension. Add a unit test for a custom extension-based marking definition where the extension is of type "toplevel-property-extension". --- stix2/test/v21/test_custom.py | 113 ++++++++++++++++++++++------------ 1 file changed, 75 insertions(+), 38 deletions(-) diff --git a/stix2/test/v21/test_custom.py b/stix2/test/v21/test_custom.py index 637c79f2..f1f59094 100644 --- a/stix2/test/v21/test_custom.py +++ b/stix2/test/v21/test_custom.py @@ -24,6 +24,33 @@ ) +@contextlib.contextmanager +def _register_extension(ext, props): + """ + A contextmanager useful for registering an extension and then ensuring + it gets unregistered again. A random extension-definition STIX ID is + generated for the extension and yielded as the contextmanager's value. + + :param ext: The class which would normally be decorated with the + CustomExtension decorator. + :param props: Properties as would normally be passed into the + CustomExtension decorator. + """ + + ext_def_id = "extension-definition--" + str(uuid.uuid4()) + + stix2.v21.CustomExtension( + ext_def_id, + props, + )(ext) + + try: + yield ext_def_id + finally: + # "unregister" the extension + del stix2.registry.STIX2_OBJ_MAPS["2.1"]["extensions"][ext_def_id] + + def test_identity_custom_property(): identity = stix2.v21.Identity( id=IDENTITY_ID, @@ -1645,54 +1672,64 @@ class MyFavSCO: def test_registered_new_extension_marking_allow_custom_false(): - @stix2.v21.CustomMarking( - 'my-favorite-marking', [ - ('some_marking_field', stix2.properties.StringProperty(required=True)), - ], 'extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff', - ) + class MyFavMarking: - pass + extension_type = "property-extension" - my_favorite_marking = { - 'type': 'marking-definition', - 'spec_version': '2.1', - 'id': 'marking-definition--f9dbe89c-0030-4a9d-8b78-0dcd0a0de874', - 'name': 'This is the name of my favorite Marking', - 'extensions': { - 'extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff': { - 'extension_type': 'property-extension', - 'some_marking_field': 'value', - }, - }, + props = { + 'some_marking_field': stix2.properties.StringProperty(required=True), } - marking_object = stix2.parse(my_favorite_marking) - assert isinstance(marking_object, stix2.v21.MarkingDefinition) - assert isinstance( - marking_object.extensions['extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff'], - stix2.v21.EXT_MAP['extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff'], - ) + with _register_extension(MyFavMarking, props) as ext_def_id: - 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 + my_favorite_marking = { + 'type': 'marking-definition', + 'spec_version': '2.1', + 'id': 'marking-definition--f9dbe89c-0030-4a9d-8b78-0dcd0a0de874', + 'name': 'This is the name of my favorite Marking', + 'extensions': { + ext_def_id: { + 'extension_type': 'property-extension', + 'some_marking_field': 'value', + }, + }, + } + marking_object = stix2.parse(my_favorite_marking) + assert isinstance(marking_object, stix2.v21.MarkingDefinition) + assert isinstance( + marking_object.extensions[ext_def_id], + stix2.v21.EXT_MAP[ext_def_id], + ) -@contextlib.contextmanager -def _register_extension(ext, props): + marking_serialized = marking_object.serialize(sort_keys=True) + assert '"extensions": {{"{}": ' \ + '{{"extension_type": "property-extension", "some_marking_field": "value"}}}}'.format(ext_def_id) in marking_serialized - ext_def_id = "extension-definition--" + str(uuid.uuid4()) - stix2.v21.CustomExtension( - ext_def_id, - props, - )(ext) +def test_custom_marking_toplevel_properties(): + class CustomMarking: + extension_type = "toplevel-property-extension" - try: - yield ext_def_id - finally: - # "unregister" the extension - del stix2.registry.STIX2_OBJ_MAPS["2.1"]["extensions"][ext_def_id] + props = { + "foo": stix2.properties.StringProperty(required=True) + } + + with _register_extension(CustomMarking, props) as ext_def_id: + + marking_dict = { + "type": "marking-definition", + "spec_version": "2.1", + "foo": "hello", + "extensions": { + ext_def_id: { + "extension_type": "toplevel-property-extension" + } + } + } + + marking = stix2.parse(marking_dict) + assert marking.foo == "hello" def test_nested_ext_prop_meta(): From e99be67c1ea34a3af359ac0972243b07bfd17d16 Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Fri, 9 Jul 2021 18:11:11 -0400 Subject: [PATCH 03/11] Remove registration._get_extension_class() since it's redundant with registry.class_for_type(). --- stix2/custom.py | 9 +++++---- stix2/registration.py | 5 ----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/stix2/custom.py b/stix2/custom.py index 7eee49ca..44a03493 100644 --- a/stix2/custom.py +++ b/stix2/custom.py @@ -3,9 +3,10 @@ from .base import _cls_init from .properties import EnumProperty from .registration import ( - _get_extension_class, _register_extension, _register_marking, - _register_object, _register_observable, + _register_extension, _register_marking, _register_object, + _register_observable, ) +from .registry import class_for_type def _get_properties_dict(properties): @@ -34,7 +35,7 @@ def __init__(self, **kwargs): if ext and version != '2.0': if 'extensions' not in self._inner: self._inner['extensions'] = {} - self._inner['extensions'][ext] = _get_extension_class(ext, version)() + self._inner['extensions'][ext] = class_for_type(ext, version, "extensions")() _CustomObject.__name__ = cls.__name__ @@ -80,7 +81,7 @@ def __init__(self, **kwargs): if ext and version != '2.0': if 'extensions' not in self._inner: self._inner['extensions'] = {} - self._inner['extensions'][ext] = _get_extension_class(ext, version)() + self._inner['extensions'][ext] = class_for_type(ext, version, "extensions")() _CustomObservable.__name__ = cls.__name__ diff --git a/stix2/registration.py b/stix2/registration.py index 28d43ba8..a37f76e7 100644 --- a/stix2/registration.py +++ b/stix2/registration.py @@ -132,11 +132,6 @@ def _register_observable(new_observable, version=version.DEFAULT_VERSION): OBJ_MAP_OBSERVABLE[new_observable._type] = new_observable -def _get_extension_class(extension_uuid, version): - """Retrieve a registered class Extension""" - return registry.STIX2_OBJ_MAPS[version]['extensions'].get(extension_uuid) - - def _register_extension( new_extension, version=version.DEFAULT_VERSION, ): From 945e3375aa71c0b8554addca7142d9cc5ca82c80 Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Fri, 9 Jul 2021 20:24:31 -0400 Subject: [PATCH 04/11] Fix extension registration to not only check nested properties for spec compliance, but also the toplevel properties, if any. --- stix2/registration.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/stix2/registration.py b/stix2/registration.py index a37f76e7..9fb2f49e 100644 --- a/stix2/registration.py +++ b/stix2/registration.py @@ -1,3 +1,4 @@ +import itertools import re from . import registry, version @@ -144,7 +145,12 @@ def _register_extension( """ ext_type = new_extension._type - properties = new_extension._properties + + # Need to check both toplevel and nested properties + prop_groups = [new_extension._properties] + if hasattr(new_extension, "_toplevel_properties"): + prop_groups.append(new_extension._toplevel_properties) + prop_names = itertools.chain.from_iterable(prop_groups) _validate_type(ext_type, version) @@ -161,7 +167,7 @@ def _register_extension( ext_type, ) - for prop_name in properties.keys(): + for prop_name in prop_names: if not re.match(PREFIX_21_REGEX, prop_name): raise ValueError("Property name '%s' must begin with an alpha character." % prop_name) From f0779d7802ca4c40e18c03d0eb25943d3845ebc0 Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Fri, 9 Jul 2021 20:28:32 -0400 Subject: [PATCH 05/11] Add unit tests for self-enabling extensions support, and for compliance checking on toplevel extension property names. --- stix2/test/v21/test_custom.py | 58 +++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/stix2/test/v21/test_custom.py b/stix2/test/v21/test_custom.py index f1f59094..0c424ee8 100644 --- a/stix2/test/v21/test_custom.py +++ b/stix2/test/v21/test_custom.py @@ -1917,6 +1917,64 @@ class TestExt: ) +def test_toplevel_extension_includes_extensions(): + """ + Test whether the library allows an extension to enable extension support + itself. :) I.e. a toplevel property extension which adds the "extensions" + property. + """ + + class ExtensionsExtension: + extension_type = "toplevel-property-extension" + + ext_props = { + "extensions": stix2.properties.ExtensionsProperty(spec_version="2.1") + } + + with _register_extension(ExtensionsExtension, ext_props) as ext_id: + + # extension-definition is not defined with an "extensions" property. + obj_dict = { + "type": "extension-definition", + "spec_version": "2.1", + "created_by_ref": "identity--8a1fd5dd-4586-4ded-bd39-04bda62f8415", + "name": "my extension", + "version": "1.2.3", + "schema": "add extension support to an object!", + "extension_types": ["toplevel-property-extension"], + "extensions": { + ext_id: { + "extension_type": "toplevel-property-extension" + } + } + } + + stix2.parse(obj_dict) + + +def test_invalid_extension_prop_name(): + + with pytest.raises(ValueError): + @stix2.v21.common.CustomExtension( + "extension-definition--0530fdbd-0fa3-42ab-90cf-660e0abad370", + [ + ("7foo", stix2.properties.StringProperty()) + ] + ) + class CustomExt: + extension_type = "property-extension" + + with pytest.raises(ValueError): + @stix2.v21.common.CustomExtension( + "extension-definition--0530fdbd-0fa3-42ab-90cf-660e0abad370", + [ + ("7foo", stix2.properties.StringProperty()) + ] + ) + class CustomExt: + extension_type = "toplevel-property-extension" + + def test_allow_custom_propagation(): obj_dict = { "type": "bundle", From 9f428c5efd86764f749d7d87bbba6bf488a1e40d Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Sun, 11 Jul 2021 20:16:55 -0400 Subject: [PATCH 06/11] Updates to extensions.ipynb: - Change CS 02 reference to CS 03 - Fix typos - Remove the extension definition from the first example. It's not relevant. Change the explanation to explain the real reason why that example works: if unregistered toplevel property extensions are present, the library lets unrecognized toplevel properties pass. - Change the explained rationale for registering an extension. It had described "repetitive instantiation" of an extension, but I think it was referring to an extension definition, and that is not what happens. The benefit of registration is that the library will know which properties are associated with the extension and can enforce their requirements. Changed the commentary to explain this. - Fix the custom marking example to not use the @CustomMarking decorator. It is no longer used for extension-based custom markings. Instead, it just shows a normal extension being registered and applied to a marking-definition. The commentary is changed to explain this too. --- docs/guide/extensions.ipynb | 408 ++++++------------------------------ 1 file changed, 63 insertions(+), 345 deletions(-) diff --git a/docs/guide/extensions.ipynb b/docs/guide/extensions.ipynb index 9dcbdb28..073cc79e 100644 --- a/docs/guide/extensions.ipynb +++ b/docs/guide/extensions.ipynb @@ -59,11 +59,11 @@ "source": [ "## STIX Extensions\n", "\n", - "This page is specific for the STIX Extensions mechanism defined in STIX 2.1 CS 02. For the deprecated STIX Customization mechanisms see the [Custom](custom.ipynb) section.\n", + "This page is specific for the STIX Extensions mechanism defined in STIX 2.1 CS 03. For the deprecated STIX Customization mechanisms see the [Custom](custom.ipynb) section.\n", "\n", "### Top Level Property Extensions\n", "\n", - "The example below shows how to create an `indicator` object with a `top-level-property-extension`. " + "The example below shows how to create an `indicator` object with a `toplevel-property-extension`. Because an unregistered toplevel property extension is present, any unrecognized toplevel properties are assumed to be extension properties. So the library lets them pass. " ] }, { @@ -72,239 +72,38 @@ "metadata": {}, "outputs": [ { - "data": { - "text/html": [ - "
{\n",
-       "    "type": "extension-definition",\n",
-       "    "spec_version": "2.1",\n",
-       "    "id": "extension-definition--dd73de4f-a7f3-49ea-8ec1-8e884196b7a8",\n",
-       "    "created_by_ref": "identity--11b76a96-5d2b-45e0-8a5a-f6994f370731",\n",
-       "    "created": "2014-02-20T09:16:08.000Z",\n",
-       "    "modified": "2014-02-20T09:16:08.000Z",\n",
-       "    "name": "New SDO 1",\n",
-       "    "description": "This schema adds two properties to a STIX object at the toplevel",\n",
-       "    "schema": "https://www.example.com/schema-foo-1a/v1/",\n",
-       "    "version": "1.2.1",\n",
-       "    "extension_types": [\n",
-       "        "toplevel-property-extension"\n",
-       "    ],\n",
-       "    "extension_properties": [\n",
-       "        "toxicity",\n",
-       "        "rank"\n",
-       "    ]\n",
-       "}\n",
-       "
\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "text/html": [ - "
{\n",
-       "    "type": "indicator",\n",
-       "    "spec_version": "2.1",\n",
-       "    "id": "indicator--e97bfccf-8970-4a3c-9cd1-5b5b97ed5d0c",\n",
-       "    "created": "2014-02-20T09:16:08.989Z",\n",
-       "    "modified": "2014-02-20T09:16:08.989Z",\n",
-       "    "name": "File hash for Poison Ivy variant",\n",
-       "    "description": "This file hash indicates that a sample of Poison Ivy is present.",\n",
-       "    "pattern": "[file:hashes.'SHA-256' = 'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c']",\n",
-       "    "pattern_type": "stix",\n",
-       "    "pattern_version": "2.1",\n",
-       "    "valid_from": "2014-02-20T09:00:00Z",\n",
-       "    "labels": [\n",
-       "        "malicious-activity"\n",
-       "    ],\n",
-       "    "extensions": {\n",
-       "        "extension-definition--dd73de4f-a7f3-49ea-8ec1-8e884196b7a8": {\n",
-       "            "extension_type": "toplevel-property-extension"\n",
-       "        }\n",
-       "    },\n",
-       "    "rank": 5,\n",
-       "    "toxicity": 8\n",
-       "}\n",
-       "
\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"type\": \"indicator\",\n", + " \"spec_version\": \"2.1\",\n", + " \"id\": \"indicator--e97bfccf-8970-4a3c-9cd1-5b5b97ed5d0c\",\n", + " \"created\": \"2014-02-20T09:16:08.989Z\",\n", + " \"modified\": \"2014-02-20T09:16:08.989Z\",\n", + " \"name\": \"File hash for Poison Ivy variant\",\n", + " \"description\": \"This file hash indicates that a sample of Poison Ivy is present.\",\n", + " \"pattern\": \"[file:hashes.'SHA-256' = 'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c']\",\n", + " \"pattern_type\": \"stix\",\n", + " \"pattern_version\": \"2.1\",\n", + " \"valid_from\": \"2014-02-20T09:00:00Z\",\n", + " \"labels\": [\n", + " \"malicious-activity\"\n", + " ],\n", + " \"extensions\": {\n", + " \"extension-definition--dd73de4f-a7f3-49ea-8ec1-8e884196b7a8\": {\n", + " \"extension_type\": \"toplevel-property-extension\"\n", + " }\n", + " },\n", + " \"rank\": 5,\n", + " \"toxicity\": 8\n", + "}\n" + ] } ], "source": [ "import stix2\n", "\n", - "extension_definition1 = stix2.v21.ExtensionDefinition(\n", - " id=\"extension-definition--dd73de4f-a7f3-49ea-8ec1-8e884196b7a8\",\n", - " created_by_ref=\"identity--11b76a96-5d2b-45e0-8a5a-f6994f370731\",\n", - " created=\"2014-02-20T09:16:08.000Z\",\n", - " modified=\"2014-02-20T09:16:08.000Z\",\n", - " name=\"New SDO 1\",\n", - " description=\"This schema adds two properties to a STIX object at the toplevel\",\n", - " schema=\"https://www.example.com/schema-foo-1a/v1/\",\n", - " version=\"1.2.1\",\n", - " extension_types=[\"toplevel-property-extension\"],\n", - " extension_properties=[\n", - " \"toxicity\",\n", - " \"rank\",\n", - " ],\n", - ")\n", - "\n", "indicator = stix2.v21.Indicator(\n", " id='indicator--e97bfccf-8970-4a3c-9cd1-5b5b97ed5d0c',\n", " created='2014-02-20T09:16:08.989000Z',\n", @@ -320,13 +119,12 @@ " pattern_type='stix',\n", " valid_from='2014-02-20T09:00:00.000000Z',\n", " extensions={\n", - " extension_definition1.id : {\n", + " \"extension-definition--dd73de4f-a7f3-49ea-8ec1-8e884196b7a8\" : {\n", " 'extension_type': 'toplevel-property-extension',\n", " },\n", " }\n", ")\n", "\n", - "print(extension_definition1.serialize(pretty=True))\n", "print(indicator.serialize(pretty=True))" ] }, @@ -336,7 +134,7 @@ "source": [ "### Using CustomExtension decorator\n", "\n", - "However, in order to prevent repetitive instantiation of the same extension, the `@CustomExtension` decorator can be used to register the `extension-definition` with stix2. Use the `extension_type` class variable to define what kind of extension it is. Then its id can be passed into objects that use this extension." + "However, in order to define which properties are actually included with an extension, the `@CustomExtension` decorator can be used to register an extension type and its properties with stix2. Use the `extension_type` class variable to define what kind of extension it is. Then its id can be passed into objects that use this extension." ] }, { @@ -500,7 +298,7 @@ "\n", "---\n", "**Note:**\n", - "Creating an instance of an extension-definition object **does not** mean it is registered in the library. Please use the appropriate decorator for this step: `@CustomExtension`, `@CustomObject`, `@CustomObservable`, `@CustomMarking`\n", + "Creating an instance of an extension object **does not** mean it is registered in the library. Please use the appropriate decorator for this step: `@CustomExtension`, `@CustomObject`, `@CustomObservable`, `@CustomMarking`\n", "\n", "---" ] @@ -632,9 +430,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Using CustomMarking for Extension Definition\n", + "### Custom Markings\n", "\n", - "The example below shows the use for MarkingDefinition extensions. Currently this is only supported as a `property-extension`. Now, as another option to building the `extensions` as a dictionary, it can also be built with objects as shown below by extracting the registered class." + "The example below show how to create a user-defined marking based on an extension. The STIX `marking-definition` object is essentially a base upon which you build the particulars of your marking, via an extension. This is done in the same way as any other extension. Marking definitions are no different in this regard. The below example illustrates an alternative to building the extension entirely as a dictionary: it can also be built by instantiating the registered class." ] }, { @@ -643,123 +441,43 @@ "metadata": {}, "outputs": [ { - "data": { - "text/html": [ - "
{\n",
-       "    "type": "marking-definition",\n",
-       "    "spec_version": "2.1",\n",
-       "    "id": "marking-definition--28417f9f-1963-4e7f-914d-233f8fd4829f",\n",
-       "    "created": "2021-03-31T21:54:46.652069Z",\n",
-       "    "name": "This is the name of my favorite Marking",\n",
-       "    "extensions": {\n",
-       "        "extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff": {\n",
-       "            "extension_type": "property-extension"\n",
-       "        }\n",
-       "    }\n",
-       "}\n",
-       "
\n" - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"type\": \"marking-definition\",\n", + " \"spec_version\": \"2.1\",\n", + " \"id\": \"marking-definition--0a970182-06fd-4bc8-ae27-863fdb0e794c\",\n", + " \"created\": \"2021-07-11T23:02:29.893782Z\",\n", + " \"name\": \"This is the name of my favorite Marking\",\n", + " \"extensions\": {\n", + " \"extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff\": {\n", + " \"extension_type\": \"property-extension\",\n", + " \"some_marking_field\": \"value\"\n", + " }\n", + " }\n", + "}\n" + ] } ], "source": [ - "from stix2 import registry\n", + "import stix2\n", + "import stix2.properties\n", "\n", "MARKING_EXTENSION_ID = 'extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff'\n", "\n", - "@stix2.v21.CustomMarking(\n", - " 'my-favorite-marking', [\n", - " ('some_marking_field', stix2.properties.StringProperty(required=True)),\n", - " ], MARKING_EXTENSION_ID,\n", - ")\n", + "@stix2.CustomExtension(MARKING_EXTENSION_ID, [\n", + " ('some_marking_field', stix2.properties.StringProperty(required=True))\n", + "])\n", "class MyFavMarking:\n", - " pass\n", - "\n", - "ext_class = registry.class_for_type(MARKING_EXTENSION_ID, '2.1')\n", + " extension_type = 'property-extension'\n", "\n", - "my_favorite_marking = MyFavMarking(\n", + "my_favorite_marking = stix2.MarkingDefinition(\n", " name='This is the name of my favorite Marking',\n", " extensions={\n", - " MARKING_EXTENSION_ID: ext_class(some_marking_field='value')\n", + " MARKING_EXTENSION_ID: MyFavMarking(\n", + " some_marking_field='value'\n", + " )\n", " }\n", ")\n", "\n", @@ -908,7 +626,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -922,7 +640,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.2" + "version": "3.8.1" } }, "nbformat": 4, From 79ceef51009e8118355ba91de5b38e6b68307ddb Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Sun, 11 Jul 2021 20:44:45 -0400 Subject: [PATCH 07/11] Fix parsing.ipynb to not use the deprecated "objects" property of the observed-data SDO. --- docs/guide/parsing.ipynb | 46 +++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/docs/guide/parsing.ipynb b/docs/guide/parsing.ipynb index 0e891261..61f59095 100644 --- a/docs/guide/parsing.ipynb +++ b/docs/guide/parsing.ipynb @@ -77,8 +77,13 @@ { "data": { "text/html": [ - "
{\n",
+       "    "type": "indicator",\n",
+       "    "spec_version": "2.1",\n",
+       "    "id": "indicator--e97bfccf-8970-4a3c-9cd1-5b5b97ed5d0c",\n",
+       "    "created": "2014-02-20T09:16:08.989Z",\n",
+       "    "modified": "2014-02-20T09:16:08.989Z",\n",
+       "    "name": "File hash for Poison Ivy variant",\n",
+       "    "description": "This file hash indicates that a sample of Poison Ivy is present.",\n",
+       "    "pattern": "[file:hashes.'SHA-256' = 'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c']",\n",
+       "    "pattern_type": "stix",\n",
+       "    "pattern_version": "2.1",\n",
+       "    "valid_from": "2014-02-20T09:00:00Z",\n",
+       "    "labels": [\n",
+       "        "malicious-activity"\n",
+       "    ],\n",
+       "    "extensions": {\n",
+       "        "extension-definition--dd73de4f-a7f3-49ea-8ec1-8e884196b7a8": {\n",
+       "            "extension_type": "toplevel-property-extension"\n",
+       "        }\n",
+       "    },\n",
+       "    "rank": 5,\n",
+       "    "toxicity": 8\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ @@ -441,23 +521,103 @@ "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\n", - " \"type\": \"marking-definition\",\n", - " \"spec_version\": \"2.1\",\n", - " \"id\": \"marking-definition--0a970182-06fd-4bc8-ae27-863fdb0e794c\",\n", - " \"created\": \"2021-07-11T23:02:29.893782Z\",\n", - " \"name\": \"This is the name of my favorite Marking\",\n", - " \"extensions\": {\n", - " \"extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff\": {\n", - " \"extension_type\": \"property-extension\",\n", - " \"some_marking_field\": \"value\"\n", - " }\n", - " }\n", - "}\n" - ] + "data": { + "text/html": [ + "
{\n",
+       "    "type": "marking-definition",\n",
+       "    "spec_version": "2.1",\n",
+       "    "id": "marking-definition--9155f07c-dd4c-4320-be6a-0701311c3b84",\n",
+       "    "created": "2021-07-12T00:56:31.47566Z",\n",
+       "    "name": "This is the name of my favorite Marking",\n",
+       "    "extensions": {\n",
+       "        "extension-definition--a932fcc6-e032-176c-126f-cb970a5a1fff": {\n",
+       "            "extension_type": "property-extension",\n",
+       "            "some_marking_field": "value"\n",
+       "        }\n",
+       "    }\n",
+       "}\n",
+       "
\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ From b2108e90c67637fdbefc8871e11fb7abb925b0dc Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Mon, 12 Jul 2021 14:33:56 -0400 Subject: [PATCH 09/11] pre-commit stylistic fixes --- stix2/test/v21/test_custom.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/stix2/test/v21/test_custom.py b/stix2/test/v21/test_custom.py index 0c424ee8..47b169b6 100644 --- a/stix2/test/v21/test_custom.py +++ b/stix2/test/v21/test_custom.py @@ -1712,7 +1712,7 @@ class CustomMarking: extension_type = "toplevel-property-extension" props = { - "foo": stix2.properties.StringProperty(required=True) + "foo": stix2.properties.StringProperty(required=True), } with _register_extension(CustomMarking, props) as ext_def_id: @@ -1723,9 +1723,9 @@ class CustomMarking: "foo": "hello", "extensions": { ext_def_id: { - "extension_type": "toplevel-property-extension" - } - } + "extension_type": "toplevel-property-extension", + }, + }, } marking = stix2.parse(marking_dict) @@ -1928,7 +1928,7 @@ class ExtensionsExtension: extension_type = "toplevel-property-extension" ext_props = { - "extensions": stix2.properties.ExtensionsProperty(spec_version="2.1") + "extensions": stix2.properties.ExtensionsProperty(spec_version="2.1"), } with _register_extension(ExtensionsExtension, ext_props) as ext_id: @@ -1944,9 +1944,9 @@ class ExtensionsExtension: "extension_types": ["toplevel-property-extension"], "extensions": { ext_id: { - "extension_type": "toplevel-property-extension" - } - } + "extension_type": "toplevel-property-extension", + }, + }, } stix2.parse(obj_dict) @@ -1958,8 +1958,8 @@ def test_invalid_extension_prop_name(): @stix2.v21.common.CustomExtension( "extension-definition--0530fdbd-0fa3-42ab-90cf-660e0abad370", [ - ("7foo", stix2.properties.StringProperty()) - ] + ("7foo", stix2.properties.StringProperty()), + ], ) class CustomExt: extension_type = "property-extension" @@ -1968,8 +1968,8 @@ class CustomExt: @stix2.v21.common.CustomExtension( "extension-definition--0530fdbd-0fa3-42ab-90cf-660e0abad370", [ - ("7foo", stix2.properties.StringProperty()) - ] + ("7foo", stix2.properties.StringProperty()), + ], ) class CustomExt: extension_type = "toplevel-property-extension" From d7981dce9fa24372b5f8f93f89a59be7d704bb0f Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Mon, 12 Jul 2021 14:40:54 -0400 Subject: [PATCH 10/11] Stop the flake8 hook from complaining about a line in a unit test that it is misunderstanding and shouldn't be complaining about. --- stix2/test/v21/test_custom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stix2/test/v21/test_custom.py b/stix2/test/v21/test_custom.py index 47b169b6..13eeba93 100644 --- a/stix2/test/v21/test_custom.py +++ b/stix2/test/v21/test_custom.py @@ -1971,7 +1971,7 @@ class CustomExt: ("7foo", stix2.properties.StringProperty()), ], ) - class CustomExt: + class CustomExt: # noqa: F811 extension_type = "toplevel-property-extension" From 295037f92c20cfc6847e2dee0760c9d88e848442 Mon Sep 17 00:00:00 2001 From: Michael Chisholm Date: Mon, 12 Jul 2021 16:16:29 -0400 Subject: [PATCH 11/11] Fix parsing.ipynb to not mention SCOs "inside" observed-data SDOs anymore. That is no longer the case in STIX 2.1. --- docs/guide/parsing.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/parsing.ipynb b/docs/guide/parsing.ipynb index 61f59095..452f5704 100644 --- a/docs/guide/parsing.ipynb +++ b/docs/guide/parsing.ipynb @@ -64,7 +64,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Parsing STIX content is as easy as calling the [parse()](../api/stix2.parsing.rst#stix2.parsing.parse) function on a JSON string, dictionary, or file-like object. It will automatically determine the type of the object. The STIX objects within `bundle` objects, and any cyber observables contained within `observed-data` objects will be parsed as well.\n", + "Parsing STIX content is as easy as calling the [parse()](../api/stix2.parsing.rst#stix2.parsing.parse) function on a JSON string, dictionary, or file-like object. It will automatically determine the type of the object. The STIX objects within `bundle` objects will be parsed as well.\n", "\n", "**Parsing a string**" ]