Replace 'field' with 'property' to be consistent

with the specification
stix2.1
clenk 2017-05-16 12:27:30 -04:00
parent a520a67511
commit 9761c37f20
12 changed files with 64 additions and 64 deletions

View File

@ -123,7 +123,7 @@ def parse_observable(data, _valid_refs):
obj['_valid_refs'] = _valid_refs obj['_valid_refs'] = _valid_refs
if 'type' not in obj: if 'type' not in obj:
raise ValueError("'type' is a required field!") raise ValueError("'type' is a required property!")
try: try:
obj_class = OBJ_MAP_OBSERVABLE[obj['type']] obj_class = OBJ_MAP_OBSERVABLE[obj['type']]
except KeyError: except KeyError:

View File

@ -12,7 +12,7 @@ from .utils import NOW, format_datetime, get_timestamp, parse_into_datetime
__all__ = ['STIXJSONEncoder', '_STIXBase'] __all__ = ['STIXJSONEncoder', '_STIXBase']
DEFAULT_ERROR = "{type} must have {field}='{expected}'." DEFAULT_ERROR = "{type} must have {property}='{expected}'."
class STIXJSONEncoder(json.JSONEncoder): class STIXJSONEncoder(json.JSONEncoder):
@ -95,9 +95,9 @@ class _STIXBase(collections.Mapping):
if prop_value: if prop_value:
setting_kwargs[prop_name] = prop_value setting_kwargs[prop_name] = prop_value
# Detect any missing required fields # Detect any missing required properties
required_fields = get_required_properties(cls._properties) required_properties = get_required_properties(cls._properties)
missing_kwargs = set(required_fields) - set(setting_kwargs) missing_kwargs = set(required_properties) - set(setting_kwargs)
if missing_kwargs: if missing_kwargs:
raise MissingFieldsError(cls, missing_kwargs) raise MissingFieldsError(cls, missing_kwargs)

View File

