Change remaining 'fields' to 'properties'

stix2.1
Greg Back 2017-05-19 12:51:59 -05:00
parent a913d9d5ad
commit 41f2ceb8e5
13 changed files with 41 additions and 39 deletions

View File

@ -45,7 +45,7 @@ provided as keyword arguments:
```python ```python
>>> indicator = Indicator(type='xxx', ...) >>> indicator = Indicator(type='xxx', ...)
ValueError: Indicators must have type='indicator' stix2.exceptions.InvalidValueError: Invalid value for Indicator 'type': must equal 'indicator'.
``` ```
- If not provided, `id` will be generated randomly. If you provide an `id` - If not provided, `id` will be generated randomly. If you provide an `id`
@ -53,19 +53,19 @@ provided as keyword arguments:
```python ```python
>>> indicator = Indicator(id="campaign--63ce9068-b5ab-47fa-a2cf-a602ea01f21a") >>> indicator = Indicator(id="campaign--63ce9068-b5ab-47fa-a2cf-a602ea01f21a")
ValueError: Invalid value for Indicator 'id': must start with 'indicator--'. stix2.exceptions.InvalidValueError: Invalid value for Indicator 'id': must start with 'indicator--'.
``` ```
- If not provided, `created` and `modified` will be set to the (same) current - If not provided, `created` and `modified` will be set to the (same) current
time. time.
For indicators, `labels` and `pattern` are required and cannot be set For indicators, `labels` and `pattern` are required and cannot be set
automatically. Trying to create an indicator that is missing one of these fields automatically. Trying to create an indicator that is missing one of these
will result in an error: properties will result in an error:
```python ```python
>>> indicator = Indicator() >>> indicator = Indicator()
ValueError: Missing required field(s) for Indicator: (labels, pattern). stix2.exceptions.MissingPropertiesError: No values for required properties for Indicator: (labels, pattern).
``` ```
However, the required `valid_from` attribute on Indicators will be set to the However, the required `valid_from` attribute on Indicators will be set to the
@ -89,8 +89,10 @@ TBD: Should we allow property access using the standard Python attribute syntax?
Attempting to modify any attributes will raise an error: Attempting to modify any attributes will raise an error:
```python ```python
>>>indicator['name'] = "This is a revised name" >>> indicator['name'] = "This is a revised name"
ValueError: Cannot modify properties after creation. TypeError: 'Indicator' object does not support item assignment
>>> indicator.name = "This is a revised name"
stix2.exceptions.ImmutableError: Cannot modify properties after creation.
``` ```
To update the properties of an object, see [Versioning](#versioning) below. To update the properties of an object, see [Versioning](#versioning) below.

View File

@ -5,8 +5,8 @@ import copy
import datetime as dt import datetime as dt
import json import json
from .exceptions import (AtLeastOnePropertyError, DependentPropertiestError, ExtraFieldsError, ImmutableError, from .exceptions import (AtLeastOnePropertyError, DependentPropertiesError, ExtraPropertiesError, ImmutableError,
InvalidObjRefError, InvalidValueError, MissingFieldsError, MutuallyExclusivePropertiesError, InvalidObjRefError, InvalidValueError, MissingPropertiesError, MutuallyExclusivePropertiesError,
RevokeError, UnmodifiablePropertyError) RevokeError, UnmodifiablePropertyError)
from .utils import NOW, format_datetime, get_timestamp, parse_into_datetime from .utils import NOW, format_datetime, get_timestamp, parse_into_datetime
@ -75,7 +75,7 @@ class _STIXBase(collections.Mapping):
if dp in current_properties and (p not in current_properties or (v and not current_properties(p) == v)): if dp in current_properties and (p not in current_properties or (v and not current_properties(p) == v)):
failed_dependency_pairs.append((p, dp)) failed_dependency_pairs.append((p, dp))
if failed_dependency_pairs: if failed_dependency_pairs:
raise DependentPropertiestError(self.__class__, failed_dependency_pairs) raise DependentPropertiesError(self.__class__, failed_dependency_pairs)
def _check_object_constraints(self): def _check_object_constraints(self):
if self.granular_markings: if self.granular_markings:
@ -92,7 +92,7 @@ class _STIXBase(collections.Mapping):
# Detect any keyword arguments not allowed for a specific type # Detect any keyword arguments not allowed for a specific type
extra_kwargs = list(set(kwargs) - set(cls._properties)) extra_kwargs = list(set(kwargs) - set(cls._properties))
if extra_kwargs: if extra_kwargs:
raise ExtraFieldsError(cls, extra_kwargs) raise ExtraPropertiesError(cls, extra_kwargs)
# Remove any keyword arguments whose value is None # Remove any keyword arguments whose value is None
setting_kwargs = {} setting_kwargs = {}
@ -104,7 +104,7 @@ class _STIXBase(collections.Mapping):
required_properties = get_required_properties(cls._properties) required_properties = get_required_properties(cls._properties)
missing_kwargs = set(required_properties) - set(setting_kwargs) missing_kwargs = set(required_properties) - set(setting_kwargs)
if missing_kwargs: if missing_kwargs:
raise MissingFieldsError(cls, missing_kwargs) raise MissingPropertiesError(cls, missing_kwargs)
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, setting_kwargs) self._check_property(prop_name, prop_metadata, setting_kwargs)

