parent
a520a67511
commit
9761c37f20
|
@ -123,7 +123,7 @@ def parse_observable(data, _valid_refs):
|
|||
obj['_valid_refs'] = _valid_refs
|
||||
|
||||
if 'type' not in obj:
|
||||
raise ValueError("'type' is a required field!")
|
||||
raise ValueError("'type' is a required property!")
|
||||
try:
|
||||
obj_class = OBJ_MAP_OBSERVABLE[obj['type']]
|
||||
except KeyError:
|
||||
|
|
|
@ -12,7 +12,7 @@ from .utils import NOW, format_datetime, get_timestamp, parse_into_datetime
|
|||
|
||||
__all__ = ['STIXJSONEncoder', '_STIXBase']
|
||||
|
||||
DEFAULT_ERROR = "{type} must have {field}='{expected}'."
|
||||
DEFAULT_ERROR = "{type} must have {property}='{expected}'."
|
||||
|
||||
|
||||
class STIXJSONEncoder(json.JSONEncoder):
|
||||
|
@ -95,9 +95,9 @@ class _STIXBase(collections.Mapping):
|
|||
if prop_value:
|
||||
setting_kwargs[prop_name] = prop_value
|
||||
|
||||
# Detect any missing required fields
|
||||
required_fields = get_required_properties(cls._properties)
|
||||
missing_kwargs = set(required_fields) - set(setting_kwargs)
|
||||
# Detect any missing required properties
|
||||
required_properties = get_required_properties(cls._properties)
|
||||
missing_kwargs = set(required_properties) - set(setting_kwargs)
|
||||
if missing_kwargs:
|
||||
raise MissingFieldsError(cls, missing_kwargs)
|
||||
|
||||
|
|
|
@ -17,31 +17,31 @@ class InvalidValueError(STIXError, ValueError):
|
|||
|
||||
|
||||
class MissingFieldsError(STIXError, ValueError):
|
||||
"""Missing required field(s) when constructing STIX object."""
|
||||
"""Missing one or more required properties when constructing STIX object."""
|
||||
|
||||
def __init__(self, cls, fields):
|
||||
def __init__(self, cls, properties):
|
||||
super(MissingFieldsError, self).__init__()
|
||||
self.cls = cls
|
||||
self.fields = sorted(list(fields))
|
||||
self.properties = sorted(list(properties))
|
||||
|
||||
def __str__(self):
|
||||
msg = "No values for required field(s) for {0}: ({1})."
|
||||
msg = "No values for required properties for {0}: ({1})."
|
||||
return msg.format(self.cls.__name__,
|
||||
", ".join(x for x in self.fields))
|
||||
", ".join(x for x in self.properties))
|
||||
|
||||
|
||||
class ExtraFieldsError(STIXError, TypeError):
|
||||
"""Extra field(s) were provided when constructing STIX object."""
|
||||
"""One or more extra properties were provided when constructing STIX object."""
|
||||
|
||||
def __init__(self, cls, fields):
|
||||
def __init__(self, cls, properties):
|
||||
super(ExtraFieldsError, self).__init__()
|
||||
self.cls = cls
|
||||
self.fields = sorted(list(fields))
|
||||
self.properties = sorted(list(properties))
|
||||
|
||||
def __str__(self):
|
||||
msg = "Unexpected field(s) for {0}: ({1})."
|
||||
msg = "Unexpected properties for {0}: ({1})."
|
||||
return msg.format(self.cls.__name__,
|
||||
", ".join(x for x in self.fields))
|
||||
", ".join(x for x in self.properties))
|
||||
|
||||
|
||||
class ImmutableError(STIXError, ValueError):
|
||||
|
@ -93,15 +93,15 @@ class UnmodifiablePropertyError(STIXError, ValueError):
|
|||
class MutuallyExclusivePropertiesError(STIXError, TypeError):
|
||||
"""Violating interproperty mutually exclusive constraint of a STIX object type."""
|
||||
|
||||
def __init__(self, cls, fields):
|
||||
def __init__(self, cls, properties):
|
||||
super(MutuallyExclusivePropertiesError, self).__init__()
|
||||
self.cls = cls
|
||||
self.fields = sorted(list(fields))
|
||||
self.properties = sorted(list(properties))
|
||||
|
||||
def __str__(self):
|
||||
msg = "The field(s) for {0}: ({1}) are mutually exclusive."
|
||||
return msg.format(self.cls.__name__,
|
||||
", ".join(x for x in self.fields))
|
||||
", ".join(x for x in self.properties))
|
||||
|
||||
|
||||
class DependentPropertiestError(STIXError, TypeError):
|
||||
|
@ -121,15 +121,15 @@ class DependentPropertiestError(STIXError, TypeError):
|
|||
class AtLeastOnePropertyError(STIXError, TypeError):
|
||||
"""Violating a constraint of a STIX object type that at least one of the given properties must be populated."""
|
||||
|
||||
def __init__(self, cls, fields):
|
||||
def __init__(self, cls, properties):
|
||||
super(AtLeastOnePropertyError, self).__init__()
|
||||
self.cls = cls
|
||||
self.fields = sorted(list(fields))
|
||||
self.properties = sorted(list(properties))
|
||||
|
||||
def __str__(self):
|
||||
msg = "At least one of the field(s) for {0}: ({1}) must be populated."
|
||||
return msg.format(self.cls.__name__,
|
||||
", ".join(x for x in self.fields))
|
||||
", ".join(x for x in self.properties))
|
||||
|
||||
|
||||
class RevokeError(STIXError, ValueError):
|
||||
|
|
|
@ -45,7 +45,7 @@ class Property(object):
|
|||
- provide a default value for this property.
|
||||
- `default()` can return the special value `NOW` to use the current
|
||||
time. This is useful when several timestamps in the same object need
|
||||
to use the same default value, so calling now() for each field--
|
||||
to use the same default value, so calling now() for each property--
|
||||
likely several microseconds apart-- does not work.
|
||||
|
||||
Subclasses can instead provide a lambda function for `default` as a keyword
|
||||
|
@ -53,7 +53,7 @@ class Property(object):
|
|||
raise their own exceptions.
|
||||
|
||||
When instantiating Properties, `required` and `default` should not be used
|
||||
together. `default` implies that the field is required in the specification
|
||||
together. `default` implies that the property is required in the specification
|
||||
so this function will be used to supply a value if none is provided.
|
||||
`required` means that the user must provide this; it is required in the
|
||||
specification and we can't or don't want to create a default value.
|
||||
|
|
|
@ -114,4 +114,4 @@ def test_external_reference_source_required():
|
|||
stix2.ExternalReference()
|
||||
|
||||
assert excinfo.value.cls == stix2.ExternalReference
|
||||
assert excinfo.value.fields == ["source_name"]
|
||||
assert excinfo.value.properties == ["source_name"]
|
||||
|
|
|
@ -32,7 +32,7 @@ EXPECTED_INDICATOR_REPR = "Indicator(" + " ".join("""
|
|||
""".split()) + ")"
|
||||
|
||||
|
||||
def test_indicator_with_all_required_fields():
|
||||
def test_indicator_with_all_required_properties():
|
||||
now = dt.datetime(2017, 1, 1, 0, 0, 1, tzinfo=pytz.utc)
|
||||
epoch = dt.datetime(1970, 1, 1, 0, 0, 1, tzinfo=pytz.utc)
|
||||
|
||||
|
@ -51,7 +51,7 @@ def test_indicator_with_all_required_fields():
|
|||
assert rep == EXPECTED_INDICATOR_REPR
|
||||
|
||||
|
||||
def test_indicator_autogenerated_fields(indicator):
|
||||
def test_indicator_autogenerated_properties(indicator):
|
||||
assert indicator.type == 'indicator'
|
||||
assert indicator.id == 'indicator--00000000-0000-0000-0000-000000000001'
|
||||
assert indicator.created == FAKE_TIME
|
||||
|
@ -89,21 +89,21 @@ def test_indicator_id_must_start_with_indicator():
|
|||
assert str(excinfo.value) == "Invalid value for Indicator 'id': must start with 'indicator--'."
|
||||
|
||||
|
||||
def test_indicator_required_fields():
|
||||
def test_indicator_required_properties():
|
||||
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||
stix2.Indicator()
|
||||
|
||||
assert excinfo.value.cls == stix2.Indicator
|
||||
assert excinfo.value.fields == ["labels", "pattern"]
|
||||
assert str(excinfo.value) == "No values for required field(s) for Indicator: (labels, pattern)."
|
||||
assert excinfo.value.properties == ["labels", "pattern"]
|
||||
assert str(excinfo.value) == "No values for required properties for Indicator: (labels, pattern)."
|
||||
|
||||
|
||||
def test_indicator_required_field_pattern():
|
||||
def test_indicator_required_property_pattern():
|
||||
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||
stix2.Indicator(labels=['malicious-activity'])
|
||||
|
||||
assert excinfo.value.cls == stix2.Indicator
|
||||
assert excinfo.value.fields == ["pattern"]
|
||||
assert excinfo.value.properties == ["pattern"]
|
||||
|
||||
|
||||
def test_indicator_created_ref_invalid_format():
|
||||
|
@ -137,8 +137,8 @@ def test_invalid_kwarg_to_indicator():
|
|||
stix2.Indicator(my_custom_property="foo", **INDICATOR_KWARGS)
|
||||
|
||||
assert excinfo.value.cls == stix2.Indicator
|
||||
assert excinfo.value.fields == ['my_custom_property']
|
||||
assert str(excinfo.value) == "Unexpected field(s) for Indicator: (my_custom_property)."
|
||||
assert excinfo.value.properties == ['my_custom_property']
|
||||
assert str(excinfo.value) == "Unexpected properties for Indicator: (my_custom_property)."
|
||||
|
||||
|
||||
def test_created_modified_time_are_identical_by_default():
|
||||
|
|
|
@ -35,28 +35,28 @@ def test_kill_chain_example():
|
|||
assert str(preattack) == FOO_PRE_ATTACK
|
||||
|
||||
|
||||
def test_kill_chain_required_fields():
|
||||
def test_kill_chain_required_properties():
|
||||
|
||||
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||
stix2.KillChainPhase()
|
||||
|
||||
assert excinfo.value.cls == stix2.KillChainPhase
|
||||
assert excinfo.value.fields == ["kill_chain_name", "phase_name"]
|
||||
assert excinfo.value.properties == ["kill_chain_name", "phase_name"]
|
||||
|
||||
|
||||
def test_kill_chain_required_field_chain_name():
|
||||
def test_kill_chain_required_property_chain_name():
|
||||
|
||||
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||
stix2.KillChainPhase(phase_name="weaponization")
|
||||
|
||||
assert excinfo.value.cls == stix2.KillChainPhase
|
||||
assert excinfo.value.fields == ["kill_chain_name"]
|
||||
assert excinfo.value.properties == ["kill_chain_name"]
|
||||
|
||||
|
||||
def test_kill_chain_required_field_phase_name():
|
||||
def test_kill_chain_required_property_phase_name():
|
||||
|
||||
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||
stix2.KillChainPhase(kill_chain_name="lockheed-martin-cyber-kill-chain")
|
||||
|
||||
assert excinfo.value.cls == stix2.KillChainPhase
|
||||
assert excinfo.value.fields == ["phase_name"]
|
||||
assert excinfo.value.properties == ["phase_name"]
|
||||
|
|
|
@ -21,7 +21,7 @@ EXPECTED_MALWARE = """{
|
|||
}"""
|
||||
|
||||
|
||||
def test_malware_with_all_required_fields():
|
||||
def test_malware_with_all_required_properties():
|
||||
now = dt.datetime(2016, 5, 12, 8, 17, 27, tzinfo=pytz.utc)
|
||||
|
||||
mal = stix2.Malware(
|
||||
|
@ -36,7 +36,7 @@ def test_malware_with_all_required_fields():
|
|||
assert str(mal) == EXPECTED_MALWARE
|
||||
|
||||
|
||||
def test_malware_autogenerated_fields(malware):
|
||||
def test_malware_autogenerated_properties(malware):
|
||||
assert malware.type == 'malware'
|
||||
assert malware.id == 'malware--00000000-0000-0000-0000-000000000001'
|
||||
assert malware.created == FAKE_TIME
|
||||
|
@ -72,20 +72,20 @@ def test_malware_id_must_start_with_malware():
|
|||
assert str(excinfo.value) == "Invalid value for Malware 'id': must start with 'malware--'."
|
||||
|
||||
|
||||
def test_malware_required_fields():
|
||||
def test_malware_required_properties():
|
||||
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||
stix2.Malware()
|
||||
|
||||
assert excinfo.value.cls == stix2.Malware
|
||||
assert excinfo.value.fields == ["labels", "name"]
|
||||
assert excinfo.value.properties == ["labels", "name"]
|
||||
|
||||
|
||||
def test_malware_required_field_name():
|
||||
def test_malware_required_property_name():
|
||||
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||
stix2.Malware(labels=['ransomware'])
|
||||
|
||||
assert excinfo.value.cls == stix2.Malware
|
||||
assert excinfo.value.fields == ["name"]
|
||||
assert excinfo.value.properties == ["name"]
|
||||
|
||||
|
||||
def test_cannot_assign_to_malware_attributes(malware):
|
||||
|
@ -100,8 +100,8 @@ def test_invalid_kwarg_to_malware():
|
|||
stix2.Malware(my_custom_property="foo", **MALWARE_KWARGS)
|
||||
|
||||
assert excinfo.value.cls == stix2.Malware
|
||||
assert excinfo.value.fields == ['my_custom_property']
|
||||
assert str(excinfo.value) == "Unexpected field(s) for Malware: (my_custom_property)."
|
||||
assert excinfo.value.properties == ['my_custom_property']
|
||||
assert str(excinfo.value) == "Unexpected properties for Malware: (my_custom_property)."
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
|
|
|
@ -369,7 +369,7 @@ def test_parse_email_message_with_at_least_one_error(data):
|
|||
stix2.parse_observable(data, [str(i) for i in range(1, 6)])
|
||||
|
||||
assert excinfo.value.cls == stix2.EmailMIMEComponent
|
||||
assert excinfo.value.fields == ["body", "body_raw_ref"]
|
||||
assert excinfo.value.properties == ["body", "body_raw_ref"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
|
@ -416,7 +416,7 @@ def test_parse_basic_tcp_traffic_with_error(data):
|
|||
stix2.parse_observable(data, ["4"])
|
||||
|
||||
assert excinfo.value.cls == stix2.NetworkTraffic
|
||||
assert excinfo.value.fields == ["dst_ref", "src_ref"]
|
||||
assert excinfo.value.properties == ["dst_ref", "src_ref"]
|
||||
|
||||
|
||||
EXPECTED_PROCESS_OD = """{
|
||||
|
@ -508,7 +508,7 @@ def test_artifact_mutual_exclusion_error():
|
|||
payload_bin="VBORw0KGgoAAAANSUhEUgAAADI==")
|
||||
|
||||
assert excinfo.value.cls == stix2.Artifact
|
||||
assert excinfo.value.fields == ["payload_bin", "url"]
|
||||
assert excinfo.value.properties == ["payload_bin", "url"]
|
||||
|
||||
|
||||
def test_directory_example():
|
||||
|
|
|
@ -20,7 +20,7 @@ EXPECTED_RELATIONSHIP = """{
|
|||
}"""
|
||||
|
||||
|
||||
def test_relationship_all_required_fields():
|
||||
def test_relationship_all_required_properties():
|
||||
now = dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc)
|
||||
|
||||
rel = stix2.Relationship(
|
||||
|
@ -35,7 +35,7 @@ def test_relationship_all_required_fields():
|
|||
assert str(rel) == EXPECTED_RELATIONSHIP
|
||||
|
||||
|
||||
def test_relationship_autogenerated_fields(relationship):
|
||||
def test_relationship_autogenerated_properties(relationship):
|
||||
assert relationship.type == 'relationship'
|
||||
assert relationship.id == 'relationship--00000000-0000-0000-0000-000000000001'
|
||||
assert relationship.created == FAKE_TIME
|
||||
|
@ -73,22 +73,22 @@ def test_relationship_id_must_start_with_relationship():
|
|||
assert str(excinfo.value) == "Invalid value for Relationship 'id': must start with 'relationship--'."
|
||||
|
||||
|
||||
def test_relationship_required_field_relationship_type():
|
||||
def test_relationship_required_property_relationship_type():
|
||||
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||
stix2.Relationship()
|
||||
assert excinfo.value.cls == stix2.Relationship
|
||||
assert excinfo.value.fields == ["relationship_type", "source_ref", "target_ref"]
|
||||
assert excinfo.value.properties == ["relationship_type", "source_ref", "target_ref"]
|
||||
|
||||
|
||||
def test_relationship_missing_some_required_fields():
|
||||
def test_relationship_missing_some_required_properties():
|
||||
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||
stix2.Relationship(relationship_type='indicates')
|
||||
|
||||
assert excinfo.value.cls == stix2.Relationship
|
||||
assert excinfo.value.fields == ["source_ref", "target_ref"]
|
||||
assert excinfo.value.properties == ["source_ref", "target_ref"]
|
||||
|
||||
|
||||
def test_relationship_required_field_target_ref():
|
||||
def test_relationship_required_properties_target_ref():
|
||||
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
|
||||
stix2.Relationship(
|
||||
relationship_type='indicates',
|
||||
|
@ -96,7 +96,7 @@ def test_relationship_required_field_target_ref():
|
|||
)
|
||||
|
||||
assert excinfo.value.cls == stix2.Relationship
|
||||
assert excinfo.value.fields == ["target_ref"]
|
||||
assert excinfo.value.properties == ["target_ref"]
|
||||
|
||||
|
||||
def test_cannot_assign_to_relationship_attributes(relationship):
|
||||
|
@ -111,8 +111,8 @@ def test_invalid_kwarg_to_relationship():
|
|||
stix2.Relationship(my_custom_property="foo", **RELATIONSHIP_KWARGS)
|
||||
|
||||
assert excinfo.value.cls == stix2.Relationship
|
||||
assert excinfo.value.fields == ['my_custom_property']
|
||||
assert str(excinfo.value) == "Unexpected field(s) for Relationship: (my_custom_property)."
|
||||
assert excinfo.value.properties == ['my_custom_property']
|
||||
assert str(excinfo.value) == "Unexpected properties for Relationship: (my_custom_property)."
|
||||
|
||||
|
||||
def test_create_relationship_from_objects_rather_than_ids(indicator, malware):
|
||||
|
|
|
@ -31,7 +31,7 @@ BAD_SIGHTING = """{
|
|||
}"""
|
||||
|
||||
|
||||
def test_sighting_all_required_fields():
|
||||
def test_sighting_all_required_properties():
|
||||
now = dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc)
|
||||
|
||||
s = stix2.Sighting(
|
||||
|
@ -79,8 +79,8 @@ def test_invalid_kwarg_to_sighting():
|
|||
stix2.Sighting(my_custom_property="foo", **SIGHTING_KWARGS)
|
||||
|
||||
assert excinfo.value.cls == stix2.Sighting
|
||||
assert excinfo.value.fields == ['my_custom_property']
|
||||
assert str(excinfo.value) == "Unexpected field(s) for Sighting: (my_custom_property)."
|
||||
assert excinfo.value.properties == ['my_custom_property']
|
||||
assert str(excinfo.value) == "Unexpected properties for Sighting: (my_custom_property)."
|
||||
|
||||
|
||||
def test_create_sighting_from_objects_rather_than_ids(malware): # noqa: F811
|
||||
|
|
|
@ -142,7 +142,7 @@ def test_versioning_error_usetting_required_property():
|
|||
campaign_v1.new_version(name=None)
|
||||
|
||||
assert excinfo.value.cls == stix2.Campaign
|
||||
assert excinfo.value.fields == ["name"]
|
||||
assert excinfo.value.properties == ["name"]
|
||||
|
||||
|
||||
def test_versioning_error_new_version_of_revoked():
|
||||
|
|
Loading…
Reference in New Issue