@ -17,31 +17,31 @@ class InvalidValueError(STIXError, ValueError):
class MissingFieldsError(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__() super(MissingFieldsError, self).__init__()
self.cls = cls self.cls = cls
self.fields = sorted(list(fields)) self.properties = sorted(list(properties))
def __str__(self): 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__, return msg.format(self.cls.__name__,
", ".join(x for x in self.fields)) ", ".join(x for x in self.properties))
class ExtraFieldsError(STIXError, TypeError): 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__() super(ExtraFieldsError, self).__init__()
self.cls = cls self.cls = cls
self.fields = sorted(list(fields)) self.properties = sorted(list(properties))
def __str__(self): def __str__(self):
msg = "Unexpected field(s) for {0}: ({1})." msg = "Unexpected properties for {0}: ({1})."
return msg.format(self.cls.__name__, return msg.format(self.cls.__name__,
", ".join(x for x in self.fields)) ", ".join(x for x in self.properties))
class ImmutableError(STIXError, ValueError): class ImmutableError(STIXError, ValueError):
@ -93,15 +93,15 @@ class UnmodifiablePropertyError(STIXError, ValueError):
class MutuallyExclusivePropertiesError(STIXError, TypeError): class MutuallyExclusivePropertiesError(STIXError, TypeError):
"""Violating interproperty mutually exclusive constraint of a STIX object type.""" """Violating interproperty mutually exclusive constraint of a STIX object type."""
def __init__(self, cls, fields): def __init__(self, cls, properties):
super(MutuallyExclusivePropertiesError, self).__init__() super(MutuallyExclusivePropertiesError, self).__init__()
self.cls = cls self.cls = cls
self.fields = sorted(list(fields)) self.properties = sorted(list(properties))
def __str__(self): def __str__(self):
msg = "The field(s) for {0}: ({1}) are mutually exclusive." msg = "The field(s) for {0}: ({1}) are mutually exclusive."
return msg.format(self.cls.__name__, return msg.format(self.cls.__name__,
", ".join(x for x in self.fields)) ", ".join(x for x in self.properties))
class DependentPropertiestError(STIXError, TypeError): class DependentPropertiestError(STIXError, TypeError):
@ -121,15 +121,15 @@ class DependentPropertiestError(STIXError, TypeError):
class AtLeastOnePropertyError(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.""" """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__() super(AtLeastOnePropertyError, self).__init__()
self.cls = cls self.cls = cls
self.fields = sorted(list(fields)) self.properties = sorted(list(properties))
def __str__(self): def __str__(self):
msg = "At least one of the field(s) for {0}: ({1}) must be populated." msg = "At least one of the field(s) for {0}: ({1}) must be populated."
return msg.format(self.cls.__name__, return msg.format(self.cls.__name__,
", ".join(x for x in self.fields)) ", ".join(x for x in self.properties))
class RevokeError(STIXError, ValueError): class RevokeError(STIXError, ValueError):

View File

@ -45,7 +45,7 @@ class Property(object):
- provide a default value for this property. - provide a default value for this property.
- `default()` can return the special value `NOW` to use the current - `default()` can return the special value `NOW` to use the current
time. This is useful when several timestamps in the same object need 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. likely several microseconds apart-- does not work.
Subclasses can instead provide a lambda function for `default` as a keyword Subclasses can instead provide a lambda function for `default` as a keyword
@ -53,7 +53,7 @@ class Property(object):
raise their own exceptions. raise their own exceptions.
When instantiating Properties, `required` and `default` should not be used 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. 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 `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. specification and we can't or don't want to create a default value.

View File

@ -114,4 +114,4 @@ def test_external_reference_source_required():
stix2.ExternalReference() stix2.ExternalReference()
assert excinfo.value.cls == stix2.ExternalReference assert excinfo.value.cls == stix2.ExternalReference
assert excinfo.value.fields == ["source_name"] assert excinfo.value.properties == ["source_name"]

View File

@ -32,7 +32,7 @@ EXPECTED_INDICATOR_REPR = "Indicator(" + " ".join("""
""".split()) + ")" """.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) now = dt.datetime(2017, 1, 1, 0, 0, 1, tzinfo=pytz.utc)
epoch = dt.datetime(1970, 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 assert rep == EXPECTED_INDICATOR_REPR
def test_indicator_autogenerated_fields(indicator): def test_indicator_autogenerated_properties(indicator):
assert indicator.type == 'indicator' assert indicator.type == 'indicator'
assert indicator.id == 'indicator--00000000-0000-0000-0000-000000000001' assert indicator.id == 'indicator--00000000-0000-0000-0000-000000000001'
assert indicator.created == FAKE_TIME 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--'." 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: with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
stix2.Indicator() stix2.Indicator()
assert excinfo.value.cls == stix2.Indicator assert excinfo.value.cls == stix2.Indicator
assert excinfo.value.fields == ["labels", "pattern"] assert excinfo.value.properties == ["labels", "pattern"]
assert str(excinfo.value) == "No values for required field(s) for Indicator: (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: 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.cls == stix2.Indicator
assert excinfo.value.fields == ["pattern"] assert excinfo.value.properties == ["pattern"]
def test_indicator_created_ref_invalid_format(): 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) stix2.Indicator(my_custom_property="foo", **INDICATOR_KWARGS)
assert excinfo.value.cls == stix2.Indicator assert excinfo.value.cls == stix2.Indicator
assert excinfo.value.fields == ['my_custom_property'] assert excinfo.value.properties == ['my_custom_property']
assert str(excinfo.value) == "Unexpected field(s) for Indicator: (my_custom_property)." assert str(excinfo.value) == "Unexpected properties for Indicator: (my_custom_property)."
def test_created_modified_time_are_identical_by_default(): def test_created_modified_time_are_identical_by_default():

View File

@ -35,28 +35,28 @@ def test_kill_chain_example():
assert str(preattack) == FOO_PRE_ATTACK 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: with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
stix2.KillChainPhase() stix2.KillChainPhase()
assert excinfo.value.cls == 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: 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.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: 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.cls == stix2.KillChainPhase
assert excinfo.value.fields == ["phase_name"] assert excinfo.value.properties == ["phase_name"]

View File

@ -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) now = dt.datetime(2016, 5, 12, 8, 17, 27, tzinfo=pytz.utc)
mal = stix2.Malware( mal = stix2.Malware(
@ -36,7 +36,7 @@ def test_malware_with_all_required_fields():
assert str(mal) == EXPECTED_MALWARE assert str(mal) == EXPECTED_MALWARE
def test_malware_autogenerated_fields(malware): def test_malware_autogenerated_properties(malware):
assert malware.type == 'malware' assert malware.type == 'malware'
assert malware.id == 'malware--00000000-0000-0000-0000-000000000001' assert malware.id == 'malware--00000000-0000-0000-0000-000000000001'
assert malware.created == FAKE_TIME 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--'." 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: with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
stix2.Malware() stix2.Malware()
assert excinfo.value.cls == 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: 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.cls == stix2.Malware
assert excinfo.value.fields == ["name"] assert excinfo.value.properties == ["name"]
def test_cannot_assign_to_malware_attributes(malware): 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) stix2.Malware(my_custom_property="foo", **MALWARE_KWARGS)
assert excinfo.value.cls == stix2.Malware assert excinfo.value.cls == stix2.Malware
assert excinfo.value.fields == ['my_custom_property'] assert excinfo.value.properties == ['my_custom_property']
assert str(excinfo.value) == "Unexpected field(s) for Malware: (my_custom_property)." assert str(excinfo.value) == "Unexpected properties for Malware: (my_custom_property)."
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize("data", [

View File

@ -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)]) stix2.parse_observable(data, [str(i) for i in range(1, 6)])
assert excinfo.value.cls == stix2.EmailMIMEComponent 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", [ @pytest.mark.parametrize("data", [
@ -416,7 +416,7 @@ def test_parse_basic_tcp_traffic_with_error(data):
stix2.parse_observable(data, ["4"]) stix2.parse_observable(data, ["4"])
assert excinfo.value.cls == stix2.NetworkTraffic 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 = """{ EXPECTED_PROCESS_OD = """{
@ -508,7 +508,7 @@ def test_artifact_mutual_exclusion_error():
payload_bin="VBORw0KGgoAAAANSUhEUgAAADI==") payload_bin="VBORw0KGgoAAAANSUhEUgAAADI==")
assert excinfo.value.cls == stix2.Artifact assert excinfo.value.cls == stix2.Artifact
assert excinfo.value.fields == ["payload_bin", "url"] assert excinfo.value.properties == ["payload_bin", "url"]
def test_directory_example(): def test_directory_example():

View File

@ -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) now = dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc)
rel = stix2.Relationship( rel = stix2.Relationship(
@ -35,7 +35,7 @@ def test_relationship_all_required_fields():
assert str(rel) == EXPECTED_RELATIONSHIP assert str(rel) == EXPECTED_RELATIONSHIP
def test_relationship_autogenerated_fields(relationship): def test_relationship_autogenerated_properties(relationship):
assert relationship.type == 'relationship' assert relationship.type == 'relationship'
assert relationship.id == 'relationship--00000000-0000-0000-0000-000000000001' assert relationship.id == 'relationship--00000000-0000-0000-0000-000000000001'
assert relationship.created == FAKE_TIME 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--'." 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: with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
stix2.Relationship() stix2.Relationship()
assert excinfo.value.cls == 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: with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
stix2.Relationship(relationship_type='indicates') stix2.Relationship(relationship_type='indicates')
assert excinfo.value.cls == stix2.Relationship 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: with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo:
stix2.Relationship( stix2.Relationship(
relationship_type='indicates', relationship_type='indicates',
@ -96,7 +96,7 @@ def test_relationship_required_field_target_ref():
) )
assert excinfo.value.cls == stix2.Relationship 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): 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) stix2.Relationship(my_custom_property="foo", **RELATIONSHIP_KWARGS)
assert excinfo.value.cls == stix2.Relationship assert excinfo.value.cls == stix2.Relationship
assert excinfo.value.fields == ['my_custom_property'] assert excinfo.value.properties == ['my_custom_property']
assert str(excinfo.value) == "Unexpected field(s) for Relationship: (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): def test_create_relationship_from_objects_rather_than_ids(indicator, malware):

View File

@ -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) now = dt.datetime(2016, 4, 6, 20, 6, 37, tzinfo=pytz.utc)
s = stix2.Sighting( s = stix2.Sighting(
@ -79,8 +79,8 @@ def test_invalid_kwarg_to_sighting():
stix2.Sighting(my_custom_property="foo", **SIGHTING_KWARGS) stix2.Sighting(my_custom_property="foo", **SIGHTING_KWARGS)
assert excinfo.value.cls == stix2.Sighting assert excinfo.value.cls == stix2.Sighting
assert excinfo.value.fields == ['my_custom_property'] assert excinfo.value.properties == ['my_custom_property']
assert str(excinfo.value) == "Unexpected field(s) for Sighting: (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 def test_create_sighting_from_objects_rather_than_ids(malware): # noqa: F811

View File

@ -142,7 +142,7 @@ def test_versioning_error_usetting_required_property():
campaign_v1.new_version(name=None) campaign_v1.new_version(name=None)
assert excinfo.value.cls == stix2.Campaign assert excinfo.value.cls == stix2.Campaign
assert excinfo.value.fields == ["name"] assert excinfo.value.properties == ["name"]
def test_versioning_error_new_version_of_revoked(): def test_versioning_error_new_version_of_revoked():