Add exception for invalid Property values.

stix2.1
Greg Back 2017-04-18 14:19:16 -05:00
parent 3c17c9259c
commit 2aa1f5cedd
11 changed files with 83 additions and 21 deletions

View File

@ -9,3 +9,5 @@ from .sdo import AttackPattern, Campaign, CourseOfAction, Identity, Indicator, \
Vulnerability Vulnerability
from .sro import Relationship, Sighting from .sro import Relationship, Sighting
from .markings import MarkingDefinition, GranularMarking, StatementMarking, TLPMarking from .markings import MarkingDefinition, GranularMarking, StatementMarking, TLPMarking
from . import exceptions

View File

@ -4,6 +4,7 @@ import collections
import datetime as dt import datetime as dt
import json import json
from .exceptions import STIXValueError
from .utils import format_datetime, get_timestamp, NOW from .utils import format_datetime, get_timestamp, NOW
__all__ = ['STIXJSONEncoder', '_STIXBase'] __all__ = ['STIXJSONEncoder', '_STIXBase']
@ -41,10 +42,7 @@ class _STIXBase(collections.Mapping):
try: try:
kwargs[prop_name] = prop.validate(kwargs[prop_name]) kwargs[prop_name] = prop.validate(kwargs[prop_name])
except ValueError as exc: except ValueError as exc:
msg = "Invalid value for {0} '{1}': {2}" raise STIXValueError(self.__class__, prop_name, reason=str(exc))
raise ValueError(msg.format(self.__class__.__name__,
prop_name,
exc))
def __init__(self, **kwargs): def __init__(self, **kwargs):
cls = self.__class__ cls = self.__class__

15
stix2/exceptions.py Normal file
View File

@ -0,0 +1,15 @@
class STIXError(Exception):
"""Base class for errors generated in the stix2 library."""
class STIXValueError(STIXError, ValueError):
"""An invalid value was provided to a STIX object's __init__."""
def __init__(self, cls, prop_name, reason):
self.cls = cls
self.prop_name = prop_name
self.reason = reason
def __str__(self):
msg = "Invalid value for {0.cls.__name__} '{0.prop_name}': {0.reason}"
return msg.format(self)

View File

@ -158,5 +158,5 @@ class SelectorProperty(Property):
def validate(self, value): def validate(self, value):
if not SELECTOR_REGEX.match(value): if not SELECTOR_REGEX.match(value):
raise ValueError("values must adhere to selector syntax") raise ValueError("must adhere to selector syntax.")
return value return value

View File

@ -51,23 +51,32 @@ def test_empty_bundle():
def test_bundle_with_wrong_type(): def test_bundle_with_wrong_type():
with pytest.raises(ValueError) as excinfo: with pytest.raises(stix2.exceptions.STIXValueError) as excinfo:
stix2.Bundle(type="not-a-bundle") stix2.Bundle(type="not-a-bundle")
assert excinfo.value.cls == stix2.Bundle
assert excinfo.value.prop_name == "type"
assert excinfo.value.reason == "must equal 'bundle'."
assert str(excinfo.value) == "Invalid value for Bundle 'type': must equal 'bundle'." assert str(excinfo.value) == "Invalid value for Bundle 'type': must equal 'bundle'."
def test_bundle_id_must_start_with_bundle(): def test_bundle_id_must_start_with_bundle():
with pytest.raises(ValueError) as excinfo: with pytest.raises(stix2.exceptions.STIXValueError) as excinfo:
stix2.Bundle(id='my-prefix--') stix2.Bundle(id='my-prefix--')
assert excinfo.value.cls == stix2.Bundle
assert excinfo.value.prop_name == "id"
assert excinfo.value.reason == "must start with 'bundle--'."
assert str(excinfo.value) == "Invalid value for Bundle 'id': must start with 'bundle--'." assert str(excinfo.value) == "Invalid value for Bundle 'id': must start with 'bundle--'."
def test_bundle_with_wrong_spec_version(): def test_bundle_with_wrong_spec_version():
with pytest.raises(ValueError) as excinfo: with pytest.raises(stix2.exceptions.STIXValueError) as excinfo:
stix2.Bundle(spec_version="1.2") stix2.Bundle(spec_version="1.2")
assert excinfo.value.cls == stix2.Bundle
assert excinfo.value.prop_name == "spec_version"
assert excinfo.value.reason == "must equal '2.0'."
assert str(excinfo.value) == "Invalid value for Bundle 'spec_version': must equal '2.0'." assert str(excinfo.value) == "Invalid value for Bundle 'spec_version': must equal '2.0'."

View File