View File

@ -16,11 +16,11 @@ class InvalidValueError(STIXError, ValueError):
return msg.format(self) return msg.format(self)
class MissingFieldsError(STIXError, ValueError): class MissingPropertiesError(STIXError, ValueError):
"""Missing one or more required properties when constructing STIX object.""" """Missing one or more required properties when constructing STIX object."""
def __init__(self, cls, properties): def __init__(self, cls, properties):
super(MissingFieldsError, self).__init__() super(MissingPropertiesError, self).__init__()
self.cls = cls self.cls = cls
self.properties = sorted(list(properties)) self.properties = sorted(list(properties))
@ -30,11 +30,11 @@ class MissingFieldsError(STIXError, ValueError):
", ".join(x for x in self.properties)) ", ".join(x for x in self.properties))
class ExtraFieldsError(STIXError, TypeError): class ExtraPropertiesError(STIXError, TypeError):
"""One or more extra properties were provided when constructing STIX object.""" """One or more extra properties were provided when constructing STIX object."""
def __init__(self, cls, properties): def __init__(self, cls, properties):
super(ExtraFieldsError, self).__init__() super(ExtraPropertiesError, self).__init__()
self.cls = cls self.cls = cls
self.properties = sorted(list(properties)) self.properties = sorted(list(properties))
@ -99,16 +99,16 @@ class MutuallyExclusivePropertiesError(STIXError, TypeError):
self.properties = sorted(list(properties)) self.properties = sorted(list(properties))
def __str__(self): def __str__(self):
msg = "The field(s) for {0}: ({1}) are mutually exclusive." msg = "The ({1}) properties for {0} are mutually exclusive."
return msg.format(self.cls.__name__, return msg.format(self.cls.__name__,
", ".join(x for x in self.properties)) ", ".join(x for x in self.properties))
class DependentPropertiestError(STIXError, TypeError): class DependentPropertiesError(STIXError, TypeError):
"""Violating interproperty dependency constraint of a STIX object type.""" """Violating interproperty dependency constraint of a STIX object type."""
def __init__(self, cls, dependencies): def __init__(self, cls, dependencies):
super(DependentPropertiestError, self).__init__() super(DependentPropertiesError, self).__init__()
self.cls = cls self.cls = cls
self.dependencies = dependencies self.dependencies = dependencies
@ -127,7 +127,7 @@ class AtLeastOnePropertyError(STIXError, TypeError):
self.properties = sorted(list(properties)) 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 ({1}) properties for {0} must be populated."
return msg.format(self.cls.__name__, return msg.format(self.cls.__name__,
", ".join(x for x in self.properties)) ", ".join(x for x in self.properties))

View File

@ -110,7 +110,7 @@ def test_external_reference_offline():
def test_external_reference_source_required(): def test_external_reference_source_required():
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo: with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo:
stix2.ExternalReference() stix2.ExternalReference()
assert excinfo.value.cls == stix2.ExternalReference assert excinfo.value.cls == stix2.ExternalReference

View File

@ -90,7 +90,7 @@ def test_indicator_id_must_start_with_indicator():
def test_indicator_required_properties(): def test_indicator_required_properties():
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo: with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo:
stix2.Indicator() stix2.Indicator()
assert excinfo.value.cls == stix2.Indicator assert excinfo.value.cls == stix2.Indicator
@ -99,7 +99,7 @@ def test_indicator_required_properties():
def test_indicator_required_property_pattern(): def test_indicator_required_property_pattern():
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo: with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo:
stix2.Indicator(labels=['malicious-activity']) stix2.Indicator(labels=['malicious-activity'])
assert excinfo.value.cls == stix2.Indicator assert excinfo.value.cls == stix2.Indicator
@ -133,7 +133,7 @@ def test_cannot_assign_to_indicator_attributes(indicator):
def test_invalid_kwarg_to_indicator(): def test_invalid_kwarg_to_indicator():
with pytest.raises(stix2.exceptions.ExtraFieldsError) as excinfo: with pytest.raises(stix2.exceptions.ExtraPropertiesError) as excinfo:
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

View File

@ -37,7 +37,7 @@ def test_kill_chain_example():
def test_kill_chain_required_properties(): def test_kill_chain_required_properties():
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo: with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo:
stix2.KillChainPhase() stix2.KillChainPhase()
assert excinfo.value.cls == stix2.KillChainPhase assert excinfo.value.cls == stix2.KillChainPhase
@ -46,7 +46,7 @@ def test_kill_chain_required_properties():
def test_kill_chain_required_property_chain_name(): def test_kill_chain_required_property_chain_name():
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo: with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo:
stix2.KillChainPhase(phase_name="weaponization") stix2.KillChainPhase(phase_name="weaponization")
assert excinfo.value.cls == stix2.KillChainPhase assert excinfo.value.cls == stix2.KillChainPhase
@ -55,7 +55,7 @@ def test_kill_chain_required_property_chain_name():
def test_kill_chain_required_property_phase_name(): def test_kill_chain_required_property_phase_name():
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo: with pytest.raises(stix2.exceptions.MissingPropertiesError) 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

