import datetime as dt import pytest import pytz import re import stix2 from .constants import FAKE_TIME, MALWARE_ID, MALWARE_KWARGS from .fixtures import clock, uuid4, malware # noqa: F401 EXPECTED_MALWARE = """{ "created": "2016-05-12T08:17:27Z", "id": "malware--fedcba98-7654-3210-fedc-ba9876543210", "labels": [ "ransomware" ], "modified": "2016-05-12T08:17:27Z", "name": "Cryptolocker", "type": "malware" }""" def test_malware_with_all_required_fields(): now = dt.datetime(2016, 5, 12, 8, 17, 27, tzinfo=pytz.utc) mal = stix2.Malware( type="malware", id=MALWARE_ID, created=now, modified=now, labels=["ransomware"], name="Cryptolocker", ) assert str(mal) == EXPECTED_MALWARE def test_malware_autogenerated_fields(malware): # noqa: F811 assert malware.type == 'malware' assert malware.id == 'malware--00000000-0000-0000-0000-000000000001' assert malware.created == FAKE_TIME assert malware.modified == FAKE_TIME assert malware.labels == ['ransomware'] assert malware.name == "Cryptolocker" assert malware['type'] == 'malware' assert malware['id'] == 'malware--00000000-0000-0000-0000-000000000001' assert malware['created'] == FAKE_TIME assert malware['modified'] == FAKE_TIME assert malware['labels'] == ['ransomware'] assert malware['name'] == "Cryptolocker" def test_malware_type_must_be_malware(): with pytest.raises(ValueError) as excinfo: stix2.Malware(type='xxx', **MALWARE_KWARGS) assert str(excinfo.value) == "Invalid value for Malware 'type': must equal 'malware'." def test_malware_id_must_start_with_malware(): with pytest.raises(ValueError) as excinfo: stix2.Malware(id='my-prefix--', **MALWARE_KWARGS) assert str(excinfo.value) == "Invalid value for Malware 'id': must start with 'malware--'." def test_malware_required_fields(): with pytest.raises(ValueError) as excinfo: stix2.Malware() assert str(excinfo.value) == "Missing required field(s) for Malware: (labels, name)." def test_malware_required_field_name(): with pytest.raises(ValueError) as excinfo: stix2.Malware(labels=['ransomware']) assert str(excinfo.value) == "Missing required field(s) for Malware: (name)." def test_cannot_assign_to_malware_attributes(malware): # noqa: F811 with pytest.raises(ValueError) as excinfo: malware.name = "Cryptolocker II" assert str(excinfo.value) == "Cannot modify properties after creation." def test_invalid_kwarg_to_malware(): with pytest.raises(TypeError) as excinfo: stix2.Malware(my_custom_property="foo", **MALWARE_KWARGS) assert str(excinfo.value) == "unexpected keyword arguments: ['my_custom_property']" def test_parse_malware(): mal = stix2.parse(EXPECTED_MALWARE) assert mal.type == 'malware' assert mal.id == MALWARE_ID assert mal.created == "2016-05-12T08:17:27Z" assert mal.modified == "2016-05-12T08:17:27Z" assert mal.labels == ['ransomware'] assert mal.name == "Cryptolocker" def test_parse_malware_invalid_labels(): data = re.compile('\[.+\]', re.DOTALL).sub('1', EXPECTED_MALWARE) with pytest.raises(ValueError) as excinfo: stix2.parse(data) assert "Invalid value for Malware 'labels'" in str(excinfo.value) def test_parse_malware_kill_chain_phases(): kill_chain = """ "kill_chain_phases": [ { "kill_chain_name": "lockheed-martin-cyber-kill-chain", "phase_name": "reconnaissance" } ]""" data = EXPECTED_MALWARE.replace('malware"', 'malware",%s' % kill_chain) mal = stix2.parse(data) assert mal.kill_chain_phases[0].kill_chain_name == "lockheed-martin-cyber-kill-chain" assert mal.kill_chain_phases[0].phase_name == "reconnaissance" assert mal['kill_chain_phases'][0]['kill_chain_name'] == "lockheed-martin-cyber-kill-chain" assert mal['kill_chain_phases'][0]['phase_name'] == "reconnaissance"