@ -67,16 +67,22 @@ def test_indicator_autogenerated_fields(indicator):
def test_indicator_type_must_be_indicator(): def test_indicator_type_must_be_indicator():
with pytest.raises(ValueError) as excinfo: with pytest.raises(stix2.exceptions.STIXValueError) as excinfo:
stix2.Indicator(type='xxx', **INDICATOR_KWARGS) stix2.Indicator(type='xxx', **INDICATOR_KWARGS)
assert excinfo.value.cls == stix2.Indicator
assert excinfo.value.prop_name == "type"
assert excinfo.value.reason == "must equal 'indicator'."
assert str(excinfo.value) == "Invalid value for Indicator 'type': must equal 'indicator'." assert str(excinfo.value) == "Invalid value for Indicator 'type': must equal 'indicator'."
def test_indicator_id_must_start_with_indicator(): def test_indicator_id_must_start_with_indicator():
with pytest.raises(ValueError) as excinfo: with pytest.raises(stix2.exceptions.STIXValueError) as excinfo:
stix2.Indicator(id='my-prefix--', **INDICATOR_KWARGS) stix2.Indicator(id='my-prefix--', **INDICATOR_KWARGS)
assert excinfo.value.cls == stix2.Indicator
assert excinfo.value.prop_name == "id"
assert excinfo.value.reason == "must start with 'indicator--'."
assert str(excinfo.value) == "Invalid value for Indicator 'id': must start with 'indicator--'." assert str(excinfo.value) == "Invalid value for Indicator 'id': must start with 'indicator--'."
@ -93,14 +99,22 @@ def test_indicator_required_field_pattern():
def test_indicator_created_ref_invalid_format(): def test_indicator_created_ref_invalid_format():
with pytest.raises(ValueError) as excinfo: with pytest.raises(stix2.exceptions.STIXValueError) as excinfo:
stix2.Indicator(created_by_ref='myprefix--12345678', **INDICATOR_KWARGS) stix2.Indicator(created_by_ref='myprefix--12345678', **INDICATOR_KWARGS)
assert excinfo.value.cls == stix2.Indicator
assert excinfo.value.prop_name == "created_by_ref"
assert excinfo.value.reason == "must start with 'identity'."
assert str(excinfo.value) == "Invalid value for Indicator 'created_by_ref': must start with 'identity'." assert str(excinfo.value) == "Invalid value for Indicator 'created_by_ref': must start with 'identity'."
def test_indicator_revoked_invalid(): def test_indicator_revoked_invalid():
with pytest.raises(ValueError) as excinfo: with pytest.raises(stix2.exceptions.STIXValueError) as excinfo:
stix2.Indicator(revoked='false', **INDICATOR_KWARGS) stix2.Indicator(revoked='false', **INDICATOR_KWARGS)
assert excinfo.value.cls == stix2.Indicator
assert excinfo.value.prop_name == "revoked"
assert excinfo.value.reason == "must be a boolean value."
assert str(excinfo.value) == "Invalid value for Indicator 'revoked': must be a boolean value." assert str(excinfo.value) == "Invalid value for Indicator 'revoked': must be a boolean value."

View File

@ -51,16 +51,22 @@ def test_malware_autogenerated_fields(malware):
def test_malware_type_must_be_malware(): def test_malware_type_must_be_malware():
with pytest.raises(ValueError) as excinfo: with pytest.raises(stix2.exceptions.STIXValueError) as excinfo:
stix2.Malware(type='xxx', **MALWARE_KWARGS) stix2.Malware(type='xxx', **MALWARE_KWARGS)
assert excinfo.value.cls == stix2.Malware
assert excinfo.value.prop_name == "type"
assert excinfo.value.reason == "must equal 'malware'."
assert str(excinfo.value) == "Invalid value for Malware 'type': must equal 'malware'." assert str(excinfo.value) == "Invalid value for Malware 'type': must equal 'malware'."
def test_malware_id_must_start_with_malware(): def test_malware_id_must_start_with_malware():
with pytest.raises(ValueError) as excinfo: with pytest.raises(stix2.exceptions.STIXValueError) as excinfo:
stix2.Malware(id='my-prefix--', **MALWARE_KWARGS) stix2.Malware(id='my-prefix--', **MALWARE_KWARGS)
assert excinfo.value.cls == stix2.Malware
assert excinfo.value.prop_name == "id"
assert excinfo.value.reason == "must start with 'malware--'."
assert str(excinfo.value) == "Invalid value for Malware 'id': must start with 'malware--'." assert str(excinfo.value) == "Invalid value for Malware 'id': must start with 'malware--'."

View File

@ -87,13 +87,16 @@ def test_granular_example():
def test_granular_example_with_bad_selector(): def test_granular_example_with_bad_selector():
with pytest.raises(ValueError) as excinfo: with pytest.raises(stix2.exceptions.STIXValueError) as excinfo:
stix2.GranularMarking( stix2.GranularMarking(
marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
selectors=["abc[0]"] # missing "." selectors=["abc[0]"] # missing "."
) )
assert str(excinfo.value) == "Invalid value for GranularMarking 'selectors': values must adhere to selector syntax" assert excinfo.value.cls == stix2.GranularMarking
assert excinfo.value.prop_name == "selectors"
assert excinfo.value.reason == "must adhere to selector syntax."
assert str(excinfo.value) == "Invalid value for GranularMarking 'selectors': must adhere to selector syntax."
def test_campaign_with_granular_markings_example(): def test_campaign_with_granular_markings_example():

