diff --git a/stix2/__init__.py b/stix2/__init__.py index 52a19ef..c82afd4 100644 --- a/stix2/__init__.py +++ b/stix2/__init__.py @@ -24,10 +24,33 @@ def parse(data): except TypeError: obj = json.load(data) + obj_map = { + 'attack-pattern': AttackPattern, + 'campaign': Campaign, + 'course-of-action': CourseOfAction, + 'identity': Identity, + 'indicator': Indicator, + 'intrusion-set': IntrusionSet, + 'malware': Malware, + 'marking-definition': MarkingDefinition, + 'observed-data': ObservedData, + 'report': Report, + 'relationship': Relationship, + 'threat-actor': ThreatActor, + 'tool': Tool, + 'sighting': Sighting, + 'vulnerability': Vulnerability, + } + if 'type' not in obj: # TODO parse external references, kill chain phases, and granular markings pass - elif obj['type'] == 'malware': - return sdo.Malware(**obj) + else: + try: + obj_class = obj_map[obj['type']] + return obj_class(**obj) + except KeyError: + # TODO handle custom objects + raise ValueError("Can't parse unknown object type!") return obj diff --git a/stix2/test/constants.py b/stix2/test/constants.py index 6d88a84..1c8ae2b 100644 --- a/stix2/test/constants.py +++ b/stix2/test/constants.py @@ -4,11 +4,21 @@ import pytz FAKE_TIME = dt.datetime(2017, 1, 1, 12, 34, 56, tzinfo=pytz.utc) +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" +IDENTITY_ID = "identity--311b2d2d-f010-5473-83ec-1edf84858f4c" INDICATOR_ID = "indicator--01234567-89ab-cdef-0123-456789abcdef" +INTRUSION_SET_ID = "intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29" MALWARE_ID = "malware--fedcba98-7654-3210-fedc-ba9876543210" +MARKING_DEFINITION_ID = "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9" +OBSERVED_DATA_ID = "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf" +REPORT_ID = "report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3" RELATIONSHIP_ID = "relationship--00000000-1111-2222-3333-444444444444" -IDENTITY_ID = "identity--d4d765ce-cff7-40e8-b7a6-e205d005ac2c" +THREAT_ACTOR_ID = "threat-actor--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f" +TOOL_ID = "tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f" SIGHTING_ID = "sighting--bfbc19db-ec35-4e45-beed-f8bde2a772fb" +VULNERABILITY_ID = "vulnerability--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061" # Minimum required args for an Indicator instance INDICATOR_KWARGS = dict( diff --git a/stix2/test/test_attack_pattern.py b/stix2/test/test_attack_pattern.py index 36b5b6d..ec82516 100644 --- a/stix2/test/test_attack_pattern.py +++ b/stix2/test/test_attack_pattern.py @@ -1,5 +1,10 @@ +import pytest +import pytz +import datetime as dt import stix2 +from .constants import ATTACK_PATTERN_ID + EXPECTED = """{ "created": "2016-05-12T08:17:27Z", "description": "...", @@ -32,4 +37,33 @@ def test_attack_pattern_example(): assert str(ap) == EXPECTED +@pytest.mark.parametrize("data", [ + EXPECTED, + { + "type": "attack-pattern", + "id": "attack-pattern--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061", + "created": "2016-05-12T08:17:27Z", + "modified": "2016-05-12T08:17:27Z", + "description": "...", + "external_references": [ + { + "id": "CAPEC-163", + "source_name": "capec" + } + ], + "name": "Spear Phishing", + }, +]) +def test_parse_attack_pattern(data): + ap = stix2.parse(data) + + assert ap.type == 'attack-pattern' + assert ap.id == ATTACK_PATTERN_ID + assert ap.created == dt.datetime(2016, 5, 12, 8, 17, 27, tzinfo=pytz.utc) + assert ap.modified == dt.datetime(2016, 5, 12, 8, 17, 27, tzinfo=pytz.utc) + assert ap.description == "..." + assert ap.external_references[0].id == ['CAPEC-163'] + assert ap.external_references[0].source_name == ['capec'] + assert ap.name == "Spear Phishing" + # TODO: Add other examples diff --git a/stix2/test/test_campaign.py b/stix2/test/test_campaign.py index 741f5ba..e1bec3b 100644 --- a/stix2/test/test_campaign.py +++ b/stix2/test/test_campaign.py @@ -1,5 +1,10 @@ +import pytest +import pytz +import datetime as dt import stix2 +from .constants import CAMPAIGN_ID + EXPECTED = """{ "created": "2016-04-06T20:03:00Z", "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", @@ -23,4 +28,28 @@ def test_campaign_example(): assert str(campaign) == EXPECTED + +@pytest.mark.parametrize("data", [ + EXPECTED, + { + "type": "campaign", + "id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", + "created": "2016-04-06T20:03:00Z", + "modified": "2016-04-06T20:03:00Z", + "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "description": "Campaign by Green Group against a series of targets in the financial services sector.", + "name": "Green Group Attacks Against Finance", + }, +]) +def test_parse_campaign(data): + cmpn = stix2.parse(data) + + assert cmpn.type == 'campaign' + assert cmpn.id == CAMPAIGN_ID + assert cmpn.created == dt.datetime(2016, 4, 6, 20, 3, 0, tzinfo=pytz.utc) + assert cmpn.modified == dt.datetime(2016, 4, 6, 20, 3, 0, tzinfo=pytz.utc) + assert cmpn.created_by_ref == "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff" + assert cmpn.description == "Campaign by Green Group against a series of targets in the financial services sector." + assert cmpn.name == "Green Group Attacks Against Finance" + # TODO: Add other examples diff --git a/stix2/test/test_course_of_action.py b/stix2/test/test_course_of_action.py index d35680e..3626539 100644 --- a/stix2/test/test_course_of_action.py +++ b/stix2/test/test_course_of_action.py @@ -1,5 +1,10 @@ +import pytest +import pytz +import datetime as dt import stix2 +from .constants import COURSE_OF_ACTION_ID + EXPECTED = """{ "created": "2016-04-06T20:03:48Z", "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", @@ -23,4 +28,28 @@ def test_course_of_action_example(): assert str(coa) == EXPECTED + +@pytest.mark.parametrize("data", [ + EXPECTED, + { + "created": "2016-04-06T20:03:48Z", + "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "description": "This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ...", + "id": "course-of-action--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", + "modified": "2016-04-06T20:03:48Z", + "name": "Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter", + "type": "course-of-action" + }, +]) +def test_parse_course_of_action(data): + coa = stix2.parse(data) + + assert coa.type == 'course-of-action' + assert coa.id == COURSE_OF_ACTION_ID + assert coa.created == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) + assert coa.modified == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) + assert coa.created_by_ref == "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff" + assert coa.description == "This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ..." + assert coa.name == "Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter" + # TODO: Add other examples diff --git a/stix2/test/test_identity.py b/stix2/test/test_identity.py index e43614e..00726c9 100644 --- a/stix2/test/test_identity.py +++ b/stix2/test/test_identity.py @@ -1,5 +1,10 @@ +import pytest +import pytz +import datetime as dt import stix2 +from .constants import IDENTITY_ID + EXPECTED = """{ "created": "2015-12-21T19:59:11Z", "id": "identity--311b2d2d-f010-5473-83ec-1edf84858f4c", @@ -21,4 +26,25 @@ def test_identity_example(): assert str(report) == EXPECTED + +@pytest.mark.parametrize("data", [ + EXPECTED, + { + "created": "2015-12-21T19:59:11Z", + "id": "identity--311b2d2d-f010-5473-83ec-1edf84858f4c", + "identity_class": "individual", + "modified": "2015-12-21T19:59:11Z", + "name": "John Smith", + "type": "identity" + }, +]) +def test_parse_identity(data): + identity = stix2.parse(data) + + assert identity.type == 'identity' + assert identity.id == IDENTITY_ID + assert identity.created == dt.datetime(2015, 12, 21, 19, 59, 11, tzinfo=pytz.utc) + assert identity.modified == dt.datetime(2015, 12, 21, 19, 59, 11, tzinfo=pytz.utc) + assert identity.name == "John Smith" + # TODO: Add other examples diff --git a/stix2/test/test_indicator.py b/stix2/test/test_indicator.py index 421f681..0ad5bb0 100644 --- a/stix2/test/test_indicator.py +++ b/stix2/test/test_indicator.py @@ -124,3 +124,29 @@ def test_created_modified_time_are_identical_by_default(): ind = stix2.Indicator(**INDICATOR_KWARGS) assert ind.created == ind.modified + + +@pytest.mark.parametrize("data", [ + EXPECTED_INDICATOR, + { + "type": "indicator", + "id": "indicator--01234567-89ab-cdef-0123-456789abcdef", + "created": "2017-01-01T00:00:01Z", + "modified": "2017-01-01T00:00:01Z", + "labels": [ + "malicious-activity" + ], + "pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']", + "valid_from": "1970-01-01T00:00:01Z" + }, +]) +def test_parse_indicator(data): + idctr = stix2.parse(data) + + assert idctr.type == 'indicator' + assert idctr.id == INDICATOR_ID + assert idctr.created == dt.datetime(2017, 1, 1, 0, 0, 1, tzinfo=pytz.utc) + assert idctr.modified == dt.datetime(2017, 1, 1, 0, 0, 1, tzinfo=pytz.utc) + assert idctr.valid_from == dt.datetime(1970, 1, 1, 0, 0, 1, tzinfo=pytz.utc) + assert idctr.labels[0] == "malicious-activity" + assert idctr.pattern == "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']" diff --git a/stix2/test/test_intrusion_set.py b/stix2/test/test_intrusion_set.py index e60532f..e6cf1cf 100644 --- a/stix2/test/test_intrusion_set.py +++ b/stix2/test/test_intrusion_set.py @@ -1,5 +1,10 @@ +import pytest +import pytz +import datetime as dt import stix2 +from .constants import INTRUSION_SET_ID + EXPECTED = """{ "aliases": [ "Zookeeper" @@ -33,4 +38,37 @@ def test_intrusion_set_example(): assert str(intrusion_set) == EXPECTED + +@pytest.mark.parametrize("data", [ + EXPECTED, + { + "aliases": [ + "Zookeeper" + ], + "created": "2016-04-06T20:03:48Z", + "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "description": "Incidents usually feature a shared TTP of a bobcat being released...", + "goals": [ + "acquisition-theft", + "harassment", + "damage" + ], + "id": "intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29", + "modified": "2016-04-06T20:03:48Z", + "name": "Bobcat Breakin", + "type": "intrusion-set" + }, +]) +def test_parse_intrusion_set(data): + intset = stix2.parse(data) + + assert intset.type == "intrusion-set" + assert intset.id == INTRUSION_SET_ID + assert intset.created == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) + assert intset.modified == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) + assert intset.goals == ["acquisition-theft", "harassment", "damage"] + assert intset.aliases == ["Zookeeper"] + assert intset.description == "Incidents usually feature a shared TTP of a bobcat being released..." + assert intset.name == "Bobcat Breakin" + # TODO: Add other examples diff --git a/stix2/test/test_observed_data.py b/stix2/test/test_observed_data.py index f47e43e..df3eaff 100644 --- a/stix2/test/test_observed_data.py +++ b/stix2/test/test_observed_data.py @@ -1,5 +1,10 @@ +import pytest +import pytz +import datetime as dt import stix2 +from .constants import OBSERVED_DATA_ID + EXPECTED = """{ "created": "2016-04-06T19:58:16Z", "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", @@ -35,4 +40,35 @@ def test_observed_data_example(): assert str(observed_data) == EXPECTED + +@pytest.mark.parametrize("data", [ + EXPECTED, + { + "type": "observed-data", + "id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", + "created": "2016-04-06T19:58:16Z", + "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "first_observed": "2015-12-21T19:00:00Z", + "last_observed": "2015-12-21T19:00:00Z", + "modified": "2016-04-06T19:58:16Z", + "number_observed": 50, + "objects": { + "0": { + "type": "file" + } + } + }, +]) +def test_parse_observed_data(data): + odata = stix2.parse(data) + + assert odata.type == 'observed-data' + assert odata.id == OBSERVED_DATA_ID + assert odata.created == dt.datetime(2016, 4, 6, 19, 58, 16, tzinfo=pytz.utc) + assert odata.modified == dt.datetime(2016, 4, 6, 19, 58, 16, tzinfo=pytz.utc) + assert odata.first_observed == dt.datetime(2015, 12, 21, 19, 0, 0, tzinfo=pytz.utc) + assert odata.last_observed == dt.datetime(2015, 12, 21, 19, 0, 0, tzinfo=pytz.utc) + assert odata.created_by_ref == "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff" + assert odata.objects["0"].type == "file" + # TODO: Add other examples diff --git a/stix2/test/test_relationship.py b/stix2/test/test_relationship.py index 0c96bb1..2ce3be5 100644 --- a/stix2/test/test_relationship.py +++ b/stix2/test/test_relationship.py @@ -121,3 +121,27 @@ def test_create_relationship_with_positional_args(indicator, malware): assert rel.source_ref == 'indicator--00000000-0000-0000-0000-000000000001' assert rel.target_ref == 'malware--00000000-0000-0000-0000-000000000002' assert rel.id == 'relationship--00000000-0000-0000-0000-000000000003' + + +@pytest.mark.parametrize("data", [ + EXPECTED_RELATIONSHIP, + { + "created": "2016-04-06T20:06:37Z", + "id": "relationship--00000000-1111-2222-3333-444444444444", + "modified": "2016-04-06T20:06:37Z", + "relationship_type": "indicates", + "source_ref": "indicator--01234567-89ab-cdef-0123-456789abcdef", + "target_ref": "malware--fedcba98-7654-3210-fedc-ba9876543210", + "type": "relationship" + }, +]) +def test_parse_relationship(data): + rel = stix2.parse(data) + + assert rel.type == 'relationship' + assert rel.id == RELATIONSHIP_ID + assert rel.created == dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc) + assert rel.modified == dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc) + assert rel.relationship_type == "indicates" + assert rel.source_ref == "indicator--01234567-89ab-cdef-0123-456789abcdef" + assert rel.target_ref == "malware--fedcba98-7654-3210-fedc-ba9876543210" diff --git a/stix2/test/test_report.py b/stix2/test/test_report.py index 2346658..a71c0cd 100644 --- a/stix2/test/test_report.py +++ b/stix2/test/test_report.py @@ -1,6 +1,8 @@ import stix2 import pytest -from .constants import INDICATOR_KWARGS +import pytz +import datetime as dt +from .constants import INDICATOR_KWARGS, REPORT_ID EXPECTED = """{ "created": "2015-12-21T19:59:11Z", @@ -82,4 +84,41 @@ def test_report_example_objects_in_object_refs_with_bad_id(): assert str(excinfo.value) == "Invalid value for Report 'object_refs': must match --." + +@pytest.mark.parametrize("data", [ + EXPECTED, + { + "created": "2015-12-21T19:59:11Z", + "created_by_ref": "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283", + "description": "A simple report with an indicator and campaign", + "id": "report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3", + "labels": [ + "campaign" + ], + "modified": "2015-12-21T19:59:11Z", + "name": "The Black Vine Cyberespionage Group", + "object_refs": [ + "indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", + "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", + "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a" + ], + "published": "2016-01-20T17:00:00Z", + "type": "report" + }, +]) +def test_parse_report(data): + rept = stix2.parse(data) + + assert rept.type == 'report' + assert rept.id == REPORT_ID + assert rept.created == dt.datetime(2015, 12, 21, 19, 59, 11, tzinfo=pytz.utc) + assert rept.modified == dt.datetime(2015, 12, 21, 19, 59, 11, tzinfo=pytz.utc) + assert rept.created_by_ref == "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283" + assert rept.object_refs == ["indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", + "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", + "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a"] + assert rept.description == "A simple report with an indicator and campaign" + assert rept.labels == ["campaign"] + assert rept.name == "The Black Vine Cyberespionage Group" + # TODO: Add other examples diff --git a/stix2/test/test_sighting.py b/stix2/test/test_sighting.py index ad30c63..b2b97df 100644 --- a/stix2/test/test_sighting.py +++ b/stix2/test/test_sighting.py @@ -79,3 +79,27 @@ def test_create_sighting_from_objects_rather_than_ids(malware): # noqa: F811 assert rel.sighting_of_ref == 'malware--00000000-0000-0000-0000-000000000001' assert rel.id == 'sighting--00000000-0000-0000-0000-000000000002' + + +@pytest.mark.parametrize("data", [ + EXPECTED_SIGHTING, + { + "created": "2016-04-06T20:06:37Z", + "id": "sighting--bfbc19db-ec35-4e45-beed-f8bde2a772fb", + "modified": "2016-04-06T20:06:37Z", + "sighting_of_ref": "indicator--01234567-89ab-cdef-0123-456789abcdef", + "type": "sighting", + "where_sighted_refs": [ + "identity--8cc7afd6-5455-4d2b-a736-e614ee631d99" + ] + }, +]) +def test_parse_sighting(data): + sighting = stix2.parse(data) + + assert sighting.type == 'sighting' + assert sighting.id == SIGHTING_ID + assert sighting.created == dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc) + assert sighting.modified == dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc) + assert sighting.sighting_of_ref == "indicator--01234567-89ab-cdef-0123-456789abcdef" + assert sighting.where_sighted_refs == ["identity--8cc7afd6-5455-4d2b-a736-e614ee631d99"] diff --git a/stix2/test/test_threat_actor.py b/stix2/test/test_threat_actor.py index c958f80..7eabbed 100644 --- a/stix2/test/test_threat_actor.py +++ b/stix2/test/test_threat_actor.py @@ -1,5 +1,10 @@ +import pytest +import pytz +import datetime as dt import stix2 +from .constants import THREAT_ACTOR_ID + EXPECTED = """{ "created": "2016-04-06T20:03:48Z", "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", @@ -27,4 +32,32 @@ def test_threat_actor_example(): assert str(threat_actor) == EXPECTED + +@pytest.mark.parametrize("data", [ + EXPECTED, + { + "created": "2016-04-06T20:03:48Z", + "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "description": "The Evil Org threat actor group", + "id": "threat-actor--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", + "labels": [ + "crime-syndicate" + ], + "modified": "2016-04-06T20:03:48Z", + "name": "Evil Org", + "type": "threat-actor" + }, +]) +def test_parse_threat_actor(data): + actor = stix2.parse(data) + + assert actor.type == 'threat-actor' + assert actor.id == THREAT_ACTOR_ID + assert actor.created == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) + assert actor.modified == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) + assert actor.created_by_ref == "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff" + assert actor.description == "The Evil Org threat actor group" + assert actor.name == "Evil Org" + assert actor.labels == ["crime-syndicate"] + # TODO: Add other examples diff --git a/stix2/test/test_tool.py b/stix2/test/test_tool.py index 322ff11..0e4cd5c 100644 --- a/stix2/test/test_tool.py +++ b/stix2/test/test_tool.py @@ -1,5 +1,10 @@ +import pytest +import pytz +import datetime as dt import stix2 +from .constants import TOOL_ID + EXPECTED = """{ "created": "2016-04-06T20:03:48Z", "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", @@ -25,4 +30,30 @@ def test_tool_example(): assert str(tool) == EXPECTED + +@pytest.mark.parametrize("data", [ + EXPECTED, + { + "created": "2016-04-06T20:03:48Z", + "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", + "id": "tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", + "labels": [ + "remote-access" + ], + "modified": "2016-04-06T20:03:48Z", + "name": "VNC", + "type": "tool" + }, +]) +def test_parse_tool(data): + tool = stix2.parse(data) + + assert tool.type == 'tool' + assert tool.id == TOOL_ID + assert tool.created == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) + assert tool.modified == dt.datetime(2016, 4, 6, 20, 3, 48, tzinfo=pytz.utc) + assert tool.created_by_ref == "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff" + assert tool.labels == ["remote-access"] + assert tool.name == "VNC" + # TODO: Add other examples diff --git a/stix2/test/test_vulnerability.py b/stix2/test/test_vulnerability.py index ee84533..bfa9c26 100644 --- a/stix2/test/test_vulnerability.py +++ b/stix2/test/test_vulnerability.py @@ -1,5 +1,10 @@ +import pytest +import pytz +import datetime as dt import stix2 +from .constants import VULNERABILITY_ID + EXPECTED = """{ "created": "2016-05-12T08:17:27Z", "external_references": [ @@ -29,4 +34,32 @@ def test_vulnerability_example(): assert str(vulnerability) == EXPECTED + +@pytest.mark.parametrize("data", [ + EXPECTED, + { + "created": "2016-05-12T08:17:27Z", + "external_references": [ + { + "external_id": "CVE-2016-1234", + "source_name": "cve" + } + ], + "id": "vulnerability--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061", + "modified": "2016-05-12T08:17:27Z", + "name": "CVE-2016-1234", + "type": "vulnerability" + }, +]) +def test_parse_vulnerability(data): + vuln = stix2.parse(data) + + assert vuln.type == 'vulnerability' + assert vuln.id == VULNERABILITY_ID + assert vuln.created == dt.datetime(2016, 5, 12, 8, 17, 27, tzinfo=pytz.utc) + assert vuln.modified == dt.datetime(2016, 5, 12, 8, 17, 27, tzinfo=pytz.utc) + assert vuln.name == "CVE-2016-1234" + assert vuln.external_references[0].external_id == "CVE-2016-1234" + assert vuln.external_references[0].source_name == "cve" + # TODO: Add other examples