Formatting changes made by the new pre-commit hook 'add trailing commas'

closes #189
stix2.1
Emmanuelle Vargas-Gonzalez 2018-07-13 11:10:05 -04:00
parent e0aa8abd0c
commit 51a499cb33
106 changed files with 4759 additions and 3569 deletions

View File

@ -49,7 +49,7 @@ html_sidebars = {
'navigation.html', 'navigation.html',
'relations.html', 'relations.html',
'searchbox.html', 'searchbox.html',
] ],
} }
latex_elements = {} latex_elements = {}

View File

@ -7,8 +7,10 @@ import stix2
def main(): def main():
collection = Collection("http://127.0.0.1:5000/trustgroup1/collections/52892447-4d7e-4f70-b94d-d7f22742ff63/", collection = Collection(
user="admin", password="Password0") "http://127.0.0.1:5000/trustgroup1/collections/52892447-4d7e-4f70-b94d-d7f22742ff63/",
user="admin", password="Password0",
)
# instantiate TAXII data source # instantiate TAXII data source
taxii = stix2.TAXIICollectionSource(collection) taxii = stix2.TAXIICollectionSource(collection)

View File

@ -55,6 +55,6 @@ setup(
'stix2-patterns', 'stix2-patterns',
], ],
extras_require={ extras_require={
'taxii': ['taxii2-client'] 'taxii': ['taxii2-client'],
} },
) )

View File

@ -37,34 +37,42 @@
from .core import _collect_stix2_mappings, parse, parse_observable from .core import _collect_stix2_mappings, parse, parse_observable
from .v21 import * # This import will always be the latest STIX 2.X version from .v21 import * # This import will always be the latest STIX 2.X version
from .datastore import CompositeDataSource from .datastore import CompositeDataSource
from .datastore.filesystem import (FileSystemSink, FileSystemSource, from .datastore.filesystem import (
FileSystemStore) FileSystemSink, FileSystemSource,
FileSystemStore
)
from .datastore.filters import Filter from .datastore.filters import Filter
from .datastore.memory import MemorySink, MemorySource, MemoryStore from .datastore.memory import MemorySink, MemorySource, MemoryStore
from .datastore.taxii import (TAXIICollectionSink, TAXIICollectionSource, from .datastore.taxii import (
TAXIICollectionStore) TAXIICollectionSink, TAXIICollectionSource,
TAXIICollectionStore
)
from .environment import Environment, ObjectFactory from .environment import Environment, ObjectFactory
from .markings import (add_markings, clear_markings, get_markings, is_marked, from .markings import (
remove_markings, set_markings) add_markings, clear_markings, get_markings, is_marked,
from .patterns import (AndBooleanExpression, AndObservationExpression, remove_markings, set_markings
BasicObjectPathComponent, BinaryConstant, )
BooleanConstant, EqualityComparisonExpression, from .patterns import (
FloatConstant, FollowedByObservationExpression, AndBooleanExpression, AndObservationExpression,
GreaterThanComparisonExpression, BasicObjectPathComponent, BinaryConstant,
GreaterThanEqualComparisonExpression, HashConstant, BooleanConstant, EqualityComparisonExpression,
HexConstant, InComparisonExpression, IntegerConstant, FloatConstant, FollowedByObservationExpression,
IsSubsetComparisonExpression, GreaterThanComparisonExpression,
IsSupersetComparisonExpression, GreaterThanEqualComparisonExpression, HashConstant,
LessThanComparisonExpression, HexConstant, InComparisonExpression, IntegerConstant,
LessThanEqualComparisonExpression, IsSubsetComparisonExpression,
LikeComparisonExpression, ListConstant, IsSupersetComparisonExpression,
ListObjectPathComponent, MatchesComparisonExpression, LessThanComparisonExpression,
ObjectPath, ObservationExpression, OrBooleanExpression, LessThanEqualComparisonExpression,
OrObservationExpression, ParentheticalExpression, LikeComparisonExpression, ListConstant,
QualifiedObservationExpression, ListObjectPathComponent, MatchesComparisonExpression,
ReferenceObjectPathComponent, RepeatQualifier, ObjectPath, ObservationExpression, OrBooleanExpression,
StartStopQualifier, StringConstant, TimestampConstant, OrObservationExpression, ParentheticalExpression,
WithinQualifier) QualifiedObservationExpression,
ReferenceObjectPathComponent, RepeatQualifier,
StartStopQualifier, StringConstant, TimestampConstant,
WithinQualifier
)
from .utils import new_version, revoke from .utils import new_version, revoke
from .version import __version__ from .version import __version__

View File

@ -6,11 +6,12 @@ import datetime as dt
import simplejson as json import simplejson as json
from .exceptions import (AtLeastOnePropertyError, CustomContentError, from .exceptions import (
DependentPropertiesError, ExtraPropertiesError, AtLeastOnePropertyError, CustomContentError, DependentPropertiesError,
ImmutableError, InvalidObjRefError, InvalidValueError, ExtraPropertiesError, ImmutableError, InvalidObjRefError,
MissingPropertiesError, InvalidValueError, MissingPropertiesError,
MutuallyExclusivePropertiesError) MutuallyExclusivePropertiesError,
)
from .markings.utils import validate from .markings.utils import validate
from .utils import NOW, find_property_index, format_datetime, get_timestamp from .utils import NOW, find_property_index, format_datetime, get_timestamp
from .utils import new_version as _new_version from .utils import new_version as _new_version
@ -206,8 +207,10 @@ class _STIXBase(collections.Mapping):
def __repr__(self): def __repr__(self):
props = [(k, self[k]) for k in self.object_properties() if self.get(k)] props = [(k, self[k]) for k in self.object_properties() if self.get(k)]
return '{0}({1})'.format(self.__class__.__name__, return '{0}({1})'.format(
', '.join(['{0!s}={1!r}'.format(k, v) for k, v in props])) self.__class__.__name__,
', '.join(['{0!s}={1!r}'.format(k, v) for k, v in props]),
)
def __deepcopy__(self, memo): def __deepcopy__(self, memo):
# Assume: we can ignore the memo argument, because no object will ever contain the same sub-object multiple times. # Assume: we can ignore the memo argument, because no object will ever contain the same sub-object multiple times.

View File

@ -254,8 +254,10 @@ def _register_observable_extension(observable, new_extension, version=None):
try: try:
observable_type = observable._type observable_type = observable._type
except AttributeError: except AttributeError:
raise ValueError("Unknown observable type. Custom observables must be " raise ValueError(
"created with the @CustomObservable decorator.") "Unknown observable type. Custom observables must be "
"created with the @CustomObservable decorator.",
)
OBJ_MAP_OBSERVABLE = STIX2_OBJ_MAPS[v]['observables'] OBJ_MAP_OBSERVABLE = STIX2_OBJ_MAPS[v]['observables']
EXT_MAP = STIX2_OBJ_MAPS[v]['observable-extensions'] EXT_MAP = STIX2_OBJ_MAPS[v]['observable-extensions']
@ -264,9 +266,11 @@ def _register_observable_extension(observable, new_extension, version=None):
EXT_MAP[observable_type][new_extension._type] = new_extension EXT_MAP[observable_type][new_extension._type] = new_extension
except KeyError: except KeyError:
if observable_type not in OBJ_MAP_OBSERVABLE: if observable_type not in OBJ_MAP_OBSERVABLE:
raise ValueError("Unknown observable type '%s'. Custom observables " raise ValueError(
"must be created with the @CustomObservable decorator." "Unknown observable type '%s'. Custom observables "
% observable_type) "must be created with the @CustomObservable decorator."
% observable_type,
)
else: else:
EXT_MAP[observable_type] = {new_extension._type: new_extension} EXT_MAP[observable_type] = {new_extension._type: new_extension}

View File

@ -2,8 +2,10 @@ from collections import OrderedDict
import re import re
from .base import _Extension, _Observable, _STIXBase from .base import _Extension, _Observable, _STIXBase
from .core import (STIXDomainObject, _register_marking, _register_object, from .core import (
_register_observable, _register_observable_extension) STIXDomainObject, _register_marking, _register_object,
_register_observable, _register_observable_extension,
)
from .utils import TYPE_REGEX, get_class_hierarchy_names from .utils import TYPE_REGEX, get_class_hierarchy_names
@ -11,11 +13,14 @@ def _custom_object_builder(cls, type, properties, version):
class _CustomObject(cls, STIXDomainObject): class _CustomObject(cls, STIXDomainObject):
if not re.match(TYPE_REGEX, type): if not re.match(TYPE_REGEX, type):
raise ValueError("Invalid type name '%s': must only contain the " raise ValueError(
"characters a-z (lowercase ASCII), 0-9, and hyphen (-)." % type) "Invalid type name '%s': must only contain the "
"characters a-z (lowercase ASCII), 0-9, and hyphen (-)." % type,
)
elif len(type) < 3 or len(type) > 250: elif len(type) < 3 or len(type) > 250:
raise ValueError( raise ValueError(
"Invalid type name '%s': must be between 3 and 250 characters." % type) "Invalid type name '%s': must be between 3 and 250 characters." % type,
)
if not properties or not isinstance(properties, list): if not properties or not isinstance(properties, list):
raise ValueError("Must supply a list, containing tuples. For example, [('property1', IntegerProperty())]") raise ValueError("Must supply a list, containing tuples. For example, [('property1', IntegerProperty())]")
@ -29,8 +34,10 @@ def _custom_object_builder(cls, type, properties, version):
cls.__init__(self, **kwargs) cls.__init__(self, **kwargs)
except (AttributeError, TypeError) as e: except (AttributeError, TypeError) as e:
# Don't accidentally catch errors raised in a custom __init__() # Don't accidentally catch errors raised in a custom __init__()
if ("has no attribute '__init__'" in str(e) or if (
str(e) == "object.__init__() takes no parameters"): "has no attribute '__init__'" in str(e) or
str(e) == "object.__init__() takes no parameters"
):
return return
raise e raise e
@ -53,8 +60,10 @@ def _custom_marking_builder(cls, type, properties, version):
cls.__init__(self, **kwargs) cls.__init__(self, **kwargs)
except (AttributeError, TypeError) as e: except (AttributeError, TypeError) as e:
# Don't accidentally catch errors raised in a custom __init__() # Don't accidentally catch errors raised in a custom __init__()
if ("has no attribute '__init__'" in str(e) or if (
str(e) == "object.__init__() takes no parameters"): "has no attribute '__init__'" in str(e) or
str(e) == "object.__init__() takes no parameters"
):
return return
raise e raise e
@ -66,8 +75,10 @@ def _custom_observable_builder(cls, type, properties, version):
class _CustomObservable(cls, _Observable): class _CustomObservable(cls, _Observable):
if not re.match(TYPE_REGEX, type): if not re.match(TYPE_REGEX, type):
raise ValueError("Invalid observable type name '%s': must only contain the " raise ValueError(
"characters a-z (lowercase ASCII), 0-9, and hyphen (-)." % type) "Invalid observable type name '%s': must only contain the "
"characters a-z (lowercase ASCII), 0-9, and hyphen (-)." % type,
)
elif len(type) < 3 or len(type) > 250: elif len(type) < 3 or len(type) > 250:
raise ValueError("Invalid observable type name '%s': must be between 3 and 250 characters." % type) raise ValueError("Invalid observable type name '%s': must be between 3 and 250 characters." % type)
@ -77,12 +88,16 @@ def _custom_observable_builder(cls, type, properties, version):
# Check properties ending in "_ref/s" are ObjectReferenceProperties # Check properties ending in "_ref/s" are ObjectReferenceProperties
for prop_name, prop in properties: for prop_name, prop in properties:
if prop_name.endswith('_ref') and ('ObjectReferenceProperty' not in get_class_hierarchy_names(prop)): if prop_name.endswith('_ref') and ('ObjectReferenceProperty' not in get_class_hierarchy_names(prop)):
raise ValueError("'%s' is named like an object reference property but " raise ValueError(
"is not an ObjectReferenceProperty." % prop_name) "'%s' is named like an object reference property but "
"is not an ObjectReferenceProperty." % prop_name,
)
elif (prop_name.endswith('_refs') and ('ListProperty' not in get_class_hierarchy_names(prop) elif (prop_name.endswith('_refs') and ('ListProperty' not in get_class_hierarchy_names(prop)
or 'ObjectReferenceProperty' not in get_class_hierarchy_names(prop.contained))): or 'ObjectReferenceProperty' not in get_class_hierarchy_names(prop.contained))):
raise ValueError("'%s' is named like an object reference list property but " raise ValueError(
"is not a ListProperty containing ObjectReferenceProperty." % prop_name) "'%s' is named like an object reference list property but "
"is not a ListProperty containing ObjectReferenceProperty." % prop_name,
)
_type = type _type = type
_properties = OrderedDict(properties) _properties = OrderedDict(properties)
@ -93,8 +108,10 @@ def _custom_observable_builder(cls, type, properties, version):
cls.__init__(self, **kwargs) cls.__init__(self, **kwargs)
except (AttributeError, TypeError) as e: except (AttributeError, TypeError) as e:
# Don't accidentally catch errors raised in a custom __init__() # Don't accidentally catch errors raised in a custom __init__()
if ("has no attribute '__init__'" in str(e) or if (
str(e) == "object.__init__() takes no parameters"): "has no attribute '__init__'" in str(e) or
str(e) == "object.__init__() takes no parameters"
):
return return
raise e raise e
@ -109,8 +126,10 @@ def _custom_extension_builder(cls, observable, type, properties, version):
class _CustomExtension(cls, _Extension): class _CustomExtension(cls, _Extension):
if not re.match(TYPE_REGEX, type): if not re.match(TYPE_REGEX, type):
raise ValueError("Invalid extension type name '%s': must only contain the " raise ValueError(
"characters a-z (lowercase ASCII), 0-9, and hyphen (-)." % type) "Invalid extension type name '%s': must only contain the "
"characters a-z (lowercase ASCII), 0-9, and hyphen (-)." % type,
)
elif len(type) < 3 or len(type) > 250: elif len(type) < 3 or len(type) > 250:
raise ValueError("Invalid extension type name '%s': must be between 3 and 250 characters." % type) raise ValueError("Invalid extension type name '%s': must be between 3 and 250 characters." % type)
@ -126,8 +145,10 @@ def _custom_extension_builder(cls, observable, type, properties, version):
cls.__init__(self, **kwargs) cls.__init__(self, **kwargs)
except (AttributeError, TypeError) as e: except (AttributeError, TypeError) as e:
# Don't accidentally catch errors raised in a custom __init__() # Don't accidentally catch errors raised in a custom __init__()
if ("has no attribute '__init__'" in str(e) or if (
str(e) == "object.__init__() takes no parameters"): "has no attribute '__init__'" in str(e) or
str(e) == "object.__init__() takes no parameters"
):
return return
raise e raise e

View File

@ -41,7 +41,7 @@ class FileSystemStore(DataStoreMixin):
super(FileSystemStore, self).__init__( super(FileSystemStore, self).__init__(
source=FileSystemSource(stix_dir=stix_dir, allow_custom=allow_custom_source), source=FileSystemSource(stix_dir=stix_dir, allow_custom=allow_custom_source),
sink=FileSystemSink(stix_dir=stix_dir, allow_custom=allow_custom_sink, bundlify=bundlify) sink=FileSystemSink(stix_dir=stix_dir, allow_custom=allow_custom_sink, bundlify=bundlify),
) )
@ -134,9 +134,11 @@ class FileSystemSink(DataSink):
self.add(stix_obj) self.add(stix_obj)
else: else:
raise TypeError("stix_data must be a STIX object (or list of), " raise TypeError(
"JSON formatted STIX (or list of), " "stix_data must be a STIX object (or list of), "
"or a JSON formatted STIX bundle") "JSON formatted STIX (or list of), "
"or a JSON formatted STIX bundle",
)
class FileSystemSource(DataSource): class FileSystemSource(DataSource):

View File

@ -81,7 +81,7 @@ class MemoryStore(DataStoreMixin):
super(MemoryStore, self).__init__( super(MemoryStore, self).__init__(
source=MemorySource(stix_data=self._data, allow_custom=allow_custom, _store=True), source=MemorySource(stix_data=self._data, allow_custom=allow_custom, _store=True),
sink=MemorySink(stix_data=self._data, allow_custom=allow_custom, _store=True) sink=MemorySink(stix_data=self._data, allow_custom=allow_custom, _store=True),
) )
def save_to_file(self, *args, **kwargs): def save_to_file(self, *args, **kwargs):

View File

@ -4,8 +4,9 @@ from requests.exceptions import HTTPError
from stix2 import Bundle, v20 from stix2 import Bundle, v20
from stix2.base import _STIXBase from stix2.base import _STIXBase
from stix2.core import parse from stix2.core import parse
from stix2.datastore import (DataSink, DataSource, DataSourceError, from stix2.datastore import (
DataStoreMixin) DataSink, DataSource, DataSourceError, DataStoreMixin,
)
from stix2.datastore.filters import Filter, FilterSet, apply_common_filters from stix2.datastore.filters import Filter, FilterSet, apply_common_filters
from stix2.utils import deduplicate from stix2.utils import deduplicate
@ -42,7 +43,7 @@ class TAXIICollectionStore(DataStoreMixin):
super(TAXIICollectionStore, self).__init__( super(TAXIICollectionStore, self).__init__(
source=TAXIICollectionSource(collection, allow_custom=allow_custom_source), source=TAXIICollectionSource(collection, allow_custom=allow_custom_source),
sink=TAXIICollectionSink(collection, allow_custom=allow_custom_sink) sink=TAXIICollectionSink(collection, allow_custom=allow_custom_sink),
) )
@ -65,12 +66,16 @@ class TAXIICollectionSink(DataSink):
if collection.can_write: if collection.can_write:
self.collection = collection self.collection = collection
else: else:
raise DataSourceError("The TAXII Collection object provided does not have write access" raise DataSourceError(
" to the underlying linked Collection resource") "The TAXII Collection object provided does not have write access"
" to the underlying linked Collection resource",
)
except (HTTPError, ValidationError) as e: except (HTTPError, ValidationError) as e:
raise DataSourceError("The underlying TAXII Collection resource defined in the supplied TAXII" raise DataSourceError(
" Collection object provided could not be reached. Receved error:", e) "The underlying TAXII Collection resource defined in the supplied TAXII"
" Collection object provided could not be reached. Receved error:", e,
)
self.allow_custom = allow_custom self.allow_custom = allow_custom
@ -146,12 +151,16 @@ class TAXIICollectionSource(DataSource):
if collection.can_read: if collection.can_read:
self.collection = collection self.collection = collection
else: else:
raise DataSourceError("The TAXII Collection object provided does not have read access" raise DataSourceError(
" to the underlying linked Collection resource") "The TAXII Collection object provided does not have read access"
" to the underlying linked Collection resource",
)
except (HTTPError, ValidationError) as e: except (HTTPError, ValidationError) as e:
raise DataSourceError("The underlying TAXII Collection resource defined in the supplied TAXII" raise DataSourceError(
" Collection object provided could not be reached. Recieved error:", e) "The underlying TAXII Collection resource defined in the supplied TAXII"
" Collection object provided could not be reached. Recieved error:", e,
)
self.allow_custom = allow_custom self.allow_custom = allow_custom
@ -218,7 +227,7 @@ class TAXIICollectionSource(DataSource):
# make query in TAXII query format since 'id' is TAXII field # make query in TAXII query format since 'id' is TAXII field
query = [ query = [
Filter('id', '=', stix_id), Filter('id', '=', stix_id),
Filter('version', '=', 'all') Filter('version', '=', 'all'),
] ]
all_data = self.query(query=query, _composite_filters=_composite_filters) all_data = self.query(query=query, _composite_filters=_composite_filters)
@ -277,9 +286,11 @@ class TAXIICollectionSource(DataSource):
except HTTPError as e: except HTTPError as e:
# if resources not found or access is denied from TAXII server, return empty list # if resources not found or access is denied from TAXII server, return empty list
if e.response.status_code == 404: if e.response.status_code == 404:
raise DataSourceError("The requested STIX objects for the TAXII Collection resource defined in" raise DataSourceError(
" the supplied TAXII Collection object are either not found or access is" "The requested STIX objects for the TAXII Collection resource defined in"
" denied. Received error: ", e) " the supplied TAXII Collection object are either not found or access is"
" denied. Received error: ", e,
)
# parse python STIX objects from the STIX object dicts # parse python STIX objects from the STIX object dicts
stix_objs = [parse(stix_obj_dict, allow_custom=self.allow_custom) for stix_obj_dict in all_data] stix_objs = [parse(stix_obj_dict, allow_custom=self.allow_custom) for stix_obj_dict in all_data]

View File

@ -27,9 +27,11 @@ class ObjectFactory(object):
default. Defaults to True. default. Defaults to True.
""" """
def __init__(self, created_by_ref=None, created=None, def __init__(
external_references=None, object_marking_refs=None, self, created_by_ref=None, created=None,
list_append=True): external_references=None, object_marking_refs=None,
list_append=True,
):
self._defaults = {} self._defaults = {}
if created_by_ref: if created_by_ref:

View File

@ -30,8 +30,10 @@ class MissingPropertiesError(STIXError, ValueError):
def __str__(self): def __str__(self):
msg = "No values for required properties for {0}: ({1})." msg = "No values for required properties for {0}: ({1})."
return msg.format(self.cls.__name__, return msg.format(
", ".join(x for x in self.properties)) self.cls.__name__,
", ".join(x for x in self.properties),
)
class ExtraPropertiesError(STIXError, TypeError): class ExtraPropertiesError(STIXError, TypeError):
@ -44,8 +46,10 @@ class ExtraPropertiesError(STIXError, TypeError):
def __str__(self): def __str__(self):
msg = "Unexpected properties for {0}: ({1})." msg = "Unexpected properties for {0}: ({1})."
return msg.format(self.cls.__name__, return msg.format(
", ".join(x for x in self.properties)) self.cls.__name__,
", ".join(x for x in self.properties),
)
class ImmutableError(STIXError, ValueError): class ImmutableError(STIXError, ValueError):
@ -110,8 +114,10 @@ class MutuallyExclusivePropertiesError(STIXError, TypeError):
def __str__(self): def __str__(self):
msg = "The ({1}) properties for {0} are mutually exclusive." msg = "The ({1}) properties for {0} are mutually exclusive."
return msg.format(self.cls.__name__, return msg.format(
", ".join(x for x in self.properties)) self.cls.__name__,
", ".join(x for x in self.properties),
)
class DependentPropertiesError(STIXError, TypeError): class DependentPropertiesError(STIXError, TypeError):
@ -124,8 +130,10 @@ class DependentPropertiesError(STIXError, TypeError):
def __str__(self): def __str__(self):
msg = "The property dependencies for {0}: ({1}) are not met." msg = "The property dependencies for {0}: ({1}) are not met."
return msg.format(self.cls.__name__, return msg.format(
", ".join(name for x in self.dependencies for name in x)) self.cls.__name__,
", ".join(name for x in self.dependencies for name in x),
)
class AtLeastOnePropertyError(STIXError, TypeError): class AtLeastOnePropertyError(STIXError, TypeError):
@ -138,8 +146,10 @@ class AtLeastOnePropertyError(STIXError, TypeError):
def __str__(self): def __str__(self):
msg = "At least one of the ({1}) properties for {0} 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(
", ".join(x for x in self.properties)) self.cls.__name__,
", ".join(x for x in self.properties),
)
class RevokeError(STIXError, ValueError): class RevokeError(STIXError, ValueError):

View File

@ -51,7 +51,7 @@ def get_markings(obj, selectors=None, inherited=False, descendants=False):
obj, obj,
selectors, selectors,
inherited, inherited,
descendants descendants,
) )
if inherited: if inherited:
@ -208,7 +208,7 @@ def is_marked(obj, marking=None, selectors=None, inherited=False, descendants=Fa
marking, marking,
selectors, selectors,
inherited, inherited,
descendants descendants,
) )
if inherited: if inherited:
@ -221,7 +221,7 @@ def is_marked(obj, marking=None, selectors=None, inherited=False, descendants=Fa
granular_marks, granular_marks,
selectors, selectors,
inherited, inherited,
descendants descendants,
) )
result = result or object_markings.is_marked(obj, object_marks) result = result or object_markings.is_marked(obj, object_marks)

View File

@ -39,9 +39,11 @@ def get_markings(obj, selectors, inherited=False, descendants=False):
for marking in granular_markings: for marking in granular_markings:
for user_selector in selectors: for user_selector in selectors:
for marking_selector in marking.get('selectors', []): for marking_selector in marking.get('selectors', []):
if any([(user_selector == marking_selector), # Catch explicit selectors. if any([
(user_selector.startswith(marking_selector) and inherited), # Catch inherited selectors. (user_selector == marking_selector), # Catch explicit selectors.
(marking_selector.startswith(user_selector) and descendants)]): # Catch descendants selectors (user_selector.startswith(marking_selector) and inherited), # Catch inherited selectors.
(marking_selector.startswith(user_selector) and descendants),
]): # Catch descendants selectors
refs = marking.get('marking_ref', []) refs = marking.get('marking_ref', [])
results.update([refs]) results.update([refs])
@ -184,16 +186,17 @@ def clear_markings(obj, selectors):
granular_markings = utils.expand_markings(granular_markings) granular_markings = utils.expand_markings(granular_markings)
sdo = utils.build_granular_marking( sdo = utils.build_granular_marking(
[{'selectors': selectors, 'marking_ref': 'N/A'}] [{'selectors': selectors, 'marking_ref': 'N/A'}],
) )
clear = sdo.get('granular_markings', []) clear = sdo.get('granular_markings', [])
if not any(clear_selector in sdo_selectors.get('selectors', []) if not any(
for sdo_selectors in granular_markings clear_selector in sdo_selectors.get('selectors', [])
for clear_marking in clear for sdo_selectors in granular_markings
for clear_selector in clear_marking.get('selectors', []) for clear_marking in clear
): for clear_selector in clear_marking.get('selectors', [])
):
raise exceptions.MarkingNotFoundError(obj, clear) raise exceptions.MarkingNotFoundError(obj, clear)
for granular_marking in granular_markings: for granular_marking in granular_markings:
@ -254,9 +257,11 @@ def is_marked(obj, marking=None, selectors=None, inherited=False, descendants=Fa
for user_selector in selectors: for user_selector in selectors:
for marking_selector in granular_marking.get('selectors', []): for marking_selector in granular_marking.get('selectors', []):
if any([(user_selector == marking_selector), # Catch explicit selectors. if any([
(user_selector.startswith(marking_selector) and inherited), # Catch inherited selectors. (user_selector == marking_selector), # Catch explicit selectors.
(marking_selector.startswith(user_selector) and descendants)]): # Catch descendants selectors (user_selector.startswith(marking_selector) and inherited), # Catch inherited selectors.
(marking_selector.startswith(user_selector) and descendants),
]): # Catch descendants selectors
marking_ref = granular_marking.get('marking_ref', '') marking_ref = granular_marking.get('marking_ref', '')
if marking and any(x == marking_ref for x in marking): if marking and any(x == marking_ref for x in marking):

View File

@ -180,7 +180,7 @@ def expand_markings(granular_markings):
[ [
{'marking_ref': marking_ref, 'selectors': [selector]} {'marking_ref': marking_ref, 'selectors': [selector]}
for selector in selectors for selector in selectors
] ],
) )
return expanded return expanded

View File

@ -211,9 +211,11 @@ class ReferenceObjectPathComponent(_ObjectPathComponent):
class ObjectPath(object): class ObjectPath(object):
def __init__(self, object_type_name, property_path): def __init__(self, object_type_name, property_path):
self.object_type_name = object_type_name self.object_type_name = object_type_name
self.property_path = [x if isinstance(x, _ObjectPathComponent) else self.property_path = [
_ObjectPathComponent.create_ObjectPathComponent(x) x if isinstance(x, _ObjectPathComponent) else
for x in property_path] _ObjectPathComponent.create_ObjectPathComponent(x)
for x in property_path
]
def __str__(self): def __str__(self):
return "%s:%s" % (self.object_type_name, ".".join(["%s" % x for x in self.property_path])) return "%s:%s" % (self.object_type_name, ".".join(["%s" % x for x in self.property_path]))

View File

@ -20,12 +20,14 @@ from .utils import _get_dict, get_class_hierarchy_names, parse_into_datetime
# 8-4-4-4-12 hexadecimal representation, the first hex digit of the third # 8-4-4-4-12 hexadecimal representation, the first hex digit of the third
# component must be a 4, and the first hex digit of the fourth component # component must be a 4, and the first hex digit of the fourth component
# must be 8, 9, a, or b (10xx bit pattern). # must be 8, 9, a, or b (10xx bit pattern).
ID_REGEX = re.compile("^[a-z0-9][a-z0-9-]+[a-z0-9]--" # object type ID_REGEX = re.compile(
"[0-9a-fA-F]{8}-" "^[a-z0-9][a-z0-9-]+[a-z0-9]--" # object type
"[0-9a-fA-F]{4}-" "[0-9a-fA-F]{8}-"
"4[0-9a-fA-F]{3}-" "[0-9a-fA-F]{4}-"
"[89abAB][0-9a-fA-F]{3}-" "4[0-9a-fA-F]{3}-"
"[0-9a-fA-F]{12}$") "[89abAB][0-9a-fA-F]{3}-"
"[0-9a-fA-F]{12}$",
)
ERROR_INVALID_ID = ( ERROR_INVALID_ID = (
"not a valid STIX identifier, must match <object-type>--<UUIDv4>" "not a valid STIX identifier, must match <object-type>--<UUIDv4>"
@ -271,9 +273,11 @@ class DictionaryProperty(Property):
if len(k) > 250: if len(k) > 250:
raise DictionaryKeyError(k, "longer than 250 characters") raise DictionaryKeyError(k, "longer than 250 characters")
if not re.match('^[a-zA-Z0-9_-]+$', k): if not re.match('^[a-zA-Z0-9_-]+$', k):
msg = ("contains characters other than lowercase a-z, " msg = (
"uppercase A-Z, numerals 0-9, hyphen (-), or " "contains characters other than lowercase a-z, "
"underscore (_)") "uppercase A-Z, numerals 0-9, hyphen (-), or "
"underscore (_)"
)
raise DictionaryKeyError(k, msg) raise DictionaryKeyError(k, msg)
return dictified return dictified
@ -435,10 +439,12 @@ class ObservableProperty(Property):
valid_refs = dict((k, v['type']) for (k, v) in dictified.items()) valid_refs = dict((k, v['type']) for (k, v) in dictified.items())
for key, obj in dictified.items(): for key, obj in dictified.items():
parsed_obj = parse_observable(obj, parsed_obj = parse_observable(
valid_refs, obj,
allow_custom=self.allow_custom, valid_refs,
version=self.spec_version) allow_custom=self.allow_custom,
version=self.spec_version,
)
dictified[key] = parsed_obj dictified[key] = parsed_obj
return dictified return dictified
@ -509,9 +515,11 @@ class STIXObjectProperty(Property):
# (spec_version). So this is a hack, and not technically spec- # (spec_version). So this is a hack, and not technically spec-
# compliant. # compliant.
if 'spec_version' in value and self.spec_version == '2.0': if 'spec_version' in value and self.spec_version == '2.0':
raise ValueError("Spec version 2.0 bundles don't yet support " raise ValueError(
"containing objects of a different spec " "Spec version 2.0 bundles don't yet support "
"version.") "containing objects of a different spec "
"version.",
)
return value return value
try: try:
dictified = _get_dict(value) dictified = _get_dict(value)
@ -523,8 +531,10 @@ class STIXObjectProperty(Property):
raise ValueError("This property may not contain a Bundle object") raise ValueError("This property may not contain a Bundle object")
if 'spec_version' in dictified and self.spec_version == '2.0': if 'spec_version' in dictified and self.spec_version == '2.0':
# See above comment regarding spec_version. # See above comment regarding spec_version.
raise ValueError("Spec version 2.0 bundles don't yet support " raise ValueError(
"containing objects of a different spec version.") "Spec version 2.0 bundles don't yet support "
"containing objects of a different spec version.",
)
parsed_obj = parse(dictified, allow_custom=self.allow_custom) parsed_obj = parse(dictified, allow_custom=self.allow_custom)

View File

@ -4,8 +4,9 @@ import pytest
import stix2 import stix2
from .constants import (FAKE_TIME, INDICATOR_KWARGS, MALWARE_KWARGS, from .constants import (
RELATIONSHIP_KWARGS) FAKE_TIME, INDICATOR_KWARGS, MALWARE_KWARGS, RELATIONSHIP_KWARGS,
)
# Inspired by: http://stackoverflow.com/a/24006251 # Inspired by: http://stackoverflow.com/a/24006251
@ -54,61 +55,61 @@ def stix_objs1():
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000001", "id": "indicator--00000000-0000-4000-8000-000000000001",
"labels": [ "labels": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
ind2 = { ind2 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000001", "id": "indicator--00000000-0000-4000-8000-000000000001",
"labels": [ "labels": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
ind3 = { ind3 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000001", "id": "indicator--00000000-0000-4000-8000-000000000001",
"labels": [ "labels": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.936Z", "modified": "2017-01-27T13:49:53.936Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
ind4 = { ind4 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000002", "id": "indicator--00000000-0000-4000-8000-000000000002",
"labels": [ "labels": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
ind5 = { ind5 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000002", "id": "indicator--00000000-0000-4000-8000-000000000002",
"labels": [ "labels": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
return [ind1, ind2, ind3, ind4, ind5] return [ind1, ind2, ind3, ind4, ind5]
@ -119,37 +120,37 @@ def stix_objs2():
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000001", "id": "indicator--00000000-0000-4000-8000-000000000001",
"labels": [ "labels": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-31T13:49:53.935Z", "modified": "2017-01-31T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
ind7 = { ind7 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000002", "id": "indicator--00000000-0000-4000-8000-000000000002",
"labels": [ "labels": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
ind8 = { ind8 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000002", "id": "indicator--00000000-0000-4000-8000-000000000002",
"labels": [ "labels": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
return [ind6, ind7, ind8] return [ind6, ind7, ind8]

View File

@ -32,7 +32,7 @@ MARKING_IDS = [
RELATIONSHIP_IDS = [ RELATIONSHIP_IDS = [
'relationship--06520621-5352-4e6a-b976-e8fa3d437ffd', 'relationship--06520621-5352-4e6a-b976-e8fa3d437ffd',
'relationship--181c9c09-43e6-45dd-9374-3bec192f05ef', 'relationship--181c9c09-43e6-45dd-9374-3bec192f05ef',
'relationship--a0cbb21c-8daf-4a7f-96aa-7155a4ef8f70' 'relationship--a0cbb21c-8daf-4a7f-96aa-7155a4ef8f70',
] ]
# *_KWARGS contains all required arguments to create an instance of that STIX object # *_KWARGS contains all required arguments to create an instance of that STIX object
@ -77,7 +77,7 @@ INTRUSION_SET_KWARGS = dict(
MALWARE_KWARGS = dict( MALWARE_KWARGS = dict(
labels=['ransomware'], labels=['ransomware'],
name="Cryptolocker" name="Cryptolocker",
) )
MALWARE_MORE_KWARGS = dict( MALWARE_MORE_KWARGS = dict(
@ -87,7 +87,7 @@ MALWARE_MORE_KWARGS = dict(
modified="2016-04-06T20:03:00.000Z", modified="2016-04-06T20:03:00.000Z",
labels=['ransomware'], labels=['ransomware'],
name="Cryptolocker", name="Cryptolocker",
description="A ransomware related to ..." description="A ransomware related to ...",
) )
OBSERVED_DATA_KWARGS = dict( OBSERVED_DATA_KWARGS = dict(
@ -98,8 +98,8 @@ OBSERVED_DATA_KWARGS = dict(
"0": { "0": {
"type": "windows-registry-key", "type": "windows-registry-key",
"key": "HKEY_LOCAL_MACHINE\\System\\Foo\\Bar", "key": "HKEY_LOCAL_MACHINE\\System\\Foo\\Bar",
} },
} },
) )
REPORT_KWARGS = dict( REPORT_KWARGS = dict(

View File

@ -31,7 +31,7 @@ def test_attack_pattern_example():
name="Spear Phishing", name="Spear Phishing",
external_references=[{ external_references=[{
"source_name": "capec", "source_name": "capec",
"external_id": "CAPEC-163" "external_id": "CAPEC-163",
}], }],
description="...", description="...",
) )
@ -39,23 +39,25 @@ def test_attack_pattern_example():
assert str(ap) == EXPECTED assert str(ap) == EXPECTED
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"type": "attack-pattern", {
"id": "attack-pattern--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061", "type": "attack-pattern",
"created": "2016-05-12T08:17:27.000Z", "id": "attack-pattern--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
"modified": "2016-05-12T08:17:27.000Z", "created": "2016-05-12T08:17:27.000Z",
"description": "...", "modified": "2016-05-12T08:17:27.000Z",
"external_references": [ "description": "...",
{ "external_references": [
"external_id": "CAPEC-163", {
"source_name": "capec" "external_id": "CAPEC-163",
} "source_name": "capec",
], },
"name": "Spear Phishing", ],
}, "name": "Spear Phishing",
]) },
],
)
def test_parse_attack_pattern(data): def test_parse_attack_pattern(data):
ap = stix2.parse(data, version="2.0") ap = stix2.parse(data, version="2.0")
@ -76,7 +78,7 @@ def test_attack_pattern_invalid_labels():
created="2016-05-12T08:17:27Z", created="2016-05-12T08:17:27Z",
modified="2016-05-12T08:17:27Z", modified="2016-05-12T08:17:27Z",
name="Spear Phishing", name="Spear Phishing",
labels=1 labels=1,
) )
# TODO: Add other examples # TODO: Add other examples

View File

@ -55,8 +55,8 @@ EXPECTED_BUNDLE_DICT = {
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']", "pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
"valid_from": "2017-01-01T12:34:56Z", "valid_from": "2017-01-01T12:34:56Z",
"labels": [ "labels": [
"malicious-activity" "malicious-activity",
] ],
}, },
{ {
"type": "malware", "type": "malware",
@ -65,8 +65,8 @@ EXPECTED_BUNDLE_DICT = {
"modified": "2017-01-01T12:34:56.000Z", "modified": "2017-01-01T12:34:56.000Z",
"name": "Cryptolocker", "name": "Cryptolocker",
"labels": [ "labels": [
"ransomware" "ransomware",
] ],
}, },
{ {
"type": "relationship", "type": "relationship",
@ -75,9 +75,9 @@ EXPECTED_BUNDLE_DICT = {
"modified": "2017-01-01T12:34:56.000Z", "modified": "2017-01-01T12:34:56.000Z",
"relationship_type": "indicates", "relationship_type": "indicates",
"source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", "source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
"target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e" "target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
} },
] ],
} }

View File

@ -25,24 +25,26 @@ def test_campaign_example():
created="2016-04-06T20:03:00Z", created="2016-04-06T20:03:00Z",
modified="2016-04-06T20:03:00Z", modified="2016-04-06T20:03:00Z",
name="Green Group Attacks Against Finance", name="Green Group Attacks Against Finance",
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.",
) )
assert str(campaign) == EXPECTED assert str(campaign) == EXPECTED
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"type": "campaign", {
"id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", "type": "campaign",
"created": "2016-04-06T20:03:00Z", "id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
"modified": "2016-04-06T20:03:00Z", "created": "2016-04-06T20:03:00Z",
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", "modified": "2016-04-06T20:03:00Z",
"description": "Campaign by Green Group against a series of targets in the financial services sector.", "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
"name": "Green Group Attacks Against Finance", "description": "Campaign by Green Group against a series of targets in the financial services sector.",
}, "name": "Green Group Attacks Against Finance",
]) },
],
)
def test_parse_campaign(data): def test_parse_campaign(data):
cmpn = stix2.parse(data, version="2.0") cmpn = stix2.parse(data, version="2.0")

View File

@ -25,24 +25,26 @@ def test_course_of_action_example():
created="2016-04-06T20:03:48.000Z", created="2016-04-06T20:03:48.000Z",
modified="2016-04-06T20:03:48.000Z", modified="2016-04-06T20:03:48.000Z",
name="Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter", name="Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter",
description="This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ..." description="This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ...",
) )
assert str(coa) == EXPECTED assert str(coa) == EXPECTED
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"created": "2016-04-06T20:03:48.000Z", {
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", "created": "2016-04-06T20:03:48.000Z",
"description": "This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ...", "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
"id": "course-of-action--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", "description": "This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ...",
"modified": "2016-04-06T20:03:48.000Z", "id": "course-of-action--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
"name": "Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter", "modified": "2016-04-06T20:03:48.000Z",
"type": "course-of-action" "name": "Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter",
}, "type": "course-of-action",
]) },
],
)
def test_parse_course_of_action(data): def test_parse_course_of_action(data):
coa = stix2.parse(data, version="2.0") coa = stix2.parse(data, version="2.0")

View File

@ -79,8 +79,9 @@ def test_identity_custom_property_allowed():
assert identity.x_foo == "bar" assert identity.x_foo == "bar"
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
"""{ "data", [
"""{
"type": "identity", "type": "identity",
"id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c",
"created": "2015-12-21T19:59:11Z", "created": "2015-12-21T19:59:11Z",
@ -89,7 +90,8 @@ def test_identity_custom_property_allowed():
"identity_class": "individual", "identity_class": "individual",
"foo": "bar" "foo": "bar"
}""", }""",
]) ],
)
def test_parse_identity_custom_property(data): def test_parse_identity_custom_property(data):
with pytest.raises(stix2.exceptions.ExtraPropertiesError) as excinfo: with pytest.raises(stix2.exceptions.ExtraPropertiesError) as excinfo:
stix2.parse(data, version="2.0") stix2.parse(data, version="2.0")
@ -114,7 +116,7 @@ def test_custom_properties_object_in_bundled_object():
identity_class="individual", identity_class="individual",
custom_properties={ custom_properties={
"x_foo": "bar", "x_foo": "bar",
} },
) )
bundle = stix2.v20.Bundle(obj, allow_custom=True) bundle = stix2.v20.Bundle(obj, allow_custom=True)
@ -160,7 +162,7 @@ def test_custom_property_in_observed_data():
artifact = stix2.v20.File( artifact = stix2.v20.File(
allow_custom=True, allow_custom=True,
name='test', name='test',
x_foo='bar' x_foo='bar',
) )
observed_data = stix2.v20.ObservedData( observed_data = stix2.v20.ObservedData(
allow_custom=True, allow_custom=True,
@ -204,7 +206,7 @@ def test_custom_property_dict_in_observable_extension():
'ntfs-ext': { 'ntfs-ext': {
'sid': 1, 'sid': 1,
'x_foo': 'bar', 'x_foo': 'bar',
} },
}, },
) )
@ -216,7 +218,7 @@ def test_custom_property_dict_in_observable_extension():
'allow_custom': True, 'allow_custom': True,
'sid': 1, 'sid': 1,
'x_foo': 'bar', 'x_foo': 'bar',
} },
}, },
) )
observed_data = stix2.v20.ObservedData( observed_data = stix2.v20.ObservedData(
@ -240,12 +242,12 @@ def test_identity_custom_property_edit_markings():
marking_obj = stix2.v20.MarkingDefinition( marking_obj = stix2.v20.MarkingDefinition(
id=MARKING_DEFINITION_ID, id=MARKING_DEFINITION_ID,
definition_type="statement", definition_type="statement",
definition=stix2.v20.StatementMarking(statement="Copyright 2016, Example Corp") definition=stix2.v20.StatementMarking(statement="Copyright 2016, Example Corp"),
) )
marking_obj2 = stix2.v20.MarkingDefinition( marking_obj2 = stix2.v20.MarkingDefinition(
id=MARKING_DEFINITION_ID, id=MARKING_DEFINITION_ID,
definition_type="statement", definition_type="statement",
definition=stix2.v20.StatementMarking(statement="Another one") definition=stix2.v20.StatementMarking(statement="Another one"),
) )
# None of the following should throw exceptions # None of the following should throw exceptions
@ -258,9 +260,11 @@ def test_identity_custom_property_edit_markings():
def test_custom_marking_no_init_1(): def test_custom_marking_no_init_1():
@stix2.v20.CustomMarking('x-new-obj', [ @stix2.v20.CustomMarking(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-obj', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class NewObj(): class NewObj():
pass pass
@ -269,9 +273,11 @@ def test_custom_marking_no_init_1():
def test_custom_marking_no_init_2(): def test_custom_marking_no_init_2():
@stix2.v20.CustomMarking('x-new-obj2', [ @stix2.v20.CustomMarking(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-obj2', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class NewObj2(object): class NewObj2(object):
pass pass
@ -279,10 +285,12 @@ def test_custom_marking_no_init_2():
assert no2.property1 == 'something' assert no2.property1 == 'something'
@stix2.v20.CustomObject('x-new-type', [ @stix2.v20.CustomObject(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-type', [
('property2', stix2.properties.IntegerProperty()), ('property1', stix2.properties.StringProperty(required=True)),
]) ('property2', stix2.properties.IntegerProperty()),
],
)
class NewType(object): class NewType(object):
def __init__(self, property2=None, **kwargs): def __init__(self, property2=None, **kwargs):
if property2 and property2 < 10: if property2 and property2 < 10:
@ -312,9 +320,11 @@ def test_custom_object_type():
def test_custom_object_no_init_1(): def test_custom_object_no_init_1():
@stix2.v20.CustomObject('x-new-obj', [ @stix2.v20.CustomObject(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-obj', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class NewObj(): class NewObj():
pass pass
@ -323,9 +333,11 @@ def test_custom_object_no_init_1():
def test_custom_object_no_init_2(): def test_custom_object_no_init_2():
@stix2.v20.CustomObject('x-new-obj2', [ @stix2.v20.CustomObject(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-obj2', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class NewObj2(object): class NewObj2(object):
pass pass
@ -335,17 +347,21 @@ def test_custom_object_no_init_2():
def test_custom_object_invalid_type_name(): def test_custom_object_invalid_type_name():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v20.CustomObject('x', [ @stix2.v20.CustomObject(
('property1', stix2.properties.StringProperty(required=True)), 'x', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class NewObj(object): class NewObj(object):
pass # pragma: no cover pass # pragma: no cover
assert "Invalid type name 'x': " in str(excinfo.value) assert "Invalid type name 'x': " in str(excinfo.value)
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v20.CustomObject('x_new_object', [ @stix2.v20.CustomObject(
('property1', stix2.properties.StringProperty(required=True)), 'x_new_object', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class NewObj2(object): class NewObj2(object):
pass # pragma: no cover pass # pragma: no cover
assert "Invalid type name 'x_new_object':" in str(excinfo.value) assert "Invalid type name 'x_new_object':" in str(excinfo.value)
@ -389,11 +405,13 @@ def test_parse_unregistered_custom_object_type_w_allow_custom():
assert custom_obj["type"] == "x-foobar-observable" assert custom_obj["type"] == "x-foobar-observable"
@stix2.v20.CustomObservable('x-new-observable', [ @stix2.v20.CustomObservable(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-observable', [
('property2', stix2.properties.IntegerProperty()), ('property1', stix2.properties.StringProperty(required=True)),
('x_property3', stix2.properties.BooleanProperty()), ('property2', stix2.properties.IntegerProperty()),
]) ('x_property3', stix2.properties.BooleanProperty()),
],
)
class NewObservable(): class NewObservable():
def __init__(self, property2=None, **kwargs): def __init__(self, property2=None, **kwargs):
if property2 and property2 < 10: if property2 and property2 < 10:
@ -428,9 +446,11 @@ def test_custom_observable_raises_exception():
def test_custom_observable_object_no_init_1(): def test_custom_observable_object_no_init_1():
@stix2.v20.CustomObservable('x-new-observable', [ @stix2.v20.CustomObservable(
('property1', stix2.properties.StringProperty()), 'x-new-observable', [
]) ('property1', stix2.properties.StringProperty()),
],
)
class NewObs(): class NewObs():
pass pass
@ -439,9 +459,11 @@ def test_custom_observable_object_no_init_1():
def test_custom_observable_object_no_init_2(): def test_custom_observable_object_no_init_2():
@stix2.v20.CustomObservable('x-new-obs2', [ @stix2.v20.CustomObservable(
('property1', stix2.properties.StringProperty()), 'x-new-obs2', [
]) ('property1', stix2.properties.StringProperty()),
],
)
class NewObs2(object): class NewObs2(object):
pass pass
@ -451,17 +473,21 @@ def test_custom_observable_object_no_init_2():
def test_custom_observable_object_invalid_type_name(): def test_custom_observable_object_invalid_type_name():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v20.CustomObservable('x', [ @stix2.v20.CustomObservable(
('property1', stix2.properties.StringProperty()), 'x', [
]) ('property1', stix2.properties.StringProperty()),
],
)
class NewObs(object): class NewObs(object):
pass # pragma: no cover pass # pragma: no cover
assert "Invalid observable type name 'x':" in str(excinfo.value) assert "Invalid observable type name 'x':" in str(excinfo.value)
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v20.CustomObservable('x_new_obs', [ @stix2.v20.CustomObservable(
('property1', stix2.properties.StringProperty()), 'x_new_obs', [
]) ('property1', stix2.properties.StringProperty()),
],
)
class NewObs2(object): class NewObs2(object):
pass # pragma: no cover pass # pragma: no cover
assert "Invalid observable type name 'x_new_obs':" in str(excinfo.value) assert "Invalid observable type name 'x_new_obs':" in str(excinfo.value)
@ -469,9 +495,11 @@ def test_custom_observable_object_invalid_type_name():
def test_custom_observable_object_invalid_ref_property(): def test_custom_observable_object_invalid_ref_property():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v20.CustomObservable('x-new-obs', [ @stix2.v20.CustomObservable(
('property_ref', stix2.properties.StringProperty()), 'x-new-obs', [
]) ('property_ref', stix2.properties.StringProperty()),
],
)
class NewObs(): class NewObs():
pass pass
assert "is named like an object reference property but is not an ObjectReferenceProperty" in str(excinfo.value) assert "is named like an object reference property but is not an ObjectReferenceProperty" in str(excinfo.value)
@ -479,9 +507,11 @@ def test_custom_observable_object_invalid_ref_property():
def test_custom_observable_object_invalid_refs_property(): def test_custom_observable_object_invalid_refs_property():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v20.CustomObservable('x-new-obs', [ @stix2.v20.CustomObservable(
('property_refs', stix2.properties.StringProperty()), 'x-new-obs', [
]) ('property_refs', stix2.properties.StringProperty()),
],
)
class NewObs(): class NewObs():
pass pass
assert "is named like an object reference list property but is not a ListProperty containing ObjectReferenceProperty" in str(excinfo.value) assert "is named like an object reference list property but is not a ListProperty containing ObjectReferenceProperty" in str(excinfo.value)
@ -489,26 +519,32 @@ def test_custom_observable_object_invalid_refs_property():
def test_custom_observable_object_invalid_refs_list_property(): def test_custom_observable_object_invalid_refs_list_property():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v20.CustomObservable('x-new-obs', [ @stix2.v20.CustomObservable(
('property_refs', stix2.properties.ListProperty(stix2.properties.StringProperty)), 'x-new-obs', [
]) ('property_refs', stix2.properties.ListProperty(stix2.properties.StringProperty)),
],
)
class NewObs(): class NewObs():
pass pass
assert "is named like an object reference list property but is not a ListProperty containing ObjectReferenceProperty" in str(excinfo.value) assert "is named like an object reference list property but is not a ListProperty containing ObjectReferenceProperty" in str(excinfo.value)
def test_custom_observable_object_invalid_valid_refs(): def test_custom_observable_object_invalid_valid_refs():
@stix2.v20.CustomObservable('x-new-obs', [ @stix2.v20.CustomObservable(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-obs', [
('property_ref', stix2.properties.ObjectReferenceProperty(valid_types='email-addr')), ('property1', stix2.properties.StringProperty(required=True)),
]) ('property_ref', stix2.properties.ObjectReferenceProperty(valid_types='email-addr')),
],
)
class NewObs(): class NewObs():
pass pass
with pytest.raises(Exception) as excinfo: with pytest.raises(Exception) as excinfo:
NewObs(_valid_refs=['1'], NewObs(
property1='something', _valid_refs=['1'],
property_ref='1') property1='something',
property_ref='1',
)
assert "must be created with _valid_refs as a dict, not a list" in str(excinfo.value) assert "must be created with _valid_refs as a dict, not a list" in str(excinfo.value)
@ -644,10 +680,12 @@ def test_observed_data_with_custom_observable_object():
assert ob_data.objects['0'].property1 == 'something' assert ob_data.objects['0'].property1 == 'something'
@stix2.v20.CustomExtension(stix2.v20.DomainName, 'x-new-ext', [ @stix2.v20.CustomExtension(
('property1', stix2.properties.StringProperty(required=True)), stix2.v20.DomainName, 'x-new-ext', [
('property2', stix2.properties.IntegerProperty()), ('property1', stix2.properties.StringProperty(required=True)),
]) ('property2', stix2.properties.IntegerProperty()),
],
)
class NewExtension(): class NewExtension():
def __init__(self, property2=None, **kwargs): def __init__(self, property2=None, **kwargs):
if property2 and property2 < 10: if property2 and property2 < 10:
@ -685,13 +723,15 @@ def test_custom_extension_wrong_observable_type():
name="abc.txt", name="abc.txt",
extensions={ extensions={
"ntfs-ext": ext, "ntfs-ext": ext,
}) },
)
assert 'Cannot determine extension type' in excinfo.value.reason assert 'Cannot determine extension type' in excinfo.value.reason
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
"""{ "data", [
"""{
"keys": [ "keys": [
{ {
"test123": 123, "test123": 123,
@ -699,11 +739,14 @@ def test_custom_extension_wrong_observable_type():
} }
] ]
}""", }""",
]) ],
)
def test_custom_extension_with_list_and_dict_properties_observable_type(data): def test_custom_extension_with_list_and_dict_properties_observable_type(data):
@stix2.v20.CustomExtension(stix2.v20.UserAccount, 'some-extension', [ @stix2.v20.CustomExtension(
('keys', stix2.properties.ListProperty(stix2.properties.DictionaryProperty, required=True)) stix2.v20.UserAccount, 'some-extension', [
]) ('keys', stix2.properties.ListProperty(stix2.properties.DictionaryProperty, required=True)),
],
)
class SomeCustomExtension: class SomeCustomExtension:
pass pass
@ -717,9 +760,11 @@ def test_custom_extension_invalid_observable():
class Foo(object): class Foo(object):
pass pass
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v20.CustomExtension(Foo, 'x-new-ext', [ @stix2.v20.CustomExtension(
('property1', stix2.properties.StringProperty(required=True)), Foo, 'x-new-ext', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class FooExtension(): class FooExtension():
pass # pragma: no cover pass # pragma: no cover
assert str(excinfo.value) == "'observable' must be a valid Observable class!" assert str(excinfo.value) == "'observable' must be a valid Observable class!"
@ -727,9 +772,11 @@ def test_custom_extension_invalid_observable():
class Bar(stix2.v20.observables._Observable): class Bar(stix2.v20.observables._Observable):
pass pass
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v20.CustomExtension(Bar, 'x-new-ext', [ @stix2.v20.CustomExtension(
('property1', stix2.properties.StringProperty(required=True)), Bar, 'x-new-ext', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class BarExtension(): class BarExtension():
pass pass
assert "Unknown observable type" in str(excinfo.value) assert "Unknown observable type" in str(excinfo.value)
@ -738,9 +785,11 @@ def test_custom_extension_invalid_observable():
class Baz(stix2.v20.observables._Observable): class Baz(stix2.v20.observables._Observable):
_type = 'Baz' _type = 'Baz'
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v20.CustomExtension(Baz, 'x-new-ext', [ @stix2.v20.CustomExtension(
('property1', stix2.properties.StringProperty(required=True)), Baz, 'x-new-ext', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class BazExtension(): class BazExtension():
pass pass
assert "Unknown observable type" in str(excinfo.value) assert "Unknown observable type" in str(excinfo.value)
@ -749,17 +798,21 @@ def test_custom_extension_invalid_observable():
def test_custom_extension_invalid_type_name(): def test_custom_extension_invalid_type_name():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v20.CustomExtension(stix2.v20.File, 'x', { @stix2.v20.CustomExtension(
'property1': stix2.properties.StringProperty(required=True), stix2.v20.File, 'x', {
}) 'property1': stix2.properties.StringProperty(required=True),
},
)
class FooExtension(): class FooExtension():
pass # pragma: no cover pass # pragma: no cover
assert "Invalid extension type name 'x':" in str(excinfo.value) assert "Invalid extension type name 'x':" in str(excinfo.value)
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v20.CustomExtension(stix2.File, 'x_new_ext', { @stix2.v20.CustomExtension(
'property1': stix2.properties.StringProperty(required=True), stix2.File, 'x_new_ext', {
}) 'property1': stix2.properties.StringProperty(required=True),
},
)
class BlaExtension(): class BlaExtension():
pass # pragma: no cover pass # pragma: no cover
assert "Invalid extension type name 'x_new_ext':" in str(excinfo.value) assert "Invalid extension type name 'x_new_ext':" in str(excinfo.value)
@ -790,9 +843,11 @@ def test_custom_extension_dict_properties():
def test_custom_extension_no_init_1(): def test_custom_extension_no_init_1():
@stix2.v20.CustomExtension(stix2.v20.DomainName, 'x-new-extension', [ @stix2.v20.CustomExtension(
('property1', stix2.properties.StringProperty(required=True)), stix2.v20.DomainName, 'x-new-extension', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class NewExt(): class NewExt():
pass pass
@ -801,9 +856,11 @@ def test_custom_extension_no_init_1():
def test_custom_extension_no_init_2(): def test_custom_extension_no_init_2():
@stix2.v20.CustomExtension(stix2.v20.DomainName, 'x-new-ext2', [ @stix2.v20.CustomExtension(
('property1', stix2.properties.StringProperty(required=True)), stix2.v20.DomainName, 'x-new-ext2', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class NewExt2(object): class NewExt2(object):
pass pass
@ -863,8 +920,9 @@ def test_extension_property_location():
assert 'extensions' not in stix2.v20.EXT_MAP['domain-name']['x-new-ext']._properties assert 'extensions' not in stix2.v20.EXT_MAP['domain-name']['x-new-ext']._properties
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
"""{ "data", [
"""{
"type": "x-example", "type": "x-example",
"id": "x-example--336d8a9f-91f1-46c5-b142-6441bb9f8b8d", "id": "x-example--336d8a9f-91f1-46c5-b142-6441bb9f8b8d",
"created": "2018-06-12T16:20:58.059Z", "created": "2018-06-12T16:20:58.059Z",
@ -876,18 +934,23 @@ def test_extension_property_location():
} }
} }
}""", }""",
]) ],
)
def test_custom_object_nested_dictionary(data): def test_custom_object_nested_dictionary(data):
@stix2.v20.CustomObject('x-example', [ @stix2.v20.CustomObject(
('dictionary', stix2.properties.DictionaryProperty()), 'x-example', [
]) ('dictionary', stix2.properties.DictionaryProperty()),
],
)
class Example(object): class Example(object):
def __init__(self, **kwargs): def __init__(self, **kwargs):
pass pass
example = Example(id='x-example--336d8a9f-91f1-46c5-b142-6441bb9f8b8d', example = Example(
created='2018-06-12T16:20:58.059Z', id='x-example--336d8a9f-91f1-46c5-b142-6441bb9f8b8d',
modified='2018-06-12T16:20:58.059Z', created='2018-06-12T16:20:58.059Z',
dictionary={'key': {'key_b': 'value', 'key_a': 'value'}}) modified='2018-06-12T16:20:58.059Z',
dictionary={'key': {'key_b': 'value', 'key_a': 'value'}},
)
assert data == str(example) assert data == str(example)

View File

@ -1,7 +1,8 @@
import pytest import pytest
from stix2.datastore import (CompositeDataSource, DataSink, DataSource, from stix2.datastore import (
DataStoreMixin) CompositeDataSource, DataSink, DataSource, DataStoreMixin,
)
from stix2.datastore.filters import Filter from stix2.datastore.filters import Filter
from stix2.test.v20.constants import CAMPAIGN_MORE_KWARGS from stix2.test.v20.constants import CAMPAIGN_MORE_KWARGS
@ -46,15 +47,19 @@ def test_datastore_creator_of_raises():
def test_datastore_relationships_raises(): def test_datastore_relationships_raises():
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
DataStoreMixin().relationships(obj="indicator--00000000-0000-4000-8000-000000000001", DataStoreMixin().relationships(
target_only=True) obj="indicator--00000000-0000-4000-8000-000000000001",
target_only=True,
)
assert "DataStoreMixin has no data source to query" == str(excinfo.value) assert "DataStoreMixin has no data source to query" == str(excinfo.value)
def test_datastore_related_to_raises(): def test_datastore_related_to_raises():
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
DataStoreMixin().related_to(obj="indicator--00000000-0000-4000-8000-000000000001", DataStoreMixin().related_to(
target_only=True) obj="indicator--00000000-0000-4000-8000-000000000001",
target_only=True,
)
assert "DataStoreMixin has no data source to query" == str(excinfo.value) assert "DataStoreMixin has no data source to query" == str(excinfo.value)
@ -84,15 +89,19 @@ def test_composite_datastore_query_raises_error():
def test_composite_datastore_relationships_raises_error(): def test_composite_datastore_relationships_raises_error():
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
CompositeDataSource().relationships(obj="indicator--00000000-0000-4000-8000-000000000001", CompositeDataSource().relationships(
target_only=True) obj="indicator--00000000-0000-4000-8000-000000000001",
target_only=True,
)
assert "CompositeDataSource has no data sources" == str(excinfo.value) assert "CompositeDataSource has no data sources" == str(excinfo.value)
def test_composite_datastore_related_to_raises_error(): def test_composite_datastore_related_to_raises_error():
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
CompositeDataSource().related_to(obj="indicator--00000000-0000-4000-8000-000000000001", CompositeDataSource().related_to(
target_only=True) obj="indicator--00000000-0000-4000-8000-000000000001",
target_only=True,
)
assert "CompositeDataSource has no data sources" == str(excinfo.value) assert "CompositeDataSource has no data sources" == str(excinfo.value)

View File

@ -13,8 +13,10 @@ def test_add_remove_composite_datasource():
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
cds.add_data_sources([ds1, ds2, ds1, ds3]) cds.add_data_sources([ds1, ds2, ds1, ds3])
assert str(excinfo.value) == ("DataSource (to be added) is not of type " assert str(excinfo.value) == (
"stix2.DataSource. DataSource type is '<class 'stix2.datastore.memory.MemorySink'>'") "DataSource (to be added) is not of type "
"stix2.DataSource. DataSource type is '<class 'stix2.datastore.memory.MemorySink'>'"
)
cds.add_data_sources([ds1, ds2, ds1]) cds.add_data_sources([ds1, ds2, ds1])
@ -26,10 +28,12 @@ def test_add_remove_composite_datasource():
def test_composite_datasource_operations(stix_objs1, stix_objs2): def test_composite_datasource_operations(stix_objs1, stix_objs2):
BUNDLE1 = dict(id="bundle--%s" % make_id(), BUNDLE1 = dict(
objects=stix_objs1, id="bundle--%s" % make_id(),
spec_version="2.0", objects=stix_objs1,
type="bundle") spec_version="2.0",
type="bundle",
)
cds1 = CompositeDataSource() cds1 = CompositeDataSource()
ds1_1 = MemorySource(stix_data=BUNDLE1) ds1_1 = MemorySource(stix_data=BUNDLE1)
ds1_2 = MemorySource(stix_data=stix_objs2) ds1_2 = MemorySource(stix_data=stix_objs2)
@ -55,11 +59,11 @@ def test_composite_datasource_operations(stix_objs1, stix_objs2):
assert indicator["type"] == "indicator" assert indicator["type"] == "indicator"
query1 = [ query1 = [
Filter("type", "=", "indicator") Filter("type", "=", "indicator"),
] ]
query2 = [ query2 = [
Filter("valid_from", "=", "2017-01-27T13:49:53.935382Z") Filter("valid_from", "=", "2017-01-27T13:49:53.935382Z"),
] ]
cds1.filters.add(query2) cds1.filters.add(query2)

View File

@ -5,11 +5,10 @@ import shutil
import pytest import pytest
import stix2 import stix2
from stix2.test.v20.constants import (CAMPAIGN_ID, CAMPAIGN_KWARGS, from stix2.test.v20.constants import (
IDENTITY_ID, IDENTITY_KWARGS, CAMPAIGN_ID, CAMPAIGN_KWARGS, IDENTITY_ID, IDENTITY_KWARGS, INDICATOR_ID,
INDICATOR_ID, INDICATOR_KWARGS, INDICATOR_KWARGS, MALWARE_ID, MALWARE_KWARGS, RELATIONSHIP_IDS,
MALWARE_ID, MALWARE_KWARGS, )
RELATIONSHIP_IDS)
FS_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "stix2_data") FS_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "stix2_data")
@ -68,7 +67,7 @@ def bad_stix_files():
# bad STIX object # bad STIX object
stix_obj = { stix_obj = {
"id": "intrusion-set--test-bad-stix", "id": "intrusion-set--test-bad-stix",
"spec_version": "2.0" "spec_version": "2.0",
# no "type" field # no "type" field
} }
@ -178,7 +177,8 @@ def test_filesystem_sink_add_python_stix_object(fs_sink, fs_source):
camp1 = stix2.v20.Campaign( camp1 = stix2.v20.Campaign(
name="Hannibal", name="Hannibal",
objective="Targeting Italian and Spanish Diplomat internet accounts", objective="Targeting Italian and Spanish Diplomat internet accounts",
aliases=["War Elephant"]) aliases=["War Elephant"],
)
fs_sink.add(camp1) fs_sink.add(camp1)
@ -200,7 +200,7 @@ def test_filesystem_sink_add_stix_object_dict(fs_sink, fs_source):
"objective": "German and French Intelligence Services", "objective": "German and French Intelligence Services",
"aliases": ["Purple Robes"], "aliases": ["Purple Robes"],
"id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", "id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
"created": "2017-05-31T21:31:53.197755Z" "created": "2017-05-31T21:31:53.197755Z",
} }
fs_sink.add(camp2) fs_sink.add(camp2)
@ -228,9 +228,9 @@ def test_filesystem_sink_add_stix_bundle_dict(fs_sink, fs_source):
"objective": "Bulgarian, Albanian and Romanian Intelligence Services", "objective": "Bulgarian, Albanian and Romanian Intelligence Services",
"aliases": ["Huns"], "aliases": ["Huns"],
"id": "campaign--b8f86161-ccae-49de-973a-4ca320c62478", "id": "campaign--b8f86161-ccae-49de-973a-4ca320c62478",
"created": "2017-05-31T21:31:53.197755Z" "created": "2017-05-31T21:31:53.197755Z",
} },
] ],
} }
fs_sink.add(bund) fs_sink.add(bund)
@ -282,7 +282,8 @@ def test_filesystem_sink_add_objects_list(fs_sink, fs_source):
camp6 = stix2.v20.Campaign( camp6 = stix2.v20.Campaign(
name="Comanche", name="Comanche",
objective="US Midwest manufacturing firms, oil refineries, and businesses", objective="US Midwest manufacturing firms, oil refineries, and businesses",
aliases=["Horse Warrior"]) aliases=["Horse Warrior"],
)
camp7 = { camp7 = {
"name": "Napolean", "name": "Napolean",
@ -290,7 +291,7 @@ def test_filesystem_sink_add_objects_list(fs_sink, fs_source):
"objective": "Central and Eastern Europe military commands and departments", "objective": "Central and Eastern Europe military commands and departments",
"aliases": ["The Frenchmen"], "aliases": ["The Frenchmen"],
"id": "campaign--122818b6-1112-4fb0-b11b-b111107ca70a", "id": "campaign--122818b6-1112-4fb0-b11b-b111107ca70a",
"created": "2017-05-31T21:31:53.197755Z" "created": "2017-05-31T21:31:53.197755Z",
} }
fs_sink.add([camp6, camp7]) fs_sink.add([camp6, camp7])
@ -370,7 +371,8 @@ def test_filesystem_store_add(fs_store):
camp1 = stix2.v20.Campaign( camp1 = stix2.v20.Campaign(
name="Great Heathen Army", name="Great Heathen Army",
objective="Targeting the government of United Kingdom and insitutions affiliated with the Church Of England", objective="Targeting the government of United Kingdom and insitutions affiliated with the Church Of England",
aliases=["Ragnar"]) aliases=["Ragnar"],
)
fs_store.add(camp1) fs_store.add(camp1)
camp1_r = fs_store.get(camp1.id) camp1_r = fs_store.get(camp1.id)
@ -387,7 +389,8 @@ def test_filesystem_store_add_as_bundle():
camp1 = stix2.v20.Campaign( camp1 = stix2.v20.Campaign(
name="Great Heathen Army", name="Great Heathen Army",
objective="Targeting the government of United Kingdom and insitutions affiliated with the Church Of England", objective="Targeting the government of United Kingdom and insitutions affiliated with the Church Of England",
aliases=["Ragnar"]) aliases=["Ragnar"],
)
fs_store.add(camp1) fs_store.add(camp1)
with open(os.path.join(FS_PATH, "campaign", camp1.id + ".json")) as bundle_file: with open(os.path.join(FS_PATH, "campaign", camp1.id + ".json")) as bundle_file:
@ -420,7 +423,8 @@ def test_filesystem_object_with_custom_property(fs_store):
name="Scipio Africanus", name="Scipio Africanus",
objective="Defeat the Carthaginians", objective="Defeat the Carthaginians",
x_empire="Roman", x_empire="Roman",
allow_custom=True) allow_custom=True,
)
fs_store.add(camp) fs_store.add(camp)
@ -434,7 +438,8 @@ def test_filesystem_object_with_custom_property_in_bundle(fs_store):
name="Scipio Africanus", name="Scipio Africanus",
objective="Defeat the Carthaginians", objective="Defeat the Carthaginians",
x_empire="Roman", x_empire="Roman",
allow_custom=True) allow_custom=True,
)
bundle = stix2.v20.Bundle(camp, allow_custom=True) bundle = stix2.v20.Bundle(camp, allow_custom=True)
fs_store.add(bundle) fs_store.add(bundle)
@ -445,9 +450,11 @@ def test_filesystem_object_with_custom_property_in_bundle(fs_store):
def test_filesystem_custom_object(fs_store): def test_filesystem_custom_object(fs_store):
@stix2.v20.CustomObject('x-new-obj', [ @stix2.v20.CustomObject(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-obj', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class NewObj(): class NewObj():
pass pass

View File

@ -10,23 +10,23 @@ stix_objs = [
"description": "\n\nTITLE:\n\tPoison Ivy", "description": "\n\nTITLE:\n\tPoison Ivy",
"id": "malware--fdd60b30-b67c-41e3-b0b9-f01faf20d111", "id": "malware--fdd60b30-b67c-41e3-b0b9-f01faf20d111",
"labels": [ "labels": [
"remote-access-trojan" "remote-access-trojan",
], ],
"modified": "2017-01-27T13:49:53.997Z", "modified": "2017-01-27T13:49:53.997Z",
"name": "Poison Ivy", "name": "Poison Ivy",
"type": "malware" "type": "malware",
}, },
{ {
"created": "2014-05-08T09:00:00.000Z", "created": "2014-05-08T09:00:00.000Z",
"id": "indicator--a932fcc6-e032-476c-826f-cb970a5a1ade", "id": "indicator--a932fcc6-e032-476c-826f-cb970a5a1ade",
"labels": [ "labels": [
"file-hash-watchlist" "file-hash-watchlist",
], ],
"modified": "2014-05-08T09:00:00.000Z", "modified": "2014-05-08T09:00:00.000Z",
"name": "File hash for Poison Ivy variant", "name": "File hash for Poison Ivy variant",
"pattern": "[file:hashes.'SHA-256' = 'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c']", "pattern": "[file:hashes.'SHA-256' = 'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c']",
"type": "indicator", "type": "indicator",
"valid_from": "2014-05-08T09:00:00.000000Z" "valid_from": "2014-05-08T09:00:00.000000Z",
}, },
{ {
"created": "2014-05-08T09:00:00.000Z", "created": "2014-05-08T09:00:00.000Z",
@ -34,20 +34,20 @@ stix_objs = [
{ {
"marking_ref": "marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed", "marking_ref": "marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed",
"selectors": [ "selectors": [
"relationship_type" "relationship_type",
] ],
} },
], ],
"id": "relationship--2f9a9aa9-108a-4333-83e2-4fb25add0463", "id": "relationship--2f9a9aa9-108a-4333-83e2-4fb25add0463",
"modified": "2014-05-08T09:00:00.000Z", "modified": "2014-05-08T09:00:00.000Z",
"object_marking_refs": [ "object_marking_refs": [
"marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9" "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
], ],
"relationship_type": "indicates", "relationship_type": "indicates",
"revoked": True, "revoked": True,
"source_ref": "indicator--a932fcc6-e032-476c-826f-cb970a5a1ade", "source_ref": "indicator--a932fcc6-e032-476c-826f-cb970a5a1ade",
"target_ref": "malware--fdd60b30-b67c-41e3-b0b9-f01faf20d111", "target_ref": "malware--fdd60b30-b67c-41e3-b0b9-f01faf20d111",
"type": "relationship" "type": "relationship",
}, },
{ {
"id": "vulnerability--ee916c28-c7a4-4d0d-ad56-a8d357f89fef", "id": "vulnerability--ee916c28-c7a4-4d0d-ad56-a8d357f89fef",
@ -60,10 +60,10 @@ stix_objs = [
"external_references": [ "external_references": [
{ {
"source_name": "cve", "source_name": "cve",
"external_id": "CVE-2014-0160" "external_id": "CVE-2014-0160",
} },
], ],
"labels": ["heartbleed", "has-logo"] "labels": ["heartbleed", "has-logo"],
}, },
{ {
"type": "observed-data", "type": "observed-data",
@ -77,11 +77,11 @@ stix_objs = [
"objects": { "objects": {
"0": { "0": {
"type": "file", "type": "file",
"name": "HAL 9000.exe" "name": "HAL 9000.exe",
} },
} },
} },
] ]
@ -414,8 +414,10 @@ def test_filters4():
# Assert invalid Filter cannot be created # Assert invalid Filter cannot be created
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
Filter("modified", "?", "2017-01-27T13:49:53.935Z") Filter("modified", "?", "2017-01-27T13:49:53.935Z")
assert str(excinfo.value) == ("Filter operator '?' not supported " assert str(excinfo.value) == (
"for specified property: 'modified'") "Filter operator '?' not supported "
"for specified property: 'modified'"
)
def test_filters5(stix_objs2, real_stix_objs2): def test_filters5(stix_objs2, real_stix_objs2):
@ -455,7 +457,7 @@ def test_filters7(stix_objs2, real_stix_objs2):
"0": { "0": {
"type": "file", "type": "file",
"hashes": { "hashes": {
"SHA-256": "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f" "SHA-256": "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f",
}, },
"extensions": { "extensions": {
"pdf-ext": { "pdf-ext": {
@ -465,14 +467,14 @@ def test_filters7(stix_objs2, real_stix_objs2):
"Author": "Adobe Systems Incorporated", "Author": "Adobe Systems Incorporated",
"Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh", "Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh",
"Producer": "Acrobat Distiller 3.01 for Power Macintosh", "Producer": "Acrobat Distiller 3.01 for Power Macintosh",
"CreationDate": "20070412090123-02" "CreationDate": "20070412090123-02",
}, },
"pdfid0": "DFCE52BD827ECF765649852119D", "pdfid0": "DFCE52BD827ECF765649852119D",
"pdfid1": "57A1E0F9ED2AE523E313C" "pdfid1": "57A1E0F9ED2AE523E313C",
} },
} },
} },
} },
} }
stix_objects = list(stix_objs2) + [obsvd_data_obj] stix_objects = list(stix_objs2) + [obsvd_data_obj]

View File

@ -5,108 +5,110 @@ import pytest
from stix2 import Filter, MemorySource, MemoryStore, properties from stix2 import Filter, MemorySource, MemoryStore, properties
from stix2.datastore import make_id from stix2.datastore import make_id
from stix2.v20 import (Bundle, Campaign, CustomObject, Identity, Indicator, from stix2.v20 import (
Malware, Relationship) Bundle, Campaign, CustomObject, Identity, Indicator, Malware, Relationship,
)
from .constants import (CAMPAIGN_ID, CAMPAIGN_KWARGS, IDENTITY_ID, from .constants import (
IDENTITY_KWARGS, INDICATOR_ID, INDICATOR_KWARGS, CAMPAIGN_ID, CAMPAIGN_KWARGS, IDENTITY_ID, IDENTITY_KWARGS, INDICATOR_ID,
MALWARE_ID, MALWARE_KWARGS, RELATIONSHIP_IDS) INDICATOR_KWARGS, MALWARE_ID, MALWARE_KWARGS, RELATIONSHIP_IDS,
)
IND1 = { IND1 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000001", "id": "indicator--00000000-0000-4000-8000-000000000001",
"labels": [ "labels": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
IND2 = { IND2 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000001", "id": "indicator--00000000-0000-4000-8000-000000000001",
"labels": [ "labels": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
IND3 = { IND3 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000001", "id": "indicator--00000000-0000-4000-8000-000000000001",
"labels": [ "labels": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.936Z", "modified": "2017-01-27T13:49:53.936Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
IND4 = { IND4 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000002", "id": "indicator--00000000-0000-4000-8000-000000000002",
"labels": [ "labels": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
IND5 = { IND5 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000002", "id": "indicator--00000000-0000-4000-8000-000000000002",
"labels": [ "labels": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
IND6 = { IND6 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000001", "id": "indicator--00000000-0000-4000-8000-000000000001",
"labels": [ "labels": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-31T13:49:53.935Z", "modified": "2017-01-31T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
IND7 = { IND7 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000002", "id": "indicator--00000000-0000-4000-8000-000000000002",
"labels": [ "labels": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
IND8 = { IND8 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000002", "id": "indicator--00000000-0000-4000-8000-000000000002",
"labels": [ "labels": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
STIX_OBJS2 = [IND6, IND7, IND8] STIX_OBJS2 = [IND6, IND7, IND8]
@ -161,10 +163,12 @@ def test_memory_source_get_nonexistant_object(mem_source):
def test_memory_store_all_versions(mem_store): def test_memory_store_all_versions(mem_store):
# Add bundle of items to sink # Add bundle of items to sink
mem_store.add(dict(id="bundle--%s" % make_id(), mem_store.add(dict(
objects=STIX_OBJS2, id="bundle--%s" % make_id(),
spec_version="2.0", objects=STIX_OBJS2,
type="bundle")) spec_version="2.0",
type="bundle",
))
resp = mem_store.all_versions("indicator--00000000-0000-4000-8000-000000000001") resp = mem_store.all_versions("indicator--00000000-0000-4000-8000-000000000001")
assert len(resp) == 1 # MemoryStore can only store 1 version of each object assert len(resp) == 1 # MemoryStore can only store 1 version of each object
@ -227,10 +231,12 @@ def test_memory_store_add_invalid_object(mem_store):
def test_memory_store_object_with_custom_property(mem_store): def test_memory_store_object_with_custom_property(mem_store):
camp = Campaign(name="Scipio Africanus", camp = Campaign(
objective="Defeat the Carthaginians", name="Scipio Africanus",
x_empire="Roman", objective="Defeat the Carthaginians",
allow_custom=True) x_empire="Roman",
allow_custom=True,
)
mem_store.add(camp) mem_store.add(camp)
@ -240,10 +246,12 @@ def test_memory_store_object_with_custom_property(mem_store):
def test_memory_store_object_with_custom_property_in_bundle(mem_store): def test_memory_store_object_with_custom_property_in_bundle(mem_store):
camp = Campaign(name="Scipio Africanus", camp = Campaign(
objective="Defeat the Carthaginians", name="Scipio Africanus",
x_empire="Roman", objective="Defeat the Carthaginians",
allow_custom=True) x_empire="Roman",
allow_custom=True,
)
bundle = Bundle(camp, allow_custom=True) bundle = Bundle(camp, allow_custom=True)
mem_store.add(bundle) mem_store.add(bundle)
@ -254,9 +262,11 @@ def test_memory_store_object_with_custom_property_in_bundle(mem_store):
def test_memory_store_custom_object(mem_store): def test_memory_store_custom_object(mem_store):
@CustomObject('x-new-obj', [ @CustomObject(
('property1', properties.StringProperty(required=True)), 'x-new-obj', [
]) ('property1', properties.StringProperty(required=True)),
],
)
class NewObj(): class NewObj():
pass pass

View File

@ -36,7 +36,7 @@ class MockTAXIICollectionEndpoint(Collection):
objs = full_filter.process_filter( objs = full_filter.process_filter(
self.objects, self.objects,
("id", "type", "version"), ("id", "type", "version"),
[] [],
) )
if objs: if objs:
return stix2.v20.Bundle(objects=objs) return stix2.v20.Bundle(objects=objs)
@ -56,7 +56,7 @@ class MockTAXIICollectionEndpoint(Collection):
objs = full_filter.process_filter( objs = full_filter.process_filter(
self.objects, self.objects,
("version",), ("version",),
[] [],
) )
if objs: if objs:
return stix2.v20.Bundle(objects=objs) return stix2.v20.Bundle(objects=objs)
@ -68,16 +68,18 @@ class MockTAXIICollectionEndpoint(Collection):
@pytest.fixture @pytest.fixture
def collection(stix_objs1): def collection(stix_objs1):
mock = MockTAXIICollectionEndpoint(COLLECTION_URL, **{ mock = MockTAXIICollectionEndpoint(
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116", COLLECTION_URL, **{
"title": "Writable Collection", "id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
"description": "This collection is a dropbox for submitting indicators", "title": "Writable Collection",
"can_read": True, "description": "This collection is a dropbox for submitting indicators",
"can_write": True, "can_read": True,
"media_types": [ "can_write": True,
"application/vnd.oasis.stix+json; version=2.0" "media_types": [
] "application/vnd.oasis.stix+json; version=2.0",
}) ],
}
)
mock.objects.extend(stix_objs1) mock.objects.extend(stix_objs1)
return mock return mock
@ -85,16 +87,18 @@ def collection(stix_objs1):
@pytest.fixture @pytest.fixture
def collection_no_rw_access(stix_objs1): def collection_no_rw_access(stix_objs1):
mock = MockTAXIICollectionEndpoint(COLLECTION_URL, **{ mock = MockTAXIICollectionEndpoint(
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116", COLLECTION_URL, **{
"title": "Not writeable or readable Collection", "id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
"description": "This collection is a dropbox for submitting indicators", "title": "Not writeable or readable Collection",
"can_read": False, "description": "This collection is a dropbox for submitting indicators",
"can_write": False, "can_read": False,
"media_types": [ "can_write": False,
"application/vnd.oasis.stix+json; version=2.0" "media_types": [
] "application/vnd.oasis.stix+json; version=2.0",
}) ],
}
)
mock.objects.extend(stix_objs1) mock.objects.extend(stix_objs1)
return mock return mock
@ -117,7 +121,8 @@ def test_add_stix2_object(collection):
goals=[ goals=[
"compromising environment NGOs", "compromising environment NGOs",
"water-hole attacks geared towards energy sector", "water-hole attacks geared towards energy sector",
]) ],
)
tc_sink.add(ta) tc_sink.add(ta)
@ -136,7 +141,8 @@ def test_add_stix2_with_custom_object(collection):
"water-hole attacks geared towards energy sector", "water-hole attacks geared towards energy sector",
], ],
foo="bar", foo="bar",
allow_custom=True) allow_custom=True,
)
tc_sink.add(ta) tc_sink.add(ta)
@ -153,7 +159,8 @@ def test_add_list_object(collection, indicator):
goals=[ goals=[
"compromising environment NGOs", "compromising environment NGOs",
"water-hole attacks geared towards energy sector", "water-hole attacks geared towards energy sector",
]) ],
)
tc_sink.add([ta, indicator]) tc_sink.add([ta, indicator])
@ -170,7 +177,8 @@ def test_add_stix2_bundle_object(collection):
goals=[ goals=[
"compromising environment NGOs", "compromising environment NGOs",
"water-hole attacks geared towards energy sector", "water-hole attacks geared towards energy sector",
]) ],
)
tc_sink.add(stix2.v20.Bundle(objects=[ta])) tc_sink.add(stix2.v20.Bundle(objects=[ta]))
@ -210,13 +218,13 @@ def test_add_dict_object(collection):
"name": "Teddy Bear", "name": "Teddy Bear",
"goals": [ "goals": [
"compromising environment NGOs", "compromising environment NGOs",
"water-hole attacks geared towards energy sector" "water-hole attacks geared towards energy sector",
], ],
"sophistication": "innovator", "sophistication": "innovator",
"resource_level": "government", "resource_level": "government",
"labels": [ "labels": [
"nation-state" "nation-state",
] ],
} }
tc_sink.add(ta) tc_sink.add(ta)
@ -237,15 +245,15 @@ def test_add_dict_bundle_object(collection):
"name": "Teddy Bear", "name": "Teddy Bear",
"goals": [ "goals": [
"compromising environment NGOs", "compromising environment NGOs",
"water-hole attacks geared towards energy sector" "water-hole attacks geared towards energy sector",
], ],
"sophistication": "innovator", "sophistication": "innovator",
"resource_level": "government", "resource_level": "government",
"labels": [ "labels": [
"nation-state" "nation-state",
] ],
} },
] ],
} }
tc_sink.add(ta) tc_sink.add(ta)
@ -272,7 +280,7 @@ def test_parse_taxii_filters(collection):
Filter("added_after", "=", "2016-02-01T00:00:01.000Z"), Filter("added_after", "=", "2016-02-01T00:00:01.000Z"),
Filter("id", "=", "taxii stix object ID"), Filter("id", "=", "taxii stix object ID"),
Filter("type", "=", "taxii stix object ID"), Filter("type", "=", "taxii stix object ID"),
Filter("version", "=", "first") Filter("version", "=", "first"),
] ]
ds = stix2.TAXIICollectionSource(collection) ds = stix2.TAXIICollectionSource(collection)

View File

@ -2,9 +2,11 @@ import pytest
import stix2 import stix2
from .constants import (CAMPAIGN_ID, CAMPAIGN_KWARGS, FAKE_TIME, IDENTITY_ID, from .constants import (
IDENTITY_KWARGS, INDICATOR_ID, INDICATOR_KWARGS, CAMPAIGN_ID, CAMPAIGN_KWARGS, FAKE_TIME, IDENTITY_ID, IDENTITY_KWARGS,
MALWARE_ID, MALWARE_KWARGS, RELATIONSHIP_IDS) INDICATOR_ID, INDICATOR_KWARGS, MALWARE_ID, MALWARE_KWARGS,
RELATIONSHIP_IDS,
)
@pytest.fixture @pytest.fixture
@ -50,7 +52,8 @@ def test_object_factory_created():
def test_object_factory_external_reference(): def test_object_factory_external_reference():
ext_ref = stix2.v20.ExternalReference( ext_ref = stix2.v20.ExternalReference(
source_name="ACME Threat Intel", source_name="ACME Threat Intel",
description="Threat report") description="Threat report",
)
factory = stix2.ObjectFactory(external_references=ext_ref) factory = stix2.ObjectFactory(external_references=ext_ref)
ind = factory.create(stix2.v20.Indicator, **INDICATOR_KWARGS) ind = factory.create(stix2.v20.Indicator, **INDICATOR_KWARGS)
assert ind.external_references[0].source_name == "ACME Threat Intel" assert ind.external_references[0].source_name == "ACME Threat Intel"
@ -64,7 +67,8 @@ def test_object_factory_obj_markings():
stmt_marking = stix2.v20.StatementMarking("Copyright 2016, Example Corp") stmt_marking = stix2.v20.StatementMarking("Copyright 2016, Example Corp")
mark_def = stix2.v20.MarkingDefinition( mark_def = stix2.v20.MarkingDefinition(
definition_type="statement", definition_type="statement",
definition=stmt_marking) definition=stmt_marking,
)
factory = stix2.ObjectFactory(object_marking_refs=[mark_def, stix2.v20.TLP_AMBER]) factory = stix2.ObjectFactory(object_marking_refs=[mark_def, stix2.v20.TLP_AMBER])
ind = factory.create(stix2.v20.Indicator, **INDICATOR_KWARGS) ind = factory.create(stix2.v20.Indicator, **INDICATOR_KWARGS)
assert mark_def.id in ind.object_marking_refs assert mark_def.id in ind.object_marking_refs
@ -78,13 +82,16 @@ def test_object_factory_obj_markings():
def test_object_factory_list_append(): def test_object_factory_list_append():
ext_ref = stix2.v20.ExternalReference( ext_ref = stix2.v20.ExternalReference(
source_name="ACME Threat Intel", source_name="ACME Threat Intel",
description="Threat report from ACME") description="Threat report from ACME",
)
ext_ref2 = stix2.v20.ExternalReference( ext_ref2 = stix2.v20.ExternalReference(
source_name="Yet Another Threat Report", source_name="Yet Another Threat Report",
description="Threat report from YATR") description="Threat report from YATR",
)
ext_ref3 = stix2.v20.ExternalReference( ext_ref3 = stix2.v20.ExternalReference(
source_name="Threat Report #3", source_name="Threat Report #3",
description="One more threat report") description="One more threat report",
)
factory = stix2.ObjectFactory(external_references=ext_ref) factory = stix2.ObjectFactory(external_references=ext_ref)
ind = factory.create(stix2.v20.Indicator, external_references=ext_ref2, **INDICATOR_KWARGS) ind = factory.create(stix2.v20.Indicator, external_references=ext_ref2, **INDICATOR_KWARGS)
assert ind.external_references[1].source_name == "Yet Another Threat Report" assert ind.external_references[1].source_name == "Yet Another Threat Report"
@ -96,10 +103,12 @@ def test_object_factory_list_append():
def test_object_factory_list_replace(): def test_object_factory_list_replace():
ext_ref = stix2.v20.ExternalReference( ext_ref = stix2.v20.ExternalReference(
source_name="ACME Threat Intel", source_name="ACME Threat Intel",
description="Threat report from ACME") description="Threat report from ACME",
)
ext_ref2 = stix2.v20.ExternalReference( ext_ref2 = stix2.v20.ExternalReference(
source_name="Yet Another Threat Report", source_name="Yet Another Threat Report",
description="Threat report from YATR") description="Threat report from YATR",
)
factory = stix2.ObjectFactory(external_references=ext_ref, list_append=False) factory = stix2.ObjectFactory(external_references=ext_ref, list_append=False)
ind = factory.create(stix2.v20.Indicator, external_references=ext_ref2, **INDICATOR_KWARGS) ind = factory.create(stix2.v20.Indicator, external_references=ext_ref2, **INDICATOR_KWARGS)
assert len(ind.external_references) == 1 assert len(ind.external_references) == 1
@ -107,8 +116,10 @@ def test_object_factory_list_replace():
def test_environment_functions(): def test_environment_functions():
env = stix2.Environment(stix2.ObjectFactory(created_by_ref=IDENTITY_ID), env = stix2.Environment(
stix2.MemoryStore()) stix2.ObjectFactory(created_by_ref=IDENTITY_ID),
stix2.MemoryStore(),
)
# Create a STIX object # Create a STIX object
ind = env.create(stix2.v20.Indicator, id=INDICATOR_ID, **INDICATOR_KWARGS) ind = env.create(stix2.v20.Indicator, id=INDICATOR_ID, **INDICATOR_KWARGS)
@ -132,8 +143,10 @@ def test_environment_functions():
assert len(resp) == 0 assert len(resp) == 0
# See different results after adding filters to the environment # See different results after adding filters to the environment
env.add_filters([stix2.Filter('type', '=', 'indicator'), env.add_filters([
stix2.Filter('created_by_ref', '=', IDENTITY_ID)]) stix2.Filter('type', '=', 'indicator'),
stix2.Filter('created_by_ref', '=', IDENTITY_ID),
])
env.add_filter(stix2.Filter('labels', '=', 'benign')) # should be 'malicious-activity' env.add_filter(stix2.Filter('labels', '=', 'benign')) # should be 'malicious-activity'
resp = env.get(INDICATOR_ID) resp = env.get(INDICATOR_ID)
assert resp['labels'][0] == 'benign' # should be 'malicious-activity' assert resp['labels'][0] == 'benign' # should be 'malicious-activity'
@ -147,8 +160,10 @@ def test_environment_source_and_sink():
def test_environment_datastore_and_sink(): def test_environment_datastore_and_sink():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
stix2.Environment(factory=stix2.ObjectFactory(), stix2.Environment(
store=stix2.MemoryStore(), sink=stix2.MemorySink) factory=stix2.ObjectFactory(),
store=stix2.MemoryStore(), sink=stix2.MemorySink,
)
assert 'Data store already provided' in str(excinfo.value) assert 'Data store already provided' in str(excinfo.value)
@ -269,7 +284,7 @@ def test_relationships_no_id(ds):
env = stix2.Environment(store=ds) env = stix2.Environment(store=ds)
mal = { mal = {
"type": "malware", "type": "malware",
"name": "some variant" "name": "some variant",
} }
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
env.relationships(mal) env.relationships(mal)
@ -333,7 +348,7 @@ def test_related_to_no_id(ds):
env = stix2.Environment(store=ds) env = stix2.Environment(store=ds)
mal = { mal = {
"type": "malware", "type": "malware",
"name": "some variant" "name": "some variant",
} }
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
env.related_to(mal) env.related_to(mal)

View File

@ -21,7 +21,7 @@ def test_external_reference_veris():
source_name="veris", source_name="veris",
external_id="0001AA7F-C601-424A-B2B8-BE6C9F5164E7", external_id="0001AA7F-C601-424A-B2B8-BE6C9F5164E7",
hashes={ hashes={
"SHA-256": "6db12788c37247f2316052e142f42f4b259d6561751e5f401a1ae2a6df9c674b" "SHA-256": "6db12788c37247f2316052e142f42f4b259d6561751e5f401a1ae2a6df9c674b",
}, },
url="https://github.com/vz-risk/VCDB/blob/master/data/json/0001AA7F-C601-424A-B2B8-BE6C9F5164E7.json", url="https://github.com/vz-risk/VCDB/blob/master/data/json/0001AA7F-C601-424A-B2B8-BE6C9F5164E7.json",
) )

View File

@ -21,11 +21,11 @@ def test_add_marking_mark_one_selector_multiple_refs():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
}, },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
@ -36,44 +36,49 @@ def test_add_marking_mark_one_selector_multiple_refs():
assert m in after["granular_markings"] assert m in after["granular_markings"]
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
( "data", [
Malware(**MALWARE_KWARGS), (
Malware( Malware(**MALWARE_KWARGS),
granular_markings=[ Malware(
{ granular_markings=[
"selectors": ["description", "name"], {
"marking_ref": MARKING_IDS[0] "selectors": ["description", "name"],
}, "marking_ref": MARKING_IDS[0],
], },
**MALWARE_KWARGS), ],
MARKING_IDS[0], **MALWARE_KWARGS
), ),
( MARKING_IDS[0],
MALWARE_KWARGS, ),
dict( (
granular_markings=[ MALWARE_KWARGS,
{ dict(
"selectors": ["description", "name"], granular_markings=[
"marking_ref": MARKING_IDS[0] {
}, "selectors": ["description", "name"],
], "marking_ref": MARKING_IDS[0],
**MALWARE_KWARGS), },
MARKING_IDS[0], ],
), **MALWARE_KWARGS
( ),
Malware(**MALWARE_KWARGS), MARKING_IDS[0],
Malware( ),
granular_markings=[ (
{ Malware(**MALWARE_KWARGS),
"selectors": ["description", "name"], Malware(
"marking_ref": TLP_RED.id, granular_markings=[
}, {
], "selectors": ["description", "name"],
**MALWARE_KWARGS), "marking_ref": TLP_RED.id,
TLP_RED, },
), ],
]) **MALWARE_KWARGS
),
TLP_RED,
),
],
)
def test_add_marking_mark_multiple_selector_one_refs(data): def test_add_marking_mark_multiple_selector_one_refs(data):
before = data[0] before = data[0]
after = data[1] after = data[1]
@ -92,12 +97,12 @@ def test_add_marking_mark_multiple_selector_multiple_refs():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description", "name"], "selectors": ["description", "name"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["description", "name"], "selectors": ["description", "name"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -112,7 +117,7 @@ def test_add_marking_mark_another_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
@ -121,7 +126,7 @@ def test_add_marking_mark_another_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description", "name"], "selectors": ["description", "name"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
@ -137,7 +142,7 @@ def test_add_marking_mark_same_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
@ -146,7 +151,7 @@ def test_add_marking_mark_same_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
@ -157,17 +162,22 @@ def test_add_marking_mark_same_property_same_marking():
assert m in after["granular_markings"] assert m in after["granular_markings"]
@pytest.mark.parametrize("data,marking", [ @pytest.mark.parametrize(
({"description": "test description"}, "data,marking", [
[["title"], ["marking-definition--1", "marking-definition--2"], (
"", ["marking-definition--1", "marking-definition--2"], {"description": "test description"},
[], ["marking-definition--1", "marking-definition--2"], [
[""], ["marking-definition--1", "marking-definition--2"], ["title"], ["marking-definition--1", "marking-definition--2"],
["description"], [""], "", ["marking-definition--1", "marking-definition--2"],
["description"], [], [], ["marking-definition--1", "marking-definition--2"],
["description"], ["marking-definition--1", 456] [""], ["marking-definition--1", "marking-definition--2"],
]) ["description"], [""],
]) ["description"], [],
["description"], ["marking-definition--1", 456],
],
),
],
)
def test_add_marking_bad_selector(data, marking): def test_add_marking_bad_selector(data, marking):
with pytest.raises(AssertionError): with pytest.raises(AssertionError):
markings.add_markings(data, marking[0], marking[1]) markings.add_markings(data, marking[0], marking[1])
@ -181,61 +191,61 @@ GET_MARKINGS_TEST_DATA = {
"list value", "list value",
{ {
"g": "nested", "g": "nested",
"h": 45 "h": 45,
} },
], ],
"x": { "x": {
"y": [ "y": [
"hello", "hello",
88 88,
], ],
"z": { "z": {
"foo1": "bar", "foo1": "bar",
"foo2": 65 "foo2": 65,
} },
}, },
"granular_markings": [ "granular_markings": [
{ {
"marking_ref": "1", "marking_ref": "1",
"selectors": ["a"] "selectors": ["a"],
}, },
{ {
"marking_ref": "2", "marking_ref": "2",
"selectors": ["c"] "selectors": ["c"],
}, },
{ {
"marking_ref": "3", "marking_ref": "3",
"selectors": ["c.[1]"] "selectors": ["c.[1]"],
}, },
{ {
"marking_ref": "4", "marking_ref": "4",
"selectors": ["c.[2]"] "selectors": ["c.[2]"],
}, },
{ {
"marking_ref": "5", "marking_ref": "5",
"selectors": ["c.[2].g"] "selectors": ["c.[2].g"],
}, },
{ {
"marking_ref": "6", "marking_ref": "6",
"selectors": ["x"] "selectors": ["x"],
}, },
{ {
"marking_ref": "7", "marking_ref": "7",
"selectors": ["x.y"] "selectors": ["x.y"],
}, },
{ {
"marking_ref": "8", "marking_ref": "8",
"selectors": ["x.y.[1]"] "selectors": ["x.y.[1]"],
}, },
{ {
"marking_ref": "9", "marking_ref": "9",
"selectors": ["x.z"] "selectors": ["x.z"],
}, },
{ {
"marking_ref": "10", "marking_ref": "10",
"selectors": ["x.z.foo2"] "selectors": ["x.z.foo2"],
}, },
] ],
} }
@ -246,10 +256,12 @@ def test_get_markings_smoke(data):
assert markings.get_markings(data, "a") == ["1"] assert markings.get_markings(data, "a") == ["1"]
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
GET_MARKINGS_TEST_DATA, "data", [
{"b": 1234}, GET_MARKINGS_TEST_DATA,
]) {"b": 1234},
],
)
def test_get_markings_not_marked(data): def test_get_markings_not_marked(data):
"""Test selector that is not marked returns empty list.""" """Test selector that is not marked returns empty list."""
results = markings.get_markings(data, "b") results = markings.get_markings(data, "b")
@ -268,21 +280,23 @@ def test_get_markings_multiple_selectors(data):
assert set(xy_markings).union(xz_markings).issuperset(total) assert set(xy_markings).union(xz_markings).issuperset(total)
@pytest.mark.parametrize("data,selector", [ @pytest.mark.parametrize(
(GET_MARKINGS_TEST_DATA, "foo"), "data,selector", [
(GET_MARKINGS_TEST_DATA, ""), (GET_MARKINGS_TEST_DATA, "foo"),
(GET_MARKINGS_TEST_DATA, []), (GET_MARKINGS_TEST_DATA, ""),
(GET_MARKINGS_TEST_DATA, [""]), (GET_MARKINGS_TEST_DATA, []),
(GET_MARKINGS_TEST_DATA, "x.z.[-2]"), (GET_MARKINGS_TEST_DATA, [""]),
(GET_MARKINGS_TEST_DATA, "c.f"), (GET_MARKINGS_TEST_DATA, "x.z.[-2]"),
(GET_MARKINGS_TEST_DATA, "c.[2].i"), (GET_MARKINGS_TEST_DATA, "c.f"),
(GET_MARKINGS_TEST_DATA, "c.[3]"), (GET_MARKINGS_TEST_DATA, "c.[2].i"),
(GET_MARKINGS_TEST_DATA, "d"), (GET_MARKINGS_TEST_DATA, "c.[3]"),
(GET_MARKINGS_TEST_DATA, "x.[0]"), (GET_MARKINGS_TEST_DATA, "d"),
(GET_MARKINGS_TEST_DATA, "z.y.w"), (GET_MARKINGS_TEST_DATA, "x.[0]"),
(GET_MARKINGS_TEST_DATA, "x.z.[1]"), (GET_MARKINGS_TEST_DATA, "z.y.w"),
(GET_MARKINGS_TEST_DATA, "x.z.foo3") (GET_MARKINGS_TEST_DATA, "x.z.[1]"),
]) (GET_MARKINGS_TEST_DATA, "x.z.foo3"),
],
)
def test_get_markings_bad_selector(data, selector): def test_get_markings_bad_selector(data, selector):
"""Test bad selectors raise exception""" """Test bad selectors raise exception"""
with pytest.raises(AssertionError): with pytest.raises(AssertionError):
@ -363,40 +377,42 @@ def test_get_markings_positional_arguments_combinations(data):
assert set(markings.get_markings(data, "x.z.foo2", False, True)) == set(["10"]) assert set(markings.get_markings(data, "x.z.foo2", False, True)) == set(["10"])
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
( "data", [
Malware( (
granular_markings=[ Malware(
{ granular_markings=[
"selectors": ["description"], {
"marking_ref": MARKING_IDS[0] "selectors": ["description"],
}, "marking_ref": MARKING_IDS[0],
{ },
"selectors": ["description"], {
"marking_ref": MARKING_IDS[1] "selectors": ["description"],
}, "marking_ref": MARKING_IDS[1],
], },
**MALWARE_KWARGS ],
**MALWARE_KWARGS
),
[MARKING_IDS[0], MARKING_IDS[1]],
), ),
[MARKING_IDS[0], MARKING_IDS[1]], (
), dict(
( granular_markings=[
dict( {
granular_markings=[ "selectors": ["description"],
{ "marking_ref": MARKING_IDS[0],
"selectors": ["description"], },
"marking_ref": MARKING_IDS[0] {
}, "selectors": ["description"],
{ "marking_ref": MARKING_IDS[1],
"selectors": ["description"], },
"marking_ref": MARKING_IDS[1] ],
}, **MALWARE_KWARGS
], ),
**MALWARE_KWARGS [MARKING_IDS[0], MARKING_IDS[1]],
), ),
[MARKING_IDS[0], MARKING_IDS[1]], ],
), )
])
def test_remove_marking_remove_one_selector_with_multiple_refs(data): def test_remove_marking_remove_one_selector_with_multiple_refs(data):
before = markings.remove_markings(data[0], data[1], ["description"]) before = markings.remove_markings(data[0], data[1], ["description"])
assert "granular_markings" not in before assert "granular_markings" not in before
@ -407,8 +423,8 @@ def test_remove_marking_remove_multiple_selector_one_ref():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -421,8 +437,8 @@ def test_remove_marking_mark_one_selector_from_multiple_ones():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -430,8 +446,8 @@ def test_remove_marking_mark_one_selector_from_multiple_ones():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -445,12 +461,12 @@ def test_remove_marking_mark_one_selector_markings_from_multiple_ones():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -458,12 +474,12 @@ def test_remove_marking_mark_one_selector_markings_from_multiple_ones():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -477,12 +493,12 @@ def test_remove_marking_mark_mutilple_selector_multiple_refs():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -495,8 +511,8 @@ def test_remove_marking_mark_another_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -504,12 +520,12 @@ def test_remove_marking_mark_another_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["modified"], "selectors": ["modified"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -523,8 +539,8 @@ def test_remove_marking_mark_same_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -553,8 +569,8 @@ def test_remove_marking_not_present():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -567,15 +583,15 @@ IS_MARKED_TEST_DATA = [
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
}, },
{ {
"selectors": ["labels", "description"], "selectors": ["labels", "description"],
"marking_ref": MARKING_IDS[2] "marking_ref": MARKING_IDS[2],
}, },
{ {
"selectors": ["labels", "description"], "selectors": ["labels", "description"],
"marking_ref": MARKING_IDS[3] "marking_ref": MARKING_IDS[3],
}, },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
@ -584,15 +600,15 @@ IS_MARKED_TEST_DATA = [
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
}, },
{ {
"selectors": ["labels", "description"], "selectors": ["labels", "description"],
"marking_ref": MARKING_IDS[2] "marking_ref": MARKING_IDS[2],
}, },
{ {
"selectors": ["labels", "description"], "selectors": ["labels", "description"],
"marking_ref": MARKING_IDS[3] "marking_ref": MARKING_IDS[3],
}, },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
@ -607,21 +623,23 @@ def test_is_marked_smoke(data):
assert markings.is_marked(data, selectors=["modified"]) is False assert markings.is_marked(data, selectors=["modified"]) is False
@pytest.mark.parametrize("data,selector", [ @pytest.mark.parametrize(
(IS_MARKED_TEST_DATA[0], "foo"), "data,selector", [
(IS_MARKED_TEST_DATA[0], ""), (IS_MARKED_TEST_DATA[0], "foo"),
(IS_MARKED_TEST_DATA[0], []), (IS_MARKED_TEST_DATA[0], ""),
(IS_MARKED_TEST_DATA[0], [""]), (IS_MARKED_TEST_DATA[0], []),
(IS_MARKED_TEST_DATA[0], "x.z.[-2]"), (IS_MARKED_TEST_DATA[0], [""]),
(IS_MARKED_TEST_DATA[0], "c.f"), (IS_MARKED_TEST_DATA[0], "x.z.[-2]"),
(IS_MARKED_TEST_DATA[0], "c.[2].i"), (IS_MARKED_TEST_DATA[0], "c.f"),
(IS_MARKED_TEST_DATA[1], "c.[3]"), (IS_MARKED_TEST_DATA[0], "c.[2].i"),
(IS_MARKED_TEST_DATA[1], "d"), (IS_MARKED_TEST_DATA[1], "c.[3]"),
(IS_MARKED_TEST_DATA[1], "x.[0]"), (IS_MARKED_TEST_DATA[1], "d"),
(IS_MARKED_TEST_DATA[1], "z.y.w"), (IS_MARKED_TEST_DATA[1], "x.[0]"),
(IS_MARKED_TEST_DATA[1], "x.z.[1]"), (IS_MARKED_TEST_DATA[1], "z.y.w"),
(IS_MARKED_TEST_DATA[1], "x.z.foo3") (IS_MARKED_TEST_DATA[1], "x.z.[1]"),
]) (IS_MARKED_TEST_DATA[1], "x.z.foo3"),
],
)
def test_is_marked_invalid_selector(data, selector): def test_is_marked_invalid_selector(data, selector):
"""Test invalid selector raises an error.""" """Test invalid selector raises an error."""
with pytest.raises(AssertionError): with pytest.raises(AssertionError):
@ -689,61 +707,61 @@ def test_is_marked_positional_arguments_combinations():
"list value", "list value",
{ {
"g": "nested", "g": "nested",
"h": 45 "h": 45,
} },
], ],
"x": { "x": {
"y": [ "y": [
"hello", "hello",
88 88,
], ],
"z": { "z": {
"foo1": "bar", "foo1": "bar",
"foo2": 65 "foo2": 65,
} },
}, },
"granular_markings": [ "granular_markings": [
{ {
"marking_ref": "1", "marking_ref": "1",
"selectors": ["a"] "selectors": ["a"],
}, },
{ {
"marking_ref": "2", "marking_ref": "2",
"selectors": ["c"] "selectors": ["c"],
}, },
{ {
"marking_ref": "3", "marking_ref": "3",
"selectors": ["c.[1]"] "selectors": ["c.[1]"],
}, },
{ {
"marking_ref": "4", "marking_ref": "4",
"selectors": ["c.[2]"] "selectors": ["c.[2]"],
}, },
{ {
"marking_ref": "5", "marking_ref": "5",
"selectors": ["c.[2].g"] "selectors": ["c.[2].g"],
}, },
{ {
"marking_ref": "6", "marking_ref": "6",
"selectors": ["x"] "selectors": ["x"],
}, },
{ {
"marking_ref": "7", "marking_ref": "7",
"selectors": ["x.y"] "selectors": ["x.y"],
}, },
{ {
"marking_ref": "8", "marking_ref": "8",
"selectors": ["x.y.[1]"] "selectors": ["x.y.[1]"],
}, },
{ {
"marking_ref": "9", "marking_ref": "9",
"selectors": ["x.z"] "selectors": ["x.z"],
}, },
{ {
"marking_ref": "10", "marking_ref": "10",
"selectors": ["x.z.foo2"] "selectors": ["x.z.foo2"],
}, },
] ],
} }
assert markings.is_marked(test_sdo, ["1"], "a", False, False) assert markings.is_marked(test_sdo, ["1"], "a", False, False)
@ -823,8 +841,8 @@ def test_create_sdo_with_invalid_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["foo"], "selectors": ["foo"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -839,12 +857,12 @@ def test_set_marking_mark_one_selector_multiple_refs():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -858,8 +876,8 @@ def test_set_marking_mark_multiple_selector_one_refs():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -867,8 +885,8 @@ def test_set_marking_mark_multiple_selector_one_refs():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -885,12 +903,12 @@ def test_set_marking_mark_multiple_selector_multiple_refs_from_none():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -904,8 +922,8 @@ def test_set_marking_mark_another_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -913,12 +931,12 @@ def test_set_marking_mark_another_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
}, },
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[2] "marking_ref": MARKING_IDS[2],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -928,19 +946,21 @@ def test_set_marking_mark_another_property_same_marking():
assert m in after["granular_markings"] assert m in after["granular_markings"]
@pytest.mark.parametrize("marking", [ @pytest.mark.parametrize(
([MARKING_IDS[4], MARKING_IDS[5]], ["foo"]), "marking", [
([MARKING_IDS[4], MARKING_IDS[5]], ""), ([MARKING_IDS[4], MARKING_IDS[5]], ["foo"]),
([MARKING_IDS[4], MARKING_IDS[5]], []), ([MARKING_IDS[4], MARKING_IDS[5]], ""),
([MARKING_IDS[4], MARKING_IDS[5]], [""]), ([MARKING_IDS[4], MARKING_IDS[5]], []),
]) ([MARKING_IDS[4], MARKING_IDS[5]], [""]),
],
)
def test_set_marking_bad_selector(marking): def test_set_marking_bad_selector(marking):
before = Malware( before = Malware(
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -948,8 +968,8 @@ def test_set_marking_bad_selector(marking):
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -965,8 +985,8 @@ def test_set_marking_mark_same_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -974,8 +994,8 @@ def test_set_marking_mark_same_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -989,15 +1009,15 @@ CLEAR_MARKINGS_TEST_DATA = [
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["modified", "description"], "selectors": ["modified", "description"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
}, },
{ {
"selectors": ["modified", "description", "type"], "selectors": ["modified", "description", "type"],
"marking_ref": MARKING_IDS[2] "marking_ref": MARKING_IDS[2],
}, },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
@ -1006,19 +1026,19 @@ CLEAR_MARKINGS_TEST_DATA = [
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["modified", "description"], "selectors": ["modified", "description"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
}, },
{ {
"selectors": ["modified", "description", "type"], "selectors": ["modified", "description", "type"],
"marking_ref": MARKING_IDS[2] "marking_ref": MARKING_IDS[2],
}, },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) ),
] ]
@ -1050,12 +1070,14 @@ def test_clear_marking_all_selectors(data):
assert "granular_markings" not in data assert "granular_markings" not in data
@pytest.mark.parametrize("data,selector", [ @pytest.mark.parametrize(
(CLEAR_MARKINGS_TEST_DATA[0], "foo"), "data,selector", [
(CLEAR_MARKINGS_TEST_DATA[0], ""), (CLEAR_MARKINGS_TEST_DATA[0], "foo"),
(CLEAR_MARKINGS_TEST_DATA[1], []), (CLEAR_MARKINGS_TEST_DATA[0], ""),
(CLEAR_MARKINGS_TEST_DATA[1], [""]), (CLEAR_MARKINGS_TEST_DATA[1], []),
]) (CLEAR_MARKINGS_TEST_DATA[1], [""]),
],
)
def test_clear_marking_bad_selector(data, selector): def test_clear_marking_bad_selector(data, selector):
"""Test bad selector raises exception.""" """Test bad selector raises exception."""
with pytest.raises(AssertionError): with pytest.raises(AssertionError):

View File

@ -29,17 +29,19 @@ def test_identity_example():
assert str(identity) == EXPECTED assert str(identity) == EXPECTED
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"created": "2015-12-21T19:59:11.000Z", {
"id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2015-12-21T19:59:11.000Z",
"identity_class": "individual", "id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c",
"modified": "2015-12-21T19:59:11.000Z", "identity_class": "individual",
"name": "John Smith", "modified": "2015-12-21T19:59:11.000Z",
"type": "identity" "name": "John Smith",
}, "type": "identity",
]) },
],
)
def test_parse_identity(data): def test_parse_identity(data):
identity = stix2.parse(data, version="2.0") identity = stix2.parse(data, version="2.0")
@ -52,21 +54,23 @@ def test_parse_identity(data):
def test_parse_no_type(): def test_parse_no_type():
with pytest.raises(stix2.exceptions.ParseError): with pytest.raises(stix2.exceptions.ParseError):
stix2.parse(""" stix2.parse(
"""
{ {
"id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c",
"created": "2015-12-21T19:59:11.000Z", "created": "2015-12-21T19:59:11.000Z",
"modified": "2015-12-21T19:59:11.000Z", "modified": "2015-12-21T19:59:11.000Z",
"name": "John Smith", "name": "John Smith",
"identity_class": "individual" "identity_class": "individual"
}""", version="2.0") }""", version="2.0",
)
def test_identity_with_custom(): def test_identity_with_custom():
identity = stix2.v20.Identity( identity = stix2.v20.Identity(
name="John Smith", name="John Smith",
identity_class="individual", identity_class="individual",
custom_properties={'x_foo': 'bar'} custom_properties={'x_foo': 'bar'},
) )
assert identity.x_foo == "bar" assert identity.x_foo == "bar"

View File

@ -148,20 +148,22 @@ def test_created_modified_time_are_identical_by_default():
assert ind.created == ind.modified assert ind.created == ind.modified
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED_INDICATOR, "data", [
{ EXPECTED_INDICATOR,
"type": "indicator", {
"id": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", "type": "indicator",
"created": "2017-01-01T00:00:01Z", "id": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
"modified": "2017-01-01T00:00:01Z", "created": "2017-01-01T00:00:01Z",
"labels": [ "modified": "2017-01-01T00:00:01Z",
"malicious-activity" "labels": [
], "malicious-activity",
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']", ],
"valid_from": "1970-01-01T00:00:01Z" "pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
}, "valid_from": "1970-01-01T00:00:01Z",
]) },
],
)
def test_parse_indicator(data): def test_parse_indicator(data):
idctr = stix2.parse(data, version="2.0") idctr = stix2.parse(data, version="2.0")

View File

@ -35,32 +35,34 @@ def test_intrusion_set_example():
name="Bobcat Breakin", name="Bobcat Breakin",
description="Incidents usually feature a shared TTP of a bobcat being released...", description="Incidents usually feature a shared TTP of a bobcat being released...",
aliases=["Zookeeper"], aliases=["Zookeeper"],
goals=["acquisition-theft", "harassment", "damage"] goals=["acquisition-theft", "harassment", "damage"],
) )
assert str(intrusion_set) == EXPECTED assert str(intrusion_set) == EXPECTED
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"aliases": [ {
"Zookeeper" "aliases": [
], "Zookeeper",
"created": "2016-04-06T20:03:48.000Z", ],
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", "created": "2016-04-06T20:03:48.000Z",
"description": "Incidents usually feature a shared TTP of a bobcat being released...", "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
"goals": [ "description": "Incidents usually feature a shared TTP of a bobcat being released...",
"acquisition-theft", "goals": [
"harassment", "acquisition-theft",
"damage" "harassment",
], "damage",
"id": "intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29", ],
"modified": "2016-04-06T20:03:48.000Z", "id": "intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29",
"name": "Bobcat Breakin", "modified": "2016-04-06T20:03:48.000Z",
"type": "intrusion-set" "name": "Bobcat Breakin",
}, "type": "intrusion-set",
]) },
],
)
def test_parse_intrusion_set(data): def test_parse_intrusion_set(data):
intset = stix2.parse(data, version="2.0") intset = stix2.parse(data, version="2.0")

View File

@ -29,7 +29,7 @@ def test_malware_with_all_required_properties():
created=now, created=now,
modified=now, modified=now,
labels=["ransomware"], labels=["ransomware"],
name="Cryptolocker" name="Cryptolocker",
) )
assert str(mal) == EXPECTED_MALWARE assert str(mal) == EXPECTED_MALWARE
@ -103,17 +103,19 @@ def test_invalid_kwarg_to_malware():
assert str(excinfo.value) == "Unexpected properties for Malware: (my_custom_property)." assert str(excinfo.value) == "Unexpected properties for Malware: (my_custom_property)."
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED_MALWARE, "data", [
{ EXPECTED_MALWARE,
"type": "malware", {
"id": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e", "type": "malware",
"created": "2016-05-12T08:17:27.000Z", "id": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
"modified": "2016-05-12T08:17:27.000Z", "created": "2016-05-12T08:17:27.000Z",
"labels": ["ransomware"], "modified": "2016-05-12T08:17:27.000Z",
"name": "Cryptolocker" "labels": ["ransomware"],
}, "name": "Cryptolocker",
]) },
],
)
def test_parse_malware(data): def test_parse_malware(data):
mal = stix2.parse(data, version="2.0") mal = stix2.parse(data, version="2.0")

View File

@ -79,7 +79,7 @@ def test_marking_def_example_with_statement_positional_argument():
id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
created="2017-01-20T00:00:00.000Z", created="2017-01-20T00:00:00.000Z",
definition_type="statement", definition_type="statement",
definition=stix2.v20.StatementMarking(statement="Copyright 2016, Example Corp") definition=stix2.v20.StatementMarking(statement="Copyright 2016, Example Corp"),
) )
assert str(marking_definition) == EXPECTED_STATEMENT_MARKING_DEFINITION assert str(marking_definition) == EXPECTED_STATEMENT_MARKING_DEFINITION
@ -91,7 +91,7 @@ def test_marking_def_example_with_kwargs_statement():
id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
created="2017-01-20T00:00:00.000Z", created="2017-01-20T00:00:00.000Z",
definition_type="statement", definition_type="statement",
definition=stix2.v20.StatementMarking(**kwargs) definition=stix2.v20.StatementMarking(**kwargs),
) )
assert str(marking_definition) == EXPECTED_STATEMENT_MARKING_DEFINITION assert str(marking_definition) == EXPECTED_STATEMENT_MARKING_DEFINITION
@ -103,7 +103,7 @@ def test_marking_def_invalid_type():
id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
created="2017-01-20T00:00:00.000Z", created="2017-01-20T00:00:00.000Z",
definition_type="my-definition-type", definition_type="my-definition-type",
definition=stix2.v20.StatementMarking("Copyright 2016, Example Corp") definition=stix2.v20.StatementMarking("Copyright 2016, Example Corp"),
) )
@ -115,7 +115,7 @@ def test_campaign_with_markings_example():
modified="2016-04-06T20:03:00Z", modified="2016-04-06T20:03:00Z",
name="Green Group Attacks Against Finance", name="Green Group Attacks Against Finance",
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.",
object_marking_refs=TLP_WHITE object_marking_refs=TLP_WHITE,
) )
assert str(campaign) == EXPECTED_CAMPAIGN_WITH_OBJECT_MARKING assert str(campaign) == EXPECTED_CAMPAIGN_WITH_OBJECT_MARKING
@ -123,7 +123,7 @@ def test_campaign_with_markings_example():
def test_granular_example(): def test_granular_example():
granular_marking = stix2.v20.GranularMarking( granular_marking = stix2.v20.GranularMarking(
marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
selectors=["abc", "abc.[23]", "abc.def", "abc.[2].efg"] selectors=["abc", "abc.[23]", "abc.def", "abc.[2].efg"],
) )
assert str(granular_marking) == EXPECTED_GRANULAR_MARKING assert str(granular_marking) == EXPECTED_GRANULAR_MARKING
@ -133,7 +133,7 @@ def test_granular_example_with_bad_selector():
with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo:
stix2.v20.GranularMarking( stix2.v20.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 excinfo.value.cls == stix2.v20.GranularMarking assert excinfo.value.cls == stix2.v20.GranularMarking
@ -153,23 +153,27 @@ def test_campaign_with_granular_markings_example():
granular_markings=[ granular_markings=[
stix2.v20.GranularMarking( stix2.v20.GranularMarking(
marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
selectors=["description"]) selectors=["description"],
]) ),
],
)
assert str(campaign) == EXPECTED_CAMPAIGN_WITH_GRANULAR_MARKINGS assert str(campaign) == EXPECTED_CAMPAIGN_WITH_GRANULAR_MARKINGS
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED_TLP_MARKING_DEFINITION, "data", [
{ EXPECTED_TLP_MARKING_DEFINITION,
"id": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", {
"type": "marking-definition", "id": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
"created": "2017-01-20T00:00:00Z", "type": "marking-definition",
"definition": { "created": "2017-01-20T00:00:00Z",
"tlp": "white" "definition": {
"tlp": "white",
},
"definition_type": "tlp",
}, },
"definition_type": "tlp", ],
}, )
])
def test_parse_marking_definition(data): def test_parse_marking_definition(data):
gm = stix2.parse(data, version="2.0") gm = stix2.parse(data, version="2.0")
@ -180,10 +184,12 @@ def test_parse_marking_definition(data):
assert gm.definition_type == "tlp" assert gm.definition_type == "tlp"
@stix2.v20.CustomMarking('x-new-marking-type', [ @stix2.v20.CustomMarking(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-marking-type', [
('property2', stix2.properties.IntegerProperty()), ('property1', stix2.properties.StringProperty(required=True)),
]) ('property2', stix2.properties.IntegerProperty()),
],
)
class NewMarking(object): class NewMarking(object):
def __init__(self, property2=None, **kwargs): def __init__(self, property2=None, **kwargs):
if "property3" in kwargs and not isinstance(kwargs.get("property3"), int): if "property3" in kwargs and not isinstance(kwargs.get("property3"), int):
@ -197,7 +203,7 @@ def test_registered_custom_marking():
id="marking-definition--00000000-0000-4000-8000-000000000012", id="marking-definition--00000000-0000-4000-8000-000000000012",
created="2017-01-22T00:00:00.000Z", created="2017-01-22T00:00:00.000Z",
definition_type="x-new-marking-type", definition_type="x-new-marking-type",
definition=nm definition=nm,
) )
assert marking_def.type == "marking-definition" assert marking_def.type == "marking-definition"
@ -218,10 +224,12 @@ def test_registered_custom_marking_raises_exception():
def test_not_registered_marking_raises_exception(): def test_not_registered_marking_raises_exception():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
# Used custom object on purpose to demonstrate a not-registered marking # Used custom object on purpose to demonstrate a not-registered marking
@stix2.v20.CustomObject('x-new-marking-type2', [ @stix2.v20.CustomObject(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-marking-type2', [
('property2', stix2.properties.IntegerProperty()), ('property1', stix2.properties.StringProperty(required=True)),
]) ('property2', stix2.properties.IntegerProperty()),
],
)
class NewObject2(object): class NewObject2(object):
def __init__(self, property2=None, **kwargs): def __init__(self, property2=None, **kwargs):
return return
@ -232,7 +240,7 @@ def test_not_registered_marking_raises_exception():
id="marking-definition--00000000-0000-4000-8000-000000000012", id="marking-definition--00000000-0000-4000-8000-000000000012",
created="2017-01-22T00:00:00.000Z", created="2017-01-22T00:00:00.000Z",
definition_type="x-new-marking-type2", definition_type="x-new-marking-type2",
definition=no definition=no,
) )
assert str(excinfo.value) == "definition_type must be a valid marking type" assert str(excinfo.value) == "definition_type must be a valid marking type"

View File

@ -18,26 +18,34 @@ MALWARE_KWARGS.update({
}) })
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
( "data", [
Malware(**MALWARE_KWARGS), (
Malware(object_marking_refs=[MARKING_IDS[0]], Malware(**MALWARE_KWARGS),
**MALWARE_KWARGS), Malware(
MARKING_IDS[0], object_marking_refs=[MARKING_IDS[0]],
), **MALWARE_KWARGS
( ),
MALWARE_KWARGS, MARKING_IDS[0],
dict(object_marking_refs=[MARKING_IDS[0]], ),
**MALWARE_KWARGS), (
MARKING_IDS[0], MALWARE_KWARGS,
), dict(
( object_marking_refs=[MARKING_IDS[0]],
Malware(**MALWARE_KWARGS), **MALWARE_KWARGS
Malware(object_marking_refs=[TLP_AMBER.id], ),
**MALWARE_KWARGS), MARKING_IDS[0],
TLP_AMBER, ),
), (
]) Malware(**MALWARE_KWARGS),
Malware(
object_marking_refs=[TLP_AMBER.id],
**MALWARE_KWARGS
),
TLP_AMBER,
),
],
)
def test_add_markings_one_marking(data): def test_add_markings_one_marking(data):
before = data[0] before = data[0]
after = data[1] after = data[1]
@ -73,12 +81,12 @@ def test_add_markings_combination():
granular_markings=[ granular_markings=[
{ {
"selectors": ["labels"], "selectors": ["labels"],
"marking_ref": MARKING_IDS[2] "marking_ref": MARKING_IDS[2],
}, },
{ {
"selectors": ["name"], "selectors": ["name"],
"marking_ref": MARKING_IDS[3] "marking_ref": MARKING_IDS[3],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -95,12 +103,14 @@ def test_add_markings_combination():
assert m in after["object_marking_refs"] assert m in after["object_marking_refs"]
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
([""]), "data", [
(""), ([""]),
([]), (""),
([MARKING_IDS[0], 456]) ([]),
]) ([MARKING_IDS[0], 456]),
],
)
def test_add_markings_bad_markings(data): def test_add_markings_bad_markings(data):
before = Malware( before = Malware(
**MALWARE_KWARGS **MALWARE_KWARGS
@ -120,62 +130,62 @@ GET_MARKINGS_TEST_DATA = \
"list value", "list value",
{ {
"g": "nested", "g": "nested",
"h": 45 "h": 45,
} },
], ],
"x": { "x": {
"y": [ "y": [
"hello", "hello",
88 88,
], ],
"z": { "z": {
"foo1": "bar", "foo1": "bar",
"foo2": 65 "foo2": 65,
} },
}, },
"object_marking_refs": ["11"], "object_marking_refs": ["11"],
"granular_markings": [ "granular_markings": [
{ {
"marking_ref": "1", "marking_ref": "1",
"selectors": ["a"] "selectors": ["a"],
}, },
{ {
"marking_ref": "2", "marking_ref": "2",
"selectors": ["c"] "selectors": ["c"],
}, },
{ {
"marking_ref": "3", "marking_ref": "3",
"selectors": ["c.[1]"] "selectors": ["c.[1]"],
}, },
{ {
"marking_ref": "4", "marking_ref": "4",
"selectors": ["c.[2]"] "selectors": ["c.[2]"],
}, },
{ {
"marking_ref": "5", "marking_ref": "5",
"selectors": ["c.[2].g"] "selectors": ["c.[2].g"],
}, },
{ {
"marking_ref": "6", "marking_ref": "6",
"selectors": ["x"] "selectors": ["x"],
}, },
{ {
"marking_ref": "7", "marking_ref": "7",
"selectors": ["x.y"] "selectors": ["x.y"],
}, },
{ {
"marking_ref": "8", "marking_ref": "8",
"selectors": ["x.y.[1]"] "selectors": ["x.y.[1]"],
}, },
{ {
"marking_ref": "9", "marking_ref": "9",
"selectors": ["x.z"] "selectors": ["x.z"],
}, },
{ {
"marking_ref": "10", "marking_ref": "10",
"selectors": ["x.z.foo2"] "selectors": ["x.z.foo2"],
}, },
] ],
} }
@ -258,18 +268,24 @@ def test_get_markings_object_and_granular_combinations(data):
assert set(markings.get_markings(data, "x.z.foo2", False, True)) == set(["10"]) assert set(markings.get_markings(data, "x.z.foo2", False, True)) == set(["10"])
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
( "data", [
Malware(object_marking_refs=[MARKING_IDS[0]], (
**MALWARE_KWARGS), Malware(
Malware(**MALWARE_KWARGS), object_marking_refs=[MARKING_IDS[0]],
), **MALWARE_KWARGS
( ),
dict(object_marking_refs=[MARKING_IDS[0]], Malware(**MALWARE_KWARGS),
**MALWARE_KWARGS), ),
MALWARE_KWARGS, (
), dict(
]) object_marking_refs=[MARKING_IDS[0]],
**MALWARE_KWARGS
),
MALWARE_KWARGS,
),
],
)
def test_remove_markings_object_level(data): def test_remove_markings_object_level(data):
before = data[0] before = data[0]
after = data[1] after = data[1]
@ -284,29 +300,43 @@ def test_remove_markings_object_level(data):
modified == after['modified'] modified == after['modified']
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
( "data", [
Malware(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]], (
**MALWARE_KWARGS), Malware(
Malware(object_marking_refs=[MARKING_IDS[1]], object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
**MALWARE_KWARGS), **MALWARE_KWARGS
[MARKING_IDS[0], MARKING_IDS[2]], ),
), Malware(
( object_marking_refs=[MARKING_IDS[1]],
dict(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]], **MALWARE_KWARGS
**MALWARE_KWARGS), ),
dict(object_marking_refs=[MARKING_IDS[1]], [MARKING_IDS[0], MARKING_IDS[2]],
**MALWARE_KWARGS), ),
[MARKING_IDS[0], MARKING_IDS[2]], (
), dict(
( object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
Malware(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], TLP_AMBER.id], **MALWARE_KWARGS
**MALWARE_KWARGS), ),
Malware(object_marking_refs=[MARKING_IDS[1]], dict(
**MALWARE_KWARGS), object_marking_refs=[MARKING_IDS[1]],
[MARKING_IDS[0], TLP_AMBER], **MALWARE_KWARGS
), ),
]) [MARKING_IDS[0], MARKING_IDS[2]],
),
(
Malware(
object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], TLP_AMBER.id],
**MALWARE_KWARGS
),
Malware(
object_marking_refs=[MARKING_IDS[1]],
**MALWARE_KWARGS
),
[MARKING_IDS[0], TLP_AMBER],
),
],
)
def test_remove_markings_multiple(data): def test_remove_markings_multiple(data):
before = data[0] before = data[0]
after = data[1] after = data[1]
@ -326,18 +356,24 @@ def test_remove_markings_bad_markings():
assert str(excinfo.value) == "Marking ['%s'] was not found in Malware!" % MARKING_IDS[4] assert str(excinfo.value) == "Marking ['%s'] was not found in Malware!" % MARKING_IDS[4]
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
( "data", [
Malware(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]], (
**MALWARE_KWARGS), Malware(
Malware(**MALWARE_KWARGS), object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
), **MALWARE_KWARGS
( ),
dict(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]], Malware(**MALWARE_KWARGS),
**MALWARE_KWARGS), ),
MALWARE_KWARGS, (
), dict(
]) object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
**MALWARE_KWARGS
),
MALWARE_KWARGS,
),
],
)
def test_clear_markings(data): def test_clear_markings(data):
before = data[0] before = data[0]
after = data[1] after = data[1]
@ -359,62 +395,62 @@ def test_is_marked_object_and_granular_combinations():
"list value", "list value",
{ {
"g": "nested", "g": "nested",
"h": 45 "h": 45,
} },
], ],
"x": { "x": {
"y": [ "y": [
"hello", "hello",
88 88,
], ],
"z": { "z": {
"foo1": "bar", "foo1": "bar",
"foo2": 65 "foo2": 65,
} },
}, },
"object_marking_refs": "11", "object_marking_refs": "11",
"granular_markings": [ "granular_markings": [
{ {
"marking_ref": "1", "marking_ref": "1",
"selectors": ["a"] "selectors": ["a"],
}, },
{ {
"marking_ref": "2", "marking_ref": "2",
"selectors": ["c"] "selectors": ["c"],
}, },
{ {
"marking_ref": "3", "marking_ref": "3",
"selectors": ["c.[1]"] "selectors": ["c.[1]"],
}, },
{ {
"marking_ref": "4", "marking_ref": "4",
"selectors": ["c.[2]"] "selectors": ["c.[2]"],
}, },
{ {
"marking_ref": "5", "marking_ref": "5",
"selectors": ["c.[2].g"] "selectors": ["c.[2].g"],
}, },
{ {
"marking_ref": "6", "marking_ref": "6",
"selectors": ["x"] "selectors": ["x"],
}, },
{ {
"marking_ref": "7", "marking_ref": "7",
"selectors": ["x.y"] "selectors": ["x.y"],
}, },
{ {
"marking_ref": "8", "marking_ref": "8",
"selectors": ["x.y.[1]"] "selectors": ["x.y.[1]"],
}, },
{ {
"marking_ref": "9", "marking_ref": "9",
"selectors": ["x.z"] "selectors": ["x.z"],
}, },
{ {
"marking_ref": "10", "marking_ref": "10",
"selectors": ["x.z.foo2"] "selectors": ["x.z.foo2"],
}, },
] ],
} }
assert markings.is_marked(test_sdo, ["1"], "a", False, False) assert markings.is_marked(test_sdo, ["1"], "a", False, False)
@ -491,18 +527,24 @@ def test_is_marked_object_and_granular_combinations():
assert markings.is_marked(test_sdo, ["2"], None, True, True) is False assert markings.is_marked(test_sdo, ["2"], None, True, True) is False
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
( "data", [
Malware(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]], (
**MALWARE_KWARGS), Malware(
Malware(**MALWARE_KWARGS), object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
), **MALWARE_KWARGS
( ),
dict(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]], Malware(**MALWARE_KWARGS),
**MALWARE_KWARGS), ),
MALWARE_KWARGS, (
), dict(
]) object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
**MALWARE_KWARGS
),
MALWARE_KWARGS,
),
],
)
def test_is_marked_no_markings(data): def test_is_marked_no_markings(data):
marked = data[0] marked = data[0]
nonmarked = data[1] nonmarked = data[1]
@ -532,12 +574,14 @@ def test_set_marking():
assert x in after["object_marking_refs"] assert x in after["object_marking_refs"]
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
([]), "data", [
([""]), ([]),
(""), ([""]),
([MARKING_IDS[4], 687]) (""),
]) ([MARKING_IDS[4], 687]),
],
)
def test_set_marking_bad_input(data): def test_set_marking_bad_input(data):
before = Malware( before = Malware(
object_marking_refs=[MARKING_IDS[0]], object_marking_refs=[MARKING_IDS[0]],

View File

@ -41,7 +41,7 @@ def test_observed_data_example():
objects={ objects={
"0": { "0": {
"name": "foo.exe", "name": "foo.exe",
"type": "file" "type": "file",
}, },
}, },
) )
@ -86,13 +86,13 @@ def test_observed_data_example_with_refs():
objects={ objects={
"0": { "0": {
"name": "foo.exe", "name": "foo.exe",
"type": "file" "type": "file",
}, },
"1": { "1": {
"type": "directory", "type": "directory",
"path": "/usr/home", "path": "/usr/home",
"contains_refs": ["0"] "contains_refs": ["0"],
} },
}, },
) )
@ -112,13 +112,13 @@ def test_observed_data_example_with_bad_refs():
objects={ objects={
"0": { "0": {
"type": "file", "type": "file",
"name": "foo.exe" "name": "foo.exe",
}, },
"1": { "1": {
"type": "directory", "type": "directory",
"path": "/usr/home", "path": "/usr/home",
"contains_refs": ["2"] "contains_refs": ["2"],
} },
}, },
) )
@ -163,25 +163,27 @@ def test_observed_data_example_with_empty_dictionary():
assert 'must contain a non-empty dictionary' in excinfo.value.reason assert 'must contain a non-empty dictionary' in excinfo.value.reason
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"type": "observed-data", {
"id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", "type": "observed-data",
"created": "2016-04-06T19:58:16.000Z", "id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", "created": "2016-04-06T19:58:16.000Z",
"first_observed": "2015-12-21T19:00:00Z", "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
"last_observed": "2015-12-21T19:00:00Z", "first_observed": "2015-12-21T19:00:00Z",
"modified": "2016-04-06T19:58:16.000Z", "last_observed": "2015-12-21T19:00:00Z",
"number_observed": 50, "modified": "2016-04-06T19:58:16.000Z",
"objects": { "number_observed": 50,
"0": { "objects": {
"name": "foo.exe", "0": {
"type": "file" "name": "foo.exe",
} "type": "file",
} },
}, },
]) },
],
)
def test_parse_observed_data(data): def test_parse_observed_data(data):
odata = stix2.parse(data, version="2.0") odata = stix2.parse(data, version="2.0")
@ -195,13 +197,14 @@ def test_parse_observed_data(data):
assert odata.objects["0"].type == "file" assert odata.objects["0"].type == "file"
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
""""0": { "data", [
""""0": {
"type": "artifact", "type": "artifact",
"mime_type": "image/jpeg", "mime_type": "image/jpeg",
"payload_bin": "VBORw0KGgoAAAANSUhEUgAAADI==" "payload_bin": "VBORw0KGgoAAAANSUhEUgAAADI=="
}""", }""",
""""0": { """"0": {
"type": "artifact", "type": "artifact",
"mime_type": "image/jpeg", "mime_type": "image/jpeg",
"url": "https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg", "url": "https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg",
@ -209,20 +212,22 @@ def test_parse_observed_data(data):
"MD5": "6826f9a05da08134006557758bb3afbb" "MD5": "6826f9a05da08134006557758bb3afbb"
} }
}""", }""",
]) ],
)
def test_parse_artifact_valid(data): def test_parse_artifact_valid(data):
odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED) odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED)
odata = stix2.parse(odata_str, version="2.0") odata = stix2.parse(odata_str, version="2.0")
assert odata.objects["0"].type == "artifact" assert odata.objects["0"].type == "artifact"
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
""""0": { "data", [
""""0": {
"type": "artifact", "type": "artifact",
"mime_type": "image/jpeg", "mime_type": "image/jpeg",
"payload_bin": "abcVBORw0KGgoAAAANSUhEUgAAADI==" "payload_bin": "abcVBORw0KGgoAAAANSUhEUgAAADI=="
}""", }""",
""""0": { """"0": {
"type": "artifact", "type": "artifact",
"mime_type": "image/jpeg", "mime_type": "image/jpeg",
"url": "https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg", "url": "https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg",
@ -230,7 +235,8 @@ def test_parse_artifact_valid(data):
"MD5": "a" "MD5": "a"
} }
}""", }""",
]) ],
)
def test_parse_artifact_invalid(data): def test_parse_artifact_invalid(data):
odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED) odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED)
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -245,14 +251,16 @@ def test_artifact_example_dependency_error():
assert str(excinfo.value) == "The property dependencies for Artifact: (hashes, url) are not met." assert str(excinfo.value) == "The property dependencies for Artifact: (hashes, url) are not met."
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
""""0": { "data", [
""""0": {
"type": "autonomous-system", "type": "autonomous-system",
"number": 15139, "number": 15139,
"name": "Slime Industries", "name": "Slime Industries",
"rir": "ARIN" "rir": "ARIN"
}""", }""",
]) ],
)
def test_parse_autonomous_system_valid(data): def test_parse_autonomous_system_valid(data):
odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED) odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED)
odata = stix2.parse(odata_str, version="2.0") odata = stix2.parse(odata_str, version="2.0")
@ -262,14 +270,16 @@ def test_parse_autonomous_system_valid(data):
assert odata.objects["0"].rir == "ARIN" assert odata.objects["0"].rir == "ARIN"
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
"""{ "data", [
"""{
"type": "email-addr", "type": "email-addr",
"value": "john@example.com", "value": "john@example.com",
"display_name": "John Doe", "display_name": "John Doe",
"belongs_to_ref": "0" "belongs_to_ref": "0"
}""", }""",
]) ],
)
def test_parse_email_address(data): def test_parse_email_address(data):
odata = stix2.parse_observable(data, {"0": "user-account"}, version='2.0') odata = stix2.parse_observable(data, {"0": "user-account"}, version='2.0')
assert odata.type == "email-addr" assert odata.type == "email-addr"
@ -279,8 +289,9 @@ def test_parse_email_address(data):
stix2.parse_observable(odata_str, {"0": "user-account"}, version='2.0') stix2.parse_observable(odata_str, {"0": "user-account"}, version='2.0')
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
""" "data", [
"""
{ {
"type": "email-message", "type": "email-message",
"is_multipart": true, "is_multipart": true,
@ -317,8 +328,9 @@ def test_parse_email_address(data):
} }
] ]
} }
""" """,
]) ],
)
def test_parse_email_message(data): def test_parse_email_message(data):
valid_refs = { valid_refs = {
"0": "email-message", "0": "email-message",
@ -333,8 +345,9 @@ def test_parse_email_message(data):
assert odata.body_multipart[0].content_disposition == "inline" assert odata.body_multipart[0].content_disposition == "inline"
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
""" "data", [
"""
{ {
"type": "email-message", "type": "email-message",
"from_ref": "0", "from_ref": "0",
@ -344,8 +357,9 @@ def test_parse_email_message(data):
"subject": "Saying Hello", "subject": "Saying Hello",
"body": "Cats are funny!" "body": "Cats are funny!"
} }
""" """,
]) ],
)
def test_parse_email_message_not_multipart(data): def test_parse_email_message_not_multipart(data):
valid_refs = { valid_refs = {
"0": "email-addr", "0": "email-addr",
@ -358,8 +372,9 @@ def test_parse_email_message_not_multipart(data):
assert excinfo.value.dependencies == [("is_multipart", "body")] assert excinfo.value.dependencies == [("is_multipart", "body")]
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
""""0": { "data", [
""""0": {
"type": "file", "type": "file",
"hashes": { "hashes": {
"SHA-256": "ceafbfd424be2ca4a5f0402cae090dda2fb0526cf521b60b60077c0f622b285a" "SHA-256": "ceafbfd424be2ca4a5f0402cae090dda2fb0526cf521b60b60077c0f622b285a"
@ -395,15 +410,17 @@ def test_parse_email_message_not_multipart(data):
} }
} }
}""", }""",
]) ],
)
def test_parse_file_archive(data): def test_parse_file_archive(data):
odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED) odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED)
odata = stix2.parse(odata_str, version="2.0") odata = stix2.parse(odata_str, version="2.0")
assert odata.objects["3"].extensions['archive-ext'].version == "5.0" assert odata.objects["3"].extensions['archive-ext'].version == "5.0"
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
""" "data", [
"""
{ {
"type": "email-message", "type": "email-message",
"is_multipart": true, "is_multipart": true,
@ -439,8 +456,9 @@ def test_parse_file_archive(data):
} }
] ]
} }
""" """,
]) ],
)
def test_parse_email_message_with_at_least_one_error(data): def test_parse_email_message_with_at_least_one_error(data):
valid_refs = { valid_refs = {
"0": "email-message", "0": "email-message",
@ -459,8 +477,9 @@ def test_parse_email_message_with_at_least_one_error(data):
assert "must be populated" in str(excinfo.value) assert "must be populated" in str(excinfo.value)
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
""" "data", [
"""
{ {
"type": "network-traffic", "type": "network-traffic",
"src_ref": "0", "src_ref": "0",
@ -469,11 +488,14 @@ def test_parse_email_message_with_at_least_one_error(data):
"tcp" "tcp"
] ]
} }
""" """,
]) ],
)
def test_parse_basic_tcp_traffic(data): def test_parse_basic_tcp_traffic(data):
odata = stix2.parse_observable(data, {"0": "ipv4-addr", "1": "ipv4-addr"}, odata = stix2.parse_observable(
version='2.0') data, {"0": "ipv4-addr", "1": "ipv4-addr"},
version='2.0',
)
assert odata.type == "network-traffic" assert odata.type == "network-traffic"
assert odata.src_ref == "0" assert odata.src_ref == "0"
@ -481,8 +503,9 @@ def test_parse_basic_tcp_traffic(data):
assert odata.protocols == ["tcp"] assert odata.protocols == ["tcp"]
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
""" "data", [
"""
{ {
"type": "network-traffic", "type": "network-traffic",
"src_port": 2487, "src_port": 2487,
@ -497,8 +520,9 @@ def test_parse_basic_tcp_traffic(data):
"4" "4"
] ]
} }
""" """,
]) ],
)
def test_parse_basic_tcp_traffic_with_error(data): def test_parse_basic_tcp_traffic_with_error(data):
with pytest.raises(stix2.exceptions.AtLeastOnePropertyError) as excinfo: with pytest.raises(stix2.exceptions.AtLeastOnePropertyError) as excinfo:
stix2.parse_observable(data, {"4": "network-traffic"}, version='2.0') stix2.parse_observable(data, {"4": "network-traffic"}, version='2.0')
@ -550,7 +574,7 @@ def test_observed_data_with_process_example():
"0": { "0": {
"type": "file", "type": "file",
"hashes": { "hashes": {
"SHA-256": "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f" "SHA-256": "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f",
}, },
}, },
"1": { "1": {
@ -559,11 +583,12 @@ def test_observed_data_with_process_example():
"name": "gedit-bin", "name": "gedit-bin",
"created": "2016-01-20T14:11:25.55Z", "created": "2016-01-20T14:11:25.55Z",
"arguments": [ "arguments": [
"--new-window" "--new-window",
], ],
"binary_ref": "0" "binary_ref": "0",
} },
}) },
)
assert observed_data.objects["0"].type == "file" assert observed_data.objects["0"].type == "file"
assert observed_data.objects["0"].hashes["SHA-256"] == "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f" assert observed_data.objects["0"].hashes["SHA-256"] == "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f"
@ -580,8 +605,9 @@ def test_artifact_example():
mime_type="image/jpeg", mime_type="image/jpeg",
url="https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg", url="https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg",
hashes={ hashes={
"MD5": "6826f9a05da08134006557758bb3afbb" "MD5": "6826f9a05da08134006557758bb3afbb",
}) },
)
assert art.mime_type == "image/jpeg" assert art.mime_type == "image/jpeg"
assert art.url == "https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg" assert art.url == "https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg"
assert art.hashes["MD5"] == "6826f9a05da08134006557758bb3afbb" assert art.hashes["MD5"] == "6826f9a05da08134006557758bb3afbb"
@ -593,9 +619,10 @@ def test_artifact_mutual_exclusion_error():
mime_type="image/jpeg", mime_type="image/jpeg",
url="https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg", url="https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg",
hashes={ hashes={
"MD5": "6826f9a05da08134006557758bb3afbb" "MD5": "6826f9a05da08134006557758bb3afbb",
}, },
payload_bin="VBORw0KGgoAAAANSUhEUgAAADI==") payload_bin="VBORw0KGgoAAAANSUhEUgAAADI==",
)
assert excinfo.value.cls == stix2.v20.Artifact assert excinfo.value.cls == stix2.v20.Artifact
assert excinfo.value.properties == ["payload_bin", "url"] assert excinfo.value.properties == ["payload_bin", "url"]
@ -609,7 +636,8 @@ def test_directory_example():
created="2015-12-21T19:00:00Z", created="2015-12-21T19:00:00Z",
modified="2015-12-24T19:00:00Z", modified="2015-12-24T19:00:00Z",
accessed="2015-12-21T20:00:00Z", accessed="2015-12-21T20:00:00Z",
contains_refs=["1"]) contains_refs=["1"],
)
assert dir.path == '/usr/lib' assert dir.path == '/usr/lib'
assert dir.created == dt.datetime(2015, 12, 21, 19, 0, 0, tzinfo=pytz.utc) assert dir.created == dt.datetime(2015, 12, 21, 19, 0, 0, tzinfo=pytz.utc)
@ -626,7 +654,8 @@ def test_directory_example_ref_error():
created="2015-12-21T19:00:00Z", created="2015-12-21T19:00:00Z",
modified="2015-12-24T19:00:00Z", modified="2015-12-24T19:00:00Z",
accessed="2015-12-21T20:00:00Z", accessed="2015-12-21T20:00:00Z",
contains_refs=["1"]) contains_refs=["1"],
)
assert excinfo.value.cls == stix2.v20.Directory assert excinfo.value.cls == stix2.v20.Directory
assert excinfo.value.prop_name == "contains_refs" assert excinfo.value.prop_name == "contains_refs"
@ -636,7 +665,8 @@ def test_domain_name_example():
dn = stix2.v20.DomainName( dn = stix2.v20.DomainName(
_valid_refs={"1": 'domain-name'}, _valid_refs={"1": 'domain-name'},
value="example.com", value="example.com",
resolves_to_refs=["1"]) resolves_to_refs=["1"],
)
assert dn.value == "example.com" assert dn.value == "example.com"
assert dn.resolves_to_refs == ["1"] assert dn.resolves_to_refs == ["1"]
@ -647,7 +677,8 @@ def test_domain_name_example_invalid_ref_type():
stix2.v20.DomainName( stix2.v20.DomainName(
_valid_refs={"1": "file"}, _valid_refs={"1": "file"},
value="example.com", value="example.com",
resolves_to_refs=["1"]) resolves_to_refs=["1"],
)
assert excinfo.value.cls == stix2.v20.DomainName assert excinfo.value.cls == stix2.v20.DomainName
assert excinfo.value.prop_name == "resolves_to_refs" assert excinfo.value.prop_name == "resolves_to_refs"
@ -657,7 +688,7 @@ def test_file_example():
f = stix2.v20.File( f = stix2.v20.File(
name="qwerty.dll", name="qwerty.dll",
hashes={ hashes={
"SHA-256": "ceafbfd424be2ca4a5f0402cae090dda2fb0526cf521b60b60077c0f622b285a" "SHA-256": "ceafbfd424be2ca4a5f0402cae090dda2fb0526cf521b60b60077c0f622b285a",
}, },
size=100, size=100,
magic_number_hex="1C", magic_number_hex="1C",
@ -667,7 +698,8 @@ def test_file_example():
accessed="2016-12-21T20:00:00Z", accessed="2016-12-21T20:00:00Z",
is_encrypted=True, is_encrypted=True,
encryption_algorithm="AES128-CBC", encryption_algorithm="AES128-CBC",
decryption_key="fred") decryption_key="fred",
)
assert f.name == "qwerty.dll" assert f.name == "qwerty.dll"
assert f.size == 100 assert f.size == 100
@ -690,11 +722,12 @@ def test_file_example_with_NTFSExt():
"alternate_data_streams": [ "alternate_data_streams": [
{ {
"name": "second.stream", "name": "second.stream",
"size": 25536 "size": 25536,
} },
] ],
} },
}) },
)
assert f.name == "abc.txt" assert f.name == "abc.txt"
assert f.extensions["ntfs-ext"].alternate_data_streams[0].size == 25536 assert f.extensions["ntfs-ext"].alternate_data_streams[0].size == 25536
@ -705,8 +738,9 @@ def test_file_example_with_empty_NTFSExt():
stix2.v20.File( stix2.v20.File(
name="abc.txt", name="abc.txt",
extensions={ extensions={
"ntfs-ext": {} "ntfs-ext": {},
}) },
)
assert excinfo.value.cls == stix2.v20.NTFSExt assert excinfo.value.cls == stix2.v20.NTFSExt
assert excinfo.value.properties == sorted(list(stix2.NTFSExt._properties.keys())) assert excinfo.value.properties == sorted(list(stix2.NTFSExt._properties.keys()))
@ -723,12 +757,13 @@ def test_file_example_with_PDFExt():
"Author": "Adobe Systems Incorporated", "Author": "Adobe Systems Incorporated",
"Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh", "Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh",
"Producer": "Acrobat Distiller 3.01 for Power Macintosh", "Producer": "Acrobat Distiller 3.01 for Power Macintosh",
"CreationDate": "20070412090123-02" "CreationDate": "20070412090123-02",
}, },
"pdfid0": "DFCE52BD827ECF765649852119D", "pdfid0": "DFCE52BD827ECF765649852119D",
"pdfid1": "57A1E0F9ED2AE523E313C" "pdfid1": "57A1E0F9ED2AE523E313C",
} },
}) },
)
assert f.name == "qwerty.dll" assert f.name == "qwerty.dll"
assert f.extensions["pdf-ext"].version == "1.7" assert f.extensions["pdf-ext"].version == "1.7"
@ -746,11 +781,13 @@ def test_file_example_with_PDFExt_Object():
"Author": "Adobe Systems Incorporated", "Author": "Adobe Systems Incorporated",
"Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh", "Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh",
"Producer": "Acrobat Distiller 3.01 for Power Macintosh", "Producer": "Acrobat Distiller 3.01 for Power Macintosh",
"CreationDate": "20070412090123-02" "CreationDate": "20070412090123-02",
}, },
pdfid0="DFCE52BD827ECF765649852119D", pdfid0="DFCE52BD827ECF765649852119D",
pdfid1="57A1E0F9ED2AE523E313C") pdfid1="57A1E0F9ED2AE523E313C",
}) ),
},
)
assert f.name == "qwerty.dll" assert f.name == "qwerty.dll"
assert f.extensions["pdf-ext"].version == "1.7" assert f.extensions["pdf-ext"].version == "1.7"
@ -767,10 +804,11 @@ def test_file_example_with_RasterImageExt_Object():
"Make": "Nikon", "Make": "Nikon",
"Model": "D7000", "Model": "D7000",
"XResolution": 4928, "XResolution": 4928,
"YResolution": 3264 "YResolution": 3264,
} },
} },
}) },
)
assert f.name == "qwerty.jpeg" assert f.name == "qwerty.jpeg"
assert f.extensions["raster-image-ext"].bits_per_pixel == 123 assert f.extensions["raster-image-ext"].bits_per_pixel == 123
assert f.extensions["raster-image-ext"].exif_tags["XResolution"] == 4928 assert f.extensions["raster-image-ext"].exif_tags["XResolution"] == 4928
@ -864,28 +902,29 @@ def test_file_example_with_WindowsPEBinaryExt():
"size_of_heap_reserve": 100000, "size_of_heap_reserve": 100000,
"size_of_heap_commit": 4096, "size_of_heap_commit": 4096,
"loader_flags_hex": "abdbffde", "loader_flags_hex": "abdbffde",
"number_of_rva_and_sizes": 3758087646 "number_of_rva_and_sizes": 3758087646,
}, },
"sections": [ "sections": [
{ {
"name": "CODE", "name": "CODE",
"entropy": 0.061089 "entropy": 0.061089,
}, },
{ {
"name": "DATA", "name": "DATA",
"entropy": 7.980693 "entropy": 7.980693,
}, },
{ {
"name": "NicolasB", "name": "NicolasB",
"entropy": 0.607433 "entropy": 0.607433,
}, },
{ {
"name": ".idata", "name": ".idata",
"entropy": 0.607433 "entropy": 0.607433,
} },
] ],
} },
}) },
)
assert f.name == "qwerty.dll" assert f.name == "qwerty.dll"
assert f.extensions["windows-pebinary-ext"].sections[2].entropy == 0.607433 assert f.extensions["windows-pebinary-ext"].sections[2].entropy == 0.607433
@ -895,7 +934,8 @@ def test_file_example_encryption_error():
stix2.v20.File( stix2.v20.File(
name="qwerty.dll", name="qwerty.dll",
is_encrypted=False, is_encrypted=False,
encryption_algorithm="AES128-CBC") encryption_algorithm="AES128-CBC",
)
assert excinfo.value.cls == stix2.v20.File assert excinfo.value.cls == stix2.v20.File
assert excinfo.value.dependencies == [("is_encrypted", "encryption_algorithm")] assert excinfo.value.dependencies == [("is_encrypted", "encryption_algorithm")]
@ -905,14 +945,16 @@ def test_file_example_encryption_error():
with pytest.raises(stix2.exceptions.DependentPropertiesError) as excinfo: with pytest.raises(stix2.exceptions.DependentPropertiesError) as excinfo:
stix2.v20.File( stix2.v20.File(
name="qwerty.dll", name="qwerty.dll",
encryption_algorithm="AES128-CBC") encryption_algorithm="AES128-CBC",
)
def test_ip4_address_example(): def test_ip4_address_example():
ip4 = stix2.v20.IPv4Address( ip4 = stix2.v20.IPv4Address(
_valid_refs={"4": "mac-addr", "5": "mac-addr"}, _valid_refs={"4": "mac-addr", "5": "mac-addr"},
value="198.51.100.3", value="198.51.100.3",
resolves_to_refs=["4", "5"]) resolves_to_refs=["4", "5"],
)
assert ip4.value == "198.51.100.3" assert ip4.value == "198.51.100.3"
assert ip4.resolves_to_refs == ["4", "5"] assert ip4.resolves_to_refs == ["4", "5"]
@ -941,7 +983,8 @@ def test_network_traffic_example():
_valid_refs={"0": "ipv4-addr", "1": "ipv4-addr"}, _valid_refs={"0": "ipv4-addr", "1": "ipv4-addr"},
protocols="tcp", protocols="tcp",
src_ref="0", src_ref="0",
dst_ref="1") dst_ref="1",
)
assert nt.protocols == ["tcp"] assert nt.protocols == ["tcp"]
assert nt.src_ref == "0" assert nt.src_ref == "0"
assert nt.dst_ref == "1" assert nt.dst_ref == "1"
@ -955,13 +998,15 @@ def test_network_traffic_http_request_example():
request_header={ request_header={
"Accept-Encoding": "gzip,deflate", "Accept-Encoding": "gzip,deflate",
"User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113", "User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113",
"Host": "www.example.com" "Host": "www.example.com",
}) },
)
nt = stix2.v20.NetworkTraffic( nt = stix2.v20.NetworkTraffic(
_valid_refs={"0": "ipv4-addr"}, _valid_refs={"0": "ipv4-addr"},
protocols="tcp", protocols="tcp",
src_ref="0", src_ref="0",
extensions={'http-request-ext': h}) extensions={'http-request-ext': h},
)
assert nt.extensions['http-request-ext'].request_method == "get" assert nt.extensions['http-request-ext'].request_method == "get"
assert nt.extensions['http-request-ext'].request_value == "/download.html" assert nt.extensions['http-request-ext'].request_value == "/download.html"
assert nt.extensions['http-request-ext'].request_version == "http/1.1" assert nt.extensions['http-request-ext'].request_version == "http/1.1"
@ -976,7 +1021,8 @@ def test_network_traffic_icmp_example():
_valid_refs={"0": "ipv4-addr"}, _valid_refs={"0": "ipv4-addr"},
protocols="tcp", protocols="tcp",
src_ref="0", src_ref="0",
extensions={'icmp-ext': h}) extensions={'icmp-ext': h},
)
assert nt.extensions['icmp-ext'].icmp_type_hex == "08" assert nt.extensions['icmp-ext'].icmp_type_hex == "08"
assert nt.extensions['icmp-ext'].icmp_code_hex == "00" assert nt.extensions['icmp-ext'].icmp_code_hex == "00"
@ -986,12 +1032,14 @@ def test_network_traffic_socket_example():
is_listening=True, is_listening=True,
address_family="AF_INET", address_family="AF_INET",
protocol_family="PF_INET", protocol_family="PF_INET",
socket_type="SOCK_STREAM") socket_type="SOCK_STREAM",
)
nt = stix2.v20.NetworkTraffic( nt = stix2.v20.NetworkTraffic(
_valid_refs={"0": "ipv4-addr"}, _valid_refs={"0": "ipv4-addr"},
protocols="tcp", protocols="tcp",
src_ref="0", src_ref="0",
extensions={'socket-ext': h}) extensions={'socket-ext': h},
)
assert nt.extensions['socket-ext'].is_listening assert nt.extensions['socket-ext'].is_listening
assert nt.extensions['socket-ext'].address_family == "AF_INET" assert nt.extensions['socket-ext'].address_family == "AF_INET"
assert nt.extensions['socket-ext'].protocol_family == "PF_INET" assert nt.extensions['socket-ext'].protocol_family == "PF_INET"
@ -1004,7 +1052,8 @@ def test_network_traffic_tcp_example():
_valid_refs={"0": "ipv4-addr"}, _valid_refs={"0": "ipv4-addr"},
protocols="tcp", protocols="tcp",
src_ref="0", src_ref="0",
extensions={'tcp-ext': h}) extensions={'tcp-ext': h},
)
assert nt.extensions['tcp-ext'].src_flags_hex == "00000002" assert nt.extensions['tcp-ext'].src_flags_hex == "00000002"
@ -1021,7 +1070,8 @@ def test_process_example():
name="gedit-bin", name="gedit-bin",
created="2016-01-20T14:11:25.55Z", created="2016-01-20T14:11:25.55Z",
arguments=["--new-window"], arguments=["--new-window"],
binary_ref="0") binary_ref="0",
)
assert p.name == "gedit-bin" assert p.name == "gedit-bin"
assert p.arguments == ["--new-window"] assert p.arguments == ["--new-window"]
@ -1036,8 +1086,10 @@ def test_process_example_empty_error():
properties_of_process.remove("type") properties_of_process.remove("type")
assert excinfo.value.properties == sorted(properties_of_process) assert excinfo.value.properties == sorted(properties_of_process)
msg = "At least one of the ({1}) properties for {0} must be populated." msg = "At least one of the ({1}) properties for {0} must be populated."
msg = msg.format(stix2.v20.Process.__name__, msg = msg.format(
", ".join(sorted(properties_of_process))) stix2.v20.Process.__name__,
", ".join(sorted(properties_of_process)),
)
assert str(excinfo.value) == msg assert str(excinfo.value) == msg
@ -1045,8 +1097,9 @@ def test_process_example_empty_with_extensions():
with pytest.raises(stix2.exceptions.AtLeastOnePropertyError) as excinfo: with pytest.raises(stix2.exceptions.AtLeastOnePropertyError) as excinfo:
stix2.v20.Process( stix2.v20.Process(
extensions={ extensions={
"windows-process-ext": {} "windows-process-ext": {},
}) },
)
assert excinfo.value.cls == stix2.v20.WindowsProcessExt assert excinfo.value.cls == stix2.v20.WindowsProcessExt
properties_of_extension = list(stix2.v20.WindowsProcessExt._properties.keys()) properties_of_extension = list(stix2.v20.WindowsProcessExt._properties.keys())
@ -1062,9 +1115,10 @@ def test_process_example_windows_process_ext():
"aslr_enabled": True, "aslr_enabled": True,
"dep_enabled": True, "dep_enabled": True,
"priority": "HIGH_PRIORITY_CLASS", "priority": "HIGH_PRIORITY_CLASS",
"owner_sid": "S-1-5-21-186985262-1144665072-74031268-1309" "owner_sid": "S-1-5-21-186985262-1144665072-74031268-1309",
} },
}) },
)
assert proc.extensions["windows-process-ext"].aslr_enabled assert proc.extensions["windows-process-ext"].aslr_enabled
assert proc.extensions["windows-process-ext"].dep_enabled assert proc.extensions["windows-process-ext"].dep_enabled
assert proc.extensions["windows-process-ext"].priority == "HIGH_PRIORITY_CLASS" assert proc.extensions["windows-process-ext"].priority == "HIGH_PRIORITY_CLASS"
@ -1077,8 +1131,9 @@ def test_process_example_windows_process_ext_empty():
pid=1221, pid=1221,
name="gedit-bin", name="gedit-bin",
extensions={ extensions={
"windows-process-ext": {} "windows-process-ext": {},
}) },
)
assert excinfo.value.cls == stix2.v20.WindowsProcessExt assert excinfo.value.cls == stix2.v20.WindowsProcessExt
properties_of_extension = list(stix2.v20.WindowsProcessExt._properties.keys()) properties_of_extension = list(stix2.v20.WindowsProcessExt._properties.keys())
@ -1100,7 +1155,8 @@ def test_process_example_with_WindowsProcessExt_Object():
aslr_enabled=True, aslr_enabled=True,
dep_enabled=True, dep_enabled=True,
priority="HIGH_PRIORITY_CLASS", priority="HIGH_PRIORITY_CLASS",
owner_sid="S-1-5-21-186985262-1144665072-74031268-1309") # noqa owner_sid="S-1-5-21-186985262-1144665072-74031268-1309",
), # noqa
}) })
assert p.extensions["windows-process-ext"].dep_enabled assert p.extensions["windows-process-ext"].dep_enabled
@ -1114,8 +1170,8 @@ def test_process_example_with_WindowsServiceExt():
"display_name": "Sirvizio", "display_name": "Sirvizio",
"start_type": "SERVICE_AUTO_START", "start_type": "SERVICE_AUTO_START",
"service_type": "SERVICE_WIN32_OWN_PROCESS", "service_type": "SERVICE_WIN32_OWN_PROCESS",
"service_status": "SERVICE_RUNNING" "service_status": "SERVICE_RUNNING",
} },
}) })
assert p.extensions["windows-service-ext"].service_name == "sirvizio" assert p.extensions["windows-service-ext"].service_name == "sirvizio"
@ -1129,14 +1185,14 @@ def test_process_example_with_WindowsProcessServiceExt():
"display_name": "Sirvizio", "display_name": "Sirvizio",
"start_type": "SERVICE_AUTO_START", "start_type": "SERVICE_AUTO_START",
"service_type": "SERVICE_WIN32_OWN_PROCESS", "service_type": "SERVICE_WIN32_OWN_PROCESS",
"service_status": "SERVICE_RUNNING" "service_status": "SERVICE_RUNNING",
}, },
"windows-process-ext": { "windows-process-ext": {
"aslr_enabled": True, "aslr_enabled": True,
"dep_enabled": True, "dep_enabled": True,
"priority": "HIGH_PRIORITY_CLASS", "priority": "HIGH_PRIORITY_CLASS",
"owner_sid": "S-1-5-21-186985262-1144665072-74031268-1309" "owner_sid": "S-1-5-21-186985262-1144665072-74031268-1309",
} },
}) })
assert p.extensions["windows-service-ext"].service_name == "sirvizio" assert p.extensions["windows-service-ext"].service_name == "sirvizio"
@ -1150,7 +1206,8 @@ def test_software_example():
name="Word", name="Word",
cpe="cpe:2.3:a:microsoft:word:2000:*:*:*:*:*:*:*", cpe="cpe:2.3:a:microsoft:word:2000:*:*:*:*:*:*:*",
version="2002", version="2002",
vendor="Microsoft") vendor="Microsoft",
)
assert s.name == "Word" assert s.name == "Word"
assert s.cpe == "cpe:2.3:a:microsoft:word:2000:*:*:*:*:*:*:*" assert s.cpe == "cpe:2.3:a:microsoft:word:2000:*:*:*:*:*:*:*"
@ -1177,7 +1234,8 @@ def test_user_account_example():
account_created="2016-01-20T12:31:12Z", account_created="2016-01-20T12:31:12Z",
password_last_changed="2016-01-20T14:27:43Z", password_last_changed="2016-01-20T14:27:43Z",
account_first_login="2016-01-20T14:26:07Z", account_first_login="2016-01-20T14:26:07Z",
account_last_login="2016-07-22T16:08:28Z") account_last_login="2016-07-22T16:08:28Z",
)
assert a.user_id == "1001" assert a.user_id == "1001"
assert a.account_login == "jdoe" assert a.account_login == "jdoe"
@ -1197,12 +1255,14 @@ def test_user_account_unix_account_ext_example():
gid=1001, gid=1001,
groups=["wheel"], groups=["wheel"],
home_dir="/home/jdoe", home_dir="/home/jdoe",
shell="/bin/bash") shell="/bin/bash",
)
a = stix2.v20.UserAccount( a = stix2.v20.UserAccount(
user_id="1001", user_id="1001",
account_login="jdoe", account_login="jdoe",
account_type="unix", account_type="unix",
extensions={'unix-account-ext': u}) extensions={'unix-account-ext': u},
)
assert a.extensions['unix-account-ext'].gid == 1001 assert a.extensions['unix-account-ext'].gid == 1001
assert a.extensions['unix-account-ext'].groups == ["wheel"] assert a.extensions['unix-account-ext'].groups == ["wheel"]
assert a.extensions['unix-account-ext'].home_dir == "/home/jdoe" assert a.extensions['unix-account-ext'].home_dir == "/home/jdoe"
@ -1214,15 +1274,18 @@ def test_windows_registry_key_example():
stix2.v20.WindowsRegistryValueType( stix2.v20.WindowsRegistryValueType(
name="Foo", name="Foo",
data="qwerty", data="qwerty",
data_type="string") data_type="string",
)
v = stix2.v20.WindowsRegistryValueType( v = stix2.v20.WindowsRegistryValueType(
name="Foo", name="Foo",
data="qwerty", data="qwerty",
data_type="REG_SZ") data_type="REG_SZ",
)
w = stix2.v20.WindowsRegistryKey( w = stix2.v20.WindowsRegistryKey(
key="hkey_local_machine\\system\\bar\\foo", key="hkey_local_machine\\system\\bar\\foo",
values=[v]) values=[v],
)
assert w.key == "hkey_local_machine\\system\\bar\\foo" assert w.key == "hkey_local_machine\\system\\bar\\foo"
assert w.values[0].name == "Foo" assert w.values[0].name == "Foo"
assert w.values[0].data == "qwerty" assert w.values[0].data == "qwerty"
@ -1234,7 +1297,8 @@ def test_x509_certificate_example():
issuer="C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Server CA/emailAddress=server-certs@thawte.com", # noqa issuer="C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Server CA/emailAddress=server-certs@thawte.com", # noqa
validity_not_before="2016-03-12T12:00:00Z", validity_not_before="2016-03-12T12:00:00Z",
validity_not_after="2016-08-21T12:00:00Z", validity_not_after="2016-08-21T12:00:00Z",
subject="C=US, ST=Maryland, L=Pasadena, O=Brent Baccala, OU=FreeSoft, CN=www.freesoft.org/emailAddress=baccala@freesoft.org") # noqa subject="C=US, ST=Maryland, L=Pasadena, O=Brent Baccala, OU=FreeSoft, CN=www.freesoft.org/emailAddress=baccala@freesoft.org",
) # noqa
assert x509.type == "x509-certificate" assert x509.type == "x509-certificate"
assert x509.issuer == "C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Server CA/emailAddress=server-certs@thawte.com" # noqa assert x509.issuer == "C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Server CA/emailAddress=server-certs@thawte.com" # noqa
@ -1249,14 +1313,14 @@ def test_new_version_with_related_objects():
objects={ objects={
'src_ip': { 'src_ip': {
'type': 'ipv4-addr', 'type': 'ipv4-addr',
'value': '127.0.0.1/32' 'value': '127.0.0.1/32',
}, },
'domain': { 'domain': {
'type': 'domain-name', 'type': 'domain-name',
'value': 'example.com', 'value': 'example.com',
'resolves_to_refs': ['src_ip'] 'resolves_to_refs': ['src_ip'],
} },
} },
) )
new_version = data.new_version(last_observed="2017-12-12T12:00:00Z") new_version = data.new_version(last_observed="2017-12-12T12:00:00Z")
assert new_version.last_observed.year == 2017 assert new_version.last_observed.year == 2017

View File

@ -7,37 +7,55 @@ import stix2
def test_create_comparison_expression(): def test_create_comparison_expression():
exp = stix2.EqualityComparisonExpression("file:hashes.'SHA-256'", exp = stix2.EqualityComparisonExpression(
stix2.HashConstant("aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f", "SHA-256")) # noqa "file:hashes.'SHA-256'",
stix2.HashConstant("aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f", "SHA-256"),
) # noqa
assert str(exp) == "file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f'" assert str(exp) == "file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f'"
def test_boolean_expression(): def test_boolean_expression():
exp1 = stix2.MatchesComparisonExpression("email-message:from_ref.value", exp1 = stix2.MatchesComparisonExpression(
stix2.StringConstant(".+\\@example\\.com$")) "email-message:from_ref.value",
exp2 = stix2.MatchesComparisonExpression("email-message:body_multipart[*].body_raw_ref.name", stix2.StringConstant(".+\\@example\\.com$"),
stix2.StringConstant("^Final Report.+\\.exe$")) )
exp2 = stix2.MatchesComparisonExpression(
"email-message:body_multipart[*].body_raw_ref.name",
stix2.StringConstant("^Final Report.+\\.exe$"),
)
exp = stix2.AndBooleanExpression([exp1, exp2]) exp = stix2.AndBooleanExpression([exp1, exp2])
assert str(exp) == "email-message:from_ref.value MATCHES '.+\\\\@example\\\\.com$' AND email-message:body_multipart[*].body_raw_ref.name MATCHES '^Final Report.+\\\\.exe$'" # noqa assert str(exp) == "email-message:from_ref.value MATCHES '.+\\\\@example\\\\.com$' AND email-message:body_multipart[*].body_raw_ref.name MATCHES '^Final Report.+\\\\.exe$'" # noqa
def test_boolean_expression_with_parentheses(): def test_boolean_expression_with_parentheses():
exp1 = stix2.MatchesComparisonExpression(stix2.ObjectPath("email-message", exp1 = stix2.MatchesComparisonExpression(
[stix2.ReferenceObjectPathComponent("from_ref"), stix2.ObjectPath(
stix2.BasicObjectPathComponent("value")]), "email-message",
stix2.StringConstant(".+\\@example\\.com$")) [
exp2 = stix2.MatchesComparisonExpression("email-message:body_multipart[*].body_raw_ref.name", stix2.ReferenceObjectPathComponent("from_ref"),
stix2.StringConstant("^Final Report.+\\.exe$")) stix2.BasicObjectPathComponent("value"),
],
),
stix2.StringConstant(".+\\@example\\.com$"),
)
exp2 = stix2.MatchesComparisonExpression(
"email-message:body_multipart[*].body_raw_ref.name",
stix2.StringConstant("^Final Report.+\\.exe$"),
)
exp = stix2.ParentheticalExpression(stix2.AndBooleanExpression([exp1, exp2])) exp = stix2.ParentheticalExpression(stix2.AndBooleanExpression([exp1, exp2]))
assert str(exp) == "(email-message:from_ref.value MATCHES '.+\\\\@example\\\\.com$' AND email-message:body_multipart[*].body_raw_ref.name MATCHES '^Final Report.+\\\\.exe$')" # noqa assert str(exp) == "(email-message:from_ref.value MATCHES '.+\\\\@example\\\\.com$' AND email-message:body_multipart[*].body_raw_ref.name MATCHES '^Final Report.+\\\\.exe$')" # noqa
def test_hash_followed_by_registryKey_expression_python_constant(): def test_hash_followed_by_registryKey_expression_python_constant():
hash_exp = stix2.EqualityComparisonExpression("file:hashes.MD5", hash_exp = stix2.EqualityComparisonExpression(
stix2.HashConstant("79054025255fb1a26e4bc422aef54eb4", "MD5")) "file:hashes.MD5",
stix2.HashConstant("79054025255fb1a26e4bc422aef54eb4", "MD5"),
)
o_exp1 = stix2.ObservationExpression(hash_exp) o_exp1 = stix2.ObservationExpression(hash_exp)
reg_exp = stix2.EqualityComparisonExpression(stix2.ObjectPath("windows-registry-key", ["key"]), reg_exp = stix2.EqualityComparisonExpression(
stix2.StringConstant("HKEY_LOCAL_MACHINE\\foo\\bar")) stix2.ObjectPath("windows-registry-key", ["key"]),
stix2.StringConstant("HKEY_LOCAL_MACHINE\\foo\\bar"),
)
o_exp2 = stix2.ObservationExpression(reg_exp) o_exp2 = stix2.ObservationExpression(reg_exp)
fb_exp = stix2.FollowedByObservationExpression([o_exp1, o_exp2]) fb_exp = stix2.FollowedByObservationExpression([o_exp1, o_exp2])
para_exp = stix2.ParentheticalExpression(fb_exp) para_exp = stix2.ParentheticalExpression(fb_exp)
@ -47,11 +65,15 @@ def test_hash_followed_by_registryKey_expression_python_constant():
def test_hash_followed_by_registryKey_expression(): def test_hash_followed_by_registryKey_expression():
hash_exp = stix2.EqualityComparisonExpression("file:hashes.MD5", hash_exp = stix2.EqualityComparisonExpression(
stix2.HashConstant("79054025255fb1a26e4bc422aef54eb4", "MD5")) "file:hashes.MD5",
stix2.HashConstant("79054025255fb1a26e4bc422aef54eb4", "MD5"),
)
o_exp1 = stix2.ObservationExpression(hash_exp) o_exp1 = stix2.ObservationExpression(hash_exp)
reg_exp = stix2.EqualityComparisonExpression(stix2.ObjectPath("windows-registry-key", ["key"]), reg_exp = stix2.EqualityComparisonExpression(
stix2.StringConstant("HKEY_LOCAL_MACHINE\\foo\\bar")) stix2.ObjectPath("windows-registry-key", ["key"]),
stix2.StringConstant("HKEY_LOCAL_MACHINE\\foo\\bar"),
)
o_exp2 = stix2.ObservationExpression(reg_exp) o_exp2 = stix2.ObservationExpression(reg_exp)
fb_exp = stix2.FollowedByObservationExpression([o_exp1, o_exp2]) fb_exp = stix2.FollowedByObservationExpression([o_exp1, o_exp2])
para_exp = stix2.ParentheticalExpression(fb_exp) para_exp = stix2.ParentheticalExpression(fb_exp)
@ -61,32 +83,45 @@ def test_hash_followed_by_registryKey_expression():
def test_file_observable_expression(): def test_file_observable_expression():
exp1 = stix2.EqualityComparisonExpression("file:hashes.'SHA-256'", exp1 = stix2.EqualityComparisonExpression(
stix2.HashConstant( "file:hashes.'SHA-256'",
"aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f", stix2.HashConstant(
'SHA-256')) "aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f",
'SHA-256',
),
)
exp2 = stix2.EqualityComparisonExpression("file:mime_type", stix2.StringConstant("application/x-pdf")) exp2 = stix2.EqualityComparisonExpression("file:mime_type", stix2.StringConstant("application/x-pdf"))
bool_exp = stix2.AndBooleanExpression([exp1, exp2]) bool_exp = stix2.AndBooleanExpression([exp1, exp2])
exp = stix2.ObservationExpression(bool_exp) exp = stix2.ObservationExpression(bool_exp)
assert str(exp) == "[file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f' AND file:mime_type = 'application/x-pdf']" # noqa assert str(exp) == "[file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f' AND file:mime_type = 'application/x-pdf']" # noqa
@pytest.mark.parametrize("observation_class, op", [ @pytest.mark.parametrize(
(stix2.AndObservationExpression, 'AND'), "observation_class, op", [
(stix2.OrObservationExpression, 'OR'), (stix2.AndObservationExpression, 'AND'),
]) (stix2.OrObservationExpression, 'OR'),
],
)
def test_multiple_file_observable_expression(observation_class, op): def test_multiple_file_observable_expression(observation_class, op):
exp1 = stix2.EqualityComparisonExpression("file:hashes.'SHA-256'", exp1 = stix2.EqualityComparisonExpression(
stix2.HashConstant( "file:hashes.'SHA-256'",
"bf07a7fbb825fc0aae7bf4a1177b2b31fcf8a3feeaf7092761e18c859ee52a9c", stix2.HashConstant(
'SHA-256')) "bf07a7fbb825fc0aae7bf4a1177b2b31fcf8a3feeaf7092761e18c859ee52a9c",
exp2 = stix2.EqualityComparisonExpression("file:hashes.MD5", 'SHA-256',
stix2.HashConstant("cead3f77f6cda6ec00f57d76c9a6879f", "MD5")) ),
)
exp2 = stix2.EqualityComparisonExpression(
"file:hashes.MD5",
stix2.HashConstant("cead3f77f6cda6ec00f57d76c9a6879f", "MD5"),
)
bool1_exp = stix2.OrBooleanExpression([exp1, exp2]) bool1_exp = stix2.OrBooleanExpression([exp1, exp2])
exp3 = stix2.EqualityComparisonExpression("file:hashes.'SHA-256'", exp3 = stix2.EqualityComparisonExpression(
stix2.HashConstant( "file:hashes.'SHA-256'",
"aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f", stix2.HashConstant(
'SHA-256')) "aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f",
'SHA-256',
),
)
op1_exp = stix2.ObservationExpression(bool1_exp) op1_exp = stix2.ObservationExpression(bool1_exp)
op2_exp = stix2.ObservationExpression(exp3) op2_exp = stix2.ObservationExpression(exp3)
exp = observation_class([op1_exp, op2_exp]) exp = observation_class([op1_exp, op2_exp])
@ -96,111 +131,177 @@ def test_multiple_file_observable_expression(observation_class, op):
def test_root_types(): def test_root_types():
ast = stix2.ObservationExpression( ast = stix2.ObservationExpression(
stix2.AndBooleanExpression( stix2.AndBooleanExpression(
[stix2.ParentheticalExpression( [
stix2.OrBooleanExpression([ stix2.ParentheticalExpression(
stix2.EqualityComparisonExpression("a:b", stix2.StringConstant("1")), stix2.OrBooleanExpression([
stix2.EqualityComparisonExpression("b:c", stix2.StringConstant("2"))])), stix2.EqualityComparisonExpression("a:b", stix2.StringConstant("1")),
stix2.EqualityComparisonExpression(u"b:d", stix2.StringConstant("3"))])) stix2.EqualityComparisonExpression("b:c", stix2.StringConstant("2")),
]),
),
stix2.EqualityComparisonExpression(u"b:d", stix2.StringConstant("3")),
],
),
)
assert str(ast) == "[(a:b = '1' OR b:c = '2') AND b:d = '3']" assert str(ast) == "[(a:b = '1' OR b:c = '2') AND b:d = '3']"
def test_artifact_payload(): def test_artifact_payload():
exp1 = stix2.EqualityComparisonExpression("artifact:mime_type", exp1 = stix2.EqualityComparisonExpression(
"application/vnd.tcpdump.pcap") "artifact:mime_type",
exp2 = stix2.MatchesComparisonExpression("artifact:payload_bin", "application/vnd.tcpdump.pcap",
stix2.StringConstant("\\xd4\\xc3\\xb2\\xa1\\x02\\x00\\x04\\x00")) )
exp2 = stix2.MatchesComparisonExpression(
"artifact:payload_bin",
stix2.StringConstant("\\xd4\\xc3\\xb2\\xa1\\x02\\x00\\x04\\x00"),
)
and_exp = stix2.AndBooleanExpression([exp1, exp2]) and_exp = stix2.AndBooleanExpression([exp1, exp2])
exp = stix2.ObservationExpression(and_exp) exp = stix2.ObservationExpression(and_exp)
assert str(exp) == "[artifact:mime_type = 'application/vnd.tcpdump.pcap' AND artifact:payload_bin MATCHES '\\\\xd4\\\\xc3\\\\xb2\\\\xa1\\\\x02\\\\x00\\\\x04\\\\x00']" # noqa assert str(exp) == "[artifact:mime_type = 'application/vnd.tcpdump.pcap' AND artifact:payload_bin MATCHES '\\\\xd4\\\\xc3\\\\xb2\\\\xa1\\\\x02\\\\x00\\\\x04\\\\x00']" # noqa
def test_greater_than_python_constant(): def test_greater_than_python_constant():
exp1 = stix2.GreaterThanComparisonExpression("file:extensions.windows-pebinary-ext.sections[*].entropy", exp1 = stix2.GreaterThanComparisonExpression(
7.0) "file:extensions.windows-pebinary-ext.sections[*].entropy",
7.0,
)
exp = stix2.ObservationExpression(exp1) exp = stix2.ObservationExpression(exp1)
assert str(exp) == "[file:extensions.windows-pebinary-ext.sections[*].entropy > 7.0]" assert str(exp) == "[file:extensions.windows-pebinary-ext.sections[*].entropy > 7.0]"
def test_greater_than(): def test_greater_than():
exp1 = stix2.GreaterThanComparisonExpression("file:extensions.windows-pebinary-ext.sections[*].entropy", exp1 = stix2.GreaterThanComparisonExpression(
stix2.FloatConstant(7.0)) "file:extensions.windows-pebinary-ext.sections[*].entropy",
stix2.FloatConstant(7.0),
)
exp = stix2.ObservationExpression(exp1) exp = stix2.ObservationExpression(exp1)
assert str(exp) == "[file:extensions.windows-pebinary-ext.sections[*].entropy > 7.0]" assert str(exp) == "[file:extensions.windows-pebinary-ext.sections[*].entropy > 7.0]"
def test_less_than(): def test_less_than():
exp = stix2.LessThanComparisonExpression("file:size", exp = stix2.LessThanComparisonExpression(
1024) "file:size",
1024,
)
assert str(exp) == "file:size < 1024" assert str(exp) == "file:size < 1024"
def test_greater_than_or_equal(): def test_greater_than_or_equal():
exp = stix2.GreaterThanEqualComparisonExpression("file:size", exp = stix2.GreaterThanEqualComparisonExpression(
1024) "file:size",
1024,
)
assert str(exp) == "file:size >= 1024" assert str(exp) == "file:size >= 1024"
def test_less_than_or_equal(): def test_less_than_or_equal():
exp = stix2.LessThanEqualComparisonExpression("file:size", exp = stix2.LessThanEqualComparisonExpression(
1024) "file:size",
1024,
)
assert str(exp) == "file:size <= 1024" assert str(exp) == "file:size <= 1024"
def test_not(): def test_not():
exp = stix2.LessThanComparisonExpression("file:size", exp = stix2.LessThanComparisonExpression(
1024, "file:size",
negated=True) 1024,
negated=True,
)
assert str(exp) == "file:size NOT < 1024" assert str(exp) == "file:size NOT < 1024"
def test_and_observable_expression(): def test_and_observable_expression():
exp1 = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("user-account:account_type", exp1 = stix2.AndBooleanExpression([
"unix"), stix2.EqualityComparisonExpression(
stix2.EqualityComparisonExpression("user-account:user_id", "user-account:account_type",
stix2.StringConstant("1007")), "unix",
stix2.EqualityComparisonExpression("user-account:account_login", ),
"Peter")]) stix2.EqualityComparisonExpression(
exp2 = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("user-account:account_type", "user-account:user_id",
"unix"), stix2.StringConstant("1007"),
stix2.EqualityComparisonExpression("user-account:user_id", ),
stix2.StringConstant("1008")), stix2.EqualityComparisonExpression(
stix2.EqualityComparisonExpression("user-account:account_login", "user-account:account_login",
"Paul")]) "Peter",
exp3 = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("user-account:account_type", ),
"unix"), ])
stix2.EqualityComparisonExpression("user-account:user_id", exp2 = stix2.AndBooleanExpression([
stix2.StringConstant("1009")), stix2.EqualityComparisonExpression(
stix2.EqualityComparisonExpression("user-account:account_login", "user-account:account_type",
"Mary")]) "unix",
exp = stix2.AndObservationExpression([stix2.ObservationExpression(exp1), ),
stix2.ObservationExpression(exp2), stix2.EqualityComparisonExpression(
stix2.ObservationExpression(exp3)]) "user-account:user_id",
stix2.StringConstant("1008"),
),
stix2.EqualityComparisonExpression(
"user-account:account_login",
"Paul",
),
])
exp3 = stix2.AndBooleanExpression([
stix2.EqualityComparisonExpression(
"user-account:account_type",
"unix",
),
stix2.EqualityComparisonExpression(
"user-account:user_id",
stix2.StringConstant("1009"),
),
stix2.EqualityComparisonExpression(
"user-account:account_login",
"Mary",
),
])
exp = stix2.AndObservationExpression([
stix2.ObservationExpression(exp1),
stix2.ObservationExpression(exp2),
stix2.ObservationExpression(exp3),
])
assert str(exp) == "[user-account:account_type = 'unix' AND user-account:user_id = '1007' AND user-account:account_login = 'Peter'] AND [user-account:account_type = 'unix' AND user-account:user_id = '1008' AND user-account:account_login = 'Paul'] AND [user-account:account_type = 'unix' AND user-account:user_id = '1009' AND user-account:account_login = 'Mary']" # noqa assert str(exp) == "[user-account:account_type = 'unix' AND user-account:user_id = '1007' AND user-account:account_login = 'Peter'] AND [user-account:account_type = 'unix' AND user-account:user_id = '1008' AND user-account:account_login = 'Paul'] AND [user-account:account_type = 'unix' AND user-account:user_id = '1009' AND user-account:account_login = 'Mary']" # noqa
def test_invalid_and_observable_expression(): def test_invalid_and_observable_expression():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("user-account:display_name", stix2.AndBooleanExpression([
"admin"), stix2.EqualityComparisonExpression(
stix2.EqualityComparisonExpression("email-addr:display_name", "user-account:display_name",
stix2.StringConstant("admin"))]) "admin",
),
stix2.EqualityComparisonExpression(
"email-addr:display_name",
stix2.StringConstant("admin"),
),
])
assert "All operands to an 'AND' expression must have the same object type" in str(excinfo) assert "All operands to an 'AND' expression must have the same object type" in str(excinfo)
def test_hex(): def test_hex():
exp_and = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("file:mime_type", exp_and = stix2.AndBooleanExpression([
"image/bmp"), stix2.EqualityComparisonExpression(
stix2.EqualityComparisonExpression("file:magic_number_hex", "file:mime_type",
stix2.HexConstant("ffd8"))]) "image/bmp",
),
stix2.EqualityComparisonExpression(
"file:magic_number_hex",
stix2.HexConstant("ffd8"),
),
])
exp = stix2.ObservationExpression(exp_and) exp = stix2.ObservationExpression(exp_and)
assert str(exp) == "[file:mime_type = 'image/bmp' AND file:magic_number_hex = h'ffd8']" assert str(exp) == "[file:mime_type = 'image/bmp' AND file:magic_number_hex = h'ffd8']"
def test_multiple_qualifiers(): def test_multiple_qualifiers():
exp_and = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("network-traffic:dst_ref.type", exp_and = stix2.AndBooleanExpression([
"domain-name"), stix2.EqualityComparisonExpression(
stix2.EqualityComparisonExpression("network-traffic:dst_ref.value", "network-traffic:dst_ref.type",
"example.com")]) "domain-name",
),
stix2.EqualityComparisonExpression(
"network-traffic:dst_ref.value",
"example.com",
),
])
exp_ob = stix2.ObservationExpression(exp_and) exp_ob = stix2.ObservationExpression(exp_and)
qual_rep = stix2.RepeatQualifier(5) qual_rep = stix2.RepeatQualifier(5)
qual_within = stix2.WithinQualifier(stix2.IntegerConstant(1800)) qual_within = stix2.WithinQualifier(stix2.IntegerConstant(1800))
@ -209,8 +310,10 @@ def test_multiple_qualifiers():
def test_set_op(): def test_set_op():
exp = stix2.ObservationExpression(stix2.IsSubsetComparisonExpression("network-traffic:dst_ref.value", exp = stix2.ObservationExpression(stix2.IsSubsetComparisonExpression(
"2001:0db8:dead:beef:0000:0000:0000:0000/64")) "network-traffic:dst_ref.value",
"2001:0db8:dead:beef:0000:0000:0000:0000/64",
))
assert str(exp) == "[network-traffic:dst_ref.value ISSUBSET '2001:0db8:dead:beef:0000:0000:0000:0000/64']" assert str(exp) == "[network-traffic:dst_ref.value ISSUBSET '2001:0db8:dead:beef:0000:0000:0000:0000/64']"
@ -220,35 +323,45 @@ def test_timestamp():
def test_boolean(): def test_boolean():
exp = stix2.EqualityComparisonExpression("email-message:is_multipart", exp = stix2.EqualityComparisonExpression(
True) "email-message:is_multipart",
True,
)
assert str(exp) == "email-message:is_multipart = true" assert str(exp) == "email-message:is_multipart = true"
def test_binary(): def test_binary():
const = stix2.BinaryConstant("dGhpcyBpcyBhIHRlc3Q=") const = stix2.BinaryConstant("dGhpcyBpcyBhIHRlc3Q=")
exp = stix2.EqualityComparisonExpression("artifact:payload_bin", exp = stix2.EqualityComparisonExpression(
const) "artifact:payload_bin",
const,
)
assert str(exp) == "artifact:payload_bin = b'dGhpcyBpcyBhIHRlc3Q='" assert str(exp) == "artifact:payload_bin = b'dGhpcyBpcyBhIHRlc3Q='"
def test_list(): def test_list():
exp = stix2.InComparisonExpression("process:name", exp = stix2.InComparisonExpression(
['proccy', 'proximus', 'badproc']) "process:name",
['proccy', 'proximus', 'badproc'],
)
assert str(exp) == "process:name IN ('proccy', 'proximus', 'badproc')" assert str(exp) == "process:name IN ('proccy', 'proximus', 'badproc')"
def test_list2(): def test_list2():
# alternate way to construct an "IN" Comparison Expression # alternate way to construct an "IN" Comparison Expression
exp = stix2.EqualityComparisonExpression("process:name", exp = stix2.EqualityComparisonExpression(
['proccy', 'proximus', 'badproc']) "process:name",
['proccy', 'proximus', 'badproc'],
)
assert str(exp) == "process:name IN ('proccy', 'proximus', 'badproc')" assert str(exp) == "process:name IN ('proccy', 'proximus', 'badproc')"
def test_invalid_constant_type(): def test_invalid_constant_type():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
stix2.EqualityComparisonExpression("artifact:payload_bin", stix2.EqualityComparisonExpression(
{'foo': 'bar'}) "artifact:payload_bin",
{'foo': 'bar'},
)
assert 'Unable to create a constant' in str(excinfo) assert 'Unable to create a constant' in str(excinfo)
@ -270,20 +383,22 @@ def test_invalid_float_constant():
assert 'must be a float' in str(excinfo) assert 'must be a float' in str(excinfo)
@pytest.mark.parametrize("data, result", [ @pytest.mark.parametrize(
(True, True), "data, result", [
(False, False), (True, True),
('True', True), (False, False),
('False', False), ('True', True),
('true', True), ('False', False),
('false', False), ('true', True),
('t', True), ('false', False),
('f', False), ('t', True),
('T', True), ('f', False),
('F', False), ('T', True),
(1, True), ('F', False),
(0, False), (1, True),
]) (0, False),
],
)
def test_boolean_constant(data, result): def test_boolean_constant(data, result):
boolean = stix2.BooleanConstant(data) boolean = stix2.BooleanConstant(data)
assert boolean.value == result assert boolean.value == result
@ -295,10 +410,12 @@ def test_invalid_boolean_constant():
assert 'must be a boolean' in str(excinfo) assert 'must be a boolean' in str(excinfo)
@pytest.mark.parametrize("hashtype, data", [ @pytest.mark.parametrize(
('MD5', 'zzz'), "hashtype, data", [
('ssdeep', 'zzz=='), ('MD5', 'zzz'),
]) ('ssdeep', 'zzz=='),
],
)
def test_invalid_hash_constant(hashtype, data): def test_invalid_hash_constant(hashtype, data):
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
stix2.HashConstant(data, hashtype) stix2.HashConstant(data, hashtype)
@ -318,20 +435,26 @@ def test_invalid_binary_constant():
def test_escape_quotes_and_backslashes(): def test_escape_quotes_and_backslashes():
exp = stix2.MatchesComparisonExpression("file:name", exp = stix2.MatchesComparisonExpression(
"^Final Report.+\\.exe$") "file:name",
"^Final Report.+\\.exe$",
)
assert str(exp) == "file:name MATCHES '^Final Report.+\\\\.exe$'" assert str(exp) == "file:name MATCHES '^Final Report.+\\\\.exe$'"
def test_like(): def test_like():
exp = stix2.LikeComparisonExpression("directory:path", exp = stix2.LikeComparisonExpression(
"C:\\Windows\\%\\foo") "directory:path",
"C:\\Windows\\%\\foo",
)
assert str(exp) == "directory:path LIKE 'C:\\\\Windows\\\\%\\\\foo'" assert str(exp) == "directory:path LIKE 'C:\\\\Windows\\\\%\\\\foo'"
def test_issuperset(): def test_issuperset():
exp = stix2.IsSupersetComparisonExpression("ipv4-addr:value", exp = stix2.IsSupersetComparisonExpression(
"198.51.100.0/24") "ipv4-addr:value",
"198.51.100.0/24",
)
assert str(exp) == "ipv4-addr:value ISSUPERSET '198.51.100.0/24'" assert str(exp) == "ipv4-addr:value ISSUPERSET '198.51.100.0/24'"
@ -353,24 +476,32 @@ def test_invalid_within_qualifier():
def test_startstop_qualifier(): def test_startstop_qualifier():
qual = stix2.StartStopQualifier(stix2.TimestampConstant('2016-06-01T00:00:00Z'), qual = stix2.StartStopQualifier(
datetime.datetime(2017, 3, 12, 8, 30, 0)) stix2.TimestampConstant('2016-06-01T00:00:00Z'),
datetime.datetime(2017, 3, 12, 8, 30, 0),
)
assert str(qual) == "START t'2016-06-01T00:00:00Z' STOP t'2017-03-12T08:30:00Z'" assert str(qual) == "START t'2016-06-01T00:00:00Z' STOP t'2017-03-12T08:30:00Z'"
qual2 = stix2.StartStopQualifier(datetime.date(2016, 6, 1), qual2 = stix2.StartStopQualifier(
stix2.TimestampConstant('2016-07-01T00:00:00Z')) datetime.date(2016, 6, 1),
stix2.TimestampConstant('2016-07-01T00:00:00Z'),
)
assert str(qual2) == "START t'2016-06-01T00:00:00Z' STOP t'2016-07-01T00:00:00Z'" assert str(qual2) == "START t'2016-06-01T00:00:00Z' STOP t'2016-07-01T00:00:00Z'"
def test_invalid_startstop_qualifier(): def test_invalid_startstop_qualifier():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
stix2.StartStopQualifier('foo', stix2.StartStopQualifier(
stix2.TimestampConstant('2016-06-01T00:00:00Z')) 'foo',
stix2.TimestampConstant('2016-06-01T00:00:00Z'),
)
assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo) assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo)
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
stix2.StartStopQualifier(datetime.date(2016, 6, 1), stix2.StartStopQualifier(
'foo') datetime.date(2016, 6, 1),
'foo',
)
assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo) assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo)

View File

@ -11,7 +11,7 @@ def test_pickling():
id="identity--d66cb89d-5228-4983-958c-fa84ef75c88c", id="identity--d66cb89d-5228-4983-958c-fa84ef75c88c",
name="alice", name="alice",
description="this is a pickle test", description="this is a pickle test",
identity_class="some_class" identity_class="some_class",
) )
pickle.loads(pickle.dumps(identity)) pickle.loads(pickle.dumps(identity))

View File

@ -4,14 +4,13 @@ import pytest
import stix2 import stix2
from stix2.exceptions import AtLeastOnePropertyError, DictionaryKeyError from stix2.exceptions import AtLeastOnePropertyError, DictionaryKeyError
from stix2.properties import (ERROR_INVALID_ID, BinaryProperty, from stix2.properties import (
BooleanProperty, DictionaryProperty, ERROR_INVALID_ID, BinaryProperty, BooleanProperty, DictionaryProperty,
EmbeddedObjectProperty, EnumProperty, EmbeddedObjectProperty, EnumProperty, ExtensionsProperty, FloatProperty,
ExtensionsProperty, FloatProperty, HashesProperty, HexProperty, IDProperty, IntegerProperty, ListProperty,
HashesProperty, HexProperty, IDProperty, Property, ReferenceProperty, StringProperty, TimestampProperty,
IntegerProperty, ListProperty, Property, TypeProperty,
ReferenceProperty, StringProperty, )
TimestampProperty, TypeProperty)
from . import constants from . import constants
@ -93,10 +92,12 @@ ID_PROP = IDProperty('my-type')
MY_ID = 'my-type--232c9d3f-49fc-4440-bb01-607f638778e7' MY_ID = 'my-type--232c9d3f-49fc-4440-bb01-607f638778e7'
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
MY_ID, "value", [
'my-type--00000000-0000-4000-8000-000000000000', MY_ID,
]) 'my-type--00000000-0000-4000-8000-000000000000',
],
)
def test_id_property_valid(value): def test_id_property_valid(value):
assert ID_PROP.clean(value) == value assert ID_PROP.clean(value) == value
@ -134,14 +135,16 @@ def test_id_property_wrong_type():
assert str(excinfo.value) == "must start with 'my-type--'." assert str(excinfo.value) == "must start with 'my-type--'."
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
'my-type--foo', "value", [
# Not a v4 UUID 'my-type--foo',
'my-type--00000000-0000-0000-0000-000000000000', # Not a v4 UUID
'my-type--' + str(uuid.uuid1()), 'my-type--00000000-0000-0000-0000-000000000000',
'my-type--' + str(uuid.uuid3(uuid.NAMESPACE_DNS, "example.org")), 'my-type--' + str(uuid.uuid1()),
'my-type--' + str(uuid.uuid5(uuid.NAMESPACE_DNS, "example.org")), 'my-type--' + str(uuid.uuid3(uuid.NAMESPACE_DNS, "example.org")),
]) 'my-type--' + str(uuid.uuid5(uuid.NAMESPACE_DNS, "example.org")),
],
)
def test_id_property_not_a_valid_hex_uuid(value): def test_id_property_not_a_valid_hex_uuid(value):
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
ID_PROP.clean(value) ID_PROP.clean(value)
@ -153,77 +156,89 @@ def test_id_property_default():
assert ID_PROP.clean(default) == default assert ID_PROP.clean(default) == default
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
2, "value", [
-1, 2,
3.14, -1,
False, 3.14,
]) False,
],
)
def test_integer_property_valid(value): def test_integer_property_valid(value):
int_prop = IntegerProperty() int_prop = IntegerProperty()
assert int_prop.clean(value) is not None assert int_prop.clean(value) is not None
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
"something", "value", [
StringProperty(), "something",
]) StringProperty(),
],
)
def test_integer_property_invalid(value): def test_integer_property_invalid(value):
int_prop = IntegerProperty() int_prop = IntegerProperty()
with pytest.raises(ValueError): with pytest.raises(ValueError):
int_prop.clean(value) int_prop.clean(value)
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
2, "value", [
-1, 2,
3.14, -1,
False, 3.14,
]) False,
],
)
def test_float_property_valid(value): def test_float_property_valid(value):
int_prop = FloatProperty() int_prop = FloatProperty()
assert int_prop.clean(value) is not None assert int_prop.clean(value) is not None
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
"something", "value", [
StringProperty(), "something",
]) StringProperty(),
],
)
def test_float_property_invalid(value): def test_float_property_invalid(value):
int_prop = FloatProperty() int_prop = FloatProperty()
with pytest.raises(ValueError): with pytest.raises(ValueError):
int_prop.clean(value) int_prop.clean(value)
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
True, "value", [
False, True,
'True', False,
'False', 'True',
'true', 'False',
'false', 'true',
'TRUE', 'false',
'FALSE', 'TRUE',
'T', 'FALSE',
'F', 'T',
't', 'F',
'f', 't',
1, 'f',
0, 1,
]) 0,
],
)
def test_boolean_property_valid(value): def test_boolean_property_valid(value):
bool_prop = BooleanProperty() bool_prop = BooleanProperty()
assert bool_prop.clean(value) is not None assert bool_prop.clean(value) is not None
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
'abc', "value", [
['false'], 'abc',
{'true': 'true'}, ['false'],
2, {'true': 'true'},
-1, 2,
]) -1,
],
)
def test_boolean_property_invalid(value): def test_boolean_property_invalid(value):
bool_prop = BooleanProperty() bool_prop = BooleanProperty()
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -242,11 +257,13 @@ def test_reference_property():
ref_prop.clean("my-type--00000000-0000-0000-0000-000000000000") ref_prop.clean("my-type--00000000-0000-0000-0000-000000000000")
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
'2017-01-01T12:34:56Z', "value", [
'2017-01-01 12:34:56', '2017-01-01T12:34:56Z',
'Jan 1 2017 12:34:56', '2017-01-01 12:34:56',
]) 'Jan 1 2017 12:34:56',
],
)
def test_timestamp_property_valid(value): def test_timestamp_property_valid(value):
ts_prop = TimestampProperty() ts_prop = TimestampProperty()
assert ts_prop.clean(value) == constants.FAKE_TIME assert ts_prop.clean(value) == constants.FAKE_TIME
@ -276,25 +293,33 @@ def test_hex_property():
hex_prop.clean("foobar") hex_prop.clean("foobar")
@pytest.mark.parametrize("d", [ @pytest.mark.parametrize(
{'description': 'something'}, "d", [
[('abc', 1), ('bcd', 2), ('cde', 3)], {'description': 'something'},
]) [('abc', 1), ('bcd', 2), ('cde', 3)],
],
)
def test_dictionary_property_valid(d): def test_dictionary_property_valid(d):
dict_prop = DictionaryProperty() dict_prop = DictionaryProperty()
assert dict_prop.clean(d) assert dict_prop.clean(d)
@pytest.mark.parametrize("d", [ @pytest.mark.parametrize(
[{'a': 'something'}, "Invalid dictionary key a: (shorter than 3 characters)."], "d", [
[{'a'*300: 'something'}, "Invalid dictionary key aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" [{'a': 'something'}, "Invalid dictionary key a: (shorter than 3 characters)."],
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" [
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" {'a'*300: 'something'}, "Invalid dictionary key aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaa: (longer than 256 characters)."], "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
[{'Hey!': 'something'}, "Invalid dictionary key Hey!: (contains characters other than lowercase a-z, " "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"uppercase A-Z, numerals 0-9, hyphen (-), or underscore (_))."], "aaaaaaaaaaaaaaaaaaaaaaa: (longer than 256 characters).",
]) ],
[
{'Hey!': 'something'}, "Invalid dictionary key Hey!: (contains characters other than lowercase a-z, "
"uppercase A-Z, numerals 0-9, hyphen (-), or underscore (_)).",
],
],
)
def test_dictionary_property_invalid_key(d): def test_dictionary_property_invalid_key(d):
dict_prop = DictionaryProperty() dict_prop = DictionaryProperty()
@ -304,18 +329,20 @@ def test_dictionary_property_invalid_key(d):
assert str(excinfo.value) == d[1] assert str(excinfo.value) == d[1]
@pytest.mark.parametrize("d", [ @pytest.mark.parametrize(
({}, "The dictionary property must contain a non-empty dictionary"), "d", [
# TODO: This error message could be made more helpful. The error is caused ({}, "The dictionary property must contain a non-empty dictionary"),
# because `json.loads()` doesn't like the *single* quotes around the key # TODO: This error message could be made more helpful. The error is caused
# name, even though they are valid in a Python dictionary. While technically # because `json.loads()` doesn't like the *single* quotes around the key
# accurate (a string is not a dictionary), if we want to be able to load # name, even though they are valid in a Python dictionary. While technically
# string-encoded "dictionaries" that are, we need a better error message # accurate (a string is not a dictionary), if we want to be able to load
# or an alternative to `json.loads()` ... and preferably *not* `eval()`. :-) # string-encoded "dictionaries" that are, we need a better error message
# Changing the following to `'{"description": "something"}'` does not cause # or an alternative to `json.loads()` ... and preferably *not* `eval()`. :-)
# any ValueError to be raised. # Changing the following to `'{"description": "something"}'` does not cause
("{'description': 'something'}", "The dictionary property must contain a dictionary"), # any ValueError to be raised.
]) ("{'description': 'something'}", "The dictionary property must contain a dictionary"),
],
)
def test_dictionary_property_invalid(d): def test_dictionary_property_invalid(d):
dict_prop = DictionaryProperty() dict_prop = DictionaryProperty()
@ -325,9 +352,11 @@ def test_dictionary_property_invalid(d):
def test_property_list_of_dictionary(): def test_property_list_of_dictionary():
@stix2.v20.CustomObject('x-new-obj', [ @stix2.v20.CustomObject(
('property1', ListProperty(DictionaryProperty(), required=True)), 'x-new-obj', [
]) ('property1', ListProperty(DictionaryProperty(), required=True)),
],
)
class NewObj(): class NewObj():
pass pass
@ -335,19 +364,23 @@ def test_property_list_of_dictionary():
assert test_obj.property1[0]['foo'] == 'bar' assert test_obj.property1[0]['foo'] == 'bar'
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
{"sha256": "6db12788c37247f2316052e142f42f4b259d6561751e5f401a1ae2a6df9c674b"}, "value", [
[('MD5', '2dfb1bcc980200c6706feee399d41b3f'), ('RIPEMD-160', 'b3a8cd8a27c90af79b3c81754f267780f443dfef')], {"sha256": "6db12788c37247f2316052e142f42f4b259d6561751e5f401a1ae2a6df9c674b"},
]) [('MD5', '2dfb1bcc980200c6706feee399d41b3f'), ('RIPEMD-160', 'b3a8cd8a27c90af79b3c81754f267780f443dfef')],
],
)
def test_hashes_property_valid(value): def test_hashes_property_valid(value):
hash_prop = HashesProperty() hash_prop = HashesProperty()
assert hash_prop.clean(value) assert hash_prop.clean(value)
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
{"MD5": "a"}, "value", [
{"SHA-256": "2dfb1bcc980200c6706feee399d41b3f"}, {"MD5": "a"},
]) {"SHA-256": "2dfb1bcc980200c6706feee399d41b3f"},
],
)
def test_hashes_property_invalid(value): def test_hashes_property_invalid(value):
hash_prop = HashesProperty() hash_prop = HashesProperty()
@ -360,7 +393,7 @@ def test_embedded_property():
mime = stix2.v20.EmailMIMEComponent( mime = stix2.v20.EmailMIMEComponent(
content_type="text/plain; charset=utf-8", content_type="text/plain; charset=utf-8",
content_disposition="inline", content_disposition="inline",
body="Cats are funny!" body="Cats are funny!",
) )
assert emb_prop.clean(mime) assert emb_prop.clean(mime)
@ -368,11 +401,13 @@ def test_embedded_property():
emb_prop.clean("string") emb_prop.clean("string")
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
['a', 'b', 'c'], "value", [
('a', 'b', 'c'), ['a', 'b', 'c'],
'b', ('a', 'b', 'c'),
]) 'b',
],
)
def test_enum_property_valid(value): def test_enum_property_valid(value):
enum_prop = EnumProperty(value) enum_prop = EnumProperty(value)
assert enum_prop.clean('b') assert enum_prop.clean('b')
@ -388,17 +423,19 @@ def test_extension_property_valid():
ext_prop = ExtensionsProperty(enclosing_type='file') ext_prop = ExtensionsProperty(enclosing_type='file')
assert ext_prop({ assert ext_prop({
'windows-pebinary-ext': { 'windows-pebinary-ext': {
'pe_type': 'exe' 'pe_type': 'exe',
}, },
}) })
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
1, "data", [
{'foobar-ext': { 1,
'pe_type': 'exe' {'foobar-ext': {
}}, 'pe_type': 'exe',
]) }},
],
)
def test_extension_property_invalid(data): def test_extension_property_invalid(data):
ext_prop = ExtensionsProperty(enclosing_type='file') ext_prop = ExtensionsProperty(enclosing_type='file')
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -408,10 +445,12 @@ def test_extension_property_invalid(data):
def test_extension_property_invalid_type(): def test_extension_property_invalid_type():
ext_prop = ExtensionsProperty(enclosing_type='indicator') ext_prop = ExtensionsProperty(enclosing_type='indicator')
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
ext_prop.clean({ ext_prop.clean(
'windows-pebinary-ext': { {
'pe_type': 'exe' 'windows-pebinary-ext': {
}} 'pe_type': 'exe',
},
},
) )
assert 'no extensions defined' in str(excinfo.value) assert 'no extensions defined' in str(excinfo.value)

View File

@ -5,8 +5,9 @@ import pytz
import stix2 import stix2
from .constants import (FAKE_TIME, INDICATOR_ID, MALWARE_ID, RELATIONSHIP_ID, from .constants import (
RELATIONSHIP_KWARGS) FAKE_TIME, INDICATOR_ID, MALWARE_ID, RELATIONSHIP_ID, RELATIONSHIP_KWARGS,
)
EXPECTED_RELATIONSHIP = """{ EXPECTED_RELATIONSHIP = """{
"type": "relationship", "type": "relationship",
@ -91,7 +92,7 @@ def test_relationship_required_properties_target_ref():
with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo: with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo:
stix2.v20.Relationship( stix2.v20.Relationship(
relationship_type='indicates', relationship_type='indicates',
source_ref=INDICATOR_ID source_ref=INDICATOR_ID,
) )
assert excinfo.value.cls == stix2.v20.Relationship assert excinfo.value.cls == stix2.v20.Relationship
@ -136,18 +137,20 @@ def test_create_relationship_with_positional_args(indicator, malware):
assert rel.id == 'relationship--00000000-0000-4000-8000-000000000005' assert rel.id == 'relationship--00000000-0000-4000-8000-000000000005'
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED_RELATIONSHIP, "data", [
{ EXPECTED_RELATIONSHIP,
"created": "2016-04-06T20:06:37Z", {
"id": "relationship--df7c87eb-75d2-4948-af81-9d49d246f301", "created": "2016-04-06T20:06:37Z",
"modified": "2016-04-06T20:06:37Z", "id": "relationship--df7c87eb-75d2-4948-af81-9d49d246f301",
"relationship_type": "indicates", "modified": "2016-04-06T20:06:37Z",
"source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", "relationship_type": "indicates",
"target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e", "source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
"type": "relationship" "target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
}, "type": "relationship",
]) },
],
)
def test_parse_relationship(data): def test_parse_relationship(data):
rel = stix2.parse(data, version="2.0") rel = stix2.parse(data, version="2.0")

View File

@ -40,7 +40,7 @@ def test_report_example():
object_refs=[ object_refs=[
"indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", "indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2",
"campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c",
"relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a" "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a",
], ],
) )
@ -60,7 +60,7 @@ def test_report_example_objects_in_object_refs():
object_refs=[ object_refs=[
stix2.v20.Indicator(id="indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", **INDICATOR_KWARGS), stix2.v20.Indicator(id="indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", **INDICATOR_KWARGS),
"campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c",
"relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a" "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a",
], ],
) )
@ -81,7 +81,7 @@ def test_report_example_objects_in_object_refs_with_bad_id():
object_refs=[ object_refs=[
stix2.v20.Indicator(id="indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", **INDICATOR_KWARGS), stix2.v20.Indicator(id="indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", **INDICATOR_KWARGS),
"campaign-83422c77-904c-4dc1-aff5-5c38f3a2c55c", # the "bad" id, missing a "-" "campaign-83422c77-904c-4dc1-aff5-5c38f3a2c55c", # the "bad" id, missing a "-"
"relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a" "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a",
], ],
) )
@ -91,27 +91,29 @@ def test_report_example_objects_in_object_refs_with_bad_id():
assert str(excinfo.value) == "Invalid value for Report 'object_refs': " + stix2.properties.ERROR_INVALID_ID assert str(excinfo.value) == "Invalid value for Report 'object_refs': " + stix2.properties.ERROR_INVALID_ID
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"created": "2015-12-21T19:59:11.000Z", {
"created_by_ref": "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283", "created": "2015-12-21T19:59:11.000Z",
"description": "A simple report with an indicator and campaign", "created_by_ref": "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283",
"id": "report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3", "description": "A simple report with an indicator and campaign",
"labels": [ "id": "report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3",
"campaign" "labels": [
], "campaign",
"modified": "2015-12-21T19:59:11.000Z", ],
"name": "The Black Vine Cyberespionage Group", "modified": "2015-12-21T19:59:11.000Z",
"object_refs": [ "name": "The Black Vine Cyberespionage Group",
"indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", "object_refs": [
"campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", "indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2",
"relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a" "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c",
], "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a",
"published": "2016-01-20T17:00:00Z", ],
"type": "report" "published": "2016-01-20T17:00:00Z",
}, "type": "report",
]) },
],
)
def test_parse_report(data): def test_parse_report(data):
rept = stix2.parse(data, version="2.0") rept = stix2.parse(data, version="2.0")
@ -120,9 +122,11 @@ def test_parse_report(data):
assert rept.created == dt.datetime(2015, 12, 21, 19, 59, 11, tzinfo=pytz.utc) assert rept.created == dt.datetime(2015, 12, 21, 19, 59, 11, tzinfo=pytz.utc)
assert rept.modified == dt.datetime(2015, 12, 21, 19, 59, 11, tzinfo=pytz.utc) assert rept.modified == dt.datetime(2015, 12, 21, 19, 59, 11, tzinfo=pytz.utc)
assert rept.created_by_ref == "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283" assert rept.created_by_ref == "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283"
assert rept.object_refs == ["indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", assert rept.object_refs == [
"campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", "indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2",
"relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a"] "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c",
"relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a",
]
assert rept.description == "A simple report with an indicator and campaign" assert rept.description == "A simple report with an indicator and campaign"
assert rept.labels == ["campaign"] assert rept.labels == ["campaign"]
assert rept.name == "The Black Vine Cyberespionage Group" assert rept.name == "The Black Vine Cyberespionage Group"

View File

@ -39,7 +39,7 @@ def test_sighting_all_required_properties():
created=now, created=now,
modified=now, modified=now,
sighting_of_ref=INDICATOR_ID, sighting_of_ref=INDICATOR_ID,
where_sighted_refs=["identity--8cc7afd6-5455-4d2b-a736-e614ee631d99"] where_sighted_refs=["identity--8cc7afd6-5455-4d2b-a736-e614ee631d99"],
) )
assert str(s) == EXPECTED_SIGHTING assert str(s) == EXPECTED_SIGHTING
@ -54,7 +54,7 @@ def test_sighting_bad_where_sighted_refs():
created=now, created=now,
modified=now, modified=now,
sighting_of_ref=INDICATOR_ID, sighting_of_ref=INDICATOR_ID,
where_sighted_refs=["malware--8cc7afd6-5455-4d2b-a736-e614ee631d99"] where_sighted_refs=["malware--8cc7afd6-5455-4d2b-a736-e614ee631d99"],
) )
assert excinfo.value.cls == stix2.v20.Sighting assert excinfo.value.cls == stix2.v20.Sighting
@ -89,19 +89,21 @@ def test_create_sighting_from_objects_rather_than_ids(malware): # noqa: F811
assert rel.id == 'sighting--00000000-0000-4000-8000-000000000003' assert rel.id == 'sighting--00000000-0000-4000-8000-000000000003'
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED_SIGHTING, "data", [
{ EXPECTED_SIGHTING,
"created": "2016-04-06T20:06:37Z", {
"id": "sighting--bfbc19db-ec35-4e45-beed-f8bde2a772fb", "created": "2016-04-06T20:06:37Z",
"modified": "2016-04-06T20:06:37Z", "id": "sighting--bfbc19db-ec35-4e45-beed-f8bde2a772fb",
"sighting_of_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", "modified": "2016-04-06T20:06:37Z",
"type": "sighting", "sighting_of_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
"where_sighted_refs": [ "type": "sighting",
"identity--8cc7afd6-5455-4d2b-a736-e614ee631d99" "where_sighted_refs": [
] "identity--8cc7afd6-5455-4d2b-a736-e614ee631d99",
}, ],
]) },
],
)
def test_parse_sighting(data): def test_parse_sighting(data):
sighting = stix2.parse(data, version="2.0") sighting = stix2.parse(data, version="2.0")

View File

@ -35,21 +35,23 @@ def test_threat_actor_example():
assert str(threat_actor) == EXPECTED assert str(threat_actor) == EXPECTED
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"created": "2016-04-06T20:03:48.000Z", {
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", "created": "2016-04-06T20:03:48.000Z",
"description": "The Evil Org threat actor group", "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
"id": "threat-actor--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", "description": "The Evil Org threat actor group",
"labels": [ "id": "threat-actor--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
"crime-syndicate" "labels": [
], "crime-syndicate",
"modified": "2016-04-06T20:03:48.000Z", ],
"name": "Evil Org", "modified": "2016-04-06T20:03:48.000Z",
"type": "threat-actor" "name": "Evil Org",
}, "type": "threat-actor",
]) },
],
)
def test_parse_threat_actor(data): def test_parse_threat_actor(data):
actor = stix2.parse(data, version="2.0") actor = stix2.parse(data, version="2.0")

View File

@ -46,20 +46,22 @@ def test_tool_example():
assert str(tool) == EXPECTED assert str(tool) == EXPECTED
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"created": "2016-04-06T20:03:48Z", {
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", "created": "2016-04-06T20:03:48Z",
"id": "tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
"labels": [ "id": "tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
"remote-access" "labels": [
], "remote-access",
"modified": "2016-04-06T20:03:48Z", ],
"name": "VNC", "modified": "2016-04-06T20:03:48Z",
"type": "tool" "name": "VNC",
}, "type": "tool",
]) },
],
)
def test_parse_tool(data): def test_parse_tool(data):
tool = stix2.parse(data, version="2.0") tool = stix2.parse(data, version="2.0")

View File

@ -12,76 +12,90 @@ amsterdam = pytz.timezone('Europe/Amsterdam')
eastern = pytz.timezone('US/Eastern') eastern = pytz.timezone('US/Eastern')
@pytest.mark.parametrize('dttm, timestamp', [ @pytest.mark.parametrize(
(dt.datetime(2017, 1, 1, tzinfo=pytz.utc), '2017-01-01T00:00:00Z'), 'dttm, timestamp', [
(amsterdam.localize(dt.datetime(2017, 1, 1)), '2016-12-31T23:00:00Z'), (dt.datetime(2017, 1, 1, tzinfo=pytz.utc), '2017-01-01T00:00:00Z'),
(eastern.localize(dt.datetime(2017, 1, 1, 12, 34, 56)), '2017-01-01T17:34:56Z'), (amsterdam.localize(dt.datetime(2017, 1, 1)), '2016-12-31T23:00:00Z'),
(eastern.localize(dt.datetime(2017, 7, 1)), '2017-07-01T04:00:00Z'), (eastern.localize(dt.datetime(2017, 1, 1, 12, 34, 56)), '2017-01-01T17:34:56Z'),
(dt.datetime(2017, 7, 1), '2017-07-01T00:00:00Z'), (eastern.localize(dt.datetime(2017, 7, 1)), '2017-07-01T04:00:00Z'),
(dt.datetime(2017, 7, 1, 0, 0, 0, 1), '2017-07-01T00:00:00.000001Z'), (dt.datetime(2017, 7, 1), '2017-07-01T00:00:00Z'),
(stix2.utils.STIXdatetime(2017, 7, 1, 0, 0, 0, 1, precision='millisecond'), '2017-07-01T00:00:00.000Z'), (dt.datetime(2017, 7, 1, 0, 0, 0, 1), '2017-07-01T00:00:00.000001Z'),
(stix2.utils.STIXdatetime(2017, 7, 1, 0, 0, 0, 1, precision='second'), '2017-07-01T00:00:00Z'), (stix2.utils.STIXdatetime(2017, 7, 1, 0, 0, 0, 1, precision='millisecond'), '2017-07-01T00:00:00.000Z'),
]) (stix2.utils.STIXdatetime(2017, 7, 1, 0, 0, 0, 1, precision='second'), '2017-07-01T00:00:00Z'),
],
)
def test_timestamp_formatting(dttm, timestamp): def test_timestamp_formatting(dttm, timestamp):
assert stix2.utils.format_datetime(dttm) == timestamp assert stix2.utils.format_datetime(dttm) == timestamp
@pytest.mark.parametrize('timestamp, dttm', [ @pytest.mark.parametrize(
(dt.datetime(2017, 1, 1, 0, tzinfo=pytz.utc), dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)), 'timestamp, dttm', [
(dt.date(2017, 1, 1), dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)), (dt.datetime(2017, 1, 1, 0, tzinfo=pytz.utc), dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)),
('2017-01-01T00:00:00Z', dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)), (dt.date(2017, 1, 1), dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)),
('2017-01-01T02:00:00+2:00', dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)), ('2017-01-01T00:00:00Z', dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)),
('2017-01-01T00:00:00', dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)), ('2017-01-01T02:00:00+2:00', dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)),
]) ('2017-01-01T00:00:00', dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)),
],
)
def test_parse_datetime(timestamp, dttm): def test_parse_datetime(timestamp, dttm):
assert stix2.utils.parse_into_datetime(timestamp) == dttm assert stix2.utils.parse_into_datetime(timestamp) == dttm
@pytest.mark.parametrize('timestamp, dttm, precision', [ @pytest.mark.parametrize(
('2017-01-01T01:02:03.000001', dt.datetime(2017, 1, 1, 1, 2, 3, 0, tzinfo=pytz.utc), 'millisecond'), 'timestamp, dttm, precision', [
('2017-01-01T01:02:03.001', dt.datetime(2017, 1, 1, 1, 2, 3, 1000, tzinfo=pytz.utc), 'millisecond'), ('2017-01-01T01:02:03.000001', dt.datetime(2017, 1, 1, 1, 2, 3, 0, tzinfo=pytz.utc), 'millisecond'),
('2017-01-01T01:02:03.1', dt.datetime(2017, 1, 1, 1, 2, 3, 100000, tzinfo=pytz.utc), 'millisecond'), ('2017-01-01T01:02:03.001', dt.datetime(2017, 1, 1, 1, 2, 3, 1000, tzinfo=pytz.utc), 'millisecond'),
('2017-01-01T01:02:03.45', dt.datetime(2017, 1, 1, 1, 2, 3, 450000, tzinfo=pytz.utc), 'millisecond'), ('2017-01-01T01:02:03.1', dt.datetime(2017, 1, 1, 1, 2, 3, 100000, tzinfo=pytz.utc), 'millisecond'),
('2017-01-01T01:02:03.45', dt.datetime(2017, 1, 1, 1, 2, 3, tzinfo=pytz.utc), 'second'), ('2017-01-01T01:02:03.45', dt.datetime(2017, 1, 1, 1, 2, 3, 450000, tzinfo=pytz.utc), 'millisecond'),
]) ('2017-01-01T01:02:03.45', dt.datetime(2017, 1, 1, 1, 2, 3, tzinfo=pytz.utc), 'second'),
],
)
def test_parse_datetime_precision(timestamp, dttm, precision): def test_parse_datetime_precision(timestamp, dttm, precision):
assert stix2.utils.parse_into_datetime(timestamp, precision) == dttm assert stix2.utils.parse_into_datetime(timestamp, precision) == dttm
@pytest.mark.parametrize('ts', [ @pytest.mark.parametrize(
'foobar', 'ts', [
1, 'foobar',
]) 1,
],
)
def test_parse_datetime_invalid(ts): def test_parse_datetime_invalid(ts):
with pytest.raises(ValueError): with pytest.raises(ValueError):
stix2.utils.parse_into_datetime('foobar') stix2.utils.parse_into_datetime('foobar')
@pytest.mark.parametrize('data', [ @pytest.mark.parametrize(
{"a": 1}, 'data', [
'{"a": 1}', {"a": 1},
StringIO(u'{"a": 1}'), '{"a": 1}',
[("a", 1,)], StringIO(u'{"a": 1}'),
]) [("a", 1,)],
],
)
def test_get_dict(data): def test_get_dict(data):
assert stix2.utils._get_dict(data) assert stix2.utils._get_dict(data)
@pytest.mark.parametrize('data', [ @pytest.mark.parametrize(
1, 'data', [
[1], 1,
['a', 1], [1],
"foobar", ['a', 1],
]) "foobar",
],
)
def test_get_dict_invalid(data): def test_get_dict_invalid(data):
with pytest.raises(ValueError): with pytest.raises(ValueError):
stix2.utils._get_dict(data) stix2.utils._get_dict(data)
@pytest.mark.parametrize('stix_id, type', [ @pytest.mark.parametrize(
('malware--d69c8146-ab35-4d50-8382-6fc80e641d43', 'malware'), 'stix_id, type', [
('intrusion-set--899ce53f-13a0-479b-a0e4-67d46e241542', 'intrusion-set') ('malware--d69c8146-ab35-4d50-8382-6fc80e641d43', 'malware'),
]) ('intrusion-set--899ce53f-13a0-479b-a0e4-67d46e241542', 'intrusion-set'),
],
)
def test_get_type_from_id(stix_id, type): def test_get_type_from_id(stix_id, type):
assert stix2.utils.get_type_from_id(stix_id) == type assert stix2.utils.get_type_from_id(stix_id) == type
@ -104,77 +118,85 @@ def test_deduplicate(stix_objs1):
assert "2017-01-27T13:49:53.936Z" in mods assert "2017-01-27T13:49:53.936Z" in mods
@pytest.mark.parametrize('object, tuple_to_find, expected_index', [ @pytest.mark.parametrize(
(stix2.v20.ObservedData( 'object, tuple_to_find, expected_index', [
id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", (
created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", stix2.v20.ObservedData(
created="2016-04-06T19:58:16.000Z", id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
modified="2016-04-06T19:58:16.000Z", created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
first_observed="2015-12-21T19:00:00Z", created="2016-04-06T19:58:16.000Z",
last_observed="2015-12-21T19:00:00Z", modified="2016-04-06T19:58:16.000Z",
number_observed=50, first_observed="2015-12-21T19:00:00Z",
objects={ last_observed="2015-12-21T19:00:00Z",
"0": { number_observed=50,
"name": "foo.exe", objects={
"type": "file" "0": {
}, "name": "foo.exe",
"1": { "type": "file",
"type": "ipv4-addr", },
"value": "198.51.100.3" "1": {
}, "type": "ipv4-addr",
"2": { "value": "198.51.100.3",
"type": "network-traffic", },
"src_ref": "1", "2": {
"protocols": [ "type": "network-traffic",
"tcp", "src_ref": "1",
"http" "protocols": [
], "tcp",
"extensions": { "http",
"http-request-ext": { ],
"request_method": "get", "extensions": {
"request_value": "/download.html", "http-request-ext": {
"request_version": "http/1.1", "request_method": "get",
"request_header": { "request_value": "/download.html",
"Accept-Encoding": "gzip,deflate", "request_version": "http/1.1",
"User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113", "request_header": {
"Host": "www.example.com" "Accept-Encoding": "gzip,deflate",
} "User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113",
} "Host": "www.example.com",
} },
} },
}, },
), ('1', {"type": "ipv4-addr", "value": "198.51.100.3"}), 1), },
({ },
"type": "x-example", ), ('1', {"type": "ipv4-addr", "value": "198.51.100.3"}), 1,
"id": "x-example--d5413db2-c26c-42e0-b0e0-ec800a310bfb", ),
"created": "2018-06-11T01:25:22.063Z", (
"modified": "2018-06-11T01:25:22.063Z", {
"dictionary": { "type": "x-example",
"key": { "id": "x-example--d5413db2-c26c-42e0-b0e0-ec800a310bfb",
"key_one": "value", "created": "2018-06-11T01:25:22.063Z",
"key_two": "value" "modified": "2018-06-11T01:25:22.063Z",
} "dictionary": {
} "key": {
}, ('key', {'key_one': 'value', 'key_two': 'value'}), 0), "key_one": "value",
({ "key_two": "value",
"type": "language-content", },
"id": "language-content--b86bd89f-98bb-4fa9-8cb2-9ad421da981d", },
"created": "2017-02-08T21:31:22.007Z", }, ('key', {'key_one': 'value', 'key_two': 'value'}), 0,
"modified": "2017-02-08T21:31:22.007Z", ),
"object_ref": "campaign--12a111f0-b824-4baf-a224-83b80237a094", (
"object_modified": "2017-02-08T21:31:22.007Z", {
"contents": { "type": "language-content",
"de": { "id": "language-content--b86bd89f-98bb-4fa9-8cb2-9ad421da981d",
"name": "Bank Angriff 1", "created": "2017-02-08T21:31:22.007Z",
"description": "Weitere Informationen über Banküberfall" "modified": "2017-02-08T21:31:22.007Z",
}, "object_ref": "campaign--12a111f0-b824-4baf-a224-83b80237a094",
"fr": { "object_modified": "2017-02-08T21:31:22.007Z",
"name": "Attaque Bank 1", "contents": {
"description": "Plus d'informations sur la crise bancaire" "de": {
} "name": "Bank Angriff 1",
} "description": "Weitere Informationen über Banküberfall",
}, ('fr', {"name": "Attaque Bank 1", "description": "Plus d'informations sur la crise bancaire"}), 1) },
]) "fr": {
"name": "Attaque Bank 1",
"description": "Plus d'informations sur la crise bancaire",
},
},
}, ('fr', {"name": "Attaque Bank 1", "description": "Plus d'informations sur la crise bancaire"}), 1,
),
],
)
def test_find_property_index(object, tuple_to_find, expected_index): def test_find_property_index(object, tuple_to_find, expected_index):
assert stix2.utils.find_property_index( assert stix2.utils.find_property_index(
object, object,
@ -182,29 +204,35 @@ def test_find_property_index(object, tuple_to_find, expected_index):
) == expected_index ) == expected_index
@pytest.mark.parametrize('dict_value, tuple_to_find, expected_index', [ @pytest.mark.parametrize(
({ 'dict_value, tuple_to_find, expected_index', [
"contents": { (
"de": { {
"name": "Bank Angriff 1", "contents": {
"description": "Weitere Informationen über Banküberfall" "de": {
}, "name": "Bank Angriff 1",
"fr": { "description": "Weitere Informationen über Banküberfall",
"name": "Attaque Bank 1", },
"description": "Plus d'informations sur la crise bancaire" "fr": {
}, "name": "Attaque Bank 1",
"es": { "description": "Plus d'informations sur la crise bancaire",
"name": "Ataque al Banco", },
"description": "Mas informacion sobre el ataque al banco" "es": {
} "name": "Ataque al Banco",
} "description": "Mas informacion sobre el ataque al banco",
}, ('es', {"name": "Ataque al Banco", "description": "Mas informacion sobre el ataque al banco"}), 1), # Sorted alphabetically },
({ },
'my_list': [ }, ('es', {"name": "Ataque al Banco", "description": "Mas informacion sobre el ataque al banco"}), 1,
{"key_one": 1}, ), # Sorted alphabetically
{"key_two": 2} (
] {
}, ('key_one', 1), 0) 'my_list': [
]) {"key_one": 1},
{"key_two": 2},
],
}, ('key_one', 1), 0,
),
],
)
def test_iterate_over_values(dict_value, tuple_to_find, expected_index): def test_iterate_over_values(dict_value, tuple_to_find, expected_index):
assert stix2.utils._find_property_in_seq(dict_value.values(), *tuple_to_find) == expected_index assert stix2.utils._find_property_in_seq(dict_value.values(), *tuple_to_find) == expected_index

View File

@ -37,15 +37,15 @@ def test_making_new_version_with_embedded_object():
campaign_v1 = stix2.v20.Campaign( campaign_v1 = stix2.v20.Campaign(
external_references=[{ external_references=[{
"source_name": "capec", "source_name": "capec",
"external_id": "CAPEC-163" "external_id": "CAPEC-163",
}], }],
**CAMPAIGN_MORE_KWARGS **CAMPAIGN_MORE_KWARGS
) )
campaign_v2 = campaign_v1.new_version(external_references=[{ campaign_v2 = campaign_v1.new_version(external_references=[{
"source_name": "capec", "source_name": "capec",
"external_id": "CAPEC-164" "external_id": "CAPEC-164",
}]) }])
assert campaign_v1.id == campaign_v2.id assert campaign_v1.id == campaign_v2.id
assert campaign_v1.created_by_ref == campaign_v2.created_by_ref assert campaign_v1.created_by_ref == campaign_v2.created_by_ref
@ -93,10 +93,12 @@ def test_versioning_error_bad_modified_value():
"but have the same id and modified timestamp do not have defined consumer behavior." "but have the same id and modified timestamp do not have defined consumer behavior."
msg = "Invalid value for {0} '{1}': {2}" msg = "Invalid value for {0} '{1}': {2}"
msg = msg.format(stix2.v20.Campaign.__name__, "modified", msg = msg.format(
"The new modified datetime cannot be before than or equal to the current modified datetime." stix2.v20.Campaign.__name__, "modified",
"It cannot be equal, as according to STIX 2 specification, objects that are different " "The new modified datetime cannot be before than or equal to the current modified datetime."
"but have the same id and modified timestamp do not have defined consumer behavior.") "It cannot be equal, as according to STIX 2 specification, objects that are different "
"but have the same id and modified timestamp do not have defined consumer behavior.",
)
assert str(excinfo.value) == msg assert str(excinfo.value) == msg
@ -215,10 +217,12 @@ def test_revoke_invalid_cls():
def test_remove_custom_stix_property(): def test_remove_custom_stix_property():
mal = stix2.v20.Malware(name="ColePowers", mal = stix2.v20.Malware(
labels=["rootkit"], name="ColePowers",
x_custom="armada", labels=["rootkit"],
allow_custom=True) x_custom="armada",
allow_custom=True,
)
mal_nc = stix2.utils.remove_custom_stix(mal) mal_nc = stix2.utils.remove_custom_stix(mal)
@ -228,10 +232,12 @@ def test_remove_custom_stix_property():
def test_remove_custom_stix_object(): def test_remove_custom_stix_object():
@stix2.v20.CustomObject("x-animal", [ @stix2.v20.CustomObject(
("species", stix2.properties.StringProperty(required=True)), "x-animal", [
("animal_class", stix2.properties.StringProperty()), ("species", stix2.properties.StringProperty(required=True)),
]) ("animal_class", stix2.properties.StringProperty()),
],
)
class Animal(object): class Animal(object):
pass pass

View File

@ -29,30 +29,34 @@ def test_vulnerability_example():
modified="2016-05-12T08:17:27.000Z", modified="2016-05-12T08:17:27.000Z",
name="CVE-2016-1234", name="CVE-2016-1234",
external_references=[ external_references=[
stix2.v20.ExternalReference(source_name='cve', stix2.v20.ExternalReference(
external_id="CVE-2016-1234"), source_name='cve',
external_id="CVE-2016-1234",
),
], ],
) )
assert str(vulnerability) == EXPECTED assert str(vulnerability) == EXPECTED
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"created": "2016-05-12T08:17:27Z", {
"external_references": [ "created": "2016-05-12T08:17:27Z",
{ "external_references": [
"external_id": "CVE-2016-1234", {
"source_name": "cve" "external_id": "CVE-2016-1234",
} "source_name": "cve",
], },
"id": "vulnerability--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061", ],
"modified": "2016-05-12T08:17:27Z", "id": "vulnerability--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
"name": "CVE-2016-1234", "modified": "2016-05-12T08:17:27Z",
"type": "vulnerability" "name": "CVE-2016-1234",
}, "type": "vulnerability",
]) },
],
)
def test_parse_vulnerability(data): def test_parse_vulnerability(data):
vuln = stix2.parse(data, version="2.0") vuln = stix2.parse(data, version="2.0")

View File

@ -3,29 +3,25 @@ import os
import pytest import pytest
import stix2 import stix2
from stix2.workbench import (AttackPattern, Campaign, CourseOfAction, from stix2.workbench import (
ExternalReference, FileSystemSource, Filter, AttackPattern, Campaign, CourseOfAction, ExternalReference,
Identity, Indicator, IntrusionSet, Malware, FileSystemSource, Filter, Identity, Indicator, IntrusionSet, Malware,
MarkingDefinition, ObservedData, Relationship, MarkingDefinition, ObservedData, Relationship, Report, StatementMarking,
Report, StatementMarking, ThreatActor, Tool, ThreatActor, Tool, Vulnerability, add_data_source, all_versions,
Vulnerability, add_data_source, all_versions, attack_patterns, campaigns, courses_of_action, create, get, identities,
attack_patterns, campaigns, courses_of_action, indicators, intrusion_sets, malware, observed_data, query, reports, save,
create, get, identities, indicators, set_default_created, set_default_creator, set_default_external_refs,
intrusion_sets, malware, observed_data, query, set_default_object_marking_refs, threat_actors, tools, vulnerabilities,
reports, save, set_default_created, )
set_default_creator, set_default_external_refs,
set_default_object_marking_refs, threat_actors,
tools, vulnerabilities)
from .constants import (ATTACK_PATTERN_ID, ATTACK_PATTERN_KWARGS, CAMPAIGN_ID, from .constants import (
CAMPAIGN_KWARGS, COURSE_OF_ACTION_ID, ATTACK_PATTERN_ID, ATTACK_PATTERN_KWARGS, CAMPAIGN_ID, CAMPAIGN_KWARGS,
COURSE_OF_ACTION_KWARGS, IDENTITY_ID, IDENTITY_KWARGS, COURSE_OF_ACTION_ID, COURSE_OF_ACTION_KWARGS, IDENTITY_ID, IDENTITY_KWARGS,
INDICATOR_ID, INDICATOR_KWARGS, INTRUSION_SET_ID, INDICATOR_ID, INDICATOR_KWARGS, INTRUSION_SET_ID, INTRUSION_SET_KWARGS,
INTRUSION_SET_KWARGS, MALWARE_ID, MALWARE_KWARGS, MALWARE_ID, MALWARE_KWARGS, OBSERVED_DATA_ID, OBSERVED_DATA_KWARGS,
OBSERVED_DATA_ID, OBSERVED_DATA_KWARGS, REPORT_ID, REPORT_ID, REPORT_KWARGS, THREAT_ACTOR_ID, THREAT_ACTOR_KWARGS, TOOL_ID,
REPORT_KWARGS, THREAT_ACTOR_ID, THREAT_ACTOR_KWARGS, TOOL_KWARGS, VULNERABILITY_ID, VULNERABILITY_KWARGS,
TOOL_ID, TOOL_KWARGS, VULNERABILITY_ID, )
VULNERABILITY_KWARGS)
@pytest.mark.skip(reason='The workbench is not working correctly for 2.0') @pytest.mark.skip(reason='The workbench is not working correctly for 2.0')
@ -240,8 +236,10 @@ def test_additional_filter():
@pytest.mark.skip(reason='The workbench is not working correctly for 2.0') @pytest.mark.skip(reason='The workbench is not working correctly for 2.0')
def test_additional_filters_list(): def test_additional_filters_list():
resp = tools([Filter('created_by_ref', '=', 'identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5'), resp = tools([
Filter('name', '=', 'Windows Credential Editor')]) Filter('created_by_ref', '=', 'identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5'),
Filter('name', '=', 'Windows Credential Editor'),
])
assert len(resp) == 1 assert len(resp) == 1
@ -264,8 +262,10 @@ def test_default_created_timestamp():
def test_default_external_refs(): def test_default_external_refs():
ext_ref = ExternalReference(source_name="ACME Threat Intel", ext_ref = ExternalReference(
description="Threat report") source_name="ACME Threat Intel",
description="Threat report",
)
set_default_external_refs(ext_ref) set_default_external_refs(ext_ref)
campaign = Campaign(**CAMPAIGN_KWARGS) campaign = Campaign(**CAMPAIGN_KWARGS)
@ -275,8 +275,10 @@ def test_default_external_refs():
def test_default_object_marking_refs(): def test_default_object_marking_refs():
stmt_marking = StatementMarking("Copyright 2016, Example Corp") stmt_marking = StatementMarking("Copyright 2016, Example Corp")
mark_def = MarkingDefinition(definition_type="statement", mark_def = MarkingDefinition(
definition=stmt_marking) definition_type="statement",
definition=stmt_marking,
)
set_default_object_marking_refs(mark_def) set_default_object_marking_refs(mark_def)
campaign = Campaign(**CAMPAIGN_KWARGS) campaign = Campaign(**CAMPAIGN_KWARGS)
@ -314,7 +316,7 @@ def test_workbench_custom_property_dict_in_observable_extension():
'allow_custom': True, 'allow_custom': True,
'sid': 1, 'sid': 1,
'x_foo': 'bar', 'x_foo': 'bar',
} },
}, },
) )
observed_data = ObservedData( observed_data = ObservedData(

View File

@ -4,8 +4,9 @@ import pytest
import stix2 import stix2
from .constants import (FAKE_TIME, INDICATOR_KWARGS, MALWARE_KWARGS, from .constants import (
RELATIONSHIP_KWARGS) FAKE_TIME, INDICATOR_KWARGS, MALWARE_KWARGS, RELATIONSHIP_KWARGS,
)
# Inspired by: http://stackoverflow.com/a/24006251 # Inspired by: http://stackoverflow.com/a/24006251
@ -54,66 +55,66 @@ def stix_objs1():
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000001", "id": "indicator--00000000-0000-4000-8000-000000000001",
"indicator_types": [ "indicator_types": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"spec_version": "2.1", "spec_version": "2.1",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
ind2 = { ind2 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000001", "id": "indicator--00000000-0000-4000-8000-000000000001",
"indicator_types": [ "indicator_types": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"spec_version": "2.1", "spec_version": "2.1",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
ind3 = { ind3 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000001", "id": "indicator--00000000-0000-4000-8000-000000000001",
"indicator_types": [ "indicator_types": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.936Z", "modified": "2017-01-27T13:49:53.936Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"spec_version": "2.1", "spec_version": "2.1",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
ind4 = { ind4 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000002", "id": "indicator--00000000-0000-4000-8000-000000000002",
"indicator_types": [ "indicator_types": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"spec_version": "2.1", "spec_version": "2.1",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
ind5 = { ind5 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000002", "id": "indicator--00000000-0000-4000-8000-000000000002",
"indicator_types": [ "indicator_types": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"spec_version": "2.1", "spec_version": "2.1",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
return [ind1, ind2, ind3, ind4, ind5] return [ind1, ind2, ind3, ind4, ind5]
@ -124,40 +125,40 @@ def stix_objs2():
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000001", "id": "indicator--00000000-0000-4000-8000-000000000001",
"indicator_types": [ "indicator_types": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-31T13:49:53.935Z", "modified": "2017-01-31T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"spec_version": "2.1", "spec_version": "2.1",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
ind7 = { ind7 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000002", "id": "indicator--00000000-0000-4000-8000-000000000002",
"indicator_types": [ "indicator_types": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"spec_version": "2.1", "spec_version": "2.1",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
ind8 = { ind8 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000002", "id": "indicator--00000000-0000-4000-8000-000000000002",
"indicator_types": [ "indicator_types": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"spec_version": "2.1", "spec_version": "2.1",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
return [ind6, ind7, ind8] return [ind6, ind7, ind8]

View File

@ -34,7 +34,7 @@ MARKING_IDS = [
RELATIONSHIP_IDS = [ RELATIONSHIP_IDS = [
'relationship--06520621-5352-4e6a-b976-e8fa3d437ffd', 'relationship--06520621-5352-4e6a-b976-e8fa3d437ffd',
'relationship--181c9c09-43e6-45dd-9374-3bec192f05ef', 'relationship--181c9c09-43e6-45dd-9374-3bec192f05ef',
'relationship--a0cbb21c-8daf-4a7f-96aa-7155a4ef8f70' 'relationship--a0cbb21c-8daf-4a7f-96aa-7155a4ef8f70',
] ]
# *_KWARGS contains all required arguments to create an instance of that STIX object # *_KWARGS contains all required arguments to create an instance of that STIX object
@ -81,7 +81,7 @@ INTRUSION_SET_KWARGS = dict(
MALWARE_KWARGS = dict( MALWARE_KWARGS = dict(
malware_types=['ransomware'], malware_types=['ransomware'],
name="Cryptolocker", name="Cryptolocker",
is_family=True is_family=True,
) )
MALWARE_MORE_KWARGS = dict( MALWARE_MORE_KWARGS = dict(
@ -92,7 +92,7 @@ MALWARE_MORE_KWARGS = dict(
malware_types=['ransomware'], malware_types=['ransomware'],
name="Cryptolocker", name="Cryptolocker",
description="A ransomware related to ...", description="A ransomware related to ...",
is_family=False is_family=False,
) )
OBSERVED_DATA_KWARGS = dict( OBSERVED_DATA_KWARGS = dict(
@ -103,8 +103,8 @@ OBSERVED_DATA_KWARGS = dict(
"0": { "0": {
"type": "windows-registry-key", "type": "windows-registry-key",
"key": "HKEY_LOCAL_MACHINE\\System\\Foo\\Bar", "key": "HKEY_LOCAL_MACHINE\\System\\Foo\\Bar",
} },
} },
) )
REPORT_KWARGS = dict( REPORT_KWARGS = dict(

View File

@ -32,7 +32,7 @@ def test_attack_pattern_example():
name="Spear Phishing", name="Spear Phishing",
external_references=[{ external_references=[{
"source_name": "capec", "source_name": "capec",
"external_id": "CAPEC-163" "external_id": "CAPEC-163",
}], }],
description="...", description="...",
) )
@ -40,24 +40,26 @@ def test_attack_pattern_example():
assert str(ap) == EXPECTED assert str(ap) == EXPECTED
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"type": "attack-pattern", {
"spec_version": "2.1", "type": "attack-pattern",
"id": "attack-pattern--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061", "spec_version": "2.1",
"created": "2016-05-12T08:17:27.000Z", "id": "attack-pattern--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
"modified": "2016-05-12T08:17:27.000Z", "created": "2016-05-12T08:17:27.000Z",
"description": "...", "modified": "2016-05-12T08:17:27.000Z",
"external_references": [ "description": "...",
{ "external_references": [
"external_id": "CAPEC-163", {
"source_name": "capec" "external_id": "CAPEC-163",
} "source_name": "capec",
], },
"name": "Spear Phishing", ],
}, "name": "Spear Phishing",
]) },
],
)
def test_parse_attack_pattern(data): def test_parse_attack_pattern(data):
ap = stix2.parse(data, version="2.1") ap = stix2.parse(data, version="2.1")
@ -79,7 +81,7 @@ def test_attack_pattern_invalid_labels():
created="2016-05-12T08:17:27Z", created="2016-05-12T08:17:27Z",
modified="2016-05-12T08:17:27Z", modified="2016-05-12T08:17:27Z",
name="Spear Phishing", name="Spear Phishing",
labels=1 labels=1,
) )
# TODO: Add other examples # TODO: Add other examples

View File

@ -58,8 +58,8 @@ EXPECTED_BUNDLE_DICT = {
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']", "pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
"valid_from": "2017-01-01T12:34:56Z", "valid_from": "2017-01-01T12:34:56Z",
"indicator_types": [ "indicator_types": [
"malicious-activity" "malicious-activity",
] ],
}, },
{ {
"type": "malware", "type": "malware",
@ -69,9 +69,9 @@ EXPECTED_BUNDLE_DICT = {
"modified": "2017-01-01T12:34:56.000Z", "modified": "2017-01-01T12:34:56.000Z",
"name": "Cryptolocker", "name": "Cryptolocker",
"malware_types": [ "malware_types": [
"ransomware" "ransomware",
], ],
"is_family": True "is_family": True,
}, },
{ {
"type": "relationship", "type": "relationship",
@ -81,9 +81,9 @@ EXPECTED_BUNDLE_DICT = {
"modified": "2017-01-01T12:34:56.000Z", "modified": "2017-01-01T12:34:56.000Z",
"relationship_type": "indicates", "relationship_type": "indicates",
"source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", "source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
"target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e" "target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
} },
] ],
} }

View File

@ -26,25 +26,27 @@ def test_campaign_example():
created="2016-04-06T20:03:00Z", created="2016-04-06T20:03:00Z",
modified="2016-04-06T20:03:00Z", modified="2016-04-06T20:03:00Z",
name="Green Group Attacks Against Finance", name="Green Group Attacks Against Finance",
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.",
) )
assert str(campaign) == EXPECTED assert str(campaign) == EXPECTED
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"type": "campaign", {
"spec_version": "2.1", "type": "campaign",
"id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", "spec_version": "2.1",
"created": "2016-04-06T20:03:00Z", "id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
"modified": "2016-04-06T20:03:00Z", "created": "2016-04-06T20:03:00Z",
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", "modified": "2016-04-06T20:03:00Z",
"description": "Campaign by Green Group against a series of targets in the financial services sector.", "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
"name": "Green Group Attacks Against Finance", "description": "Campaign by Green Group against a series of targets in the financial services sector.",
}, "name": "Green Group Attacks Against Finance",
]) },
],
)
def test_parse_campaign(data): def test_parse_campaign(data):
cmpn = stix2.parse(data, version="2.1") cmpn = stix2.parse(data, version="2.1")

View File

@ -1,12 +1,11 @@
import pytest import pytest
from stix2.confidence.scales import (admiralty_credibility_to_value, from stix2.confidence.scales import (
dni_to_value, none_low_med_high_to_value, admiralty_credibility_to_value, dni_to_value, none_low_med_high_to_value,
value_to_admiralty_credibility, value_to_admiralty_credibility, value_to_dni,
value_to_dni, value_to_none_low_medium_high, value_to_wep, value_to_zero_ten,
value_to_none_low_medium_high, wep_to_value, zero_ten_to_value,
value_to_wep, value_to_zero_ten, )
wep_to_value, zero_ten_to_value)
CONFIDENCE_ERROR_STR = "STIX Confidence value cannot be determined for %s" CONFIDENCE_ERROR_STR = "STIX Confidence value cannot be determined for %s"
RANGE_ERROR_STR = "Range of values out of bounds: %s" RANGE_ERROR_STR = "Range of values out of bounds: %s"
@ -39,22 +38,26 @@ def test_confidence_range_none_low_med_high():
pytest.fail("Unexpected behavior %s" % val) pytest.fail("Unexpected behavior %s" % val)
@pytest.mark.parametrize("scale_value,result", [ @pytest.mark.parametrize(
("None", 0), "scale_value,result", [
("Low", 15), ("None", 0),
("Med", 50), ("Low", 15),
("High", 85) ("Med", 50),
]) ("High", 85),
],
)
def test_confidence_scale_valid_none_low_med_high(scale_value, result): def test_confidence_scale_valid_none_low_med_high(scale_value, result):
val = none_low_med_high_to_value(scale_value) val = none_low_med_high_to_value(scale_value)
assert val == result assert val == result
@pytest.mark.parametrize("scale_value", [ @pytest.mark.parametrize(
"Super", "scale_value", [
"none", "Super",
"" "none",
]) "",
],
)
def test_confidence_scale_invalid_none_low_med_high(scale_value): def test_confidence_scale_invalid_none_low_med_high(scale_value):
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
none_low_med_high_to_value(scale_value) none_low_med_high_to_value(scale_value)
@ -99,29 +102,33 @@ def test_confidence_range_zero_ten():
pytest.fail("Unexpected behavior %s" % val) pytest.fail("Unexpected behavior %s" % val)
@pytest.mark.parametrize("scale_value,result", [ @pytest.mark.parametrize(
("0", 0), "scale_value,result", [
("1", 10), ("0", 0),
("2", 20), ("1", 10),
("3", 30), ("2", 20),
("4", 40), ("3", 30),
("5", 50), ("4", 40),
("6", 60), ("5", 50),
("7", 70), ("6", 60),
("8", 80), ("7", 70),
("9", 90), ("8", 80),
("10", 100) ("9", 90),
]) ("10", 100),
],
)
def test_confidence_scale_valid_zero_ten(scale_value, result): def test_confidence_scale_valid_zero_ten(scale_value, result):
val = zero_ten_to_value(scale_value) val = zero_ten_to_value(scale_value)
assert val == result assert val == result
@pytest.mark.parametrize("scale_value", [ @pytest.mark.parametrize(
"11", "scale_value", [
8, "11",
"" 8,
]) "",
],
)
def test_confidence_scale_invalid_zero_ten(scale_value): def test_confidence_scale_invalid_zero_ten(scale_value):
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
zero_ten_to_value(scale_value) zero_ten_to_value(scale_value)
@ -154,23 +161,27 @@ def test_confidence_range_admiralty_credibility():
pytest.fail("Unexpected behavior %s" % val) pytest.fail("Unexpected behavior %s" % val)
@pytest.mark.parametrize("scale_value,result", [ @pytest.mark.parametrize(
("5 - Improbable", 10), "scale_value,result", [
("4 - Doubtful", 30), ("5 - Improbable", 10),
("3 - Possibly True", 50), ("4 - Doubtful", 30),
("2 - Probably True", 70), ("3 - Possibly True", 50),
("1 - Confirmed by other sources", 90) ("2 - Probably True", 70),
]) ("1 - Confirmed by other sources", 90),
],
)
def test_confidence_scale_valid_admiralty_credibility(scale_value, result): def test_confidence_scale_valid_admiralty_credibility(scale_value, result):
val = admiralty_credibility_to_value(scale_value) val = admiralty_credibility_to_value(scale_value)
assert val == result assert val == result
@pytest.mark.parametrize("scale_value", [ @pytest.mark.parametrize(
"5 - improbable", "scale_value", [
"6 - Truth cannot be judged", "5 - improbable",
"" "6 - Truth cannot be judged",
]) "",
],
)
def test_confidence_scale_invalid_admiralty_credibility(scale_value): def test_confidence_scale_invalid_admiralty_credibility(scale_value):
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
admiralty_credibility_to_value(scale_value) admiralty_credibility_to_value(scale_value)
@ -207,25 +218,29 @@ def test_confidence_range_wep():
pytest.fail("Unexpected behavior %s" % val) pytest.fail("Unexpected behavior %s" % val)
@pytest.mark.parametrize("scale_value,result", [ @pytest.mark.parametrize(
("Impossible", 0), "scale_value,result", [
("Highly Unlikely/Almost Certainly Not", 10), ("Impossible", 0),
("Unlikely/Probably Not", 30), ("Highly Unlikely/Almost Certainly Not", 10),
("Even Chance", 50), ("Unlikely/Probably Not", 30),
("Likely/Probable", 70), ("Even Chance", 50),
("Highly likely/Almost Certain", 90), ("Likely/Probable", 70),
("Certain", 100) ("Highly likely/Almost Certain", 90),
]) ("Certain", 100),
],
)
def test_confidence_scale_valid_wep(scale_value, result): def test_confidence_scale_valid_wep(scale_value, result):
val = wep_to_value(scale_value) val = wep_to_value(scale_value)
assert val == result assert val == result
@pytest.mark.parametrize("scale_value", [ @pytest.mark.parametrize(
"Unlikely / Probably Not", "scale_value", [
"Almost certain", "Unlikely / Probably Not",
"" "Almost certain",
]) "",
],
)
def test_confidence_scale_invalid_wep(scale_value): def test_confidence_scale_invalid_wep(scale_value):
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
wep_to_value(scale_value) wep_to_value(scale_value)
@ -262,25 +277,29 @@ def test_confidence_range_dni():
pytest.fail("Unexpected behavior %s" % val) pytest.fail("Unexpected behavior %s" % val)
@pytest.mark.parametrize("scale_value,result", [ @pytest.mark.parametrize(
("Almost No Chance / Remote", 5), "scale_value,result", [
("Very Unlikely / Highly Improbable", 15), ("Almost No Chance / Remote", 5),
("Unlikely / Improbable", 30), ("Very Unlikely / Highly Improbable", 15),
("Roughly Even Change / Roughly Even Odds", 50), ("Unlikely / Improbable", 30),
("Likely / Probable", 70), ("Roughly Even Change / Roughly Even Odds", 50),
("Very Likely / Highly Probable", 85), ("Likely / Probable", 70),
("Almost Certain / Nearly Certain", 95) ("Very Likely / Highly Probable", 85),
]) ("Almost Certain / Nearly Certain", 95),
],
)
def test_confidence_scale_valid_dni(scale_value, result): def test_confidence_scale_valid_dni(scale_value, result):
val = dni_to_value(scale_value) val = dni_to_value(scale_value)
assert val == result assert val == result
@pytest.mark.parametrize("scale_value", [ @pytest.mark.parametrize(
"Almost Certain/Nearly Certain", "scale_value", [
"Almost Certain / nearly Certain", "Almost Certain/Nearly Certain",
"" "Almost Certain / nearly Certain",
]) "",
],
)
def test_confidence_scale_invalid_none_dni(scale_value): def test_confidence_scale_invalid_none_dni(scale_value):
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
dni_to_value(scale_value) dni_to_value(scale_value)

View File

@ -26,25 +26,27 @@ def test_course_of_action_example():
created="2016-04-06T20:03:48.000Z", created="2016-04-06T20:03:48.000Z",
modified="2016-04-06T20:03:48.000Z", modified="2016-04-06T20:03:48.000Z",
name="Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter", name="Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter",
description="This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ..." description="This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ...",
) )
assert str(coa) == EXPECTED assert str(coa) == EXPECTED
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"created": "2016-04-06T20:03:48.000Z", {
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", "created": "2016-04-06T20:03:48.000Z",
"description": "This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ...", "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
"id": "course-of-action--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", "description": "This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ...",
"modified": "2016-04-06T20:03:48.000Z", "id": "course-of-action--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
"name": "Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter", "modified": "2016-04-06T20:03:48.000Z",
"spec_version": "2.1", "name": "Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter",
"type": "course-of-action" "spec_version": "2.1",
}, "type": "course-of-action",
]) },
],
)
def test_parse_course_of_action(data): def test_parse_course_of_action(data):
coa = stix2.parse(data, version="2.1") coa = stix2.parse(data, version="2.1")

View File

@ -36,7 +36,7 @@ def test_identity_custom_property():
"foo": "bar", "foo": "bar",
}, },
foo="bar", foo="bar",
) )
assert "Unexpected properties for Identity" in str(excinfo.value) assert "Unexpected properties for Identity" in str(excinfo.value)
identity = stix2.v21.Identity( identity = stix2.v21.Identity(
@ -80,8 +80,9 @@ def test_identity_custom_property_allowed():
assert identity.x_foo == "bar" assert identity.x_foo == "bar"
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
"""{ "data", [
"""{
"type": "identity", "type": "identity",
"spec_version": "2.1", "spec_version": "2.1",
"id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c",
@ -91,7 +92,8 @@ def test_identity_custom_property_allowed():
"identity_class": "individual", "identity_class": "individual",
"foo": "bar" "foo": "bar"
}""", }""",
]) ],
)
def test_parse_identity_custom_property(data): def test_parse_identity_custom_property(data):
with pytest.raises(stix2.exceptions.ExtraPropertiesError) as excinfo: with pytest.raises(stix2.exceptions.ExtraPropertiesError) as excinfo:
stix2.parse(data, version="2.1") stix2.parse(data, version="2.1")
@ -116,7 +118,7 @@ def test_custom_properties_object_in_bundled_object():
identity_class="individual", identity_class="individual",
custom_properties={ custom_properties={
"x_foo": "bar", "x_foo": "bar",
} },
) )
bundle = stix2.v21.Bundle(obj, allow_custom=True) bundle = stix2.v21.Bundle(obj, allow_custom=True)
@ -164,7 +166,7 @@ def test_custom_property_in_observed_data():
artifact = stix2.v21.File( artifact = stix2.v21.File(
allow_custom=True, allow_custom=True,
name='test', name='test',
x_foo='bar' x_foo='bar',
) )
observed_data = stix2.v21.ObservedData( observed_data = stix2.v21.ObservedData(
allow_custom=True, allow_custom=True,
@ -208,7 +210,7 @@ def test_custom_property_dict_in_observable_extension():
'ntfs-ext': { 'ntfs-ext': {
'sid': 1, 'sid': 1,
'x_foo': 'bar', 'x_foo': 'bar',
} },
}, },
) )
@ -220,7 +222,7 @@ def test_custom_property_dict_in_observable_extension():
'allow_custom': True, 'allow_custom': True,
'sid': 1, 'sid': 1,
'x_foo': 'bar', 'x_foo': 'bar',
} },
}, },
) )
observed_data = stix2.v21.ObservedData( observed_data = stix2.v21.ObservedData(
@ -244,12 +246,12 @@ def test_identity_custom_property_edit_markings():
marking_obj = stix2.v21.MarkingDefinition( marking_obj = stix2.v21.MarkingDefinition(
id=MARKING_DEFINITION_ID, id=MARKING_DEFINITION_ID,
definition_type="statement", definition_type="statement",
definition=stix2.v21.StatementMarking(statement="Copyright 2016, Example Corp") definition=stix2.v21.StatementMarking(statement="Copyright 2016, Example Corp"),
) )
marking_obj2 = stix2.v21.MarkingDefinition( marking_obj2 = stix2.v21.MarkingDefinition(
id=MARKING_DEFINITION_ID, id=MARKING_DEFINITION_ID,
definition_type="statement", definition_type="statement",
definition=stix2.v21.StatementMarking(statement="Another one") definition=stix2.v21.StatementMarking(statement="Another one"),
) )
# None of the following should throw exceptions # None of the following should throw exceptions
@ -262,9 +264,11 @@ def test_identity_custom_property_edit_markings():
def test_custom_marking_no_init_1(): def test_custom_marking_no_init_1():
@stix2.v21.CustomMarking('x-new-obj', [ @stix2.v21.CustomMarking(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-obj', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class NewObj(): class NewObj():
pass pass
@ -273,9 +277,11 @@ def test_custom_marking_no_init_1():
def test_custom_marking_no_init_2(): def test_custom_marking_no_init_2():
@stix2.v21.CustomMarking('x-new-obj2', [ @stix2.v21.CustomMarking(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-obj2', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class NewObj2(object): class NewObj2(object):
pass pass
@ -283,10 +289,12 @@ def test_custom_marking_no_init_2():
assert no2.property1 == 'something' assert no2.property1 == 'something'
@stix2.v21.CustomObject('x-new-type', [ @stix2.v21.CustomObject(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-type', [
('property2', stix2.properties.IntegerProperty()), ('property1', stix2.properties.StringProperty(required=True)),
]) ('property2', stix2.properties.IntegerProperty()),
],
)
class NewType(object): class NewType(object):
def __init__(self, property2=None, **kwargs): def __init__(self, property2=None, **kwargs):
if property2 and property2 < 10: if property2 and property2 < 10:
@ -316,9 +324,11 @@ def test_custom_object_type():
def test_custom_object_no_init_1(): def test_custom_object_no_init_1():
@stix2.v21.CustomObject('x-new-obj', [ @stix2.v21.CustomObject(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-obj', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class NewObj(): class NewObj():
pass pass
@ -327,9 +337,11 @@ def test_custom_object_no_init_1():
def test_custom_object_no_init_2(): def test_custom_object_no_init_2():
@stix2.v21.CustomObject('x-new-obj2', [ @stix2.v21.CustomObject(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-obj2', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class NewObj2(object): class NewObj2(object):
pass pass
@ -339,17 +351,21 @@ def test_custom_object_no_init_2():
def test_custom_object_invalid_type_name(): def test_custom_object_invalid_type_name():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomObject('x', [ @stix2.v21.CustomObject(
('property1', stix2.properties.StringProperty(required=True)), 'x', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class NewObj(object): class NewObj(object):
pass # pragma: no cover pass # pragma: no cover
assert "Invalid type name 'x': " in str(excinfo.value) assert "Invalid type name 'x': " in str(excinfo.value)
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomObject('x_new_object', [ @stix2.v21.CustomObject(
('property1', stix2.properties.StringProperty(required=True)), 'x_new_object', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class NewObj2(object): class NewObj2(object):
pass # pragma: no cover pass # pragma: no cover
assert "Invalid type name 'x_new_object':" in str(excinfo.value) assert "Invalid type name 'x_new_object':" in str(excinfo.value)
@ -393,11 +409,13 @@ def test_parse_unregistered_custom_object_type_w_allow_custom():
assert custom_obj["type"] == "x-foobar-observable" assert custom_obj["type"] == "x-foobar-observable"
@stix2.v21.CustomObservable('x-new-observable', [ @stix2.v21.CustomObservable(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-observable', [
('property2', stix2.properties.IntegerProperty()), ('property1', stix2.properties.StringProperty(required=True)),
('x_property3', stix2.properties.BooleanProperty()), ('property2', stix2.properties.IntegerProperty()),
]) ('x_property3', stix2.properties.BooleanProperty()),
],
)
class NewObservable(): class NewObservable():
def __init__(self, property2=None, **kwargs): def __init__(self, property2=None, **kwargs):
if property2 and property2 < 10: if property2 and property2 < 10:
@ -432,9 +450,11 @@ def test_custom_observable_raises_exception():
def test_custom_observable_object_no_init_1(): def test_custom_observable_object_no_init_1():
@stix2.v21.CustomObservable('x-new-observable', [ @stix2.v21.CustomObservable(
('property1', stix2.properties.StringProperty()), 'x-new-observable', [
]) ('property1', stix2.properties.StringProperty()),
],
)
class NewObs(): class NewObs():
pass pass
@ -443,9 +463,11 @@ def test_custom_observable_object_no_init_1():
def test_custom_observable_object_no_init_2(): def test_custom_observable_object_no_init_2():
@stix2.v21.CustomObservable('x-new-obs2', [ @stix2.v21.CustomObservable(
('property1', stix2.properties.StringProperty()), 'x-new-obs2', [
]) ('property1', stix2.properties.StringProperty()),
],
)
class NewObs2(object): class NewObs2(object):
pass pass
@ -455,17 +477,21 @@ def test_custom_observable_object_no_init_2():
def test_custom_observable_object_invalid_type_name(): def test_custom_observable_object_invalid_type_name():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomObservable('x', [ @stix2.v21.CustomObservable(
('property1', stix2.properties.StringProperty()), 'x', [
]) ('property1', stix2.properties.StringProperty()),
],
)
class NewObs(object): class NewObs(object):
pass # pragma: no cover pass # pragma: no cover
assert "Invalid observable type name 'x':" in str(excinfo.value) assert "Invalid observable type name 'x':" in str(excinfo.value)
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomObservable('x_new_obs', [ @stix2.v21.CustomObservable(
('property1', stix2.properties.StringProperty()), 'x_new_obs', [
]) ('property1', stix2.properties.StringProperty()),
],
)
class NewObs2(object): class NewObs2(object):
pass # pragma: no cover pass # pragma: no cover
assert "Invalid observable type name 'x_new_obs':" in str(excinfo.value) assert "Invalid observable type name 'x_new_obs':" in str(excinfo.value)
@ -473,9 +499,11 @@ def test_custom_observable_object_invalid_type_name():
def test_custom_observable_object_invalid_ref_property(): def test_custom_observable_object_invalid_ref_property():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomObservable('x-new-obs', [ @stix2.v21.CustomObservable(
('property_ref', stix2.properties.StringProperty()), 'x-new-obs', [
]) ('property_ref', stix2.properties.StringProperty()),
],
)
class NewObs(): class NewObs():
pass pass
assert "is named like an object reference property but is not an ObjectReferenceProperty" in str(excinfo.value) assert "is named like an object reference property but is not an ObjectReferenceProperty" in str(excinfo.value)
@ -483,9 +511,11 @@ def test_custom_observable_object_invalid_ref_property():
def test_custom_observable_object_invalid_refs_property(): def test_custom_observable_object_invalid_refs_property():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomObservable('x-new-obs', [ @stix2.v21.CustomObservable(
('property_refs', stix2.properties.StringProperty()), 'x-new-obs', [
]) ('property_refs', stix2.properties.StringProperty()),
],
)
class NewObs(): class NewObs():
pass pass
assert "is named like an object reference list property but is not a ListProperty containing ObjectReferenceProperty" in str(excinfo.value) assert "is named like an object reference list property but is not a ListProperty containing ObjectReferenceProperty" in str(excinfo.value)
@ -493,26 +523,32 @@ def test_custom_observable_object_invalid_refs_property():
def test_custom_observable_object_invalid_refs_list_property(): def test_custom_observable_object_invalid_refs_list_property():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomObservable('x-new-obs', [ @stix2.v21.CustomObservable(
('property_refs', stix2.properties.ListProperty(stix2.properties.StringProperty)), 'x-new-obs', [
]) ('property_refs', stix2.properties.ListProperty(stix2.properties.StringProperty)),
],
)
class NewObs(): class NewObs():
pass pass
assert "is named like an object reference list property but is not a ListProperty containing ObjectReferenceProperty" in str(excinfo.value) assert "is named like an object reference list property but is not a ListProperty containing ObjectReferenceProperty" in str(excinfo.value)
def test_custom_observable_object_invalid_valid_refs(): def test_custom_observable_object_invalid_valid_refs():
@stix2.v21.CustomObservable('x-new-obs', [ @stix2.v21.CustomObservable(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-obs', [
('property_ref', stix2.properties.ObjectReferenceProperty(valid_types='email-addr')), ('property1', stix2.properties.StringProperty(required=True)),
]) ('property_ref', stix2.properties.ObjectReferenceProperty(valid_types='email-addr')),
],
)
class NewObs(): class NewObs():
pass pass
with pytest.raises(Exception) as excinfo: with pytest.raises(Exception) as excinfo:
NewObs(_valid_refs=['1'], NewObs(
property1='something', _valid_refs=['1'],
property_ref='1') property1='something',
property_ref='1',
)
assert "must be created with _valid_refs as a dict, not a list" in str(excinfo.value) assert "must be created with _valid_refs as a dict, not a list" in str(excinfo.value)
@ -648,10 +684,12 @@ def test_observed_data_with_custom_observable_object():
assert ob_data.objects['0'].property1 == 'something' assert ob_data.objects['0'].property1 == 'something'
@stix2.v21.CustomExtension(stix2.v21.DomainName, 'x-new-ext', [ @stix2.v21.CustomExtension(
('property1', stix2.properties.StringProperty(required=True)), stix2.v21.DomainName, 'x-new-ext', [
('property2', stix2.properties.IntegerProperty()), ('property1', stix2.properties.StringProperty(required=True)),
]) ('property2', stix2.properties.IntegerProperty()),
],
)
class NewExtension(): class NewExtension():
def __init__(self, property2=None, **kwargs): def __init__(self, property2=None, **kwargs):
if property2 and property2 < 10: if property2 and property2 < 10:
@ -689,13 +727,15 @@ def test_custom_extension_wrong_observable_type():
name="abc.txt", name="abc.txt",
extensions={ extensions={
"ntfs-ext": ext, "ntfs-ext": ext,
}) },
)
assert 'Cannot determine extension type' in excinfo.value.reason assert 'Cannot determine extension type' in excinfo.value.reason
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
"""{ "data", [
"""{
"keys": [ "keys": [
{ {
"test123": 123, "test123": 123,
@ -703,11 +743,14 @@ def test_custom_extension_wrong_observable_type():
} }
] ]
}""", }""",
]) ],
)
def test_custom_extension_with_list_and_dict_properties_observable_type(data): def test_custom_extension_with_list_and_dict_properties_observable_type(data):
@stix2.v21.CustomExtension(stix2.v21.UserAccount, 'some-extension', [ @stix2.v21.CustomExtension(
('keys', stix2.properties.ListProperty(stix2.properties.DictionaryProperty, required=True)) stix2.v21.UserAccount, 'some-extension', [
]) ('keys', stix2.properties.ListProperty(stix2.properties.DictionaryProperty, required=True)),
],
)
class SomeCustomExtension: class SomeCustomExtension:
pass pass
@ -721,9 +764,11 @@ def test_custom_extension_invalid_observable():
class Foo(object): class Foo(object):
pass pass
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomExtension(Foo, 'x-new-ext', [ @stix2.v21.CustomExtension(
('property1', stix2.properties.StringProperty(required=True)), Foo, 'x-new-ext', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class FooExtension(): class FooExtension():
pass # pragma: no cover pass # pragma: no cover
assert str(excinfo.value) == "'observable' must be a valid Observable class!" assert str(excinfo.value) == "'observable' must be a valid Observable class!"
@ -731,9 +776,11 @@ def test_custom_extension_invalid_observable():
class Bar(stix2.v21.observables._Observable): class Bar(stix2.v21.observables._Observable):
pass pass
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomExtension(Bar, 'x-new-ext', [ @stix2.v21.CustomExtension(
('property1', stix2.properties.StringProperty(required=True)), Bar, 'x-new-ext', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class BarExtension(): class BarExtension():
pass pass
assert "Unknown observable type" in str(excinfo.value) assert "Unknown observable type" in str(excinfo.value)
@ -742,9 +789,11 @@ def test_custom_extension_invalid_observable():
class Baz(stix2.v21.observables._Observable): class Baz(stix2.v21.observables._Observable):
_type = 'Baz' _type = 'Baz'
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomExtension(Baz, 'x-new-ext', [ @stix2.v21.CustomExtension(
('property1', stix2.properties.StringProperty(required=True)), Baz, 'x-new-ext', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class BazExtension(): class BazExtension():
pass pass
assert "Unknown observable type" in str(excinfo.value) assert "Unknown observable type" in str(excinfo.value)
@ -753,17 +802,21 @@ def test_custom_extension_invalid_observable():
def test_custom_extension_invalid_type_name(): def test_custom_extension_invalid_type_name():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomExtension(stix2.v21.File, 'x', { @stix2.v21.CustomExtension(
'property1': stix2.properties.StringProperty(required=True), stix2.v21.File, 'x', {
}) 'property1': stix2.properties.StringProperty(required=True),
},
)
class FooExtension(): class FooExtension():
pass # pragma: no cover pass # pragma: no cover
assert "Invalid extension type name 'x':" in str(excinfo.value) assert "Invalid extension type name 'x':" in str(excinfo.value)
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
@stix2.v21.CustomExtension(stix2.v21.File, 'x_new_ext', { @stix2.v21.CustomExtension(
'property1': stix2.properties.StringProperty(required=True), stix2.v21.File, 'x_new_ext', {
}) 'property1': stix2.properties.StringProperty(required=True),
},
)
class BlaExtension(): class BlaExtension():
pass # pragma: no cover pass # pragma: no cover
assert "Invalid extension type name 'x_new_ext':" in str(excinfo.value) assert "Invalid extension type name 'x_new_ext':" in str(excinfo.value)
@ -794,9 +847,11 @@ def test_custom_extension_dict_properties():
def test_custom_extension_no_init_1(): def test_custom_extension_no_init_1():
@stix2.v21.CustomExtension(stix2.v21.DomainName, 'x-new-extension', [ @stix2.v21.CustomExtension(
('property1', stix2.properties.StringProperty(required=True)), stix2.v21.DomainName, 'x-new-extension', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class NewExt(): class NewExt():
pass pass
@ -805,9 +860,11 @@ def test_custom_extension_no_init_1():
def test_custom_extension_no_init_2(): def test_custom_extension_no_init_2():
@stix2.v21.CustomExtension(stix2.v21.DomainName, 'x-new-ext2', [ @stix2.v21.CustomExtension(
('property1', stix2.properties.StringProperty(required=True)), stix2.v21.DomainName, 'x-new-ext2', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class NewExt2(object): class NewExt2(object):
pass pass
@ -867,8 +924,9 @@ def test_extension_property_location():
assert 'extensions' not in stix2.v21.EXT_MAP['domain-name']['x-new-ext']._properties assert 'extensions' not in stix2.v21.EXT_MAP['domain-name']['x-new-ext']._properties
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
"""{ "data", [
"""{
"type": "x-example", "type": "x-example",
"spec_version": "2.1", "spec_version": "2.1",
"id": "x-example--336d8a9f-91f1-46c5-b142-6441bb9f8b8d", "id": "x-example--336d8a9f-91f1-46c5-b142-6441bb9f8b8d",
@ -881,18 +939,23 @@ def test_extension_property_location():
} }
} }
}""", }""",
]) ],
)
def test_custom_object_nested_dictionary(data): def test_custom_object_nested_dictionary(data):
@stix2.v21.CustomObject('x-example', [ @stix2.v21.CustomObject(
('dictionary', stix2.properties.DictionaryProperty()), 'x-example', [
]) ('dictionary', stix2.properties.DictionaryProperty()),
],
)
class Example(object): class Example(object):
def __init__(self, **kwargs): def __init__(self, **kwargs):
pass pass
example = Example(id='x-example--336d8a9f-91f1-46c5-b142-6441bb9f8b8d', example = Example(
created='2018-06-12T16:20:58.059Z', id='x-example--336d8a9f-91f1-46c5-b142-6441bb9f8b8d',
modified='2018-06-12T16:20:58.059Z', created='2018-06-12T16:20:58.059Z',
dictionary={'key': {'key_b': 'value', 'key_a': 'value'}}) modified='2018-06-12T16:20:58.059Z',
dictionary={'key': {'key_b': 'value', 'key_a': 'value'}},
)
assert data == str(example) assert data == str(example)

View File

@ -1,7 +1,8 @@
import pytest import pytest
from stix2.datastore import (CompositeDataSource, DataSink, DataSource, from stix2.datastore import (
DataStoreMixin) CompositeDataSource, DataSink, DataSource, DataStoreMixin,
)
from stix2.datastore.filters import Filter from stix2.datastore.filters import Filter
from stix2.test.v21.constants import CAMPAIGN_MORE_KWARGS from stix2.test.v21.constants import CAMPAIGN_MORE_KWARGS
@ -46,15 +47,19 @@ def test_datastore_creator_of_raises():
def test_datastore_relationships_raises(): def test_datastore_relationships_raises():
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
DataStoreMixin().relationships(obj="indicator--00000000-0000-4000-8000-000000000001", DataStoreMixin().relationships(
target_only=True) obj="indicator--00000000-0000-4000-8000-000000000001",
target_only=True,
)
assert "DataStoreMixin has no data source to query" == str(excinfo.value) assert "DataStoreMixin has no data source to query" == str(excinfo.value)
def test_datastore_related_to_raises(): def test_datastore_related_to_raises():
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
DataStoreMixin().related_to(obj="indicator--00000000-0000-4000-8000-000000000001", DataStoreMixin().related_to(
target_only=True) obj="indicator--00000000-0000-4000-8000-000000000001",
target_only=True,
)
assert "DataStoreMixin has no data source to query" == str(excinfo.value) assert "DataStoreMixin has no data source to query" == str(excinfo.value)
@ -84,15 +89,19 @@ def test_composite_datastore_query_raises_error():
def test_composite_datastore_relationships_raises_error(): def test_composite_datastore_relationships_raises_error():
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
CompositeDataSource().relationships(obj="indicator--00000000-0000-4000-8000-000000000001", CompositeDataSource().relationships(
target_only=True) obj="indicator--00000000-0000-4000-8000-000000000001",
target_only=True,
)
assert "CompositeDataSource has no data sources" == str(excinfo.value) assert "CompositeDataSource has no data sources" == str(excinfo.value)
def test_composite_datastore_related_to_raises_error(): def test_composite_datastore_related_to_raises_error():
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
CompositeDataSource().related_to(obj="indicator--00000000-0000-4000-8000-000000000001", CompositeDataSource().related_to(
target_only=True) obj="indicator--00000000-0000-4000-8000-000000000001",
target_only=True,
)
assert "CompositeDataSource has no data sources" == str(excinfo.value) assert "CompositeDataSource has no data sources" == str(excinfo.value)

View File

@ -13,8 +13,10 @@ def test_add_remove_composite_datasource():
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
cds.add_data_sources([ds1, ds2, ds1, ds3]) cds.add_data_sources([ds1, ds2, ds1, ds3])
assert str(excinfo.value) == ("DataSource (to be added) is not of type " assert str(excinfo.value) == (
"stix2.DataSource. DataSource type is '<class 'stix2.datastore.memory.MemorySink'>'") "DataSource (to be added) is not of type "
"stix2.DataSource. DataSource type is '<class 'stix2.datastore.memory.MemorySink'>'"
)
cds.add_data_sources([ds1, ds2, ds1]) cds.add_data_sources([ds1, ds2, ds1])
@ -26,9 +28,11 @@ def test_add_remove_composite_datasource():
def test_composite_datasource_operations(stix_objs1, stix_objs2): def test_composite_datasource_operations(stix_objs1, stix_objs2):
BUNDLE1 = dict(id="bundle--%s" % make_id(), BUNDLE1 = dict(
objects=stix_objs1, id="bundle--%s" % make_id(),
type="bundle") objects=stix_objs1,
type="bundle",
)
cds1 = CompositeDataSource() cds1 = CompositeDataSource()
ds1_1 = MemorySource(stix_data=BUNDLE1) ds1_1 = MemorySource(stix_data=BUNDLE1)
ds1_2 = MemorySource(stix_data=stix_objs2) ds1_2 = MemorySource(stix_data=stix_objs2)
@ -54,11 +58,11 @@ def test_composite_datasource_operations(stix_objs1, stix_objs2):
assert indicator["type"] == "indicator" assert indicator["type"] == "indicator"
query1 = [ query1 = [
Filter("type", "=", "indicator") Filter("type", "=", "indicator"),
] ]
query2 = [ query2 = [
Filter("valid_from", "=", "2017-01-27T13:49:53.935382Z") Filter("valid_from", "=", "2017-01-27T13:49:53.935382Z"),
] ]
cds1.filters.add(query2) cds1.filters.add(query2)

View File

@ -5,11 +5,10 @@ import shutil
import pytest import pytest
import stix2 import stix2
from stix2.test.v21.constants import (CAMPAIGN_ID, CAMPAIGN_KWARGS, from stix2.test.v21.constants import (
IDENTITY_ID, IDENTITY_KWARGS, CAMPAIGN_ID, CAMPAIGN_KWARGS, IDENTITY_ID, IDENTITY_KWARGS, INDICATOR_ID,
INDICATOR_ID, INDICATOR_KWARGS, INDICATOR_KWARGS, MALWARE_ID, MALWARE_KWARGS, RELATIONSHIP_IDS,
MALWARE_ID, MALWARE_KWARGS, )
RELATIONSHIP_IDS)
FS_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "stix2_data") FS_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "stix2_data")
@ -68,7 +67,7 @@ def bad_stix_files():
# bad STIX object # bad STIX object
stix_obj = { stix_obj = {
"id": "intrusion-set--test-bad-stix", "id": "intrusion-set--test-bad-stix",
"spec_version": "2.0" "spec_version": "2.0",
# no "type" field # no "type" field
} }
@ -175,9 +174,11 @@ def test_filesytem_source_query_multiple(fs_source):
def test_filesystem_sink_add_python_stix_object(fs_sink, fs_source): def test_filesystem_sink_add_python_stix_object(fs_sink, fs_source):
# add python stix object # add python stix object
camp1 = stix2.v21.Campaign(name="Hannibal", camp1 = stix2.v21.Campaign(
objective="Targeting Italian and Spanish Diplomat internet accounts", name="Hannibal",
aliases=["War Elephant"]) objective="Targeting Italian and Spanish Diplomat internet accounts",
aliases=["War Elephant"],
)
fs_sink.add(camp1) fs_sink.add(camp1)
@ -199,7 +200,7 @@ def test_filesystem_sink_add_stix_object_dict(fs_sink, fs_source):
"objective": "German and French Intelligence Services", "objective": "German and French Intelligence Services",
"aliases": ["Purple Robes"], "aliases": ["Purple Robes"],
"id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", "id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
"created": "2017-05-31T21:31:53.197755Z" "created": "2017-05-31T21:31:53.197755Z",
} }
fs_sink.add(camp2) fs_sink.add(camp2)
@ -226,9 +227,9 @@ def test_filesystem_sink_add_stix_bundle_dict(fs_sink, fs_source):
"objective": "Bulgarian, Albanian and Romanian Intelligence Services", "objective": "Bulgarian, Albanian and Romanian Intelligence Services",
"aliases": ["Huns"], "aliases": ["Huns"],
"id": "campaign--b8f86161-ccae-49de-973a-4ca320c62478", "id": "campaign--b8f86161-ccae-49de-973a-4ca320c62478",
"created": "2017-05-31T21:31:53.197755Z" "created": "2017-05-31T21:31:53.197755Z",
} },
] ],
} }
fs_sink.add(bund) fs_sink.add(bund)
@ -277,9 +278,11 @@ def test_filesystem_sink_json_stix_bundle(fs_sink, fs_source):
def test_filesystem_sink_add_objects_list(fs_sink, fs_source): def test_filesystem_sink_add_objects_list(fs_sink, fs_source):
# add list of objects # add list of objects
camp6 = stix2.v21.Campaign(name="Comanche", camp6 = stix2.v21.Campaign(
objective="US Midwest manufacturing firms, oil refineries, and businesses", name="Comanche",
aliases=["Horse Warrior"]) objective="US Midwest manufacturing firms, oil refineries, and businesses",
aliases=["Horse Warrior"],
)
camp7 = { camp7 = {
"name": "Napolean", "name": "Napolean",
@ -288,7 +291,7 @@ def test_filesystem_sink_add_objects_list(fs_sink, fs_source):
"objective": "Central and Eastern Europe military commands and departments", "objective": "Central and Eastern Europe military commands and departments",
"aliases": ["The Frenchmen"], "aliases": ["The Frenchmen"],
"id": "campaign--122818b6-1112-4fb0-b11b-b111107ca70a", "id": "campaign--122818b6-1112-4fb0-b11b-b111107ca70a",
"created": "2017-05-31T21:31:53.197755Z" "created": "2017-05-31T21:31:53.197755Z",
} }
fs_sink.add([camp6, camp7]) fs_sink.add([camp6, camp7])
@ -365,9 +368,11 @@ def test_filesystem_store_query_dont_include_type_folder(fs_store):
def test_filesystem_store_add(fs_store): def test_filesystem_store_add(fs_store):
# add() # add()
camp1 = stix2.v21.Campaign(name="Great Heathen Army", camp1 = stix2.v21.Campaign(
objective="Targeting the government of United Kingdom and insitutions affiliated with the Church Of England", name="Great Heathen Army",
aliases=["Ragnar"]) objective="Targeting the government of United Kingdom and insitutions affiliated with the Church Of England",
aliases=["Ragnar"],
)
fs_store.add(camp1) fs_store.add(camp1)
camp1_r = fs_store.get(camp1.id) camp1_r = fs_store.get(camp1.id)
@ -381,9 +386,11 @@ def test_filesystem_store_add(fs_store):
def test_filesystem_store_add_as_bundle(): def test_filesystem_store_add_as_bundle():
fs_store = stix2.FileSystemStore(FS_PATH, bundlify=True) fs_store = stix2.FileSystemStore(FS_PATH, bundlify=True)
camp1 = stix2.v21.Campaign(name="Great Heathen Army", camp1 = stix2.v21.Campaign(
objective="Targeting the government of United Kingdom and insitutions affiliated with the Church Of England", name="Great Heathen Army",
aliases=["Ragnar"]) objective="Targeting the government of United Kingdom and insitutions affiliated with the Church Of England",
aliases=["Ragnar"],
)
fs_store.add(camp1) fs_store.add(camp1)
with open(os.path.join(FS_PATH, "campaign", camp1.id + ".json")) as bundle_file: with open(os.path.join(FS_PATH, "campaign", camp1.id + ".json")) as bundle_file:
@ -412,10 +419,12 @@ def test_filesystem_store_add_invalid_object(fs_store):
def test_filesystem_object_with_custom_property(fs_store): def test_filesystem_object_with_custom_property(fs_store):
camp = stix2.v21.Campaign(name="Scipio Africanus", camp = stix2.v21.Campaign(
objective="Defeat the Carthaginians", name="Scipio Africanus",
x_empire="Roman", objective="Defeat the Carthaginians",
allow_custom=True) x_empire="Roman",
allow_custom=True,
)
fs_store.add(camp) fs_store.add(camp)
@ -425,10 +434,12 @@ def test_filesystem_object_with_custom_property(fs_store):
def test_filesystem_object_with_custom_property_in_bundle(fs_store): def test_filesystem_object_with_custom_property_in_bundle(fs_store):
camp = stix2.v21.Campaign(name="Scipio Africanus", camp = stix2.v21.Campaign(
objective="Defeat the Carthaginians", name="Scipio Africanus",
x_empire="Roman", objective="Defeat the Carthaginians",
allow_custom=True) x_empire="Roman",
allow_custom=True,
)
bundle = stix2.v21.Bundle(camp, allow_custom=True) bundle = stix2.v21.Bundle(camp, allow_custom=True)
fs_store.add(bundle) fs_store.add(bundle)
@ -439,9 +450,11 @@ def test_filesystem_object_with_custom_property_in_bundle(fs_store):
def test_filesystem_custom_object(fs_store): def test_filesystem_custom_object(fs_store):
@stix2.v21.CustomObject('x-new-obj', [ @stix2.v21.CustomObject(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-obj', [
]) ('property1', stix2.properties.StringProperty(required=True)),
],
)
class NewObj(): class NewObj():
pass pass

View File

@ -11,25 +11,25 @@ stix_objs = [
"id": "malware--fdd60b30-b67c-41e3-b0b9-f01faf20d111", "id": "malware--fdd60b30-b67c-41e3-b0b9-f01faf20d111",
"spec_version": "2.1", "spec_version": "2.1",
"malware_types": [ "malware_types": [
"remote-access-trojan" "remote-access-trojan",
], ],
"modified": "2017-01-27T13:49:53.997Z", "modified": "2017-01-27T13:49:53.997Z",
"name": "Poison Ivy", "name": "Poison Ivy",
"type": "malware", "type": "malware",
"is_family": False "is_family": False,
}, },
{ {
"created": "2014-05-08T09:00:00.000Z", "created": "2014-05-08T09:00:00.000Z",
"id": "indicator--a932fcc6-e032-476c-826f-cb970a5a1ade", "id": "indicator--a932fcc6-e032-476c-826f-cb970a5a1ade",
"indicator_types": [ "indicator_types": [
"file-hash-watchlist" "file-hash-watchlist",
], ],
"modified": "2014-05-08T09:00:00.000Z", "modified": "2014-05-08T09:00:00.000Z",
"name": "File hash for Poison Ivy variant", "name": "File hash for Poison Ivy variant",
"pattern": "[file:hashes.'SHA-256' = 'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c']", "pattern": "[file:hashes.'SHA-256' = 'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c']",
"spec_version": "2.1", "spec_version": "2.1",
"type": "indicator", "type": "indicator",
"valid_from": "2014-05-08T09:00:00.000000Z" "valid_from": "2014-05-08T09:00:00.000000Z",
}, },
{ {
"created": "2014-05-08T09:00:00.000Z", "created": "2014-05-08T09:00:00.000Z",
@ -37,21 +37,21 @@ stix_objs = [
{ {
"marking_ref": "marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed", "marking_ref": "marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed",
"selectors": [ "selectors": [
"relationship_type" "relationship_type",
] ],
} },
], ],
"id": "relationship--2f9a9aa9-108a-4333-83e2-4fb25add0463", "id": "relationship--2f9a9aa9-108a-4333-83e2-4fb25add0463",
"modified": "2014-05-08T09:00:00.000Z", "modified": "2014-05-08T09:00:00.000Z",
"object_marking_refs": [ "object_marking_refs": [
"marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9" "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
], ],
"relationship_type": "indicates", "relationship_type": "indicates",
"revoked": True, "revoked": True,
"source_ref": "indicator--a932fcc6-e032-476c-826f-cb970a5a1ade", "source_ref": "indicator--a932fcc6-e032-476c-826f-cb970a5a1ade",
"spec_version": "2.1", "spec_version": "2.1",
"target_ref": "malware--fdd60b30-b67c-41e3-b0b9-f01faf20d111", "target_ref": "malware--fdd60b30-b67c-41e3-b0b9-f01faf20d111",
"type": "relationship" "type": "relationship",
}, },
{ {
"id": "vulnerability--ee916c28-c7a4-4d0d-ad56-a8d357f89fef", "id": "vulnerability--ee916c28-c7a4-4d0d-ad56-a8d357f89fef",
@ -65,10 +65,10 @@ stix_objs = [
"external_references": [ "external_references": [
{ {
"source_name": "cve", "source_name": "cve",
"external_id": "CVE-2014-0160" "external_id": "CVE-2014-0160",
} },
], ],
"labels": ["heartbleed", "has-logo"] "labels": ["heartbleed", "has-logo"],
}, },
{ {
"type": "observed-data", "type": "observed-data",
@ -83,11 +83,11 @@ stix_objs = [
"objects": { "objects": {
"0": { "0": {
"type": "file", "type": "file",
"name": "HAL 9000.exe" "name": "HAL 9000.exe",
} },
} },
} },
] ]
@ -420,8 +420,10 @@ def test_filters4():
# Assert invalid Filter cannot be created # Assert invalid Filter cannot be created
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
Filter("modified", "?", "2017-01-27T13:49:53.935Z") Filter("modified", "?", "2017-01-27T13:49:53.935Z")
assert str(excinfo.value) == ("Filter operator '?' not supported " assert str(excinfo.value) == (
"for specified property: 'modified'") "Filter operator '?' not supported "
"for specified property: 'modified'"
)
def test_filters5(stix_objs2, real_stix_objs2): def test_filters5(stix_objs2, real_stix_objs2):
@ -462,7 +464,7 @@ def test_filters7(stix_objs2, real_stix_objs2):
"0": { "0": {
"type": "file", "type": "file",
"hashes": { "hashes": {
"SHA-256": "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f" "SHA-256": "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f",
}, },
"extensions": { "extensions": {
"pdf-ext": { "pdf-ext": {
@ -472,14 +474,14 @@ def test_filters7(stix_objs2, real_stix_objs2):
"Author": "Adobe Systems Incorporated", "Author": "Adobe Systems Incorporated",
"Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh", "Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh",
"Producer": "Acrobat Distiller 3.01 for Power Macintosh", "Producer": "Acrobat Distiller 3.01 for Power Macintosh",
"CreationDate": "20070412090123-02" "CreationDate": "20070412090123-02",
}, },
"pdfid0": "DFCE52BD827ECF765649852119D", "pdfid0": "DFCE52BD827ECF765649852119D",
"pdfid1": "57A1E0F9ED2AE523E313C" "pdfid1": "57A1E0F9ED2AE523E313C",
} },
} },
} },
} },
} }
stix_objects = list(stix_objs2) + [obsvd_data_obj] stix_objects = list(stix_objs2) + [obsvd_data_obj]

View File

@ -5,116 +5,118 @@ import pytest
from stix2 import Filter, MemorySource, MemoryStore, properties from stix2 import Filter, MemorySource, MemoryStore, properties
from stix2.datastore import make_id from stix2.datastore import make_id
from stix2.v21 import (Bundle, Campaign, CustomObject, Identity, Indicator, from stix2.v21 import (
Malware, Relationship) Bundle, Campaign, CustomObject, Identity, Indicator, Malware, Relationship,
)
from .constants import (CAMPAIGN_ID, CAMPAIGN_KWARGS, IDENTITY_ID, from .constants import (
IDENTITY_KWARGS, INDICATOR_ID, INDICATOR_KWARGS, CAMPAIGN_ID, CAMPAIGN_KWARGS, IDENTITY_ID, IDENTITY_KWARGS, INDICATOR_ID,
MALWARE_ID, MALWARE_KWARGS, RELATIONSHIP_IDS) INDICATOR_KWARGS, MALWARE_ID, MALWARE_KWARGS, RELATIONSHIP_IDS,
)
IND1 = { IND1 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000001", "id": "indicator--00000000-0000-4000-8000-000000000001",
"indicator_types": [ "indicator_types": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"spec_version": "2.1", "spec_version": "2.1",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
IND2 = { IND2 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000001", "id": "indicator--00000000-0000-4000-8000-000000000001",
"indicator_types": [ "indicator_types": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"spec_version": "2.1", "spec_version": "2.1",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
IND3 = { IND3 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000001", "id": "indicator--00000000-0000-4000-8000-000000000001",
"indicator_types": [ "indicator_types": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.936Z", "modified": "2017-01-27T13:49:53.936Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"spec_version": "2.1", "spec_version": "2.1",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
IND4 = { IND4 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000002", "id": "indicator--00000000-0000-4000-8000-000000000002",
"indicator_types": [ "indicator_types": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"spec_version": "2.1", "spec_version": "2.1",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
IND5 = { IND5 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000002", "id": "indicator--00000000-0000-4000-8000-000000000002",
"indicator_types": [ "indicator_types": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"spec_version": "2.1", "spec_version": "2.1",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
IND6 = { IND6 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000001", "id": "indicator--00000000-0000-4000-8000-000000000001",
"indicator_types": [ "indicator_types": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-31T13:49:53.935Z", "modified": "2017-01-31T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"spec_version": "2.1", "spec_version": "2.1",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
IND7 = { IND7 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000002", "id": "indicator--00000000-0000-4000-8000-000000000002",
"indicator_types": [ "indicator_types": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"spec_version": "2.1", "spec_version": "2.1",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
IND8 = { IND8 = {
"created": "2017-01-27T13:49:53.935Z", "created": "2017-01-27T13:49:53.935Z",
"id": "indicator--00000000-0000-4000-8000-000000000002", "id": "indicator--00000000-0000-4000-8000-000000000002",
"indicator_types": [ "indicator_types": [
"url-watchlist" "url-watchlist",
], ],
"modified": "2017-01-27T13:49:53.935Z", "modified": "2017-01-27T13:49:53.935Z",
"name": "Malicious site hosting downloader", "name": "Malicious site hosting downloader",
"pattern": "[url:value = 'http://x4z9arb.cn/4712']", "pattern": "[url:value = 'http://x4z9arb.cn/4712']",
"spec_version": "2.1", "spec_version": "2.1",
"type": "indicator", "type": "indicator",
"valid_from": "2017-01-27T13:49:53.935382Z" "valid_from": "2017-01-27T13:49:53.935382Z",
} }
STIX_OBJS2 = [IND6, IND7, IND8] STIX_OBJS2 = [IND6, IND7, IND8]
@ -169,10 +171,12 @@ def test_memory_source_get_nonexistant_object(mem_source):
def test_memory_store_all_versions(mem_store): def test_memory_store_all_versions(mem_store):
# Add bundle of items to sink # Add bundle of items to sink
mem_store.add(dict(id="bundle--%s" % make_id(), mem_store.add(dict(
objects=STIX_OBJS2, id="bundle--%s" % make_id(),
spec_version="2.0", objects=STIX_OBJS2,
type="bundle")) spec_version="2.0",
type="bundle",
))
resp = mem_store.all_versions("indicator--00000000-0000-4000-8000-000000000001") resp = mem_store.all_versions("indicator--00000000-0000-4000-8000-000000000001")
assert len(resp) == 1 # MemoryStore can only store 1 version of each object assert len(resp) == 1 # MemoryStore can only store 1 version of each object
@ -235,10 +239,12 @@ def test_memory_store_add_invalid_object(mem_store):
def test_memory_store_object_with_custom_property(mem_store): def test_memory_store_object_with_custom_property(mem_store):
camp = Campaign(name="Scipio Africanus", camp = Campaign(
objective="Defeat the Carthaginians", name="Scipio Africanus",
x_empire="Roman", objective="Defeat the Carthaginians",
allow_custom=True) x_empire="Roman",
allow_custom=True,
)
mem_store.add(camp) mem_store.add(camp)
@ -248,10 +254,12 @@ def test_memory_store_object_with_custom_property(mem_store):
def test_memory_store_object_with_custom_property_in_bundle(mem_store): def test_memory_store_object_with_custom_property_in_bundle(mem_store):
camp = Campaign(name="Scipio Africanus", camp = Campaign(
objective="Defeat the Carthaginians", name="Scipio Africanus",
x_empire="Roman", objective="Defeat the Carthaginians",
allow_custom=True) x_empire="Roman",
allow_custom=True,
)
bundle = Bundle(camp, allow_custom=True) bundle = Bundle(camp, allow_custom=True)
mem_store.add(bundle) mem_store.add(bundle)
@ -262,9 +270,11 @@ def test_memory_store_object_with_custom_property_in_bundle(mem_store):
def test_memory_store_custom_object(mem_store): def test_memory_store_custom_object(mem_store):
@CustomObject('x-new-obj', [ @CustomObject(
('property1', properties.StringProperty(required=True)), 'x-new-obj', [
]) ('property1', properties.StringProperty(required=True)),
],
)
class NewObj(): class NewObj():
pass pass

View File

@ -36,7 +36,7 @@ class MockTAXIICollectionEndpoint(Collection):
objs = full_filter.process_filter( objs = full_filter.process_filter(
self.objects, self.objects,
("id", "type", "version"), ("id", "type", "version"),
[] [],
) )
if objs: if objs:
return stix2.v21.Bundle(objects=objs) return stix2.v21.Bundle(objects=objs)
@ -56,7 +56,7 @@ class MockTAXIICollectionEndpoint(Collection):
objs = full_filter.process_filter( objs = full_filter.process_filter(
self.objects, self.objects,
("version",), ("version",),
[] [],
) )
if objs: if objs:
return stix2.v21.Bundle(objects=objs) return stix2.v21.Bundle(objects=objs)
@ -68,16 +68,18 @@ class MockTAXIICollectionEndpoint(Collection):
@pytest.fixture @pytest.fixture
def collection(stix_objs1): def collection(stix_objs1):
mock = MockTAXIICollectionEndpoint(COLLECTION_URL, **{ mock = MockTAXIICollectionEndpoint(
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116", COLLECTION_URL, **{
"title": "Writable Collection", "id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
"description": "This collection is a dropbox for submitting indicators", "title": "Writable Collection",
"can_read": True, "description": "This collection is a dropbox for submitting indicators",
"can_write": True, "can_read": True,
"media_types": [ "can_write": True,
"application/vnd.oasis.stix+json; version=2.0" "media_types": [
] "application/vnd.oasis.stix+json; version=2.0",
}) ],
}
)
mock.objects.extend(stix_objs1) mock.objects.extend(stix_objs1)
return mock return mock
@ -85,16 +87,18 @@ def collection(stix_objs1):
@pytest.fixture @pytest.fixture
def collection_no_rw_access(stix_objs1): def collection_no_rw_access(stix_objs1):
mock = MockTAXIICollectionEndpoint(COLLECTION_URL, **{ mock = MockTAXIICollectionEndpoint(
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116", COLLECTION_URL, **{
"title": "Not writeable or readable Collection", "id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
"description": "This collection is a dropbox for submitting indicators", "title": "Not writeable or readable Collection",
"can_read": False, "description": "This collection is a dropbox for submitting indicators",
"can_write": False, "can_read": False,
"media_types": [ "can_write": False,
"application/vnd.oasis.stix+json; version=2.0" "media_types": [
] "application/vnd.oasis.stix+json; version=2.0",
}) ],
}
)
mock.objects.extend(stix_objs1) mock.objects.extend(stix_objs1)
return mock return mock
@ -109,14 +113,16 @@ def test_add_stix2_object(collection):
tc_sink = stix2.TAXIICollectionSink(collection) tc_sink = stix2.TAXIICollectionSink(collection)
# create new STIX threat-actor # create new STIX threat-actor
ta = stix2.v21.ThreatActor(name="Teddy Bear", ta = stix2.v21.ThreatActor(
threat_actor_types=["nation-state"], name="Teddy Bear",
sophistication="innovator", threat_actor_types=["nation-state"],
resource_level="government", sophistication="innovator",
goals=[ resource_level="government",
"compromising environment NGOs", goals=[
"water-hole attacks geared towards energy sector", "compromising environment NGOs",
]) "water-hole attacks geared towards energy sector",
],
)
tc_sink.add(ta) tc_sink.add(ta)
@ -125,16 +131,18 @@ def test_add_stix2_with_custom_object(collection):
tc_sink = stix2.TAXIICollectionStore(collection, allow_custom=True) tc_sink = stix2.TAXIICollectionStore(collection, allow_custom=True)
# create new STIX threat-actor # create new STIX threat-actor
ta = stix2.v21.ThreatActor(name="Teddy Bear", ta = stix2.v21.ThreatActor(
threat_actor_types=["nation-state"], name="Teddy Bear",
sophistication="innovator", threat_actor_types=["nation-state"],
resource_level="government", sophistication="innovator",
goals=[ resource_level="government",
"compromising environment NGOs", goals=[
"water-hole attacks geared towards energy sector", "compromising environment NGOs",
], "water-hole attacks geared towards energy sector",
foo="bar", ],
allow_custom=True) foo="bar",
allow_custom=True,
)
tc_sink.add(ta) tc_sink.add(ta)
@ -143,14 +151,16 @@ def test_add_list_object(collection, indicator):
tc_sink = stix2.TAXIICollectionSink(collection) tc_sink = stix2.TAXIICollectionSink(collection)
# create new STIX threat-actor # create new STIX threat-actor
ta = stix2.v21.ThreatActor(name="Teddy Bear", ta = stix2.v21.ThreatActor(
threat_actor_types=["nation-state"], name="Teddy Bear",
sophistication="innovator", threat_actor_types=["nation-state"],
resource_level="government", sophistication="innovator",
goals=[ resource_level="government",
"compromising environment NGOs", goals=[
"water-hole attacks geared towards energy sector", "compromising environment NGOs",
]) "water-hole attacks geared towards energy sector",
],
)
tc_sink.add([ta, indicator]) tc_sink.add([ta, indicator])
@ -159,14 +169,16 @@ def test_add_stix2_bundle_object(collection):
tc_sink = stix2.TAXIICollectionSink(collection) tc_sink = stix2.TAXIICollectionSink(collection)
# create new STIX threat-actor # create new STIX threat-actor
ta = stix2.v21.ThreatActor(name="Teddy Bear", ta = stix2.v21.ThreatActor(
threat_actor_types=["nation-state"], name="Teddy Bear",
sophistication="innovator", threat_actor_types=["nation-state"],
resource_level="government", sophistication="innovator",
goals=[ resource_level="government",
"compromising environment NGOs", goals=[
"water-hole attacks geared towards energy sector", "compromising environment NGOs",
]) "water-hole attacks geared towards energy sector",
],
)
tc_sink.add(stix2.v21.Bundle(objects=[ta])) tc_sink.add(stix2.v21.Bundle(objects=[ta]))
@ -208,13 +220,13 @@ def test_add_dict_object(collection):
"name": "Teddy Bear", "name": "Teddy Bear",
"goals": [ "goals": [
"compromising environment NGOs", "compromising environment NGOs",
"water-hole attacks geared towards energy sector" "water-hole attacks geared towards energy sector",
], ],
"sophistication": "innovator", "sophistication": "innovator",
"resource_level": "government", "resource_level": "government",
"threat_actor_types": [ "threat_actor_types": [
"nation-state" "nation-state",
] ],
} }
tc_sink.add(ta) tc_sink.add(ta)
@ -236,15 +248,15 @@ def test_add_dict_bundle_object(collection):
"name": "Teddy Bear", "name": "Teddy Bear",
"goals": [ "goals": [
"compromising environment NGOs", "compromising environment NGOs",
"water-hole attacks geared towards energy sector" "water-hole attacks geared towards energy sector",
], ],
"sophistication": "innovator", "sophistication": "innovator",
"resource_level": "government", "resource_level": "government",
"threat_actor_types": [ "threat_actor_types": [
"nation-state" "nation-state",
] ],
} },
] ],
} }
tc_sink.add(ta) tc_sink.add(ta)
@ -271,7 +283,7 @@ def test_parse_taxii_filters(collection):
Filter("added_after", "=", "2016-02-01T00:00:01.000Z"), Filter("added_after", "=", "2016-02-01T00:00:01.000Z"),
Filter("id", "=", "taxii stix object ID"), Filter("id", "=", "taxii stix object ID"),
Filter("type", "=", "taxii stix object ID"), Filter("type", "=", "taxii stix object ID"),
Filter("version", "=", "first") Filter("version", "=", "first"),
] ]
ds = stix2.TAXIICollectionSource(collection) ds = stix2.TAXIICollectionSource(collection)

View File

@ -2,9 +2,11 @@ import pytest
import stix2 import stix2
from .constants import (CAMPAIGN_ID, CAMPAIGN_KWARGS, FAKE_TIME, IDENTITY_ID, from .constants import (
IDENTITY_KWARGS, INDICATOR_ID, INDICATOR_KWARGS, CAMPAIGN_ID, CAMPAIGN_KWARGS, FAKE_TIME, IDENTITY_ID, IDENTITY_KWARGS,
MALWARE_ID, MALWARE_KWARGS, RELATIONSHIP_IDS) INDICATOR_ID, INDICATOR_KWARGS, MALWARE_ID, MALWARE_KWARGS,
RELATIONSHIP_IDS,
)
@pytest.fixture @pytest.fixture
@ -48,8 +50,10 @@ def test_object_factory_created():
def test_object_factory_external_reference(): def test_object_factory_external_reference():
ext_ref = stix2.v21.ExternalReference(source_name="ACME Threat Intel", ext_ref = stix2.v21.ExternalReference(
description="Threat report") source_name="ACME Threat Intel",
description="Threat report",
)
factory = stix2.ObjectFactory(external_references=ext_ref) factory = stix2.ObjectFactory(external_references=ext_ref)
ind = factory.create(stix2.v21.Indicator, **INDICATOR_KWARGS) ind = factory.create(stix2.v21.Indicator, **INDICATOR_KWARGS)
assert ind.external_references[0].source_name == "ACME Threat Intel" assert ind.external_references[0].source_name == "ACME Threat Intel"
@ -61,8 +65,10 @@ def test_object_factory_external_reference():
def test_object_factory_obj_markings(): def test_object_factory_obj_markings():
stmt_marking = stix2.v21.StatementMarking("Copyright 2016, Example Corp") stmt_marking = stix2.v21.StatementMarking("Copyright 2016, Example Corp")
mark_def = stix2.v21.MarkingDefinition(definition_type="statement", mark_def = stix2.v21.MarkingDefinition(
definition=stmt_marking) definition_type="statement",
definition=stmt_marking,
)
factory = stix2.ObjectFactory(object_marking_refs=[mark_def, stix2.v21.TLP_AMBER]) factory = stix2.ObjectFactory(object_marking_refs=[mark_def, stix2.v21.TLP_AMBER])
ind = factory.create(stix2.v21.Indicator, **INDICATOR_KWARGS) ind = factory.create(stix2.v21.Indicator, **INDICATOR_KWARGS)
assert mark_def.id in ind.object_marking_refs assert mark_def.id in ind.object_marking_refs
@ -74,12 +80,18 @@ def test_object_factory_obj_markings():
def test_object_factory_list_append(): def test_object_factory_list_append():
ext_ref = stix2.v21.ExternalReference(source_name="ACME Threat Intel", ext_ref = stix2.v21.ExternalReference(
description="Threat report from ACME") source_name="ACME Threat Intel",
ext_ref2 = stix2.v21.ExternalReference(source_name="Yet Another Threat Report", description="Threat report from ACME",
description="Threat report from YATR") )
ext_ref3 = stix2.v21.ExternalReference(source_name="Threat Report #3", ext_ref2 = stix2.v21.ExternalReference(
description="One more threat report") source_name="Yet Another Threat Report",
description="Threat report from YATR",
)
ext_ref3 = stix2.v21.ExternalReference(
source_name="Threat Report #3",
description="One more threat report",
)
factory = stix2.ObjectFactory(external_references=ext_ref) factory = stix2.ObjectFactory(external_references=ext_ref)
ind = factory.create(stix2.v21.Indicator, external_references=ext_ref2, **INDICATOR_KWARGS) ind = factory.create(stix2.v21.Indicator, external_references=ext_ref2, **INDICATOR_KWARGS)
assert ind.external_references[1].source_name == "Yet Another Threat Report" assert ind.external_references[1].source_name == "Yet Another Threat Report"
@ -89,10 +101,14 @@ def test_object_factory_list_append():
def test_object_factory_list_replace(): def test_object_factory_list_replace():
ext_ref = stix2.v21.ExternalReference(source_name="ACME Threat Intel", ext_ref = stix2.v21.ExternalReference(
description="Threat report from ACME") source_name="ACME Threat Intel",
ext_ref2 = stix2.v21.ExternalReference(source_name="Yet Another Threat Report", description="Threat report from ACME",
description="Threat report from YATR") )
ext_ref2 = stix2.v21.ExternalReference(
source_name="Yet Another Threat Report",
description="Threat report from YATR",
)
factory = stix2.ObjectFactory(external_references=ext_ref, list_append=False) factory = stix2.ObjectFactory(external_references=ext_ref, list_append=False)
ind = factory.create(stix2.v21.Indicator, external_references=ext_ref2, **INDICATOR_KWARGS) ind = factory.create(stix2.v21.Indicator, external_references=ext_ref2, **INDICATOR_KWARGS)
assert len(ind.external_references) == 1 assert len(ind.external_references) == 1
@ -100,8 +116,10 @@ def test_object_factory_list_replace():
def test_environment_functions(): def test_environment_functions():
env = stix2.Environment(stix2.ObjectFactory(created_by_ref=IDENTITY_ID), env = stix2.Environment(
stix2.MemoryStore()) stix2.ObjectFactory(created_by_ref=IDENTITY_ID),
stix2.MemoryStore(),
)
# Create a STIX object # Create a STIX object
ind = env.create(stix2.v21.Indicator, id=INDICATOR_ID, **INDICATOR_KWARGS) ind = env.create(stix2.v21.Indicator, id=INDICATOR_ID, **INDICATOR_KWARGS)
@ -125,8 +143,10 @@ def test_environment_functions():
assert len(resp) == 0 assert len(resp) == 0
# See different results after adding filters to the environment # See different results after adding filters to the environment
env.add_filters([stix2.Filter('type', '=', 'indicator'), env.add_filters([
stix2.Filter('created_by_ref', '=', IDENTITY_ID)]) stix2.Filter('type', '=', 'indicator'),
stix2.Filter('created_by_ref', '=', IDENTITY_ID),
])
env.add_filter(stix2.Filter('labels', '=', 'benign')) # should be 'malicious-activity' env.add_filter(stix2.Filter('labels', '=', 'benign')) # should be 'malicious-activity'
resp = env.get(INDICATOR_ID) resp = env.get(INDICATOR_ID)
assert resp['labels'][0] == 'benign' # should be 'malicious-activity' assert resp['labels'][0] == 'benign' # should be 'malicious-activity'
@ -140,8 +160,10 @@ def test_environment_source_and_sink():
def test_environment_datastore_and_sink(): def test_environment_datastore_and_sink():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
stix2.Environment(factory=stix2.ObjectFactory(), stix2.Environment(
store=stix2.MemoryStore(), sink=stix2.MemorySink) factory=stix2.ObjectFactory(),
store=stix2.MemoryStore(), sink=stix2.MemorySink,
)
assert 'Data store already provided' in str(excinfo.value) assert 'Data store already provided' in str(excinfo.value)
@ -265,7 +287,7 @@ def test_relationships_no_id(ds):
env = stix2.Environment(store=ds) env = stix2.Environment(store=ds)
mal = { mal = {
"type": "malware", "type": "malware",
"name": "some variant" "name": "some variant",
} }
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
env.relationships(mal) env.relationships(mal)
@ -329,7 +351,7 @@ def test_related_to_no_id(ds):
env = stix2.Environment(store=ds) env = stix2.Environment(store=ds)
mal = { mal = {
"type": "malware", "type": "malware",
"name": "some variant" "name": "some variant",
} }
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
env.related_to(mal) env.related_to(mal)

View File

@ -21,7 +21,7 @@ def test_external_reference_veris():
source_name="veris", source_name="veris",
external_id="0001AA7F-C601-424A-B2B8-BE6C9F5164E7", external_id="0001AA7F-C601-424A-B2B8-BE6C9F5164E7",
hashes={ hashes={
"SHA-256": "6db12788c37247f2316052e142f42f4b259d6561751e5f401a1ae2a6df9c674b" "SHA-256": "6db12788c37247f2316052e142f42f4b259d6561751e5f401a1ae2a6df9c674b",
}, },
url="https://github.com/vz-risk/VCDB/blob/master/data/json/0001AA7F-C601-424A-B2B8-BE6C9F5164E7.json", url="https://github.com/vz-risk/VCDB/blob/master/data/json/0001AA7F-C601-424A-B2B8-BE6C9F5164E7.json",
) )

View File

@ -20,11 +20,11 @@ def test_add_marking_mark_one_selector_multiple_refs():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
}, },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
@ -35,44 +35,49 @@ def test_add_marking_mark_one_selector_multiple_refs():
assert m in after["granular_markings"] assert m in after["granular_markings"]
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
( "data", [
Malware(**MALWARE_KWARGS), (
Malware( Malware(**MALWARE_KWARGS),
granular_markings=[ Malware(
{ granular_markings=[
"selectors": ["description", "name"], {
"marking_ref": MARKING_IDS[0] "selectors": ["description", "name"],
}, "marking_ref": MARKING_IDS[0],
], },
**MALWARE_KWARGS), ],
MARKING_IDS[0], **MALWARE_KWARGS
), ),
( MARKING_IDS[0],
MALWARE_KWARGS, ),
dict( (
granular_markings=[ MALWARE_KWARGS,
{ dict(
"selectors": ["description", "name"], granular_markings=[
"marking_ref": MARKING_IDS[0] {
}, "selectors": ["description", "name"],
], "marking_ref": MARKING_IDS[0],
**MALWARE_KWARGS), },
MARKING_IDS[0], ],
), **MALWARE_KWARGS
( ),
Malware(**MALWARE_KWARGS), MARKING_IDS[0],
Malware( ),
granular_markings=[ (
{ Malware(**MALWARE_KWARGS),
"selectors": ["description", "name"], Malware(
"marking_ref": TLP_RED.id, granular_markings=[
}, {
], "selectors": ["description", "name"],
**MALWARE_KWARGS), "marking_ref": TLP_RED.id,
TLP_RED, },
), ],
]) **MALWARE_KWARGS
),
TLP_RED,
),
],
)
def test_add_marking_mark_multiple_selector_one_refs(data): def test_add_marking_mark_multiple_selector_one_refs(data):
before = data[0] before = data[0]
after = data[1] after = data[1]
@ -91,12 +96,12 @@ def test_add_marking_mark_multiple_selector_multiple_refs():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description", "name"], "selectors": ["description", "name"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["description", "name"], "selectors": ["description", "name"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -111,7 +116,7 @@ def test_add_marking_mark_another_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
@ -120,7 +125,7 @@ def test_add_marking_mark_another_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description", "name"], "selectors": ["description", "name"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
@ -136,7 +141,7 @@ def test_add_marking_mark_same_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
@ -145,7 +150,7 @@ def test_add_marking_mark_same_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
@ -156,17 +161,22 @@ def test_add_marking_mark_same_property_same_marking():
assert m in after["granular_markings"] assert m in after["granular_markings"]
@pytest.mark.parametrize("data,marking", [ @pytest.mark.parametrize(
({"description": "test description"}, "data,marking", [
[["title"], ["marking-definition--1", "marking-definition--2"], (
"", ["marking-definition--1", "marking-definition--2"], {"description": "test description"},
[], ["marking-definition--1", "marking-definition--2"], [
[""], ["marking-definition--1", "marking-definition--2"], ["title"], ["marking-definition--1", "marking-definition--2"],
["description"], [""], "", ["marking-definition--1", "marking-definition--2"],
["description"], [], [], ["marking-definition--1", "marking-definition--2"],
["description"], ["marking-definition--1", 456] [""], ["marking-definition--1", "marking-definition--2"],
]) ["description"], [""],
]) ["description"], [],
["description"], ["marking-definition--1", 456],
],
),
],
)
def test_add_marking_bad_selector(data, marking): def test_add_marking_bad_selector(data, marking):
with pytest.raises(AssertionError): with pytest.raises(AssertionError):
markings.add_markings(data, marking[0], marking[1]) markings.add_markings(data, marking[0], marking[1])
@ -180,61 +190,61 @@ GET_MARKINGS_TEST_DATA = {
"list value", "list value",
{ {
"g": "nested", "g": "nested",
"h": 45 "h": 45,
} },
], ],
"x": { "x": {
"y": [ "y": [
"hello", "hello",
88 88,
], ],
"z": { "z": {
"foo1": "bar", "foo1": "bar",
"foo2": 65 "foo2": 65,
} },
}, },
"granular_markings": [ "granular_markings": [
{ {
"marking_ref": "1", "marking_ref": "1",
"selectors": ["a"] "selectors": ["a"],
}, },
{ {
"marking_ref": "2", "marking_ref": "2",
"selectors": ["c"] "selectors": ["c"],
}, },
{ {
"marking_ref": "3", "marking_ref": "3",
"selectors": ["c.[1]"] "selectors": ["c.[1]"],
}, },
{ {
"marking_ref": "4", "marking_ref": "4",
"selectors": ["c.[2]"] "selectors": ["c.[2]"],
}, },
{ {
"marking_ref": "5", "marking_ref": "5",
"selectors": ["c.[2].g"] "selectors": ["c.[2].g"],
}, },
{ {
"marking_ref": "6", "marking_ref": "6",
"selectors": ["x"] "selectors": ["x"],
}, },
{ {
"marking_ref": "7", "marking_ref": "7",
"selectors": ["x.y"] "selectors": ["x.y"],
}, },
{ {
"marking_ref": "8", "marking_ref": "8",
"selectors": ["x.y.[1]"] "selectors": ["x.y.[1]"],
}, },
{ {
"marking_ref": "9", "marking_ref": "9",
"selectors": ["x.z"] "selectors": ["x.z"],
}, },
{ {
"marking_ref": "10", "marking_ref": "10",
"selectors": ["x.z.foo2"] "selectors": ["x.z.foo2"],
}, },
] ],
} }
@ -245,10 +255,12 @@ def test_get_markings_smoke(data):
assert markings.get_markings(data, "a") == ["1"] assert markings.get_markings(data, "a") == ["1"]
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
GET_MARKINGS_TEST_DATA, "data", [
{"b": 1234}, GET_MARKINGS_TEST_DATA,
]) {"b": 1234},
],
)
def test_get_markings_not_marked(data): def test_get_markings_not_marked(data):
"""Test selector that is not marked returns empty list.""" """Test selector that is not marked returns empty list."""
results = markings.get_markings(data, "b") results = markings.get_markings(data, "b")
@ -267,21 +279,23 @@ def test_get_markings_multiple_selectors(data):
assert set(xy_markings).union(xz_markings).issuperset(total) assert set(xy_markings).union(xz_markings).issuperset(total)
@pytest.mark.parametrize("data,selector", [ @pytest.mark.parametrize(
(GET_MARKINGS_TEST_DATA, "foo"), "data,selector", [
(GET_MARKINGS_TEST_DATA, ""), (GET_MARKINGS_TEST_DATA, "foo"),
(GET_MARKINGS_TEST_DATA, []), (GET_MARKINGS_TEST_DATA, ""),
(GET_MARKINGS_TEST_DATA, [""]), (GET_MARKINGS_TEST_DATA, []),
(GET_MARKINGS_TEST_DATA, "x.z.[-2]"), (GET_MARKINGS_TEST_DATA, [""]),
(GET_MARKINGS_TEST_DATA, "c.f"), (GET_MARKINGS_TEST_DATA, "x.z.[-2]"),
(GET_MARKINGS_TEST_DATA, "c.[2].i"), (GET_MARKINGS_TEST_DATA, "c.f"),
(GET_MARKINGS_TEST_DATA, "c.[3]"), (GET_MARKINGS_TEST_DATA, "c.[2].i"),
(GET_MARKINGS_TEST_DATA, "d"), (GET_MARKINGS_TEST_DATA, "c.[3]"),
(GET_MARKINGS_TEST_DATA, "x.[0]"), (GET_MARKINGS_TEST_DATA, "d"),
(GET_MARKINGS_TEST_DATA, "z.y.w"), (GET_MARKINGS_TEST_DATA, "x.[0]"),
(GET_MARKINGS_TEST_DATA, "x.z.[1]"), (GET_MARKINGS_TEST_DATA, "z.y.w"),
(GET_MARKINGS_TEST_DATA, "x.z.foo3") (GET_MARKINGS_TEST_DATA, "x.z.[1]"),
]) (GET_MARKINGS_TEST_DATA, "x.z.foo3"),
],
)
def test_get_markings_bad_selector(data, selector): def test_get_markings_bad_selector(data, selector):
"""Test bad selectors raise exception""" """Test bad selectors raise exception"""
with pytest.raises(AssertionError): with pytest.raises(AssertionError):
@ -362,40 +376,42 @@ def test_get_markings_positional_arguments_combinations(data):
assert set(markings.get_markings(data, "x.z.foo2", False, True)) == set(["10"]) assert set(markings.get_markings(data, "x.z.foo2", False, True)) == set(["10"])
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
( "data", [
Malware( (
granular_markings=[ Malware(
{ granular_markings=[
"selectors": ["description"], {
"marking_ref": MARKING_IDS[0] "selectors": ["description"],
}, "marking_ref": MARKING_IDS[0],
{ },
"selectors": ["description"], {
"marking_ref": MARKING_IDS[1] "selectors": ["description"],
}, "marking_ref": MARKING_IDS[1],
], },
**MALWARE_KWARGS ],
**MALWARE_KWARGS
),
[MARKING_IDS[0], MARKING_IDS[1]],
), ),
[MARKING_IDS[0], MARKING_IDS[1]], (
), dict(
( granular_markings=[
dict( {
granular_markings=[ "selectors": ["description"],
{ "marking_ref": MARKING_IDS[0],
"selectors": ["description"], },
"marking_ref": MARKING_IDS[0] {
}, "selectors": ["description"],
{ "marking_ref": MARKING_IDS[1],
"selectors": ["description"], },
"marking_ref": MARKING_IDS[1] ],
}, **MALWARE_KWARGS
], ),
**MALWARE_KWARGS [MARKING_IDS[0], MARKING_IDS[1]],
), ),
[MARKING_IDS[0], MARKING_IDS[1]], ],
), )
])
def test_remove_marking_remove_one_selector_with_multiple_refs(data): def test_remove_marking_remove_one_selector_with_multiple_refs(data):
before = markings.remove_markings(data[0], data[1], ["description"]) before = markings.remove_markings(data[0], data[1], ["description"])
assert "granular_markings" not in before assert "granular_markings" not in before
@ -406,8 +422,8 @@ def test_remove_marking_remove_multiple_selector_one_ref():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -420,8 +436,8 @@ def test_remove_marking_mark_one_selector_from_multiple_ones():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -429,8 +445,8 @@ def test_remove_marking_mark_one_selector_from_multiple_ones():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -444,12 +460,12 @@ def test_remove_marking_mark_one_selector_markings_from_multiple_ones():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -457,12 +473,12 @@ def test_remove_marking_mark_one_selector_markings_from_multiple_ones():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -476,12 +492,12 @@ def test_remove_marking_mark_mutilple_selector_multiple_refs():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -494,8 +510,8 @@ def test_remove_marking_mark_another_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -503,12 +519,12 @@ def test_remove_marking_mark_another_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["modified"], "selectors": ["modified"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -522,8 +538,8 @@ def test_remove_marking_mark_same_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -552,8 +568,8 @@ def test_remove_marking_not_present():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -566,15 +582,15 @@ IS_MARKED_TEST_DATA = [
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
}, },
{ {
"selectors": ["malware_types", "description"], "selectors": ["malware_types", "description"],
"marking_ref": MARKING_IDS[2] "marking_ref": MARKING_IDS[2],
}, },
{ {
"selectors": ["malware_types", "description"], "selectors": ["malware_types", "description"],
"marking_ref": MARKING_IDS[3] "marking_ref": MARKING_IDS[3],
}, },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
@ -583,15 +599,15 @@ IS_MARKED_TEST_DATA = [
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
}, },
{ {
"selectors": ["malware_types", "description"], "selectors": ["malware_types", "description"],
"marking_ref": MARKING_IDS[2] "marking_ref": MARKING_IDS[2],
}, },
{ {
"selectors": ["malware_types", "description"], "selectors": ["malware_types", "description"],
"marking_ref": MARKING_IDS[3] "marking_ref": MARKING_IDS[3],
}, },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
@ -606,21 +622,23 @@ def test_is_marked_smoke(data):
assert markings.is_marked(data, selectors=["modified"]) is False assert markings.is_marked(data, selectors=["modified"]) is False
@pytest.mark.parametrize("data,selector", [ @pytest.mark.parametrize(
(IS_MARKED_TEST_DATA[0], "foo"), "data,selector", [
(IS_MARKED_TEST_DATA[0], ""), (IS_MARKED_TEST_DATA[0], "foo"),
(IS_MARKED_TEST_DATA[0], []), (IS_MARKED_TEST_DATA[0], ""),
(IS_MARKED_TEST_DATA[0], [""]), (IS_MARKED_TEST_DATA[0], []),
(IS_MARKED_TEST_DATA[0], "x.z.[-2]"), (IS_MARKED_TEST_DATA[0], [""]),
(IS_MARKED_TEST_DATA[0], "c.f"), (IS_MARKED_TEST_DATA[0], "x.z.[-2]"),
(IS_MARKED_TEST_DATA[0], "c.[2].i"), (IS_MARKED_TEST_DATA[0], "c.f"),
(IS_MARKED_TEST_DATA[1], "c.[3]"), (IS_MARKED_TEST_DATA[0], "c.[2].i"),
(IS_MARKED_TEST_DATA[1], "d"), (IS_MARKED_TEST_DATA[1], "c.[3]"),
(IS_MARKED_TEST_DATA[1], "x.[0]"), (IS_MARKED_TEST_DATA[1], "d"),
(IS_MARKED_TEST_DATA[1], "z.y.w"), (IS_MARKED_TEST_DATA[1], "x.[0]"),
(IS_MARKED_TEST_DATA[1], "x.z.[1]"), (IS_MARKED_TEST_DATA[1], "z.y.w"),
(IS_MARKED_TEST_DATA[1], "x.z.foo3") (IS_MARKED_TEST_DATA[1], "x.z.[1]"),
]) (IS_MARKED_TEST_DATA[1], "x.z.foo3"),
],
)
def test_is_marked_invalid_selector(data, selector): def test_is_marked_invalid_selector(data, selector):
"""Test invalid selector raises an error.""" """Test invalid selector raises an error."""
with pytest.raises(AssertionError): with pytest.raises(AssertionError):
@ -688,61 +706,61 @@ def test_is_marked_positional_arguments_combinations():
"list value", "list value",
{ {
"g": "nested", "g": "nested",
"h": 45 "h": 45,
} },
], ],
"x": { "x": {
"y": [ "y": [
"hello", "hello",
88 88,
], ],
"z": { "z": {
"foo1": "bar", "foo1": "bar",
"foo2": 65 "foo2": 65,
} },
}, },
"granular_markings": [ "granular_markings": [
{ {
"marking_ref": "1", "marking_ref": "1",
"selectors": ["a"] "selectors": ["a"],
}, },
{ {
"marking_ref": "2", "marking_ref": "2",
"selectors": ["c"] "selectors": ["c"],
}, },
{ {
"marking_ref": "3", "marking_ref": "3",
"selectors": ["c.[1]"] "selectors": ["c.[1]"],
}, },
{ {
"marking_ref": "4", "marking_ref": "4",
"selectors": ["c.[2]"] "selectors": ["c.[2]"],
}, },
{ {
"marking_ref": "5", "marking_ref": "5",
"selectors": ["c.[2].g"] "selectors": ["c.[2].g"],
}, },
{ {
"marking_ref": "6", "marking_ref": "6",
"selectors": ["x"] "selectors": ["x"],
}, },
{ {
"marking_ref": "7", "marking_ref": "7",
"selectors": ["x.y"] "selectors": ["x.y"],
}, },
{ {
"marking_ref": "8", "marking_ref": "8",
"selectors": ["x.y.[1]"] "selectors": ["x.y.[1]"],
}, },
{ {
"marking_ref": "9", "marking_ref": "9",
"selectors": ["x.z"] "selectors": ["x.z"],
}, },
{ {
"marking_ref": "10", "marking_ref": "10",
"selectors": ["x.z.foo2"] "selectors": ["x.z.foo2"],
}, },
] ],
} }
assert markings.is_marked(test_sdo, ["1"], "a", False, False) assert markings.is_marked(test_sdo, ["1"], "a", False, False)
@ -822,8 +840,8 @@ def test_create_sdo_with_invalid_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["foo"], "selectors": ["foo"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -838,12 +856,12 @@ def test_set_marking_mark_one_selector_multiple_refs():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -857,8 +875,8 @@ def test_set_marking_mark_multiple_selector_one_refs():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -866,8 +884,8 @@ def test_set_marking_mark_multiple_selector_one_refs():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -884,12 +902,12 @@ def test_set_marking_mark_multiple_selector_multiple_refs_from_none():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["description", "modified"], "selectors": ["description", "modified"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -903,8 +921,8 @@ def test_set_marking_mark_another_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -912,12 +930,12 @@ def test_set_marking_mark_another_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
}, },
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[2] "marking_ref": MARKING_IDS[2],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -927,19 +945,21 @@ def test_set_marking_mark_another_property_same_marking():
assert m in after["granular_markings"] assert m in after["granular_markings"]
@pytest.mark.parametrize("marking", [ @pytest.mark.parametrize(
([MARKING_IDS[4], MARKING_IDS[5]], ["foo"]), "marking", [
([MARKING_IDS[4], MARKING_IDS[5]], ""), ([MARKING_IDS[4], MARKING_IDS[5]], ["foo"]),
([MARKING_IDS[4], MARKING_IDS[5]], []), ([MARKING_IDS[4], MARKING_IDS[5]], ""),
([MARKING_IDS[4], MARKING_IDS[5]], [""]), ([MARKING_IDS[4], MARKING_IDS[5]], []),
]) ([MARKING_IDS[4], MARKING_IDS[5]], [""]),
],
)
def test_set_marking_bad_selector(marking): def test_set_marking_bad_selector(marking):
before = Malware( before = Malware(
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -947,8 +967,8 @@ def test_set_marking_bad_selector(marking):
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -964,8 +984,8 @@ def test_set_marking_mark_same_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -973,8 +993,8 @@ def test_set_marking_mark_same_property_same_marking():
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -988,15 +1008,15 @@ CLEAR_MARKINGS_TEST_DATA = [
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["modified", "description"], "selectors": ["modified", "description"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
}, },
{ {
"selectors": ["modified", "description", "type"], "selectors": ["modified", "description", "type"],
"marking_ref": MARKING_IDS[2] "marking_ref": MARKING_IDS[2],
}, },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
@ -1005,19 +1025,19 @@ CLEAR_MARKINGS_TEST_DATA = [
granular_markings=[ granular_markings=[
{ {
"selectors": ["description"], "selectors": ["description"],
"marking_ref": MARKING_IDS[0] "marking_ref": MARKING_IDS[0],
}, },
{ {
"selectors": ["modified", "description"], "selectors": ["modified", "description"],
"marking_ref": MARKING_IDS[1] "marking_ref": MARKING_IDS[1],
}, },
{ {
"selectors": ["modified", "description", "type"], "selectors": ["modified", "description", "type"],
"marking_ref": MARKING_IDS[2] "marking_ref": MARKING_IDS[2],
}, },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) ),
] ]
@ -1049,12 +1069,14 @@ def test_clear_marking_all_selectors(data):
assert "granular_markings" not in data assert "granular_markings" not in data
@pytest.mark.parametrize("data,selector", [ @pytest.mark.parametrize(
(CLEAR_MARKINGS_TEST_DATA[0], "foo"), "data,selector", [
(CLEAR_MARKINGS_TEST_DATA[0], ""), (CLEAR_MARKINGS_TEST_DATA[0], "foo"),
(CLEAR_MARKINGS_TEST_DATA[1], []), (CLEAR_MARKINGS_TEST_DATA[0], ""),
(CLEAR_MARKINGS_TEST_DATA[1], [""]), (CLEAR_MARKINGS_TEST_DATA[1], []),
]) (CLEAR_MARKINGS_TEST_DATA[1], [""]),
],
)
def test_clear_marking_bad_selector(data, selector): def test_clear_marking_bad_selector(data, selector):
"""Test bad selector raises exception.""" """Test bad selector raises exception."""
with pytest.raises(AssertionError): with pytest.raises(AssertionError):

View File

@ -30,18 +30,20 @@ def test_identity_example():
assert str(identity) == EXPECTED assert str(identity) == EXPECTED
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"created": "2015-12-21T19:59:11.000Z", {
"id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "created": "2015-12-21T19:59:11.000Z",
"identity_class": "individual", "id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c",
"modified": "2015-12-21T19:59:11.000Z", "identity_class": "individual",
"name": "John Smith", "modified": "2015-12-21T19:59:11.000Z",
"spec_version": "2.1", "name": "John Smith",
"type": "identity" "spec_version": "2.1",
}, "type": "identity",
]) },
],
)
def test_parse_identity(data): def test_parse_identity(data):
identity = stix2.parse(data, version="2.1") identity = stix2.parse(data, version="2.1")
@ -55,21 +57,23 @@ def test_parse_identity(data):
def test_parse_no_type(): def test_parse_no_type():
with pytest.raises(stix2.exceptions.ParseError): with pytest.raises(stix2.exceptions.ParseError):
stix2.parse(""" stix2.parse(
"""
{ {
"id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c", "id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c",
"created": "2015-12-21T19:59:11.000Z", "created": "2015-12-21T19:59:11.000Z",
"modified": "2015-12-21T19:59:11.000Z", "modified": "2015-12-21T19:59:11.000Z",
"name": "John Smith", "name": "John Smith",
"identity_class": "individual" "identity_class": "individual"
}""", version="2.1") }""", version="2.1",
)
def test_identity_with_custom(): def test_identity_with_custom():
identity = stix2.v21.Identity( identity = stix2.v21.Identity(
name="John Smith", name="John Smith",
identity_class="individual", identity_class="individual",
custom_properties={'x_foo': 'bar'} custom_properties={'x_foo': 'bar'},
) )
assert identity.x_foo == "bar" assert identity.x_foo == "bar"

View File

@ -152,20 +152,22 @@ def test_created_modified_time_are_identical_by_default():
assert ind.created == ind.modified assert ind.created == ind.modified
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED_INDICATOR, "data", [
{ EXPECTED_INDICATOR,
"type": "indicator", {
"id": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", "type": "indicator",
"created": "2017-01-01T00:00:01Z", "id": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
"modified": "2017-01-01T00:00:01Z", "created": "2017-01-01T00:00:01Z",
"indicator_types": [ "modified": "2017-01-01T00:00:01Z",
"malicious-activity" "indicator_types": [
], "malicious-activity",
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']", ],
"valid_from": "1970-01-01T00:00:01Z" "pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
}, "valid_from": "1970-01-01T00:00:01Z",
]) },
],
)
def test_parse_indicator(data): def test_parse_indicator(data):
idctr = stix2.parse(data, version="2.1") idctr = stix2.parse(data, version="2.1")

View File

@ -36,33 +36,35 @@ def test_intrusion_set_example():
name="Bobcat Breakin", name="Bobcat Breakin",
description="Incidents usually feature a shared TTP of a bobcat being released...", description="Incidents usually feature a shared TTP of a bobcat being released...",
aliases=["Zookeeper"], aliases=["Zookeeper"],
goals=["acquisition-theft", "harassment", "damage"] goals=["acquisition-theft", "harassment", "damage"],
) )
assert str(intrusion_set) == EXPECTED assert str(intrusion_set) == EXPECTED
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"aliases": [ {
"Zookeeper" "aliases": [
], "Zookeeper",
"created": "2016-04-06T20:03:48.000Z", ],
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", "created": "2016-04-06T20:03:48.000Z",
"description": "Incidents usually feature a shared TTP of a bobcat being released...", "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
"goals": [ "description": "Incidents usually feature a shared TTP of a bobcat being released...",
"acquisition-theft", "goals": [
"harassment", "acquisition-theft",
"damage" "harassment",
], "damage",
"id": "intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29", ],
"modified": "2016-04-06T20:03:48.000Z", "id": "intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29",
"name": "Bobcat Breakin", "modified": "2016-04-06T20:03:48.000Z",
"spec_version": "2.1", "name": "Bobcat Breakin",
"type": "intrusion-set" "spec_version": "2.1",
}, "type": "intrusion-set",
]) },
],
)
def test_parse_intrusion_set(data): def test_parse_intrusion_set(data):
intset = stix2.parse(data) intset = stix2.parse(data)

View File

@ -55,13 +55,13 @@ def test_language_content_campaign():
contents={ contents={
'de': { 'de': {
'name': 'Bank Angriff 1', 'name': 'Bank Angriff 1',
'description': 'Weitere Informationen über Banküberfall' 'description': 'Weitere Informationen über Banküberfall',
}, },
'fr': { 'fr': {
'name': 'Attaque Bank 1', 'name': 'Attaque Bank 1',
'description': 'Plus d\'informations sur la crise bancaire' 'description': 'Plus d\'informations sur la crise bancaire',
} },
} },
) )
camp = stix2.parse(TEST_CAMPAIGN, version='2.1') camp = stix2.parse(TEST_CAMPAIGN, version='2.1')

View File

@ -55,7 +55,7 @@ def test_location_with_some_required_properties():
created=now, created=now,
modified=now, modified=now,
latitude=48.8566, latitude=48.8566,
longitude=2.3522 longitude=2.3522,
) )
assert str(loc) == EXPECTED_LOCATION_1 assert str(loc) == EXPECTED_LOCATION_1
@ -63,17 +63,19 @@ def test_location_with_some_required_properties():
assert rep == EXPECTED_LOCATION_1_REPR assert rep == EXPECTED_LOCATION_1_REPR
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED_LOCATION_2, "data", [
{ EXPECTED_LOCATION_2,
"type": "location", {
"spec_version": "2.1", "type": "location",
"id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64", "spec_version": "2.1",
"created": "2016-04-06T20:03:00.000Z", "id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64",
"modified": "2016-04-06T20:03:00.000Z", "created": "2016-04-06T20:03:00.000Z",
"region": "north-america" "modified": "2016-04-06T20:03:00.000Z",
} "region": "north-america",
]) },
],
)
def test_parse_location(data): def test_parse_location(data):
location = stix2.parse(data, version="2.1") location = stix2.parse(data, version="2.1")

View File

@ -32,7 +32,7 @@ def test_malware_with_all_required_properties():
modified=now, modified=now,
malware_types=["ransomware"], malware_types=["ransomware"],
name="Cryptolocker", name="Cryptolocker",
is_family=True is_family=True,
) )
assert str(mal) == EXPECTED_MALWARE assert str(mal) == EXPECTED_MALWARE
@ -106,19 +106,21 @@ def test_invalid_kwarg_to_malware():
assert str(excinfo.value) == "Unexpected properties for Malware: (my_custom_property)." assert str(excinfo.value) == "Unexpected properties for Malware: (my_custom_property)."
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED_MALWARE, "data", [
{ EXPECTED_MALWARE,
"type": "malware", {
"spec_version": "2.1", "type": "malware",
"id": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e", "spec_version": "2.1",
"created": "2016-05-12T08:17:27.000Z", "id": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
"modified": "2016-05-12T08:17:27.000Z", "created": "2016-05-12T08:17:27.000Z",
"malware_types": ["ransomware"], "modified": "2016-05-12T08:17:27.000Z",
"name": "Cryptolocker", "malware_types": ["ransomware"],
"is_family": True "name": "Cryptolocker",
}, "is_family": True,
]) },
],
)
def test_parse_malware(data): def test_parse_malware(data):
mal = stix2.parse(data) mal = stix2.parse(data)

View File

@ -83,7 +83,7 @@ def test_marking_def_example_with_statement_positional_argument():
id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
created="2017-01-20T00:00:00.000Z", created="2017-01-20T00:00:00.000Z",
definition_type="statement", definition_type="statement",
definition=stix2.StatementMarking(statement="Copyright 2016, Example Corp") definition=stix2.StatementMarking(statement="Copyright 2016, Example Corp"),
) )
assert str(marking_definition) == EXPECTED_STATEMENT_MARKING_DEFINITION assert str(marking_definition) == EXPECTED_STATEMENT_MARKING_DEFINITION
@ -95,7 +95,7 @@ def test_marking_def_example_with_kwargs_statement():
id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
created="2017-01-20T00:00:00.000Z", created="2017-01-20T00:00:00.000Z",
definition_type="statement", definition_type="statement",
definition=stix2.StatementMarking(**kwargs) definition=stix2.StatementMarking(**kwargs),
) )
assert str(marking_definition) == EXPECTED_STATEMENT_MARKING_DEFINITION assert str(marking_definition) == EXPECTED_STATEMENT_MARKING_DEFINITION
@ -107,7 +107,7 @@ def test_marking_def_invalid_type():
id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
created="2017-01-20T00:00:00.000Z", created="2017-01-20T00:00:00.000Z",
definition_type="my-definition-type", definition_type="my-definition-type",
definition=stix2.StatementMarking("Copyright 2016, Example Corp") definition=stix2.StatementMarking("Copyright 2016, Example Corp"),
) )
@ -119,7 +119,7 @@ def test_campaign_with_markings_example():
modified="2016-04-06T20:03:00Z", modified="2016-04-06T20:03:00Z",
name="Green Group Attacks Against Finance", name="Green Group Attacks Against Finance",
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.",
object_marking_refs=TLP_WHITE object_marking_refs=TLP_WHITE,
) )
assert str(campaign) == EXPECTED_CAMPAIGN_WITH_OBJECT_MARKING assert str(campaign) == EXPECTED_CAMPAIGN_WITH_OBJECT_MARKING
@ -127,7 +127,7 @@ def test_campaign_with_markings_example():
def test_granular_example(): def test_granular_example():
granular_marking = stix2.v21.GranularMarking( granular_marking = stix2.v21.GranularMarking(
marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
selectors=["abc", "abc.[23]", "abc.def", "abc.[2].efg"] selectors=["abc", "abc.[23]", "abc.def", "abc.[2].efg"],
) )
assert str(granular_marking) == EXPECTED_GRANULAR_MARKING assert str(granular_marking) == EXPECTED_GRANULAR_MARKING
@ -137,7 +137,7 @@ def test_granular_example_with_bad_selector():
with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo: with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo:
stix2.v21.GranularMarking( stix2.v21.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 excinfo.value.cls == stix2.v21.GranularMarking assert excinfo.value.cls == stix2.v21.GranularMarking
@ -157,24 +157,28 @@ def test_campaign_with_granular_markings_example():
granular_markings=[ granular_markings=[
stix2.v21.GranularMarking( stix2.v21.GranularMarking(
marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
selectors=["description"]) selectors=["description"],
]) ),
],
)
assert str(campaign) == EXPECTED_CAMPAIGN_WITH_GRANULAR_MARKINGS assert str(campaign) == EXPECTED_CAMPAIGN_WITH_GRANULAR_MARKINGS
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED_TLP_MARKING_DEFINITION, "data", [
{ EXPECTED_TLP_MARKING_DEFINITION,
"id": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9", {
"spec_version": "2.1", "id": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
"type": "marking-definition", "spec_version": "2.1",
"created": "2017-01-20T00:00:00Z", "type": "marking-definition",
"definition": { "created": "2017-01-20T00:00:00Z",
"tlp": "white" "definition": {
"tlp": "white",
},
"definition_type": "tlp",
}, },
"definition_type": "tlp", ],
}, )
])
def test_parse_marking_definition(data): def test_parse_marking_definition(data):
gm = stix2.parse(data, version="2.1") gm = stix2.parse(data, version="2.1")
@ -186,10 +190,12 @@ def test_parse_marking_definition(data):
assert gm.definition_type == "tlp" assert gm.definition_type == "tlp"
@stix2.v21.CustomMarking('x-new-marking-type', [ @stix2.v21.CustomMarking(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-marking-type', [
('property2', stix2.properties.IntegerProperty()), ('property1', stix2.properties.StringProperty(required=True)),
]) ('property2', stix2.properties.IntegerProperty()),
],
)
class NewMarking(object): class NewMarking(object):
def __init__(self, property2=None, **kwargs): def __init__(self, property2=None, **kwargs):
if "property3" in kwargs and not isinstance(kwargs.get("property3"), int): if "property3" in kwargs and not isinstance(kwargs.get("property3"), int):
@ -203,7 +209,7 @@ def test_registered_custom_marking():
id="marking-definition--00000000-0000-4000-8000-000000000012", id="marking-definition--00000000-0000-4000-8000-000000000012",
created="2017-01-22T00:00:00.000Z", created="2017-01-22T00:00:00.000Z",
definition_type="x-new-marking-type", definition_type="x-new-marking-type",
definition=nm definition=nm,
) )
assert marking_def.type == "marking-definition" assert marking_def.type == "marking-definition"
@ -224,10 +230,12 @@ def test_registered_custom_marking_raises_exception():
def test_not_registered_marking_raises_exception(): def test_not_registered_marking_raises_exception():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
# Used custom object on purpose to demonstrate a not-registered marking # Used custom object on purpose to demonstrate a not-registered marking
@stix2.v21.CustomObject('x-new-marking-type2', [ @stix2.v21.CustomObject(
('property1', stix2.properties.StringProperty(required=True)), 'x-new-marking-type2', [
('property2', stix2.properties.IntegerProperty()), ('property1', stix2.properties.StringProperty(required=True)),
]) ('property2', stix2.properties.IntegerProperty()),
],
)
class NewObject2(object): class NewObject2(object):
def __init__(self, property2=None, **kwargs): def __init__(self, property2=None, **kwargs):
return return
@ -238,7 +246,7 @@ def test_not_registered_marking_raises_exception():
id="marking-definition--00000000-0000-4000-8000-000000000012", id="marking-definition--00000000-0000-4000-8000-000000000012",
created="2017-01-22T00:00:00.000Z", created="2017-01-22T00:00:00.000Z",
definition_type="x-new-marking-type2", definition_type="x-new-marking-type2",
definition=no definition=no,
) )
assert str(excinfo.value) == "definition_type must be a valid marking type" assert str(excinfo.value) == "definition_type must be a valid marking type"

View File

@ -8,10 +8,12 @@ import stix2
from .constants import CAMPAIGN_ID, NOTE_ID from .constants import CAMPAIGN_ID, NOTE_ID
DESCRIPTION = ('This note indicates the various steps taken by the threat' DESCRIPTION = (
' analyst team to investigate this specific campaign. Step' 'This note indicates the various steps taken by the threat'
' 1) Do a scan 2) Review scanned results for identified ' ' analyst team to investigate this specific campaign. Step'
'hosts not known by external intel... etc') ' 1) Do a scan 2) Review scanned results for identified '
'hosts not known by external intel... etc'
)
EXPECTED_NOTE = """{ EXPECTED_NOTE = """{
"type": "note", "type": "note",
@ -35,7 +37,8 @@ EXPECTED_NOTE = """{
] ]
}""" % DESCRIPTION }""" % DESCRIPTION
EXPECTED_OPINION_REPR = "Note(" + " ".join((""" EXPECTED_OPINION_REPR = "Note(" + " ".join((
"""
type='note', type='note',
spec_version='2.1', spec_version='2.1',
id='note--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061', id='note--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061',
@ -46,7 +49,8 @@ EXPECTED_OPINION_REPR = "Note(" + " ".join(("""
authors=['John Doe'], authors=['John Doe'],
object_refs=['campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f'], object_refs=['campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f'],
external_references=[ExternalReference(source_name='job-tracker', external_id='job-id-1234')] external_references=[ExternalReference(source_name='job-tracker', external_id='job-id-1234')]
""" % DESCRIPTION).split()) + ")" """ % DESCRIPTION
).split()) + ")"
def test_note_with_required_properties(): def test_note_with_required_properties():
@ -64,9 +68,9 @@ def test_note_with_required_properties():
external_references=[ external_references=[
{ {
'source_name': 'job-tracker', 'source_name': 'job-tracker',
'external_id': 'job-id-1234' 'external_id': 'job-id-1234',
} },
] ],
) )
assert str(note) == EXPECTED_NOTE assert str(note) == EXPECTED_NOTE
@ -74,30 +78,32 @@ def test_note_with_required_properties():
assert rep == EXPECTED_OPINION_REPR assert rep == EXPECTED_OPINION_REPR
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED_NOTE, "data", [
{ EXPECTED_NOTE,
"type": "note", {
"spec_version": "2.1", "type": "note",
"id": "note--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061", "spec_version": "2.1",
"created": "2016-05-12T08:17:27.000Z", "id": "note--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
"modified": "2016-05-12T08:17:27.000Z", "created": "2016-05-12T08:17:27.000Z",
"summary": "Tracking Team Note#1", "modified": "2016-05-12T08:17:27.000Z",
"description": DESCRIPTION, "summary": "Tracking Team Note#1",
"authors": [ "description": DESCRIPTION,
"John Doe" "authors": [
], "John Doe",
"object_refs": [ ],
"campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f" "object_refs": [
], "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
"external_references": [ ],
{ "external_references": [
"source_name": "job-tracker", {
"external_id": "job-id-1234" "source_name": "job-tracker",
} "external_id": "job-id-1234",
] },
} ],
]) },
],
)
def test_parse_note(data): def test_parse_note(data):
note = stix2.parse(data, version="2.1") note = stix2.parse(data, version="2.1")

View File

@ -17,26 +17,34 @@ MALWARE_KWARGS.update({
}) })
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
( "data", [
Malware(**MALWARE_KWARGS), (
Malware(object_marking_refs=[MARKING_IDS[0]], Malware(**MALWARE_KWARGS),
**MALWARE_KWARGS), Malware(
MARKING_IDS[0], object_marking_refs=[MARKING_IDS[0]],
), **MALWARE_KWARGS
( ),
MALWARE_KWARGS, MARKING_IDS[0],
dict(object_marking_refs=[MARKING_IDS[0]], ),
**MALWARE_KWARGS), (
MARKING_IDS[0], MALWARE_KWARGS,
), dict(
( object_marking_refs=[MARKING_IDS[0]],
Malware(**MALWARE_KWARGS), **MALWARE_KWARGS
Malware(object_marking_refs=[TLP_AMBER.id], ),
**MALWARE_KWARGS), MARKING_IDS[0],
TLP_AMBER, ),
), (
]) Malware(**MALWARE_KWARGS),
Malware(
object_marking_refs=[TLP_AMBER.id],
**MALWARE_KWARGS
),
TLP_AMBER,
),
],
)
def test_add_markings_one_marking(data): def test_add_markings_one_marking(data):
before = data[0] before = data[0]
after = data[1] after = data[1]
@ -72,12 +80,12 @@ def test_add_markings_combination():
granular_markings=[ granular_markings=[
{ {
"selectors": ["malware_types"], "selectors": ["malware_types"],
"marking_ref": MARKING_IDS[2] "marking_ref": MARKING_IDS[2],
}, },
{ {
"selectors": ["name"], "selectors": ["name"],
"marking_ref": MARKING_IDS[3] "marking_ref": MARKING_IDS[3],
} },
], ],
**MALWARE_KWARGS **MALWARE_KWARGS
) )
@ -94,12 +102,14 @@ def test_add_markings_combination():
assert m in after["object_marking_refs"] assert m in after["object_marking_refs"]
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
([""]), "data", [
(""), ([""]),
([]), (""),
([MARKING_IDS[0], 456]) ([]),
]) ([MARKING_IDS[0], 456]),
],
)
def test_add_markings_bad_markings(data): def test_add_markings_bad_markings(data):
before = Malware( before = Malware(
**MALWARE_KWARGS **MALWARE_KWARGS
@ -119,62 +129,62 @@ GET_MARKINGS_TEST_DATA = \
"list value", "list value",
{ {
"g": "nested", "g": "nested",
"h": 45 "h": 45,
} },
], ],
"x": { "x": {
"y": [ "y": [
"hello", "hello",
88 88,
], ],
"z": { "z": {
"foo1": "bar", "foo1": "bar",
"foo2": 65 "foo2": 65,
} },
}, },
"object_marking_refs": ["11"], "object_marking_refs": ["11"],
"granular_markings": [ "granular_markings": [
{ {
"marking_ref": "1", "marking_ref": "1",
"selectors": ["a"] "selectors": ["a"],
}, },
{ {
"marking_ref": "2", "marking_ref": "2",
"selectors": ["c"] "selectors": ["c"],
}, },
{ {
"marking_ref": "3", "marking_ref": "3",
"selectors": ["c.[1]"] "selectors": ["c.[1]"],
}, },
{ {
"marking_ref": "4", "marking_ref": "4",
"selectors": ["c.[2]"] "selectors": ["c.[2]"],
}, },
{ {
"marking_ref": "5", "marking_ref": "5",
"selectors": ["c.[2].g"] "selectors": ["c.[2].g"],
}, },
{ {
"marking_ref": "6", "marking_ref": "6",
"selectors": ["x"] "selectors": ["x"],
}, },
{ {
"marking_ref": "7", "marking_ref": "7",
"selectors": ["x.y"] "selectors": ["x.y"],
}, },
{ {
"marking_ref": "8", "marking_ref": "8",
"selectors": ["x.y.[1]"] "selectors": ["x.y.[1]"],
}, },
{ {
"marking_ref": "9", "marking_ref": "9",
"selectors": ["x.z"] "selectors": ["x.z"],
}, },
{ {
"marking_ref": "10", "marking_ref": "10",
"selectors": ["x.z.foo2"] "selectors": ["x.z.foo2"],
}, },
] ],
} }
@ -257,18 +267,24 @@ def test_get_markings_object_and_granular_combinations(data):
assert set(markings.get_markings(data, "x.z.foo2", False, True)) == set(["10"]) assert set(markings.get_markings(data, "x.z.foo2", False, True)) == set(["10"])
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
( "data", [
Malware(object_marking_refs=[MARKING_IDS[0]], (
**MALWARE_KWARGS), Malware(
Malware(**MALWARE_KWARGS), object_marking_refs=[MARKING_IDS[0]],
), **MALWARE_KWARGS
( ),
dict(object_marking_refs=[MARKING_IDS[0]], Malware(**MALWARE_KWARGS),
**MALWARE_KWARGS), ),
MALWARE_KWARGS, (
), dict(
]) object_marking_refs=[MARKING_IDS[0]],
**MALWARE_KWARGS
),
MALWARE_KWARGS,
),
],
)
def test_remove_markings_object_level(data): def test_remove_markings_object_level(data):
before = data[0] before = data[0]
after = data[1] after = data[1]
@ -283,29 +299,43 @@ def test_remove_markings_object_level(data):
modified == after['modified'] modified == after['modified']
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
( "data", [
Malware(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]], (
**MALWARE_KWARGS), Malware(
Malware(object_marking_refs=[MARKING_IDS[1]], object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
**MALWARE_KWARGS), **MALWARE_KWARGS
[MARKING_IDS[0], MARKING_IDS[2]], ),
), Malware(
( object_marking_refs=[MARKING_IDS[1]],
dict(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]], **MALWARE_KWARGS
**MALWARE_KWARGS), ),
dict(object_marking_refs=[MARKING_IDS[1]], [MARKING_IDS[0], MARKING_IDS[2]],
**MALWARE_KWARGS), ),
[MARKING_IDS[0], MARKING_IDS[2]], (
), dict(
( object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
Malware(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], TLP_AMBER.id], **MALWARE_KWARGS
**MALWARE_KWARGS), ),
Malware(object_marking_refs=[MARKING_IDS[1]], dict(
**MALWARE_KWARGS), object_marking_refs=[MARKING_IDS[1]],
[MARKING_IDS[0], TLP_AMBER], **MALWARE_KWARGS
), ),
]) [MARKING_IDS[0], MARKING_IDS[2]],
),
(
Malware(
object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], TLP_AMBER.id],
**MALWARE_KWARGS
),
Malware(
object_marking_refs=[MARKING_IDS[1]],
**MALWARE_KWARGS
),
[MARKING_IDS[0], TLP_AMBER],
),
],
)
def test_remove_markings_multiple(data): def test_remove_markings_multiple(data):
before = data[0] before = data[0]
after = data[1] after = data[1]
@ -325,18 +355,24 @@ def test_remove_markings_bad_markings():
assert str(excinfo.value) == "Marking ['%s'] was not found in Malware!" % MARKING_IDS[4] assert str(excinfo.value) == "Marking ['%s'] was not found in Malware!" % MARKING_IDS[4]
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
( "data", [
Malware(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]], (
**MALWARE_KWARGS), Malware(
Malware(**MALWARE_KWARGS), object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
), **MALWARE_KWARGS
( ),
dict(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]], Malware(**MALWARE_KWARGS),
**MALWARE_KWARGS), ),
MALWARE_KWARGS, (
), dict(
]) object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
**MALWARE_KWARGS
),
MALWARE_KWARGS,
),
],
)
def test_clear_markings(data): def test_clear_markings(data):
before = data[0] before = data[0]
after = data[1] after = data[1]
@ -358,62 +394,62 @@ def test_is_marked_object_and_granular_combinations():
"list value", "list value",
{ {
"g": "nested", "g": "nested",
"h": 45 "h": 45,
} },
], ],
"x": { "x": {
"y": [ "y": [
"hello", "hello",
88 88,
], ],
"z": { "z": {
"foo1": "bar", "foo1": "bar",
"foo2": 65 "foo2": 65,
} },
}, },
"object_marking_refs": "11", "object_marking_refs": "11",
"granular_markings": [ "granular_markings": [
{ {
"marking_ref": "1", "marking_ref": "1",
"selectors": ["a"] "selectors": ["a"],
}, },
{ {
"marking_ref": "2", "marking_ref": "2",
"selectors": ["c"] "selectors": ["c"],
}, },
{ {
"marking_ref": "3", "marking_ref": "3",
"selectors": ["c.[1]"] "selectors": ["c.[1]"],
}, },
{ {
"marking_ref": "4", "marking_ref": "4",
"selectors": ["c.[2]"] "selectors": ["c.[2]"],
}, },
{ {
"marking_ref": "5", "marking_ref": "5",
"selectors": ["c.[2].g"] "selectors": ["c.[2].g"],
}, },
{ {
"marking_ref": "6", "marking_ref": "6",
"selectors": ["x"] "selectors": ["x"],
}, },
{ {
"marking_ref": "7", "marking_ref": "7",
"selectors": ["x.y"] "selectors": ["x.y"],
}, },
{ {
"marking_ref": "8", "marking_ref": "8",
"selectors": ["x.y.[1]"] "selectors": ["x.y.[1]"],
}, },
{ {
"marking_ref": "9", "marking_ref": "9",
"selectors": ["x.z"] "selectors": ["x.z"],
}, },
{ {
"marking_ref": "10", "marking_ref": "10",
"selectors": ["x.z.foo2"] "selectors": ["x.z.foo2"],
}, },
] ],
} }
assert markings.is_marked(test_sdo, ["1"], "a", False, False) assert markings.is_marked(test_sdo, ["1"], "a", False, False)
@ -490,18 +526,24 @@ def test_is_marked_object_and_granular_combinations():
assert markings.is_marked(test_sdo, ["2"], None, True, True) is False assert markings.is_marked(test_sdo, ["2"], None, True, True) is False
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
( "data", [
Malware(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]], (
**MALWARE_KWARGS), Malware(
Malware(**MALWARE_KWARGS), object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
), **MALWARE_KWARGS
( ),
dict(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]], Malware(**MALWARE_KWARGS),
**MALWARE_KWARGS), ),
MALWARE_KWARGS, (
), dict(
]) object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
**MALWARE_KWARGS
),
MALWARE_KWARGS,
),
],
)
def test_is_marked_no_markings(data): def test_is_marked_no_markings(data):
marked = data[0] marked = data[0]
nonmarked = data[1] nonmarked = data[1]
@ -531,12 +573,14 @@ def test_set_marking():
assert x in after["object_marking_refs"] assert x in after["object_marking_refs"]
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
([]), "data", [
([""]), ([]),
(""), ([""]),
([MARKING_IDS[4], 687]) (""),
]) ([MARKING_IDS[4], 687]),
],
)
def test_set_marking_bad_input(data): def test_set_marking_bad_input(data):
before = Malware( before = Malware(
object_marking_refs=[MARKING_IDS[0]], object_marking_refs=[MARKING_IDS[0]],

View File

@ -42,7 +42,7 @@ def test_observed_data_example():
objects={ objects={
"0": { "0": {
"name": "foo.exe", "name": "foo.exe",
"type": "file" "type": "file",
}, },
}, },
) )
@ -88,13 +88,13 @@ def test_observed_data_example_with_refs():
objects={ objects={
"0": { "0": {
"name": "foo.exe", "name": "foo.exe",
"type": "file" "type": "file",
}, },
"1": { "1": {
"type": "directory", "type": "directory",
"path": "/usr/home", "path": "/usr/home",
"contains_refs": ["0"] "contains_refs": ["0"],
} },
}, },
) )
@ -114,13 +114,13 @@ def test_observed_data_example_with_bad_refs():
objects={ objects={
"0": { "0": {
"type": "file", "type": "file",
"name": "foo.exe" "name": "foo.exe",
}, },
"1": { "1": {
"type": "directory", "type": "directory",
"path": "/usr/home", "path": "/usr/home",
"contains_refs": ["2"] "contains_refs": ["2"],
} },
}, },
) )
@ -165,26 +165,28 @@ def test_observed_data_example_with_empty_dictionary():
assert 'must contain a non-empty dictionary' in excinfo.value.reason assert 'must contain a non-empty dictionary' in excinfo.value.reason
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"type": "observed-data", {
"spec_version": "2.1", "type": "observed-data",
"id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", "spec_version": "2.1",
"created": "2016-04-06T19:58:16.000Z", "id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", "created": "2016-04-06T19:58:16.000Z",
"first_observed": "2015-12-21T19:00:00Z", "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
"last_observed": "2015-12-21T19:00:00Z", "first_observed": "2015-12-21T19:00:00Z",
"modified": "2016-04-06T19:58:16.000Z", "last_observed": "2015-12-21T19:00:00Z",
"number_observed": 50, "modified": "2016-04-06T19:58:16.000Z",
"objects": { "number_observed": 50,
"0": { "objects": {
"name": "foo.exe", "0": {
"type": "file" "name": "foo.exe",
} "type": "file",
} },
}, },
]) },
],
)
def test_parse_observed_data(data): def test_parse_observed_data(data):
odata = stix2.parse(data, version="2.1") odata = stix2.parse(data, version="2.1")
@ -199,13 +201,14 @@ def test_parse_observed_data(data):
assert odata.objects["0"].type == "file" assert odata.objects["0"].type == "file"
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
""""0": { "data", [
""""0": {
"type": "artifact", "type": "artifact",
"mime_type": "image/jpeg", "mime_type": "image/jpeg",
"payload_bin": "VBORw0KGgoAAAANSUhEUgAAADI==" "payload_bin": "VBORw0KGgoAAAANSUhEUgAAADI=="
}""", }""",
""""0": { """"0": {
"type": "artifact", "type": "artifact",
"mime_type": "image/jpeg", "mime_type": "image/jpeg",
"url": "https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg", "url": "https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg",
@ -213,20 +216,22 @@ def test_parse_observed_data(data):
"MD5": "6826f9a05da08134006557758bb3afbb" "MD5": "6826f9a05da08134006557758bb3afbb"
} }
}""", }""",
]) ],
)
def test_parse_artifact_valid(data): def test_parse_artifact_valid(data):
odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED) odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED)
odata = stix2.parse(odata_str, version="2.1") odata = stix2.parse(odata_str, version="2.1")
assert odata.objects["0"].type == "artifact" assert odata.objects["0"].type == "artifact"
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
""""0": { "data", [
""""0": {
"type": "artifact", "type": "artifact",
"mime_type": "image/jpeg", "mime_type": "image/jpeg",
"payload_bin": "abcVBORw0KGgoAAAANSUhEUgAAADI==" "payload_bin": "abcVBORw0KGgoAAAANSUhEUgAAADI=="
}""", }""",
""""0": { """"0": {
"type": "artifact", "type": "artifact",
"mime_type": "image/jpeg", "mime_type": "image/jpeg",
"url": "https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg", "url": "https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg",
@ -234,7 +239,8 @@ def test_parse_artifact_valid(data):
"MD5": "a" "MD5": "a"
} }
}""", }""",
]) ],
)
def test_parse_artifact_invalid(data): def test_parse_artifact_invalid(data):
odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED) odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED)
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -249,14 +255,16 @@ def test_artifact_example_dependency_error():
assert str(excinfo.value) == "The property dependencies for Artifact: (hashes, url) are not met." assert str(excinfo.value) == "The property dependencies for Artifact: (hashes, url) are not met."
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
""""0": { "data", [
""""0": {
"type": "autonomous-system", "type": "autonomous-system",
"number": 15139, "number": 15139,
"name": "Slime Industries", "name": "Slime Industries",
"rir": "ARIN" "rir": "ARIN"
}""", }""",
]) ],
)
def test_parse_autonomous_system_valid(data): def test_parse_autonomous_system_valid(data):
odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED) odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED)
odata = stix2.parse(odata_str, version="2.1") odata = stix2.parse(odata_str, version="2.1")
@ -266,14 +274,16 @@ def test_parse_autonomous_system_valid(data):
assert odata.objects["0"].rir == "ARIN" assert odata.objects["0"].rir == "ARIN"
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
"""{ "data", [
"""{
"type": "email-addr", "type": "email-addr",
"value": "john@example.com", "value": "john@example.com",
"display_name": "John Doe", "display_name": "John Doe",
"belongs_to_ref": "0" "belongs_to_ref": "0"
}""", }""",
]) ],
)
def test_parse_email_address(data): def test_parse_email_address(data):
odata = stix2.parse_observable(data, {"0": "user-account"}, version='2.1') odata = stix2.parse_observable(data, {"0": "user-account"}, version='2.1')
assert odata.type == "email-addr" assert odata.type == "email-addr"
@ -283,8 +293,9 @@ def test_parse_email_address(data):
stix2.parse_observable(odata_str, {"0": "user-account"}, version='2.1') stix2.parse_observable(odata_str, {"0": "user-account"}, version='2.1')
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
""" "data", [
"""
{ {
"type": "email-message", "type": "email-message",
"is_multipart": true, "is_multipart": true,
@ -321,8 +332,9 @@ def test_parse_email_address(data):
} }
] ]
} }
""" """,
]) ],
)
def test_parse_email_message(data): def test_parse_email_message(data):
valid_refs = { valid_refs = {
"0": "email-message", "0": "email-message",
@ -337,8 +349,9 @@ def test_parse_email_message(data):
assert odata.body_multipart[0].content_disposition == "inline" assert odata.body_multipart[0].content_disposition == "inline"
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
""" "data", [
"""
{ {
"type": "email-message", "type": "email-message",
"from_ref": "0", "from_ref": "0",
@ -348,8 +361,9 @@ def test_parse_email_message(data):
"subject": "Saying Hello", "subject": "Saying Hello",
"body": "Cats are funny!" "body": "Cats are funny!"
} }
""" """,
]) ],
)
def test_parse_email_message_not_multipart(data): def test_parse_email_message_not_multipart(data):
valid_refs = { valid_refs = {
"0": "email-addr", "0": "email-addr",
@ -362,8 +376,9 @@ def test_parse_email_message_not_multipart(data):
assert excinfo.value.dependencies == [("is_multipart", "body")] assert excinfo.value.dependencies == [("is_multipart", "body")]
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
""""0": { "data", [
""""0": {
"type": "file", "type": "file",
"hashes": { "hashes": {
"SHA-256": "ceafbfd424be2ca4a5f0402cae090dda2fb0526cf521b60b60077c0f622b285a" "SHA-256": "ceafbfd424be2ca4a5f0402cae090dda2fb0526cf521b60b60077c0f622b285a"
@ -399,15 +414,17 @@ def test_parse_email_message_not_multipart(data):
} }
} }
}""", }""",
]) ],
)
def test_parse_file_archive(data): def test_parse_file_archive(data):
odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED) odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED)
odata = stix2.parse(odata_str, version="2.1") odata = stix2.parse(odata_str, version="2.1")
assert odata.objects["3"].extensions['archive-ext'].version == "5.0" assert odata.objects["3"].extensions['archive-ext'].version == "5.0"
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
""" "data", [
"""
{ {
"type": "email-message", "type": "email-message",
"is_multipart": true, "is_multipart": true,
@ -443,8 +460,9 @@ def test_parse_file_archive(data):
} }
] ]
} }
""" """,
]) ],
)
def test_parse_email_message_with_at_least_one_error(data): def test_parse_email_message_with_at_least_one_error(data):
valid_refs = { valid_refs = {
"0": "email-message", "0": "email-message",
@ -463,8 +481,9 @@ def test_parse_email_message_with_at_least_one_error(data):
assert "must be populated" in str(excinfo.value) assert "must be populated" in str(excinfo.value)
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
""" "data", [
"""
{ {
"type": "network-traffic", "type": "network-traffic",
"src_ref": "0", "src_ref": "0",
@ -473,11 +492,14 @@ def test_parse_email_message_with_at_least_one_error(data):
"tcp" "tcp"
] ]
} }
""" """,
]) ],
)
def test_parse_basic_tcp_traffic(data): def test_parse_basic_tcp_traffic(data):
odata = stix2.parse_observable(data, {"0": "ipv4-addr", "1": "ipv4-addr"}, odata = stix2.parse_observable(
version='2.1') data, {"0": "ipv4-addr", "1": "ipv4-addr"},
version='2.1',
)
assert odata.type == "network-traffic" assert odata.type == "network-traffic"
assert odata.src_ref == "0" assert odata.src_ref == "0"
@ -485,8 +507,9 @@ def test_parse_basic_tcp_traffic(data):
assert odata.protocols == ["tcp"] assert odata.protocols == ["tcp"]
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
""" "data", [
"""
{ {
"type": "network-traffic", "type": "network-traffic",
"src_port": 2487, "src_port": 2487,
@ -501,8 +524,9 @@ def test_parse_basic_tcp_traffic(data):
"4" "4"
] ]
} }
""" """,
]) ],
)
def test_parse_basic_tcp_traffic_with_error(data): def test_parse_basic_tcp_traffic_with_error(data):
with pytest.raises(stix2.exceptions.AtLeastOnePropertyError) as excinfo: with pytest.raises(stix2.exceptions.AtLeastOnePropertyError) as excinfo:
stix2.parse_observable(data, {"4": "network-traffic"}, version='2.1') stix2.parse_observable(data, {"4": "network-traffic"}, version='2.1')
@ -555,7 +579,7 @@ def test_observed_data_with_process_example():
"0": { "0": {
"type": "file", "type": "file",
"hashes": { "hashes": {
"SHA-256": "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f" "SHA-256": "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f",
}, },
}, },
"1": { "1": {
@ -564,11 +588,12 @@ def test_observed_data_with_process_example():
"name": "gedit-bin", "name": "gedit-bin",
"created": "2016-01-20T14:11:25.55Z", "created": "2016-01-20T14:11:25.55Z",
"arguments": [ "arguments": [
"--new-window" "--new-window",
], ],
"image_ref": "0" "image_ref": "0",
} },
}) },
)
assert observed_data.objects["0"].type == "file" assert observed_data.objects["0"].type == "file"
assert observed_data.objects["0"].hashes["SHA-256"] == "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f" assert observed_data.objects["0"].hashes["SHA-256"] == "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f"
@ -585,8 +610,9 @@ def test_artifact_example():
mime_type="image/jpeg", mime_type="image/jpeg",
url="https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg", url="https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg",
hashes={ hashes={
"MD5": "6826f9a05da08134006557758bb3afbb" "MD5": "6826f9a05da08134006557758bb3afbb",
}) },
)
assert art.mime_type == "image/jpeg" assert art.mime_type == "image/jpeg"
assert art.url == "https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg" assert art.url == "https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg"
assert art.hashes["MD5"] == "6826f9a05da08134006557758bb3afbb" assert art.hashes["MD5"] == "6826f9a05da08134006557758bb3afbb"
@ -598,9 +624,10 @@ def test_artifact_mutual_exclusion_error():
mime_type="image/jpeg", mime_type="image/jpeg",
url="https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg", url="https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg",
hashes={ hashes={
"MD5": "6826f9a05da08134006557758bb3afbb" "MD5": "6826f9a05da08134006557758bb3afbb",
}, },
payload_bin="VBORw0KGgoAAAANSUhEUgAAADI==") payload_bin="VBORw0KGgoAAAANSUhEUgAAADI==",
)
assert excinfo.value.cls == stix2.v21.Artifact assert excinfo.value.cls == stix2.v21.Artifact
assert excinfo.value.properties == ["payload_bin", "url"] assert excinfo.value.properties == ["payload_bin", "url"]
@ -614,7 +641,8 @@ def test_directory_example():
created="2015-12-21T19:00:00Z", created="2015-12-21T19:00:00Z",
modified="2015-12-24T19:00:00Z", modified="2015-12-24T19:00:00Z",
accessed="2015-12-21T20:00:00Z", accessed="2015-12-21T20:00:00Z",
contains_refs=["1"]) contains_refs=["1"],
)
assert dir.path == '/usr/lib' assert dir.path == '/usr/lib'
assert dir.created == dt.datetime(2015, 12, 21, 19, 0, 0, tzinfo=pytz.utc) assert dir.created == dt.datetime(2015, 12, 21, 19, 0, 0, tzinfo=pytz.utc)
@ -631,7 +659,8 @@ def test_directory_example_ref_error():
created="2015-12-21T19:00:00Z", created="2015-12-21T19:00:00Z",
modified="2015-12-24T19:00:00Z", modified="2015-12-24T19:00:00Z",
accessed="2015-12-21T20:00:00Z", accessed="2015-12-21T20:00:00Z",
contains_refs=["1"]) contains_refs=["1"],
)
assert excinfo.value.cls == stix2.v21.Directory assert excinfo.value.cls == stix2.v21.Directory
assert excinfo.value.prop_name == "contains_refs" assert excinfo.value.prop_name == "contains_refs"
@ -641,7 +670,8 @@ def test_domain_name_example():
dn = stix2.v21.DomainName( dn = stix2.v21.DomainName(
_valid_refs={"1": 'domain-name'}, _valid_refs={"1": 'domain-name'},
value="example.com", value="example.com",
resolves_to_refs=["1"]) resolves_to_refs=["1"],
)
assert dn.value == "example.com" assert dn.value == "example.com"
assert dn.resolves_to_refs == ["1"] assert dn.resolves_to_refs == ["1"]
@ -652,7 +682,8 @@ def test_domain_name_example_invalid_ref_type():
stix2.v21.DomainName( stix2.v21.DomainName(
_valid_refs={"1": "file"}, _valid_refs={"1": "file"},
value="example.com", value="example.com",
resolves_to_refs=["1"]) resolves_to_refs=["1"],
)
assert excinfo.value.cls == stix2.v21.DomainName assert excinfo.value.cls == stix2.v21.DomainName
assert excinfo.value.prop_name == "resolves_to_refs" assert excinfo.value.prop_name == "resolves_to_refs"
@ -662,14 +693,14 @@ def test_file_example():
f = stix2.v21.File( f = stix2.v21.File(
name="qwerty.dll", name="qwerty.dll",
hashes={ hashes={
"SHA-256": "ceafbfd424be2ca4a5f0402cae090dda2fb0526cf521b60b60077c0f622b285a" "SHA-256": "ceafbfd424be2ca4a5f0402cae090dda2fb0526cf521b60b60077c0f622b285a",
}, },
size=100, size=100,
magic_number_hex="1C", magic_number_hex="1C",
mime_type="application/msword", mime_type="application/msword",
created="2016-12-21T19:00:00Z", created="2016-12-21T19:00:00Z",
modified="2016-12-24T19:00:00Z", modified="2016-12-24T19:00:00Z",
accessed="2016-12-21T20:00:00Z" accessed="2016-12-21T20:00:00Z",
) )
assert f.name == "qwerty.dll" assert f.name == "qwerty.dll"
@ -690,11 +721,12 @@ def test_file_example_with_NTFSExt():
"alternate_data_streams": [ "alternate_data_streams": [
{ {
"name": "second.stream", "name": "second.stream",
"size": 25536 "size": 25536,
} },
] ],
} },
}) },
)
assert f.name == "abc.txt" assert f.name == "abc.txt"
assert f.extensions["ntfs-ext"].alternate_data_streams[0].size == 25536 assert f.extensions["ntfs-ext"].alternate_data_streams[0].size == 25536
@ -705,8 +737,9 @@ def test_file_example_with_empty_NTFSExt():
stix2.v21.File( stix2.v21.File(
name="abc.txt", name="abc.txt",
extensions={ extensions={
"ntfs-ext": {} "ntfs-ext": {},
}) },
)
assert excinfo.value.cls == stix2.NTFSExt assert excinfo.value.cls == stix2.NTFSExt
assert excinfo.value.properties == sorted(list(stix2.NTFSExt._properties.keys())) assert excinfo.value.properties == sorted(list(stix2.NTFSExt._properties.keys()))
@ -723,12 +756,13 @@ def test_file_example_with_PDFExt():
"Author": "Adobe Systems Incorporated", "Author": "Adobe Systems Incorporated",
"Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh", "Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh",
"Producer": "Acrobat Distiller 3.01 for Power Macintosh", "Producer": "Acrobat Distiller 3.01 for Power Macintosh",
"CreationDate": "20070412090123-02" "CreationDate": "20070412090123-02",
}, },
"pdfid0": "DFCE52BD827ECF765649852119D", "pdfid0": "DFCE52BD827ECF765649852119D",
"pdfid1": "57A1E0F9ED2AE523E313C" "pdfid1": "57A1E0F9ED2AE523E313C",
} },
}) },
)
assert f.name == "qwerty.dll" assert f.name == "qwerty.dll"
assert f.extensions["pdf-ext"].version == "1.7" assert f.extensions["pdf-ext"].version == "1.7"
@ -746,11 +780,13 @@ def test_file_example_with_PDFExt_Object():
"Author": "Adobe Systems Incorporated", "Author": "Adobe Systems Incorporated",
"Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh", "Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh",
"Producer": "Acrobat Distiller 3.01 for Power Macintosh", "Producer": "Acrobat Distiller 3.01 for Power Macintosh",
"CreationDate": "20070412090123-02" "CreationDate": "20070412090123-02",
}, },
pdfid0="DFCE52BD827ECF765649852119D", pdfid0="DFCE52BD827ECF765649852119D",
pdfid1="57A1E0F9ED2AE523E313C") pdfid1="57A1E0F9ED2AE523E313C",
}) ),
},
)
assert f.name == "qwerty.dll" assert f.name == "qwerty.dll"
assert f.extensions["pdf-ext"].version == "1.7" assert f.extensions["pdf-ext"].version == "1.7"
@ -767,10 +803,11 @@ def test_file_example_with_RasterImageExt_Object():
"Make": "Nikon", "Make": "Nikon",
"Model": "D7000", "Model": "D7000",
"XResolution": 4928, "XResolution": 4928,
"YResolution": 3264 "YResolution": 3264,
} },
} },
}) },
)
assert f.name == "qwerty.jpeg" assert f.name == "qwerty.jpeg"
assert f.extensions["raster-image-ext"].bits_per_pixel == 123 assert f.extensions["raster-image-ext"].bits_per_pixel == 123
assert f.extensions["raster-image-ext"].exif_tags["XResolution"] == 4928 assert f.extensions["raster-image-ext"].exif_tags["XResolution"] == 4928
@ -865,28 +902,29 @@ def test_file_example_with_WindowsPEBinaryExt():
"size_of_heap_reserve": 100000, "size_of_heap_reserve": 100000,
"size_of_heap_commit": 4096, "size_of_heap_commit": 4096,
"loader_flags_hex": "abdbffde", "loader_flags_hex": "abdbffde",
"number_of_rva_and_sizes": 3758087646 "number_of_rva_and_sizes": 3758087646,
}, },
"sections": [ "sections": [
{ {
"name": "CODE", "name": "CODE",
"entropy": 0.061089 "entropy": 0.061089,
}, },
{ {
"name": "DATA", "name": "DATA",
"entropy": 7.980693 "entropy": 7.980693,
}, },
{ {
"name": "NicolasB", "name": "NicolasB",
"entropy": 0.607433 "entropy": 0.607433,
}, },
{ {
"name": ".idata", "name": ".idata",
"entropy": 0.607433 "entropy": 0.607433,
} },
] ],
} },
}) },
)
assert f.name == "qwerty.dll" assert f.name == "qwerty.dll"
assert f.extensions["windows-pebinary-ext"].sections[2].entropy == 0.607433 assert f.extensions["windows-pebinary-ext"].sections[2].entropy == 0.607433
@ -903,7 +941,8 @@ def test_ip4_address_example():
ip4 = stix2.v21.IPv4Address( ip4 = stix2.v21.IPv4Address(
_valid_refs={"4": "mac-addr", "5": "mac-addr"}, _valid_refs={"4": "mac-addr", "5": "mac-addr"},
value="198.51.100.3", value="198.51.100.3",
resolves_to_refs=["4", "5"]) resolves_to_refs=["4", "5"],
)
assert ip4.value == "198.51.100.3" assert ip4.value == "198.51.100.3"
assert ip4.resolves_to_refs == ["4", "5"] assert ip4.resolves_to_refs == ["4", "5"]
@ -932,7 +971,8 @@ def test_network_traffic_example():
_valid_refs={"0": "ipv4-addr", "1": "ipv4-addr"}, _valid_refs={"0": "ipv4-addr", "1": "ipv4-addr"},
protocols="tcp", protocols="tcp",
src_ref="0", src_ref="0",
dst_ref="1") dst_ref="1",
)
assert nt.protocols == ["tcp"] assert nt.protocols == ["tcp"]
assert nt.src_ref == "0" assert nt.src_ref == "0"
assert nt.dst_ref == "1" assert nt.dst_ref == "1"
@ -946,13 +986,15 @@ def test_network_traffic_http_request_example():
request_header={ request_header={
"Accept-Encoding": "gzip,deflate", "Accept-Encoding": "gzip,deflate",
"User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113", "User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113",
"Host": "www.example.com" "Host": "www.example.com",
}) },
)
nt = stix2.v21.NetworkTraffic( nt = stix2.v21.NetworkTraffic(
_valid_refs={"0": "ipv4-addr"}, _valid_refs={"0": "ipv4-addr"},
protocols="tcp", protocols="tcp",
src_ref="0", src_ref="0",
extensions={'http-request-ext': h}) extensions={'http-request-ext': h},
)
assert nt.extensions['http-request-ext'].request_method == "get" assert nt.extensions['http-request-ext'].request_method == "get"
assert nt.extensions['http-request-ext'].request_value == "/download.html" assert nt.extensions['http-request-ext'].request_value == "/download.html"
assert nt.extensions['http-request-ext'].request_version == "http/1.1" assert nt.extensions['http-request-ext'].request_version == "http/1.1"
@ -967,7 +1009,8 @@ def test_network_traffic_icmp_example():
_valid_refs={"0": "ipv4-addr"}, _valid_refs={"0": "ipv4-addr"},
protocols="tcp", protocols="tcp",
src_ref="0", src_ref="0",
extensions={'icmp-ext': h}) extensions={'icmp-ext': h},
)
assert nt.extensions['icmp-ext'].icmp_type_hex == "08" assert nt.extensions['icmp-ext'].icmp_type_hex == "08"
assert nt.extensions['icmp-ext'].icmp_code_hex == "00" assert nt.extensions['icmp-ext'].icmp_code_hex == "00"
@ -977,12 +1020,14 @@ def test_network_traffic_socket_example():
is_listening=True, is_listening=True,
address_family="AF_INET", address_family="AF_INET",
protocol_family="PF_INET", protocol_family="PF_INET",
socket_type="SOCK_STREAM") socket_type="SOCK_STREAM",
)
nt = stix2.v21.NetworkTraffic( nt = stix2.v21.NetworkTraffic(
_valid_refs={"0": "ipv4-addr"}, _valid_refs={"0": "ipv4-addr"},
protocols="tcp", protocols="tcp",
src_ref="0", src_ref="0",
extensions={'socket-ext': h}) extensions={'socket-ext': h},
)
assert nt.extensions['socket-ext'].is_listening assert nt.extensions['socket-ext'].is_listening
assert nt.extensions['socket-ext'].address_family == "AF_INET" assert nt.extensions['socket-ext'].address_family == "AF_INET"
assert nt.extensions['socket-ext'].protocol_family == "PF_INET" assert nt.extensions['socket-ext'].protocol_family == "PF_INET"
@ -995,7 +1040,8 @@ def test_network_traffic_tcp_example():
_valid_refs={"0": "ipv4-addr"}, _valid_refs={"0": "ipv4-addr"},
protocols="tcp", protocols="tcp",
src_ref="0", src_ref="0",
extensions={'tcp-ext': h}) extensions={'tcp-ext': h},
)
assert nt.extensions['tcp-ext'].src_flags_hex == "00000002" assert nt.extensions['tcp-ext'].src_flags_hex == "00000002"
@ -1012,7 +1058,8 @@ def test_process_example():
name="gedit-bin", name="gedit-bin",
created="2016-01-20T14:11:25.55Z", created="2016-01-20T14:11:25.55Z",
arguments=["--new-window"], arguments=["--new-window"],
image_ref="0") image_ref="0",
)
assert p.name == "gedit-bin" assert p.name == "gedit-bin"
assert p.arguments == ["--new-window"] assert p.arguments == ["--new-window"]
@ -1027,15 +1074,17 @@ def test_process_example_empty_error():
properties_of_process.remove("type") properties_of_process.remove("type")
assert excinfo.value.properties == sorted(properties_of_process) assert excinfo.value.properties == sorted(properties_of_process)
msg = "At least one of the ({1}) properties for {0} must be populated." msg = "At least one of the ({1}) properties for {0} must be populated."
msg = msg.format(stix2.v21.Process.__name__, msg = msg.format(
", ".join(sorted(properties_of_process))) stix2.v21.Process.__name__,
", ".join(sorted(properties_of_process)),
)
assert str(excinfo.value) == msg assert str(excinfo.value) == msg
def test_process_example_empty_with_extensions(): def test_process_example_empty_with_extensions():
with pytest.raises(stix2.exceptions.AtLeastOnePropertyError) as excinfo: with pytest.raises(stix2.exceptions.AtLeastOnePropertyError) as excinfo:
stix2.v21.Process(extensions={ stix2.v21.Process(extensions={
"windows-process-ext": {} "windows-process-ext": {},
}) })
assert excinfo.value.cls == stix2.v21.WindowsProcessExt assert excinfo.value.cls == stix2.v21.WindowsProcessExt
@ -1052,9 +1101,10 @@ def test_process_example_windows_process_ext():
"aslr_enabled": True, "aslr_enabled": True,
"dep_enabled": True, "dep_enabled": True,
"priority": "HIGH_PRIORITY_CLASS", "priority": "HIGH_PRIORITY_CLASS",
"owner_sid": "S-1-5-21-186985262-1144665072-74031268-1309" "owner_sid": "S-1-5-21-186985262-1144665072-74031268-1309",
} },
}) },
)
assert proc.extensions["windows-process-ext"].aslr_enabled assert proc.extensions["windows-process-ext"].aslr_enabled
assert proc.extensions["windows-process-ext"].dep_enabled assert proc.extensions["windows-process-ext"].dep_enabled
assert proc.extensions["windows-process-ext"].priority == "HIGH_PRIORITY_CLASS" assert proc.extensions["windows-process-ext"].priority == "HIGH_PRIORITY_CLASS"
@ -1067,8 +1117,9 @@ def test_process_example_windows_process_ext_empty():
pid=1221, pid=1221,
name="gedit-bin", name="gedit-bin",
extensions={ extensions={
"windows-process-ext": {} "windows-process-ext": {},
}) },
)
assert excinfo.value.cls == stix2.v21.WindowsProcessExt assert excinfo.value.cls == stix2.v21.WindowsProcessExt
properties_of_extension = list(stix2.v21.WindowsProcessExt._properties.keys()) properties_of_extension = list(stix2.v21.WindowsProcessExt._properties.keys())
@ -1090,7 +1141,8 @@ def test_process_example_with_WindowsProcessExt_Object():
aslr_enabled=True, aslr_enabled=True,
dep_enabled=True, dep_enabled=True,
priority="HIGH_PRIORITY_CLASS", priority="HIGH_PRIORITY_CLASS",
owner_sid="S-1-5-21-186985262-1144665072-74031268-1309") # noqa owner_sid="S-1-5-21-186985262-1144665072-74031268-1309",
), # noqa
}) })
assert p.extensions["windows-process-ext"].dep_enabled assert p.extensions["windows-process-ext"].dep_enabled
@ -1104,8 +1156,8 @@ def test_process_example_with_WindowsServiceExt():
"display_name": "Sirvizio", "display_name": "Sirvizio",
"start_type": "SERVICE_AUTO_START", "start_type": "SERVICE_AUTO_START",
"service_type": "SERVICE_WIN32_OWN_PROCESS", "service_type": "SERVICE_WIN32_OWN_PROCESS",
"service_status": "SERVICE_RUNNING" "service_status": "SERVICE_RUNNING",
} },
}) })
assert p.extensions["windows-service-ext"].service_name == "sirvizio" assert p.extensions["windows-service-ext"].service_name == "sirvizio"
@ -1119,14 +1171,14 @@ def test_process_example_with_WindowsProcessServiceExt():
"display_name": "Sirvizio", "display_name": "Sirvizio",
"start_type": "SERVICE_AUTO_START", "start_type": "SERVICE_AUTO_START",
"service_type": "SERVICE_WIN32_OWN_PROCESS", "service_type": "SERVICE_WIN32_OWN_PROCESS",
"service_status": "SERVICE_RUNNING" "service_status": "SERVICE_RUNNING",
}, },
"windows-process-ext": { "windows-process-ext": {
"aslr_enabled": True, "aslr_enabled": True,
"dep_enabled": True, "dep_enabled": True,
"priority": "HIGH_PRIORITY_CLASS", "priority": "HIGH_PRIORITY_CLASS",
"owner_sid": "S-1-5-21-186985262-1144665072-74031268-1309" "owner_sid": "S-1-5-21-186985262-1144665072-74031268-1309",
} },
}) })
assert p.extensions["windows-service-ext"].service_name == "sirvizio" assert p.extensions["windows-service-ext"].service_name == "sirvizio"
@ -1140,7 +1192,8 @@ def test_software_example():
name="Word", name="Word",
cpe="cpe:2.3:a:microsoft:word:2000:*:*:*:*:*:*:*", cpe="cpe:2.3:a:microsoft:word:2000:*:*:*:*:*:*:*",
version="2002", version="2002",
vendor="Microsoft") vendor="Microsoft",
)
assert s.name == "Word" assert s.name == "Word"
assert s.cpe == "cpe:2.3:a:microsoft:word:2000:*:*:*:*:*:*:*" assert s.cpe == "cpe:2.3:a:microsoft:word:2000:*:*:*:*:*:*:*"
@ -1167,7 +1220,8 @@ def test_user_account_example():
account_created="2016-01-20T12:31:12Z", account_created="2016-01-20T12:31:12Z",
credential_last_changed="2016-01-20T14:27:43Z", credential_last_changed="2016-01-20T14:27:43Z",
account_first_login="2016-01-20T14:26:07Z", account_first_login="2016-01-20T14:26:07Z",
account_last_login="2016-07-22T16:08:28Z") account_last_login="2016-07-22T16:08:28Z",
)
assert a.user_id == "1001" assert a.user_id == "1001"
assert a.account_login == "jdoe" assert a.account_login == "jdoe"
@ -1187,12 +1241,14 @@ def test_user_account_unix_account_ext_example():
gid=1001, gid=1001,
groups=["wheel"], groups=["wheel"],
home_dir="/home/jdoe", home_dir="/home/jdoe",
shell="/bin/bash") shell="/bin/bash",
)
a = stix2.v21.UserAccount( a = stix2.v21.UserAccount(
user_id="1001", user_id="1001",
account_login="jdoe", account_login="jdoe",
account_type="unix", account_type="unix",
extensions={'unix-account-ext': u}) extensions={'unix-account-ext': u},
)
assert a.extensions['unix-account-ext'].gid == 1001 assert a.extensions['unix-account-ext'].gid == 1001
assert a.extensions['unix-account-ext'].groups == ["wheel"] assert a.extensions['unix-account-ext'].groups == ["wheel"]
assert a.extensions['unix-account-ext'].home_dir == "/home/jdoe" assert a.extensions['unix-account-ext'].home_dir == "/home/jdoe"
@ -1204,16 +1260,17 @@ def test_windows_registry_key_example():
stix2.v21.WindowsRegistryValueType( stix2.v21.WindowsRegistryValueType(
name="Foo", name="Foo",
data="qwerty", data="qwerty",
data_type="string") data_type="string",
)
v = stix2.v21.WindowsRegistryValueType( v = stix2.v21.WindowsRegistryValueType(
name="Foo", name="Foo",
data="qwerty", data="qwerty",
data_type="REG_SZ" data_type="REG_SZ",
) )
w = stix2.v21.WindowsRegistryKey( w = stix2.v21.WindowsRegistryKey(
key="hkey_local_machine\\system\\bar\\foo", key="hkey_local_machine\\system\\bar\\foo",
values=[v] values=[v],
) )
assert w.key == "hkey_local_machine\\system\\bar\\foo" assert w.key == "hkey_local_machine\\system\\bar\\foo"
assert w.values[0].name == "Foo" assert w.values[0].name == "Foo"
@ -1226,7 +1283,8 @@ def test_x509_certificate_example():
issuer="C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Server CA/emailAddress=server-certs@thawte.com", # noqa issuer="C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Server CA/emailAddress=server-certs@thawte.com", # noqa
validity_not_before="2016-03-12T12:00:00Z", validity_not_before="2016-03-12T12:00:00Z",
validity_not_after="2016-08-21T12:00:00Z", validity_not_after="2016-08-21T12:00:00Z",
subject="C=US, ST=Maryland, L=Pasadena, O=Brent Baccala, OU=FreeSoft, CN=www.freesoft.org/emailAddress=baccala@freesoft.org") # noqa subject="C=US, ST=Maryland, L=Pasadena, O=Brent Baccala, OU=FreeSoft, CN=www.freesoft.org/emailAddress=baccala@freesoft.org",
) # noqa
assert x509.type == "x509-certificate" assert x509.type == "x509-certificate"
assert x509.issuer == "C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Server CA/emailAddress=server-certs@thawte.com" # noqa assert x509.issuer == "C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Server CA/emailAddress=server-certs@thawte.com" # noqa
@ -1241,14 +1299,14 @@ def test_new_version_with_related_objects():
objects={ objects={
'src_ip': { 'src_ip': {
'type': 'ipv4-addr', 'type': 'ipv4-addr',
'value': '127.0.0.1/32' 'value': '127.0.0.1/32',
}, },
'domain': { 'domain': {
'type': 'domain-name', 'type': 'domain-name',
'value': 'example.com', 'value': 'example.com',
'resolves_to_refs': ['src_ip'] 'resolves_to_refs': ['src_ip'],
} },
} },
) )
new_version = data.new_version(last_observed="2017-12-12T12:00:00Z") new_version = data.new_version(last_observed="2017-12-12T12:00:00Z")
assert new_version.last_observed.year == 2017 assert new_version.last_observed.year == 2017

View File

@ -8,11 +8,13 @@ import stix2
from .constants import OPINION_ID from .constants import OPINION_ID
DESCRIPTION = ('This doesn\'t seem like it is feasible. We\'ve seen how ' DESCRIPTION = (
'PandaCat has attacked Spanish infrastructure over the ' 'This doesn\'t seem like it is feasible. We\'ve seen how '
'last 3 years, so this change in targeting seems too great' 'PandaCat has attacked Spanish infrastructure over the '
' to be viable. The methods used are more commonly ' 'last 3 years, so this change in targeting seems too great'
'associated with the FlameDragonCrew.') ' to be viable. The methods used are more commonly '
'associated with the FlameDragonCrew.'
)
EXPECTED_OPINION = """{ EXPECTED_OPINION = """{
"type": "opinion", "type": "opinion",
@ -27,7 +29,8 @@ EXPECTED_OPINION = """{
"opinion": "strongly-disagree" "opinion": "strongly-disagree"
}""" % DESCRIPTION }""" % DESCRIPTION
EXPECTED_OPINION_REPR = "Opinion(" + " ".join((""" EXPECTED_OPINION_REPR = "Opinion(" + " ".join((
"""
type='opinion', type='opinion',
spec_version='2.1', spec_version='2.1',
id='opinion--b01efc25-77b4-4003-b18b-f6e24b5cd9f7', id='opinion--b01efc25-77b4-4003-b18b-f6e24b5cd9f7',
@ -35,7 +38,8 @@ EXPECTED_OPINION_REPR = "Opinion(" + " ".join(("""
modified='2016-05-12T08:17:27.000Z', modified='2016-05-12T08:17:27.000Z',
description="%s", description="%s",
object_refs=['relationship--16d2358f-3b0d-4c88-b047-0da2f7ed4471'], object_refs=['relationship--16d2358f-3b0d-4c88-b047-0da2f7ed4471'],
opinion='strongly-disagree'""" % DESCRIPTION).split()) + ")" opinion='strongly-disagree'""" % DESCRIPTION
).split()) + ")"
def test_opinion_with_required_properties(): def test_opinion_with_required_properties():
@ -48,7 +52,7 @@ def test_opinion_with_required_properties():
modified=now, modified=now,
object_refs=['relationship--16d2358f-3b0d-4c88-b047-0da2f7ed4471'], object_refs=['relationship--16d2358f-3b0d-4c88-b047-0da2f7ed4471'],
opinion='strongly-disagree', opinion='strongly-disagree',
description=DESCRIPTION description=DESCRIPTION,
) )
assert str(opi) == EXPECTED_OPINION assert str(opi) == EXPECTED_OPINION
@ -56,21 +60,23 @@ def test_opinion_with_required_properties():
assert rep == EXPECTED_OPINION_REPR assert rep == EXPECTED_OPINION_REPR
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED_OPINION, "data", [
{ EXPECTED_OPINION,
"type": "opinion", {
"spec_version": "2.1", "type": "opinion",
"id": "opinion--b01efc25-77b4-4003-b18b-f6e24b5cd9f7", "spec_version": "2.1",
"created": "2016-05-12T08:17:27.000Z", "id": "opinion--b01efc25-77b4-4003-b18b-f6e24b5cd9f7",
"modified": "2016-05-12T08:17:27.000Z", "created": "2016-05-12T08:17:27.000Z",
"description": DESCRIPTION, "modified": "2016-05-12T08:17:27.000Z",
"object_refs": [ "description": DESCRIPTION,
"relationship--16d2358f-3b0d-4c88-b047-0da2f7ed4471" "object_refs": [
], "relationship--16d2358f-3b0d-4c88-b047-0da2f7ed4471",
"opinion": "strongly-disagree" ],
} "opinion": "strongly-disagree",
]) },
],
)
def test_parse_opinion(data): def test_parse_opinion(data):
opinion = stix2.parse(data, version="2.1") opinion = stix2.parse(data, version="2.1")

View File

@ -7,37 +7,55 @@ import stix2
def test_create_comparison_expression(): def test_create_comparison_expression():
exp = stix2.EqualityComparisonExpression("file:hashes.'SHA-256'", exp = stix2.EqualityComparisonExpression(
stix2.HashConstant("aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f", "SHA-256")) # noqa "file:hashes.'SHA-256'",
stix2.HashConstant("aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f", "SHA-256"),
) # noqa
assert str(exp) == "file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f'" assert str(exp) == "file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f'"
def test_boolean_expression(): def test_boolean_expression():
exp1 = stix2.MatchesComparisonExpression("email-message:from_ref.value", exp1 = stix2.MatchesComparisonExpression(
stix2.StringConstant(".+\\@example\\.com$")) "email-message:from_ref.value",
exp2 = stix2.MatchesComparisonExpression("email-message:body_multipart[*].body_raw_ref.name", stix2.StringConstant(".+\\@example\\.com$"),
stix2.StringConstant("^Final Report.+\\.exe$")) )
exp2 = stix2.MatchesComparisonExpression(
"email-message:body_multipart[*].body_raw_ref.name",
stix2.StringConstant("^Final Report.+\\.exe$"),
)
exp = stix2.AndBooleanExpression([exp1, exp2]) exp = stix2.AndBooleanExpression([exp1, exp2])
assert str(exp) == "email-message:from_ref.value MATCHES '.+\\\\@example\\\\.com$' AND email-message:body_multipart[*].body_raw_ref.name MATCHES '^Final Report.+\\\\.exe$'" # noqa assert str(exp) == "email-message:from_ref.value MATCHES '.+\\\\@example\\\\.com$' AND email-message:body_multipart[*].body_raw_ref.name MATCHES '^Final Report.+\\\\.exe$'" # noqa
def test_boolean_expression_with_parentheses(): def test_boolean_expression_with_parentheses():
exp1 = stix2.MatchesComparisonExpression(stix2.ObjectPath("email-message", exp1 = stix2.MatchesComparisonExpression(
[stix2.ReferenceObjectPathComponent("from_ref"), stix2.ObjectPath(
stix2.BasicObjectPathComponent("value")]), "email-message",
stix2.StringConstant(".+\\@example\\.com$")) [
exp2 = stix2.MatchesComparisonExpression("email-message:body_multipart[*].body_raw_ref.name", stix2.ReferenceObjectPathComponent("from_ref"),
stix2.StringConstant("^Final Report.+\\.exe$")) stix2.BasicObjectPathComponent("value"),
],
),
stix2.StringConstant(".+\\@example\\.com$"),
)
exp2 = stix2.MatchesComparisonExpression(
"email-message:body_multipart[*].body_raw_ref.name",
stix2.StringConstant("^Final Report.+\\.exe$"),
)
exp = stix2.ParentheticalExpression(stix2.AndBooleanExpression([exp1, exp2])) exp = stix2.ParentheticalExpression(stix2.AndBooleanExpression([exp1, exp2]))
assert str(exp) == "(email-message:from_ref.value MATCHES '.+\\\\@example\\\\.com$' AND email-message:body_multipart[*].body_raw_ref.name MATCHES '^Final Report.+\\\\.exe$')" # noqa assert str(exp) == "(email-message:from_ref.value MATCHES '.+\\\\@example\\\\.com$' AND email-message:body_multipart[*].body_raw_ref.name MATCHES '^Final Report.+\\\\.exe$')" # noqa
def test_hash_followed_by_registryKey_expression_python_constant(): def test_hash_followed_by_registryKey_expression_python_constant():
hash_exp = stix2.EqualityComparisonExpression("file:hashes.MD5", hash_exp = stix2.EqualityComparisonExpression(
stix2.HashConstant("79054025255fb1a26e4bc422aef54eb4", "MD5")) "file:hashes.MD5",
stix2.HashConstant("79054025255fb1a26e4bc422aef54eb4", "MD5"),
)
o_exp1 = stix2.ObservationExpression(hash_exp) o_exp1 = stix2.ObservationExpression(hash_exp)
reg_exp = stix2.EqualityComparisonExpression(stix2.ObjectPath("windows-registry-key", ["key"]), reg_exp = stix2.EqualityComparisonExpression(
stix2.StringConstant("HKEY_LOCAL_MACHINE\\foo\\bar")) stix2.ObjectPath("windows-registry-key", ["key"]),
stix2.StringConstant("HKEY_LOCAL_MACHINE\\foo\\bar"),
)
o_exp2 = stix2.ObservationExpression(reg_exp) o_exp2 = stix2.ObservationExpression(reg_exp)
fb_exp = stix2.FollowedByObservationExpression([o_exp1, o_exp2]) fb_exp = stix2.FollowedByObservationExpression([o_exp1, o_exp2])
para_exp = stix2.ParentheticalExpression(fb_exp) para_exp = stix2.ParentheticalExpression(fb_exp)
@ -47,11 +65,15 @@ def test_hash_followed_by_registryKey_expression_python_constant():
def test_hash_followed_by_registryKey_expression(): def test_hash_followed_by_registryKey_expression():
hash_exp = stix2.EqualityComparisonExpression("file:hashes.MD5", hash_exp = stix2.EqualityComparisonExpression(
stix2.HashConstant("79054025255fb1a26e4bc422aef54eb4", "MD5")) "file:hashes.MD5",
stix2.HashConstant("79054025255fb1a26e4bc422aef54eb4", "MD5"),
)
o_exp1 = stix2.ObservationExpression(hash_exp) o_exp1 = stix2.ObservationExpression(hash_exp)
reg_exp = stix2.EqualityComparisonExpression(stix2.ObjectPath("windows-registry-key", ["key"]), reg_exp = stix2.EqualityComparisonExpression(
stix2.StringConstant("HKEY_LOCAL_MACHINE\\foo\\bar")) stix2.ObjectPath("windows-registry-key", ["key"]),
stix2.StringConstant("HKEY_LOCAL_MACHINE\\foo\\bar"),
)
o_exp2 = stix2.ObservationExpression(reg_exp) o_exp2 = stix2.ObservationExpression(reg_exp)
fb_exp = stix2.FollowedByObservationExpression([o_exp1, o_exp2]) fb_exp = stix2.FollowedByObservationExpression([o_exp1, o_exp2])
para_exp = stix2.ParentheticalExpression(fb_exp) para_exp = stix2.ParentheticalExpression(fb_exp)
@ -61,32 +83,45 @@ def test_hash_followed_by_registryKey_expression():
def test_file_observable_expression(): def test_file_observable_expression():
exp1 = stix2.EqualityComparisonExpression("file:hashes.'SHA-256'", exp1 = stix2.EqualityComparisonExpression(
stix2.HashConstant( "file:hashes.'SHA-256'",
"aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f", stix2.HashConstant(
'SHA-256')) "aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f",
'SHA-256',
),
)
exp2 = stix2.EqualityComparisonExpression("file:mime_type", stix2.StringConstant("application/x-pdf")) exp2 = stix2.EqualityComparisonExpression("file:mime_type", stix2.StringConstant("application/x-pdf"))
bool_exp = stix2.AndBooleanExpression([exp1, exp2]) bool_exp = stix2.AndBooleanExpression([exp1, exp2])
exp = stix2.ObservationExpression(bool_exp) exp = stix2.ObservationExpression(bool_exp)
assert str(exp) == "[file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f' AND file:mime_type = 'application/x-pdf']" # noqa assert str(exp) == "[file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f' AND file:mime_type = 'application/x-pdf']" # noqa
@pytest.mark.parametrize("observation_class, op", [ @pytest.mark.parametrize(
(stix2.AndObservationExpression, 'AND'), "observation_class, op", [
(stix2.OrObservationExpression, 'OR'), (stix2.AndObservationExpression, 'AND'),
]) (stix2.OrObservationExpression, 'OR'),
],
)
def test_multiple_file_observable_expression(observation_class, op): def test_multiple_file_observable_expression(observation_class, op):
exp1 = stix2.EqualityComparisonExpression("file:hashes.'SHA-256'", exp1 = stix2.EqualityComparisonExpression(
stix2.HashConstant( "file:hashes.'SHA-256'",
"bf07a7fbb825fc0aae7bf4a1177b2b31fcf8a3feeaf7092761e18c859ee52a9c", stix2.HashConstant(
'SHA-256')) "bf07a7fbb825fc0aae7bf4a1177b2b31fcf8a3feeaf7092761e18c859ee52a9c",
exp2 = stix2.EqualityComparisonExpression("file:hashes.MD5", 'SHA-256',
stix2.HashConstant("cead3f77f6cda6ec00f57d76c9a6879f", "MD5")) ),
)
exp2 = stix2.EqualityComparisonExpression(
"file:hashes.MD5",
stix2.HashConstant("cead3f77f6cda6ec00f57d76c9a6879f", "MD5"),
)
bool1_exp = stix2.OrBooleanExpression([exp1, exp2]) bool1_exp = stix2.OrBooleanExpression([exp1, exp2])
exp3 = stix2.EqualityComparisonExpression("file:hashes.'SHA-256'", exp3 = stix2.EqualityComparisonExpression(
stix2.HashConstant( "file:hashes.'SHA-256'",
"aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f", stix2.HashConstant(
'SHA-256')) "aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f",
'SHA-256',
),
)
op1_exp = stix2.ObservationExpression(bool1_exp) op1_exp = stix2.ObservationExpression(bool1_exp)
op2_exp = stix2.ObservationExpression(exp3) op2_exp = stix2.ObservationExpression(exp3)
exp = observation_class([op1_exp, op2_exp]) exp = observation_class([op1_exp, op2_exp])
@ -96,111 +131,177 @@ def test_multiple_file_observable_expression(observation_class, op):
def test_root_types(): def test_root_types():
ast = stix2.ObservationExpression( ast = stix2.ObservationExpression(
stix2.AndBooleanExpression( stix2.AndBooleanExpression(
[stix2.ParentheticalExpression( [
stix2.OrBooleanExpression([ stix2.ParentheticalExpression(
stix2.EqualityComparisonExpression("a:b", stix2.StringConstant("1")), stix2.OrBooleanExpression([
stix2.EqualityComparisonExpression("b:c", stix2.StringConstant("2"))])), stix2.EqualityComparisonExpression("a:b", stix2.StringConstant("1")),
stix2.EqualityComparisonExpression(u"b:d", stix2.StringConstant("3"))])) stix2.EqualityComparisonExpression("b:c", stix2.StringConstant("2")),
]),
),
stix2.EqualityComparisonExpression(u"b:d", stix2.StringConstant("3")),
],
),
)
assert str(ast) == "[(a:b = '1' OR b:c = '2') AND b:d = '3']" assert str(ast) == "[(a:b = '1' OR b:c = '2') AND b:d = '3']"
def test_artifact_payload(): def test_artifact_payload():
exp1 = stix2.EqualityComparisonExpression("artifact:mime_type", exp1 = stix2.EqualityComparisonExpression(
"application/vnd.tcpdump.pcap") "artifact:mime_type",
exp2 = stix2.MatchesComparisonExpression("artifact:payload_bin", "application/vnd.tcpdump.pcap",
stix2.StringConstant("\\xd4\\xc3\\xb2\\xa1\\x02\\x00\\x04\\x00")) )
exp2 = stix2.MatchesComparisonExpression(
"artifact:payload_bin",
stix2.StringConstant("\\xd4\\xc3\\xb2\\xa1\\x02\\x00\\x04\\x00"),
)
and_exp = stix2.AndBooleanExpression([exp1, exp2]) and_exp = stix2.AndBooleanExpression([exp1, exp2])
exp = stix2.ObservationExpression(and_exp) exp = stix2.ObservationExpression(and_exp)
assert str(exp) == "[artifact:mime_type = 'application/vnd.tcpdump.pcap' AND artifact:payload_bin MATCHES '\\\\xd4\\\\xc3\\\\xb2\\\\xa1\\\\x02\\\\x00\\\\x04\\\\x00']" # noqa assert str(exp) == "[artifact:mime_type = 'application/vnd.tcpdump.pcap' AND artifact:payload_bin MATCHES '\\\\xd4\\\\xc3\\\\xb2\\\\xa1\\\\x02\\\\x00\\\\x04\\\\x00']" # noqa
def test_greater_than_python_constant(): def test_greater_than_python_constant():
exp1 = stix2.GreaterThanComparisonExpression("file:extensions.windows-pebinary-ext.sections[*].entropy", exp1 = stix2.GreaterThanComparisonExpression(
7.0) "file:extensions.windows-pebinary-ext.sections[*].entropy",
7.0,
)
exp = stix2.ObservationExpression(exp1) exp = stix2.ObservationExpression(exp1)
assert str(exp) == "[file:extensions.windows-pebinary-ext.sections[*].entropy > 7.0]" assert str(exp) == "[file:extensions.windows-pebinary-ext.sections[*].entropy > 7.0]"
def test_greater_than(): def test_greater_than():
exp1 = stix2.GreaterThanComparisonExpression("file:extensions.windows-pebinary-ext.sections[*].entropy", exp1 = stix2.GreaterThanComparisonExpression(
stix2.FloatConstant(7.0)) "file:extensions.windows-pebinary-ext.sections[*].entropy",
stix2.FloatConstant(7.0),
)
exp = stix2.ObservationExpression(exp1) exp = stix2.ObservationExpression(exp1)
assert str(exp) == "[file:extensions.windows-pebinary-ext.sections[*].entropy > 7.0]" assert str(exp) == "[file:extensions.windows-pebinary-ext.sections[*].entropy > 7.0]"
def test_less_than(): def test_less_than():
exp = stix2.LessThanComparisonExpression("file:size", exp = stix2.LessThanComparisonExpression(
1024) "file:size",
1024,
)
assert str(exp) == "file:size < 1024" assert str(exp) == "file:size < 1024"
def test_greater_than_or_equal(): def test_greater_than_or_equal():
exp = stix2.GreaterThanEqualComparisonExpression("file:size", exp = stix2.GreaterThanEqualComparisonExpression(
1024) "file:size",
1024,
)
assert str(exp) == "file:size >= 1024" assert str(exp) == "file:size >= 1024"
def test_less_than_or_equal(): def test_less_than_or_equal():
exp = stix2.LessThanEqualComparisonExpression("file:size", exp = stix2.LessThanEqualComparisonExpression(
1024) "file:size",
1024,
)
assert str(exp) == "file:size <= 1024" assert str(exp) == "file:size <= 1024"
def test_not(): def test_not():
exp = stix2.LessThanComparisonExpression("file:size", exp = stix2.LessThanComparisonExpression(
1024, "file:size",
negated=True) 1024,
negated=True,
)
assert str(exp) == "file:size NOT < 1024" assert str(exp) == "file:size NOT < 1024"
def test_and_observable_expression(): def test_and_observable_expression():
exp1 = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("user-account:account_type", exp1 = stix2.AndBooleanExpression([
"unix"), stix2.EqualityComparisonExpression(
stix2.EqualityComparisonExpression("user-account:user_id", "user-account:account_type",
stix2.StringConstant("1007")), "unix",
stix2.EqualityComparisonExpression("user-account:account_login", ),
"Peter")]) stix2.EqualityComparisonExpression(
exp2 = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("user-account:account_type", "user-account:user_id",
"unix"), stix2.StringConstant("1007"),
stix2.EqualityComparisonExpression("user-account:user_id", ),
stix2.StringConstant("1008")), stix2.EqualityComparisonExpression(
stix2.EqualityComparisonExpression("user-account:account_login", "user-account:account_login",
"Paul")]) "Peter",
exp3 = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("user-account:account_type", ),
"unix"), ])
stix2.EqualityComparisonExpression("user-account:user_id", exp2 = stix2.AndBooleanExpression([
stix2.StringConstant("1009")), stix2.EqualityComparisonExpression(
stix2.EqualityComparisonExpression("user-account:account_login", "user-account:account_type",
"Mary")]) "unix",
exp = stix2.AndObservationExpression([stix2.ObservationExpression(exp1), ),
stix2.ObservationExpression(exp2), stix2.EqualityComparisonExpression(
stix2.ObservationExpression(exp3)]) "user-account:user_id",
stix2.StringConstant("1008"),
),
stix2.EqualityComparisonExpression(
"user-account:account_login",
"Paul",
),
])
exp3 = stix2.AndBooleanExpression([
stix2.EqualityComparisonExpression(
"user-account:account_type",
"unix",
),
stix2.EqualityComparisonExpression(
"user-account:user_id",
stix2.StringConstant("1009"),
),
stix2.EqualityComparisonExpression(
"user-account:account_login",
"Mary",
),
])
exp = stix2.AndObservationExpression([
stix2.ObservationExpression(exp1),
stix2.ObservationExpression(exp2),
stix2.ObservationExpression(exp3),
])
assert str(exp) == "[user-account:account_type = 'unix' AND user-account:user_id = '1007' AND user-account:account_login = 'Peter'] AND [user-account:account_type = 'unix' AND user-account:user_id = '1008' AND user-account:account_login = 'Paul'] AND [user-account:account_type = 'unix' AND user-account:user_id = '1009' AND user-account:account_login = 'Mary']" # noqa assert str(exp) == "[user-account:account_type = 'unix' AND user-account:user_id = '1007' AND user-account:account_login = 'Peter'] AND [user-account:account_type = 'unix' AND user-account:user_id = '1008' AND user-account:account_login = 'Paul'] AND [user-account:account_type = 'unix' AND user-account:user_id = '1009' AND user-account:account_login = 'Mary']" # noqa
def test_invalid_and_observable_expression(): def test_invalid_and_observable_expression():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("user-account:display_name", stix2.AndBooleanExpression([
"admin"), stix2.EqualityComparisonExpression(
stix2.EqualityComparisonExpression("email-addr:display_name", "user-account:display_name",
stix2.StringConstant("admin"))]) "admin",
),
stix2.EqualityComparisonExpression(
"email-addr:display_name",
stix2.StringConstant("admin"),
),
])
assert "All operands to an 'AND' expression must have the same object type" in str(excinfo) assert "All operands to an 'AND' expression must have the same object type" in str(excinfo)
def test_hex(): def test_hex():
exp_and = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("file:mime_type", exp_and = stix2.AndBooleanExpression([
"image/bmp"), stix2.EqualityComparisonExpression(
stix2.EqualityComparisonExpression("file:magic_number_hex", "file:mime_type",
stix2.HexConstant("ffd8"))]) "image/bmp",
),
stix2.EqualityComparisonExpression(
"file:magic_number_hex",
stix2.HexConstant("ffd8"),
),
])
exp = stix2.ObservationExpression(exp_and) exp = stix2.ObservationExpression(exp_and)
assert str(exp) == "[file:mime_type = 'image/bmp' AND file:magic_number_hex = h'ffd8']" assert str(exp) == "[file:mime_type = 'image/bmp' AND file:magic_number_hex = h'ffd8']"
def test_multiple_qualifiers(): def test_multiple_qualifiers():
exp_and = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("network-traffic:dst_ref.type", exp_and = stix2.AndBooleanExpression([
"domain-name"), stix2.EqualityComparisonExpression(
stix2.EqualityComparisonExpression("network-traffic:dst_ref.value", "network-traffic:dst_ref.type",
"example.com")]) "domain-name",
),
stix2.EqualityComparisonExpression(
"network-traffic:dst_ref.value",
"example.com",
),
])
exp_ob = stix2.ObservationExpression(exp_and) exp_ob = stix2.ObservationExpression(exp_and)
qual_rep = stix2.RepeatQualifier(5) qual_rep = stix2.RepeatQualifier(5)
qual_within = stix2.WithinQualifier(stix2.IntegerConstant(1800)) qual_within = stix2.WithinQualifier(stix2.IntegerConstant(1800))
@ -209,8 +310,10 @@ def test_multiple_qualifiers():
def test_set_op(): def test_set_op():
exp = stix2.ObservationExpression(stix2.IsSubsetComparisonExpression("network-traffic:dst_ref.value", exp = stix2.ObservationExpression(stix2.IsSubsetComparisonExpression(
"2001:0db8:dead:beef:0000:0000:0000:0000/64")) "network-traffic:dst_ref.value",
"2001:0db8:dead:beef:0000:0000:0000:0000/64",
))
assert str(exp) == "[network-traffic:dst_ref.value ISSUBSET '2001:0db8:dead:beef:0000:0000:0000:0000/64']" assert str(exp) == "[network-traffic:dst_ref.value ISSUBSET '2001:0db8:dead:beef:0000:0000:0000:0000/64']"
@ -220,35 +323,45 @@ def test_timestamp():
def test_boolean(): def test_boolean():
exp = stix2.EqualityComparisonExpression("email-message:is_multipart", exp = stix2.EqualityComparisonExpression(
True) "email-message:is_multipart",
True,
)
assert str(exp) == "email-message:is_multipart = true" assert str(exp) == "email-message:is_multipart = true"
def test_binary(): def test_binary():
const = stix2.BinaryConstant("dGhpcyBpcyBhIHRlc3Q=") const = stix2.BinaryConstant("dGhpcyBpcyBhIHRlc3Q=")
exp = stix2.EqualityComparisonExpression("artifact:payload_bin", exp = stix2.EqualityComparisonExpression(
const) "artifact:payload_bin",
const,
)
assert str(exp) == "artifact:payload_bin = b'dGhpcyBpcyBhIHRlc3Q='" assert str(exp) == "artifact:payload_bin = b'dGhpcyBpcyBhIHRlc3Q='"
def test_list(): def test_list():
exp = stix2.InComparisonExpression("process:name", exp = stix2.InComparisonExpression(
['proccy', 'proximus', 'badproc']) "process:name",
['proccy', 'proximus', 'badproc'],
)
assert str(exp) == "process:name IN ('proccy', 'proximus', 'badproc')" assert str(exp) == "process:name IN ('proccy', 'proximus', 'badproc')"
def test_list2(): def test_list2():
# alternate way to construct an "IN" Comparison Expression # alternate way to construct an "IN" Comparison Expression
exp = stix2.EqualityComparisonExpression("process:name", exp = stix2.EqualityComparisonExpression(
['proccy', 'proximus', 'badproc']) "process:name",
['proccy', 'proximus', 'badproc'],
)
assert str(exp) == "process:name IN ('proccy', 'proximus', 'badproc')" assert str(exp) == "process:name IN ('proccy', 'proximus', 'badproc')"
def test_invalid_constant_type(): def test_invalid_constant_type():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
stix2.EqualityComparisonExpression("artifact:payload_bin", stix2.EqualityComparisonExpression(
{'foo': 'bar'}) "artifact:payload_bin",
{'foo': 'bar'},
)
assert 'Unable to create a constant' in str(excinfo) assert 'Unable to create a constant' in str(excinfo)
@ -270,20 +383,22 @@ def test_invalid_float_constant():
assert 'must be a float' in str(excinfo) assert 'must be a float' in str(excinfo)
@pytest.mark.parametrize("data, result", [ @pytest.mark.parametrize(
(True, True), "data, result", [
(False, False), (True, True),
('True', True), (False, False),
('False', False), ('True', True),
('true', True), ('False', False),
('false', False), ('true', True),
('t', True), ('false', False),
('f', False), ('t', True),
('T', True), ('f', False),
('F', False), ('T', True),
(1, True), ('F', False),
(0, False), (1, True),
]) (0, False),
],
)
def test_boolean_constant(data, result): def test_boolean_constant(data, result):
boolean = stix2.BooleanConstant(data) boolean = stix2.BooleanConstant(data)
assert boolean.value == result assert boolean.value == result
@ -295,10 +410,12 @@ def test_invalid_boolean_constant():
assert 'must be a boolean' in str(excinfo) assert 'must be a boolean' in str(excinfo)
@pytest.mark.parametrize("hashtype, data", [ @pytest.mark.parametrize(
('MD5', 'zzz'), "hashtype, data", [
('ssdeep', 'zzz=='), ('MD5', 'zzz'),
]) ('ssdeep', 'zzz=='),
],
)
def test_invalid_hash_constant(hashtype, data): def test_invalid_hash_constant(hashtype, data):
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
stix2.HashConstant(data, hashtype) stix2.HashConstant(data, hashtype)
@ -318,20 +435,26 @@ def test_invalid_binary_constant():
def test_escape_quotes_and_backslashes(): def test_escape_quotes_and_backslashes():
exp = stix2.MatchesComparisonExpression("file:name", exp = stix2.MatchesComparisonExpression(
"^Final Report.+\\.exe$") "file:name",
"^Final Report.+\\.exe$",
)
assert str(exp) == "file:name MATCHES '^Final Report.+\\\\.exe$'" assert str(exp) == "file:name MATCHES '^Final Report.+\\\\.exe$'"
def test_like(): def test_like():
exp = stix2.LikeComparisonExpression("directory:path", exp = stix2.LikeComparisonExpression(
"C:\\Windows\\%\\foo") "directory:path",
"C:\\Windows\\%\\foo",
)
assert str(exp) == "directory:path LIKE 'C:\\\\Windows\\\\%\\\\foo'" assert str(exp) == "directory:path LIKE 'C:\\\\Windows\\\\%\\\\foo'"
def test_issuperset(): def test_issuperset():
exp = stix2.IsSupersetComparisonExpression("ipv4-addr:value", exp = stix2.IsSupersetComparisonExpression(
"198.51.100.0/24") "ipv4-addr:value",
"198.51.100.0/24",
)
assert str(exp) == "ipv4-addr:value ISSUPERSET '198.51.100.0/24'" assert str(exp) == "ipv4-addr:value ISSUPERSET '198.51.100.0/24'"
@ -353,24 +476,32 @@ def test_invalid_within_qualifier():
def test_startstop_qualifier(): def test_startstop_qualifier():
qual = stix2.StartStopQualifier(stix2.TimestampConstant('2016-06-01T00:00:00Z'), qual = stix2.StartStopQualifier(
datetime.datetime(2017, 3, 12, 8, 30, 0)) stix2.TimestampConstant('2016-06-01T00:00:00Z'),
datetime.datetime(2017, 3, 12, 8, 30, 0),
)
assert str(qual) == "START t'2016-06-01T00:00:00Z' STOP t'2017-03-12T08:30:00Z'" assert str(qual) == "START t'2016-06-01T00:00:00Z' STOP t'2017-03-12T08:30:00Z'"
qual2 = stix2.StartStopQualifier(datetime.date(2016, 6, 1), qual2 = stix2.StartStopQualifier(
stix2.TimestampConstant('2016-07-01T00:00:00Z')) datetime.date(2016, 6, 1),
stix2.TimestampConstant('2016-07-01T00:00:00Z'),
)
assert str(qual2) == "START t'2016-06-01T00:00:00Z' STOP t'2016-07-01T00:00:00Z'" assert str(qual2) == "START t'2016-06-01T00:00:00Z' STOP t'2016-07-01T00:00:00Z'"
def test_invalid_startstop_qualifier(): def test_invalid_startstop_qualifier():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
stix2.StartStopQualifier('foo', stix2.StartStopQualifier(
stix2.TimestampConstant('2016-06-01T00:00:00Z')) 'foo',
stix2.TimestampConstant('2016-06-01T00:00:00Z'),
)
assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo) assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo)
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
stix2.StartStopQualifier(datetime.date(2016, 6, 1), stix2.StartStopQualifier(
'foo') datetime.date(2016, 6, 1),
'foo',
)
assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo) assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo)

View File

@ -11,7 +11,7 @@ def test_pickling():
id="identity--d66cb89d-5228-4983-958c-fa84ef75c88c", id="identity--d66cb89d-5228-4983-958c-fa84ef75c88c",
name="alice", name="alice",
description="this is a pickle test", description="this is a pickle test",
identity_class="some_class" identity_class="some_class",
) )
pickle.loads(pickle.dumps(identity)) pickle.loads(pickle.dumps(identity))

View File

@ -4,14 +4,13 @@ import pytest
import stix2 import stix2
from stix2.exceptions import AtLeastOnePropertyError, DictionaryKeyError from stix2.exceptions import AtLeastOnePropertyError, DictionaryKeyError
from stix2.properties import (ERROR_INVALID_ID, BinaryProperty, from stix2.properties import (
BooleanProperty, DictionaryProperty, ERROR_INVALID_ID, BinaryProperty, BooleanProperty, DictionaryProperty,
EmbeddedObjectProperty, EnumProperty, EmbeddedObjectProperty, EnumProperty, ExtensionsProperty, FloatProperty,
ExtensionsProperty, FloatProperty, HashesProperty, HexProperty, IDProperty, IntegerProperty, ListProperty,
HashesProperty, HexProperty, IDProperty, Property, ReferenceProperty, StringProperty, TimestampProperty,
IntegerProperty, ListProperty, Property, TypeProperty,
ReferenceProperty, StringProperty, )
TimestampProperty, TypeProperty)
from . import constants from . import constants
@ -93,10 +92,12 @@ ID_PROP = IDProperty('my-type')
MY_ID = 'my-type--232c9d3f-49fc-4440-bb01-607f638778e7' MY_ID = 'my-type--232c9d3f-49fc-4440-bb01-607f638778e7'
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
MY_ID, "value", [
'my-type--00000000-0000-4000-8000-000000000000', MY_ID,
]) 'my-type--00000000-0000-4000-8000-000000000000',
],
)
def test_id_property_valid(value): def test_id_property_valid(value):
assert ID_PROP.clean(value) == value assert ID_PROP.clean(value) == value
@ -134,14 +135,16 @@ def test_id_property_wrong_type():
assert str(excinfo.value) == "must start with 'my-type--'." assert str(excinfo.value) == "must start with 'my-type--'."
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
'my-type--foo', "value", [
# Not a v4 UUID 'my-type--foo',
'my-type--00000000-0000-0000-0000-000000000000', # Not a v4 UUID
'my-type--' + str(uuid.uuid1()), 'my-type--00000000-0000-0000-0000-000000000000',
'my-type--' + str(uuid.uuid3(uuid.NAMESPACE_DNS, "example.org")), 'my-type--' + str(uuid.uuid1()),
'my-type--' + str(uuid.uuid5(uuid.NAMESPACE_DNS, "example.org")), 'my-type--' + str(uuid.uuid3(uuid.NAMESPACE_DNS, "example.org")),
]) 'my-type--' + str(uuid.uuid5(uuid.NAMESPACE_DNS, "example.org")),
],
)
def test_id_property_not_a_valid_hex_uuid(value): def test_id_property_not_a_valid_hex_uuid(value):
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
ID_PROP.clean(value) ID_PROP.clean(value)
@ -153,77 +156,89 @@ def test_id_property_default():
assert ID_PROP.clean(default) == default assert ID_PROP.clean(default) == default
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
2, "value", [
-1, 2,
3.14, -1,
False, 3.14,
]) False,
],
)
def test_integer_property_valid(value): def test_integer_property_valid(value):
int_prop = IntegerProperty() int_prop = IntegerProperty()
assert int_prop.clean(value) is not None assert int_prop.clean(value) is not None
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
"something", "value", [
StringProperty(), "something",
]) StringProperty(),
],
)
def test_integer_property_invalid(value): def test_integer_property_invalid(value):
int_prop = IntegerProperty() int_prop = IntegerProperty()
with pytest.raises(ValueError): with pytest.raises(ValueError):
int_prop.clean(value) int_prop.clean(value)
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
2, "value", [
-1, 2,
3.14, -1,
False, 3.14,
]) False,
],
)
def test_float_property_valid(value): def test_float_property_valid(value):
int_prop = FloatProperty() int_prop = FloatProperty()
assert int_prop.clean(value) is not None assert int_prop.clean(value) is not None
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
"something", "value", [
StringProperty(), "something",
]) StringProperty(),
],
)
def test_float_property_invalid(value): def test_float_property_invalid(value):
int_prop = FloatProperty() int_prop = FloatProperty()
with pytest.raises(ValueError): with pytest.raises(ValueError):
int_prop.clean(value) int_prop.clean(value)
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
True, "value", [
False, True,
'True', False,
'False', 'True',
'true', 'False',
'false', 'true',
'TRUE', 'false',
'FALSE', 'TRUE',
'T', 'FALSE',
'F', 'T',
't', 'F',
'f', 't',
1, 'f',
0, 1,
]) 0,
],
)
def test_boolean_property_valid(value): def test_boolean_property_valid(value):
bool_prop = BooleanProperty() bool_prop = BooleanProperty()
assert bool_prop.clean(value) is not None assert bool_prop.clean(value) is not None
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
'abc', "value", [
['false'], 'abc',
{'true': 'true'}, ['false'],
2, {'true': 'true'},
-1, 2,
]) -1,
],
)
def test_boolean_property_invalid(value): def test_boolean_property_invalid(value):
bool_prop = BooleanProperty() bool_prop = BooleanProperty()
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -242,11 +257,13 @@ def test_reference_property():
ref_prop.clean("my-type--00000000-0000-0000-0000-000000000000") ref_prop.clean("my-type--00000000-0000-0000-0000-000000000000")
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
'2017-01-01T12:34:56Z', "value", [
'2017-01-01 12:34:56', '2017-01-01T12:34:56Z',
'Jan 1 2017 12:34:56', '2017-01-01 12:34:56',
]) 'Jan 1 2017 12:34:56',
],
)
def test_timestamp_property_valid(value): def test_timestamp_property_valid(value):
ts_prop = TimestampProperty() ts_prop = TimestampProperty()
assert ts_prop.clean(value) == constants.FAKE_TIME assert ts_prop.clean(value) == constants.FAKE_TIME
@ -276,18 +293,22 @@ def test_hex_property():
hex_prop.clean("foobar") hex_prop.clean("foobar")
@pytest.mark.parametrize("d", [ @pytest.mark.parametrize(
{'description': 'something'}, "d", [
[('abc', 1), ('bcd', 2), ('cde', 3)], {'description': 'something'},
]) [('abc', 1), ('bcd', 2), ('cde', 3)],
],
)
def test_dictionary_property_valid(d): def test_dictionary_property_valid(d):
dict_prop = DictionaryProperty(spec_version='2.1') dict_prop = DictionaryProperty(spec_version='2.1')
assert dict_prop.clean(d) assert dict_prop.clean(d)
@pytest.mark.parametrize("d", [ @pytest.mark.parametrize(
[{'a': 'something'}, "Invalid dictionary key a: (shorter than 3 characters)."], "d", [
]) [{'a': 'something'}, "Invalid dictionary key a: (shorter than 3 characters)."],
],
)
def test_dictionary_no_longer_raises(d): def test_dictionary_no_longer_raises(d):
dict_prop = DictionaryProperty(spec_version='2.1') dict_prop = DictionaryProperty(spec_version='2.1')
@ -297,15 +318,21 @@ def test_dictionary_no_longer_raises(d):
pytest.fail("Unexpected DictionaryKeyError...") pytest.fail("Unexpected DictionaryKeyError...")
@pytest.mark.parametrize("d", [ @pytest.mark.parametrize(
[{'a'*300: 'something'}, "Invalid dictionary key aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "d", [
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" [
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" {'a'*300: 'something'}, "Invalid dictionary key aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaa: (longer than 250 characters)."], "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
[{'Hey!': 'something'}, "Invalid dictionary key Hey!: (contains characters other than lowercase a-z, " "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"uppercase A-Z, numerals 0-9, hyphen (-), or underscore (_))."], "aaaaaaaaaaaaaaaaaaaaaaa: (longer than 250 characters).",
]) ],
[
{'Hey!': 'something'}, "Invalid dictionary key Hey!: (contains characters other than lowercase a-z, "
"uppercase A-Z, numerals 0-9, hyphen (-), or underscore (_)).",
],
],
)
def test_dictionary_property_invalid_key(d): def test_dictionary_property_invalid_key(d):
dict_prop = DictionaryProperty(spec_version='2.1') dict_prop = DictionaryProperty(spec_version='2.1')
@ -315,18 +342,20 @@ def test_dictionary_property_invalid_key(d):
assert str(excinfo.value) == d[1] assert str(excinfo.value) == d[1]
@pytest.mark.parametrize("d", [ @pytest.mark.parametrize(
({}, "The dictionary property must contain a non-empty dictionary"), "d", [
# TODO: This error message could be made more helpful. The error is caused ({}, "The dictionary property must contain a non-empty dictionary"),
# because `json.loads()` doesn't like the *single* quotes around the key # TODO: This error message could be made more helpful. The error is caused
# name, even though they are valid in a Python dictionary. While technically # because `json.loads()` doesn't like the *single* quotes around the key
# accurate (a string is not a dictionary), if we want to be able to load # name, even though they are valid in a Python dictionary. While technically
# string-encoded "dictionaries" that are, we need a better error message # accurate (a string is not a dictionary), if we want to be able to load
# or an alternative to `json.loads()` ... and preferably *not* `eval()`. :-) # string-encoded "dictionaries" that are, we need a better error message
# Changing the following to `'{"description": "something"}'` does not cause # or an alternative to `json.loads()` ... and preferably *not* `eval()`. :-)
# any ValueError to be raised. # Changing the following to `'{"description": "something"}'` does not cause
("{'description': 'something'}", "The dictionary property must contain a dictionary"), # any ValueError to be raised.
]) ("{'description': 'something'}", "The dictionary property must contain a dictionary"),
],
)
def test_dictionary_property_invalid(d): def test_dictionary_property_invalid(d):
dict_prop = DictionaryProperty(spec_version='2.1') dict_prop = DictionaryProperty(spec_version='2.1')
@ -336,9 +365,11 @@ def test_dictionary_property_invalid(d):
def test_property_list_of_dictionary(): def test_property_list_of_dictionary():
@stix2.v21.CustomObject('x-new-obj', [ @stix2.v21.CustomObject(
('property1', ListProperty(DictionaryProperty(spec_version='2.1'), required=True)), 'x-new-obj', [
]) ('property1', ListProperty(DictionaryProperty(spec_version='2.1'), required=True)),
],
)
class NewObj(): class NewObj():
pass pass
@ -346,19 +377,23 @@ def test_property_list_of_dictionary():
assert test_obj.property1[0]['foo'] == 'bar' assert test_obj.property1[0]['foo'] == 'bar'
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
{"sha256": "6db12788c37247f2316052e142f42f4b259d6561751e5f401a1ae2a6df9c674b"}, "value", [
[('MD5', '2dfb1bcc980200c6706feee399d41b3f'), ('RIPEMD-160', 'b3a8cd8a27c90af79b3c81754f267780f443dfef')], {"sha256": "6db12788c37247f2316052e142f42f4b259d6561751e5f401a1ae2a6df9c674b"},
]) [('MD5', '2dfb1bcc980200c6706feee399d41b3f'), ('RIPEMD-160', 'b3a8cd8a27c90af79b3c81754f267780f443dfef')],
],
)
def test_hashes_property_valid(value): def test_hashes_property_valid(value):
hash_prop = HashesProperty() hash_prop = HashesProperty()
assert hash_prop.clean(value) assert hash_prop.clean(value)
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
{"MD5": "a"}, "value", [
{"SHA-256": "2dfb1bcc980200c6706feee399d41b3f"}, {"MD5": "a"},
]) {"SHA-256": "2dfb1bcc980200c6706feee399d41b3f"},
],
)
def test_hashes_property_invalid(value): def test_hashes_property_invalid(value):
hash_prop = HashesProperty() hash_prop = HashesProperty()
@ -371,7 +406,7 @@ def test_embedded_property():
mime = stix2.v21.EmailMIMEComponent( mime = stix2.v21.EmailMIMEComponent(
content_type="text/plain; charset=utf-8", content_type="text/plain; charset=utf-8",
content_disposition="inline", content_disposition="inline",
body="Cats are funny!" body="Cats are funny!",
) )
assert emb_prop.clean(mime) assert emb_prop.clean(mime)
@ -379,11 +414,13 @@ def test_embedded_property():
emb_prop.clean("string") emb_prop.clean("string")
@pytest.mark.parametrize("value", [ @pytest.mark.parametrize(
['a', 'b', 'c'], "value", [
('a', 'b', 'c'), ['a', 'b', 'c'],
'b', ('a', 'b', 'c'),
]) 'b',
],
)
def test_enum_property_valid(value): def test_enum_property_valid(value):
enum_prop = EnumProperty(value) enum_prop = EnumProperty(value)
assert enum_prop.clean('b') assert enum_prop.clean('b')
@ -399,17 +436,19 @@ def test_extension_property_valid():
ext_prop = ExtensionsProperty(spec_version='2.1', enclosing_type='file') ext_prop = ExtensionsProperty(spec_version='2.1', enclosing_type='file')
assert ext_prop({ assert ext_prop({
'windows-pebinary-ext': { 'windows-pebinary-ext': {
'pe_type': 'exe' 'pe_type': 'exe',
}, },
}) })
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
1, "data", [
{'foobar-ext': { 1,
'pe_type': 'exe' {'foobar-ext': {
}}, 'pe_type': 'exe',
]) }},
],
)
def test_extension_property_invalid(data): def test_extension_property_invalid(data):
ext_prop = ExtensionsProperty(spec_version='2.1', enclosing_type='file') ext_prop = ExtensionsProperty(spec_version='2.1', enclosing_type='file')
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -419,10 +458,12 @@ def test_extension_property_invalid(data):
def test_extension_property_invalid_type(): def test_extension_property_invalid_type():
ext_prop = ExtensionsProperty(spec_version='2.1', enclosing_type='indicator') ext_prop = ExtensionsProperty(spec_version='2.1', enclosing_type='indicator')
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
ext_prop.clean({ ext_prop.clean(
'windows-pebinary-ext': { {
'pe_type': 'exe' 'windows-pebinary-ext': {
}} 'pe_type': 'exe',
},
},
) )
assert 'no extensions defined' in str(excinfo.value) assert 'no extensions defined' in str(excinfo.value)

View File

@ -5,8 +5,9 @@ import pytz
import stix2 import stix2
from .constants import (FAKE_TIME, INDICATOR_ID, MALWARE_ID, RELATIONSHIP_ID, from .constants import (
RELATIONSHIP_KWARGS) FAKE_TIME, INDICATOR_ID, MALWARE_ID, RELATIONSHIP_ID, RELATIONSHIP_KWARGS,
)
EXPECTED_RELATIONSHIP = """{ EXPECTED_RELATIONSHIP = """{
"type": "relationship", "type": "relationship",
@ -94,7 +95,7 @@ def test_relationship_required_properties_target_ref():
with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo: with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo:
stix2.v21.Relationship( stix2.v21.Relationship(
relationship_type='indicates', relationship_type='indicates',
source_ref=INDICATOR_ID source_ref=INDICATOR_ID,
) )
assert excinfo.value.cls == stix2.v21.Relationship assert excinfo.value.cls == stix2.v21.Relationship
@ -139,19 +140,21 @@ def test_create_relationship_with_positional_args(indicator, malware):
assert rel.id == 'relationship--00000000-0000-4000-8000-000000000005' assert rel.id == 'relationship--00000000-0000-4000-8000-000000000005'
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED_RELATIONSHIP, "data", [
{ EXPECTED_RELATIONSHIP,
"created": "2016-04-06T20:06:37Z", {
"id": "relationship--df7c87eb-75d2-4948-af81-9d49d246f301", "created": "2016-04-06T20:06:37Z",
"modified": "2016-04-06T20:06:37Z", "id": "relationship--df7c87eb-75d2-4948-af81-9d49d246f301",
"relationship_type": "indicates", "modified": "2016-04-06T20:06:37Z",
"source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", "relationship_type": "indicates",
"target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e", "source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
"spec_version": "2.1", "target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
"type": "relationship" "spec_version": "2.1",
}, "type": "relationship",
]) },
],
)
def test_parse_relationship(data): def test_parse_relationship(data):
rel = stix2.parse(data, version="2.1") rel = stix2.parse(data, version="2.1")

View File

@ -41,7 +41,7 @@ def test_report_example():
object_refs=[ object_refs=[
"indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", "indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2",
"campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c",
"relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a" "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a",
], ],
) )
@ -61,7 +61,7 @@ def test_report_example_objects_in_object_refs():
object_refs=[ object_refs=[
stix2.v21.Indicator(id="indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", **INDICATOR_KWARGS), stix2.v21.Indicator(id="indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", **INDICATOR_KWARGS),
"campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c",
"relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a" "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a",
], ],
) )
@ -82,7 +82,7 @@ def test_report_example_objects_in_object_refs_with_bad_id():
object_refs=[ object_refs=[
stix2.v21.Indicator(id="indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", **INDICATOR_KWARGS), stix2.v21.Indicator(id="indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", **INDICATOR_KWARGS),
"campaign-83422c77-904c-4dc1-aff5-5c38f3a2c55c", # the "bad" id, missing a "-" "campaign-83422c77-904c-4dc1-aff5-5c38f3a2c55c", # the "bad" id, missing a "-"
"relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a" "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a",
], ],
) )
@ -92,28 +92,30 @@ def test_report_example_objects_in_object_refs_with_bad_id():
assert str(excinfo.value) == "Invalid value for Report 'object_refs': " + stix2.properties.ERROR_INVALID_ID assert str(excinfo.value) == "Invalid value for Report 'object_refs': " + stix2.properties.ERROR_INVALID_ID
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"created": "2015-12-21T19:59:11.000Z", {
"created_by_ref": "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283", "created": "2015-12-21T19:59:11.000Z",
"description": "A simple report with an indicator and campaign", "created_by_ref": "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283",
"id": "report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3", "description": "A simple report with an indicator and campaign",
"report_types": [ "id": "report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3",
"campaign" "report_types": [
], "campaign",
"modified": "2015-12-21T19:59:11.000Z", ],
"name": "The Black Vine Cyberespionage Group", "modified": "2015-12-21T19:59:11.000Z",
"object_refs": [ "name": "The Black Vine Cyberespionage Group",
"indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", "object_refs": [
"campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", "indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2",
"relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a" "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c",
], "relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a",
"published": "2016-01-20T17:00:00Z", ],
"spec_version": "2.1", "published": "2016-01-20T17:00:00Z",
"type": "report" "spec_version": "2.1",
}, "type": "report",
]) },
],
)
def test_parse_report(data): def test_parse_report(data):
rept = stix2.parse(data, version="2.1") rept = stix2.parse(data, version="2.1")
@ -123,9 +125,11 @@ def test_parse_report(data):
assert rept.created == dt.datetime(2015, 12, 21, 19, 59, 11, tzinfo=pytz.utc) assert rept.created == dt.datetime(2015, 12, 21, 19, 59, 11, tzinfo=pytz.utc)
assert rept.modified == dt.datetime(2015, 12, 21, 19, 59, 11, tzinfo=pytz.utc) assert rept.modified == dt.datetime(2015, 12, 21, 19, 59, 11, tzinfo=pytz.utc)
assert rept.created_by_ref == "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283" assert rept.created_by_ref == "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283"
assert rept.object_refs == ["indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", assert rept.object_refs == [
"campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c", "indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2",
"relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a"] "campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c",
"relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a",
]
assert rept.description == "A simple report with an indicator and campaign" assert rept.description == "A simple report with an indicator and campaign"
assert rept.report_types == ["campaign"] assert rept.report_types == ["campaign"]
assert rept.name == "The Black Vine Cyberespionage Group" assert rept.name == "The Black Vine Cyberespionage Group"

View File

@ -41,7 +41,7 @@ def test_sighting_all_required_properties():
created=now, created=now,
modified=now, modified=now,
sighting_of_ref=INDICATOR_ID, sighting_of_ref=INDICATOR_ID,
where_sighted_refs=["identity--8cc7afd6-5455-4d2b-a736-e614ee631d99"] where_sighted_refs=["identity--8cc7afd6-5455-4d2b-a736-e614ee631d99"],
) )
assert str(s) == EXPECTED_SIGHTING assert str(s) == EXPECTED_SIGHTING
@ -56,7 +56,7 @@ def test_sighting_bad_where_sighted_refs():
created=now, created=now,
modified=now, modified=now,
sighting_of_ref=INDICATOR_ID, sighting_of_ref=INDICATOR_ID,
where_sighted_refs=["malware--8cc7afd6-5455-4d2b-a736-e614ee631d99"] where_sighted_refs=["malware--8cc7afd6-5455-4d2b-a736-e614ee631d99"],
) )
assert excinfo.value.cls == stix2.v21.Sighting assert excinfo.value.cls == stix2.v21.Sighting
@ -91,20 +91,22 @@ def test_create_sighting_from_objects_rather_than_ids(malware): # noqa: F811
assert rel.id == 'sighting--00000000-0000-4000-8000-000000000003' assert rel.id == 'sighting--00000000-0000-4000-8000-000000000003'
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED_SIGHTING, "data", [
{ EXPECTED_SIGHTING,
"created": "2016-04-06T20:06:37Z", {
"id": "sighting--bfbc19db-ec35-4e45-beed-f8bde2a772fb", "created": "2016-04-06T20:06:37Z",
"modified": "2016-04-06T20:06:37Z", "id": "sighting--bfbc19db-ec35-4e45-beed-f8bde2a772fb",
"sighting_of_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7", "modified": "2016-04-06T20:06:37Z",
"spec_version": "2.1", "sighting_of_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
"type": "sighting", "spec_version": "2.1",
"where_sighted_refs": [ "type": "sighting",
"identity--8cc7afd6-5455-4d2b-a736-e614ee631d99" "where_sighted_refs": [
] "identity--8cc7afd6-5455-4d2b-a736-e614ee631d99",
}, ],
]) },
],
)
def test_parse_sighting(data): def test_parse_sighting(data):
sighting = stix2.parse(data, version="2.1") sighting = stix2.parse(data, version="2.1")

View File

@ -36,22 +36,24 @@ def test_threat_actor_example():
assert str(threat_actor) == EXPECTED assert str(threat_actor) == EXPECTED
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"created": "2016-04-06T20:03:48.000Z", {
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", "created": "2016-04-06T20:03:48.000Z",
"description": "The Evil Org threat actor group", "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
"id": "threat-actor--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", "description": "The Evil Org threat actor group",
"threat_actor_types": [ "id": "threat-actor--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
"crime-syndicate" "threat_actor_types": [
], "crime-syndicate",
"modified": "2016-04-06T20:03:48.000Z", ],
"name": "Evil Org", "modified": "2016-04-06T20:03:48.000Z",
"spec_version": "2.1", "name": "Evil Org",
"type": "threat-actor" "spec_version": "2.1",
}, "type": "threat-actor",
]) },
],
)
def test_parse_threat_actor(data): def test_parse_threat_actor(data):
actor = stix2.parse(data, version="2.1") actor = stix2.parse(data, version="2.1")

View File

@ -48,21 +48,23 @@ def test_tool_example():
assert str(tool) == EXPECTED assert str(tool) == EXPECTED
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"created": "2016-04-06T20:03:48Z", {
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", "created": "2016-04-06T20:03:48Z",
"id": "tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f", "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
"tool_types": [ "id": "tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
"remote-access" "tool_types": [
], "remote-access",
"modified": "2016-04-06T20:03:48Z", ],
"name": "VNC", "modified": "2016-04-06T20:03:48Z",
"spec_version": "2.1", "name": "VNC",
"type": "tool" "spec_version": "2.1",
}, "type": "tool",
]) },
],
)
def test_parse_tool(data): def test_parse_tool(data):
tool = stix2.parse(data, version="2.1") tool = stix2.parse(data, version="2.1")

View File

@ -12,76 +12,90 @@ amsterdam = pytz.timezone('Europe/Amsterdam')
eastern = pytz.timezone('US/Eastern') eastern = pytz.timezone('US/Eastern')
@pytest.mark.parametrize('dttm, timestamp', [ @pytest.mark.parametrize(
(dt.datetime(2017, 1, 1, tzinfo=pytz.utc), '2017-01-01T00:00:00Z'), 'dttm, timestamp', [
(amsterdam.localize(dt.datetime(2017, 1, 1)), '2016-12-31T23:00:00Z'), (dt.datetime(2017, 1, 1, tzinfo=pytz.utc), '2017-01-01T00:00:00Z'),
(eastern.localize(dt.datetime(2017, 1, 1, 12, 34, 56)), '2017-01-01T17:34:56Z'), (amsterdam.localize(dt.datetime(2017, 1, 1)), '2016-12-31T23:00:00Z'),
(eastern.localize(dt.datetime(2017, 7, 1)), '2017-07-01T04:00:00Z'), (eastern.localize(dt.datetime(2017, 1, 1, 12, 34, 56)), '2017-01-01T17:34:56Z'),
(dt.datetime(2017, 7, 1), '2017-07-01T00:00:00Z'), (eastern.localize(dt.datetime(2017, 7, 1)), '2017-07-01T04:00:00Z'),
(dt.datetime(2017, 7, 1, 0, 0, 0, 1), '2017-07-01T00:00:00.000001Z'), (dt.datetime(2017, 7, 1), '2017-07-01T00:00:00Z'),
(stix2.utils.STIXdatetime(2017, 7, 1, 0, 0, 0, 1, precision='millisecond'), '2017-07-01T00:00:00.000Z'), (dt.datetime(2017, 7, 1, 0, 0, 0, 1), '2017-07-01T00:00:00.000001Z'),
(stix2.utils.STIXdatetime(2017, 7, 1, 0, 0, 0, 1, precision='second'), '2017-07-01T00:00:00Z'), (stix2.utils.STIXdatetime(2017, 7, 1, 0, 0, 0, 1, precision='millisecond'), '2017-07-01T00:00:00.000Z'),
]) (stix2.utils.STIXdatetime(2017, 7, 1, 0, 0, 0, 1, precision='second'), '2017-07-01T00:00:00Z'),
],
)
def test_timestamp_formatting(dttm, timestamp): def test_timestamp_formatting(dttm, timestamp):
assert stix2.utils.format_datetime(dttm) == timestamp assert stix2.utils.format_datetime(dttm) == timestamp
@pytest.mark.parametrize('timestamp, dttm', [ @pytest.mark.parametrize(
(dt.datetime(2017, 1, 1, 0, tzinfo=pytz.utc), dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)), 'timestamp, dttm', [
(dt.date(2017, 1, 1), dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)), (dt.datetime(2017, 1, 1, 0, tzinfo=pytz.utc), dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)),
('2017-01-01T00:00:00Z', dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)), (dt.date(2017, 1, 1), dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)),
('2017-01-01T02:00:00+2:00', dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)), ('2017-01-01T00:00:00Z', dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)),
('2017-01-01T00:00:00', dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)), ('2017-01-01T02:00:00+2:00', dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)),
]) ('2017-01-01T00:00:00', dt.datetime(2017, 1, 1, 0, 0, 0, tzinfo=pytz.utc)),
],
)
def test_parse_datetime(timestamp, dttm): def test_parse_datetime(timestamp, dttm):
assert stix2.utils.parse_into_datetime(timestamp) == dttm assert stix2.utils.parse_into_datetime(timestamp) == dttm
@pytest.mark.parametrize('timestamp, dttm, precision', [ @pytest.mark.parametrize(
('2017-01-01T01:02:03.000001', dt.datetime(2017, 1, 1, 1, 2, 3, 0, tzinfo=pytz.utc), 'millisecond'), 'timestamp, dttm, precision', [
('2017-01-01T01:02:03.001', dt.datetime(2017, 1, 1, 1, 2, 3, 1000, tzinfo=pytz.utc), 'millisecond'), ('2017-01-01T01:02:03.000001', dt.datetime(2017, 1, 1, 1, 2, 3, 0, tzinfo=pytz.utc), 'millisecond'),
('2017-01-01T01:02:03.1', dt.datetime(2017, 1, 1, 1, 2, 3, 100000, tzinfo=pytz.utc), 'millisecond'), ('2017-01-01T01:02:03.001', dt.datetime(2017, 1, 1, 1, 2, 3, 1000, tzinfo=pytz.utc), 'millisecond'),
('2017-01-01T01:02:03.45', dt.datetime(2017, 1, 1, 1, 2, 3, 450000, tzinfo=pytz.utc), 'millisecond'), ('2017-01-01T01:02:03.1', dt.datetime(2017, 1, 1, 1, 2, 3, 100000, tzinfo=pytz.utc), 'millisecond'),
('2017-01-01T01:02:03.45', dt.datetime(2017, 1, 1, 1, 2, 3, tzinfo=pytz.utc), 'second'), ('2017-01-01T01:02:03.45', dt.datetime(2017, 1, 1, 1, 2, 3, 450000, tzinfo=pytz.utc), 'millisecond'),
]) ('2017-01-01T01:02:03.45', dt.datetime(2017, 1, 1, 1, 2, 3, tzinfo=pytz.utc), 'second'),
],
)
def test_parse_datetime_precision(timestamp, dttm, precision): def test_parse_datetime_precision(timestamp, dttm, precision):
assert stix2.utils.parse_into_datetime(timestamp, precision) == dttm assert stix2.utils.parse_into_datetime(timestamp, precision) == dttm
@pytest.mark.parametrize('ts', [ @pytest.mark.parametrize(
'foobar', 'ts', [
1, 'foobar',
]) 1,
],
)
def test_parse_datetime_invalid(ts): def test_parse_datetime_invalid(ts):
with pytest.raises(ValueError): with pytest.raises(ValueError):
stix2.utils.parse_into_datetime('foobar') stix2.utils.parse_into_datetime('foobar')
@pytest.mark.parametrize('data', [ @pytest.mark.parametrize(
{"a": 1}, 'data', [
'{"a": 1}', {"a": 1},
StringIO(u'{"a": 1}'), '{"a": 1}',
[("a", 1,)], StringIO(u'{"a": 1}'),
]) [("a", 1,)],
],
)
def test_get_dict(data): def test_get_dict(data):
assert stix2.utils._get_dict(data) assert stix2.utils._get_dict(data)
@pytest.mark.parametrize('data', [ @pytest.mark.parametrize(
1, 'data', [
[1], 1,
['a', 1], [1],
"foobar", ['a', 1],
]) "foobar",
],
)
def test_get_dict_invalid(data): def test_get_dict_invalid(data):
with pytest.raises(ValueError): with pytest.raises(ValueError):
stix2.utils._get_dict(data) stix2.utils._get_dict(data)
@pytest.mark.parametrize('stix_id, type', [ @pytest.mark.parametrize(
('malware--d69c8146-ab35-4d50-8382-6fc80e641d43', 'malware'), 'stix_id, type', [
('intrusion-set--899ce53f-13a0-479b-a0e4-67d46e241542', 'intrusion-set') ('malware--d69c8146-ab35-4d50-8382-6fc80e641d43', 'malware'),
]) ('intrusion-set--899ce53f-13a0-479b-a0e4-67d46e241542', 'intrusion-set'),
],
)
def test_get_type_from_id(stix_id, type): def test_get_type_from_id(stix_id, type):
assert stix2.utils.get_type_from_id(stix_id) == type assert stix2.utils.get_type_from_id(stix_id) == type
@ -104,78 +118,86 @@ def test_deduplicate(stix_objs1):
assert "2017-01-27T13:49:53.936Z" in mods assert "2017-01-27T13:49:53.936Z" in mods
@pytest.mark.parametrize('object, tuple_to_find, expected_index', [ @pytest.mark.parametrize(
(stix2.v21.ObservedData( 'object, tuple_to_find, expected_index', [
id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf", (
created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff", stix2.v21.ObservedData(
created="2016-04-06T19:58:16.000Z", id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
modified="2016-04-06T19:58:16.000Z", created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
first_observed="2015-12-21T19:00:00Z", created="2016-04-06T19:58:16.000Z",
last_observed="2015-12-21T19:00:00Z", modified="2016-04-06T19:58:16.000Z",
number_observed=50, first_observed="2015-12-21T19:00:00Z",
objects={ last_observed="2015-12-21T19:00:00Z",
"0": { number_observed=50,
"name": "foo.exe", objects={
"type": "file" "0": {
}, "name": "foo.exe",
"1": { "type": "file",
"type": "ipv4-addr", },
"value": "198.51.100.3" "1": {
}, "type": "ipv4-addr",
"2": { "value": "198.51.100.3",
"type": "network-traffic", },
"src_ref": "1", "2": {
"protocols": [ "type": "network-traffic",
"tcp", "src_ref": "1",
"http" "protocols": [
], "tcp",
"extensions": { "http",
"http-request-ext": { ],
"request_method": "get", "extensions": {
"request_value": "/download.html", "http-request-ext": {
"request_version": "http/1.1", "request_method": "get",
"request_header": { "request_value": "/download.html",
"Accept-Encoding": "gzip,deflate", "request_version": "http/1.1",
"User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113", "request_header": {
"Host": "www.example.com" "Accept-Encoding": "gzip,deflate",
} "User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6) Gecko/20040113",
} "Host": "www.example.com",
} },
} },
}, },
), ('1', {"type": "ipv4-addr", "value": "198.51.100.3"}), 1), },
({ },
"type": "x-example", ), ('1', {"type": "ipv4-addr", "value": "198.51.100.3"}), 1,
"id": "x-example--d5413db2-c26c-42e0-b0e0-ec800a310bfb", ),
"created": "2018-06-11T01:25:22.063Z", (
"modified": "2018-06-11T01:25:22.063Z", {
"dictionary": { "type": "x-example",
"key": { "id": "x-example--d5413db2-c26c-42e0-b0e0-ec800a310bfb",
"key_one": "value", "created": "2018-06-11T01:25:22.063Z",
"key_two": "value" "modified": "2018-06-11T01:25:22.063Z",
} "dictionary": {
} "key": {
}, ('key', {'key_one': 'value', 'key_two': 'value'}), 0), "key_one": "value",
({ "key_two": "value",
"type": "language-content", },
"spec_version": "2.1", },
"id": "language-content--b86bd89f-98bb-4fa9-8cb2-9ad421da981d", }, ('key', {'key_one': 'value', 'key_two': 'value'}), 0,
"created": "2017-02-08T21:31:22.007Z", ),
"modified": "2017-02-08T21:31:22.007Z", (
"object_ref": "campaign--12a111f0-b824-4baf-a224-83b80237a094", {
"object_modified": "2017-02-08T21:31:22.007Z", "type": "language-content",
"contents": { "spec_version": "2.1",
"de": { "id": "language-content--b86bd89f-98bb-4fa9-8cb2-9ad421da981d",
"name": "Bank Angriff 1", "created": "2017-02-08T21:31:22.007Z",
"description": "Weitere Informationen über Banküberfall" "modified": "2017-02-08T21:31:22.007Z",
}, "object_ref": "campaign--12a111f0-b824-4baf-a224-83b80237a094",
"fr": { "object_modified": "2017-02-08T21:31:22.007Z",
"name": "Attaque Bank 1", "contents": {
"description": "Plus d'informations sur la crise bancaire" "de": {
} "name": "Bank Angriff 1",
} "description": "Weitere Informationen über Banküberfall",
}, ('fr', {"name": "Attaque Bank 1", "description": "Plus d'informations sur la crise bancaire"}), 1) },
]) "fr": {
"name": "Attaque Bank 1",
"description": "Plus d'informations sur la crise bancaire",
},
},
}, ('fr', {"name": "Attaque Bank 1", "description": "Plus d'informations sur la crise bancaire"}), 1,
),
],
)
def test_find_property_index(object, tuple_to_find, expected_index): def test_find_property_index(object, tuple_to_find, expected_index):
assert stix2.utils.find_property_index( assert stix2.utils.find_property_index(
object, object,
@ -183,29 +205,35 @@ def test_find_property_index(object, tuple_to_find, expected_index):
) == expected_index ) == expected_index
@pytest.mark.parametrize('dict_value, tuple_to_find, expected_index', [ @pytest.mark.parametrize(
({ 'dict_value, tuple_to_find, expected_index', [
"contents": { (
"de": { {
"name": "Bank Angriff 1", "contents": {
"description": "Weitere Informationen über Banküberfall" "de": {
}, "name": "Bank Angriff 1",
"fr": { "description": "Weitere Informationen über Banküberfall",
"name": "Attaque Bank 1", },
"description": "Plus d'informations sur la crise bancaire" "fr": {
}, "name": "Attaque Bank 1",
"es": { "description": "Plus d'informations sur la crise bancaire",
"name": "Ataque al Banco", },
"description": "Mas informacion sobre el ataque al banco" "es": {
} "name": "Ataque al Banco",
} "description": "Mas informacion sobre el ataque al banco",
}, ('es', {"name": "Ataque al Banco", "description": "Mas informacion sobre el ataque al banco"}), 1), # Sorted alphabetically },
({ },
'my_list': [ }, ('es', {"name": "Ataque al Banco", "description": "Mas informacion sobre el ataque al banco"}), 1,
{"key_one": 1}, ), # Sorted alphabetically
{"key_two": 2} (
] {
}, ('key_one', 1), 0) 'my_list': [
]) {"key_one": 1},
{"key_two": 2},
],
}, ('key_one', 1), 0,
),
],
)
def test_iterate_over_values(dict_value, tuple_to_find, expected_index): def test_iterate_over_values(dict_value, tuple_to_find, expected_index):
assert stix2.utils._find_property_in_seq(dict_value.values(), *tuple_to_find) == expected_index assert stix2.utils._find_property_in_seq(dict_value.values(), *tuple_to_find) == expected_index

View File

@ -39,15 +39,15 @@ def test_making_new_version_with_embedded_object():
campaign_v1 = stix2.v21.Campaign( campaign_v1 = stix2.v21.Campaign(
external_references=[{ external_references=[{
"source_name": "capec", "source_name": "capec",
"external_id": "CAPEC-163" "external_id": "CAPEC-163",
}], }],
**CAMPAIGN_MORE_KWARGS **CAMPAIGN_MORE_KWARGS
) )
campaign_v2 = campaign_v1.new_version(external_references=[{ campaign_v2 = campaign_v1.new_version(external_references=[{
"source_name": "capec", "source_name": "capec",
"external_id": "CAPEC-164" "external_id": "CAPEC-164",
}]) }])
assert campaign_v1.id == campaign_v2.id assert campaign_v1.id == campaign_v2.id
assert campaign_v1.spec_version == campaign_v2.spec_version assert campaign_v1.spec_version == campaign_v2.spec_version
@ -92,15 +92,19 @@ def test_versioning_error_bad_modified_value():
assert excinfo.value.cls == stix2.v21.Campaign assert excinfo.value.cls == stix2.v21.Campaign
assert excinfo.value.prop_name == "modified" assert excinfo.value.prop_name == "modified"
assert excinfo.value.reason == ("The new modified datetime cannot be before than or equal to the current modified datetime." assert excinfo.value.reason == (
"It cannot be equal, as according to STIX 2 specification, objects that are different " "The new modified datetime cannot be before than or equal to the current modified datetime."
"but have the same id and modified timestamp do not have defined consumer behavior.") "It cannot be equal, as according to STIX 2 specification, objects that are different "
"but have the same id and modified timestamp do not have defined consumer behavior."
)
msg = "Invalid value for {0} '{1}': {2}" msg = "Invalid value for {0} '{1}': {2}"
msg = msg.format(stix2.v21.Campaign.__name__, "modified", msg = msg.format(
"The new modified datetime cannot be before than or equal to the current modified datetime." stix2.v21.Campaign.__name__, "modified",
"It cannot be equal, as according to STIX 2 specification, objects that are different " "The new modified datetime cannot be before than or equal to the current modified datetime."
"but have the same id and modified timestamp do not have defined consumer behavior.") "It cannot be equal, as according to STIX 2 specification, objects that are different "
"but have the same id and modified timestamp do not have defined consumer behavior.",
)
assert str(excinfo.value) == msg assert str(excinfo.value) == msg
@ -221,11 +225,13 @@ def test_revoke_invalid_cls():
def test_remove_custom_stix_property(): def test_remove_custom_stix_property():
mal = stix2.v21.Malware(name="ColePowers", mal = stix2.v21.Malware(
malware_types=["rootkit"], name="ColePowers",
is_family=False, malware_types=["rootkit"],
x_custom="armada", is_family=False,
allow_custom=True) x_custom="armada",
allow_custom=True,
)
mal_nc = stix2.utils.remove_custom_stix(mal) mal_nc = stix2.utils.remove_custom_stix(mal)
@ -235,10 +241,12 @@ def test_remove_custom_stix_property():
def test_remove_custom_stix_object(): def test_remove_custom_stix_object():
@stix2.v21.CustomObject("x-animal", [ @stix2.v21.CustomObject(
("species", stix2.properties.StringProperty(required=True)), "x-animal", [
("animal_class", stix2.properties.StringProperty()), ("species", stix2.properties.StringProperty(required=True)),
]) ("animal_class", stix2.properties.StringProperty()),
],
)
class Animal(object): class Animal(object):
pass pass

View File

@ -30,31 +30,35 @@ def test_vulnerability_example():
modified="2016-05-12T08:17:27.000Z", modified="2016-05-12T08:17:27.000Z",
name="CVE-2016-1234", name="CVE-2016-1234",
external_references=[ external_references=[
stix2.ExternalReference(source_name='cve', stix2.ExternalReference(
external_id="CVE-2016-1234"), source_name='cve',
external_id="CVE-2016-1234",
),
], ],
) )
assert str(vulnerability) == EXPECTED assert str(vulnerability) == EXPECTED
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize(
EXPECTED, "data", [
{ EXPECTED,
"created": "2016-05-12T08:17:27Z", {
"external_references": [ "created": "2016-05-12T08:17:27Z",
{ "external_references": [
"external_id": "CVE-2016-1234", {
"source_name": "cve" "external_id": "CVE-2016-1234",
} "source_name": "cve",
], },
"id": "vulnerability--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061", ],
"modified": "2016-05-12T08:17:27Z", "id": "vulnerability--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
"name": "CVE-2016-1234", "modified": "2016-05-12T08:17:27Z",
"spec_version": "2.1", "name": "CVE-2016-1234",
"type": "vulnerability" "spec_version": "2.1",
}, "type": "vulnerability",
]) },
],
)
def test_parse_vulnerability(data): def test_parse_vulnerability(data):
vuln = stix2.parse(data, version="2.1") vuln = stix2.parse(data, version="2.1")

View File

@ -1,29 +1,25 @@
import os import os
import stix2 import stix2
from stix2.workbench import (AttackPattern, Campaign, CourseOfAction, from stix2.workbench import (
ExternalReference, FileSystemSource, Filter, AttackPattern, Campaign, CourseOfAction, ExternalReference,
Identity, Indicator, IntrusionSet, Malware, FileSystemSource, Filter, Identity, Indicator, IntrusionSet, Malware,
MarkingDefinition, ObservedData, Relationship, MarkingDefinition, ObservedData, Relationship, Report, StatementMarking,
Report, StatementMarking, ThreatActor, Tool, ThreatActor, Tool, Vulnerability, add_data_source, all_versions,
Vulnerability, add_data_source, all_versions, attack_patterns, campaigns, courses_of_action, create, get, identities,
attack_patterns, campaigns, courses_of_action, indicators, intrusion_sets, malware, observed_data, query, reports, save,
create, get, identities, indicators, set_default_created, set_default_creator, set_default_external_refs,
intrusion_sets, malware, observed_data, query, set_default_object_marking_refs, threat_actors, tools, vulnerabilities,
reports, save, set_default_created, )
set_default_creator, set_default_external_refs,
set_default_object_marking_refs, threat_actors,
tools, vulnerabilities)
from .constants import (ATTACK_PATTERN_ID, ATTACK_PATTERN_KWARGS, CAMPAIGN_ID, from .constants import (
CAMPAIGN_KWARGS, COURSE_OF_ACTION_ID, ATTACK_PATTERN_ID, ATTACK_PATTERN_KWARGS, CAMPAIGN_ID, CAMPAIGN_KWARGS,
COURSE_OF_ACTION_KWARGS, IDENTITY_ID, IDENTITY_KWARGS, COURSE_OF_ACTION_ID, COURSE_OF_ACTION_KWARGS, IDENTITY_ID, IDENTITY_KWARGS,
INDICATOR_ID, INDICATOR_KWARGS, INTRUSION_SET_ID, INDICATOR_ID, INDICATOR_KWARGS, INTRUSION_SET_ID, INTRUSION_SET_KWARGS,
INTRUSION_SET_KWARGS, MALWARE_ID, MALWARE_KWARGS, MALWARE_ID, MALWARE_KWARGS, OBSERVED_DATA_ID, OBSERVED_DATA_KWARGS,
OBSERVED_DATA_ID, OBSERVED_DATA_KWARGS, REPORT_ID, REPORT_ID, REPORT_KWARGS, THREAT_ACTOR_ID, THREAT_ACTOR_KWARGS, TOOL_ID,
REPORT_KWARGS, THREAT_ACTOR_ID, THREAT_ACTOR_KWARGS, TOOL_KWARGS, VULNERABILITY_ID, VULNERABILITY_KWARGS,
TOOL_ID, TOOL_KWARGS, VULNERABILITY_ID, )
VULNERABILITY_KWARGS)
def test_workbench_environment(): def test_workbench_environment():
@ -190,8 +186,10 @@ def test_workbench_related():
def test_workbench_related_with_filters(): def test_workbench_related_with_filters():
malware = Malware(malware_types=["ransomware"], name="CryptorBit", malware = Malware(
created_by_ref=IDENTITY_ID, is_family=False) malware_types=["ransomware"], name="CryptorBit",
created_by_ref=IDENTITY_ID, is_family=False,
)
rel = Relationship(malware.id, 'variant-of', MALWARE_ID) rel = Relationship(malware.id, 'variant-of', MALWARE_ID)
save([malware, rel]) save([malware, rel])
@ -226,8 +224,10 @@ def test_additional_filter():
def test_additional_filters_list(): def test_additional_filters_list():
resp = tools([Filter('created_by_ref', '=', 'identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5'), resp = tools([
Filter('name', '=', 'Windows Credential Editor')]) Filter('created_by_ref', '=', 'identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5'),
Filter('name', '=', 'Windows Credential Editor'),
])
assert len(resp) == 1 assert len(resp) == 1
@ -250,8 +250,10 @@ def test_default_created_timestamp():
def test_default_external_refs(): def test_default_external_refs():
ext_ref = ExternalReference(source_name="ACME Threat Intel", ext_ref = ExternalReference(
description="Threat report") source_name="ACME Threat Intel",
description="Threat report",
)
set_default_external_refs(ext_ref) set_default_external_refs(ext_ref)
campaign = Campaign(**CAMPAIGN_KWARGS) campaign = Campaign(**CAMPAIGN_KWARGS)
@ -261,8 +263,10 @@ def test_default_external_refs():
def test_default_object_marking_refs(): def test_default_object_marking_refs():
stmt_marking = StatementMarking("Copyright 2016, Example Corp") stmt_marking = StatementMarking("Copyright 2016, Example Corp")
mark_def = MarkingDefinition(definition_type="statement", mark_def = MarkingDefinition(
definition=stmt_marking) definition_type="statement",
definition=stmt_marking,
)
set_default_object_marking_refs(mark_def) set_default_object_marking_refs(mark_def)
campaign = Campaign(**CAMPAIGN_KWARGS) campaign = Campaign(**CAMPAIGN_KWARGS)
@ -300,7 +304,7 @@ def test_workbench_custom_property_dict_in_observable_extension():
'allow_custom': True, 'allow_custom': True,
'sid': 1, 'sid': 1,
'x_foo': 'bar', 'x_foo': 'bar',
} },
}, },
) )
observed_data = ObservedData( observed_data = ObservedData(

View File

@ -7,8 +7,9 @@ import json
from dateutil import parser from dateutil import parser
import pytz import pytz
from .exceptions import (InvalidValueError, RevokeError, from .exceptions import (
UnmodifiablePropertyError) InvalidValueError, RevokeError, UnmodifiablePropertyError,
)
# Sentinel value for properties 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
@ -26,8 +27,10 @@ class STIXdatetime(dt.datetime):
precision = kwargs.pop('precision', None) precision = kwargs.pop('precision', None)
if isinstance(args[0], dt.datetime): # Allow passing in a datetime object if isinstance(args[0], dt.datetime): # Allow passing in a datetime object
dttm = args[0] dttm = args[0]
args = (dttm.year, dttm.month, dttm.day, dttm.hour, dttm.minute, args = (
dttm.second, dttm.microsecond, dttm.tzinfo) dttm.year, dttm.month, dttm.day, dttm.hour, dttm.minute,
dttm.second, dttm.microsecond, dttm.tzinfo,
)
# self will be an instance of STIXdatetime, not dt.datetime # self will be an instance of STIXdatetime, not dt.datetime
self = dt.datetime.__new__(cls, *args, **kwargs) self = dt.datetime.__new__(cls, *args, **kwargs)
self.precision = precision self.precision = precision
@ -117,8 +120,10 @@ def parse_into_datetime(value, precision=None):
parsed = parser.parse(value) parsed = parser.parse(value)
except (TypeError, ValueError): except (TypeError, ValueError):
# Unknown format # Unknown format
raise ValueError("must be a datetime object, date object, or " raise ValueError(
"timestamp string in a recognizable format.") "must be a datetime object, date object, or "
"timestamp string in a recognizable format.",
)
if parsed.tzinfo: if parsed.tzinfo:
ts = parsed.astimezone(pytz.utc) ts = parsed.astimezone(pytz.utc)
else: else:
@ -250,8 +255,10 @@ def new_version(data, **kwargs):
""" """
if not isinstance(data, Mapping): if not isinstance(data, Mapping):
raise ValueError("cannot create new version of object of this type! " raise ValueError(
"Try a dictionary or instance of an SDO or SRO class.") "cannot create new version of object of this type! "
"Try a dictionary or instance of an SDO or SRO class.",
)
unchangable_properties = [] unchangable_properties = []
if data.get('revoked'): if data.get('revoked'):
@ -276,10 +283,12 @@ def new_version(data, **kwargs):
old_modified_property = parse_into_datetime(data.get('modified'), precision='millisecond') old_modified_property = parse_into_datetime(data.get('modified'), precision='millisecond')
new_modified_property = parse_into_datetime(kwargs['modified'], precision='millisecond') new_modified_property = parse_into_datetime(kwargs['modified'], precision='millisecond')
if new_modified_property <= old_modified_property: if new_modified_property <= old_modified_property:
raise InvalidValueError(cls, 'modified', raise InvalidValueError(
"The new modified datetime cannot be before than or equal to the current modified datetime." cls, 'modified',
"It cannot be equal, as according to STIX 2 specification, objects that are different " "The new modified datetime cannot be before than or equal to the current modified datetime."
"but have the same id and modified timestamp do not have defined consumer behavior.") "It cannot be equal, as according to STIX 2 specification, objects that are different "
"but have the same id and modified timestamp do not have defined consumer behavior.",
)
new_obj_inner.update(kwargs) new_obj_inner.update(kwargs)
# Exclude properties with a value of 'None' in case data is not an instance of a _STIXBase subclass # Exclude properties with a value of 'None' in case data is not an instance of a _STIXBase subclass
return cls(**{k: v for k, v in new_obj_inner.items() if v is not None}) return cls(**{k: v for k, v in new_obj_inner.items() if v is not None})
@ -292,8 +301,10 @@ def revoke(data):
A new version of the object with ``revoked`` set to ``True``. A new version of the object with ``revoked`` set to ``True``.
""" """
if not isinstance(data, Mapping): if not isinstance(data, Mapping):
raise ValueError("cannot revoke object of this type! Try a dictionary " raise ValueError(
"or instance of an SDO or SRO class.") "cannot revoke object of this type! Try a dictionary "
"or instance of an SDO or SRO class.",
)
if data.get('revoked'): if data.get('revoked'):
raise RevokeError("revoke") raise RevokeError("revoke")

View File

@ -2,24 +2,27 @@
# flake8: noqa # flake8: noqa
from .bundle import Bundle from .bundle import Bundle
from .common import (TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, from .common import (
ExternalReference, GranularMarking, KillChainPhase, TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, ExternalReference,
MarkingDefinition, StatementMarking, TLPMarking) GranularMarking, KillChainPhase, MarkingDefinition, StatementMarking,
from .observables import (URL, AlternateDataStream, ArchiveExt, Artifact, TLPMarking,
AutonomousSystem, CustomExtension, CustomObservable, )
Directory, DomainName, EmailAddress, EmailMessage, from .observables import (
EmailMIMEComponent, File, HTTPRequestExt, ICMPExt, URL, AlternateDataStream, ArchiveExt, Artifact, AutonomousSystem,
IPv4Address, IPv6Address, MACAddress, Mutex, CustomExtension, CustomObservable, Directory, DomainName, EmailAddress,
NetworkTraffic, NTFSExt, PDFExt, Process, EmailMessage, EmailMIMEComponent, File, HTTPRequestExt, ICMPExt,
RasterImageExt, SocketExt, Software, TCPExt, IPv4Address, IPv6Address, MACAddress, Mutex, NetworkTraffic, NTFSExt,
UNIXAccountExt, UserAccount, WindowsPEBinaryExt, PDFExt, Process, RasterImageExt, SocketExt, Software, TCPExt,
WindowsPEOptionalHeaderType, WindowsPESection, UNIXAccountExt, UserAccount, WindowsPEBinaryExt,
WindowsProcessExt, WindowsRegistryKey, WindowsPEOptionalHeaderType, WindowsPESection, WindowsProcessExt,
WindowsRegistryValueType, WindowsServiceExt, WindowsRegistryKey, WindowsRegistryValueType, WindowsServiceExt,
X509Certificate, X509V3ExtenstionsType) X509Certificate, X509V3ExtenstionsType,
from .sdo import (AttackPattern, Campaign, CourseOfAction, CustomObject, )
Identity, Indicator, IntrusionSet, Malware, ObservedData, from .sdo import (
Report, ThreatActor, Tool, Vulnerability) AttackPattern, Campaign, CourseOfAction, CustomObject, Identity, Indicator,
IntrusionSet, Malware, ObservedData, Report, ThreatActor, Tool,
Vulnerability,
)
from .sro import Relationship, Sighting from .sro import Relationship, Sighting
OBJ_MAP = { OBJ_MAP = {
@ -68,7 +71,7 @@ EXT_MAP = {
'ntfs-ext': NTFSExt, 'ntfs-ext': NTFSExt,
'pdf-ext': PDFExt, 'pdf-ext': PDFExt,
'raster-image-ext': RasterImageExt, 'raster-image-ext': RasterImageExt,
'windows-pebinary-ext': WindowsPEBinaryExt 'windows-pebinary-ext': WindowsPEBinaryExt,
}, },
'network-traffic': { 'network-traffic': {
'http-request-ext': HTTPRequestExt, 'http-request-ext': HTTPRequestExt,

View File

@ -1,8 +1,9 @@
from collections import OrderedDict from collections import OrderedDict
from ..base import _STIXBase from ..base import _STIXBase
from ..properties import (IDProperty, ListProperty, STIXObjectProperty, from ..properties import (
StringProperty, TypeProperty) IDProperty, ListProperty, STIXObjectProperty, StringProperty, TypeProperty,
)
class Bundle(_STIXBase): class Bundle(_STIXBase):

View File

@ -5,9 +5,10 @@ from collections import OrderedDict
from ..base import _STIXBase from ..base import _STIXBase
from ..custom import _custom_marking_builder from ..custom import _custom_marking_builder
from ..markings import _MarkingsMixin from ..markings import _MarkingsMixin
from ..properties import (HashesProperty, IDProperty, ListProperty, Property, from ..properties import (
ReferenceProperty, SelectorProperty, StringProperty, HashesProperty, IDProperty, ListProperty, Property, ReferenceProperty,
TimestampProperty, TypeProperty) SelectorProperty, StringProperty, TimestampProperty, TypeProperty,
)
from ..utils import NOW, _get_dict from ..utils import NOW, _get_dict
@ -59,7 +60,7 @@ class TLPMarking(_STIXBase):
# TODO: don't allow the creation of any other TLPMarkings than the ones below # TODO: don't allow the creation of any other TLPMarkings than the ones below
_type = 'tlp' _type = 'tlp'
_properties = OrderedDict([ _properties = OrderedDict([
('tlp', StringProperty(required=True)) ('tlp', StringProperty(required=True)),
]) ])
@ -70,7 +71,7 @@ class StatementMarking(_STIXBase):
_type = 'statement' _type = 'statement'
_properties = OrderedDict([ _properties = OrderedDict([
('statement', StringProperty(required=True)) ('statement', StringProperty(required=True)),
]) ])
def __init__(self, statement=None, **kwargs): def __init__(self, statement=None, **kwargs):
@ -157,26 +158,26 @@ TLP_WHITE = MarkingDefinition(
id='marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9', id='marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9',
created='2017-01-20T00:00:00.000Z', created='2017-01-20T00:00:00.000Z',
definition_type='tlp', definition_type='tlp',
definition=TLPMarking(tlp='white') definition=TLPMarking(tlp='white'),
) )
TLP_GREEN = MarkingDefinition( TLP_GREEN = MarkingDefinition(
id='marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da', id='marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da',
created='2017-01-20T00:00:00.000Z', created='2017-01-20T00:00:00.000Z',
definition_type='tlp', definition_type='tlp',
definition=TLPMarking(tlp='green') definition=TLPMarking(tlp='green'),
) )
TLP_AMBER = MarkingDefinition( TLP_AMBER = MarkingDefinition(
id='marking-definition--f88d31f6-486f-44da-b317-01333bde0b82', id='marking-definition--f88d31f6-486f-44da-b317-01333bde0b82',
created='2017-01-20T00:00:00.000Z', created='2017-01-20T00:00:00.000Z',
definition_type='tlp', definition_type='tlp',
definition=TLPMarking(tlp='amber') definition=TLPMarking(tlp='amber'),
) )
TLP_RED = MarkingDefinition( TLP_RED = MarkingDefinition(
id='marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed', id='marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed',
created='2017-01-20T00:00:00.000Z', created='2017-01-20T00:00:00.000Z',
definition_type='tlp', definition_type='tlp',
definition=TLPMarking(tlp='red') definition=TLPMarking(tlp='red'),
) )

View File

@ -11,12 +11,12 @@ import itertools
from ..base import _Extension, _Observable, _STIXBase from ..base import _Extension, _Observable, _STIXBase
from ..custom import _custom_extension_builder, _custom_observable_builder from ..custom import _custom_extension_builder, _custom_observable_builder
from ..exceptions import AtLeastOnePropertyError, DependentPropertiesError from ..exceptions import AtLeastOnePropertyError, DependentPropertiesError
from ..properties import (BinaryProperty, BooleanProperty, DictionaryProperty, from ..properties import (
EmbeddedObjectProperty, EnumProperty, BinaryProperty, BooleanProperty, DictionaryProperty,
ExtensionsProperty, FloatProperty, HashesProperty, EmbeddedObjectProperty, EnumProperty, ExtensionsProperty, FloatProperty,
HexProperty, IntegerProperty, ListProperty, HashesProperty, HexProperty, IntegerProperty, ListProperty,
ObjectReferenceProperty, StringProperty, ObjectReferenceProperty, StringProperty, TimestampProperty, TypeProperty,
TimestampProperty, TypeProperty) )
class Artifact(_Observable): class Artifact(_Observable):
@ -423,34 +423,42 @@ class SocketExt(_Extension):
_type = 'socket-ext' _type = 'socket-ext'
_properties = OrderedDict([ _properties = OrderedDict([
('address_family', EnumProperty(allowed=[ (
"AF_UNSPEC", 'address_family', EnumProperty(
"AF_INET", allowed=[
"AF_IPX", "AF_UNSPEC",
"AF_APPLETALK", "AF_INET",
"AF_NETBIOS", "AF_IPX",
"AF_INET6", "AF_APPLETALK",
"AF_IRDA", "AF_NETBIOS",
"AF_BTH", "AF_INET6",
], required=True)), "AF_IRDA",
"AF_BTH",
], required=True,
),
),
('is_blocking', BooleanProperty()), ('is_blocking', BooleanProperty()),
('is_listening', BooleanProperty()), ('is_listening', BooleanProperty()),
('protocol_family', EnumProperty(allowed=[ (
"PF_INET", 'protocol_family', EnumProperty(allowed=[
"PF_IPX", "PF_INET",
"PF_APPLETALK", "PF_IPX",
"PF_INET6", "PF_APPLETALK",
"PF_AX25", "PF_INET6",
"PF_NETROM" "PF_AX25",
])), "PF_NETROM",
]),
),
('options', DictionaryProperty()), ('options', DictionaryProperty()),
('socket_type', EnumProperty(allowed=[ (
"SOCK_STREAM", 'socket_type', EnumProperty(allowed=[
"SOCK_DGRAM", "SOCK_STREAM",
"SOCK_RAW", "SOCK_DGRAM",
"SOCK_RDM", "SOCK_RAW",
"SOCK_SEQPACKET", "SOCK_RDM",
])), "SOCK_SEQPACKET",
]),
),
('socket_descriptor', IntegerProperty()), ('socket_descriptor', IntegerProperty()),
('socket_handle', IntegerProperty()), ('socket_handle', IntegerProperty()),
]) ])
@ -528,29 +536,35 @@ class WindowsServiceExt(_Extension):
('descriptions', ListProperty(StringProperty)), ('descriptions', ListProperty(StringProperty)),
('display_name', StringProperty()), ('display_name', StringProperty()),
('group_name', StringProperty()), ('group_name', StringProperty()),
('start_type', EnumProperty(allowed=[ (
"SERVICE_AUTO_START", 'start_type', EnumProperty(allowed=[
"SERVICE_BOOT_START", "SERVICE_AUTO_START",
"SERVICE_DEMAND_START", "SERVICE_BOOT_START",
"SERVICE_DISABLED", "SERVICE_DEMAND_START",
"SERVICE_SYSTEM_ALERT", "SERVICE_DISABLED",
])), "SERVICE_SYSTEM_ALERT",
]),
),
('service_dll_refs', ListProperty(ObjectReferenceProperty(valid_types='file'))), ('service_dll_refs', ListProperty(ObjectReferenceProperty(valid_types='file'))),
('service_type', EnumProperty(allowed=[ (
"SERVICE_KERNEL_DRIVER", 'service_type', EnumProperty(allowed=[
"SERVICE_FILE_SYSTEM_DRIVER", "SERVICE_KERNEL_DRIVER",
"SERVICE_WIN32_OWN_PROCESS", "SERVICE_FILE_SYSTEM_DRIVER",
"SERVICE_WIN32_SHARE_PROCESS", "SERVICE_WIN32_OWN_PROCESS",
])), "SERVICE_WIN32_SHARE_PROCESS",
('service_status', EnumProperty(allowed=[ ]),
"SERVICE_CONTINUE_PENDING", ),
"SERVICE_PAUSE_PENDING", (
"SERVICE_PAUSED", 'service_status', EnumProperty(allowed=[
"SERVICE_RUNNING", "SERVICE_CONTINUE_PENDING",
"SERVICE_START_PENDING", "SERVICE_PAUSE_PENDING",
"SERVICE_STOP_PENDING", "SERVICE_PAUSED",
"SERVICE_STOPPED", "SERVICE_RUNNING",
])), "SERVICE_START_PENDING",
"SERVICE_STOP_PENDING",
"SERVICE_STOPPED",
]),
),
]) ])
@ -672,21 +686,23 @@ class WindowsRegistryValueType(_STIXBase):
_properties = OrderedDict([ _properties = OrderedDict([
('name', StringProperty(required=True)), ('name', StringProperty(required=True)),
('data', StringProperty()), ('data', StringProperty()),
('data_type', EnumProperty(allowed=[ (
"REG_NONE", 'data_type', EnumProperty(allowed=[
"REG_SZ", "REG_NONE",
"REG_EXPAND_SZ", "REG_SZ",
"REG_BINARY", "REG_EXPAND_SZ",
"REG_DWORD", "REG_BINARY",
"REG_DWORD_BIG_ENDIAN", "REG_DWORD",
"REG_LINK", "REG_DWORD_BIG_ENDIAN",
"REG_MULTI_SZ", "REG_LINK",
"REG_RESOURCE_LIST", "REG_MULTI_SZ",
"REG_FULL_RESOURCE_DESCRIPTION", "REG_RESOURCE_LIST",
"REG_RESOURCE_REQUIREMENTS_LIST", "REG_FULL_RESOURCE_DESCRIPTION",
"REG_QWORD", "REG_RESOURCE_REQUIREMENTS_LIST",
"REG_INVALID_TYPE", "REG_QWORD",
])), "REG_INVALID_TYPE",
]),
),
]) ])
@ -782,7 +798,7 @@ def CustomObservable(type='x-custom-observable', properties=None):
_properties = list(itertools.chain.from_iterable([ _properties = list(itertools.chain.from_iterable([
[('type', TypeProperty(type))], [('type', TypeProperty(type))],
properties, properties,
[('extensions', ExtensionsProperty(enclosing_type=type))] [('extensions', ExtensionsProperty(enclosing_type=type))],
])) ]))
return _custom_observable_builder(cls, type, _properties, '2.0') return _custom_observable_builder(cls, type, _properties, '2.0')
return wrapper return wrapper

View File

@ -6,10 +6,11 @@ import itertools
from ..core import STIXDomainObject from ..core import STIXDomainObject
from ..custom import _custom_object_builder from ..custom import _custom_object_builder
from ..properties import (BooleanProperty, IDProperty, IntegerProperty, from ..properties import (
ListProperty, ObservableProperty, PatternProperty, BooleanProperty, IDProperty, IntegerProperty, ListProperty,
ReferenceProperty, StringProperty, TimestampProperty, ObservableProperty, PatternProperty, ReferenceProperty, StringProperty,
TypeProperty) TimestampProperty, TypeProperty,
)
from ..utils import NOW from ..utils import NOW
from .common import ExternalReference, GranularMarking, KillChainPhase from .common import ExternalReference, GranularMarking, KillChainPhase
@ -354,7 +355,7 @@ def CustomObject(type='x-custom-type', properties=None):
('id', IDProperty(type)), ('id', IDProperty(type)),
('created_by_ref', ReferenceProperty(type='identity')), ('created_by_ref', ReferenceProperty(type='identity')),
('created', TimestampProperty(default=lambda: NOW, precision='millisecond')), ('created', TimestampProperty(default=lambda: NOW, precision='millisecond')),
('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')) ('modified', TimestampProperty(default=lambda: NOW, precision='millisecond')),
], ],
[x for x in properties if not x[0].startswith('x_')], [x for x in properties if not x[0].startswith('x_')],
[ [
@ -364,7 +365,7 @@ def CustomObject(type='x-custom-type', properties=None):
('object_marking_refs', ListProperty(ReferenceProperty(type='marking-definition'))), ('object_marking_refs', ListProperty(ReferenceProperty(type='marking-definition'))),
('granular_markings', ListProperty(GranularMarking)), ('granular_markings', ListProperty(GranularMarking)),
], ],
sorted([x for x in properties if x[0].startswith('x_')], key=lambda x: x[0]) sorted([x for x in properties if x[0].startswith('x_')], key=lambda x: x[0]),
])) ]))
return _custom_object_builder(cls, type, _properties, '2.0') return _custom_object_builder(cls, type, _properties, '2.0')

View File

@ -3,9 +3,10 @@
from collections import OrderedDict from collections import OrderedDict
from ..core import STIXRelationshipObject from ..core import STIXRelationshipObject
from ..properties import (BooleanProperty, IDProperty, IntegerProperty, from ..properties import (
ListProperty, ReferenceProperty, StringProperty, BooleanProperty, IDProperty, IntegerProperty, ListProperty,
TimestampProperty, TypeProperty) ReferenceProperty, StringProperty, TimestampProperty, TypeProperty,
)
from ..utils import NOW from ..utils import NOW
from .common import ExternalReference, GranularMarking from .common import ExternalReference, GranularMarking
@ -34,8 +35,10 @@ class Relationship(STIXRelationshipObject):
]) ])
# Explicitly define the first three kwargs to make readable Relationship declarations. # Explicitly define the first three kwargs to make readable Relationship declarations.
def __init__(self, source_ref=None, relationship_type=None, def __init__(
target_ref=None, **kwargs): self, source_ref=None, relationship_type=None,
target_ref=None, **kwargs
):
# Allow (source_ref, relationship_type, target_ref) as positional args. # Allow (source_ref, relationship_type, target_ref) as positional args.
if source_ref and not kwargs.get('source_ref'): if source_ref and not kwargs.get('source_ref'):
kwargs['source_ref'] = source_ref kwargs['source_ref'] = source_ref

View File

@ -2,26 +2,27 @@
# flake8: noqa # flake8: noqa
from .bundle import Bundle from .bundle import Bundle
from .common import (TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, from .common import (
ExternalReference, GranularMarking, KillChainPhase, TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, ExternalReference,
LanguageContent, MarkingDefinition, StatementMarking, GranularMarking, KillChainPhase, LanguageContent, MarkingDefinition,
TLPMarking) StatementMarking, TLPMarking,
from .observables import (URL, AlternateDataStream, ArchiveExt, Artifact, )
AutonomousSystem, CustomExtension, CustomObservable, from .observables import (
Directory, DomainName, EmailAddress, EmailMessage, URL, AlternateDataStream, ArchiveExt, Artifact, AutonomousSystem,
EmailMIMEComponent, File, HTTPRequestExt, ICMPExt, CustomExtension, CustomObservable, Directory, DomainName, EmailAddress,
IPv4Address, IPv6Address, MACAddress, Mutex, EmailMessage, EmailMIMEComponent, File, HTTPRequestExt, ICMPExt,
NetworkTraffic, NTFSExt, PDFExt, Process, IPv4Address, IPv6Address, MACAddress, Mutex, NetworkTraffic, NTFSExt,
RasterImageExt, SocketExt, Software, TCPExt, PDFExt, Process, RasterImageExt, SocketExt, Software, TCPExt,
UNIXAccountExt, UserAccount, WindowsPEBinaryExt, UNIXAccountExt, UserAccount, WindowsPEBinaryExt,
WindowsPEOptionalHeaderType, WindowsPESection, WindowsPEOptionalHeaderType, WindowsPESection, WindowsProcessExt,
WindowsProcessExt, WindowsRegistryKey, WindowsRegistryKey, WindowsRegistryValueType, WindowsServiceExt,
WindowsRegistryValueType, WindowsServiceExt, X509Certificate, X509V3ExtenstionsType,
X509Certificate, X509V3ExtenstionsType) )
from .sdo import (AttackPattern, Campaign, CourseOfAction, CustomObject, from .sdo import (
Identity, Indicator, IntrusionSet, Location, Malware, Note, AttackPattern, Campaign, CourseOfAction, CustomObject, Identity, Indicator,
ObservedData, Opinion, Report, ThreatActor, Tool, IntrusionSet, Location, Malware, Note, ObservedData, Opinion, Report,
Vulnerability) ThreatActor, Tool, Vulnerability,
)
from .sro import Relationship, Sighting from .sro import Relationship, Sighting
OBJ_MAP = { OBJ_MAP = {
@ -74,7 +75,7 @@ EXT_MAP = {
'ntfs-ext': NTFSExt, 'ntfs-ext': NTFSExt,
'pdf-ext': PDFExt, 'pdf-ext': PDFExt,
'raster-image-ext': RasterImageExt, 'raster-image-ext': RasterImageExt,
'windows-pebinary-ext': WindowsPEBinaryExt 'windows-pebinary-ext': WindowsPEBinaryExt,
}, },
'network-traffic': { 'network-traffic': {
'http-request-ext': HTTPRequestExt, 'http-request-ext': HTTPRequestExt,

Some files were not shown because too many files have changed in this diff Show More