Add and update tests to conform code to WD04 SDO specs

master
Desai, Kartikey H 2019-07-02 13:17:43 -04:00
parent ffbf5fa34c
commit ae35d2ab01
15 changed files with 324 additions and 14 deletions

View File

@ -5,7 +5,8 @@ import pytest
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)

View File

@ -7,8 +7,10 @@ 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"
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 @@ COURSE_OF_ACTION_KWARGS = dict(
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 @@ INDICATOR_KWARGS = dict(
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",
)

View File

@ -24,5 +24,6 @@
],
"object_marking_refs": [
"marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168"
]
],
"is_family": false
}

View File

@ -27,7 +27,8 @@
"marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168"
],
"spec_version": "2.1",
"type": "malware"
"type": "malware",
"is_family": false
}
],
"type": "bundle"

View File

@ -24,5 +24,6 @@
],
"object_marking_refs": [
"marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168"
]
],
"is_family": false
}

View File

@ -24,5 +24,6 @@
],
"object_marking_refs": [
"marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168"
]
],
"is_family": false
}

View File

@ -27,7 +27,8 @@
"marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168"
],
"spec_version": "2.1",
"type": "malware"
"type": "malware",
"is_family": false
}
],
"type": "bundle"

View File

@ -27,7 +27,8 @@
"marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168"
],
"spec_version": "2.1",
"type": "malware"
"type": "malware",
"is_family": false
}
],
"type": "bundle"

View File

@ -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",

View File

@ -32,7 +32,7 @@ EXPECTED_BUNDLE = """{
"malware_types": [
"ransomware"
],
"is_family": "False"
"is_family": false
},
{
"type": "relationship",

View File

@ -220,7 +220,7 @@ def test_parse_malware():
"malware_types": [
"ransomware"
],
"is_family": "False"
"is_family": false
}"""
mal = env.parse(data, version="2.1")

View File

@ -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"

View File

@ -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)

View File

@ -18,7 +18,7 @@ EXPECTED_MALWARE = """{
"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)

View File

@ -32,9 +32,10 @@ from .observables import (
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 @@ OBJ_MAP = {
'bundle': Bundle,
'campaign': Campaign,
'course-of-action': CourseOfAction,
'grouping': Grouping,
'identity': Identity,
'indicator': Indicator,
'infrastructure': Infrastructure,
'intrusion-set': IntrusionSet,
'language-content': LanguageContent,
'location': Location,