View File

@ -54,16 +54,22 @@ def test_relationship_autogenerated_fields(relationship):
def test_relationship_type_must_be_relationship(): def test_relationship_type_must_be_relationship():
with pytest.raises(ValueError) as excinfo: with pytest.raises(stix2.exceptions.STIXValueError) as excinfo:
stix2.Relationship(type='xxx', **RELATIONSHIP_KWARGS) stix2.Relationship(type='xxx', **RELATIONSHIP_KWARGS)
assert excinfo.value.cls == stix2.Relationship
assert excinfo.value.prop_name == "type"
assert excinfo.value.reason == "must equal 'relationship'."
assert str(excinfo.value) == "Invalid value for Relationship 'type': must equal 'relationship'." assert str(excinfo.value) == "Invalid value for Relationship 'type': must equal 'relationship'."
def test_relationship_id_must_start_with_relationship(): def test_relationship_id_must_start_with_relationship():
with pytest.raises(ValueError) as excinfo: with pytest.raises(stix2.exceptions.STIXValueError) as excinfo:
stix2.Relationship(id='my-prefix--', **RELATIONSHIP_KWARGS) stix2.Relationship(id='my-prefix--', **RELATIONSHIP_KWARGS)
assert excinfo.value.cls == stix2.Relationship
assert excinfo.value.prop_name == "id"
assert excinfo.value.reason == "must start with 'relationship--'."
assert str(excinfo.value) == "Invalid value for Relationship 'id': must start with 'relationship--'." assert str(excinfo.value) == "Invalid value for Relationship 'id': must start with 'relationship--'."

View File

@ -63,7 +63,7 @@ def test_report_example_objects_in_object_refs():
def test_report_example_objects_in_object_refs_with_bad_id(): def test_report_example_objects_in_object_refs_with_bad_id():
with pytest.raises(ValueError) as excinfo: with pytest.raises(stix2.exceptions.STIXValueError) as excinfo:
stix2.Report( stix2.Report(
id="report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3", id="report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3",
created_by_ref="identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283", created_by_ref="identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283",
@ -80,6 +80,9 @@ def test_report_example_objects_in_object_refs_with_bad_id():
], ],
) )
assert excinfo.value.cls == stix2.Report
assert excinfo.value.prop_name == "object_refs"
assert excinfo.value.reason == "must match <object-type>--<guid>."
assert str(excinfo.value) == "Invalid value for Report 'object_refs': must match <object-type>--<guid>." assert str(excinfo.value) == "Invalid value for Report 'object_refs': must match <object-type>--<guid>."
# TODO: Add other examples # TODO: Add other examples

View File

@ -48,7 +48,7 @@ def test_sighting_all_required_fields():
def test_sighting_bad_where_sighted_refs(): def test_sighting_bad_where_sighted_refs():
now = dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc) now = dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc)
with pytest.raises(ValueError) as excinfo: with pytest.raises(stix2.exceptions.STIXValueError) as excinfo:
stix2.Sighting( stix2.Sighting(
type='sighting', type='sighting',
id=SIGHTING_ID, id=SIGHTING_ID,
@ -58,13 +58,19 @@ def test_sighting_bad_where_sighted_refs():
where_sighted_refs=["malware--8cc7afd6-5455-4d2b-a736-e614ee631d99"] where_sighted_refs=["malware--8cc7afd6-5455-4d2b-a736-e614ee631d99"]
) )
assert excinfo.value.cls == stix2.Sighting
assert excinfo.value.prop_name == "where_sighted_refs"
assert excinfo.value.reason == "must start with 'identity'."
assert str(excinfo.value) == "Invalid value for Sighting 'where_sighted_refs': must start with 'identity'." assert str(excinfo.value) == "Invalid value for Sighting 'where_sighted_refs': must start with 'identity'."
def test_sighting_type_must_be_sightings(): def test_sighting_type_must_be_sightings():
with pytest.raises(ValueError) as excinfo: with pytest.raises(stix2.exceptions.STIXValueError) as excinfo:
stix2.Sighting(type='xxx', **SIGHTING_KWARGS) stix2.Sighting(type='xxx', **SIGHTING_KWARGS)
assert excinfo.value.cls == stix2.Sighting
assert excinfo.value.prop_name == "type"
assert excinfo.value.reason == "must equal 'sighting'."
assert str(excinfo.value) == "Invalid value for Sighting 'type': must equal 'sighting'." assert str(excinfo.value) == "Invalid value for Sighting 'type': must equal 'sighting'."