cti-python-stix2/stix2/test/test_stix2.py

207 lines
6.4 KiB
Python

"""Tests for the stix2 library"""
import datetime
import pytest
import pytz
import stix2
amsterdam = pytz.timezone('Europe/Amsterdam')
eastern = pytz.timezone('US/Eastern')
@pytest.mark.parametrize('dt,timestamp', [
(datetime.datetime(2017, 1, 1, tzinfo=pytz.utc), '2017-01-01T00:00:00Z'),
(amsterdam.localize(datetime.datetime(2017, 1, 1)), '2016-12-31T23:00:00Z'),
(eastern.localize(datetime.datetime(2017, 1, 1, 12, 34, 56)), '2017-01-01T17:34:56Z'),
(eastern.localize(datetime.datetime(2017, 7, 1)), '2017-07-01T04:00:00Z'),
])
def test_timestamp_formatting(dt, timestamp):
assert stix2.format_datetime(dt) == timestamp
EXPECTED_INDICATOR = """{
"created": "2017-01-01T00:00:00Z",
"id": "indicator--01234567-89ab-cdef-0123-456789abcdef",
"labels": [
"malicious-activity"
],
"modified": "2017-01-01T00:00:00Z",
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
"type": "indicator",
"valid_from": "1970-01-01T00:00:00Z"
}"""
def test_indicator_with_all_required_fields():
now = datetime.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)
epoch = datetime.datetime(1970, 1, 1, 0, 0, 0, tzinfo=pytz.utc)
indicator = stix2.Indicator(
type="indicator",
id="indicator--01234567-89ab-cdef-0123-456789abcdef",
labels=['malicious-activity'],
pattern="[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
created=now,
modified=now,
valid_from=epoch,
)
assert str(indicator) == EXPECTED_INDICATOR
# Minimum required args for an Indicator instance
INDICATOR_KWARGS = dict(
labels=['malicious-activity'],
pattern="[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
)
def test_indicator_autogenerated_fields():
indicator = stix2.Indicator(**INDICATOR_KWARGS)
assert indicator.type == 'indicator'
assert indicator.id.startswith('indicator--')
assert indicator.created is not None
assert indicator.modified is not None
assert indicator.labels == ['malicious-activity']
assert indicator.pattern == "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']"
assert indicator.valid_from is not None
assert indicator['type'] == 'indicator'
assert indicator['id'].startswith('indicator--')
assert indicator['created'] is not None
assert indicator['modified'] is not None
assert indicator['labels'] == ['malicious-activity']
assert indicator['pattern'] == "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']"
assert indicator['valid_from'] is not None
def test_indicator_type_must_be_indicator():
with pytest.raises(ValueError) as excinfo:
indicator = stix2.Indicator(type='xxx')
assert "Indicator must have type='indicator'." in str(excinfo)
def test_indicator_id_must_start_with_indicator():
with pytest.raises(ValueError) as excinfo:
indicator = stix2.Indicator(id='my-prefix--')
assert "Indicator id values must begin with 'indicator--'." in str(excinfo)
def test_indicator_required_field_labels():
with pytest.raises(ValueError) as excinfo:
indicator = stix2.Indicator()
assert "Missing required field for Indicator: 'labels'." in str(excinfo)
def test_indicator_required_field_pattern():
with pytest.raises(ValueError) as excinfo:
# Label is checked first, so make sure that is provided
indicator = stix2.Indicator(labels=['malicious-activity'])
assert "Missing required field for Indicator: 'pattern'." in str(excinfo)
def test_cannot_assign_to_attributes():
indicator = stix2.Indicator(**INDICATOR_KWARGS)
with pytest.raises(ValueError) as excinfo:
indicator.valid_from = datetime.datetime.now()
assert "Cannot modify properties after creation." in str(excinfo)
def test_invalid_kwarg_to_indicator():
with pytest.raises(TypeError) as excinfo:
indicator = stix2.Indicator(my_custom_property="foo", **INDICATOR_KWARGS)
assert "unexpected keyword arguments: ['my_custom_property']" in str(excinfo)
EXPECTED_MALWARE = """{
"created": "2016-05-12T08:17:27Z",
"id": "malware--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
"labels": [
"ransomware"
],
"modified": "2016-05-12T08:17:27Z",
"name": "Cryptolocker",
"type": "malware"
}"""
def test_malware_with_all_required_fields():
now = datetime.datetime(2016, 5, 12, 8, 17, 27, tzinfo=pytz.utc)
malware = stix2.Malware(
type="malware",
id="malware--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
created=now,
modified=now,
labels=["ransomware"],
name="Cryptolocker",
)
assert str(malware) == EXPECTED_MALWARE
# Minimum required args for a Malware instance
MALWARE_KWARGS = dict(
labels=['ransomware'],
name="Cryptolocker",
)
def test_malware_autogenerated_fields():
malware = stix2.Malware(**MALWARE_KWARGS)
assert malware.type == 'malware'
assert malware.id.startswith('malware--')
assert malware.created is not None
assert malware.modified is not None
assert malware.labels == ['ransomware']
assert malware.name == "Cryptolocker"
assert malware['type'] == 'malware'
assert malware['id'].startswith('malware--')
assert malware['created'] is not None
assert malware['modified'] is not None
assert malware['labels'] == ['ransomware']
assert malware['name'] == "Cryptolocker"
def test_malware_type_must_be_malware():
with pytest.raises(ValueError) as excinfo:
malware = stix2.Malware(type='xxx')
assert "Malware must have type='malware'." in str(excinfo)
def test_malware_id_must_start_with_malware():
with pytest.raises(ValueError) as excinfo:
malware = stix2.Malware(id='my-prefix--')
assert "Malware id values must begin with 'malware--'." in str(excinfo)
def test_malware_required_field_labels():
with pytest.raises(ValueError) as excinfo:
malware = stix2.Malware()
assert "Missing required field for Malware: 'labels'." in str(excinfo)
def test_malware_required_field_name():
with pytest.raises(ValueError) as excinfo:
# Label is checked first, so make sure that is provided
malware = stix2.Malware(labels=['ransomware'])
assert "Missing required field for Malware: 'name'." in str(excinfo)
def test_cannot_assign_to_attributes():
malware = stix2.Malware(**MALWARE_KWARGS)
with pytest.raises(ValueError) as excinfo:
malware.name = "Cryptolocker II"
assert "Cannot modify properties after creation." in str(excinfo)