From ef408e1971733f37e32af011850e1f87bcfebf71 Mon Sep 17 00:00:00 2001 From: "Desai, Kartikey H" Date: Mon, 1 Jul 2019 11:52:55 -0400 Subject: [PATCH 1/5] preliminary changes to make stix2 code conform to WD 04 specs --- stix2/v21/sdo.py | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/stix2/v21/sdo.py b/stix2/v21/sdo.py index 0717f88d..0ae0c80f 100644 --- a/stix2/v21/sdo.py +++ b/stix2/v21/sdo.py @@ -122,6 +122,34 @@ def _check_object_constraints(self): ) +class Grouping(STIXDomainObject): + # TODO: Add link + """For more detailed information on this object's properties, see + `the STIX 2.1 specification `__. + """ + + _type = 'grouping' + _properties = OrderedDict([ + ('type', TypeProperty(_type)), + ('spec_version', StringProperty(fixed='2.1')), + ('id', IDProperty(_type, spec_version='2.1')), + ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), + ('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')), + ('created_by_ref', ReferenceProperty(type='identity', spec_version='2.1')), + ('revoked', BooleanProperty(default=lambda: False)), + ('labels', ListProperty(StringProperty)), + ('confidence', IntegerProperty()), + ('lang', StringProperty()), + ('external_references', ListProperty(ExternalReference)), + ('object_marking_refs', ListProperty(ReferenceProperty(type='marking-definition', spec_version='2.1'))), + ('granular_markings', ListProperty(GranularMarking)), + ('name', StringProperty()), + ('description', StringProperty()), + ('context', StringProperty(required=True)), + ('object_refs', ListProperty(ReferenceProperty)), + ]) + + class Identity(STIXDomainObject): # TODO: Add link """For more detailed information on this object's properties, see @@ -193,6 +221,46 @@ def _check_object_constraints(self): raise ValueError(msg.format(self)) +class Infrastructure(STIXDomainObject): + # TODO: Add link + """For more detailed information on this object's properties, see + `the STIX 2.1 specification `__. + """ + + _type = 'infrastructure' + _properties = OrderedDict([ + ('type', TypeProperty(_type)), + ('spec_version', StringProperty(fixed='2.1')), + ('id', IDProperty(_type, spec_version='2.1')), + ('created_by_ref', ReferenceProperty(type='identity', spec_version='2.1')), + ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), + ('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')), + ('revoked', BooleanProperty(default=lambda: False)), + ('labels', ListProperty(StringProperty)), + ('confidence', IntegerProperty()), + ('lang', StringProperty()), + ('external_references', ListProperty(ExternalReference)), + ('object_marking_refs', ListProperty(ReferenceProperty(type='marking-definition', spec_version='2.1'))), + ('granular_markings', ListProperty(GranularMarking)), + ('name', StringProperty(required=True)), + ('description', StringProperty()), + ('infrastructure_types', ListProperty(StringProperty, required=True)), + ('kill_chain_phases', ListProperty(KillChainPhase)), + ('first_seen', TimestampProperty()), + ('last_seen', TimestampProperty()), + ]) + + def _check_object_constraints(self): + super(self.__class__, self)._check_object_constraints() + + first_seen = self.get('first_seen') + last_seen = self.get('last_seen') + + if first_seen and last_seen and last_seen < first_seen: + msg = "{0.id} 'last_seen' must be greater than or equal to 'first_seen'" + raise ValueError(msg.format(self)) + + class IntrusionSet(STIXDomainObject): # TODO: Add link """For more detailed information on this object's properties, see @@ -346,7 +414,16 @@ class Malware(STIXDomainObject): ('name', StringProperty(required=True)), ('description', StringProperty()), ('malware_types', ListProperty(StringProperty, required=True)), + ('is_family', BooleanProperty(required=True)), + ('aliases', ListProperty(StringProperty)), ('kill_chain_phases', ListProperty(KillChainPhase)), + ('first_seen', TimestampProperty()), + ('last_seen', TimestampProperty()), + ('os_execution_envs', ListProperty(StringProperty)), + ('architecture_execution_envs', ListProperty(StringProperty)), + ('implementation_languages', ListProperty(StringProperty)), + ('capabilities', ListProperty(StringProperty)), + ('sample_refs', ListProperty(ReferenceProperty(spec_version='2.1'))), ('revoked', BooleanProperty(default=lambda: False)), ('labels', ListProperty(StringProperty)), ('confidence', IntegerProperty()), @@ -356,6 +433,16 @@ class Malware(STIXDomainObject): ('granular_markings', ListProperty(GranularMarking)), ]) + def _check_object_constraints(self): + super(self.__class__, self)._check_object_constraints() + + first_seen = self.get('first_seen') + last_seen = self.get('last_seen') + + if first_seen and last_seen and last_seen < first_seen: + msg = "{0.id} 'last_seen' must be greater than or equal to 'first_seen'" + raise ValueError(msg.format(self)) + class MalwareAnalysis(STIXDomainObject): # TODO: Add link From c98fcafb1ac1dc4dcd3883469c3775b14cd54845 Mon Sep 17 00:00:00 2001 From: "Desai, Kartikey H" Date: Mon, 1 Jul 2019 15:26:30 -0400 Subject: [PATCH 2/5] Update tests to address conformance to WD04 specs --- stix2/test/v21/constants.py | 3 +++ stix2/test/v21/test_bundle.py | 6 +++++- stix2/test/v21/test_core.py | 1 + stix2/test/v21/test_datastore_filters.py | 1 + stix2/test/v21/test_environment.py | 5 ++++- stix2/test/v21/test_indicator.py | 5 +++-- stix2/test/v21/test_malware.py | 10 +++++++--- stix2/test/v21/test_versioning.py | 1 + stix2/test/v21/test_workbench.py | 2 +- stix2/v21/sdo.py | 3 ++- 10 files changed, 28 insertions(+), 9 deletions(-) diff --git a/stix2/test/v21/constants.py b/stix2/test/v21/constants.py index b0ba1ef0..66cb9566 100644 --- a/stix2/test/v21/constants.py +++ b/stix2/test/v21/constants.py @@ -78,6 +78,7 @@ INDICATOR_KWARGS = dict( indicator_types=['malicious-activity'], pattern="[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']", + valid_from="2017-01-01T12:34:56Z", ) INTRUSION_SET_KWARGS = dict( @@ -87,6 +88,7 @@ MALWARE_KWARGS = dict( malware_types=['ransomware'], name="Cryptolocker", + is_family=False, ) MALWARE_MORE_KWARGS = dict( @@ -97,6 +99,7 @@ malware_types=['ransomware'], name="Cryptolocker", description="A ransomware related to ...", + is_family=False, ) OBSERVED_DATA_KWARGS = dict( diff --git a/stix2/test/v21/test_bundle.py b/stix2/test/v21/test_bundle.py index 47d0a7a8..9b782152 100644 --- a/stix2/test/v21/test_bundle.py +++ b/stix2/test/v21/test_bundle.py @@ -31,7 +31,8 @@ "name": "Cryptolocker", "malware_types": [ "ransomware" - ] + ], + "is_family": False }, { "type": "relationship", @@ -72,6 +73,7 @@ "malware_types": [ "ransomware", ], + "is_family": False, }, { "type": "relationship", @@ -244,6 +246,7 @@ def test_bundle_obj_id_found(): "malware_types": [ "ransomware", ], + "is_family": False, }, { "type": "malware", @@ -255,6 +258,7 @@ def test_bundle_obj_id_found(): "malware_types": [ "ransomware", ], + "is_family": False, }, { "type": "relationship", diff --git a/stix2/test/v21/test_core.py b/stix2/test/v21/test_core.py index bf45f327..06a829c1 100644 --- a/stix2/test/v21/test_core.py +++ b/stix2/test/v21/test_core.py @@ -31,6 +31,7 @@ "malware_types": [ "ransomware", ], + "is_family": False, }, { "type": "relationship", diff --git a/stix2/test/v21/test_datastore_filters.py b/stix2/test/v21/test_datastore_filters.py index 4b9878a5..cbe3fe48 100644 --- a/stix2/test/v21/test_datastore_filters.py +++ b/stix2/test/v21/test_datastore_filters.py @@ -16,6 +16,7 @@ "remote-access-trojan", ], "modified": "2017-01-27T13:49:53.997Z", + "is_family": False, "name": "Poison Ivy", "type": "malware", }, diff --git a/stix2/test/v21/test_environment.py b/stix2/test/v21/test_environment.py index e08971ef..53ab744f 100644 --- a/stix2/test/v21/test_environment.py +++ b/stix2/test/v21/test_environment.py @@ -219,7 +219,8 @@ def test_parse_malware(): "name": "Cryptolocker", "malware_types": [ "ransomware" - ] + ], + "is_family": False }""" mal = env.parse(data, version="2.1") @@ -230,6 +231,7 @@ def test_parse_malware(): assert mal.modified == FAKE_TIME assert mal.malware_types == ['ransomware'] assert mal.name == "Cryptolocker" + assert not mal.is_family def test_creator_of(): @@ -351,6 +353,7 @@ def test_related_to_no_id(ds): mal = { "type": "malware", "name": "some variant", + "is_family": False, } with pytest.raises(ValueError) as excinfo: env.related_to(mal) diff --git a/stix2/test/v21/test_indicator.py b/stix2/test/v21/test_indicator.py index 49bc6e07..d0611048 100644 --- a/stix2/test/v21/test_indicator.py +++ b/stix2/test/v21/test_indicator.py @@ -98,7 +98,7 @@ def test_indicator_required_properties(): stix2.v21.Indicator() assert excinfo.value.cls == stix2.v21.Indicator - assert excinfo.value.properties == ["indicator_types", "pattern"] + assert excinfo.value.properties == ["indicator_types", "pattern", "valid_from"] assert str(excinfo.value) == "No values for required properties for Indicator: (indicator_types, pattern)." @@ -107,7 +107,7 @@ def test_indicator_required_property_pattern(): stix2.v21.Indicator(indicator_types=['malicious-activity']) assert excinfo.value.cls == stix2.v21.Indicator - assert excinfo.value.properties == ["pattern"] + assert excinfo.value.properties == ["pattern", "valid_from"] def test_indicator_created_ref_invalid_format(): @@ -184,6 +184,7 @@ def test_invalid_indicator_pattern(): stix2.v21.Indicator( indicator_types=['malicious-activity'], pattern="file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e'", + valid_from="2017-01-01T12:34:56Z", ) assert excinfo.value.cls == stix2.v21.Indicator assert excinfo.value.prop_name == 'pattern' diff --git a/stix2/test/v21/test_malware.py b/stix2/test/v21/test_malware.py index c55bfa9a..e6dfc2e4 100644 --- a/stix2/test/v21/test_malware.py +++ b/stix2/test/v21/test_malware.py @@ -17,7 +17,8 @@ "name": "Cryptolocker", "malware_types": [ "ransomware" - ] + ], + "is_family": False }""" @@ -31,6 +32,7 @@ def test_malware_with_all_required_properties(): modified=now, malware_types=["ransomware"], name="Cryptolocker", + is_family=False, ) assert str(mal) == EXPECTED_MALWARE @@ -77,7 +79,7 @@ def test_malware_required_properties(): stix2.v21.Malware() assert excinfo.value.cls == stix2.v21.Malware - assert excinfo.value.properties == ["malware_types", "name"] + assert excinfo.value.properties == ["is_family", "malware_types", "name"] def test_malware_required_property_name(): @@ -85,7 +87,7 @@ def test_malware_required_property_name(): stix2.v21.Malware(malware_types=['ransomware']) assert excinfo.value.cls == stix2.v21.Malware - assert excinfo.value.properties == ["name"] + assert excinfo.value.properties == ["is_family", "name"] def test_cannot_assign_to_malware_attributes(malware): @@ -115,6 +117,7 @@ def test_invalid_kwarg_to_malware(): "modified": "2016-05-12T08:17:27.000Z", "malware_types": ["ransomware"], "name": "Cryptolocker", + "is_family": False, }, ], ) @@ -128,6 +131,7 @@ def test_parse_malware(data): assert mal.modified == dt.datetime(2016, 5, 12, 8, 17, 27, tzinfo=pytz.utc) assert mal.malware_types == ['ransomware'] assert mal.name == 'Cryptolocker' + assert not mal.is_family def test_parse_malware_invalid_labels(): diff --git a/stix2/test/v21/test_versioning.py b/stix2/test/v21/test_versioning.py index a7f4a2f6..c46183cf 100644 --- a/stix2/test/v21/test_versioning.py +++ b/stix2/test/v21/test_versioning.py @@ -230,6 +230,7 @@ def test_remove_custom_stix_property(): malware_types=["rootkit"], x_custom="armada", allow_custom=True, + is_family=False, ) mal_nc = stix2.utils.remove_custom_stix(mal) diff --git a/stix2/test/v21/test_workbench.py b/stix2/test/v21/test_workbench.py index 0a976d7d..0d844223 100644 --- a/stix2/test/v21/test_workbench.py +++ b/stix2/test/v21/test_workbench.py @@ -199,7 +199,7 @@ def test_workbench_related(): def test_workbench_related_with_filters(): malware = Malware( malware_types=["ransomware"], name="CryptorBit", - created_by_ref=IDENTITY_ID, + created_by_ref=IDENTITY_ID, is_family=False, ) rel = Relationship(malware.id, 'variant-of', MALWARE_ID) save([malware, rel]) diff --git a/stix2/v21/sdo.py b/stix2/v21/sdo.py index 0ae0c80f..8ec4131f 100644 --- a/stix2/v21/sdo.py +++ b/stix2/v21/sdo.py @@ -198,7 +198,7 @@ class Indicator(STIXDomainObject): ('description', StringProperty()), ('indicator_types', ListProperty(StringProperty, required=True)), ('pattern', PatternProperty(required=True)), - ('valid_from', TimestampProperty(default=lambda: NOW)), + ('valid_from', TimestampProperty(default=lambda: NOW, required=True)), ('valid_until', TimestampProperty()), ('kill_chain_phases', ListProperty(KillChainPhase)), ('revoked', BooleanProperty(default=lambda: False)), @@ -683,6 +683,7 @@ class Tool(STIXDomainObject): ('name', StringProperty(required=True)), ('description', StringProperty()), ('tool_types', ListProperty(StringProperty, required=True)), + ('aliases', ListProperty(StringProperty)), ('kill_chain_phases', ListProperty(KillChainPhase)), ('tool_version', StringProperty()), ('revoked', BooleanProperty(default=lambda: False)), From ffbf5fa34cf26a84e03d3c704c934c22d2eb63b8 Mon Sep 17 00:00:00 2001 From: "Desai, Kartikey H" Date: Mon, 1 Jul 2019 15:41:44 -0400 Subject: [PATCH 3/5] Fix JSON encoding issue within tests --- stix2/test/v21/test_bundle.py | 2 +- stix2/test/v21/test_environment.py | 2 +- stix2/test/v21/test_indicator.py | 3 ++- stix2/test/v21/test_malware.py | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/stix2/test/v21/test_bundle.py b/stix2/test/v21/test_bundle.py index 9b782152..a884b1fd 100644 --- a/stix2/test/v21/test_bundle.py +++ b/stix2/test/v21/test_bundle.py @@ -32,7 +32,7 @@ "malware_types": [ "ransomware" ], - "is_family": False + "is_family": "False" }, { "type": "relationship", diff --git a/stix2/test/v21/test_environment.py b/stix2/test/v21/test_environment.py index 53ab744f..6887e417 100644 --- a/stix2/test/v21/test_environment.py +++ b/stix2/test/v21/test_environment.py @@ -220,7 +220,7 @@ def test_parse_malware(): "malware_types": [ "ransomware" ], - "is_family": False + "is_family": "False" }""" mal = env.parse(data, version="2.1") diff --git a/stix2/test/v21/test_indicator.py b/stix2/test/v21/test_indicator.py index d0611048..b68b887d 100644 --- a/stix2/test/v21/test_indicator.py +++ b/stix2/test/v21/test_indicator.py @@ -99,7 +99,7 @@ def test_indicator_required_properties(): assert excinfo.value.cls == stix2.v21.Indicator assert excinfo.value.properties == ["indicator_types", "pattern", "valid_from"] - assert str(excinfo.value) == "No values for required properties for Indicator: (indicator_types, pattern)." + assert str(excinfo.value) == "No values for required properties for Indicator: (indicator_types, pattern, valid_from)." def test_indicator_required_property_pattern(): @@ -194,6 +194,7 @@ def test_invalid_indicator_pattern(): stix2.v21.Indicator( indicator_types=['malicious-activity'], pattern='[file:hashes.MD5 = "d41d8cd98f00b204e9800998ecf8427e"]', + valid_from="2017-01-01T12:34:56Z", ) assert excinfo.value.cls == stix2.v21.Indicator assert excinfo.value.prop_name == 'pattern' diff --git a/stix2/test/v21/test_malware.py b/stix2/test/v21/test_malware.py index e6dfc2e4..bf5b5383 100644 --- a/stix2/test/v21/test_malware.py +++ b/stix2/test/v21/test_malware.py @@ -18,7 +18,7 @@ "malware_types": [ "ransomware" ], - "is_family": False + "is_family": "False" }""" From ae35d2ab01146942e3b29ad9d3747830ba3ac85e Mon Sep 17 00:00:00 2001 From: "Desai, Kartikey H" Date: Tue, 2 Jul 2019 13:17:43 -0400 Subject: [PATCH 4/5] Add and update tests to conform code to WD04 SDO specs --- stix2/test/v21/conftest.py | 13 +- stix2/test/v21/constants.py | 12 ++ ...-6b616fc1-1505-48e3-8b2c-0d19337bff38.json | 3 +- .../20170531213258226477.json | 3 +- .../20181101232448456000.json | 3 +- .../20181101232448457000.json | 3 +- .../20170531213326565056.json | 3 +- .../20170531213248482655.json | 3 +- .../20170531213215263882.json | 3 +- stix2/test/v21/test_bundle.py | 2 +- stix2/test/v21/test_environment.py | 2 +- stix2/test/v21/test_grouping.py | 112 +++++++++++++ stix2/test/v21/test_infrastructure.py | 158 ++++++++++++++++++ stix2/test/v21/test_malware.py | 9 +- stix2/v21/__init__.py | 9 +- 15 files changed, 324 insertions(+), 14 deletions(-) create mode 100644 stix2/test/v21/test_grouping.py create mode 100644 stix2/test/v21/test_infrastructure.py diff --git a/stix2/test/v21/conftest.py b/stix2/test/v21/conftest.py index dea29ca2..ea2853d0 100644 --- a/stix2/test/v21/conftest.py +++ b/stix2/test/v21/conftest.py @@ -5,7 +5,8 @@ import stix2 from .constants import ( - FAKE_TIME, INDICATOR_KWARGS, MALWARE_KWARGS, RELATIONSHIP_KWARGS, + FAKE_TIME, GROUPING_KWARGS, INDICATOR_KWARGS, INFRASTRUCTURE_KWARGS, + MALWARE_KWARGS, RELATIONSHIP_KWARGS, ) @@ -39,6 +40,16 @@ def indicator(uuid4, clock): return stix2.v21.Indicator(**INDICATOR_KWARGS) +@pytest.fixture +def infrastructure(uuid4, clock): + return stix2.v21.Infrastructure(**INFRASTRUCTURE_KWARGS) + + +@pytest.fixture +def grouping(uuid4, clock): + return stix2.v21.Grouping(**GROUPING_KWARGS) + + @pytest.fixture def malware(uuid4, clock): return stix2.v21.Malware(**MALWARE_KWARGS) diff --git a/stix2/test/v21/constants.py b/stix2/test/v21/constants.py index 66cb9566..40a2bb54 100644 --- a/stix2/test/v21/constants.py +++ b/stix2/test/v21/constants.py @@ -7,8 +7,10 @@ ATTACK_PATTERN_ID = "attack-pattern--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061" CAMPAIGN_ID = "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f" COURSE_OF_ACTION_ID = "course-of-action--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f" +GROUPING_ID = "grouping--753abcde-3141-5926-ace5-0a810b1ff996" IDENTITY_ID = "identity--311b2d2d-f010-4473-83ec-1edf84858f4c" INDICATOR_ID = "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7" +INFRASTRUCTURE_ID = "infrastructure--3000ae1b-784c-f03d-8abc-0a625b2ff018" INTRUSION_SET_ID = "intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29" LOCATION_ID = "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64" MALWARE_ID = "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e" @@ -70,6 +72,11 @@ name="Block", ) +GROUPING_KWARGS = dict( + name="Harry Potter and the Leet Hackers", + context="suspicious-activity", +) + IDENTITY_KWARGS = dict( name="John Smith", identity_class="individual", @@ -81,6 +88,11 @@ valid_from="2017-01-01T12:34:56Z", ) +INFRASTRUCTURE_KWARGS = dict( + name="Poison Ivy C2", + infrastructure_types=["command-and-control"], +) + INTRUSION_SET_KWARGS = dict( name="Bobcat Breakin", ) diff --git a/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38.json b/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38.json index 54343ce9..23e28bb6 100644 --- a/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38.json +++ b/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38.json @@ -24,5 +24,6 @@ ], "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" - ] + ], + "is_family": false } diff --git a/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20170531213258226477.json b/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20170531213258226477.json index 1bedc5b4..f65449df 100644 --- a/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20170531213258226477.json +++ b/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20170531213258226477.json @@ -27,7 +27,8 @@ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], "spec_version": "2.1", - "type": "malware" + "type": "malware", + "is_family": false } ], "type": "bundle" diff --git a/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20181101232448456000.json b/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20181101232448456000.json index 4236920c..1b22cf28 100644 --- a/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20181101232448456000.json +++ b/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20181101232448456000.json @@ -24,5 +24,6 @@ ], "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" - ] + ], + "is_family": false } diff --git a/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20181101232448457000.json b/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20181101232448457000.json index 37dd9c5b..7802c50f 100644 --- a/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20181101232448457000.json +++ b/stix2/test/v21/stix2_data/malware/malware--6b616fc1-1505-48e3-8b2c-0d19337bff38/20181101232448457000.json @@ -24,5 +24,6 @@ ], "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" - ] + ], + "is_family": false } diff --git a/stix2/test/v21/stix2_data/malware/malware--92ec0cbd-2c30-44a2-b270-73f4ec949841/20170531213326565056.json b/stix2/test/v21/stix2_data/malware/malware--92ec0cbd-2c30-44a2-b270-73f4ec949841/20170531213326565056.json index 0b7c01e5..24f38376 100644 --- a/stix2/test/v21/stix2_data/malware/malware--92ec0cbd-2c30-44a2-b270-73f4ec949841/20170531213326565056.json +++ b/stix2/test/v21/stix2_data/malware/malware--92ec0cbd-2c30-44a2-b270-73f4ec949841/20170531213326565056.json @@ -27,7 +27,8 @@ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], "spec_version": "2.1", - "type": "malware" + "type": "malware", + "is_family": false } ], "type": "bundle" diff --git a/stix2/test/v21/stix2_data/malware/malware--96b08451-b27a-4ff6-893f-790e26393a8e/20170531213248482655.json b/stix2/test/v21/stix2_data/malware/malware--96b08451-b27a-4ff6-893f-790e26393a8e/20170531213248482655.json index 195c973f..8495bfe5 100644 --- a/stix2/test/v21/stix2_data/malware/malware--96b08451-b27a-4ff6-893f-790e26393a8e/20170531213248482655.json +++ b/stix2/test/v21/stix2_data/malware/malware--96b08451-b27a-4ff6-893f-790e26393a8e/20170531213248482655.json @@ -27,7 +27,8 @@ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], "spec_version": "2.1", - "type": "malware" + "type": "malware", + "is_family": false } ], "type": "bundle" diff --git a/stix2/test/v21/stix2_data/malware/malware--b42378e0-f147-496f-992a-26a49705395b/20170531213215263882.json b/stix2/test/v21/stix2_data/malware/malware--b42378e0-f147-496f-992a-26a49705395b/20170531213215263882.json index 4d57db55..a509a5e4 100644 --- a/stix2/test/v21/stix2_data/malware/malware--b42378e0-f147-496f-992a-26a49705395b/20170531213215263882.json +++ b/stix2/test/v21/stix2_data/malware/malware--b42378e0-f147-496f-992a-26a49705395b/20170531213215263882.json @@ -26,7 +26,8 @@ "object_marking_refs": [ "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168" ], - "type": "malware" + "type": "malware", + "is_family": false } ], "spec_version": "2.0", diff --git a/stix2/test/v21/test_bundle.py b/stix2/test/v21/test_bundle.py index a884b1fd..7ba0729f 100644 --- a/stix2/test/v21/test_bundle.py +++ b/stix2/test/v21/test_bundle.py @@ -32,7 +32,7 @@ "malware_types": [ "ransomware" ], - "is_family": "False" + "is_family": false }, { "type": "relationship", diff --git a/stix2/test/v21/test_environment.py b/stix2/test/v21/test_environment.py index 6887e417..90f31cb5 100644 --- a/stix2/test/v21/test_environment.py +++ b/stix2/test/v21/test_environment.py @@ -220,7 +220,7 @@ def test_parse_malware(): "malware_types": [ "ransomware" ], - "is_family": "False" + "is_family": false }""" mal = env.parse(data, version="2.1") diff --git a/stix2/test/v21/test_grouping.py b/stix2/test/v21/test_grouping.py new file mode 100644 index 00000000..405a80c6 --- /dev/null +++ b/stix2/test/v21/test_grouping.py @@ -0,0 +1,112 @@ +import datetime as dt + +import pytest +import pytz + +import stix2 + +from .constants import FAKE_TIME, GROUPING_ID, GROUPING_KWARGS + +EXPECTED_GROUPING = """{ + "type": "grouping", + "spec_version": "2.1", + "id": "grouping--753abcde-3141-5926-ace5-0a810b1ff996", + "created": "2017-01-01T12:34:56.000Z", + "modified": "2017-01-01T12:34:56.000Z", + "name": "Harry Potter and the Leet Hackers", + "context": "suspicious-activity" +}""" + + +def test_grouping_with_all_required_properties(): + now = dt.datetime(2017, 1, 1, 12, 34, 56, tzinfo=pytz.utc) + + grp = stix2.v21.Grouping( + type="grouping", + id=GROUPING_ID, + created=now, + modified=now, + name="Harry Potter and the Leet Hackers", + context="suspicious-activity", + ) + + assert str(grp) == EXPECTED_GROUPING + + +def test_grouping_autogenerated_properties(grouping): + assert grouping.type == 'grouping' + assert grouping.id == 'grouping--00000000-0000-4000-8000-000000000001' + assert grouping.created == FAKE_TIME + assert grouping.modified == FAKE_TIME + assert grouping.name == "Harry Potter and the Leet Hackers" + assert grouping.context == "suspicious-activity" + + assert grouping['type'] == 'grouping' + assert grouping['id'] == 'grouping--00000000-0000-4000-8000-000000000001' + assert grouping['created'] == FAKE_TIME + assert grouping['modified'] == FAKE_TIME + assert grouping['name'] == "Harry Potter and the Leet Hackers" + assert grouping['context'] == "suspicious-activity" + + +def test_grouping_type_must_be_grouping(): + with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: + stix2.v21.Grouping(type='xxx', **GROUPING_KWARGS) + + assert excinfo.value.cls == stix2.v21.Grouping + assert excinfo.value.prop_name == "type" + assert excinfo.value.reason == "must equal 'grouping'." + assert str(excinfo.value) == "Invalid value for Grouping 'type': must equal 'grouping'." + + +def test_grouping_id_must_start_with_grouping(): + with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: + stix2.v21.Grouping(id='my-prefix--', **GROUPING_KWARGS) + + assert excinfo.value.cls == stix2.v21.Grouping + assert excinfo.value.prop_name == "id" + assert excinfo.value.reason == "must start with 'grouping--'." + assert str(excinfo.value) == "Invalid value for Grouping 'id': must start with 'grouping--'." + + +def test_grouping_required_properties(): + with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo: + stix2.v21.Grouping() + + assert excinfo.value.cls == stix2.v21.Grouping + assert excinfo.value.properties == ["context"] + + +def test_invalid_kwarg_to_grouping(): + with pytest.raises(stix2.exceptions.ExtraPropertiesError) as excinfo: + stix2.v21.Grouping(my_custom_property="foo", **GROUPING_KWARGS) + + assert excinfo.value.cls == stix2.v21.Grouping + assert excinfo.value.properties == ['my_custom_property'] + assert str(excinfo.value) == "Unexpected properties for Grouping: (my_custom_property)." + + +@pytest.mark.parametrize( + "data", [ + EXPECTED_GROUPING, + { + "type": "grouping", + "spec_version": "2.1", + "id": GROUPING_ID, + "created": "2017-01-01T12:34:56.000Z", + "modified": "2017-01-01T12:34:56.000Z", + "name": "Harry Potter and the Leet Hackers", + "context": "suspicious-activity", + }, + ], +) +def test_parse_grouping(data): + grp = stix2.parse(data) + + assert grp.type == 'grouping' + assert grp.spec_version == '2.1' + assert grp.id == GROUPING_ID + assert grp.created == dt.datetime(2017, 1, 1, 12, 34, 56, tzinfo=pytz.utc) + assert grp.modified == dt.datetime(2017, 1, 1, 12, 34, 56, tzinfo=pytz.utc) + assert grp.name == "Harry Potter and the Leet Hackers" + assert grp.context == "suspicious-activity" diff --git a/stix2/test/v21/test_infrastructure.py b/stix2/test/v21/test_infrastructure.py new file mode 100644 index 00000000..30632bb2 --- /dev/null +++ b/stix2/test/v21/test_infrastructure.py @@ -0,0 +1,158 @@ +import datetime as dt + +import pytest +import pytz + +import stix2 + +from .constants import FAKE_TIME, INFRASTRUCTURE_ID, INFRASTRUCTURE_KWARGS + +EXPECTED_INFRASTRUCTURE = """{ + "type": "infrastructure", + "spec_version": "2.1", + "id": "infrastructure--3000ae1b-784c-f03d-8abc-0a625b2ff018", + "created": "2017-01-01T12:34:56.000Z", + "modified": "2017-01-01T12:34:56.000Z", + "name": "Poison Ivy C2", + "infrastructure_types": [ + "command-and-control" + ] +}""" + + +def test_infrastructure_with_all_required_properties(): + now = dt.datetime(2017, 1, 1, 12, 34, 56, tzinfo=pytz.utc) + + infra = stix2.v21.Infrastructure( + type="infrastructure", + id=INFRASTRUCTURE_ID, + created=now, + modified=now, + name="Poison Ivy C2", + infrastructure_types=["command-and-control"], + ) + + assert str(infra) == EXPECTED_INFRASTRUCTURE + + +def test_infrastructure_autogenerated_properties(infrastructure): + assert infrastructure.type == 'infrastructure' + assert infrastructure.id == 'infrastructure--00000000-0000-4000-8000-000000000001' + assert infrastructure.created == FAKE_TIME + assert infrastructure.modified == FAKE_TIME + assert infrastructure.infrastructure_types == ['command-and-control'] + assert infrastructure.name == "Poison Ivy C2" + + assert infrastructure['type'] == 'infrastructure' + assert infrastructure['id'] == 'infrastructure--00000000-0000-4000-8000-000000000001' + assert infrastructure['created'] == FAKE_TIME + assert infrastructure['modified'] == FAKE_TIME + assert infrastructure['infrastructure_types'] == ['command-and-control'] + assert infrastructure['name'] == "Poison Ivy C2" + + +def test_infrastructure_type_must_be_infrastructure(): + with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: + stix2.v21.Infrastructure(type='xxx', **INFRASTRUCTURE_KWARGS) + + assert excinfo.value.cls == stix2.v21.Infrastructure + assert excinfo.value.prop_name == "type" + assert excinfo.value.reason == "must equal 'infrastructure'." + assert str(excinfo.value) == "Invalid value for Infrastructure 'type': must equal 'infrastructure'." + + +def test_infrastructure_id_must_start_with_infrastructure(): + with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: + stix2.v21.Infrastructure(id='my-prefix--', **INFRASTRUCTURE_KWARGS) + + assert excinfo.value.cls == stix2.v21.Infrastructure + assert excinfo.value.prop_name == "id" + assert excinfo.value.reason == "must start with 'infrastructure--'." + assert str(excinfo.value) == "Invalid value for Infrastructure 'id': must start with 'infrastructure--'." + + +def test_infrastructure_required_properties(): + with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo: + stix2.v21.Infrastructure() + + assert excinfo.value.cls == stix2.v21.Infrastructure + assert excinfo.value.properties == ["infrastructure_types", "name"] + + +def test_infrastructure_required_property_name(): + with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo: + stix2.v21.Infrastructure(infrastructure_types=['command-and-control']) + + assert excinfo.value.cls == stix2.v21.Infrastructure + assert excinfo.value.properties == ["name"] + + +def test_invalid_kwarg_to_infrastructure(): + with pytest.raises(stix2.exceptions.ExtraPropertiesError) as excinfo: + stix2.v21.Infrastructure(my_custom_property="foo", **INFRASTRUCTURE_KWARGS) + + assert excinfo.value.cls == stix2.v21.Infrastructure + assert excinfo.value.properties == ['my_custom_property'] + assert str(excinfo.value) == "Unexpected properties for Infrastructure: (my_custom_property)." + + +@pytest.mark.parametrize( + "data", [ + EXPECTED_INFRASTRUCTURE, + { + "type": "infrastructure", + "spec_version": "2.1", + "id": INFRASTRUCTURE_ID, + "created": "2017-01-01T12:34:56.000Z", + "modified": "2017-01-01T12:34:56.000Z", + "infrastructure_types": ["command-and-control"], + "name": "Poison Ivy C2", + }, + ], +) +def test_parse_infrastructure(data): + infra = stix2.parse(data) + + assert infra.type == 'infrastructure' + assert infra.spec_version == '2.1' + assert infra.id == INFRASTRUCTURE_ID + assert infra.created == dt.datetime(2017, 1, 1, 12, 34, 56, tzinfo=pytz.utc) + assert infra.modified == dt.datetime(2017, 1, 1, 12, 34, 56, tzinfo=pytz.utc) + assert infra.infrastructure_types == ['command-and-control'] + assert infra.name == 'Poison Ivy C2' + + +def test_parse_infrastructure_kill_chain_phases(): + kill_chain = """ + "kill_chain_phases": [ + { + "kill_chain_name": "lockheed-martin-cyber-kill-chain", + "phase_name": "reconnaissance" + } + ]""" + data = EXPECTED_INFRASTRUCTURE.replace('infrastructure"', 'infrastructure",%s' % kill_chain) + infra = stix2.parse(data, version="2.1") + assert infra.kill_chain_phases[0].kill_chain_name == "lockheed-martin-cyber-kill-chain" + assert infra.kill_chain_phases[0].phase_name == "reconnaissance" + assert infra['kill_chain_phases'][0]['kill_chain_name'] == "lockheed-martin-cyber-kill-chain" + assert infra['kill_chain_phases'][0]['phase_name'] == "reconnaissance" + + +def test_parse_infrastructure_clean_kill_chain_phases(): + kill_chain = """ + "kill_chain_phases": [ + { + "kill_chain_name": "lockheed-martin-cyber-kill-chain", + "phase_name": 1 + } + ]""" + data = EXPECTED_INFRASTRUCTURE.replace('2.1"', '2.1",%s' % kill_chain) + infra = stix2.parse(data, version="2.1") + assert infra['kill_chain_phases'][0]['phase_name'] == "1" + + +def test_infrastructure_invalid_last_before_first(): + with pytest.raises(ValueError) as excinfo: + stix2.v21.Infrastructure(first_seen="2017-01-01T12:34:56.000Z", last_seen="2017-01-01T12:33:56.000Z", **INFRASTRUCTURE_KWARGS) + + assert "'last_seen' must be greater than or equal to 'first_seen'" in str(excinfo.value) diff --git a/stix2/test/v21/test_malware.py b/stix2/test/v21/test_malware.py index bf5b5383..1817c63d 100644 --- a/stix2/test/v21/test_malware.py +++ b/stix2/test/v21/test_malware.py @@ -18,7 +18,7 @@ "malware_types": [ "ransomware" ], - "is_family": "False" + "is_family": false }""" @@ -168,3 +168,10 @@ def test_parse_malware_clean_kill_chain_phases(): data = EXPECTED_MALWARE.replace('2.1"', '2.1",%s' % kill_chain) mal = stix2.parse(data, version="2.1") assert mal['kill_chain_phases'][0]['phase_name'] == "1" + + +def test_malware_invalid_last_before_first(): + with pytest.raises(ValueError) as excinfo: + stix2.v21.Malware(first_seen="2017-01-01T12:34:56.000Z", last_seen="2017-01-01T12:33:56.000Z", **MALWARE_KWARGS) + + assert "'last_seen' must be greater than or equal to 'first_seen'" in str(excinfo.value) diff --git a/stix2/v21/__init__.py b/stix2/v21/__init__.py index efac0718..b2451d25 100644 --- a/stix2/v21/__init__.py +++ b/stix2/v21/__init__.py @@ -32,9 +32,10 @@ X509Certificate, X509V3ExtenstionsType, ) from .sdo import ( - AttackPattern, Campaign, CourseOfAction, CustomObject, Identity, Indicator, - IntrusionSet, Location, Malware, MalwareAnalysis, Note, ObservedData, - Opinion, Report, ThreatActor, Tool, Vulnerability, + AttackPattern, Campaign, CourseOfAction, CustomObject, Grouping, Identity, + Indicator, Infrastructure, IntrusionSet, Location, Malware, + MalwareAnalysis, Note, ObservedData, Opinion, Report, ThreatActor, Tool, + Vulnerability, ) from .sro import Relationship, Sighting @@ -43,8 +44,10 @@ 'bundle': Bundle, 'campaign': Campaign, 'course-of-action': CourseOfAction, + 'grouping': Grouping, 'identity': Identity, 'indicator': Indicator, + 'infrastructure': Infrastructure, 'intrusion-set': IntrusionSet, 'language-content': LanguageContent, 'location': Location, From b464a9cc0ab82b9ef5c491a0c9e92e7fb005d895 Mon Sep 17 00:00:00 2001 From: "Desai, Kartikey H" Date: Tue, 9 Jul 2019 13:34:19 -0400 Subject: [PATCH 5/5] Remove certain human message assertions from test suites --- stix2/test/v20/test_datastore_filesystem.py | 9 ++--- stix2/test/v20/test_pattern_expressions.py | 39 +++++++-------------- stix2/test/v21/test_datastore_filesystem.py | 6 ++-- stix2/test/v21/test_pattern_expressions.py | 39 +++++++-------------- 4 files changed, 31 insertions(+), 62 deletions(-) diff --git a/stix2/test/v20/test_datastore_filesystem.py b/stix2/test/v20/test_datastore_filesystem.py index 25de37e2..317f927b 100644 --- a/stix2/test/v20/test_datastore_filesystem.py +++ b/stix2/test/v20/test_datastore_filesystem.py @@ -125,15 +125,13 @@ def rel_fs_store(): def test_filesystem_source_nonexistent_folder(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.FileSystemSource('nonexistent-folder') - assert "for STIX data does not exist" in str(excinfo) def test_filesystem_sink_nonexistent_folder(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.FileSystemSink('nonexistent-folder') - assert "for STIX data does not exist" in str(excinfo) def test_filesystem_source_bad_json_file(fs_source, bad_json_files): @@ -441,9 +439,8 @@ def test_filesystem_attempt_stix_file_overwrite(fs_store): ) # Now attempt to overwrite the existing file - with pytest.raises(DataSourceError) as excinfo: + with pytest.raises(DataSourceError): fs_store.add(camp8) - assert "Attempted to overwrite file" in str(excinfo) os.remove(filepath) diff --git a/stix2/test/v20/test_pattern_expressions.py b/stix2/test/v20/test_pattern_expressions.py index 3dc7cde9..23a401ba 100644 --- a/stix2/test/v20/test_pattern_expressions.py +++ b/stix2/test/v20/test_pattern_expressions.py @@ -257,7 +257,7 @@ def test_and_observable_expression(): def test_invalid_and_observable_expression(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.AndBooleanExpression([ stix2.EqualityComparisonExpression( "user-account:display_name", @@ -268,7 +268,6 @@ def test_invalid_and_observable_expression(): stix2.StringConstant("admin"), ), ]) - assert "All operands to an 'AND' expression must have the same object type" in str(excinfo) def test_hex(): @@ -352,30 +351,26 @@ def test_list2(): def test_invalid_constant_type(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.EqualityComparisonExpression( "artifact:payload_bin", {'foo': 'bar'}, ) - assert 'Unable to create a constant' in str(excinfo) def test_invalid_integer_constant(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.IntegerConstant('foo') - assert 'must be an integer' in str(excinfo) def test_invalid_timestamp_constant(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.TimestampConstant('foo') - assert 'Must be a datetime object or timestamp string' in str(excinfo) def test_invalid_float_constant(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.FloatConstant('foo') - assert 'must be a float' in str(excinfo) @pytest.mark.parametrize( @@ -400,9 +395,8 @@ def test_boolean_constant(data, result): def test_invalid_boolean_constant(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.BooleanConstant('foo') - assert 'must be a boolean' in str(excinfo) @pytest.mark.parametrize( @@ -412,21 +406,18 @@ def test_invalid_boolean_constant(): ], ) def test_invalid_hash_constant(hashtype, data): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.HashConstant(data, hashtype) - assert 'is not a valid {} hash'.format(hashtype) in str(excinfo) def test_invalid_hex_constant(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.HexConstant('mm') - assert "must contain an even number of hexadecimal characters" in str(excinfo) def test_invalid_binary_constant(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.BinaryConstant('foo') - assert 'must contain a base64' in str(excinfo) def test_escape_quotes_and_backslashes(): @@ -459,15 +450,13 @@ def test_repeat_qualifier(): def test_invalid_repeat_qualifier(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.RepeatQualifier('foo') - assert 'is not a valid argument for a Repeat Qualifier' in str(excinfo) def test_invalid_within_qualifier(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.WithinQualifier('foo') - assert 'is not a valid argument for a Within Qualifier' in str(excinfo) def test_startstop_qualifier(): @@ -485,19 +474,17 @@ def test_startstop_qualifier(): def test_invalid_startstop_qualifier(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.StartStopQualifier( 'foo', stix2.TimestampConstant('2016-06-01T00:00:00Z'), ) - assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo) - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.StartStopQualifier( datetime.date(2016, 6, 1), 'foo', ) - assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo) def test_make_constant_already_a_constant(): diff --git a/stix2/test/v21/test_datastore_filesystem.py b/stix2/test/v21/test_datastore_filesystem.py index 34b10881..9917ccd0 100644 --- a/stix2/test/v21/test_datastore_filesystem.py +++ b/stix2/test/v21/test_datastore_filesystem.py @@ -124,15 +124,13 @@ def rel_fs_store(): def test_filesystem_source_nonexistent_folder(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.FileSystemSource('nonexistent-folder') - assert "for STIX data does not exist" in str(excinfo) def test_filesystem_sink_nonexistent_folder(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.FileSystemSink('nonexistent-folder') - assert "for STIX data does not exist" in str(excinfo) def test_filesystem_source_bad_json_file(fs_source, bad_json_files): diff --git a/stix2/test/v21/test_pattern_expressions.py b/stix2/test/v21/test_pattern_expressions.py index 3dc7cde9..23a401ba 100644 --- a/stix2/test/v21/test_pattern_expressions.py +++ b/stix2/test/v21/test_pattern_expressions.py @@ -257,7 +257,7 @@ def test_and_observable_expression(): def test_invalid_and_observable_expression(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.AndBooleanExpression([ stix2.EqualityComparisonExpression( "user-account:display_name", @@ -268,7 +268,6 @@ def test_invalid_and_observable_expression(): stix2.StringConstant("admin"), ), ]) - assert "All operands to an 'AND' expression must have the same object type" in str(excinfo) def test_hex(): @@ -352,30 +351,26 @@ def test_list2(): def test_invalid_constant_type(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.EqualityComparisonExpression( "artifact:payload_bin", {'foo': 'bar'}, ) - assert 'Unable to create a constant' in str(excinfo) def test_invalid_integer_constant(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.IntegerConstant('foo') - assert 'must be an integer' in str(excinfo) def test_invalid_timestamp_constant(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.TimestampConstant('foo') - assert 'Must be a datetime object or timestamp string' in str(excinfo) def test_invalid_float_constant(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.FloatConstant('foo') - assert 'must be a float' in str(excinfo) @pytest.mark.parametrize( @@ -400,9 +395,8 @@ def test_boolean_constant(data, result): def test_invalid_boolean_constant(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.BooleanConstant('foo') - assert 'must be a boolean' in str(excinfo) @pytest.mark.parametrize( @@ -412,21 +406,18 @@ def test_invalid_boolean_constant(): ], ) def test_invalid_hash_constant(hashtype, data): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.HashConstant(data, hashtype) - assert 'is not a valid {} hash'.format(hashtype) in str(excinfo) def test_invalid_hex_constant(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.HexConstant('mm') - assert "must contain an even number of hexadecimal characters" in str(excinfo) def test_invalid_binary_constant(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.BinaryConstant('foo') - assert 'must contain a base64' in str(excinfo) def test_escape_quotes_and_backslashes(): @@ -459,15 +450,13 @@ def test_repeat_qualifier(): def test_invalid_repeat_qualifier(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.RepeatQualifier('foo') - assert 'is not a valid argument for a Repeat Qualifier' in str(excinfo) def test_invalid_within_qualifier(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.WithinQualifier('foo') - assert 'is not a valid argument for a Within Qualifier' in str(excinfo) def test_startstop_qualifier(): @@ -485,19 +474,17 @@ def test_startstop_qualifier(): def test_invalid_startstop_qualifier(): - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.StartStopQualifier( 'foo', stix2.TimestampConstant('2016-06-01T00:00:00Z'), ) - assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo) - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): stix2.StartStopQualifier( datetime.date(2016, 6, 1), 'foo', ) - assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo) def test_make_constant_already_a_constant():