From cf972479ed487b0ef58f1275d0bf3ae81b48721a Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Wed, 16 May 2018 15:37:30 -0400 Subject: [PATCH 1/2] Pass allow_custom to object dicts in a Bundle --- stix2/base.py | 8 ++++---- stix2/core.py | 2 +- stix2/test/test_custom.py | 20 +++++++++++++++++++- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/stix2/base.py b/stix2/base.py index bb8cd2f..84397f0 100644 --- a/stix2/base.py +++ b/stix2/base.py @@ -136,7 +136,7 @@ class _STIXBase(collections.Mapping): if custom_props and not isinstance(custom_props, dict): raise ValueError("'custom_properties' must be a dictionary") if not allow_custom: - extra_kwargs = list(set(kwargs) - set(cls._properties)) + extra_kwargs = list(set(kwargs) - set(self._properties)) if extra_kwargs: raise ExtraPropertiesError(cls, extra_kwargs) @@ -149,17 +149,17 @@ class _STIXBase(collections.Mapping): setting_kwargs[prop_name] = prop_value # Detect any missing required properties - required_properties = set(get_required_properties(cls._properties)) + required_properties = set(get_required_properties(self._properties)) missing_kwargs = required_properties - set(setting_kwargs) if missing_kwargs: raise MissingPropertiesError(cls, missing_kwargs) - for prop_name, prop_metadata in cls._properties.items(): + for prop_name, prop_metadata in self._properties.items(): self._check_property(prop_name, prop_metadata, setting_kwargs) # Cache defaulted optional properties for serialization defaulted = [] - for name, prop in cls._properties.items(): + for name, prop in self._properties.items(): try: if (not prop.required and not hasattr(prop, '_fixed_value') and prop.default() == setting_kwargs[name]): diff --git a/stix2/core.py b/stix2/core.py index 6c2e23a..af74a9e 100644 --- a/stix2/core.py +++ b/stix2/core.py @@ -63,7 +63,7 @@ class Bundle(_STIXBase): kwargs['objects'] = list(args) + kwargs.get('objects', []) self.__allow_custom = kwargs.get('allow_custom', False) - self._properties['objects'].allow_custom = kwargs.get('allow_custom', False) + self._properties['objects'].contained.allow_custom = kwargs.get('allow_custom', False) super(Bundle, self).__init__(**kwargs) diff --git a/stix2/test/test_custom.py b/stix2/test/test_custom.py index 59cbea8..47e8ae1 100644 --- a/stix2/test/test_custom.py +++ b/stix2/test/test_custom.py @@ -88,13 +88,31 @@ def test_parse_identity_custom_property(data): assert identity.foo == "bar" -def test_custom_property_in_bundled_object(): +def test_custom_property_object_in_bundled_object(): bundle = stix2.Bundle(IDENTITY_CUSTOM_PROP, allow_custom=True) assert bundle.objects[0].x_foo == "bar" assert '"x_foo": "bar"' in str(bundle) +def test_custom_property_dict_in_bundled_object(): + custom_identity = { + 'type': 'identity', + 'id': 'identity--311b2d2d-f010-5473-83ec-1edf84858f4c', + 'created': '2015-12-21T19:59:11Z', + 'name': 'John Smith', + 'identity_class': 'individual', + 'x_foo': 'bar', + } + with pytest.raises(stix2.exceptions.ExtraPropertiesError): + bundle = stix2.Bundle(custom_identity) + + bundle = stix2.Bundle(custom_identity, allow_custom=True) + + assert bundle.objects[0].x_foo == "bar" + assert '"x_foo": "bar"' in str(bundle) + + def test_custom_property_in_observed_data(): artifact = stix2.File( allow_custom=True, From ddc09f70c7df3e9f8128b63fe9907613bef5c600 Mon Sep 17 00:00:00 2001 From: Chris Lenk Date: Thu, 17 May 2018 09:04:44 -0400 Subject: [PATCH 2/2] Set allow_custom if using a custom_properties dict Fixes #179. --- stix2/base.py | 4 +++- stix2/test/test_custom.py | 45 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/stix2/base.py b/stix2/base.py index 84397f0..2afba16 100644 --- a/stix2/base.py +++ b/stix2/base.py @@ -135,10 +135,12 @@ class _STIXBase(collections.Mapping): custom_props = kwargs.pop('custom_properties', {}) if custom_props and not isinstance(custom_props, dict): raise ValueError("'custom_properties' must be a dictionary") - if not allow_custom: + if not self.__allow_custom: extra_kwargs = list(set(kwargs) - set(self._properties)) if extra_kwargs: raise ExtraPropertiesError(cls, extra_kwargs) + if custom_props: + self.__allow_custom = True # Remove any keyword arguments whose value is None setting_kwargs = {} diff --git a/stix2/test/test_custom.py b/stix2/test/test_custom.py index 47e8ae1..7f91d79 100644 --- a/stix2/test/test_custom.py +++ b/stix2/test/test_custom.py @@ -24,6 +24,20 @@ def test_identity_custom_property(): ) assert str(excinfo.value) == "'custom_properties' must be a dictionary" + with pytest.raises(stix2.exceptions.ExtraPropertiesError) as excinfo: + stix2.Identity( + id="identity--311b2d2d-f010-5473-83ec-1edf84858f4c", + created="2015-12-21T19:59:11Z", + modified="2015-12-21T19:59:11Z", + name="John Smith", + identity_class="individual", + custom_properties={ + "foo": "bar", + }, + foo="bar", + ) + assert "Unexpected properties for Identity" in str(excinfo.value) + identity = stix2.Identity( id="identity--311b2d2d-f010-5473-83ec-1edf84858f4c", created="2015-12-21T19:59:11Z", @@ -34,7 +48,6 @@ def test_identity_custom_property(): "foo": "bar", }, ) - assert identity.foo == "bar" @@ -95,6 +108,20 @@ def test_custom_property_object_in_bundled_object(): assert '"x_foo": "bar"' in str(bundle) +def test_custom_properties_object_in_bundled_object(): + obj = stix2.Identity( + name="John Smith", + identity_class="individual", + custom_properties={ + "x_foo": "bar", + } + ) + bundle = stix2.Bundle(obj, allow_custom=True) + + assert bundle.objects[0].x_foo == "bar" + assert '"x_foo": "bar"' in str(bundle) + + def test_custom_property_dict_in_bundled_object(): custom_identity = { 'type': 'identity', @@ -108,6 +135,22 @@ def test_custom_property_dict_in_bundled_object(): bundle = stix2.Bundle(custom_identity) bundle = stix2.Bundle(custom_identity, allow_custom=True) + assert bundle.objects[0].x_foo == "bar" + assert '"x_foo": "bar"' in str(bundle) + + +def test_custom_properties_dict_in_bundled_object(): + custom_identity = { + 'type': 'identity', + 'id': 'identity--311b2d2d-f010-5473-83ec-1edf84858f4c', + 'created': '2015-12-21T19:59:11Z', + 'name': 'John Smith', + 'identity_class': 'individual', + 'custom_properties': { + 'x_foo': 'bar', + }, + } + bundle = stix2.Bundle(custom_identity) assert bundle.objects[0].x_foo == "bar" assert '"x_foo": "bar"' in str(bundle)