View File

@ -73,7 +73,7 @@ def test_malware_id_must_start_with_malware():
def test_malware_required_properties(): def test_malware_required_properties():
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo: with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo:
stix2.Malware() stix2.Malware()
assert excinfo.value.cls == stix2.Malware assert excinfo.value.cls == stix2.Malware
@ -81,7 +81,7 @@ def test_malware_required_properties():
def test_malware_required_property_name(): def test_malware_required_property_name():
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo: with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo:
stix2.Malware(labels=['ransomware']) stix2.Malware(labels=['ransomware'])
assert excinfo.value.cls == stix2.Malware assert excinfo.value.cls == stix2.Malware
@ -96,7 +96,7 @@ def test_cannot_assign_to_malware_attributes(malware):
def test_invalid_kwarg_to_malware(): def test_invalid_kwarg_to_malware():
with pytest.raises(stix2.exceptions.ExtraFieldsError) as excinfo: with pytest.raises(stix2.exceptions.ExtraPropertiesError) as excinfo:
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

View File

@ -761,7 +761,7 @@ def test_file_example_with_WindowsPEBinaryExt():
def test_file_example_encryption_error(): def test_file_example_encryption_error():
with pytest.raises(stix2.exceptions.DependentPropertiestError) as excinfo: with pytest.raises(stix2.exceptions.DependentPropertiesError) as excinfo:
stix2.File(name="qwerty.dll", stix2.File(name="qwerty.dll",
is_encrypted=False, is_encrypted=False,
encryption_algorithm="AES128-CBC" encryption_algorithm="AES128-CBC"

View File

@ -35,7 +35,7 @@ def test_basic_clean():
p.clean(41) p.clean(41)
def test_default_field(): def test_property_default():
class Prop(Property): class Prop(Property):
def default(self): def default(self):

View File

@ -74,14 +74,14 @@ def test_relationship_id_must_start_with_relationship():
def test_relationship_required_property_relationship_type(): def test_relationship_required_property_relationship_type():
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo: with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo:
stix2.Relationship() stix2.Relationship()
assert excinfo.value.cls == stix2.Relationship assert excinfo.value.cls == stix2.Relationship
assert excinfo.value.properties == ["relationship_type", "source_ref", "target_ref"] assert excinfo.value.properties == ["relationship_type", "source_ref", "target_ref"]
def test_relationship_missing_some_required_properties(): def test_relationship_missing_some_required_properties():
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo: with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo:
stix2.Relationship(relationship_type='indicates') stix2.Relationship(relationship_type='indicates')
assert excinfo.value.cls == stix2.Relationship assert excinfo.value.cls == stix2.Relationship
@ -89,7 +89,7 @@ def test_relationship_missing_some_required_properties():
def test_relationship_required_properties_target_ref(): def test_relationship_required_properties_target_ref():
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo: with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo:
stix2.Relationship( stix2.Relationship(
relationship_type='indicates', relationship_type='indicates',
source_ref=INDICATOR_ID source_ref=INDICATOR_ID
@ -107,7 +107,7 @@ def test_cannot_assign_to_relationship_attributes(relationship):
def test_invalid_kwarg_to_relationship(): def test_invalid_kwarg_to_relationship():
with pytest.raises(stix2.exceptions.ExtraFieldsError) as excinfo: with pytest.raises(stix2.exceptions.ExtraPropertiesError) as excinfo:
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

View File

@ -75,7 +75,7 @@ def test_sighting_type_must_be_sightings():
def test_invalid_kwarg_to_sighting(): def test_invalid_kwarg_to_sighting():
with pytest.raises(stix2.exceptions.ExtraFieldsError) as excinfo: with pytest.raises(stix2.exceptions.ExtraPropertiesError) as excinfo:
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

View File

@ -138,7 +138,7 @@ def test_versioning_error_usetting_required_property():
description="Campaign by Green Group against a series of targets in the financial services sector." description="Campaign by Green Group against a series of targets in the financial services sector."
) )
with pytest.raises(stix2.exceptions.MissingFieldsError) as excinfo: with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo:
campaign_v1.new_version(name=None) campaign_v1.new_version(name=None)
assert excinfo.value.cls == stix2.Campaign assert excinfo.value.cls == stix2.Campaign

View File

@ -6,7 +6,7 @@ import json
from dateutil import parser from dateutil import parser
import pytz import pytz
# Sentinel value for fields that should be set to the current time. # Sentinel value for properties that should be set to the current time.
# We can't use the standard 'default' approach, since if there are multiple # We can't use the standard 'default' approach, since if there are multiple
# timestamps in a single object, the timestamps will vary by a few microseconds. # timestamps in a single object, the timestamps will vary by a few microseconds.
NOW = object() NOW = object()