Add Exception for missing values.
parent
2aa1f5cedd
commit
a7805c4ac0
|
@ -4,7 +4,7 @@ import collections
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from .exceptions import STIXValueError
|
from .exceptions import STIXValueError, MissingFieldsError
|
||||||
from .utils import format_datetime, get_timestamp, NOW
|
from .utils import format_datetime, get_timestamp, NOW
|
||||||
|
|
||||||
__all__ = ['STIXJSONEncoder', '_STIXBase']
|
__all__ = ['STIXJSONEncoder', '_STIXBase']
|
||||||
|
@ -46,7 +46,6 @@ class _STIXBase(collections.Mapping):
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
cls = self.__class__
|
cls = self.__class__
|
||||||
class_name = cls.__name__
|
|
||||||
|
|
||||||
# Use the same timestamp for any auto-generated datetimes
|
# Use the same timestamp for any auto-generated datetimes
|
||||||
self.__now = get_timestamp()
|
self.__now = get_timestamp()
|
||||||
|
@ -59,9 +58,7 @@ class _STIXBase(collections.Mapping):
|
||||||
required_fields = get_required_properties(cls._properties)
|
required_fields = get_required_properties(cls._properties)
|
||||||
missing_kwargs = set(required_fields) - set(kwargs)
|
missing_kwargs = set(required_fields) - set(kwargs)
|
||||||
if missing_kwargs:
|
if missing_kwargs:
|
||||||
msg = "Missing required field(s) for {type}: ({fields})."
|
raise MissingFieldsError(cls, missing_kwargs)
|
||||||
field_list = ", ".join(x for x in sorted(list(missing_kwargs)))
|
|
||||||
raise ValueError(msg.format(type=class_name, fields=field_list))
|
|
||||||
|
|
||||||
for prop_name, prop_metadata in cls._properties.items():
|
for prop_name, prop_metadata in cls._properties.items():
|
||||||
self._check_property(prop_name, prop_metadata, kwargs)
|
self._check_property(prop_name, prop_metadata, kwargs)
|
||||||
|
|
|
@ -6,6 +6,7 @@ class STIXValueError(STIXError, ValueError):
|
||||||
"""An invalid value was provided to a STIX object's __init__."""
|
"""An invalid value was provided to a STIX object's __init__."""
|
||||||
|
|
||||||
def __init__(self, cls, prop_name, reason):
|
def __init__(self, cls, prop_name, reason):
|
||||||
|
super(STIXValueError, self).__init__()
|
||||||
self.cls = cls
|
self.cls = cls
|
||||||
self.prop_name = prop_name
|
self.prop_name = prop_name
|
||||||
self.reason = reason
|
self.reason = reason
|
||||||
|
@ -13,3 +14,17 @@ class STIXValueError(STIXError, ValueError):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
msg = "Invalid value for {0.cls.__name__} '{0.prop_name}': {0.reason}"
|
msg = "Invalid value for {0.cls.__name__} '{0.prop_name}': {0.reason}"
|
||||||
return msg.format(self)
|
return msg.format(self)
|
||||||
|
|
||||||
|
|
||||||
|
class MissingFieldsError(STIXError, ValueError):
|
||||||
|
"""Missing required field(s) when construting STIX object."""
|
||||||
|
|
||||||
|
def __init__(self, cls, fields):
|
||||||
|
super(MissingFieldsError, self).__init__()
|
||||||
|
self.cls = cls
|
||||||
|
self.fields = sorted(list(fields))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
msg = "Missing required field(s) for {0}: ({1})."
|
||||||
|
return msg.format(self.cls.__name__,
|
||||||
|
", ".join(x for x in self.fields))
|
||||||
|
|
|
@ -107,6 +107,9 @@ def test_external_reference_offline():
|
||||||
|
|
||||||
|
|
||||||
def test_external_reference_source_required():
|
def test_external_reference_source_required():
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||||
stix2.ExternalReference()
|
stix2.ExternalReference()
|
||||||
|
|
||||||
|
assert excinfo.value.cls == stix2.ExternalReference
|
||||||
|
assert excinfo.value.fields == ["source_name"]
|
||||||
assert str(excinfo.value) == "Missing required field(s) for ExternalReference: (source_name)."
|
assert str(excinfo.value) == "Missing required field(s) for ExternalReference: (source_name)."
|
||||||
|
|
|
@ -87,14 +87,20 @@ def test_indicator_id_must_start_with_indicator():
|
||||||
|
|
||||||
|
|
||||||
def test_indicator_required_fields():
|
def test_indicator_required_fields():
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||||
stix2.Indicator()
|
stix2.Indicator()
|
||||||
|
|
||||||
|
assert excinfo.value.cls == stix2.Indicator
|
||||||
|
assert excinfo.value.fields == ["labels", "pattern"]
|
||||||
assert str(excinfo.value) == "Missing required field(s) for Indicator: (labels, pattern)."
|
assert str(excinfo.value) == "Missing required field(s) for Indicator: (labels, pattern)."
|
||||||
|
|
||||||
|
|
||||||
def test_indicator_required_field_pattern():
|
def test_indicator_required_field_pattern():
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||||
stix2.Indicator(labels=['malicious-activity'])
|
stix2.Indicator(labels=['malicious-activity'])
|
||||||
|
|
||||||
|
assert excinfo.value.cls == stix2.Indicator
|
||||||
|
assert excinfo.value.fields == ["pattern"]
|
||||||
assert str(excinfo.value) == "Missing required field(s) for Indicator: (pattern)."
|
assert str(excinfo.value) == "Missing required field(s) for Indicator: (pattern)."
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -36,23 +36,29 @@ def test_kill_chain_example():
|
||||||
|
|
||||||
def test_kill_chain_required_fields():
|
def test_kill_chain_required_fields():
|
||||||
|
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||||
stix2.KillChainPhase()
|
stix2.KillChainPhase()
|
||||||
|
|
||||||
|
assert excinfo.value.cls == stix2.KillChainPhase
|
||||||
|
assert excinfo.value.fields == ["kill_chain_name", "phase_name"]
|
||||||
assert str(excinfo.value) == "Missing required field(s) for KillChainPhase: (kill_chain_name, phase_name)."
|
assert str(excinfo.value) == "Missing required field(s) for KillChainPhase: (kill_chain_name, phase_name)."
|
||||||
|
|
||||||
|
|
||||||
def test_kill_chain_required_field_chain_name():
|
def test_kill_chain_required_field_chain_name():
|
||||||
|
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||||
stix2.KillChainPhase(phase_name="weaponization")
|
stix2.KillChainPhase(phase_name="weaponization")
|
||||||
|
|
||||||
|
assert excinfo.value.cls == stix2.KillChainPhase
|
||||||
|
assert excinfo.value.fields == ["kill_chain_name"]
|
||||||
assert str(excinfo.value) == "Missing required field(s) for KillChainPhase: (kill_chain_name)."
|
assert str(excinfo.value) == "Missing required field(s) for KillChainPhase: (kill_chain_name)."
|
||||||
|
|
||||||
|
|
||||||
def test_kill_chain_required_field_phase_name():
|
def test_kill_chain_required_field_phase_name():
|
||||||
|
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||||
stix2.KillChainPhase(kill_chain_name="lockheed-martin-cyber-kill-chain")
|
stix2.KillChainPhase(kill_chain_name="lockheed-martin-cyber-kill-chain")
|
||||||
|
|
||||||
|
assert excinfo.value.cls == stix2.KillChainPhase
|
||||||
|
assert excinfo.value.fields == ["phase_name"]
|
||||||
assert str(excinfo.value) == "Missing required field(s) for KillChainPhase: (phase_name)."
|
assert str(excinfo.value) == "Missing required field(s) for KillChainPhase: (phase_name)."
|
||||||
|
|
|
@ -71,14 +71,20 @@ def test_malware_id_must_start_with_malware():
|
||||||
|
|
||||||
|
|
||||||
def test_malware_required_fields():
|
def test_malware_required_fields():
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||||
stix2.Malware()
|
stix2.Malware()
|
||||||
|
|
||||||
|
assert excinfo.value.cls == stix2.Malware
|
||||||
|
assert excinfo.value.fields == ["labels", "name"]
|
||||||
assert str(excinfo.value) == "Missing required field(s) for Malware: (labels, name)."
|
assert str(excinfo.value) == "Missing required field(s) for Malware: (labels, name)."
|
||||||
|
|
||||||
|
|
||||||
def test_malware_required_field_name():
|
def test_malware_required_field_name():
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||||
stix2.Malware(labels=['ransomware'])
|
stix2.Malware(labels=['ransomware'])
|
||||||
|
|
||||||
|
assert excinfo.value.cls == stix2.Malware
|
||||||
|
assert excinfo.value.fields == ["name"]
|
||||||
assert str(excinfo.value) == "Missing required field(s) for Malware: (name)."
|
assert str(excinfo.value) == "Missing required field(s) for Malware: (name)."
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -74,23 +74,26 @@ def test_relationship_id_must_start_with_relationship():
|
||||||
|
|
||||||
|
|
||||||
def test_relationship_required_field_relationship_type():
|
def test_relationship_required_field_relationship_type():
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||||
stix2.Relationship()
|
stix2.Relationship()
|
||||||
assert str(excinfo.value) == "Missing required field(s) for Relationship: (relationship_type, source_ref, target_ref)."
|
assert str(excinfo.value) == "Missing required field(s) for Relationship: (relationship_type, source_ref, target_ref)."
|
||||||
|
|
||||||
|
|
||||||
def test_relationship_missing_some_required_fields():
|
def test_relationship_missing_some_required_fields():
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||||
stix2.Relationship(relationship_type='indicates')
|
stix2.Relationship(relationship_type='indicates')
|
||||||
assert str(excinfo.value) == "Missing required field(s) for Relationship: (source_ref, target_ref)."
|
assert str(excinfo.value) == "Missing required field(s) for Relationship: (source_ref, target_ref)."
|
||||||
|
|
||||||
|
|
||||||
def test_relationship_required_field_target_ref():
|
def test_relationship_required_field_target_ref():
|
||||||
with pytest.raises(ValueError) as excinfo:
|
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||||
stix2.Relationship(
|
stix2.Relationship(
|
||||||
relationship_type='indicates',
|
relationship_type='indicates',
|
||||||
source_ref=INDICATOR_ID
|
source_ref=INDICATOR_ID
|
||||||
)
|
)
|
||||||
|
|
||||||
|
assert excinfo.value.cls == stix2.Relationship
|
||||||
|
assert excinfo.value.fields == ["target_ref"]
|
||||||
assert str(excinfo.value) == "Missing required field(s) for Relationship: (target_ref)."
|
assert str(excinfo.value) == "Missing required field(s) for Relationship: (target_ref)."
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue