2017-03-22 13:46:39 +01:00
|
|
|
import datetime as dt
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
import pytz
|
|
|
|
|
|
|
|
import stix2
|
|
|
|
|
|
|
|
from .constants import FAKE_TIME, INDICATOR_ID, INDICATOR_KWARGS
|
2017-03-22 14:05:59 +01:00
|
|
|
from .fixtures import clock, uuid4, indicator # noqa: F401
|
2017-03-22 13:46:39 +01:00
|
|
|
|
|
|
|
EXPECTED_INDICATOR = """{
|
|
|
|
"created": "2017-01-01T00:00:01Z",
|
|
|
|
"id": "indicator--01234567-89ab-cdef-0123-456789abcdef",
|
|
|
|
"labels": [
|
|
|
|
"malicious-activity"
|
|
|
|
],
|
|
|
|
"modified": "2017-01-01T00:00:01Z",
|
|
|
|
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
|
|
|
"type": "indicator",
|
|
|
|
"valid_from": "1970-01-01T00:00:01Z"
|
|
|
|
}"""
|
|
|
|
|
|
|
|
EXPECTED_INDICATOR_REPR = "Indicator(" + " ".join("""
|
|
|
|
created=datetime.datetime(2017, 1, 1, 0, 0, 1, tzinfo=<UTC>),
|
|
|
|
id='indicator--01234567-89ab-cdef-0123-456789abcdef',
|
|
|
|
labels=['malicious-activity'],
|
|
|
|
modified=datetime.datetime(2017, 1, 1, 0, 0, 1, tzinfo=<UTC>),
|
|
|
|
pattern="[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
|
|
|
type='indicator',
|
|
|
|
valid_from=datetime.datetime(1970, 1, 1, 0, 0, 1, tzinfo=<UTC>)
|
|
|
|
""".split()) + ")"
|
|
|
|
|
|
|
|
|
|
|
|
def test_indicator_with_all_required_fields():
|
|
|
|
now = dt.datetime(2017, 1, 1, 0, 0, 1, tzinfo=pytz.utc)
|
|
|
|
epoch = dt.datetime(1970, 1, 1, 0, 0, 1, tzinfo=pytz.utc)
|
|
|
|
|
2017-03-22 14:05:59 +01:00
|
|
|
ind = stix2.Indicator(
|
2017-03-22 13:46:39 +01:00
|
|
|
type="indicator",
|
|
|
|
id=INDICATOR_ID,
|
|
|
|
labels=['malicious-activity'],
|
|
|
|
pattern="[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
|
|
|
created=now,
|
|
|
|
modified=now,
|
|
|
|
valid_from=epoch,
|
|
|
|
)
|
|
|
|
|
2017-03-22 14:05:59 +01:00
|
|
|
assert str(ind) == EXPECTED_INDICATOR
|
|
|
|
assert repr(ind) == EXPECTED_INDICATOR_REPR
|
2017-03-22 13:46:39 +01:00
|
|
|
|
|
|
|
|
2017-03-22 14:05:59 +01:00
|
|
|
def test_indicator_autogenerated_fields(indicator): # noqa: F811
|
2017-03-22 13:46:39 +01:00
|
|
|
assert indicator.type == 'indicator'
|
|
|
|
assert indicator.id == 'indicator--00000000-0000-0000-0000-000000000001'
|
|
|
|
assert indicator.created == FAKE_TIME
|
|
|
|
assert indicator.modified == FAKE_TIME
|
|
|
|
assert indicator.labels == ['malicious-activity']
|
|
|
|
assert indicator.pattern == "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']"
|
|
|
|
assert indicator.valid_from == FAKE_TIME
|
|
|
|
|
|
|
|
assert indicator['type'] == 'indicator'
|
|
|
|
assert indicator['id'] == 'indicator--00000000-0000-0000-0000-000000000001'
|
|
|
|
assert indicator['created'] == FAKE_TIME
|
|
|
|
assert indicator['modified'] == FAKE_TIME
|
|
|
|
assert indicator['labels'] == ['malicious-activity']
|
|
|
|
assert indicator['pattern'] == "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']"
|
|
|
|
assert indicator['valid_from'] == FAKE_TIME
|
|
|
|
|
|
|
|
|
|
|
|
def test_indicator_type_must_be_indicator():
|
|
|
|
with pytest.raises(ValueError) as excinfo:
|
2017-03-22 14:05:59 +01:00
|
|
|
stix2.Indicator(type='xxx', **INDICATOR_KWARGS)
|
2017-03-22 13:46:39 +01:00
|
|
|
|
|
|
|
assert str(excinfo.value) == "Invalid value for Indicator 'type': must equal 'indicator'."
|
|
|
|
|
|
|
|
|
|
|
|
def test_indicator_id_must_start_with_indicator():
|
|
|
|
with pytest.raises(ValueError) as excinfo:
|
2017-03-22 14:05:59 +01:00
|
|
|
stix2.Indicator(id='my-prefix--', **INDICATOR_KWARGS)
|
2017-03-22 13:46:39 +01:00
|
|
|
|
|
|
|
assert str(excinfo.value) == "Invalid value for Indicator 'id': must start with 'indicator--'."
|
|
|
|
|
|
|
|
|
|
|
|
def test_indicator_required_fields():
|
|
|
|
with pytest.raises(ValueError) as excinfo:
|
2017-03-22 14:05:59 +01:00
|
|
|
stix2.Indicator()
|
2017-03-22 13:46:39 +01:00
|
|
|
assert str(excinfo.value) == "Missing required field(s) for Indicator: (labels, pattern)."
|
|
|
|
|
|
|
|
|
|
|
|
def test_indicator_required_field_pattern():
|
|
|
|
with pytest.raises(ValueError) as excinfo:
|
2017-03-22 14:05:59 +01:00
|
|
|
stix2.Indicator(labels=['malicious-activity'])
|
2017-03-22 13:46:39 +01:00
|
|
|
assert str(excinfo.value) == "Missing required field(s) for Indicator: (pattern)."
|
|
|
|
|
|
|
|
|
|
|
|
def test_indicator_created_ref_invalid_format():
|
|
|
|
with pytest.raises(ValueError) as excinfo:
|
2017-03-22 14:05:59 +01:00
|
|
|
stix2.Indicator(created_by_ref='myprefix--12345678', **INDICATOR_KWARGS)
|
2017-03-22 13:46:39 +01:00
|
|
|
assert str(excinfo.value) == "Invalid value for Indicator 'created_by_ref': must match <object-type>--<guid>."
|
|
|
|
|
|
|
|
|
|
|
|
def test_indicator_revoked_invalid():
|
|
|
|
with pytest.raises(ValueError) as excinfo:
|
2017-04-06 22:08:36 +02:00
|
|
|
stix2.Indicator(revoked='no', **INDICATOR_KWARGS)
|
2017-03-22 13:46:39 +01:00
|
|
|
assert str(excinfo.value) == "Invalid value for Indicator 'revoked': must be a boolean value."
|
|
|
|
|
|
|
|
|
2017-03-22 14:05:59 +01:00
|
|
|
def test_cannot_assign_to_indicator_attributes(indicator): # noqa: F811
|
2017-03-22 13:46:39 +01:00
|
|
|
with pytest.raises(ValueError) as excinfo:
|
|
|
|
indicator.valid_from = dt.datetime.now()
|
|
|
|
|
|
|
|
assert str(excinfo.value) == "Cannot modify properties after creation."
|
|
|
|
|
|
|
|
|
|
|
|
def test_invalid_kwarg_to_indicator():
|
|
|
|
with pytest.raises(TypeError) as excinfo:
|
2017-03-22 14:05:59 +01:00
|
|
|
stix2.Indicator(my_custom_property="foo", **INDICATOR_KWARGS)
|
2017-03-22 13:46:39 +01:00
|
|
|
assert str(excinfo.value) == "unexpected keyword arguments: ['my_custom_property']"
|
|
|
|
|
|
|
|
|
|
|
|
def test_created_modified_time_are_identical_by_default():
|
|
|
|
"""By default, the created and modified times should be the same."""
|
2017-03-22 14:05:59 +01:00
|
|
|
ind = stix2.Indicator(**INDICATOR_KWARGS)
|
2017-03-22 13:46:39 +01:00
|
|
|
|
2017-03-22 14:05:59 +01:00
|
|
|
assert ind.created == ind.modified
|