parent
e0aa8abd0c
commit
51a499cb33
|
@ -49,7 +49,7 @@ html_sidebars = {
|
|||
'navigation.html',
|
||||
'relations.html',
|
||||
'searchbox.html',
|
||||
]
|
||||
],
|
||||
}
|
||||
|
||||
latex_elements = {}
|
||||
|
|
|
@ -7,8 +7,10 @@ import stix2
|
|||
|
||||
|
||||
def main():
|
||||
collection = Collection("http://127.0.0.1:5000/trustgroup1/collections/52892447-4d7e-4f70-b94d-d7f22742ff63/",
|
||||
user="admin", password="Password0")
|
||||
collection = Collection(
|
||||
"http://127.0.0.1:5000/trustgroup1/collections/52892447-4d7e-4f70-b94d-d7f22742ff63/",
|
||||
user="admin", password="Password0",
|
||||
)
|
||||
|
||||
# instantiate TAXII data source
|
||||
taxii = stix2.TAXIICollectionSource(collection)
|
||||
|
|
4
setup.py
4
setup.py
|
@ -55,6 +55,6 @@ setup(
|
|||
'stix2-patterns',
|
||||
],
|
||||
extras_require={
|
||||
'taxii': ['taxii2-client']
|
||||
}
|
||||
'taxii': ['taxii2-client'],
|
||||
},
|
||||
)
|
||||
|
|
|
@ -37,34 +37,42 @@
|
|||
from .core import _collect_stix2_mappings, parse, parse_observable
|
||||
from .v21 import * # This import will always be the latest STIX 2.X version
|
||||
from .datastore import CompositeDataSource
|
||||
from .datastore.filesystem import (FileSystemSink, FileSystemSource,
|
||||
FileSystemStore)
|
||||
from .datastore.filesystem import (
|
||||
FileSystemSink, FileSystemSource,
|
||||
FileSystemStore
|
||||
)
|
||||
from .datastore.filters import Filter
|
||||
from .datastore.memory import MemorySink, MemorySource, MemoryStore
|
||||
from .datastore.taxii import (TAXIICollectionSink, TAXIICollectionSource,
|
||||
TAXIICollectionStore)
|
||||
from .datastore.taxii import (
|
||||
TAXIICollectionSink, TAXIICollectionSource,
|
||||
TAXIICollectionStore
|
||||
)
|
||||
from .environment import Environment, ObjectFactory
|
||||
from .markings import (add_markings, clear_markings, get_markings, is_marked,
|
||||
remove_markings, set_markings)
|
||||
from .patterns import (AndBooleanExpression, AndObservationExpression,
|
||||
BasicObjectPathComponent, BinaryConstant,
|
||||
BooleanConstant, EqualityComparisonExpression,
|
||||
FloatConstant, FollowedByObservationExpression,
|
||||
GreaterThanComparisonExpression,
|
||||
GreaterThanEqualComparisonExpression, HashConstant,
|
||||
HexConstant, InComparisonExpression, IntegerConstant,
|
||||
IsSubsetComparisonExpression,
|
||||
IsSupersetComparisonExpression,
|
||||
LessThanComparisonExpression,
|
||||
LessThanEqualComparisonExpression,
|
||||
LikeComparisonExpression, ListConstant,
|
||||
ListObjectPathComponent, MatchesComparisonExpression,
|
||||
ObjectPath, ObservationExpression, OrBooleanExpression,
|
||||
OrObservationExpression, ParentheticalExpression,
|
||||
QualifiedObservationExpression,
|
||||
ReferenceObjectPathComponent, RepeatQualifier,
|
||||
StartStopQualifier, StringConstant, TimestampConstant,
|
||||
WithinQualifier)
|
||||
from .markings import (
|
||||
add_markings, clear_markings, get_markings, is_marked,
|
||||
remove_markings, set_markings
|
||||
)
|
||||
from .patterns import (
|
||||
AndBooleanExpression, AndObservationExpression,
|
||||
BasicObjectPathComponent, BinaryConstant,
|
||||
BooleanConstant, EqualityComparisonExpression,
|
||||
FloatConstant, FollowedByObservationExpression,
|
||||
GreaterThanComparisonExpression,
|
||||
GreaterThanEqualComparisonExpression, HashConstant,
|
||||
HexConstant, InComparisonExpression, IntegerConstant,
|
||||
IsSubsetComparisonExpression,
|
||||
IsSupersetComparisonExpression,
|
||||
LessThanComparisonExpression,
|
||||
LessThanEqualComparisonExpression,
|
||||
LikeComparisonExpression, ListConstant,
|
||||
ListObjectPathComponent, MatchesComparisonExpression,
|
||||
ObjectPath, ObservationExpression, OrBooleanExpression,
|
||||
OrObservationExpression, ParentheticalExpression,
|
||||
QualifiedObservationExpression,
|
||||
ReferenceObjectPathComponent, RepeatQualifier,
|
||||
StartStopQualifier, StringConstant, TimestampConstant,
|
||||
WithinQualifier
|
||||
)
|
||||
from .utils import new_version, revoke
|
||||
from .version import __version__
|
||||
|
||||
|
|
|
@ -6,11 +6,12 @@ import datetime as dt
|
|||
|
||||
import simplejson as json
|
||||
|
||||
from .exceptions import (AtLeastOnePropertyError, CustomContentError,
|
||||
DependentPropertiesError, ExtraPropertiesError,
|
||||
ImmutableError, InvalidObjRefError, InvalidValueError,
|
||||
MissingPropertiesError,
|
||||
MutuallyExclusivePropertiesError)
|
||||
from .exceptions import (
|
||||
AtLeastOnePropertyError, CustomContentError, DependentPropertiesError,
|
||||
ExtraPropertiesError, ImmutableError, InvalidObjRefError,
|
||||
InvalidValueError, MissingPropertiesError,
|
||||
MutuallyExclusivePropertiesError,
|
||||
)
|
||||
from .markings.utils import validate
|
||||
from .utils import NOW, find_property_index, format_datetime, get_timestamp
|
||||
from .utils import new_version as _new_version
|
||||
|
@ -206,8 +207,10 @@ class _STIXBase(collections.Mapping):
|
|||
|
||||
def __repr__(self):
|
||||
props = [(k, self[k]) for k in self.object_properties() if self.get(k)]
|
||||
return '{0}({1})'.format(self.__class__.__name__,
|
||||
', '.join(['{0!s}={1!r}'.format(k, v) for k, v in props]))
|
||||
return '{0}({1})'.format(
|
||||
self.__class__.__name__,
|
||||
', '.join(['{0!s}={1!r}'.format(k, v) for k, v in props]),
|
||||
)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
# Assume: we can ignore the memo argument, because no object will ever contain the same sub-object multiple times.
|
||||
|
|
|
@ -254,8 +254,10 @@ def _register_observable_extension(observable, new_extension, version=None):
|
|||
try:
|
||||
observable_type = observable._type
|
||||
except AttributeError:
|
||||
raise ValueError("Unknown observable type. Custom observables must be "
|
||||
"created with the @CustomObservable decorator.")
|
||||
raise ValueError(
|
||||
"Unknown observable type. Custom observables must be "
|
||||
"created with the @CustomObservable decorator.",
|
||||
)
|
||||
|
||||
OBJ_MAP_OBSERVABLE = STIX2_OBJ_MAPS[v]['observables']
|
||||
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
|
||||
except KeyError:
|
||||
if observable_type not in OBJ_MAP_OBSERVABLE:
|
||||
raise ValueError("Unknown observable type '%s'. Custom observables "
|
||||
"must be created with the @CustomObservable decorator."
|
||||
% observable_type)
|
||||
raise ValueError(
|
||||
"Unknown observable type '%s'. Custom observables "
|
||||
"must be created with the @CustomObservable decorator."
|
||||
% observable_type,
|
||||
)
|
||||
else:
|
||||
EXT_MAP[observable_type] = {new_extension._type: new_extension}
|
||||
|
||||
|
|
|
@ -2,8 +2,10 @@ from collections import OrderedDict
|
|||
import re
|
||||
|
||||
from .base import _Extension, _Observable, _STIXBase
|
||||
from .core import (STIXDomainObject, _register_marking, _register_object,
|
||||
_register_observable, _register_observable_extension)
|
||||
from .core import (
|
||||
STIXDomainObject, _register_marking, _register_object,
|
||||
_register_observable, _register_observable_extension,
|
||||
)
|
||||
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):
|
||||
|
||||
if not re.match(TYPE_REGEX, type):
|
||||
raise ValueError("Invalid type name '%s': must only contain the "
|
||||
"characters a-z (lowercase ASCII), 0-9, and hyphen (-)." % type)
|
||||
raise ValueError(
|
||||
"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:
|
||||
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):
|
||||
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)
|
||||
except (AttributeError, TypeError) as e:
|
||||
# Don't accidentally catch errors raised in a custom __init__()
|
||||
if ("has no attribute '__init__'" in str(e) or
|
||||
str(e) == "object.__init__() takes no parameters"):
|
||||
if (
|
||||
"has no attribute '__init__'" in str(e) or
|
||||
str(e) == "object.__init__() takes no parameters"
|
||||
):
|
||||
return
|
||||
raise e
|
||||
|
||||
|
@ -53,8 +60,10 @@ def _custom_marking_builder(cls, type, properties, version):
|
|||
cls.__init__(self, **kwargs)
|
||||
except (AttributeError, TypeError) as e:
|
||||
# Don't accidentally catch errors raised in a custom __init__()
|
||||
if ("has no attribute '__init__'" in str(e) or
|
||||
str(e) == "object.__init__() takes no parameters"):
|
||||
if (
|
||||
"has no attribute '__init__'" in str(e) or
|
||||
str(e) == "object.__init__() takes no parameters"
|
||||
):
|
||||
return
|
||||
raise e
|
||||
|
||||
|
@ -66,8 +75,10 @@ def _custom_observable_builder(cls, type, properties, version):
|
|||
class _CustomObservable(cls, _Observable):
|
||||
|
||||
if not re.match(TYPE_REGEX, type):
|
||||
raise ValueError("Invalid observable type name '%s': must only contain the "
|
||||
"characters a-z (lowercase ASCII), 0-9, and hyphen (-)." % type)
|
||||
raise ValueError(
|
||||
"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:
|
||||
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
|
||||
for prop_name, prop in properties:
|
||||
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 "
|
||||
"is not an ObjectReferenceProperty." % prop_name)
|
||||
raise ValueError(
|
||||
"'%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)
|
||||
or 'ObjectReferenceProperty' not in get_class_hierarchy_names(prop.contained))):
|
||||
raise ValueError("'%s' is named like an object reference list property but "
|
||||
"is not a ListProperty containing ObjectReferenceProperty." % prop_name)
|
||||
raise ValueError(
|
||||
"'%s' is named like an object reference list property but "
|
||||
"is not a ListProperty containing ObjectReferenceProperty." % prop_name,
|
||||
)
|
||||
|
||||
_type = type
|
||||
_properties = OrderedDict(properties)
|
||||
|
@ -93,8 +108,10 @@ def _custom_observable_builder(cls, type, properties, version):
|
|||
cls.__init__(self, **kwargs)
|
||||
except (AttributeError, TypeError) as e:
|
||||
# Don't accidentally catch errors raised in a custom __init__()
|
||||
if ("has no attribute '__init__'" in str(e) or
|
||||
str(e) == "object.__init__() takes no parameters"):
|
||||
if (
|
||||
"has no attribute '__init__'" in str(e) or
|
||||
str(e) == "object.__init__() takes no parameters"
|
||||
):
|
||||
return
|
||||
raise e
|
||||
|
||||
|
@ -109,8 +126,10 @@ def _custom_extension_builder(cls, observable, type, properties, version):
|
|||
class _CustomExtension(cls, _Extension):
|
||||
|
||||
if not re.match(TYPE_REGEX, type):
|
||||
raise ValueError("Invalid extension type name '%s': must only contain the "
|
||||
"characters a-z (lowercase ASCII), 0-9, and hyphen (-)." % type)
|
||||
raise ValueError(
|
||||
"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:
|
||||
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)
|
||||
except (AttributeError, TypeError) as e:
|
||||
# Don't accidentally catch errors raised in a custom __init__()
|
||||
if ("has no attribute '__init__'" in str(e) or
|
||||
str(e) == "object.__init__() takes no parameters"):
|
||||
if (
|
||||
"has no attribute '__init__'" in str(e) or
|
||||
str(e) == "object.__init__() takes no parameters"
|
||||
):
|
||||
return
|
||||
raise e
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ class FileSystemStore(DataStoreMixin):
|
|||
|
||||
super(FileSystemStore, self).__init__(
|
||||
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)
|
||||
|
||||
else:
|
||||
raise TypeError("stix_data must be a STIX object (or list of), "
|
||||
"JSON formatted STIX (or list of), "
|
||||
"or a JSON formatted STIX bundle")
|
||||
raise TypeError(
|
||||
"stix_data must be a STIX object (or list of), "
|
||||
"JSON formatted STIX (or list of), "
|
||||
"or a JSON formatted STIX bundle",
|
||||
)
|
||||
|
||||
|
||||
class FileSystemSource(DataSource):
|
||||
|
|
|
@ -81,7 +81,7 @@ class MemoryStore(DataStoreMixin):
|
|||
|
||||
super(MemoryStore, self).__init__(
|
||||
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):
|
||||
|
|
|
@ -4,8 +4,9 @@ from requests.exceptions import HTTPError
|
|||
from stix2 import Bundle, v20
|
||||
from stix2.base import _STIXBase
|
||||
from stix2.core import parse
|
||||
from stix2.datastore import (DataSink, DataSource, DataSourceError,
|
||||
DataStoreMixin)
|
||||
from stix2.datastore import (
|
||||
DataSink, DataSource, DataSourceError, DataStoreMixin,
|
||||
)
|
||||
from stix2.datastore.filters import Filter, FilterSet, apply_common_filters
|
||||
from stix2.utils import deduplicate
|
||||
|
||||
|
@ -42,7 +43,7 @@ class TAXIICollectionStore(DataStoreMixin):
|
|||
|
||||
super(TAXIICollectionStore, self).__init__(
|
||||
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:
|
||||
self.collection = collection
|
||||
else:
|
||||
raise DataSourceError("The TAXII Collection object provided does not have write access"
|
||||
" to the underlying linked Collection resource")
|
||||
raise DataSourceError(
|
||||
"The TAXII Collection object provided does not have write access"
|
||||
" to the underlying linked Collection resource",
|
||||
)
|
||||
|
||||
except (HTTPError, ValidationError) as e:
|
||||
raise DataSourceError("The underlying TAXII Collection resource defined in the supplied TAXII"
|
||||
" Collection object provided could not be reached. Receved error:", e)
|
||||
raise DataSourceError(
|
||||
"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
|
||||
|
||||
|
@ -146,12 +151,16 @@ class TAXIICollectionSource(DataSource):
|
|||
if collection.can_read:
|
||||
self.collection = collection
|
||||
else:
|
||||
raise DataSourceError("The TAXII Collection object provided does not have read access"
|
||||
" to the underlying linked Collection resource")
|
||||
raise DataSourceError(
|
||||
"The TAXII Collection object provided does not have read access"
|
||||
" to the underlying linked Collection resource",
|
||||
)
|
||||
|
||||
except (HTTPError, ValidationError) as e:
|
||||
raise DataSourceError("The underlying TAXII Collection resource defined in the supplied TAXII"
|
||||
" Collection object provided could not be reached. Recieved error:", e)
|
||||
raise DataSourceError(
|
||||
"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
|
||||
|
||||
|
@ -218,7 +227,7 @@ class TAXIICollectionSource(DataSource):
|
|||
# make query in TAXII query format since 'id' is TAXII field
|
||||
query = [
|
||||
Filter('id', '=', stix_id),
|
||||
Filter('version', '=', 'all')
|
||||
Filter('version', '=', 'all'),
|
||||
]
|
||||
|
||||
all_data = self.query(query=query, _composite_filters=_composite_filters)
|
||||
|
@ -277,9 +286,11 @@ class TAXIICollectionSource(DataSource):
|
|||
except HTTPError as e:
|
||||
# if resources not found or access is denied from TAXII server, return empty list
|
||||
if e.response.status_code == 404:
|
||||
raise DataSourceError("The requested STIX objects for the TAXII Collection resource defined in"
|
||||
" the supplied TAXII Collection object are either not found or access is"
|
||||
" denied. Received error: ", e)
|
||||
raise DataSourceError(
|
||||
"The requested STIX objects for the TAXII Collection resource defined in"
|
||||
" 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
|
||||
stix_objs = [parse(stix_obj_dict, allow_custom=self.allow_custom) for stix_obj_dict in all_data]
|
||||
|
|
|
@ -27,9 +27,11 @@ class ObjectFactory(object):
|
|||
default. Defaults to True.
|
||||
"""
|
||||
|
||||
def __init__(self, created_by_ref=None, created=None,
|
||||
external_references=None, object_marking_refs=None,
|
||||
list_append=True):
|
||||
def __init__(
|
||||
self, created_by_ref=None, created=None,
|
||||
external_references=None, object_marking_refs=None,
|
||||
list_append=True,
|
||||
):
|
||||
|
||||
self._defaults = {}
|
||||
if created_by_ref:
|
||||
|
|
|
@ -30,8 +30,10 @@ class MissingPropertiesError(STIXError, ValueError):
|
|||
|
||||
def __str__(self):
|
||||
msg = "No values for required properties for {0}: ({1})."
|
||||
return msg.format(self.cls.__name__,
|
||||
", ".join(x for x in self.properties))
|
||||
return msg.format(
|
||||
self.cls.__name__,
|
||||
", ".join(x for x in self.properties),
|
||||
)
|
||||
|
||||
|
||||
class ExtraPropertiesError(STIXError, TypeError):
|
||||
|
@ -44,8 +46,10 @@ class ExtraPropertiesError(STIXError, TypeError):
|
|||
|
||||
def __str__(self):
|
||||
msg = "Unexpected properties for {0}: ({1})."
|
||||
return msg.format(self.cls.__name__,
|
||||
", ".join(x for x in self.properties))
|
||||
return msg.format(
|
||||
self.cls.__name__,
|
||||
", ".join(x for x in self.properties),
|
||||
)
|
||||
|
||||
|
||||
class ImmutableError(STIXError, ValueError):
|
||||
|
@ -110,8 +114,10 @@ class MutuallyExclusivePropertiesError(STIXError, TypeError):
|
|||
|
||||
def __str__(self):
|
||||
msg = "The ({1}) properties for {0} are mutually exclusive."
|
||||
return msg.format(self.cls.__name__,
|
||||
", ".join(x for x in self.properties))
|
||||
return msg.format(
|
||||
self.cls.__name__,
|
||||
", ".join(x for x in self.properties),
|
||||
)
|
||||
|
||||
|
||||
class DependentPropertiesError(STIXError, TypeError):
|
||||
|
@ -124,8 +130,10 @@ class DependentPropertiesError(STIXError, TypeError):
|
|||
|
||||
def __str__(self):
|
||||
msg = "The property dependencies for {0}: ({1}) are not met."
|
||||
return msg.format(self.cls.__name__,
|
||||
", ".join(name for x in self.dependencies for name in x))
|
||||
return msg.format(
|
||||
self.cls.__name__,
|
||||
", ".join(name for x in self.dependencies for name in x),
|
||||
)
|
||||
|
||||
|
||||
class AtLeastOnePropertyError(STIXError, TypeError):
|
||||
|
@ -138,8 +146,10 @@ class AtLeastOnePropertyError(STIXError, TypeError):
|
|||
|
||||
def __str__(self):
|
||||
msg = "At least one of the ({1}) properties for {0} must be populated."
|
||||
return msg.format(self.cls.__name__,
|
||||
", ".join(x for x in self.properties))
|
||||
return msg.format(
|
||||
self.cls.__name__,
|
||||
", ".join(x for x in self.properties),
|
||||
)
|
||||
|
||||
|
||||
class RevokeError(STIXError, ValueError):
|
||||
|
|
|
@ -51,7 +51,7 @@ def get_markings(obj, selectors=None, inherited=False, descendants=False):
|
|||
obj,
|
||||
selectors,
|
||||
inherited,
|
||||
descendants
|
||||
descendants,
|
||||
)
|
||||
|
||||
if inherited:
|
||||
|
@ -208,7 +208,7 @@ def is_marked(obj, marking=None, selectors=None, inherited=False, descendants=Fa
|
|||
marking,
|
||||
selectors,
|
||||
inherited,
|
||||
descendants
|
||||
descendants,
|
||||
)
|
||||
|
||||
if inherited:
|
||||
|
@ -221,7 +221,7 @@ def is_marked(obj, marking=None, selectors=None, inherited=False, descendants=Fa
|
|||
granular_marks,
|
||||
selectors,
|
||||
inherited,
|
||||
descendants
|
||||
descendants,
|
||||
)
|
||||
|
||||
result = result or object_markings.is_marked(obj, object_marks)
|
||||
|
|
|
@ -39,9 +39,11 @@ def get_markings(obj, selectors, inherited=False, descendants=False):
|
|||
for marking in granular_markings:
|
||||
for user_selector in selectors:
|
||||
for marking_selector in marking.get('selectors', []):
|
||||
if any([(user_selector == marking_selector), # Catch explicit selectors.
|
||||
(user_selector.startswith(marking_selector) and inherited), # Catch inherited selectors.
|
||||
(marking_selector.startswith(user_selector) and descendants)]): # Catch descendants selectors
|
||||
if any([
|
||||
(user_selector == marking_selector), # Catch explicit 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', [])
|
||||
results.update([refs])
|
||||
|
||||
|
@ -184,16 +186,17 @@ def clear_markings(obj, selectors):
|
|||
granular_markings = utils.expand_markings(granular_markings)
|
||||
|
||||
sdo = utils.build_granular_marking(
|
||||
[{'selectors': selectors, 'marking_ref': 'N/A'}]
|
||||
[{'selectors': selectors, 'marking_ref': 'N/A'}],
|
||||
)
|
||||
|
||||
clear = sdo.get('granular_markings', [])
|
||||
|
||||
if not any(clear_selector in sdo_selectors.get('selectors', [])
|
||||
for sdo_selectors in granular_markings
|
||||
for clear_marking in clear
|
||||
for clear_selector in clear_marking.get('selectors', [])
|
||||
):
|
||||
if not any(
|
||||
clear_selector in sdo_selectors.get('selectors', [])
|
||||
for sdo_selectors in granular_markings
|
||||
for clear_marking in clear
|
||||
for clear_selector in clear_marking.get('selectors', [])
|
||||
):
|
||||
raise exceptions.MarkingNotFoundError(obj, clear)
|
||||
|
||||
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 marking_selector in granular_marking.get('selectors', []):
|
||||
|
||||
if any([(user_selector == marking_selector), # Catch explicit selectors.
|
||||
(user_selector.startswith(marking_selector) and inherited), # Catch inherited selectors.
|
||||
(marking_selector.startswith(user_selector) and descendants)]): # Catch descendants selectors
|
||||
if any([
|
||||
(user_selector == marking_selector), # Catch explicit 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', '')
|
||||
|
||||
if marking and any(x == marking_ref for x in marking):
|
||||
|
|
|
@ -180,7 +180,7 @@ def expand_markings(granular_markings):
|
|||
[
|
||||
{'marking_ref': marking_ref, 'selectors': [selector]}
|
||||
for selector in selectors
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
return expanded
|
||||
|
|
|
@ -211,9 +211,11 @@ class ReferenceObjectPathComponent(_ObjectPathComponent):
|
|||
class ObjectPath(object):
|
||||
def __init__(self, object_type_name, property_path):
|
||||
self.object_type_name = object_type_name
|
||||
self.property_path = [x if isinstance(x, _ObjectPathComponent) else
|
||||
_ObjectPathComponent.create_ObjectPathComponent(x)
|
||||
for x in property_path]
|
||||
self.property_path = [
|
||||
x if isinstance(x, _ObjectPathComponent) else
|
||||
_ObjectPathComponent.create_ObjectPathComponent(x)
|
||||
for x in property_path
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return "%s:%s" % (self.object_type_name, ".".join(["%s" % x for x in self.property_path]))
|
||||
|
|
|
@ -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
|
||||
# component must be a 4, and the first hex digit of the fourth component
|
||||
# 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
|
||||
"[0-9a-fA-F]{8}-"
|
||||
"[0-9a-fA-F]{4}-"
|
||||
"4[0-9a-fA-F]{3}-"
|
||||
"[89abAB][0-9a-fA-F]{3}-"
|
||||
"[0-9a-fA-F]{12}$")
|
||||
ID_REGEX = re.compile(
|
||||
"^[a-z0-9][a-z0-9-]+[a-z0-9]--" # object type
|
||||
"[0-9a-fA-F]{8}-"
|
||||
"[0-9a-fA-F]{4}-"
|
||||
"4[0-9a-fA-F]{3}-"
|
||||
"[89abAB][0-9a-fA-F]{3}-"
|
||||
"[0-9a-fA-F]{12}$",
|
||||
)
|
||||
|
||||
ERROR_INVALID_ID = (
|
||||
"not a valid STIX identifier, must match <object-type>--<UUIDv4>"
|
||||
|
@ -271,9 +273,11 @@ class DictionaryProperty(Property):
|
|||
if len(k) > 250:
|
||||
raise DictionaryKeyError(k, "longer than 250 characters")
|
||||
if not re.match('^[a-zA-Z0-9_-]+$', k):
|
||||
msg = ("contains characters other than lowercase a-z, "
|
||||
"uppercase A-Z, numerals 0-9, hyphen (-), or "
|
||||
"underscore (_)")
|
||||
msg = (
|
||||
"contains characters other than lowercase a-z, "
|
||||
"uppercase A-Z, numerals 0-9, hyphen (-), or "
|
||||
"underscore (_)"
|
||||
)
|
||||
raise DictionaryKeyError(k, msg)
|
||||
return dictified
|
||||
|
||||
|
@ -435,10 +439,12 @@ class ObservableProperty(Property):
|
|||
valid_refs = dict((k, v['type']) for (k, v) in dictified.items())
|
||||
|
||||
for key, obj in dictified.items():
|
||||
parsed_obj = parse_observable(obj,
|
||||
valid_refs,
|
||||
allow_custom=self.allow_custom,
|
||||
version=self.spec_version)
|
||||
parsed_obj = parse_observable(
|
||||
obj,
|
||||
valid_refs,
|
||||
allow_custom=self.allow_custom,
|
||||
version=self.spec_version,
|
||||
)
|
||||
dictified[key] = parsed_obj
|
||||
|
||||
return dictified
|
||||
|
@ -509,9 +515,11 @@ class STIXObjectProperty(Property):
|
|||
# (spec_version). So this is a hack, and not technically spec-
|
||||
# compliant.
|
||||
if 'spec_version' in value and self.spec_version == '2.0':
|
||||
raise ValueError("Spec version 2.0 bundles don't yet support "
|
||||
"containing objects of a different spec "
|
||||
"version.")
|
||||
raise ValueError(
|
||||
"Spec version 2.0 bundles don't yet support "
|
||||
"containing objects of a different spec "
|
||||
"version.",
|
||||
)
|
||||
return value
|
||||
try:
|
||||
dictified = _get_dict(value)
|
||||
|
@ -523,8 +531,10 @@ class STIXObjectProperty(Property):
|
|||
raise ValueError("This property may not contain a Bundle object")
|
||||
if 'spec_version' in dictified and self.spec_version == '2.0':
|
||||
# See above comment regarding spec_version.
|
||||
raise ValueError("Spec version 2.0 bundles don't yet support "
|
||||
"containing objects of a different spec version.")
|
||||
raise ValueError(
|
||||
"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)
|
||||
|
||||
|
|
|
@ -4,8 +4,9 @@ import pytest
|
|||
|
||||
import stix2
|
||||
|
||||
from .constants import (FAKE_TIME, INDICATOR_KWARGS, MALWARE_KWARGS,
|
||||
RELATIONSHIP_KWARGS)
|
||||
from .constants import (
|
||||
FAKE_TIME, INDICATOR_KWARGS, MALWARE_KWARGS, RELATIONSHIP_KWARGS,
|
||||
)
|
||||
|
||||
|
||||
# Inspired by: http://stackoverflow.com/a/24006251
|
||||
|
@ -54,61 +55,61 @@ def stix_objs1():
|
|||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||
"labels": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
ind2 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||
"labels": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
ind3 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||
"labels": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.936Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
ind4 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||
"labels": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
ind5 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||
"labels": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
return [ind1, ind2, ind3, ind4, ind5]
|
||||
|
||||
|
@ -119,37 +120,37 @@ def stix_objs2():
|
|||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||
"labels": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-31T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
ind7 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||
"labels": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
ind8 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||
"labels": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
return [ind6, ind7, ind8]
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ MARKING_IDS = [
|
|||
RELATIONSHIP_IDS = [
|
||||
'relationship--06520621-5352-4e6a-b976-e8fa3d437ffd',
|
||||
'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
|
||||
|
@ -77,7 +77,7 @@ INTRUSION_SET_KWARGS = dict(
|
|||
|
||||
MALWARE_KWARGS = dict(
|
||||
labels=['ransomware'],
|
||||
name="Cryptolocker"
|
||||
name="Cryptolocker",
|
||||
)
|
||||
|
||||
MALWARE_MORE_KWARGS = dict(
|
||||
|
@ -87,7 +87,7 @@ MALWARE_MORE_KWARGS = dict(
|
|||
modified="2016-04-06T20:03:00.000Z",
|
||||
labels=['ransomware'],
|
||||
name="Cryptolocker",
|
||||
description="A ransomware related to ..."
|
||||
description="A ransomware related to ...",
|
||||
)
|
||||
|
||||
OBSERVED_DATA_KWARGS = dict(
|
||||
|
@ -98,8 +98,8 @@ OBSERVED_DATA_KWARGS = dict(
|
|||
"0": {
|
||||
"type": "windows-registry-key",
|
||||
"key": "HKEY_LOCAL_MACHINE\\System\\Foo\\Bar",
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
REPORT_KWARGS = dict(
|
||||
|
|
|
@ -31,7 +31,7 @@ def test_attack_pattern_example():
|
|||
name="Spear Phishing",
|
||||
external_references=[{
|
||||
"source_name": "capec",
|
||||
"external_id": "CAPEC-163"
|
||||
"external_id": "CAPEC-163",
|
||||
}],
|
||||
description="...",
|
||||
)
|
||||
|
@ -39,23 +39,25 @@ def test_attack_pattern_example():
|
|||
assert str(ap) == EXPECTED
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"type": "attack-pattern",
|
||||
"id": "attack-pattern--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
|
||||
"created": "2016-05-12T08:17:27.000Z",
|
||||
"modified": "2016-05-12T08:17:27.000Z",
|
||||
"description": "...",
|
||||
"external_references": [
|
||||
{
|
||||
"external_id": "CAPEC-163",
|
||||
"source_name": "capec"
|
||||
}
|
||||
],
|
||||
"name": "Spear Phishing",
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"type": "attack-pattern",
|
||||
"id": "attack-pattern--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
|
||||
"created": "2016-05-12T08:17:27.000Z",
|
||||
"modified": "2016-05-12T08:17:27.000Z",
|
||||
"description": "...",
|
||||
"external_references": [
|
||||
{
|
||||
"external_id": "CAPEC-163",
|
||||
"source_name": "capec",
|
||||
},
|
||||
],
|
||||
"name": "Spear Phishing",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_attack_pattern(data):
|
||||
ap = stix2.parse(data, version="2.0")
|
||||
|
||||
|
@ -76,7 +78,7 @@ def test_attack_pattern_invalid_labels():
|
|||
created="2016-05-12T08:17:27Z",
|
||||
modified="2016-05-12T08:17:27Z",
|
||||
name="Spear Phishing",
|
||||
labels=1
|
||||
labels=1,
|
||||
)
|
||||
|
||||
# TODO: Add other examples
|
||||
|
|
|
@ -55,8 +55,8 @@ EXPECTED_BUNDLE_DICT = {
|
|||
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
||||
"valid_from": "2017-01-01T12:34:56Z",
|
||||
"labels": [
|
||||
"malicious-activity"
|
||||
]
|
||||
"malicious-activity",
|
||||
],
|
||||
},
|
||||
{
|
||||
"type": "malware",
|
||||
|
@ -65,8 +65,8 @@ EXPECTED_BUNDLE_DICT = {
|
|||
"modified": "2017-01-01T12:34:56.000Z",
|
||||
"name": "Cryptolocker",
|
||||
"labels": [
|
||||
"ransomware"
|
||||
]
|
||||
"ransomware",
|
||||
],
|
||||
},
|
||||
{
|
||||
"type": "relationship",
|
||||
|
@ -75,9 +75,9 @@ EXPECTED_BUNDLE_DICT = {
|
|||
"modified": "2017-01-01T12:34:56.000Z",
|
||||
"relationship_type": "indicates",
|
||||
"source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
|
||||
"target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e"
|
||||
}
|
||||
]
|
||||
"target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -25,24 +25,26 @@ def test_campaign_example():
|
|||
created="2016-04-06T20:03:00Z",
|
||||
modified="2016-04-06T20:03:00Z",
|
||||
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
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"type": "campaign",
|
||||
"id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"created": "2016-04-06T20:03:00Z",
|
||||
"modified": "2016-04-06T20:03:00Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"description": "Campaign by Green Group against a series of targets in the financial services sector.",
|
||||
"name": "Green Group Attacks Against Finance",
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"type": "campaign",
|
||||
"id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"created": "2016-04-06T20:03:00Z",
|
||||
"modified": "2016-04-06T20:03:00Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"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):
|
||||
cmpn = stix2.parse(data, version="2.0")
|
||||
|
||||
|
|
|
@ -25,24 +25,26 @@ def test_course_of_action_example():
|
|||
created="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",
|
||||
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
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2016-04-06T20:03:48.000Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"description": "This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ...",
|
||||
"id": "course-of-action--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"modified": "2016-04-06T20:03:48.000Z",
|
||||
"name": "Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter",
|
||||
"type": "course-of-action"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2016-04-06T20:03:48.000Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"description": "This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ...",
|
||||
"id": "course-of-action--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"modified": "2016-04-06T20:03:48.000Z",
|
||||
"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):
|
||||
coa = stix2.parse(data, version="2.0")
|
||||
|
||||
|
|
|
@ -79,8 +79,9 @@ def test_identity_custom_property_allowed():
|
|||
assert identity.x_foo == "bar"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
"""{
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
"""{
|
||||
"type": "identity",
|
||||
"id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c",
|
||||
"created": "2015-12-21T19:59:11Z",
|
||||
|
@ -89,7 +90,8 @@ def test_identity_custom_property_allowed():
|
|||
"identity_class": "individual",
|
||||
"foo": "bar"
|
||||
}""",
|
||||
])
|
||||
],
|
||||
)
|
||||
def test_parse_identity_custom_property(data):
|
||||
with pytest.raises(stix2.exceptions.ExtraPropertiesError) as excinfo:
|
||||
stix2.parse(data, version="2.0")
|
||||
|
@ -114,7 +116,7 @@ def test_custom_properties_object_in_bundled_object():
|
|||
identity_class="individual",
|
||||
custom_properties={
|
||||
"x_foo": "bar",
|
||||
}
|
||||
},
|
||||
)
|
||||
bundle = stix2.v20.Bundle(obj, allow_custom=True)
|
||||
|
||||
|
@ -160,7 +162,7 @@ def test_custom_property_in_observed_data():
|
|||
artifact = stix2.v20.File(
|
||||
allow_custom=True,
|
||||
name='test',
|
||||
x_foo='bar'
|
||||
x_foo='bar',
|
||||
)
|
||||
observed_data = stix2.v20.ObservedData(
|
||||
allow_custom=True,
|
||||
|
@ -204,7 +206,7 @@ def test_custom_property_dict_in_observable_extension():
|
|||
'ntfs-ext': {
|
||||
'sid': 1,
|
||||
'x_foo': 'bar',
|
||||
}
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -216,7 +218,7 @@ def test_custom_property_dict_in_observable_extension():
|
|||
'allow_custom': True,
|
||||
'sid': 1,
|
||||
'x_foo': 'bar',
|
||||
}
|
||||
},
|
||||
},
|
||||
)
|
||||
observed_data = stix2.v20.ObservedData(
|
||||
|
@ -240,12 +242,12 @@ def test_identity_custom_property_edit_markings():
|
|||
marking_obj = stix2.v20.MarkingDefinition(
|
||||
id=MARKING_DEFINITION_ID,
|
||||
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(
|
||||
id=MARKING_DEFINITION_ID,
|
||||
definition_type="statement",
|
||||
definition=stix2.v20.StatementMarking(statement="Another one")
|
||||
definition=stix2.v20.StatementMarking(statement="Another one"),
|
||||
)
|
||||
|
||||
# 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():
|
||||
@stix2.v20.CustomMarking('x-new-obj', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v20.CustomMarking(
|
||||
'x-new-obj', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewObj():
|
||||
pass
|
||||
|
||||
|
@ -269,9 +273,11 @@ def test_custom_marking_no_init_1():
|
|||
|
||||
|
||||
def test_custom_marking_no_init_2():
|
||||
@stix2.v20.CustomMarking('x-new-obj2', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v20.CustomMarking(
|
||||
'x-new-obj2', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewObj2(object):
|
||||
pass
|
||||
|
||||
|
@ -279,10 +285,12 @@ def test_custom_marking_no_init_2():
|
|||
assert no2.property1 == 'something'
|
||||
|
||||
|
||||
@stix2.v20.CustomObject('x-new-type', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
])
|
||||
@stix2.v20.CustomObject(
|
||||
'x-new-type', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
],
|
||||
)
|
||||
class NewType(object):
|
||||
def __init__(self, property2=None, **kwargs):
|
||||
if property2 and property2 < 10:
|
||||
|
@ -312,9 +320,11 @@ def test_custom_object_type():
|
|||
|
||||
|
||||
def test_custom_object_no_init_1():
|
||||
@stix2.v20.CustomObject('x-new-obj', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v20.CustomObject(
|
||||
'x-new-obj', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewObj():
|
||||
pass
|
||||
|
||||
|
@ -323,9 +333,11 @@ def test_custom_object_no_init_1():
|
|||
|
||||
|
||||
def test_custom_object_no_init_2():
|
||||
@stix2.v20.CustomObject('x-new-obj2', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v20.CustomObject(
|
||||
'x-new-obj2', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewObj2(object):
|
||||
pass
|
||||
|
||||
|
@ -335,17 +347,21 @@ def test_custom_object_no_init_2():
|
|||
|
||||
def test_custom_object_invalid_type_name():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v20.CustomObject('x', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v20.CustomObject(
|
||||
'x', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewObj(object):
|
||||
pass # pragma: no cover
|
||||
assert "Invalid type name 'x': " in str(excinfo.value)
|
||||
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v20.CustomObject('x_new_object', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v20.CustomObject(
|
||||
'x_new_object', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewObj2(object):
|
||||
pass # pragma: no cover
|
||||
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"
|
||||
|
||||
|
||||
@stix2.v20.CustomObservable('x-new-observable', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
('x_property3', stix2.properties.BooleanProperty()),
|
||||
])
|
||||
@stix2.v20.CustomObservable(
|
||||
'x-new-observable', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
('x_property3', stix2.properties.BooleanProperty()),
|
||||
],
|
||||
)
|
||||
class NewObservable():
|
||||
def __init__(self, property2=None, **kwargs):
|
||||
if property2 and property2 < 10:
|
||||
|
@ -428,9 +446,11 @@ def test_custom_observable_raises_exception():
|
|||
|
||||
|
||||
def test_custom_observable_object_no_init_1():
|
||||
@stix2.v20.CustomObservable('x-new-observable', [
|
||||
('property1', stix2.properties.StringProperty()),
|
||||
])
|
||||
@stix2.v20.CustomObservable(
|
||||
'x-new-observable', [
|
||||
('property1', stix2.properties.StringProperty()),
|
||||
],
|
||||
)
|
||||
class NewObs():
|
||||
pass
|
||||
|
||||
|
@ -439,9 +459,11 @@ def test_custom_observable_object_no_init_1():
|
|||
|
||||
|
||||
def test_custom_observable_object_no_init_2():
|
||||
@stix2.v20.CustomObservable('x-new-obs2', [
|
||||
('property1', stix2.properties.StringProperty()),
|
||||
])
|
||||
@stix2.v20.CustomObservable(
|
||||
'x-new-obs2', [
|
||||
('property1', stix2.properties.StringProperty()),
|
||||
],
|
||||
)
|
||||
class NewObs2(object):
|
||||
pass
|
||||
|
||||
|
@ -451,17 +473,21 @@ def test_custom_observable_object_no_init_2():
|
|||
|
||||
def test_custom_observable_object_invalid_type_name():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v20.CustomObservable('x', [
|
||||
('property1', stix2.properties.StringProperty()),
|
||||
])
|
||||
@stix2.v20.CustomObservable(
|
||||
'x', [
|
||||
('property1', stix2.properties.StringProperty()),
|
||||
],
|
||||
)
|
||||
class NewObs(object):
|
||||
pass # pragma: no cover
|
||||
assert "Invalid observable type name 'x':" in str(excinfo.value)
|
||||
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v20.CustomObservable('x_new_obs', [
|
||||
('property1', stix2.properties.StringProperty()),
|
||||
])
|
||||
@stix2.v20.CustomObservable(
|
||||
'x_new_obs', [
|
||||
('property1', stix2.properties.StringProperty()),
|
||||
],
|
||||
)
|
||||
class NewObs2(object):
|
||||
pass # pragma: no cover
|
||||
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():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v20.CustomObservable('x-new-obs', [
|
||||
('property_ref', stix2.properties.StringProperty()),
|
||||
])
|
||||
@stix2.v20.CustomObservable(
|
||||
'x-new-obs', [
|
||||
('property_ref', stix2.properties.StringProperty()),
|
||||
],
|
||||
)
|
||||
class NewObs():
|
||||
pass
|
||||
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():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v20.CustomObservable('x-new-obs', [
|
||||
('property_refs', stix2.properties.StringProperty()),
|
||||
])
|
||||
@stix2.v20.CustomObservable(
|
||||
'x-new-obs', [
|
||||
('property_refs', stix2.properties.StringProperty()),
|
||||
],
|
||||
)
|
||||
class NewObs():
|
||||
pass
|
||||
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():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v20.CustomObservable('x-new-obs', [
|
||||
('property_refs', stix2.properties.ListProperty(stix2.properties.StringProperty)),
|
||||
])
|
||||
@stix2.v20.CustomObservable(
|
||||
'x-new-obs', [
|
||||
('property_refs', stix2.properties.ListProperty(stix2.properties.StringProperty)),
|
||||
],
|
||||
)
|
||||
class NewObs():
|
||||
pass
|
||||
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():
|
||||
@stix2.v20.CustomObservable('x-new-obs', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property_ref', stix2.properties.ObjectReferenceProperty(valid_types='email-addr')),
|
||||
])
|
||||
@stix2.v20.CustomObservable(
|
||||
'x-new-obs', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property_ref', stix2.properties.ObjectReferenceProperty(valid_types='email-addr')),
|
||||
],
|
||||
)
|
||||
class NewObs():
|
||||
pass
|
||||
|
||||
with pytest.raises(Exception) as excinfo:
|
||||
NewObs(_valid_refs=['1'],
|
||||
property1='something',
|
||||
property_ref='1')
|
||||
NewObs(
|
||||
_valid_refs=['1'],
|
||||
property1='something',
|
||||
property_ref='1',
|
||||
)
|
||||
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'
|
||||
|
||||
|
||||
@stix2.v20.CustomExtension(stix2.v20.DomainName, 'x-new-ext', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
])
|
||||
@stix2.v20.CustomExtension(
|
||||
stix2.v20.DomainName, 'x-new-ext', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
],
|
||||
)
|
||||
class NewExtension():
|
||||
def __init__(self, property2=None, **kwargs):
|
||||
if property2 and property2 < 10:
|
||||
|
@ -685,13 +723,15 @@ def test_custom_extension_wrong_observable_type():
|
|||
name="abc.txt",
|
||||
extensions={
|
||||
"ntfs-ext": ext,
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
assert 'Cannot determine extension type' in excinfo.value.reason
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
"""{
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
"""{
|
||||
"keys": [
|
||||
{
|
||||
"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):
|
||||
@stix2.v20.CustomExtension(stix2.v20.UserAccount, 'some-extension', [
|
||||
('keys', stix2.properties.ListProperty(stix2.properties.DictionaryProperty, required=True))
|
||||
])
|
||||
@stix2.v20.CustomExtension(
|
||||
stix2.v20.UserAccount, 'some-extension', [
|
||||
('keys', stix2.properties.ListProperty(stix2.properties.DictionaryProperty, required=True)),
|
||||
],
|
||||
)
|
||||
class SomeCustomExtension:
|
||||
pass
|
||||
|
||||
|
@ -717,9 +760,11 @@ def test_custom_extension_invalid_observable():
|
|||
class Foo(object):
|
||||
pass
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v20.CustomExtension(Foo, 'x-new-ext', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v20.CustomExtension(
|
||||
Foo, 'x-new-ext', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class FooExtension():
|
||||
pass # pragma: no cover
|
||||
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):
|
||||
pass
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v20.CustomExtension(Bar, 'x-new-ext', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v20.CustomExtension(
|
||||
Bar, 'x-new-ext', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class BarExtension():
|
||||
pass
|
||||
assert "Unknown observable type" in str(excinfo.value)
|
||||
|
@ -738,9 +785,11 @@ def test_custom_extension_invalid_observable():
|
|||
class Baz(stix2.v20.observables._Observable):
|
||||
_type = 'Baz'
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v20.CustomExtension(Baz, 'x-new-ext', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v20.CustomExtension(
|
||||
Baz, 'x-new-ext', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class BazExtension():
|
||||
pass
|
||||
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():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v20.CustomExtension(stix2.v20.File, 'x', {
|
||||
'property1': stix2.properties.StringProperty(required=True),
|
||||
})
|
||||
@stix2.v20.CustomExtension(
|
||||
stix2.v20.File, 'x', {
|
||||
'property1': stix2.properties.StringProperty(required=True),
|
||||
},
|
||||
)
|
||||
class FooExtension():
|
||||
pass # pragma: no cover
|
||||
assert "Invalid extension type name 'x':" in str(excinfo.value)
|
||||
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v20.CustomExtension(stix2.File, 'x_new_ext', {
|
||||
'property1': stix2.properties.StringProperty(required=True),
|
||||
})
|
||||
@stix2.v20.CustomExtension(
|
||||
stix2.File, 'x_new_ext', {
|
||||
'property1': stix2.properties.StringProperty(required=True),
|
||||
},
|
||||
)
|
||||
class BlaExtension():
|
||||
pass # pragma: no cover
|
||||
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():
|
||||
@stix2.v20.CustomExtension(stix2.v20.DomainName, 'x-new-extension', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v20.CustomExtension(
|
||||
stix2.v20.DomainName, 'x-new-extension', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewExt():
|
||||
pass
|
||||
|
||||
|
@ -801,9 +856,11 @@ def test_custom_extension_no_init_1():
|
|||
|
||||
|
||||
def test_custom_extension_no_init_2():
|
||||
@stix2.v20.CustomExtension(stix2.v20.DomainName, 'x-new-ext2', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v20.CustomExtension(
|
||||
stix2.v20.DomainName, 'x-new-ext2', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewExt2(object):
|
||||
pass
|
||||
|
||||
|
@ -863,8 +920,9 @@ def test_extension_property_location():
|
|||
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",
|
||||
"id": "x-example--336d8a9f-91f1-46c5-b142-6441bb9f8b8d",
|
||||
"created": "2018-06-12T16:20:58.059Z",
|
||||
|
@ -876,18 +934,23 @@ def test_extension_property_location():
|
|||
}
|
||||
}
|
||||
}""",
|
||||
])
|
||||
],
|
||||
)
|
||||
def test_custom_object_nested_dictionary(data):
|
||||
@stix2.v20.CustomObject('x-example', [
|
||||
('dictionary', stix2.properties.DictionaryProperty()),
|
||||
])
|
||||
@stix2.v20.CustomObject(
|
||||
'x-example', [
|
||||
('dictionary', stix2.properties.DictionaryProperty()),
|
||||
],
|
||||
)
|
||||
class Example(object):
|
||||
def __init__(self, **kwargs):
|
||||
pass
|
||||
|
||||
example = Example(id='x-example--336d8a9f-91f1-46c5-b142-6441bb9f8b8d',
|
||||
created='2018-06-12T16:20:58.059Z',
|
||||
modified='2018-06-12T16:20:58.059Z',
|
||||
dictionary={'key': {'key_b': 'value', 'key_a': 'value'}})
|
||||
example = Example(
|
||||
id='x-example--336d8a9f-91f1-46c5-b142-6441bb9f8b8d',
|
||||
created='2018-06-12T16:20:58.059Z',
|
||||
modified='2018-06-12T16:20:58.059Z',
|
||||
dictionary={'key': {'key_b': 'value', 'key_a': 'value'}},
|
||||
)
|
||||
|
||||
assert data == str(example)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import pytest
|
||||
|
||||
from stix2.datastore import (CompositeDataSource, DataSink, DataSource,
|
||||
DataStoreMixin)
|
||||
from stix2.datastore import (
|
||||
CompositeDataSource, DataSink, DataSource, DataStoreMixin,
|
||||
)
|
||||
from stix2.datastore.filters import Filter
|
||||
from stix2.test.v20.constants import CAMPAIGN_MORE_KWARGS
|
||||
|
||||
|
@ -46,15 +47,19 @@ def test_datastore_creator_of_raises():
|
|||
|
||||
def test_datastore_relationships_raises():
|
||||
with pytest.raises(AttributeError) as excinfo:
|
||||
DataStoreMixin().relationships(obj="indicator--00000000-0000-4000-8000-000000000001",
|
||||
target_only=True)
|
||||
DataStoreMixin().relationships(
|
||||
obj="indicator--00000000-0000-4000-8000-000000000001",
|
||||
target_only=True,
|
||||
)
|
||||
assert "DataStoreMixin has no data source to query" == str(excinfo.value)
|
||||
|
||||
|
||||
def test_datastore_related_to_raises():
|
||||
with pytest.raises(AttributeError) as excinfo:
|
||||
DataStoreMixin().related_to(obj="indicator--00000000-0000-4000-8000-000000000001",
|
||||
target_only=True)
|
||||
DataStoreMixin().related_to(
|
||||
obj="indicator--00000000-0000-4000-8000-000000000001",
|
||||
target_only=True,
|
||||
)
|
||||
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():
|
||||
with pytest.raises(AttributeError) as excinfo:
|
||||
CompositeDataSource().relationships(obj="indicator--00000000-0000-4000-8000-000000000001",
|
||||
target_only=True)
|
||||
CompositeDataSource().relationships(
|
||||
obj="indicator--00000000-0000-4000-8000-000000000001",
|
||||
target_only=True,
|
||||
)
|
||||
assert "CompositeDataSource has no data sources" == str(excinfo.value)
|
||||
|
||||
|
||||
def test_composite_datastore_related_to_raises_error():
|
||||
with pytest.raises(AttributeError) as excinfo:
|
||||
CompositeDataSource().related_to(obj="indicator--00000000-0000-4000-8000-000000000001",
|
||||
target_only=True)
|
||||
CompositeDataSource().related_to(
|
||||
obj="indicator--00000000-0000-4000-8000-000000000001",
|
||||
target_only=True,
|
||||
)
|
||||
assert "CompositeDataSource has no data sources" == str(excinfo.value)
|
||||
|
||||
|
||||
|
|
|
@ -13,8 +13,10 @@ def test_add_remove_composite_datasource():
|
|||
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
cds.add_data_sources([ds1, ds2, ds1, ds3])
|
||||
assert str(excinfo.value) == ("DataSource (to be added) is not of type "
|
||||
"stix2.DataSource. DataSource type is '<class 'stix2.datastore.memory.MemorySink'>'")
|
||||
assert str(excinfo.value) == (
|
||||
"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])
|
||||
|
||||
|
@ -26,10 +28,12 @@ def test_add_remove_composite_datasource():
|
|||
|
||||
|
||||
def test_composite_datasource_operations(stix_objs1, stix_objs2):
|
||||
BUNDLE1 = dict(id="bundle--%s" % make_id(),
|
||||
objects=stix_objs1,
|
||||
spec_version="2.0",
|
||||
type="bundle")
|
||||
BUNDLE1 = dict(
|
||||
id="bundle--%s" % make_id(),
|
||||
objects=stix_objs1,
|
||||
spec_version="2.0",
|
||||
type="bundle",
|
||||
)
|
||||
cds1 = CompositeDataSource()
|
||||
ds1_1 = MemorySource(stix_data=BUNDLE1)
|
||||
ds1_2 = MemorySource(stix_data=stix_objs2)
|
||||
|
@ -55,11 +59,11 @@ def test_composite_datasource_operations(stix_objs1, stix_objs2):
|
|||
assert indicator["type"] == "indicator"
|
||||
|
||||
query1 = [
|
||||
Filter("type", "=", "indicator")
|
||||
Filter("type", "=", "indicator"),
|
||||
]
|
||||
|
||||
query2 = [
|
||||
Filter("valid_from", "=", "2017-01-27T13:49:53.935382Z")
|
||||
Filter("valid_from", "=", "2017-01-27T13:49:53.935382Z"),
|
||||
]
|
||||
|
||||
cds1.filters.add(query2)
|
||||
|
|
|
@ -5,11 +5,10 @@ import shutil
|
|||
import pytest
|
||||
|
||||
import stix2
|
||||
from stix2.test.v20.constants import (CAMPAIGN_ID, CAMPAIGN_KWARGS,
|
||||
IDENTITY_ID, IDENTITY_KWARGS,
|
||||
INDICATOR_ID, INDICATOR_KWARGS,
|
||||
MALWARE_ID, MALWARE_KWARGS,
|
||||
RELATIONSHIP_IDS)
|
||||
from stix2.test.v20.constants import (
|
||||
CAMPAIGN_ID, CAMPAIGN_KWARGS, IDENTITY_ID, IDENTITY_KWARGS, INDICATOR_ID,
|
||||
INDICATOR_KWARGS, MALWARE_ID, MALWARE_KWARGS, RELATIONSHIP_IDS,
|
||||
)
|
||||
|
||||
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
|
||||
stix_obj = {
|
||||
"id": "intrusion-set--test-bad-stix",
|
||||
"spec_version": "2.0"
|
||||
"spec_version": "2.0",
|
||||
# no "type" field
|
||||
}
|
||||
|
||||
|
@ -178,7 +177,8 @@ def test_filesystem_sink_add_python_stix_object(fs_sink, fs_source):
|
|||
camp1 = stix2.v20.Campaign(
|
||||
name="Hannibal",
|
||||
objective="Targeting Italian and Spanish Diplomat internet accounts",
|
||||
aliases=["War Elephant"])
|
||||
aliases=["War Elephant"],
|
||||
)
|
||||
|
||||
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",
|
||||
"aliases": ["Purple Robes"],
|
||||
"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)
|
||||
|
@ -228,9 +228,9 @@ def test_filesystem_sink_add_stix_bundle_dict(fs_sink, fs_source):
|
|||
"objective": "Bulgarian, Albanian and Romanian Intelligence Services",
|
||||
"aliases": ["Huns"],
|
||||
"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)
|
||||
|
@ -282,7 +282,8 @@ def test_filesystem_sink_add_objects_list(fs_sink, fs_source):
|
|||
camp6 = stix2.v20.Campaign(
|
||||
name="Comanche",
|
||||
objective="US Midwest manufacturing firms, oil refineries, and businesses",
|
||||
aliases=["Horse Warrior"])
|
||||
aliases=["Horse Warrior"],
|
||||
)
|
||||
|
||||
camp7 = {
|
||||
"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",
|
||||
"aliases": ["The Frenchmen"],
|
||||
"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])
|
||||
|
@ -370,7 +371,8 @@ def test_filesystem_store_add(fs_store):
|
|||
camp1 = stix2.v20.Campaign(
|
||||
name="Great Heathen Army",
|
||||
objective="Targeting the government of United Kingdom and insitutions affiliated with the Church Of England",
|
||||
aliases=["Ragnar"])
|
||||
aliases=["Ragnar"],
|
||||
)
|
||||
fs_store.add(camp1)
|
||||
|
||||
camp1_r = fs_store.get(camp1.id)
|
||||
|
@ -387,7 +389,8 @@ def test_filesystem_store_add_as_bundle():
|
|||
camp1 = stix2.v20.Campaign(
|
||||
name="Great Heathen Army",
|
||||
objective="Targeting the government of United Kingdom and insitutions affiliated with the Church Of England",
|
||||
aliases=["Ragnar"])
|
||||
aliases=["Ragnar"],
|
||||
)
|
||||
fs_store.add(camp1)
|
||||
|
||||
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",
|
||||
objective="Defeat the Carthaginians",
|
||||
x_empire="Roman",
|
||||
allow_custom=True)
|
||||
allow_custom=True,
|
||||
)
|
||||
|
||||
fs_store.add(camp)
|
||||
|
||||
|
@ -434,7 +438,8 @@ def test_filesystem_object_with_custom_property_in_bundle(fs_store):
|
|||
name="Scipio Africanus",
|
||||
objective="Defeat the Carthaginians",
|
||||
x_empire="Roman",
|
||||
allow_custom=True)
|
||||
allow_custom=True,
|
||||
)
|
||||
|
||||
bundle = stix2.v20.Bundle(camp, allow_custom=True)
|
||||
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):
|
||||
@stix2.v20.CustomObject('x-new-obj', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v20.CustomObject(
|
||||
'x-new-obj', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewObj():
|
||||
pass
|
||||
|
||||
|
|
|
@ -10,23 +10,23 @@ stix_objs = [
|
|||
"description": "\n\nTITLE:\n\tPoison Ivy",
|
||||
"id": "malware--fdd60b30-b67c-41e3-b0b9-f01faf20d111",
|
||||
"labels": [
|
||||
"remote-access-trojan"
|
||||
"remote-access-trojan",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.997Z",
|
||||
"name": "Poison Ivy",
|
||||
"type": "malware"
|
||||
"type": "malware",
|
||||
},
|
||||
{
|
||||
"created": "2014-05-08T09:00:00.000Z",
|
||||
"id": "indicator--a932fcc6-e032-476c-826f-cb970a5a1ade",
|
||||
"labels": [
|
||||
"file-hash-watchlist"
|
||||
"file-hash-watchlist",
|
||||
],
|
||||
"modified": "2014-05-08T09:00:00.000Z",
|
||||
"name": "File hash for Poison Ivy variant",
|
||||
"pattern": "[file:hashes.'SHA-256' = 'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c']",
|
||||
"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",
|
||||
|
@ -34,20 +34,20 @@ stix_objs = [
|
|||
{
|
||||
"marking_ref": "marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed",
|
||||
"selectors": [
|
||||
"relationship_type"
|
||||
]
|
||||
}
|
||||
"relationship_type",
|
||||
],
|
||||
},
|
||||
],
|
||||
"id": "relationship--2f9a9aa9-108a-4333-83e2-4fb25add0463",
|
||||
"modified": "2014-05-08T09:00:00.000Z",
|
||||
"object_marking_refs": [
|
||||
"marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9"
|
||||
"marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
|
||||
],
|
||||
"relationship_type": "indicates",
|
||||
"revoked": True,
|
||||
"source_ref": "indicator--a932fcc6-e032-476c-826f-cb970a5a1ade",
|
||||
"target_ref": "malware--fdd60b30-b67c-41e3-b0b9-f01faf20d111",
|
||||
"type": "relationship"
|
||||
"type": "relationship",
|
||||
},
|
||||
{
|
||||
"id": "vulnerability--ee916c28-c7a4-4d0d-ad56-a8d357f89fef",
|
||||
|
@ -60,10 +60,10 @@ stix_objs = [
|
|||
"external_references": [
|
||||
{
|
||||
"source_name": "cve",
|
||||
"external_id": "CVE-2014-0160"
|
||||
}
|
||||
"external_id": "CVE-2014-0160",
|
||||
},
|
||||
],
|
||||
"labels": ["heartbleed", "has-logo"]
|
||||
"labels": ["heartbleed", "has-logo"],
|
||||
},
|
||||
{
|
||||
"type": "observed-data",
|
||||
|
@ -77,11 +77,11 @@ stix_objs = [
|
|||
"objects": {
|
||||
"0": {
|
||||
"type": "file",
|
||||
"name": "HAL 9000.exe"
|
||||
}
|
||||
}
|
||||
"name": "HAL 9000.exe",
|
||||
},
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
|
@ -414,8 +414,10 @@ def test_filters4():
|
|||
# Assert invalid Filter cannot be created
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
Filter("modified", "?", "2017-01-27T13:49:53.935Z")
|
||||
assert str(excinfo.value) == ("Filter operator '?' not supported "
|
||||
"for specified property: 'modified'")
|
||||
assert str(excinfo.value) == (
|
||||
"Filter operator '?' not supported "
|
||||
"for specified property: 'modified'"
|
||||
)
|
||||
|
||||
|
||||
def test_filters5(stix_objs2, real_stix_objs2):
|
||||
|
@ -455,7 +457,7 @@ def test_filters7(stix_objs2, real_stix_objs2):
|
|||
"0": {
|
||||
"type": "file",
|
||||
"hashes": {
|
||||
"SHA-256": "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f"
|
||||
"SHA-256": "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f",
|
||||
},
|
||||
"extensions": {
|
||||
"pdf-ext": {
|
||||
|
@ -465,14 +467,14 @@ def test_filters7(stix_objs2, real_stix_objs2):
|
|||
"Author": "Adobe Systems Incorporated",
|
||||
"Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh",
|
||||
"Producer": "Acrobat Distiller 3.01 for Power Macintosh",
|
||||
"CreationDate": "20070412090123-02"
|
||||
"CreationDate": "20070412090123-02",
|
||||
},
|
||||
"pdfid0": "DFCE52BD827ECF765649852119D",
|
||||
"pdfid1": "57A1E0F9ED2AE523E313C"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"pdfid1": "57A1E0F9ED2AE523E313C",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
stix_objects = list(stix_objs2) + [obsvd_data_obj]
|
||||
|
|
|
@ -5,108 +5,110 @@ import pytest
|
|||
|
||||
from stix2 import Filter, MemorySource, MemoryStore, properties
|
||||
from stix2.datastore import make_id
|
||||
from stix2.v20 import (Bundle, Campaign, CustomObject, Identity, Indicator,
|
||||
Malware, Relationship)
|
||||
from stix2.v20 import (
|
||||
Bundle, Campaign, CustomObject, Identity, Indicator, Malware, Relationship,
|
||||
)
|
||||
|
||||
from .constants import (CAMPAIGN_ID, CAMPAIGN_KWARGS, IDENTITY_ID,
|
||||
IDENTITY_KWARGS, INDICATOR_ID, INDICATOR_KWARGS,
|
||||
MALWARE_ID, MALWARE_KWARGS, RELATIONSHIP_IDS)
|
||||
from .constants import (
|
||||
CAMPAIGN_ID, CAMPAIGN_KWARGS, IDENTITY_ID, IDENTITY_KWARGS, INDICATOR_ID,
|
||||
INDICATOR_KWARGS, MALWARE_ID, MALWARE_KWARGS, RELATIONSHIP_IDS,
|
||||
)
|
||||
|
||||
IND1 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||
"labels": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
IND2 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||
"labels": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
IND3 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||
"labels": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.936Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
IND4 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||
"labels": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
IND5 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||
"labels": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
IND6 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||
"labels": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-31T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
IND7 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||
"labels": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
IND8 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||
"labels": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
|
||||
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):
|
||||
# Add bundle of items to sink
|
||||
mem_store.add(dict(id="bundle--%s" % make_id(),
|
||||
objects=STIX_OBJS2,
|
||||
spec_version="2.0",
|
||||
type="bundle"))
|
||||
mem_store.add(dict(
|
||||
id="bundle--%s" % make_id(),
|
||||
objects=STIX_OBJS2,
|
||||
spec_version="2.0",
|
||||
type="bundle",
|
||||
))
|
||||
|
||||
resp = mem_store.all_versions("indicator--00000000-0000-4000-8000-000000000001")
|
||||
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):
|
||||
camp = Campaign(name="Scipio Africanus",
|
||||
objective="Defeat the Carthaginians",
|
||||
x_empire="Roman",
|
||||
allow_custom=True)
|
||||
camp = Campaign(
|
||||
name="Scipio Africanus",
|
||||
objective="Defeat the Carthaginians",
|
||||
x_empire="Roman",
|
||||
allow_custom=True,
|
||||
)
|
||||
|
||||
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):
|
||||
camp = Campaign(name="Scipio Africanus",
|
||||
objective="Defeat the Carthaginians",
|
||||
x_empire="Roman",
|
||||
allow_custom=True)
|
||||
camp = Campaign(
|
||||
name="Scipio Africanus",
|
||||
objective="Defeat the Carthaginians",
|
||||
x_empire="Roman",
|
||||
allow_custom=True,
|
||||
)
|
||||
|
||||
bundle = Bundle(camp, allow_custom=True)
|
||||
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):
|
||||
@CustomObject('x-new-obj', [
|
||||
('property1', properties.StringProperty(required=True)),
|
||||
])
|
||||
@CustomObject(
|
||||
'x-new-obj', [
|
||||
('property1', properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewObj():
|
||||
pass
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ class MockTAXIICollectionEndpoint(Collection):
|
|||
objs = full_filter.process_filter(
|
||||
self.objects,
|
||||
("id", "type", "version"),
|
||||
[]
|
||||
[],
|
||||
)
|
||||
if objs:
|
||||
return stix2.v20.Bundle(objects=objs)
|
||||
|
@ -56,7 +56,7 @@ class MockTAXIICollectionEndpoint(Collection):
|
|||
objs = full_filter.process_filter(
|
||||
self.objects,
|
||||
("version",),
|
||||
[]
|
||||
[],
|
||||
)
|
||||
if objs:
|
||||
return stix2.v20.Bundle(objects=objs)
|
||||
|
@ -68,16 +68,18 @@ class MockTAXIICollectionEndpoint(Collection):
|
|||
|
||||
@pytest.fixture
|
||||
def collection(stix_objs1):
|
||||
mock = MockTAXIICollectionEndpoint(COLLECTION_URL, **{
|
||||
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
|
||||
"title": "Writable Collection",
|
||||
"description": "This collection is a dropbox for submitting indicators",
|
||||
"can_read": True,
|
||||
"can_write": True,
|
||||
"media_types": [
|
||||
"application/vnd.oasis.stix+json; version=2.0"
|
||||
]
|
||||
})
|
||||
mock = MockTAXIICollectionEndpoint(
|
||||
COLLECTION_URL, **{
|
||||
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
|
||||
"title": "Writable Collection",
|
||||
"description": "This collection is a dropbox for submitting indicators",
|
||||
"can_read": True,
|
||||
"can_write": True,
|
||||
"media_types": [
|
||||
"application/vnd.oasis.stix+json; version=2.0",
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
mock.objects.extend(stix_objs1)
|
||||
return mock
|
||||
|
@ -85,16 +87,18 @@ def collection(stix_objs1):
|
|||
|
||||
@pytest.fixture
|
||||
def collection_no_rw_access(stix_objs1):
|
||||
mock = MockTAXIICollectionEndpoint(COLLECTION_URL, **{
|
||||
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
|
||||
"title": "Not writeable or readable Collection",
|
||||
"description": "This collection is a dropbox for submitting indicators",
|
||||
"can_read": False,
|
||||
"can_write": False,
|
||||
"media_types": [
|
||||
"application/vnd.oasis.stix+json; version=2.0"
|
||||
]
|
||||
})
|
||||
mock = MockTAXIICollectionEndpoint(
|
||||
COLLECTION_URL, **{
|
||||
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
|
||||
"title": "Not writeable or readable Collection",
|
||||
"description": "This collection is a dropbox for submitting indicators",
|
||||
"can_read": False,
|
||||
"can_write": False,
|
||||
"media_types": [
|
||||
"application/vnd.oasis.stix+json; version=2.0",
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
mock.objects.extend(stix_objs1)
|
||||
return mock
|
||||
|
@ -117,7 +121,8 @@ def test_add_stix2_object(collection):
|
|||
goals=[
|
||||
"compromising environment NGOs",
|
||||
"water-hole attacks geared towards energy sector",
|
||||
])
|
||||
],
|
||||
)
|
||||
|
||||
tc_sink.add(ta)
|
||||
|
||||
|
@ -136,7 +141,8 @@ def test_add_stix2_with_custom_object(collection):
|
|||
"water-hole attacks geared towards energy sector",
|
||||
],
|
||||
foo="bar",
|
||||
allow_custom=True)
|
||||
allow_custom=True,
|
||||
)
|
||||
|
||||
tc_sink.add(ta)
|
||||
|
||||
|
@ -153,7 +159,8 @@ def test_add_list_object(collection, indicator):
|
|||
goals=[
|
||||
"compromising environment NGOs",
|
||||
"water-hole attacks geared towards energy sector",
|
||||
])
|
||||
],
|
||||
)
|
||||
|
||||
tc_sink.add([ta, indicator])
|
||||
|
||||
|
@ -170,7 +177,8 @@ def test_add_stix2_bundle_object(collection):
|
|||
goals=[
|
||||
"compromising environment NGOs",
|
||||
"water-hole attacks geared towards energy sector",
|
||||
])
|
||||
],
|
||||
)
|
||||
|
||||
tc_sink.add(stix2.v20.Bundle(objects=[ta]))
|
||||
|
||||
|
@ -210,13 +218,13 @@ def test_add_dict_object(collection):
|
|||
"name": "Teddy Bear",
|
||||
"goals": [
|
||||
"compromising environment NGOs",
|
||||
"water-hole attacks geared towards energy sector"
|
||||
"water-hole attacks geared towards energy sector",
|
||||
],
|
||||
"sophistication": "innovator",
|
||||
"resource_level": "government",
|
||||
"labels": [
|
||||
"nation-state"
|
||||
]
|
||||
"nation-state",
|
||||
],
|
||||
}
|
||||
|
||||
tc_sink.add(ta)
|
||||
|
@ -237,15 +245,15 @@ def test_add_dict_bundle_object(collection):
|
|||
"name": "Teddy Bear",
|
||||
"goals": [
|
||||
"compromising environment NGOs",
|
||||
"water-hole attacks geared towards energy sector"
|
||||
"water-hole attacks geared towards energy sector",
|
||||
],
|
||||
"sophistication": "innovator",
|
||||
"resource_level": "government",
|
||||
"labels": [
|
||||
"nation-state"
|
||||
]
|
||||
}
|
||||
]
|
||||
"nation-state",
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
tc_sink.add(ta)
|
||||
|
@ -272,7 +280,7 @@ def test_parse_taxii_filters(collection):
|
|||
Filter("added_after", "=", "2016-02-01T00:00:01.000Z"),
|
||||
Filter("id", "=", "taxii stix object ID"),
|
||||
Filter("type", "=", "taxii stix object ID"),
|
||||
Filter("version", "=", "first")
|
||||
Filter("version", "=", "first"),
|
||||
]
|
||||
|
||||
ds = stix2.TAXIICollectionSource(collection)
|
||||
|
|
|
@ -2,9 +2,11 @@ import pytest
|
|||
|
||||
import stix2
|
||||
|
||||
from .constants import (CAMPAIGN_ID, CAMPAIGN_KWARGS, FAKE_TIME, IDENTITY_ID,
|
||||
IDENTITY_KWARGS, INDICATOR_ID, INDICATOR_KWARGS,
|
||||
MALWARE_ID, MALWARE_KWARGS, RELATIONSHIP_IDS)
|
||||
from .constants import (
|
||||
CAMPAIGN_ID, CAMPAIGN_KWARGS, FAKE_TIME, IDENTITY_ID, IDENTITY_KWARGS,
|
||||
INDICATOR_ID, INDICATOR_KWARGS, MALWARE_ID, MALWARE_KWARGS,
|
||||
RELATIONSHIP_IDS,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -50,7 +52,8 @@ def test_object_factory_created():
|
|||
def test_object_factory_external_reference():
|
||||
ext_ref = stix2.v20.ExternalReference(
|
||||
source_name="ACME Threat Intel",
|
||||
description="Threat report")
|
||||
description="Threat report",
|
||||
)
|
||||
factory = stix2.ObjectFactory(external_references=ext_ref)
|
||||
ind = factory.create(stix2.v20.Indicator, **INDICATOR_KWARGS)
|
||||
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")
|
||||
mark_def = stix2.v20.MarkingDefinition(
|
||||
definition_type="statement",
|
||||
definition=stmt_marking)
|
||||
definition=stmt_marking,
|
||||
)
|
||||
factory = stix2.ObjectFactory(object_marking_refs=[mark_def, stix2.v20.TLP_AMBER])
|
||||
ind = factory.create(stix2.v20.Indicator, **INDICATOR_KWARGS)
|
||||
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():
|
||||
ext_ref = stix2.v20.ExternalReference(
|
||||
source_name="ACME Threat Intel",
|
||||
description="Threat report from ACME")
|
||||
description="Threat report from ACME",
|
||||
)
|
||||
ext_ref2 = stix2.v20.ExternalReference(
|
||||
source_name="Yet Another Threat Report",
|
||||
description="Threat report from YATR")
|
||||
description="Threat report from YATR",
|
||||
)
|
||||
ext_ref3 = stix2.v20.ExternalReference(
|
||||
source_name="Threat Report #3",
|
||||
description="One more threat report")
|
||||
description="One more threat report",
|
||||
)
|
||||
factory = stix2.ObjectFactory(external_references=ext_ref)
|
||||
ind = factory.create(stix2.v20.Indicator, external_references=ext_ref2, **INDICATOR_KWARGS)
|
||||
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():
|
||||
ext_ref = stix2.v20.ExternalReference(
|
||||
source_name="ACME Threat Intel",
|
||||
description="Threat report from ACME")
|
||||
description="Threat report from ACME",
|
||||
)
|
||||
ext_ref2 = stix2.v20.ExternalReference(
|
||||
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)
|
||||
ind = factory.create(stix2.v20.Indicator, external_references=ext_ref2, **INDICATOR_KWARGS)
|
||||
assert len(ind.external_references) == 1
|
||||
|
@ -107,8 +116,10 @@ def test_object_factory_list_replace():
|
|||
|
||||
|
||||
def test_environment_functions():
|
||||
env = stix2.Environment(stix2.ObjectFactory(created_by_ref=IDENTITY_ID),
|
||||
stix2.MemoryStore())
|
||||
env = stix2.Environment(
|
||||
stix2.ObjectFactory(created_by_ref=IDENTITY_ID),
|
||||
stix2.MemoryStore(),
|
||||
)
|
||||
|
||||
# Create a STIX object
|
||||
ind = env.create(stix2.v20.Indicator, id=INDICATOR_ID, **INDICATOR_KWARGS)
|
||||
|
@ -132,8 +143,10 @@ def test_environment_functions():
|
|||
assert len(resp) == 0
|
||||
|
||||
# See different results after adding filters to the environment
|
||||
env.add_filters([stix2.Filter('type', '=', 'indicator'),
|
||||
stix2.Filter('created_by_ref', '=', IDENTITY_ID)])
|
||||
env.add_filters([
|
||||
stix2.Filter('type', '=', 'indicator'),
|
||||
stix2.Filter('created_by_ref', '=', IDENTITY_ID),
|
||||
])
|
||||
env.add_filter(stix2.Filter('labels', '=', 'benign')) # should be 'malicious-activity'
|
||||
resp = env.get(INDICATOR_ID)
|
||||
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():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
stix2.Environment(factory=stix2.ObjectFactory(),
|
||||
store=stix2.MemoryStore(), sink=stix2.MemorySink)
|
||||
stix2.Environment(
|
||||
factory=stix2.ObjectFactory(),
|
||||
store=stix2.MemoryStore(), sink=stix2.MemorySink,
|
||||
)
|
||||
assert 'Data store already provided' in str(excinfo.value)
|
||||
|
||||
|
||||
|
@ -269,7 +284,7 @@ def test_relationships_no_id(ds):
|
|||
env = stix2.Environment(store=ds)
|
||||
mal = {
|
||||
"type": "malware",
|
||||
"name": "some variant"
|
||||
"name": "some variant",
|
||||
}
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
env.relationships(mal)
|
||||
|
@ -333,7 +348,7 @@ def test_related_to_no_id(ds):
|
|||
env = stix2.Environment(store=ds)
|
||||
mal = {
|
||||
"type": "malware",
|
||||
"name": "some variant"
|
||||
"name": "some variant",
|
||||
}
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
env.related_to(mal)
|
||||
|
|
|
@ -21,7 +21,7 @@ def test_external_reference_veris():
|
|||
source_name="veris",
|
||||
external_id="0001AA7F-C601-424A-B2B8-BE6C9F5164E7",
|
||||
hashes={
|
||||
"SHA-256": "6db12788c37247f2316052e142f42f4b259d6561751e5f401a1ae2a6df9c674b"
|
||||
"SHA-256": "6db12788c37247f2316052e142f42f4b259d6561751e5f401a1ae2a6df9c674b",
|
||||
},
|
||||
url="https://github.com/vz-risk/VCDB/blob/master/data/json/0001AA7F-C601-424A-B2B8-BE6C9F5164E7.json",
|
||||
)
|
||||
|
|
|
@ -21,11 +21,11 @@ def test_add_marking_mark_one_selector_multiple_refs():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
|
@ -36,44 +36,49 @@ def test_add_marking_mark_one_selector_multiple_refs():
|
|||
assert m in after["granular_markings"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
(
|
||||
Malware(**MALWARE_KWARGS),
|
||||
Malware(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "name"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS),
|
||||
MARKING_IDS[0],
|
||||
),
|
||||
(
|
||||
MALWARE_KWARGS,
|
||||
dict(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "name"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS),
|
||||
MARKING_IDS[0],
|
||||
),
|
||||
(
|
||||
Malware(**MALWARE_KWARGS),
|
||||
Malware(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "name"],
|
||||
"marking_ref": TLP_RED.id,
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS),
|
||||
TLP_RED,
|
||||
),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
(
|
||||
Malware(**MALWARE_KWARGS),
|
||||
Malware(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "name"],
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
MARKING_IDS[0],
|
||||
),
|
||||
(
|
||||
MALWARE_KWARGS,
|
||||
dict(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "name"],
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
MARKING_IDS[0],
|
||||
),
|
||||
(
|
||||
Malware(**MALWARE_KWARGS),
|
||||
Malware(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "name"],
|
||||
"marking_ref": TLP_RED.id,
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
TLP_RED,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_add_marking_mark_multiple_selector_one_refs(data):
|
||||
before = data[0]
|
||||
after = data[1]
|
||||
|
@ -92,12 +97,12 @@ def test_add_marking_mark_multiple_selector_multiple_refs():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "name"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["description", "name"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -112,7 +117,7 @@ def test_add_marking_mark_another_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
|
@ -121,7 +126,7 @@ def test_add_marking_mark_another_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "name"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
|
@ -137,7 +142,7 @@ def test_add_marking_mark_same_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
|
@ -146,7 +151,7 @@ def test_add_marking_mark_same_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
|
@ -157,17 +162,22 @@ def test_add_marking_mark_same_property_same_marking():
|
|||
assert m in after["granular_markings"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data,marking", [
|
||||
({"description": "test description"},
|
||||
[["title"], ["marking-definition--1", "marking-definition--2"],
|
||||
"", ["marking-definition--1", "marking-definition--2"],
|
||||
[], ["marking-definition--1", "marking-definition--2"],
|
||||
[""], ["marking-definition--1", "marking-definition--2"],
|
||||
["description"], [""],
|
||||
["description"], [],
|
||||
["description"], ["marking-definition--1", 456]
|
||||
])
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data,marking", [
|
||||
(
|
||||
{"description": "test description"},
|
||||
[
|
||||
["title"], ["marking-definition--1", "marking-definition--2"],
|
||||
"", ["marking-definition--1", "marking-definition--2"],
|
||||
[], ["marking-definition--1", "marking-definition--2"],
|
||||
[""], ["marking-definition--1", "marking-definition--2"],
|
||||
["description"], [""],
|
||||
["description"], [],
|
||||
["description"], ["marking-definition--1", 456],
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_add_marking_bad_selector(data, marking):
|
||||
with pytest.raises(AssertionError):
|
||||
markings.add_markings(data, marking[0], marking[1])
|
||||
|
@ -181,61 +191,61 @@ GET_MARKINGS_TEST_DATA = {
|
|||
"list value",
|
||||
{
|
||||
"g": "nested",
|
||||
"h": 45
|
||||
}
|
||||
"h": 45,
|
||||
},
|
||||
],
|
||||
"x": {
|
||||
"y": [
|
||||
"hello",
|
||||
88
|
||||
88,
|
||||
],
|
||||
"z": {
|
||||
"foo1": "bar",
|
||||
"foo2": 65
|
||||
}
|
||||
"foo2": 65,
|
||||
},
|
||||
},
|
||||
"granular_markings": [
|
||||
{
|
||||
"marking_ref": "1",
|
||||
"selectors": ["a"]
|
||||
"selectors": ["a"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "2",
|
||||
"selectors": ["c"]
|
||||
"selectors": ["c"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "3",
|
||||
"selectors": ["c.[1]"]
|
||||
"selectors": ["c.[1]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "4",
|
||||
"selectors": ["c.[2]"]
|
||||
"selectors": ["c.[2]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "5",
|
||||
"selectors": ["c.[2].g"]
|
||||
"selectors": ["c.[2].g"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "6",
|
||||
"selectors": ["x"]
|
||||
"selectors": ["x"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "7",
|
||||
"selectors": ["x.y"]
|
||||
"selectors": ["x.y"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "8",
|
||||
"selectors": ["x.y.[1]"]
|
||||
"selectors": ["x.y.[1]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "9",
|
||||
"selectors": ["x.z"]
|
||||
"selectors": ["x.z"],
|
||||
},
|
||||
{
|
||||
"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"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
GET_MARKINGS_TEST_DATA,
|
||||
{"b": 1234},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
GET_MARKINGS_TEST_DATA,
|
||||
{"b": 1234},
|
||||
],
|
||||
)
|
||||
def test_get_markings_not_marked(data):
|
||||
"""Test selector that is not marked returns empty list."""
|
||||
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)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data,selector", [
|
||||
(GET_MARKINGS_TEST_DATA, "foo"),
|
||||
(GET_MARKINGS_TEST_DATA, ""),
|
||||
(GET_MARKINGS_TEST_DATA, []),
|
||||
(GET_MARKINGS_TEST_DATA, [""]),
|
||||
(GET_MARKINGS_TEST_DATA, "x.z.[-2]"),
|
||||
(GET_MARKINGS_TEST_DATA, "c.f"),
|
||||
(GET_MARKINGS_TEST_DATA, "c.[2].i"),
|
||||
(GET_MARKINGS_TEST_DATA, "c.[3]"),
|
||||
(GET_MARKINGS_TEST_DATA, "d"),
|
||||
(GET_MARKINGS_TEST_DATA, "x.[0]"),
|
||||
(GET_MARKINGS_TEST_DATA, "z.y.w"),
|
||||
(GET_MARKINGS_TEST_DATA, "x.z.[1]"),
|
||||
(GET_MARKINGS_TEST_DATA, "x.z.foo3")
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data,selector", [
|
||||
(GET_MARKINGS_TEST_DATA, "foo"),
|
||||
(GET_MARKINGS_TEST_DATA, ""),
|
||||
(GET_MARKINGS_TEST_DATA, []),
|
||||
(GET_MARKINGS_TEST_DATA, [""]),
|
||||
(GET_MARKINGS_TEST_DATA, "x.z.[-2]"),
|
||||
(GET_MARKINGS_TEST_DATA, "c.f"),
|
||||
(GET_MARKINGS_TEST_DATA, "c.[2].i"),
|
||||
(GET_MARKINGS_TEST_DATA, "c.[3]"),
|
||||
(GET_MARKINGS_TEST_DATA, "d"),
|
||||
(GET_MARKINGS_TEST_DATA, "x.[0]"),
|
||||
(GET_MARKINGS_TEST_DATA, "z.y.w"),
|
||||
(GET_MARKINGS_TEST_DATA, "x.z.[1]"),
|
||||
(GET_MARKINGS_TEST_DATA, "x.z.foo3"),
|
||||
],
|
||||
)
|
||||
def test_get_markings_bad_selector(data, selector):
|
||||
"""Test bad selectors raise exception"""
|
||||
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"])
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
(
|
||||
Malware(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
},
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
(
|
||||
Malware(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
[MARKING_IDS[0], MARKING_IDS[1]],
|
||||
),
|
||||
[MARKING_IDS[0], MARKING_IDS[1]],
|
||||
),
|
||||
(
|
||||
dict(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
},
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
(
|
||||
dict(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**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):
|
||||
before = markings.remove_markings(data[0], data[1], ["description"])
|
||||
assert "granular_markings" not in before
|
||||
|
@ -407,8 +423,8 @@ def test_remove_marking_remove_multiple_selector_one_ref():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -421,8 +437,8 @@ def test_remove_marking_mark_one_selector_from_multiple_ones():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -430,8 +446,8 @@ def test_remove_marking_mark_one_selector_from_multiple_ones():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -445,12 +461,12 @@ def test_remove_marking_mark_one_selector_markings_from_multiple_ones():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -458,12 +474,12 @@ def test_remove_marking_mark_one_selector_markings_from_multiple_ones():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -477,12 +493,12 @@ def test_remove_marking_mark_mutilple_selector_multiple_refs():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -495,8 +511,8 @@ def test_remove_marking_mark_another_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -504,12 +520,12 @@ def test_remove_marking_mark_another_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["modified"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -523,8 +539,8 @@ def test_remove_marking_mark_same_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -553,8 +569,8 @@ def test_remove_marking_not_present():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -567,15 +583,15 @@ IS_MARKED_TEST_DATA = [
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
{
|
||||
"selectors": ["labels", "description"],
|
||||
"marking_ref": MARKING_IDS[2]
|
||||
"marking_ref": MARKING_IDS[2],
|
||||
},
|
||||
{
|
||||
"selectors": ["labels", "description"],
|
||||
"marking_ref": MARKING_IDS[3]
|
||||
"marking_ref": MARKING_IDS[3],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
|
@ -584,15 +600,15 @@ IS_MARKED_TEST_DATA = [
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
{
|
||||
"selectors": ["labels", "description"],
|
||||
"marking_ref": MARKING_IDS[2]
|
||||
"marking_ref": MARKING_IDS[2],
|
||||
},
|
||||
{
|
||||
"selectors": ["labels", "description"],
|
||||
"marking_ref": MARKING_IDS[3]
|
||||
"marking_ref": MARKING_IDS[3],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
|
@ -607,21 +623,23 @@ def test_is_marked_smoke(data):
|
|||
assert markings.is_marked(data, selectors=["modified"]) is False
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data,selector", [
|
||||
(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], "x.z.[-2]"),
|
||||
(IS_MARKED_TEST_DATA[0], "c.f"),
|
||||
(IS_MARKED_TEST_DATA[0], "c.[2].i"),
|
||||
(IS_MARKED_TEST_DATA[1], "c.[3]"),
|
||||
(IS_MARKED_TEST_DATA[1], "d"),
|
||||
(IS_MARKED_TEST_DATA[1], "x.[0]"),
|
||||
(IS_MARKED_TEST_DATA[1], "z.y.w"),
|
||||
(IS_MARKED_TEST_DATA[1], "x.z.[1]"),
|
||||
(IS_MARKED_TEST_DATA[1], "x.z.foo3")
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data,selector", [
|
||||
(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], "x.z.[-2]"),
|
||||
(IS_MARKED_TEST_DATA[0], "c.f"),
|
||||
(IS_MARKED_TEST_DATA[0], "c.[2].i"),
|
||||
(IS_MARKED_TEST_DATA[1], "c.[3]"),
|
||||
(IS_MARKED_TEST_DATA[1], "d"),
|
||||
(IS_MARKED_TEST_DATA[1], "x.[0]"),
|
||||
(IS_MARKED_TEST_DATA[1], "z.y.w"),
|
||||
(IS_MARKED_TEST_DATA[1], "x.z.[1]"),
|
||||
(IS_MARKED_TEST_DATA[1], "x.z.foo3"),
|
||||
],
|
||||
)
|
||||
def test_is_marked_invalid_selector(data, selector):
|
||||
"""Test invalid selector raises an error."""
|
||||
with pytest.raises(AssertionError):
|
||||
|
@ -689,61 +707,61 @@ def test_is_marked_positional_arguments_combinations():
|
|||
"list value",
|
||||
{
|
||||
"g": "nested",
|
||||
"h": 45
|
||||
}
|
||||
"h": 45,
|
||||
},
|
||||
],
|
||||
"x": {
|
||||
"y": [
|
||||
"hello",
|
||||
88
|
||||
88,
|
||||
],
|
||||
"z": {
|
||||
"foo1": "bar",
|
||||
"foo2": 65
|
||||
}
|
||||
"foo2": 65,
|
||||
},
|
||||
},
|
||||
"granular_markings": [
|
||||
{
|
||||
"marking_ref": "1",
|
||||
"selectors": ["a"]
|
||||
"selectors": ["a"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "2",
|
||||
"selectors": ["c"]
|
||||
"selectors": ["c"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "3",
|
||||
"selectors": ["c.[1]"]
|
||||
"selectors": ["c.[1]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "4",
|
||||
"selectors": ["c.[2]"]
|
||||
"selectors": ["c.[2]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "5",
|
||||
"selectors": ["c.[2].g"]
|
||||
"selectors": ["c.[2].g"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "6",
|
||||
"selectors": ["x"]
|
||||
"selectors": ["x"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "7",
|
||||
"selectors": ["x.y"]
|
||||
"selectors": ["x.y"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "8",
|
||||
"selectors": ["x.y.[1]"]
|
||||
"selectors": ["x.y.[1]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "9",
|
||||
"selectors": ["x.z"]
|
||||
"selectors": ["x.z"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "10",
|
||||
"selectors": ["x.z.foo2"]
|
||||
"selectors": ["x.z.foo2"],
|
||||
},
|
||||
]
|
||||
],
|
||||
}
|
||||
|
||||
assert markings.is_marked(test_sdo, ["1"], "a", False, False)
|
||||
|
@ -823,8 +841,8 @@ def test_create_sdo_with_invalid_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["foo"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -839,12 +857,12 @@ def test_set_marking_mark_one_selector_multiple_refs():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -858,8 +876,8 @@ def test_set_marking_mark_multiple_selector_one_refs():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -867,8 +885,8 @@ def test_set_marking_mark_multiple_selector_one_refs():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -885,12 +903,12 @@ def test_set_marking_mark_multiple_selector_multiple_refs_from_none():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -904,8 +922,8 @@ def test_set_marking_mark_another_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -913,12 +931,12 @@ def test_set_marking_mark_another_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[2]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[2],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -928,19 +946,21 @@ def test_set_marking_mark_another_property_same_marking():
|
|||
assert m in after["granular_markings"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("marking", [
|
||||
([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]], [""]),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"marking", [
|
||||
([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]], [""]),
|
||||
],
|
||||
)
|
||||
def test_set_marking_bad_selector(marking):
|
||||
before = Malware(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -948,8 +968,8 @@ def test_set_marking_bad_selector(marking):
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -965,8 +985,8 @@ def test_set_marking_mark_same_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -974,8 +994,8 @@ def test_set_marking_mark_same_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -989,15 +1009,15 @@ CLEAR_MARKINGS_TEST_DATA = [
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["modified", "description"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
{
|
||||
"selectors": ["modified", "description", "type"],
|
||||
"marking_ref": MARKING_IDS[2]
|
||||
"marking_ref": MARKING_IDS[2],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
|
@ -1006,19 +1026,19 @@ CLEAR_MARKINGS_TEST_DATA = [
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["modified", "description"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
{
|
||||
"selectors": ["modified", "description", "type"],
|
||||
"marking_ref": MARKING_IDS[2]
|
||||
"marking_ref": MARKING_IDS[2],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
@ -1050,12 +1070,14 @@ def test_clear_marking_all_selectors(data):
|
|||
assert "granular_markings" not in data
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data,selector", [
|
||||
(CLEAR_MARKINGS_TEST_DATA[0], "foo"),
|
||||
(CLEAR_MARKINGS_TEST_DATA[0], ""),
|
||||
(CLEAR_MARKINGS_TEST_DATA[1], []),
|
||||
(CLEAR_MARKINGS_TEST_DATA[1], [""]),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data,selector", [
|
||||
(CLEAR_MARKINGS_TEST_DATA[0], "foo"),
|
||||
(CLEAR_MARKINGS_TEST_DATA[0], ""),
|
||||
(CLEAR_MARKINGS_TEST_DATA[1], []),
|
||||
(CLEAR_MARKINGS_TEST_DATA[1], [""]),
|
||||
],
|
||||
)
|
||||
def test_clear_marking_bad_selector(data, selector):
|
||||
"""Test bad selector raises exception."""
|
||||
with pytest.raises(AssertionError):
|
||||
|
|
|
@ -29,17 +29,19 @@ def test_identity_example():
|
|||
assert str(identity) == EXPECTED
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2015-12-21T19:59:11.000Z",
|
||||
"id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c",
|
||||
"identity_class": "individual",
|
||||
"modified": "2015-12-21T19:59:11.000Z",
|
||||
"name": "John Smith",
|
||||
"type": "identity"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2015-12-21T19:59:11.000Z",
|
||||
"id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c",
|
||||
"identity_class": "individual",
|
||||
"modified": "2015-12-21T19:59:11.000Z",
|
||||
"name": "John Smith",
|
||||
"type": "identity",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_identity(data):
|
||||
identity = stix2.parse(data, version="2.0")
|
||||
|
||||
|
@ -52,21 +54,23 @@ def test_parse_identity(data):
|
|||
|
||||
def test_parse_no_type():
|
||||
with pytest.raises(stix2.exceptions.ParseError):
|
||||
stix2.parse("""
|
||||
stix2.parse(
|
||||
"""
|
||||
{
|
||||
"id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c",
|
||||
"created": "2015-12-21T19:59:11.000Z",
|
||||
"modified": "2015-12-21T19:59:11.000Z",
|
||||
"name": "John Smith",
|
||||
"identity_class": "individual"
|
||||
}""", version="2.0")
|
||||
}""", version="2.0",
|
||||
)
|
||||
|
||||
|
||||
def test_identity_with_custom():
|
||||
identity = stix2.v20.Identity(
|
||||
name="John Smith",
|
||||
identity_class="individual",
|
||||
custom_properties={'x_foo': 'bar'}
|
||||
custom_properties={'x_foo': 'bar'},
|
||||
)
|
||||
|
||||
assert identity.x_foo == "bar"
|
||||
|
|
|
@ -148,20 +148,22 @@ def test_created_modified_time_are_identical_by_default():
|
|||
assert ind.created == ind.modified
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED_INDICATOR,
|
||||
{
|
||||
"type": "indicator",
|
||||
"id": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
|
||||
"created": "2017-01-01T00:00:01Z",
|
||||
"modified": "2017-01-01T00:00:01Z",
|
||||
"labels": [
|
||||
"malicious-activity"
|
||||
],
|
||||
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
||||
"valid_from": "1970-01-01T00:00:01Z"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED_INDICATOR,
|
||||
{
|
||||
"type": "indicator",
|
||||
"id": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
|
||||
"created": "2017-01-01T00:00:01Z",
|
||||
"modified": "2017-01-01T00:00:01Z",
|
||||
"labels": [
|
||||
"malicious-activity",
|
||||
],
|
||||
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
||||
"valid_from": "1970-01-01T00:00:01Z",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_indicator(data):
|
||||
idctr = stix2.parse(data, version="2.0")
|
||||
|
||||
|
|
|
@ -35,32 +35,34 @@ def test_intrusion_set_example():
|
|||
name="Bobcat Breakin",
|
||||
description="Incidents usually feature a shared TTP of a bobcat being released...",
|
||||
aliases=["Zookeeper"],
|
||||
goals=["acquisition-theft", "harassment", "damage"]
|
||||
goals=["acquisition-theft", "harassment", "damage"],
|
||||
)
|
||||
|
||||
assert str(intrusion_set) == EXPECTED
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"aliases": [
|
||||
"Zookeeper"
|
||||
],
|
||||
"created": "2016-04-06T20:03:48.000Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"description": "Incidents usually feature a shared TTP of a bobcat being released...",
|
||||
"goals": [
|
||||
"acquisition-theft",
|
||||
"harassment",
|
||||
"damage"
|
||||
],
|
||||
"id": "intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29",
|
||||
"modified": "2016-04-06T20:03:48.000Z",
|
||||
"name": "Bobcat Breakin",
|
||||
"type": "intrusion-set"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"aliases": [
|
||||
"Zookeeper",
|
||||
],
|
||||
"created": "2016-04-06T20:03:48.000Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"description": "Incidents usually feature a shared TTP of a bobcat being released...",
|
||||
"goals": [
|
||||
"acquisition-theft",
|
||||
"harassment",
|
||||
"damage",
|
||||
],
|
||||
"id": "intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29",
|
||||
"modified": "2016-04-06T20:03:48.000Z",
|
||||
"name": "Bobcat Breakin",
|
||||
"type": "intrusion-set",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_intrusion_set(data):
|
||||
intset = stix2.parse(data, version="2.0")
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ def test_malware_with_all_required_properties():
|
|||
created=now,
|
||||
modified=now,
|
||||
labels=["ransomware"],
|
||||
name="Cryptolocker"
|
||||
name="Cryptolocker",
|
||||
)
|
||||
|
||||
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)."
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED_MALWARE,
|
||||
{
|
||||
"type": "malware",
|
||||
"id": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
|
||||
"created": "2016-05-12T08:17:27.000Z",
|
||||
"modified": "2016-05-12T08:17:27.000Z",
|
||||
"labels": ["ransomware"],
|
||||
"name": "Cryptolocker"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED_MALWARE,
|
||||
{
|
||||
"type": "malware",
|
||||
"id": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
|
||||
"created": "2016-05-12T08:17:27.000Z",
|
||||
"modified": "2016-05-12T08:17:27.000Z",
|
||||
"labels": ["ransomware"],
|
||||
"name": "Cryptolocker",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_malware(data):
|
||||
mal = stix2.parse(data, version="2.0")
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ def test_marking_def_example_with_statement_positional_argument():
|
|||
id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
|
||||
created="2017-01-20T00:00:00.000Z",
|
||||
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
|
||||
|
@ -91,7 +91,7 @@ def test_marking_def_example_with_kwargs_statement():
|
|||
id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
|
||||
created="2017-01-20T00:00:00.000Z",
|
||||
definition_type="statement",
|
||||
definition=stix2.v20.StatementMarking(**kwargs)
|
||||
definition=stix2.v20.StatementMarking(**kwargs),
|
||||
)
|
||||
|
||||
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",
|
||||
created="2017-01-20T00:00:00.000Z",
|
||||
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",
|
||||
name="Green Group Attacks Against Finance",
|
||||
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
|
||||
|
||||
|
@ -123,7 +123,7 @@ def test_campaign_with_markings_example():
|
|||
def test_granular_example():
|
||||
granular_marking = stix2.v20.GranularMarking(
|
||||
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
|
||||
|
@ -133,7 +133,7 @@ def test_granular_example_with_bad_selector():
|
|||
with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo:
|
||||
stix2.v20.GranularMarking(
|
||||
marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
|
||||
selectors=["abc[0]"] # missing "."
|
||||
selectors=["abc[0]"], # missing "."
|
||||
)
|
||||
|
||||
assert excinfo.value.cls == stix2.v20.GranularMarking
|
||||
|
@ -153,23 +153,27 @@ def test_campaign_with_granular_markings_example():
|
|||
granular_markings=[
|
||||
stix2.v20.GranularMarking(
|
||||
marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
|
||||
selectors=["description"])
|
||||
])
|
||||
selectors=["description"],
|
||||
),
|
||||
],
|
||||
)
|
||||
assert str(campaign) == EXPECTED_CAMPAIGN_WITH_GRANULAR_MARKINGS
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED_TLP_MARKING_DEFINITION,
|
||||
{
|
||||
"id": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
|
||||
"type": "marking-definition",
|
||||
"created": "2017-01-20T00:00:00Z",
|
||||
"definition": {
|
||||
"tlp": "white"
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED_TLP_MARKING_DEFINITION,
|
||||
{
|
||||
"id": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
|
||||
"type": "marking-definition",
|
||||
"created": "2017-01-20T00:00:00Z",
|
||||
"definition": {
|
||||
"tlp": "white",
|
||||
},
|
||||
"definition_type": "tlp",
|
||||
},
|
||||
"definition_type": "tlp",
|
||||
},
|
||||
])
|
||||
],
|
||||
)
|
||||
def test_parse_marking_definition(data):
|
||||
gm = stix2.parse(data, version="2.0")
|
||||
|
||||
|
@ -180,10 +184,12 @@ def test_parse_marking_definition(data):
|
|||
assert gm.definition_type == "tlp"
|
||||
|
||||
|
||||
@stix2.v20.CustomMarking('x-new-marking-type', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
])
|
||||
@stix2.v20.CustomMarking(
|
||||
'x-new-marking-type', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
],
|
||||
)
|
||||
class NewMarking(object):
|
||||
def __init__(self, property2=None, **kwargs):
|
||||
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",
|
||||
created="2017-01-22T00:00:00.000Z",
|
||||
definition_type="x-new-marking-type",
|
||||
definition=nm
|
||||
definition=nm,
|
||||
)
|
||||
|
||||
assert marking_def.type == "marking-definition"
|
||||
|
@ -218,10 +224,12 @@ def test_registered_custom_marking_raises_exception():
|
|||
def test_not_registered_marking_raises_exception():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
# Used custom object on purpose to demonstrate a not-registered marking
|
||||
@stix2.v20.CustomObject('x-new-marking-type2', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
])
|
||||
@stix2.v20.CustomObject(
|
||||
'x-new-marking-type2', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
],
|
||||
)
|
||||
class NewObject2(object):
|
||||
def __init__(self, property2=None, **kwargs):
|
||||
return
|
||||
|
@ -232,7 +240,7 @@ def test_not_registered_marking_raises_exception():
|
|||
id="marking-definition--00000000-0000-4000-8000-000000000012",
|
||||
created="2017-01-22T00:00:00.000Z",
|
||||
definition_type="x-new-marking-type2",
|
||||
definition=no
|
||||
definition=no,
|
||||
)
|
||||
|
||||
assert str(excinfo.value) == "definition_type must be a valid marking type"
|
||||
|
|
|
@ -18,26 +18,34 @@ MALWARE_KWARGS.update({
|
|||
})
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
(
|
||||
Malware(**MALWARE_KWARGS),
|
||||
Malware(object_marking_refs=[MARKING_IDS[0]],
|
||||
**MALWARE_KWARGS),
|
||||
MARKING_IDS[0],
|
||||
),
|
||||
(
|
||||
MALWARE_KWARGS,
|
||||
dict(object_marking_refs=[MARKING_IDS[0]],
|
||||
**MALWARE_KWARGS),
|
||||
MARKING_IDS[0],
|
||||
),
|
||||
(
|
||||
Malware(**MALWARE_KWARGS),
|
||||
Malware(object_marking_refs=[TLP_AMBER.id],
|
||||
**MALWARE_KWARGS),
|
||||
TLP_AMBER,
|
||||
),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
(
|
||||
Malware(**MALWARE_KWARGS),
|
||||
Malware(
|
||||
object_marking_refs=[MARKING_IDS[0]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
MARKING_IDS[0],
|
||||
),
|
||||
(
|
||||
MALWARE_KWARGS,
|
||||
dict(
|
||||
object_marking_refs=[MARKING_IDS[0]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
MARKING_IDS[0],
|
||||
),
|
||||
(
|
||||
Malware(**MALWARE_KWARGS),
|
||||
Malware(
|
||||
object_marking_refs=[TLP_AMBER.id],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
TLP_AMBER,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_add_markings_one_marking(data):
|
||||
before = data[0]
|
||||
after = data[1]
|
||||
|
@ -73,12 +81,12 @@ def test_add_markings_combination():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["labels"],
|
||||
"marking_ref": MARKING_IDS[2]
|
||||
"marking_ref": MARKING_IDS[2],
|
||||
},
|
||||
{
|
||||
"selectors": ["name"],
|
||||
"marking_ref": MARKING_IDS[3]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[3],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -95,12 +103,14 @@ def test_add_markings_combination():
|
|||
assert m in after["object_marking_refs"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
([""]),
|
||||
(""),
|
||||
([]),
|
||||
([MARKING_IDS[0], 456])
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
([""]),
|
||||
(""),
|
||||
([]),
|
||||
([MARKING_IDS[0], 456]),
|
||||
],
|
||||
)
|
||||
def test_add_markings_bad_markings(data):
|
||||
before = Malware(
|
||||
**MALWARE_KWARGS
|
||||
|
@ -120,62 +130,62 @@ GET_MARKINGS_TEST_DATA = \
|
|||
"list value",
|
||||
{
|
||||
"g": "nested",
|
||||
"h": 45
|
||||
}
|
||||
"h": 45,
|
||||
},
|
||||
],
|
||||
"x": {
|
||||
"y": [
|
||||
"hello",
|
||||
88
|
||||
88,
|
||||
],
|
||||
"z": {
|
||||
"foo1": "bar",
|
||||
"foo2": 65
|
||||
}
|
||||
"foo2": 65,
|
||||
},
|
||||
},
|
||||
"object_marking_refs": ["11"],
|
||||
"granular_markings": [
|
||||
{
|
||||
"marking_ref": "1",
|
||||
"selectors": ["a"]
|
||||
"selectors": ["a"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "2",
|
||||
"selectors": ["c"]
|
||||
"selectors": ["c"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "3",
|
||||
"selectors": ["c.[1]"]
|
||||
"selectors": ["c.[1]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "4",
|
||||
"selectors": ["c.[2]"]
|
||||
"selectors": ["c.[2]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "5",
|
||||
"selectors": ["c.[2].g"]
|
||||
"selectors": ["c.[2].g"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "6",
|
||||
"selectors": ["x"]
|
||||
"selectors": ["x"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "7",
|
||||
"selectors": ["x.y"]
|
||||
"selectors": ["x.y"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "8",
|
||||
"selectors": ["x.y.[1]"]
|
||||
"selectors": ["x.y.[1]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "9",
|
||||
"selectors": ["x.z"]
|
||||
"selectors": ["x.z"],
|
||||
},
|
||||
{
|
||||
"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"])
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
(
|
||||
Malware(object_marking_refs=[MARKING_IDS[0]],
|
||||
**MALWARE_KWARGS),
|
||||
Malware(**MALWARE_KWARGS),
|
||||
),
|
||||
(
|
||||
dict(object_marking_refs=[MARKING_IDS[0]],
|
||||
**MALWARE_KWARGS),
|
||||
MALWARE_KWARGS,
|
||||
),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
(
|
||||
Malware(
|
||||
object_marking_refs=[MARKING_IDS[0]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
Malware(**MALWARE_KWARGS),
|
||||
),
|
||||
(
|
||||
dict(
|
||||
object_marking_refs=[MARKING_IDS[0]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
MALWARE_KWARGS,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_remove_markings_object_level(data):
|
||||
before = data[0]
|
||||
after = data[1]
|
||||
|
@ -284,29 +300,43 @@ def test_remove_markings_object_level(data):
|
|||
modified == after['modified']
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
(
|
||||
Malware(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS),
|
||||
Malware(object_marking_refs=[MARKING_IDS[1]],
|
||||
**MALWARE_KWARGS),
|
||||
[MARKING_IDS[0], MARKING_IDS[2]],
|
||||
),
|
||||
(
|
||||
dict(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS),
|
||||
dict(object_marking_refs=[MARKING_IDS[1]],
|
||||
**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],
|
||||
),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
(
|
||||
Malware(
|
||||
object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
Malware(
|
||||
object_marking_refs=[MARKING_IDS[1]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
[MARKING_IDS[0], MARKING_IDS[2]],
|
||||
),
|
||||
(
|
||||
dict(
|
||||
object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
dict(
|
||||
object_marking_refs=[MARKING_IDS[1]],
|
||||
**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):
|
||||
before = data[0]
|
||||
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]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
(
|
||||
Malware(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS),
|
||||
Malware(**MALWARE_KWARGS),
|
||||
),
|
||||
(
|
||||
dict(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS),
|
||||
MALWARE_KWARGS,
|
||||
),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
(
|
||||
Malware(
|
||||
object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
Malware(**MALWARE_KWARGS),
|
||||
),
|
||||
(
|
||||
dict(
|
||||
object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
MALWARE_KWARGS,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_clear_markings(data):
|
||||
before = data[0]
|
||||
after = data[1]
|
||||
|
@ -359,62 +395,62 @@ def test_is_marked_object_and_granular_combinations():
|
|||
"list value",
|
||||
{
|
||||
"g": "nested",
|
||||
"h": 45
|
||||
}
|
||||
"h": 45,
|
||||
},
|
||||
],
|
||||
"x": {
|
||||
"y": [
|
||||
"hello",
|
||||
88
|
||||
88,
|
||||
],
|
||||
"z": {
|
||||
"foo1": "bar",
|
||||
"foo2": 65
|
||||
}
|
||||
"foo2": 65,
|
||||
},
|
||||
},
|
||||
"object_marking_refs": "11",
|
||||
"granular_markings": [
|
||||
{
|
||||
"marking_ref": "1",
|
||||
"selectors": ["a"]
|
||||
"selectors": ["a"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "2",
|
||||
"selectors": ["c"]
|
||||
"selectors": ["c"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "3",
|
||||
"selectors": ["c.[1]"]
|
||||
"selectors": ["c.[1]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "4",
|
||||
"selectors": ["c.[2]"]
|
||||
"selectors": ["c.[2]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "5",
|
||||
"selectors": ["c.[2].g"]
|
||||
"selectors": ["c.[2].g"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "6",
|
||||
"selectors": ["x"]
|
||||
"selectors": ["x"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "7",
|
||||
"selectors": ["x.y"]
|
||||
"selectors": ["x.y"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "8",
|
||||
"selectors": ["x.y.[1]"]
|
||||
"selectors": ["x.y.[1]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "9",
|
||||
"selectors": ["x.z"]
|
||||
"selectors": ["x.z"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "10",
|
||||
"selectors": ["x.z.foo2"]
|
||||
"selectors": ["x.z.foo2"],
|
||||
},
|
||||
]
|
||||
],
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
(
|
||||
Malware(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS),
|
||||
Malware(**MALWARE_KWARGS),
|
||||
),
|
||||
(
|
||||
dict(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS),
|
||||
MALWARE_KWARGS,
|
||||
),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
(
|
||||
Malware(
|
||||
object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
Malware(**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):
|
||||
marked = data[0]
|
||||
nonmarked = data[1]
|
||||
|
@ -532,12 +574,14 @@ def test_set_marking():
|
|||
assert x in after["object_marking_refs"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
([]),
|
||||
([""]),
|
||||
(""),
|
||||
([MARKING_IDS[4], 687])
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
([]),
|
||||
([""]),
|
||||
(""),
|
||||
([MARKING_IDS[4], 687]),
|
||||
],
|
||||
)
|
||||
def test_set_marking_bad_input(data):
|
||||
before = Malware(
|
||||
object_marking_refs=[MARKING_IDS[0]],
|
||||
|
|
|
@ -41,7 +41,7 @@ def test_observed_data_example():
|
|||
objects={
|
||||
"0": {
|
||||
"name": "foo.exe",
|
||||
"type": "file"
|
||||
"type": "file",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
@ -86,13 +86,13 @@ def test_observed_data_example_with_refs():
|
|||
objects={
|
||||
"0": {
|
||||
"name": "foo.exe",
|
||||
"type": "file"
|
||||
"type": "file",
|
||||
},
|
||||
"1": {
|
||||
"type": "directory",
|
||||
"path": "/usr/home",
|
||||
"contains_refs": ["0"]
|
||||
}
|
||||
"contains_refs": ["0"],
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -112,13 +112,13 @@ def test_observed_data_example_with_bad_refs():
|
|||
objects={
|
||||
"0": {
|
||||
"type": "file",
|
||||
"name": "foo.exe"
|
||||
"name": "foo.exe",
|
||||
},
|
||||
"1": {
|
||||
"type": "directory",
|
||||
"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
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"type": "observed-data",
|
||||
"id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
|
||||
"created": "2016-04-06T19:58:16.000Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"first_observed": "2015-12-21T19:00:00Z",
|
||||
"last_observed": "2015-12-21T19:00:00Z",
|
||||
"modified": "2016-04-06T19:58:16.000Z",
|
||||
"number_observed": 50,
|
||||
"objects": {
|
||||
"0": {
|
||||
"name": "foo.exe",
|
||||
"type": "file"
|
||||
}
|
||||
}
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"type": "observed-data",
|
||||
"id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
|
||||
"created": "2016-04-06T19:58:16.000Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"first_observed": "2015-12-21T19:00:00Z",
|
||||
"last_observed": "2015-12-21T19:00:00Z",
|
||||
"modified": "2016-04-06T19:58:16.000Z",
|
||||
"number_observed": 50,
|
||||
"objects": {
|
||||
"0": {
|
||||
"name": "foo.exe",
|
||||
"type": "file",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_observed_data(data):
|
||||
odata = stix2.parse(data, version="2.0")
|
||||
|
||||
|
@ -195,13 +197,14 @@ def test_parse_observed_data(data):
|
|||
assert odata.objects["0"].type == "file"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
""""0": {
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
""""0": {
|
||||
"type": "artifact",
|
||||
"mime_type": "image/jpeg",
|
||||
"payload_bin": "VBORw0KGgoAAAANSUhEUgAAADI=="
|
||||
}""",
|
||||
""""0": {
|
||||
""""0": {
|
||||
"type": "artifact",
|
||||
"mime_type": "image/jpeg",
|
||||
"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"
|
||||
}
|
||||
}""",
|
||||
])
|
||||
],
|
||||
)
|
||||
def test_parse_artifact_valid(data):
|
||||
odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED)
|
||||
odata = stix2.parse(odata_str, version="2.0")
|
||||
assert odata.objects["0"].type == "artifact"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
""""0": {
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
""""0": {
|
||||
"type": "artifact",
|
||||
"mime_type": "image/jpeg",
|
||||
"payload_bin": "abcVBORw0KGgoAAAANSUhEUgAAADI=="
|
||||
}""",
|
||||
""""0": {
|
||||
""""0": {
|
||||
"type": "artifact",
|
||||
"mime_type": "image/jpeg",
|
||||
"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"
|
||||
}
|
||||
}""",
|
||||
])
|
||||
],
|
||||
)
|
||||
def test_parse_artifact_invalid(data):
|
||||
odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED)
|
||||
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."
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
""""0": {
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
""""0": {
|
||||
"type": "autonomous-system",
|
||||
"number": 15139,
|
||||
"name": "Slime Industries",
|
||||
"rir": "ARIN"
|
||||
}""",
|
||||
])
|
||||
],
|
||||
)
|
||||
def test_parse_autonomous_system_valid(data):
|
||||
odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED)
|
||||
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"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
"""{
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
"""{
|
||||
"type": "email-addr",
|
||||
"value": "john@example.com",
|
||||
"display_name": "John Doe",
|
||||
"belongs_to_ref": "0"
|
||||
}""",
|
||||
])
|
||||
],
|
||||
)
|
||||
def test_parse_email_address(data):
|
||||
odata = stix2.parse_observable(data, {"0": "user-account"}, version='2.0')
|
||||
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')
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
"""
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
"""
|
||||
{
|
||||
"type": "email-message",
|
||||
"is_multipart": true,
|
||||
|
@ -317,8 +328,9 @@ def test_parse_email_address(data):
|
|||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
])
|
||||
""",
|
||||
],
|
||||
)
|
||||
def test_parse_email_message(data):
|
||||
valid_refs = {
|
||||
"0": "email-message",
|
||||
|
@ -333,8 +345,9 @@ def test_parse_email_message(data):
|
|||
assert odata.body_multipart[0].content_disposition == "inline"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
"""
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
"""
|
||||
{
|
||||
"type": "email-message",
|
||||
"from_ref": "0",
|
||||
|
@ -344,8 +357,9 @@ def test_parse_email_message(data):
|
|||
"subject": "Saying Hello",
|
||||
"body": "Cats are funny!"
|
||||
}
|
||||
"""
|
||||
])
|
||||
""",
|
||||
],
|
||||
)
|
||||
def test_parse_email_message_not_multipart(data):
|
||||
valid_refs = {
|
||||
"0": "email-addr",
|
||||
|
@ -358,8 +372,9 @@ def test_parse_email_message_not_multipart(data):
|
|||
assert excinfo.value.dependencies == [("is_multipart", "body")]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
""""0": {
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
""""0": {
|
||||
"type": "file",
|
||||
"hashes": {
|
||||
"SHA-256": "ceafbfd424be2ca4a5f0402cae090dda2fb0526cf521b60b60077c0f622b285a"
|
||||
|
@ -395,15 +410,17 @@ def test_parse_email_message_not_multipart(data):
|
|||
}
|
||||
}
|
||||
}""",
|
||||
])
|
||||
],
|
||||
)
|
||||
def test_parse_file_archive(data):
|
||||
odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED)
|
||||
odata = stix2.parse(odata_str, version="2.0")
|
||||
assert odata.objects["3"].extensions['archive-ext'].version == "5.0"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
"""
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
"""
|
||||
{
|
||||
"type": "email-message",
|
||||
"is_multipart": true,
|
||||
|
@ -439,8 +456,9 @@ def test_parse_file_archive(data):
|
|||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
])
|
||||
""",
|
||||
],
|
||||
)
|
||||
def test_parse_email_message_with_at_least_one_error(data):
|
||||
valid_refs = {
|
||||
"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)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
"""
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
"""
|
||||
{
|
||||
"type": "network-traffic",
|
||||
"src_ref": "0",
|
||||
|
@ -469,11 +488,14 @@ def test_parse_email_message_with_at_least_one_error(data):
|
|||
"tcp"
|
||||
]
|
||||
}
|
||||
"""
|
||||
])
|
||||
""",
|
||||
],
|
||||
)
|
||||
def test_parse_basic_tcp_traffic(data):
|
||||
odata = stix2.parse_observable(data, {"0": "ipv4-addr", "1": "ipv4-addr"},
|
||||
version='2.0')
|
||||
odata = stix2.parse_observable(
|
||||
data, {"0": "ipv4-addr", "1": "ipv4-addr"},
|
||||
version='2.0',
|
||||
)
|
||||
|
||||
assert odata.type == "network-traffic"
|
||||
assert odata.src_ref == "0"
|
||||
|
@ -481,8 +503,9 @@ def test_parse_basic_tcp_traffic(data):
|
|||
assert odata.protocols == ["tcp"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
"""
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
"""
|
||||
{
|
||||
"type": "network-traffic",
|
||||
"src_port": 2487,
|
||||
|
@ -497,8 +520,9 @@ def test_parse_basic_tcp_traffic(data):
|
|||
"4"
|
||||
]
|
||||
}
|
||||
"""
|
||||
])
|
||||
""",
|
||||
],
|
||||
)
|
||||
def test_parse_basic_tcp_traffic_with_error(data):
|
||||
with pytest.raises(stix2.exceptions.AtLeastOnePropertyError) as excinfo:
|
||||
stix2.parse_observable(data, {"4": "network-traffic"}, version='2.0')
|
||||
|
@ -550,7 +574,7 @@ def test_observed_data_with_process_example():
|
|||
"0": {
|
||||
"type": "file",
|
||||
"hashes": {
|
||||
"SHA-256": "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f"
|
||||
"SHA-256": "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f",
|
||||
},
|
||||
},
|
||||
"1": {
|
||||
|
@ -559,11 +583,12 @@ def test_observed_data_with_process_example():
|
|||
"name": "gedit-bin",
|
||||
"created": "2016-01-20T14:11:25.55Z",
|
||||
"arguments": [
|
||||
"--new-window"
|
||||
"--new-window",
|
||||
],
|
||||
"binary_ref": "0"
|
||||
}
|
||||
})
|
||||
"binary_ref": "0",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert observed_data.objects["0"].type == "file"
|
||||
assert observed_data.objects["0"].hashes["SHA-256"] == "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f"
|
||||
|
@ -580,8 +605,9 @@ def test_artifact_example():
|
|||
mime_type="image/jpeg",
|
||||
url="https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg",
|
||||
hashes={
|
||||
"MD5": "6826f9a05da08134006557758bb3afbb"
|
||||
})
|
||||
"MD5": "6826f9a05da08134006557758bb3afbb",
|
||||
},
|
||||
)
|
||||
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.hashes["MD5"] == "6826f9a05da08134006557758bb3afbb"
|
||||
|
@ -593,9 +619,10 @@ def test_artifact_mutual_exclusion_error():
|
|||
mime_type="image/jpeg",
|
||||
url="https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg",
|
||||
hashes={
|
||||
"MD5": "6826f9a05da08134006557758bb3afbb"
|
||||
"MD5": "6826f9a05da08134006557758bb3afbb",
|
||||
},
|
||||
payload_bin="VBORw0KGgoAAAANSUhEUgAAADI==")
|
||||
payload_bin="VBORw0KGgoAAAANSUhEUgAAADI==",
|
||||
)
|
||||
|
||||
assert excinfo.value.cls == stix2.v20.Artifact
|
||||
assert excinfo.value.properties == ["payload_bin", "url"]
|
||||
|
@ -609,7 +636,8 @@ def test_directory_example():
|
|||
created="2015-12-21T19:00:00Z",
|
||||
modified="2015-12-24T19:00:00Z",
|
||||
accessed="2015-12-21T20:00:00Z",
|
||||
contains_refs=["1"])
|
||||
contains_refs=["1"],
|
||||
)
|
||||
|
||||
assert dir.path == '/usr/lib'
|
||||
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",
|
||||
modified="2015-12-24T19:00:00Z",
|
||||
accessed="2015-12-21T20:00:00Z",
|
||||
contains_refs=["1"])
|
||||
contains_refs=["1"],
|
||||
)
|
||||
|
||||
assert excinfo.value.cls == stix2.v20.Directory
|
||||
assert excinfo.value.prop_name == "contains_refs"
|
||||
|
@ -636,7 +665,8 @@ def test_domain_name_example():
|
|||
dn = stix2.v20.DomainName(
|
||||
_valid_refs={"1": 'domain-name'},
|
||||
value="example.com",
|
||||
resolves_to_refs=["1"])
|
||||
resolves_to_refs=["1"],
|
||||
)
|
||||
|
||||
assert dn.value == "example.com"
|
||||
assert dn.resolves_to_refs == ["1"]
|
||||
|
@ -647,7 +677,8 @@ def test_domain_name_example_invalid_ref_type():
|
|||
stix2.v20.DomainName(
|
||||
_valid_refs={"1": "file"},
|
||||
value="example.com",
|
||||
resolves_to_refs=["1"])
|
||||
resolves_to_refs=["1"],
|
||||
)
|
||||
|
||||
assert excinfo.value.cls == stix2.v20.DomainName
|
||||
assert excinfo.value.prop_name == "resolves_to_refs"
|
||||
|
@ -657,7 +688,7 @@ def test_file_example():
|
|||
f = stix2.v20.File(
|
||||
name="qwerty.dll",
|
||||
hashes={
|
||||
"SHA-256": "ceafbfd424be2ca4a5f0402cae090dda2fb0526cf521b60b60077c0f622b285a"
|
||||
"SHA-256": "ceafbfd424be2ca4a5f0402cae090dda2fb0526cf521b60b60077c0f622b285a",
|
||||
},
|
||||
size=100,
|
||||
magic_number_hex="1C",
|
||||
|
@ -667,7 +698,8 @@ def test_file_example():
|
|||
accessed="2016-12-21T20:00:00Z",
|
||||
is_encrypted=True,
|
||||
encryption_algorithm="AES128-CBC",
|
||||
decryption_key="fred")
|
||||
decryption_key="fred",
|
||||
)
|
||||
|
||||
assert f.name == "qwerty.dll"
|
||||
assert f.size == 100
|
||||
|
@ -690,11 +722,12 @@ def test_file_example_with_NTFSExt():
|
|||
"alternate_data_streams": [
|
||||
{
|
||||
"name": "second.stream",
|
||||
"size": 25536
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
"size": 25536,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert f.name == "abc.txt"
|
||||
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(
|
||||
name="abc.txt",
|
||||
extensions={
|
||||
"ntfs-ext": {}
|
||||
})
|
||||
"ntfs-ext": {},
|
||||
},
|
||||
)
|
||||
|
||||
assert excinfo.value.cls == stix2.v20.NTFSExt
|
||||
assert excinfo.value.properties == sorted(list(stix2.NTFSExt._properties.keys()))
|
||||
|
@ -723,12 +757,13 @@ def test_file_example_with_PDFExt():
|
|||
"Author": "Adobe Systems Incorporated",
|
||||
"Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh",
|
||||
"Producer": "Acrobat Distiller 3.01 for Power Macintosh",
|
||||
"CreationDate": "20070412090123-02"
|
||||
"CreationDate": "20070412090123-02",
|
||||
},
|
||||
"pdfid0": "DFCE52BD827ECF765649852119D",
|
||||
"pdfid1": "57A1E0F9ED2AE523E313C"
|
||||
}
|
||||
})
|
||||
"pdfid1": "57A1E0F9ED2AE523E313C",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert f.name == "qwerty.dll"
|
||||
assert f.extensions["pdf-ext"].version == "1.7"
|
||||
|
@ -746,11 +781,13 @@ def test_file_example_with_PDFExt_Object():
|
|||
"Author": "Adobe Systems Incorporated",
|
||||
"Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh",
|
||||
"Producer": "Acrobat Distiller 3.01 for Power Macintosh",
|
||||
"CreationDate": "20070412090123-02"
|
||||
"CreationDate": "20070412090123-02",
|
||||
},
|
||||
pdfid0="DFCE52BD827ECF765649852119D",
|
||||
pdfid1="57A1E0F9ED2AE523E313C")
|
||||
})
|
||||
pdfid1="57A1E0F9ED2AE523E313C",
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
assert f.name == "qwerty.dll"
|
||||
assert f.extensions["pdf-ext"].version == "1.7"
|
||||
|
@ -767,10 +804,11 @@ def test_file_example_with_RasterImageExt_Object():
|
|||
"Make": "Nikon",
|
||||
"Model": "D7000",
|
||||
"XResolution": 4928,
|
||||
"YResolution": 3264
|
||||
}
|
||||
}
|
||||
})
|
||||
"YResolution": 3264,
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
assert f.name == "qwerty.jpeg"
|
||||
assert f.extensions["raster-image-ext"].bits_per_pixel == 123
|
||||
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_commit": 4096,
|
||||
"loader_flags_hex": "abdbffde",
|
||||
"number_of_rva_and_sizes": 3758087646
|
||||
"number_of_rva_and_sizes": 3758087646,
|
||||
},
|
||||
"sections": [
|
||||
{
|
||||
"name": "CODE",
|
||||
"entropy": 0.061089
|
||||
"entropy": 0.061089,
|
||||
},
|
||||
{
|
||||
"name": "DATA",
|
||||
"entropy": 7.980693
|
||||
"entropy": 7.980693,
|
||||
},
|
||||
{
|
||||
"name": "NicolasB",
|
||||
"entropy": 0.607433
|
||||
"entropy": 0.607433,
|
||||
},
|
||||
{
|
||||
"name": ".idata",
|
||||
"entropy": 0.607433
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
"entropy": 0.607433,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
)
|
||||
assert f.name == "qwerty.dll"
|
||||
assert f.extensions["windows-pebinary-ext"].sections[2].entropy == 0.607433
|
||||
|
||||
|
@ -895,7 +934,8 @@ def test_file_example_encryption_error():
|
|||
stix2.v20.File(
|
||||
name="qwerty.dll",
|
||||
is_encrypted=False,
|
||||
encryption_algorithm="AES128-CBC")
|
||||
encryption_algorithm="AES128-CBC",
|
||||
)
|
||||
|
||||
assert excinfo.value.cls == stix2.v20.File
|
||||
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:
|
||||
stix2.v20.File(
|
||||
name="qwerty.dll",
|
||||
encryption_algorithm="AES128-CBC")
|
||||
encryption_algorithm="AES128-CBC",
|
||||
)
|
||||
|
||||
|
||||
def test_ip4_address_example():
|
||||
ip4 = stix2.v20.IPv4Address(
|
||||
_valid_refs={"4": "mac-addr", "5": "mac-addr"},
|
||||
value="198.51.100.3",
|
||||
resolves_to_refs=["4", "5"])
|
||||
resolves_to_refs=["4", "5"],
|
||||
)
|
||||
|
||||
assert ip4.value == "198.51.100.3"
|
||||
assert ip4.resolves_to_refs == ["4", "5"]
|
||||
|
@ -941,7 +983,8 @@ def test_network_traffic_example():
|
|||
_valid_refs={"0": "ipv4-addr", "1": "ipv4-addr"},
|
||||
protocols="tcp",
|
||||
src_ref="0",
|
||||
dst_ref="1")
|
||||
dst_ref="1",
|
||||
)
|
||||
assert nt.protocols == ["tcp"]
|
||||
assert nt.src_ref == "0"
|
||||
assert nt.dst_ref == "1"
|
||||
|
@ -955,13 +998,15 @@ def test_network_traffic_http_request_example():
|
|||
request_header={
|
||||
"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"
|
||||
})
|
||||
"Host": "www.example.com",
|
||||
},
|
||||
)
|
||||
nt = stix2.v20.NetworkTraffic(
|
||||
_valid_refs={"0": "ipv4-addr"},
|
||||
protocols="tcp",
|
||||
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_value == "/download.html"
|
||||
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"},
|
||||
protocols="tcp",
|
||||
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_code_hex == "00"
|
||||
|
||||
|
@ -986,12 +1032,14 @@ def test_network_traffic_socket_example():
|
|||
is_listening=True,
|
||||
address_family="AF_INET",
|
||||
protocol_family="PF_INET",
|
||||
socket_type="SOCK_STREAM")
|
||||
socket_type="SOCK_STREAM",
|
||||
)
|
||||
nt = stix2.v20.NetworkTraffic(
|
||||
_valid_refs={"0": "ipv4-addr"},
|
||||
protocols="tcp",
|
||||
src_ref="0",
|
||||
extensions={'socket-ext': h})
|
||||
extensions={'socket-ext': h},
|
||||
)
|
||||
assert nt.extensions['socket-ext'].is_listening
|
||||
assert nt.extensions['socket-ext'].address_family == "AF_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"},
|
||||
protocols="tcp",
|
||||
src_ref="0",
|
||||
extensions={'tcp-ext': h})
|
||||
extensions={'tcp-ext': h},
|
||||
)
|
||||
assert nt.extensions['tcp-ext'].src_flags_hex == "00000002"
|
||||
|
||||
|
||||
|
@ -1021,7 +1070,8 @@ def test_process_example():
|
|||
name="gedit-bin",
|
||||
created="2016-01-20T14:11:25.55Z",
|
||||
arguments=["--new-window"],
|
||||
binary_ref="0")
|
||||
binary_ref="0",
|
||||
)
|
||||
|
||||
assert p.name == "gedit-bin"
|
||||
assert p.arguments == ["--new-window"]
|
||||
|
@ -1036,8 +1086,10 @@ def test_process_example_empty_error():
|
|||
properties_of_process.remove("type")
|
||||
assert excinfo.value.properties == sorted(properties_of_process)
|
||||
msg = "At least one of the ({1}) properties for {0} must be populated."
|
||||
msg = msg.format(stix2.v20.Process.__name__,
|
||||
", ".join(sorted(properties_of_process)))
|
||||
msg = msg.format(
|
||||
stix2.v20.Process.__name__,
|
||||
", ".join(sorted(properties_of_process)),
|
||||
)
|
||||
assert str(excinfo.value) == msg
|
||||
|
||||
|
||||
|
@ -1045,8 +1097,9 @@ def test_process_example_empty_with_extensions():
|
|||
with pytest.raises(stix2.exceptions.AtLeastOnePropertyError) as excinfo:
|
||||
stix2.v20.Process(
|
||||
extensions={
|
||||
"windows-process-ext": {}
|
||||
})
|
||||
"windows-process-ext": {},
|
||||
},
|
||||
)
|
||||
|
||||
assert excinfo.value.cls == stix2.v20.WindowsProcessExt
|
||||
properties_of_extension = list(stix2.v20.WindowsProcessExt._properties.keys())
|
||||
|
@ -1062,9 +1115,10 @@ def test_process_example_windows_process_ext():
|
|||
"aslr_enabled": True,
|
||||
"dep_enabled": True,
|
||||
"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"].dep_enabled
|
||||
assert proc.extensions["windows-process-ext"].priority == "HIGH_PRIORITY_CLASS"
|
||||
|
@ -1077,8 +1131,9 @@ def test_process_example_windows_process_ext_empty():
|
|||
pid=1221,
|
||||
name="gedit-bin",
|
||||
extensions={
|
||||
"windows-process-ext": {}
|
||||
})
|
||||
"windows-process-ext": {},
|
||||
},
|
||||
)
|
||||
|
||||
assert excinfo.value.cls == stix2.v20.WindowsProcessExt
|
||||
properties_of_extension = list(stix2.v20.WindowsProcessExt._properties.keys())
|
||||
|
@ -1100,7 +1155,8 @@ def test_process_example_with_WindowsProcessExt_Object():
|
|||
aslr_enabled=True,
|
||||
dep_enabled=True,
|
||||
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
|
||||
|
@ -1114,8 +1170,8 @@ def test_process_example_with_WindowsServiceExt():
|
|||
"display_name": "Sirvizio",
|
||||
"start_type": "SERVICE_AUTO_START",
|
||||
"service_type": "SERVICE_WIN32_OWN_PROCESS",
|
||||
"service_status": "SERVICE_RUNNING"
|
||||
}
|
||||
"service_status": "SERVICE_RUNNING",
|
||||
},
|
||||
})
|
||||
|
||||
assert p.extensions["windows-service-ext"].service_name == "sirvizio"
|
||||
|
@ -1129,14 +1185,14 @@ def test_process_example_with_WindowsProcessServiceExt():
|
|||
"display_name": "Sirvizio",
|
||||
"start_type": "SERVICE_AUTO_START",
|
||||
"service_type": "SERVICE_WIN32_OWN_PROCESS",
|
||||
"service_status": "SERVICE_RUNNING"
|
||||
"service_status": "SERVICE_RUNNING",
|
||||
},
|
||||
"windows-process-ext": {
|
||||
"aslr_enabled": True,
|
||||
"dep_enabled": True,
|
||||
"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"
|
||||
|
@ -1150,7 +1206,8 @@ def test_software_example():
|
|||
name="Word",
|
||||
cpe="cpe:2.3:a:microsoft:word:2000:*:*:*:*:*:*:*",
|
||||
version="2002",
|
||||
vendor="Microsoft")
|
||||
vendor="Microsoft",
|
||||
)
|
||||
|
||||
assert s.name == "Word"
|
||||
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",
|
||||
password_last_changed="2016-01-20T14:27:43Z",
|
||||
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.account_login == "jdoe"
|
||||
|
@ -1197,12 +1255,14 @@ def test_user_account_unix_account_ext_example():
|
|||
gid=1001,
|
||||
groups=["wheel"],
|
||||
home_dir="/home/jdoe",
|
||||
shell="/bin/bash")
|
||||
shell="/bin/bash",
|
||||
)
|
||||
a = stix2.v20.UserAccount(
|
||||
user_id="1001",
|
||||
account_login="jdoe",
|
||||
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'].groups == ["wheel"]
|
||||
assert a.extensions['unix-account-ext'].home_dir == "/home/jdoe"
|
||||
|
@ -1214,15 +1274,18 @@ def test_windows_registry_key_example():
|
|||
stix2.v20.WindowsRegistryValueType(
|
||||
name="Foo",
|
||||
data="qwerty",
|
||||
data_type="string")
|
||||
data_type="string",
|
||||
)
|
||||
|
||||
v = stix2.v20.WindowsRegistryValueType(
|
||||
name="Foo",
|
||||
data="qwerty",
|
||||
data_type="REG_SZ")
|
||||
data_type="REG_SZ",
|
||||
)
|
||||
w = stix2.v20.WindowsRegistryKey(
|
||||
key="hkey_local_machine\\system\\bar\\foo",
|
||||
values=[v])
|
||||
values=[v],
|
||||
)
|
||||
assert w.key == "hkey_local_machine\\system\\bar\\foo"
|
||||
assert w.values[0].name == "Foo"
|
||||
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
|
||||
validity_not_before="2016-03-12T12: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.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={
|
||||
'src_ip': {
|
||||
'type': 'ipv4-addr',
|
||||
'value': '127.0.0.1/32'
|
||||
'value': '127.0.0.1/32',
|
||||
},
|
||||
'domain': {
|
||||
'type': 'domain-name',
|
||||
'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")
|
||||
assert new_version.last_observed.year == 2017
|
||||
|
|
|
@ -7,37 +7,55 @@ import stix2
|
|||
|
||||
def test_create_comparison_expression():
|
||||
|
||||
exp = stix2.EqualityComparisonExpression("file:hashes.'SHA-256'",
|
||||
stix2.HashConstant("aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f", "SHA-256")) # noqa
|
||||
exp = stix2.EqualityComparisonExpression(
|
||||
"file:hashes.'SHA-256'",
|
||||
stix2.HashConstant("aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f", "SHA-256"),
|
||||
) # noqa
|
||||
assert str(exp) == "file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f'"
|
||||
|
||||
|
||||
def test_boolean_expression():
|
||||
exp1 = stix2.MatchesComparisonExpression("email-message:from_ref.value",
|
||||
stix2.StringConstant(".+\\@example\\.com$"))
|
||||
exp2 = stix2.MatchesComparisonExpression("email-message:body_multipart[*].body_raw_ref.name",
|
||||
stix2.StringConstant("^Final Report.+\\.exe$"))
|
||||
exp1 = stix2.MatchesComparisonExpression(
|
||||
"email-message:from_ref.value",
|
||||
stix2.StringConstant(".+\\@example\\.com$"),
|
||||
)
|
||||
exp2 = stix2.MatchesComparisonExpression(
|
||||
"email-message:body_multipart[*].body_raw_ref.name",
|
||||
stix2.StringConstant("^Final Report.+\\.exe$"),
|
||||
)
|
||||
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
|
||||
|
||||
|
||||
def test_boolean_expression_with_parentheses():
|
||||
exp1 = stix2.MatchesComparisonExpression(stix2.ObjectPath("email-message",
|
||||
[stix2.ReferenceObjectPathComponent("from_ref"),
|
||||
stix2.BasicObjectPathComponent("value")]),
|
||||
stix2.StringConstant(".+\\@example\\.com$"))
|
||||
exp2 = stix2.MatchesComparisonExpression("email-message:body_multipart[*].body_raw_ref.name",
|
||||
stix2.StringConstant("^Final Report.+\\.exe$"))
|
||||
exp1 = stix2.MatchesComparisonExpression(
|
||||
stix2.ObjectPath(
|
||||
"email-message",
|
||||
[
|
||||
stix2.ReferenceObjectPathComponent("from_ref"),
|
||||
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]))
|
||||
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():
|
||||
hash_exp = stix2.EqualityComparisonExpression("file:hashes.MD5",
|
||||
stix2.HashConstant("79054025255fb1a26e4bc422aef54eb4", "MD5"))
|
||||
hash_exp = stix2.EqualityComparisonExpression(
|
||||
"file:hashes.MD5",
|
||||
stix2.HashConstant("79054025255fb1a26e4bc422aef54eb4", "MD5"),
|
||||
)
|
||||
o_exp1 = stix2.ObservationExpression(hash_exp)
|
||||
reg_exp = stix2.EqualityComparisonExpression(stix2.ObjectPath("windows-registry-key", ["key"]),
|
||||
stix2.StringConstant("HKEY_LOCAL_MACHINE\\foo\\bar"))
|
||||
reg_exp = stix2.EqualityComparisonExpression(
|
||||
stix2.ObjectPath("windows-registry-key", ["key"]),
|
||||
stix2.StringConstant("HKEY_LOCAL_MACHINE\\foo\\bar"),
|
||||
)
|
||||
o_exp2 = stix2.ObservationExpression(reg_exp)
|
||||
fb_exp = stix2.FollowedByObservationExpression([o_exp1, o_exp2])
|
||||
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():
|
||||
hash_exp = stix2.EqualityComparisonExpression("file:hashes.MD5",
|
||||
stix2.HashConstant("79054025255fb1a26e4bc422aef54eb4", "MD5"))
|
||||
hash_exp = stix2.EqualityComparisonExpression(
|
||||
"file:hashes.MD5",
|
||||
stix2.HashConstant("79054025255fb1a26e4bc422aef54eb4", "MD5"),
|
||||
)
|
||||
o_exp1 = stix2.ObservationExpression(hash_exp)
|
||||
reg_exp = stix2.EqualityComparisonExpression(stix2.ObjectPath("windows-registry-key", ["key"]),
|
||||
stix2.StringConstant("HKEY_LOCAL_MACHINE\\foo\\bar"))
|
||||
reg_exp = stix2.EqualityComparisonExpression(
|
||||
stix2.ObjectPath("windows-registry-key", ["key"]),
|
||||
stix2.StringConstant("HKEY_LOCAL_MACHINE\\foo\\bar"),
|
||||
)
|
||||
o_exp2 = stix2.ObservationExpression(reg_exp)
|
||||
fb_exp = stix2.FollowedByObservationExpression([o_exp1, o_exp2])
|
||||
para_exp = stix2.ParentheticalExpression(fb_exp)
|
||||
|
@ -61,32 +83,45 @@ def test_hash_followed_by_registryKey_expression():
|
|||
|
||||
|
||||
def test_file_observable_expression():
|
||||
exp1 = stix2.EqualityComparisonExpression("file:hashes.'SHA-256'",
|
||||
stix2.HashConstant(
|
||||
"aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f",
|
||||
'SHA-256'))
|
||||
exp1 = stix2.EqualityComparisonExpression(
|
||||
"file:hashes.'SHA-256'",
|
||||
stix2.HashConstant(
|
||||
"aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f",
|
||||
'SHA-256',
|
||||
),
|
||||
)
|
||||
exp2 = stix2.EqualityComparisonExpression("file:mime_type", stix2.StringConstant("application/x-pdf"))
|
||||
bool_exp = stix2.AndBooleanExpression([exp1, exp2])
|
||||
exp = stix2.ObservationExpression(bool_exp)
|
||||
assert str(exp) == "[file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f' AND file:mime_type = 'application/x-pdf']" # noqa
|
||||
|
||||
|
||||
@pytest.mark.parametrize("observation_class, op", [
|
||||
(stix2.AndObservationExpression, 'AND'),
|
||||
(stix2.OrObservationExpression, 'OR'),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"observation_class, op", [
|
||||
(stix2.AndObservationExpression, 'AND'),
|
||||
(stix2.OrObservationExpression, 'OR'),
|
||||
],
|
||||
)
|
||||
def test_multiple_file_observable_expression(observation_class, op):
|
||||
exp1 = stix2.EqualityComparisonExpression("file:hashes.'SHA-256'",
|
||||
stix2.HashConstant(
|
||||
"bf07a7fbb825fc0aae7bf4a1177b2b31fcf8a3feeaf7092761e18c859ee52a9c",
|
||||
'SHA-256'))
|
||||
exp2 = stix2.EqualityComparisonExpression("file:hashes.MD5",
|
||||
stix2.HashConstant("cead3f77f6cda6ec00f57d76c9a6879f", "MD5"))
|
||||
exp1 = stix2.EqualityComparisonExpression(
|
||||
"file:hashes.'SHA-256'",
|
||||
stix2.HashConstant(
|
||||
"bf07a7fbb825fc0aae7bf4a1177b2b31fcf8a3feeaf7092761e18c859ee52a9c",
|
||||
'SHA-256',
|
||||
),
|
||||
)
|
||||
exp2 = stix2.EqualityComparisonExpression(
|
||||
"file:hashes.MD5",
|
||||
stix2.HashConstant("cead3f77f6cda6ec00f57d76c9a6879f", "MD5"),
|
||||
)
|
||||
bool1_exp = stix2.OrBooleanExpression([exp1, exp2])
|
||||
exp3 = stix2.EqualityComparisonExpression("file:hashes.'SHA-256'",
|
||||
stix2.HashConstant(
|
||||
"aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f",
|
||||
'SHA-256'))
|
||||
exp3 = stix2.EqualityComparisonExpression(
|
||||
"file:hashes.'SHA-256'",
|
||||
stix2.HashConstant(
|
||||
"aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f",
|
||||
'SHA-256',
|
||||
),
|
||||
)
|
||||
op1_exp = stix2.ObservationExpression(bool1_exp)
|
||||
op2_exp = stix2.ObservationExpression(exp3)
|
||||
exp = observation_class([op1_exp, op2_exp])
|
||||
|
@ -96,111 +131,177 @@ def test_multiple_file_observable_expression(observation_class, op):
|
|||
def test_root_types():
|
||||
ast = stix2.ObservationExpression(
|
||||
stix2.AndBooleanExpression(
|
||||
[stix2.ParentheticalExpression(
|
||||
stix2.OrBooleanExpression([
|
||||
stix2.EqualityComparisonExpression("a:b", stix2.StringConstant("1")),
|
||||
stix2.EqualityComparisonExpression("b:c", stix2.StringConstant("2"))])),
|
||||
stix2.EqualityComparisonExpression(u"b:d", stix2.StringConstant("3"))]))
|
||||
[
|
||||
stix2.ParentheticalExpression(
|
||||
stix2.OrBooleanExpression([
|
||||
stix2.EqualityComparisonExpression("a:b", stix2.StringConstant("1")),
|
||||
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']"
|
||||
|
||||
|
||||
def test_artifact_payload():
|
||||
exp1 = stix2.EqualityComparisonExpression("artifact:mime_type",
|
||||
"application/vnd.tcpdump.pcap")
|
||||
exp2 = stix2.MatchesComparisonExpression("artifact:payload_bin",
|
||||
stix2.StringConstant("\\xd4\\xc3\\xb2\\xa1\\x02\\x00\\x04\\x00"))
|
||||
exp1 = stix2.EqualityComparisonExpression(
|
||||
"artifact:mime_type",
|
||||
"application/vnd.tcpdump.pcap",
|
||||
)
|
||||
exp2 = stix2.MatchesComparisonExpression(
|
||||
"artifact:payload_bin",
|
||||
stix2.StringConstant("\\xd4\\xc3\\xb2\\xa1\\x02\\x00\\x04\\x00"),
|
||||
)
|
||||
and_exp = stix2.AndBooleanExpression([exp1, exp2])
|
||||
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
|
||||
|
||||
|
||||
def test_greater_than_python_constant():
|
||||
exp1 = stix2.GreaterThanComparisonExpression("file:extensions.windows-pebinary-ext.sections[*].entropy",
|
||||
7.0)
|
||||
exp1 = stix2.GreaterThanComparisonExpression(
|
||||
"file:extensions.windows-pebinary-ext.sections[*].entropy",
|
||||
7.0,
|
||||
)
|
||||
exp = stix2.ObservationExpression(exp1)
|
||||
assert str(exp) == "[file:extensions.windows-pebinary-ext.sections[*].entropy > 7.0]"
|
||||
|
||||
|
||||
def test_greater_than():
|
||||
exp1 = stix2.GreaterThanComparisonExpression("file:extensions.windows-pebinary-ext.sections[*].entropy",
|
||||
stix2.FloatConstant(7.0))
|
||||
exp1 = stix2.GreaterThanComparisonExpression(
|
||||
"file:extensions.windows-pebinary-ext.sections[*].entropy",
|
||||
stix2.FloatConstant(7.0),
|
||||
)
|
||||
exp = stix2.ObservationExpression(exp1)
|
||||
assert str(exp) == "[file:extensions.windows-pebinary-ext.sections[*].entropy > 7.0]"
|
||||
|
||||
|
||||
def test_less_than():
|
||||
exp = stix2.LessThanComparisonExpression("file:size",
|
||||
1024)
|
||||
exp = stix2.LessThanComparisonExpression(
|
||||
"file:size",
|
||||
1024,
|
||||
)
|
||||
assert str(exp) == "file:size < 1024"
|
||||
|
||||
|
||||
def test_greater_than_or_equal():
|
||||
exp = stix2.GreaterThanEqualComparisonExpression("file:size",
|
||||
1024)
|
||||
exp = stix2.GreaterThanEqualComparisonExpression(
|
||||
"file:size",
|
||||
1024,
|
||||
)
|
||||
assert str(exp) == "file:size >= 1024"
|
||||
|
||||
|
||||
def test_less_than_or_equal():
|
||||
exp = stix2.LessThanEqualComparisonExpression("file:size",
|
||||
1024)
|
||||
exp = stix2.LessThanEqualComparisonExpression(
|
||||
"file:size",
|
||||
1024,
|
||||
)
|
||||
assert str(exp) == "file:size <= 1024"
|
||||
|
||||
|
||||
def test_not():
|
||||
exp = stix2.LessThanComparisonExpression("file:size",
|
||||
1024,
|
||||
negated=True)
|
||||
exp = stix2.LessThanComparisonExpression(
|
||||
"file:size",
|
||||
1024,
|
||||
negated=True,
|
||||
)
|
||||
assert str(exp) == "file:size NOT < 1024"
|
||||
|
||||
|
||||
def test_and_observable_expression():
|
||||
exp1 = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("user-account:account_type",
|
||||
"unix"),
|
||||
stix2.EqualityComparisonExpression("user-account:user_id",
|
||||
stix2.StringConstant("1007")),
|
||||
stix2.EqualityComparisonExpression("user-account:account_login",
|
||||
"Peter")])
|
||||
exp2 = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("user-account:account_type",
|
||||
"unix"),
|
||||
stix2.EqualityComparisonExpression("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)])
|
||||
exp1 = stix2.AndBooleanExpression([
|
||||
stix2.EqualityComparisonExpression(
|
||||
"user-account:account_type",
|
||||
"unix",
|
||||
),
|
||||
stix2.EqualityComparisonExpression(
|
||||
"user-account:user_id",
|
||||
stix2.StringConstant("1007"),
|
||||
),
|
||||
stix2.EqualityComparisonExpression(
|
||||
"user-account:account_login",
|
||||
"Peter",
|
||||
),
|
||||
])
|
||||
exp2 = stix2.AndBooleanExpression([
|
||||
stix2.EqualityComparisonExpression(
|
||||
"user-account:account_type",
|
||||
"unix",
|
||||
),
|
||||
stix2.EqualityComparisonExpression(
|
||||
"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
|
||||
|
||||
|
||||
def test_invalid_and_observable_expression():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("user-account:display_name",
|
||||
"admin"),
|
||||
stix2.EqualityComparisonExpression("email-addr:display_name",
|
||||
stix2.StringConstant("admin"))])
|
||||
stix2.AndBooleanExpression([
|
||||
stix2.EqualityComparisonExpression(
|
||||
"user-account:display_name",
|
||||
"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)
|
||||
|
||||
|
||||
def test_hex():
|
||||
exp_and = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("file:mime_type",
|
||||
"image/bmp"),
|
||||
stix2.EqualityComparisonExpression("file:magic_number_hex",
|
||||
stix2.HexConstant("ffd8"))])
|
||||
exp_and = stix2.AndBooleanExpression([
|
||||
stix2.EqualityComparisonExpression(
|
||||
"file:mime_type",
|
||||
"image/bmp",
|
||||
),
|
||||
stix2.EqualityComparisonExpression(
|
||||
"file:magic_number_hex",
|
||||
stix2.HexConstant("ffd8"),
|
||||
),
|
||||
])
|
||||
exp = stix2.ObservationExpression(exp_and)
|
||||
assert str(exp) == "[file:mime_type = 'image/bmp' AND file:magic_number_hex = h'ffd8']"
|
||||
|
||||
|
||||
def test_multiple_qualifiers():
|
||||
exp_and = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("network-traffic:dst_ref.type",
|
||||
"domain-name"),
|
||||
stix2.EqualityComparisonExpression("network-traffic:dst_ref.value",
|
||||
"example.com")])
|
||||
exp_and = stix2.AndBooleanExpression([
|
||||
stix2.EqualityComparisonExpression(
|
||||
"network-traffic:dst_ref.type",
|
||||
"domain-name",
|
||||
),
|
||||
stix2.EqualityComparisonExpression(
|
||||
"network-traffic:dst_ref.value",
|
||||
"example.com",
|
||||
),
|
||||
])
|
||||
exp_ob = stix2.ObservationExpression(exp_and)
|
||||
qual_rep = stix2.RepeatQualifier(5)
|
||||
qual_within = stix2.WithinQualifier(stix2.IntegerConstant(1800))
|
||||
|
@ -209,8 +310,10 @@ def test_multiple_qualifiers():
|
|||
|
||||
|
||||
def test_set_op():
|
||||
exp = stix2.ObservationExpression(stix2.IsSubsetComparisonExpression("network-traffic:dst_ref.value",
|
||||
"2001:0db8:dead:beef:0000:0000:0000:0000/64"))
|
||||
exp = stix2.ObservationExpression(stix2.IsSubsetComparisonExpression(
|
||||
"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']"
|
||||
|
||||
|
||||
|
@ -220,35 +323,45 @@ def test_timestamp():
|
|||
|
||||
|
||||
def test_boolean():
|
||||
exp = stix2.EqualityComparisonExpression("email-message:is_multipart",
|
||||
True)
|
||||
exp = stix2.EqualityComparisonExpression(
|
||||
"email-message:is_multipart",
|
||||
True,
|
||||
)
|
||||
assert str(exp) == "email-message:is_multipart = true"
|
||||
|
||||
|
||||
def test_binary():
|
||||
const = stix2.BinaryConstant("dGhpcyBpcyBhIHRlc3Q=")
|
||||
exp = stix2.EqualityComparisonExpression("artifact:payload_bin",
|
||||
const)
|
||||
exp = stix2.EqualityComparisonExpression(
|
||||
"artifact:payload_bin",
|
||||
const,
|
||||
)
|
||||
assert str(exp) == "artifact:payload_bin = b'dGhpcyBpcyBhIHRlc3Q='"
|
||||
|
||||
|
||||
def test_list():
|
||||
exp = stix2.InComparisonExpression("process:name",
|
||||
['proccy', 'proximus', 'badproc'])
|
||||
exp = stix2.InComparisonExpression(
|
||||
"process:name",
|
||||
['proccy', 'proximus', 'badproc'],
|
||||
)
|
||||
assert str(exp) == "process:name IN ('proccy', 'proximus', 'badproc')"
|
||||
|
||||
|
||||
def test_list2():
|
||||
# alternate way to construct an "IN" Comparison Expression
|
||||
exp = stix2.EqualityComparisonExpression("process:name",
|
||||
['proccy', 'proximus', 'badproc'])
|
||||
exp = stix2.EqualityComparisonExpression(
|
||||
"process:name",
|
||||
['proccy', 'proximus', 'badproc'],
|
||||
)
|
||||
assert str(exp) == "process:name IN ('proccy', 'proximus', 'badproc')"
|
||||
|
||||
|
||||
def test_invalid_constant_type():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
stix2.EqualityComparisonExpression("artifact:payload_bin",
|
||||
{'foo': 'bar'})
|
||||
stix2.EqualityComparisonExpression(
|
||||
"artifact:payload_bin",
|
||||
{'foo': 'bar'},
|
||||
)
|
||||
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)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data, result", [
|
||||
(True, True),
|
||||
(False, False),
|
||||
('True', True),
|
||||
('False', False),
|
||||
('true', True),
|
||||
('false', False),
|
||||
('t', True),
|
||||
('f', False),
|
||||
('T', True),
|
||||
('F', False),
|
||||
(1, True),
|
||||
(0, False),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data, result", [
|
||||
(True, True),
|
||||
(False, False),
|
||||
('True', True),
|
||||
('False', False),
|
||||
('true', True),
|
||||
('false', False),
|
||||
('t', True),
|
||||
('f', False),
|
||||
('T', True),
|
||||
('F', False),
|
||||
(1, True),
|
||||
(0, False),
|
||||
],
|
||||
)
|
||||
def test_boolean_constant(data, result):
|
||||
boolean = stix2.BooleanConstant(data)
|
||||
assert boolean.value == result
|
||||
|
@ -295,10 +410,12 @@ def test_invalid_boolean_constant():
|
|||
assert 'must be a boolean' in str(excinfo)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("hashtype, data", [
|
||||
('MD5', 'zzz'),
|
||||
('ssdeep', 'zzz=='),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"hashtype, data", [
|
||||
('MD5', 'zzz'),
|
||||
('ssdeep', 'zzz=='),
|
||||
],
|
||||
)
|
||||
def test_invalid_hash_constant(hashtype, data):
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
stix2.HashConstant(data, hashtype)
|
||||
|
@ -318,20 +435,26 @@ def test_invalid_binary_constant():
|
|||
|
||||
|
||||
def test_escape_quotes_and_backslashes():
|
||||
exp = stix2.MatchesComparisonExpression("file:name",
|
||||
"^Final Report.+\\.exe$")
|
||||
exp = stix2.MatchesComparisonExpression(
|
||||
"file:name",
|
||||
"^Final Report.+\\.exe$",
|
||||
)
|
||||
assert str(exp) == "file:name MATCHES '^Final Report.+\\\\.exe$'"
|
||||
|
||||
|
||||
def test_like():
|
||||
exp = stix2.LikeComparisonExpression("directory:path",
|
||||
"C:\\Windows\\%\\foo")
|
||||
exp = stix2.LikeComparisonExpression(
|
||||
"directory:path",
|
||||
"C:\\Windows\\%\\foo",
|
||||
)
|
||||
assert str(exp) == "directory:path LIKE 'C:\\\\Windows\\\\%\\\\foo'"
|
||||
|
||||
|
||||
def test_issuperset():
|
||||
exp = stix2.IsSupersetComparisonExpression("ipv4-addr:value",
|
||||
"198.51.100.0/24")
|
||||
exp = stix2.IsSupersetComparisonExpression(
|
||||
"ipv4-addr:value",
|
||||
"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():
|
||||
qual = stix2.StartStopQualifier(stix2.TimestampConstant('2016-06-01T00:00:00Z'),
|
||||
datetime.datetime(2017, 3, 12, 8, 30, 0))
|
||||
qual = stix2.StartStopQualifier(
|
||||
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'"
|
||||
|
||||
qual2 = stix2.StartStopQualifier(datetime.date(2016, 6, 1),
|
||||
stix2.TimestampConstant('2016-07-01T00:00:00Z'))
|
||||
qual2 = stix2.StartStopQualifier(
|
||||
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'"
|
||||
|
||||
|
||||
def test_invalid_startstop_qualifier():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
stix2.StartStopQualifier('foo',
|
||||
stix2.TimestampConstant('2016-06-01T00:00:00Z'))
|
||||
stix2.StartStopQualifier(
|
||||
'foo',
|
||||
stix2.TimestampConstant('2016-06-01T00:00:00Z'),
|
||||
)
|
||||
assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo)
|
||||
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
stix2.StartStopQualifier(datetime.date(2016, 6, 1),
|
||||
'foo')
|
||||
stix2.StartStopQualifier(
|
||||
datetime.date(2016, 6, 1),
|
||||
'foo',
|
||||
)
|
||||
assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo)
|
||||
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ def test_pickling():
|
|||
id="identity--d66cb89d-5228-4983-958c-fa84ef75c88c",
|
||||
name="alice",
|
||||
description="this is a pickle test",
|
||||
identity_class="some_class"
|
||||
identity_class="some_class",
|
||||
)
|
||||
|
||||
pickle.loads(pickle.dumps(identity))
|
||||
|
|
|
@ -4,14 +4,13 @@ import pytest
|
|||
|
||||
import stix2
|
||||
from stix2.exceptions import AtLeastOnePropertyError, DictionaryKeyError
|
||||
from stix2.properties import (ERROR_INVALID_ID, BinaryProperty,
|
||||
BooleanProperty, DictionaryProperty,
|
||||
EmbeddedObjectProperty, EnumProperty,
|
||||
ExtensionsProperty, FloatProperty,
|
||||
HashesProperty, HexProperty, IDProperty,
|
||||
IntegerProperty, ListProperty, Property,
|
||||
ReferenceProperty, StringProperty,
|
||||
TimestampProperty, TypeProperty)
|
||||
from stix2.properties import (
|
||||
ERROR_INVALID_ID, BinaryProperty, BooleanProperty, DictionaryProperty,
|
||||
EmbeddedObjectProperty, EnumProperty, ExtensionsProperty, FloatProperty,
|
||||
HashesProperty, HexProperty, IDProperty, IntegerProperty, ListProperty,
|
||||
Property, ReferenceProperty, StringProperty, TimestampProperty,
|
||||
TypeProperty,
|
||||
)
|
||||
|
||||
from . import constants
|
||||
|
||||
|
@ -93,10 +92,12 @@ ID_PROP = IDProperty('my-type')
|
|||
MY_ID = 'my-type--232c9d3f-49fc-4440-bb01-607f638778e7'
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
MY_ID,
|
||||
'my-type--00000000-0000-4000-8000-000000000000',
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
MY_ID,
|
||||
'my-type--00000000-0000-4000-8000-000000000000',
|
||||
],
|
||||
)
|
||||
def test_id_property_valid(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--'."
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
'my-type--foo',
|
||||
# Not a v4 UUID
|
||||
'my-type--00000000-0000-0000-0000-000000000000',
|
||||
'my-type--' + str(uuid.uuid1()),
|
||||
'my-type--' + str(uuid.uuid3(uuid.NAMESPACE_DNS, "example.org")),
|
||||
'my-type--' + str(uuid.uuid5(uuid.NAMESPACE_DNS, "example.org")),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
'my-type--foo',
|
||||
# Not a v4 UUID
|
||||
'my-type--00000000-0000-0000-0000-000000000000',
|
||||
'my-type--' + str(uuid.uuid1()),
|
||||
'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):
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
ID_PROP.clean(value)
|
||||
|
@ -153,77 +156,89 @@ def test_id_property_default():
|
|||
assert ID_PROP.clean(default) == default
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
2,
|
||||
-1,
|
||||
3.14,
|
||||
False,
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
2,
|
||||
-1,
|
||||
3.14,
|
||||
False,
|
||||
],
|
||||
)
|
||||
def test_integer_property_valid(value):
|
||||
int_prop = IntegerProperty()
|
||||
assert int_prop.clean(value) is not None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
"something",
|
||||
StringProperty(),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
"something",
|
||||
StringProperty(),
|
||||
],
|
||||
)
|
||||
def test_integer_property_invalid(value):
|
||||
int_prop = IntegerProperty()
|
||||
with pytest.raises(ValueError):
|
||||
int_prop.clean(value)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
2,
|
||||
-1,
|
||||
3.14,
|
||||
False,
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
2,
|
||||
-1,
|
||||
3.14,
|
||||
False,
|
||||
],
|
||||
)
|
||||
def test_float_property_valid(value):
|
||||
int_prop = FloatProperty()
|
||||
assert int_prop.clean(value) is not None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
"something",
|
||||
StringProperty(),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
"something",
|
||||
StringProperty(),
|
||||
],
|
||||
)
|
||||
def test_float_property_invalid(value):
|
||||
int_prop = FloatProperty()
|
||||
with pytest.raises(ValueError):
|
||||
int_prop.clean(value)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
True,
|
||||
False,
|
||||
'True',
|
||||
'False',
|
||||
'true',
|
||||
'false',
|
||||
'TRUE',
|
||||
'FALSE',
|
||||
'T',
|
||||
'F',
|
||||
't',
|
||||
'f',
|
||||
1,
|
||||
0,
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
True,
|
||||
False,
|
||||
'True',
|
||||
'False',
|
||||
'true',
|
||||
'false',
|
||||
'TRUE',
|
||||
'FALSE',
|
||||
'T',
|
||||
'F',
|
||||
't',
|
||||
'f',
|
||||
1,
|
||||
0,
|
||||
],
|
||||
)
|
||||
def test_boolean_property_valid(value):
|
||||
bool_prop = BooleanProperty()
|
||||
|
||||
assert bool_prop.clean(value) is not None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
'abc',
|
||||
['false'],
|
||||
{'true': 'true'},
|
||||
2,
|
||||
-1,
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
'abc',
|
||||
['false'],
|
||||
{'true': 'true'},
|
||||
2,
|
||||
-1,
|
||||
],
|
||||
)
|
||||
def test_boolean_property_invalid(value):
|
||||
bool_prop = BooleanProperty()
|
||||
with pytest.raises(ValueError):
|
||||
|
@ -242,11 +257,13 @@ def test_reference_property():
|
|||
ref_prop.clean("my-type--00000000-0000-0000-0000-000000000000")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
'2017-01-01T12:34:56Z',
|
||||
'2017-01-01 12:34:56',
|
||||
'Jan 1 2017 12:34:56',
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
'2017-01-01T12:34:56Z',
|
||||
'2017-01-01 12:34:56',
|
||||
'Jan 1 2017 12:34:56',
|
||||
],
|
||||
)
|
||||
def test_timestamp_property_valid(value):
|
||||
ts_prop = TimestampProperty()
|
||||
assert ts_prop.clean(value) == constants.FAKE_TIME
|
||||
|
@ -276,25 +293,33 @@ def test_hex_property():
|
|||
hex_prop.clean("foobar")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("d", [
|
||||
{'description': 'something'},
|
||||
[('abc', 1), ('bcd', 2), ('cde', 3)],
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"d", [
|
||||
{'description': 'something'},
|
||||
[('abc', 1), ('bcd', 2), ('cde', 3)],
|
||||
],
|
||||
)
|
||||
def test_dictionary_property_valid(d):
|
||||
dict_prop = DictionaryProperty()
|
||||
assert dict_prop.clean(d)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("d", [
|
||||
[{'a': 'something'}, "Invalid dictionary key a: (shorter than 3 characters)."],
|
||||
[{'a'*300: 'something'}, "Invalid dictionary key aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"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 (_))."],
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"d", [
|
||||
[{'a': 'something'}, "Invalid dictionary key a: (shorter than 3 characters)."],
|
||||
[
|
||||
{'a'*300: 'something'}, "Invalid dictionary key aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"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):
|
||||
dict_prop = DictionaryProperty()
|
||||
|
||||
|
@ -304,18 +329,20 @@ def test_dictionary_property_invalid_key(d):
|
|||
assert str(excinfo.value) == d[1]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("d", [
|
||||
({}, "The dictionary property must contain a non-empty dictionary"),
|
||||
# TODO: This error message could be made more helpful. The error is caused
|
||||
# because `json.loads()` doesn't like the *single* quotes around the key
|
||||
# name, even though they are valid in a Python dictionary. While technically
|
||||
# accurate (a string is not a dictionary), if we want to be able to load
|
||||
# string-encoded "dictionaries" that are, we need a better error message
|
||||
# or an alternative to `json.loads()` ... and preferably *not* `eval()`. :-)
|
||||
# Changing the following to `'{"description": "something"}'` does not cause
|
||||
# any ValueError to be raised.
|
||||
("{'description': 'something'}", "The dictionary property must contain a dictionary"),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"d", [
|
||||
({}, "The dictionary property must contain a non-empty dictionary"),
|
||||
# TODO: This error message could be made more helpful. The error is caused
|
||||
# because `json.loads()` doesn't like the *single* quotes around the key
|
||||
# name, even though they are valid in a Python dictionary. While technically
|
||||
# accurate (a string is not a dictionary), if we want to be able to load
|
||||
# string-encoded "dictionaries" that are, we need a better error message
|
||||
# or an alternative to `json.loads()` ... and preferably *not* `eval()`. :-)
|
||||
# Changing the following to `'{"description": "something"}'` does not cause
|
||||
# any ValueError to be raised.
|
||||
("{'description': 'something'}", "The dictionary property must contain a dictionary"),
|
||||
],
|
||||
)
|
||||
def test_dictionary_property_invalid(d):
|
||||
dict_prop = DictionaryProperty()
|
||||
|
||||
|
@ -325,9 +352,11 @@ def test_dictionary_property_invalid(d):
|
|||
|
||||
|
||||
def test_property_list_of_dictionary():
|
||||
@stix2.v20.CustomObject('x-new-obj', [
|
||||
('property1', ListProperty(DictionaryProperty(), required=True)),
|
||||
])
|
||||
@stix2.v20.CustomObject(
|
||||
'x-new-obj', [
|
||||
('property1', ListProperty(DictionaryProperty(), required=True)),
|
||||
],
|
||||
)
|
||||
class NewObj():
|
||||
pass
|
||||
|
||||
|
@ -335,19 +364,23 @@ def test_property_list_of_dictionary():
|
|||
assert test_obj.property1[0]['foo'] == 'bar'
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
{"sha256": "6db12788c37247f2316052e142f42f4b259d6561751e5f401a1ae2a6df9c674b"},
|
||||
[('MD5', '2dfb1bcc980200c6706feee399d41b3f'), ('RIPEMD-160', 'b3a8cd8a27c90af79b3c81754f267780f443dfef')],
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
{"sha256": "6db12788c37247f2316052e142f42f4b259d6561751e5f401a1ae2a6df9c674b"},
|
||||
[('MD5', '2dfb1bcc980200c6706feee399d41b3f'), ('RIPEMD-160', 'b3a8cd8a27c90af79b3c81754f267780f443dfef')],
|
||||
],
|
||||
)
|
||||
def test_hashes_property_valid(value):
|
||||
hash_prop = HashesProperty()
|
||||
assert hash_prop.clean(value)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
{"MD5": "a"},
|
||||
{"SHA-256": "2dfb1bcc980200c6706feee399d41b3f"},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
{"MD5": "a"},
|
||||
{"SHA-256": "2dfb1bcc980200c6706feee399d41b3f"},
|
||||
],
|
||||
)
|
||||
def test_hashes_property_invalid(value):
|
||||
hash_prop = HashesProperty()
|
||||
|
||||
|
@ -360,7 +393,7 @@ def test_embedded_property():
|
|||
mime = stix2.v20.EmailMIMEComponent(
|
||||
content_type="text/plain; charset=utf-8",
|
||||
content_disposition="inline",
|
||||
body="Cats are funny!"
|
||||
body="Cats are funny!",
|
||||
)
|
||||
assert emb_prop.clean(mime)
|
||||
|
||||
|
@ -368,11 +401,13 @@ def test_embedded_property():
|
|||
emb_prop.clean("string")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
['a', 'b', 'c'],
|
||||
('a', 'b', 'c'),
|
||||
'b',
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
['a', 'b', 'c'],
|
||||
('a', 'b', 'c'),
|
||||
'b',
|
||||
],
|
||||
)
|
||||
def test_enum_property_valid(value):
|
||||
enum_prop = EnumProperty(value)
|
||||
assert enum_prop.clean('b')
|
||||
|
@ -388,17 +423,19 @@ def test_extension_property_valid():
|
|||
ext_prop = ExtensionsProperty(enclosing_type='file')
|
||||
assert ext_prop({
|
||||
'windows-pebinary-ext': {
|
||||
'pe_type': 'exe'
|
||||
'pe_type': 'exe',
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
1,
|
||||
{'foobar-ext': {
|
||||
'pe_type': 'exe'
|
||||
}},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
1,
|
||||
{'foobar-ext': {
|
||||
'pe_type': 'exe',
|
||||
}},
|
||||
],
|
||||
)
|
||||
def test_extension_property_invalid(data):
|
||||
ext_prop = ExtensionsProperty(enclosing_type='file')
|
||||
with pytest.raises(ValueError):
|
||||
|
@ -408,10 +445,12 @@ def test_extension_property_invalid(data):
|
|||
def test_extension_property_invalid_type():
|
||||
ext_prop = ExtensionsProperty(enclosing_type='indicator')
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
ext_prop.clean({
|
||||
'windows-pebinary-ext': {
|
||||
'pe_type': 'exe'
|
||||
}}
|
||||
ext_prop.clean(
|
||||
{
|
||||
'windows-pebinary-ext': {
|
||||
'pe_type': 'exe',
|
||||
},
|
||||
},
|
||||
)
|
||||
assert 'no extensions defined' in str(excinfo.value)
|
||||
|
||||
|
|
|
@ -5,8 +5,9 @@ import pytz
|
|||
|
||||
import stix2
|
||||
|
||||
from .constants import (FAKE_TIME, INDICATOR_ID, MALWARE_ID, RELATIONSHIP_ID,
|
||||
RELATIONSHIP_KWARGS)
|
||||
from .constants import (
|
||||
FAKE_TIME, INDICATOR_ID, MALWARE_ID, RELATIONSHIP_ID, RELATIONSHIP_KWARGS,
|
||||
)
|
||||
|
||||
EXPECTED_RELATIONSHIP = """{
|
||||
"type": "relationship",
|
||||
|
@ -91,7 +92,7 @@ def test_relationship_required_properties_target_ref():
|
|||
with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo:
|
||||
stix2.v20.Relationship(
|
||||
relationship_type='indicates',
|
||||
source_ref=INDICATOR_ID
|
||||
source_ref=INDICATOR_ID,
|
||||
)
|
||||
|
||||
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'
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED_RELATIONSHIP,
|
||||
{
|
||||
"created": "2016-04-06T20:06:37Z",
|
||||
"id": "relationship--df7c87eb-75d2-4948-af81-9d49d246f301",
|
||||
"modified": "2016-04-06T20:06:37Z",
|
||||
"relationship_type": "indicates",
|
||||
"source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
|
||||
"target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
|
||||
"type": "relationship"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED_RELATIONSHIP,
|
||||
{
|
||||
"created": "2016-04-06T20:06:37Z",
|
||||
"id": "relationship--df7c87eb-75d2-4948-af81-9d49d246f301",
|
||||
"modified": "2016-04-06T20:06:37Z",
|
||||
"relationship_type": "indicates",
|
||||
"source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
|
||||
"target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
|
||||
"type": "relationship",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_relationship(data):
|
||||
rel = stix2.parse(data, version="2.0")
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ def test_report_example():
|
|||
object_refs=[
|
||||
"indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2",
|
||||
"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=[
|
||||
stix2.v20.Indicator(id="indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", **INDICATOR_KWARGS),
|
||||
"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=[
|
||||
stix2.v20.Indicator(id="indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", **INDICATOR_KWARGS),
|
||||
"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
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2015-12-21T19:59:11.000Z",
|
||||
"created_by_ref": "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283",
|
||||
"description": "A simple report with an indicator and campaign",
|
||||
"id": "report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3",
|
||||
"labels": [
|
||||
"campaign"
|
||||
],
|
||||
"modified": "2015-12-21T19:59:11.000Z",
|
||||
"name": "The Black Vine Cyberespionage Group",
|
||||
"object_refs": [
|
||||
"indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2",
|
||||
"campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c",
|
||||
"relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a"
|
||||
],
|
||||
"published": "2016-01-20T17:00:00Z",
|
||||
"type": "report"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2015-12-21T19:59:11.000Z",
|
||||
"created_by_ref": "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283",
|
||||
"description": "A simple report with an indicator and campaign",
|
||||
"id": "report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3",
|
||||
"labels": [
|
||||
"campaign",
|
||||
],
|
||||
"modified": "2015-12-21T19:59:11.000Z",
|
||||
"name": "The Black Vine Cyberespionage Group",
|
||||
"object_refs": [
|
||||
"indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2",
|
||||
"campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c",
|
||||
"relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a",
|
||||
],
|
||||
"published": "2016-01-20T17:00:00Z",
|
||||
"type": "report",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_report(data):
|
||||
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.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.object_refs == ["indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2",
|
||||
"campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c",
|
||||
"relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a"]
|
||||
assert rept.object_refs == [
|
||||
"indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2",
|
||||
"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.labels == ["campaign"]
|
||||
assert rept.name == "The Black Vine Cyberespionage Group"
|
||||
|
|
|
@ -39,7 +39,7 @@ def test_sighting_all_required_properties():
|
|||
created=now,
|
||||
modified=now,
|
||||
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
|
||||
|
||||
|
@ -54,7 +54,7 @@ def test_sighting_bad_where_sighted_refs():
|
|||
created=now,
|
||||
modified=now,
|
||||
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
|
||||
|
@ -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'
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED_SIGHTING,
|
||||
{
|
||||
"created": "2016-04-06T20:06:37Z",
|
||||
"id": "sighting--bfbc19db-ec35-4e45-beed-f8bde2a772fb",
|
||||
"modified": "2016-04-06T20:06:37Z",
|
||||
"sighting_of_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
|
||||
"type": "sighting",
|
||||
"where_sighted_refs": [
|
||||
"identity--8cc7afd6-5455-4d2b-a736-e614ee631d99"
|
||||
]
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED_SIGHTING,
|
||||
{
|
||||
"created": "2016-04-06T20:06:37Z",
|
||||
"id": "sighting--bfbc19db-ec35-4e45-beed-f8bde2a772fb",
|
||||
"modified": "2016-04-06T20:06:37Z",
|
||||
"sighting_of_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
|
||||
"type": "sighting",
|
||||
"where_sighted_refs": [
|
||||
"identity--8cc7afd6-5455-4d2b-a736-e614ee631d99",
|
||||
],
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_sighting(data):
|
||||
sighting = stix2.parse(data, version="2.0")
|
||||
|
||||
|
|
|
@ -35,21 +35,23 @@ def test_threat_actor_example():
|
|||
assert str(threat_actor) == EXPECTED
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2016-04-06T20:03:48.000Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"description": "The Evil Org threat actor group",
|
||||
"id": "threat-actor--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"labels": [
|
||||
"crime-syndicate"
|
||||
],
|
||||
"modified": "2016-04-06T20:03:48.000Z",
|
||||
"name": "Evil Org",
|
||||
"type": "threat-actor"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2016-04-06T20:03:48.000Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"description": "The Evil Org threat actor group",
|
||||
"id": "threat-actor--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"labels": [
|
||||
"crime-syndicate",
|
||||
],
|
||||
"modified": "2016-04-06T20:03:48.000Z",
|
||||
"name": "Evil Org",
|
||||
"type": "threat-actor",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_threat_actor(data):
|
||||
actor = stix2.parse(data, version="2.0")
|
||||
|
||||
|
|
|
@ -46,20 +46,22 @@ def test_tool_example():
|
|||
assert str(tool) == EXPECTED
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2016-04-06T20:03:48Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"id": "tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"labels": [
|
||||
"remote-access"
|
||||
],
|
||||
"modified": "2016-04-06T20:03:48Z",
|
||||
"name": "VNC",
|
||||
"type": "tool"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2016-04-06T20:03:48Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"id": "tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"labels": [
|
||||
"remote-access",
|
||||
],
|
||||
"modified": "2016-04-06T20:03:48Z",
|
||||
"name": "VNC",
|
||||
"type": "tool",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_tool(data):
|
||||
tool = stix2.parse(data, version="2.0")
|
||||
|
||||
|
|
|
@ -12,76 +12,90 @@ amsterdam = pytz.timezone('Europe/Amsterdam')
|
|||
eastern = pytz.timezone('US/Eastern')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('dttm, timestamp', [
|
||||
(dt.datetime(2017, 1, 1, tzinfo=pytz.utc), '2017-01-01T00:00:00Z'),
|
||||
(amsterdam.localize(dt.datetime(2017, 1, 1)), '2016-12-31T23:00:00Z'),
|
||||
(eastern.localize(dt.datetime(2017, 1, 1, 12, 34, 56)), '2017-01-01T17:34:56Z'),
|
||||
(eastern.localize(dt.datetime(2017, 7, 1)), '2017-07-01T04:00:00Z'),
|
||||
(dt.datetime(2017, 7, 1), '2017-07-01T00:00:00Z'),
|
||||
(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='millisecond'), '2017-07-01T00:00:00.000Z'),
|
||||
(stix2.utils.STIXdatetime(2017, 7, 1, 0, 0, 0, 1, precision='second'), '2017-07-01T00:00:00Z'),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'dttm, timestamp', [
|
||||
(dt.datetime(2017, 1, 1, tzinfo=pytz.utc), '2017-01-01T00:00:00Z'),
|
||||
(amsterdam.localize(dt.datetime(2017, 1, 1)), '2016-12-31T23:00:00Z'),
|
||||
(eastern.localize(dt.datetime(2017, 1, 1, 12, 34, 56)), '2017-01-01T17:34:56Z'),
|
||||
(eastern.localize(dt.datetime(2017, 7, 1)), '2017-07-01T04:00:00Z'),
|
||||
(dt.datetime(2017, 7, 1), '2017-07-01T00:00:00Z'),
|
||||
(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='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):
|
||||
assert stix2.utils.format_datetime(dttm) == timestamp
|
||||
|
||||
|
||||
@pytest.mark.parametrize('timestamp, dttm', [
|
||||
(dt.datetime(2017, 1, 1, 0, tzinfo=pytz.utc), 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-01T00:00:00Z', 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)),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'timestamp, dttm', [
|
||||
(dt.datetime(2017, 1, 1, 0, tzinfo=pytz.utc), 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-01T00:00:00Z', 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):
|
||||
assert stix2.utils.parse_into_datetime(timestamp) == dttm
|
||||
|
||||
|
||||
@pytest.mark.parametrize('timestamp, dttm, precision', [
|
||||
('2017-01-01T01:02:03.000001', dt.datetime(2017, 1, 1, 1, 2, 3, 0, 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.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, 450000, tzinfo=pytz.utc), 'millisecond'),
|
||||
('2017-01-01T01:02:03.45', dt.datetime(2017, 1, 1, 1, 2, 3, tzinfo=pytz.utc), 'second'),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'timestamp, dttm, precision', [
|
||||
('2017-01-01T01:02:03.000001', dt.datetime(2017, 1, 1, 1, 2, 3, 0, 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.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, 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):
|
||||
assert stix2.utils.parse_into_datetime(timestamp, precision) == dttm
|
||||
|
||||
|
||||
@pytest.mark.parametrize('ts', [
|
||||
'foobar',
|
||||
1,
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'ts', [
|
||||
'foobar',
|
||||
1,
|
||||
],
|
||||
)
|
||||
def test_parse_datetime_invalid(ts):
|
||||
with pytest.raises(ValueError):
|
||||
stix2.utils.parse_into_datetime('foobar')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('data', [
|
||||
{"a": 1},
|
||||
'{"a": 1}',
|
||||
StringIO(u'{"a": 1}'),
|
||||
[("a", 1,)],
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'data', [
|
||||
{"a": 1},
|
||||
'{"a": 1}',
|
||||
StringIO(u'{"a": 1}'),
|
||||
[("a", 1,)],
|
||||
],
|
||||
)
|
||||
def test_get_dict(data):
|
||||
assert stix2.utils._get_dict(data)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('data', [
|
||||
1,
|
||||
[1],
|
||||
['a', 1],
|
||||
"foobar",
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'data', [
|
||||
1,
|
||||
[1],
|
||||
['a', 1],
|
||||
"foobar",
|
||||
],
|
||||
)
|
||||
def test_get_dict_invalid(data):
|
||||
with pytest.raises(ValueError):
|
||||
stix2.utils._get_dict(data)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('stix_id, type', [
|
||||
('malware--d69c8146-ab35-4d50-8382-6fc80e641d43', 'malware'),
|
||||
('intrusion-set--899ce53f-13a0-479b-a0e4-67d46e241542', 'intrusion-set')
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'stix_id, type', [
|
||||
('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):
|
||||
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
|
||||
|
||||
|
||||
@pytest.mark.parametrize('object, tuple_to_find, expected_index', [
|
||||
(stix2.v20.ObservedData(
|
||||
id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
|
||||
created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
created="2016-04-06T19:58:16.000Z",
|
||||
modified="2016-04-06T19:58:16.000Z",
|
||||
first_observed="2015-12-21T19:00:00Z",
|
||||
last_observed="2015-12-21T19:00:00Z",
|
||||
number_observed=50,
|
||||
objects={
|
||||
"0": {
|
||||
"name": "foo.exe",
|
||||
"type": "file"
|
||||
},
|
||||
"1": {
|
||||
"type": "ipv4-addr",
|
||||
"value": "198.51.100.3"
|
||||
},
|
||||
"2": {
|
||||
"type": "network-traffic",
|
||||
"src_ref": "1",
|
||||
"protocols": [
|
||||
"tcp",
|
||||
"http"
|
||||
],
|
||||
"extensions": {
|
||||
"http-request-ext": {
|
||||
"request_method": "get",
|
||||
"request_value": "/download.html",
|
||||
"request_version": "http/1.1",
|
||||
"request_header": {
|
||||
"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",
|
||||
"id": "x-example--d5413db2-c26c-42e0-b0e0-ec800a310bfb",
|
||||
"created": "2018-06-11T01:25:22.063Z",
|
||||
"modified": "2018-06-11T01:25:22.063Z",
|
||||
"dictionary": {
|
||||
"key": {
|
||||
"key_one": "value",
|
||||
"key_two": "value"
|
||||
}
|
||||
}
|
||||
}, ('key', {'key_one': 'value', 'key_two': 'value'}), 0),
|
||||
({
|
||||
"type": "language-content",
|
||||
"id": "language-content--b86bd89f-98bb-4fa9-8cb2-9ad421da981d",
|
||||
"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",
|
||||
"contents": {
|
||||
"de": {
|
||||
"name": "Bank Angriff 1",
|
||||
"description": "Weitere Informationen über Banküberfall"
|
||||
},
|
||||
"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)
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'object, tuple_to_find, expected_index', [
|
||||
(
|
||||
stix2.v20.ObservedData(
|
||||
id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
|
||||
created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
created="2016-04-06T19:58:16.000Z",
|
||||
modified="2016-04-06T19:58:16.000Z",
|
||||
first_observed="2015-12-21T19:00:00Z",
|
||||
last_observed="2015-12-21T19:00:00Z",
|
||||
number_observed=50,
|
||||
objects={
|
||||
"0": {
|
||||
"name": "foo.exe",
|
||||
"type": "file",
|
||||
},
|
||||
"1": {
|
||||
"type": "ipv4-addr",
|
||||
"value": "198.51.100.3",
|
||||
},
|
||||
"2": {
|
||||
"type": "network-traffic",
|
||||
"src_ref": "1",
|
||||
"protocols": [
|
||||
"tcp",
|
||||
"http",
|
||||
],
|
||||
"extensions": {
|
||||
"http-request-ext": {
|
||||
"request_method": "get",
|
||||
"request_value": "/download.html",
|
||||
"request_version": "http/1.1",
|
||||
"request_header": {
|
||||
"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",
|
||||
"id": "x-example--d5413db2-c26c-42e0-b0e0-ec800a310bfb",
|
||||
"created": "2018-06-11T01:25:22.063Z",
|
||||
"modified": "2018-06-11T01:25:22.063Z",
|
||||
"dictionary": {
|
||||
"key": {
|
||||
"key_one": "value",
|
||||
"key_two": "value",
|
||||
},
|
||||
},
|
||||
}, ('key', {'key_one': 'value', 'key_two': 'value'}), 0,
|
||||
),
|
||||
(
|
||||
{
|
||||
"type": "language-content",
|
||||
"id": "language-content--b86bd89f-98bb-4fa9-8cb2-9ad421da981d",
|
||||
"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",
|
||||
"contents": {
|
||||
"de": {
|
||||
"name": "Bank Angriff 1",
|
||||
"description": "Weitere Informationen über Banküberfall",
|
||||
},
|
||||
"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):
|
||||
assert stix2.utils.find_property_index(
|
||||
object,
|
||||
|
@ -182,29 +204,35 @@ def test_find_property_index(object, tuple_to_find, expected_index):
|
|||
) == expected_index
|
||||
|
||||
|
||||
@pytest.mark.parametrize('dict_value, tuple_to_find, expected_index', [
|
||||
({
|
||||
"contents": {
|
||||
"de": {
|
||||
"name": "Bank Angriff 1",
|
||||
"description": "Weitere Informationen über Banküberfall"
|
||||
},
|
||||
"fr": {
|
||||
"name": "Attaque Bank 1",
|
||||
"description": "Plus d'informations sur la crise bancaire"
|
||||
},
|
||||
"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': [
|
||||
{"key_one": 1},
|
||||
{"key_two": 2}
|
||||
]
|
||||
}, ('key_one', 1), 0)
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'dict_value, tuple_to_find, expected_index', [
|
||||
(
|
||||
{
|
||||
"contents": {
|
||||
"de": {
|
||||
"name": "Bank Angriff 1",
|
||||
"description": "Weitere Informationen über Banküberfall",
|
||||
},
|
||||
"fr": {
|
||||
"name": "Attaque Bank 1",
|
||||
"description": "Plus d'informations sur la crise bancaire",
|
||||
},
|
||||
"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': [
|
||||
{"key_one": 1},
|
||||
{"key_two": 2},
|
||||
],
|
||||
}, ('key_one', 1), 0,
|
||||
),
|
||||
],
|
||||
)
|
||||
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
|
||||
|
|
|
@ -37,15 +37,15 @@ def test_making_new_version_with_embedded_object():
|
|||
campaign_v1 = stix2.v20.Campaign(
|
||||
external_references=[{
|
||||
"source_name": "capec",
|
||||
"external_id": "CAPEC-163"
|
||||
"external_id": "CAPEC-163",
|
||||
}],
|
||||
**CAMPAIGN_MORE_KWARGS
|
||||
)
|
||||
|
||||
campaign_v2 = campaign_v1.new_version(external_references=[{
|
||||
"source_name": "capec",
|
||||
"external_id": "CAPEC-164"
|
||||
}])
|
||||
"external_id": "CAPEC-164",
|
||||
}])
|
||||
|
||||
assert campaign_v1.id == campaign_v2.id
|
||||
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."
|
||||
|
||||
msg = "Invalid value for {0} '{1}': {2}"
|
||||
msg = msg.format(stix2.v20.Campaign.__name__, "modified",
|
||||
"The new modified datetime cannot be before than or equal to the current modified datetime."
|
||||
"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 = msg.format(
|
||||
stix2.v20.Campaign.__name__, "modified",
|
||||
"The new modified datetime cannot be before than or equal to the current modified datetime."
|
||||
"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
|
||||
|
||||
|
||||
|
@ -215,10 +217,12 @@ def test_revoke_invalid_cls():
|
|||
|
||||
|
||||
def test_remove_custom_stix_property():
|
||||
mal = stix2.v20.Malware(name="ColePowers",
|
||||
labels=["rootkit"],
|
||||
x_custom="armada",
|
||||
allow_custom=True)
|
||||
mal = stix2.v20.Malware(
|
||||
name="ColePowers",
|
||||
labels=["rootkit"],
|
||||
x_custom="armada",
|
||||
allow_custom=True,
|
||||
)
|
||||
|
||||
mal_nc = stix2.utils.remove_custom_stix(mal)
|
||||
|
||||
|
@ -228,10 +232,12 @@ def test_remove_custom_stix_property():
|
|||
|
||||
|
||||
def test_remove_custom_stix_object():
|
||||
@stix2.v20.CustomObject("x-animal", [
|
||||
("species", stix2.properties.StringProperty(required=True)),
|
||||
("animal_class", stix2.properties.StringProperty()),
|
||||
])
|
||||
@stix2.v20.CustomObject(
|
||||
"x-animal", [
|
||||
("species", stix2.properties.StringProperty(required=True)),
|
||||
("animal_class", stix2.properties.StringProperty()),
|
||||
],
|
||||
)
|
||||
class Animal(object):
|
||||
pass
|
||||
|
||||
|
|
|
@ -29,30 +29,34 @@ def test_vulnerability_example():
|
|||
modified="2016-05-12T08:17:27.000Z",
|
||||
name="CVE-2016-1234",
|
||||
external_references=[
|
||||
stix2.v20.ExternalReference(source_name='cve',
|
||||
external_id="CVE-2016-1234"),
|
||||
stix2.v20.ExternalReference(
|
||||
source_name='cve',
|
||||
external_id="CVE-2016-1234",
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
assert str(vulnerability) == EXPECTED
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2016-05-12T08:17:27Z",
|
||||
"external_references": [
|
||||
{
|
||||
"external_id": "CVE-2016-1234",
|
||||
"source_name": "cve"
|
||||
}
|
||||
],
|
||||
"id": "vulnerability--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
|
||||
"modified": "2016-05-12T08:17:27Z",
|
||||
"name": "CVE-2016-1234",
|
||||
"type": "vulnerability"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2016-05-12T08:17:27Z",
|
||||
"external_references": [
|
||||
{
|
||||
"external_id": "CVE-2016-1234",
|
||||
"source_name": "cve",
|
||||
},
|
||||
],
|
||||
"id": "vulnerability--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
|
||||
"modified": "2016-05-12T08:17:27Z",
|
||||
"name": "CVE-2016-1234",
|
||||
"type": "vulnerability",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_vulnerability(data):
|
||||
vuln = stix2.parse(data, version="2.0")
|
||||
|
||||
|
|
|
@ -3,29 +3,25 @@ import os
|
|||
import pytest
|
||||
|
||||
import stix2
|
||||
from stix2.workbench import (AttackPattern, Campaign, CourseOfAction,
|
||||
ExternalReference, FileSystemSource, Filter,
|
||||
Identity, Indicator, IntrusionSet, Malware,
|
||||
MarkingDefinition, ObservedData, Relationship,
|
||||
Report, StatementMarking, ThreatActor, Tool,
|
||||
Vulnerability, add_data_source, all_versions,
|
||||
attack_patterns, campaigns, courses_of_action,
|
||||
create, get, identities, indicators,
|
||||
intrusion_sets, malware, observed_data, query,
|
||||
reports, save, set_default_created,
|
||||
set_default_creator, set_default_external_refs,
|
||||
set_default_object_marking_refs, threat_actors,
|
||||
tools, vulnerabilities)
|
||||
from stix2.workbench import (
|
||||
AttackPattern, Campaign, CourseOfAction, ExternalReference,
|
||||
FileSystemSource, Filter, Identity, Indicator, IntrusionSet, Malware,
|
||||
MarkingDefinition, ObservedData, Relationship, Report, StatementMarking,
|
||||
ThreatActor, Tool, Vulnerability, add_data_source, all_versions,
|
||||
attack_patterns, campaigns, courses_of_action, create, get, identities,
|
||||
indicators, intrusion_sets, malware, observed_data, query, 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,
|
||||
CAMPAIGN_KWARGS, COURSE_OF_ACTION_ID,
|
||||
COURSE_OF_ACTION_KWARGS, IDENTITY_ID, IDENTITY_KWARGS,
|
||||
INDICATOR_ID, INDICATOR_KWARGS, INTRUSION_SET_ID,
|
||||
INTRUSION_SET_KWARGS, MALWARE_ID, MALWARE_KWARGS,
|
||||
OBSERVED_DATA_ID, OBSERVED_DATA_KWARGS, REPORT_ID,
|
||||
REPORT_KWARGS, THREAT_ACTOR_ID, THREAT_ACTOR_KWARGS,
|
||||
TOOL_ID, TOOL_KWARGS, VULNERABILITY_ID,
|
||||
VULNERABILITY_KWARGS)
|
||||
from .constants import (
|
||||
ATTACK_PATTERN_ID, ATTACK_PATTERN_KWARGS, CAMPAIGN_ID, CAMPAIGN_KWARGS,
|
||||
COURSE_OF_ACTION_ID, COURSE_OF_ACTION_KWARGS, IDENTITY_ID, IDENTITY_KWARGS,
|
||||
INDICATOR_ID, INDICATOR_KWARGS, INTRUSION_SET_ID, INTRUSION_SET_KWARGS,
|
||||
MALWARE_ID, MALWARE_KWARGS, OBSERVED_DATA_ID, OBSERVED_DATA_KWARGS,
|
||||
REPORT_ID, REPORT_KWARGS, THREAT_ACTOR_ID, THREAT_ACTOR_KWARGS, TOOL_ID,
|
||||
TOOL_KWARGS, VULNERABILITY_ID, VULNERABILITY_KWARGS,
|
||||
)
|
||||
|
||||
|
||||
@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')
|
||||
def test_additional_filters_list():
|
||||
resp = tools([Filter('created_by_ref', '=', 'identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5'),
|
||||
Filter('name', '=', 'Windows Credential Editor')])
|
||||
resp = tools([
|
||||
Filter('created_by_ref', '=', 'identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5'),
|
||||
Filter('name', '=', 'Windows Credential Editor'),
|
||||
])
|
||||
assert len(resp) == 1
|
||||
|
||||
|
||||
|
@ -264,8 +262,10 @@ def test_default_created_timestamp():
|
|||
|
||||
|
||||
def test_default_external_refs():
|
||||
ext_ref = ExternalReference(source_name="ACME Threat Intel",
|
||||
description="Threat report")
|
||||
ext_ref = ExternalReference(
|
||||
source_name="ACME Threat Intel",
|
||||
description="Threat report",
|
||||
)
|
||||
set_default_external_refs(ext_ref)
|
||||
campaign = Campaign(**CAMPAIGN_KWARGS)
|
||||
|
||||
|
@ -275,8 +275,10 @@ def test_default_external_refs():
|
|||
|
||||
def test_default_object_marking_refs():
|
||||
stmt_marking = StatementMarking("Copyright 2016, Example Corp")
|
||||
mark_def = MarkingDefinition(definition_type="statement",
|
||||
definition=stmt_marking)
|
||||
mark_def = MarkingDefinition(
|
||||
definition_type="statement",
|
||||
definition=stmt_marking,
|
||||
)
|
||||
set_default_object_marking_refs(mark_def)
|
||||
campaign = Campaign(**CAMPAIGN_KWARGS)
|
||||
|
||||
|
@ -314,7 +316,7 @@ def test_workbench_custom_property_dict_in_observable_extension():
|
|||
'allow_custom': True,
|
||||
'sid': 1,
|
||||
'x_foo': 'bar',
|
||||
}
|
||||
},
|
||||
},
|
||||
)
|
||||
observed_data = ObservedData(
|
||||
|
|
|
@ -4,8 +4,9 @@ import pytest
|
|||
|
||||
import stix2
|
||||
|
||||
from .constants import (FAKE_TIME, INDICATOR_KWARGS, MALWARE_KWARGS,
|
||||
RELATIONSHIP_KWARGS)
|
||||
from .constants import (
|
||||
FAKE_TIME, INDICATOR_KWARGS, MALWARE_KWARGS, RELATIONSHIP_KWARGS,
|
||||
)
|
||||
|
||||
|
||||
# Inspired by: http://stackoverflow.com/a/24006251
|
||||
|
@ -54,66 +55,66 @@ def stix_objs1():
|
|||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||
"indicator_types": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"spec_version": "2.1",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
ind2 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||
"indicator_types": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"spec_version": "2.1",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
ind3 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||
"indicator_types": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.936Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"spec_version": "2.1",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
ind4 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||
"indicator_types": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"spec_version": "2.1",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
ind5 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||
"indicator_types": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"spec_version": "2.1",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
return [ind1, ind2, ind3, ind4, ind5]
|
||||
|
||||
|
@ -124,40 +125,40 @@ def stix_objs2():
|
|||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||
"indicator_types": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-31T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"spec_version": "2.1",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
ind7 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||
"indicator_types": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"spec_version": "2.1",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
ind8 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||
"indicator_types": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"spec_version": "2.1",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
return [ind6, ind7, ind8]
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ MARKING_IDS = [
|
|||
RELATIONSHIP_IDS = [
|
||||
'relationship--06520621-5352-4e6a-b976-e8fa3d437ffd',
|
||||
'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
|
||||
|
@ -81,7 +81,7 @@ INTRUSION_SET_KWARGS = dict(
|
|||
MALWARE_KWARGS = dict(
|
||||
malware_types=['ransomware'],
|
||||
name="Cryptolocker",
|
||||
is_family=True
|
||||
is_family=True,
|
||||
)
|
||||
|
||||
MALWARE_MORE_KWARGS = dict(
|
||||
|
@ -92,7 +92,7 @@ MALWARE_MORE_KWARGS = dict(
|
|||
malware_types=['ransomware'],
|
||||
name="Cryptolocker",
|
||||
description="A ransomware related to ...",
|
||||
is_family=False
|
||||
is_family=False,
|
||||
)
|
||||
|
||||
OBSERVED_DATA_KWARGS = dict(
|
||||
|
@ -103,8 +103,8 @@ OBSERVED_DATA_KWARGS = dict(
|
|||
"0": {
|
||||
"type": "windows-registry-key",
|
||||
"key": "HKEY_LOCAL_MACHINE\\System\\Foo\\Bar",
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
REPORT_KWARGS = dict(
|
||||
|
|
|
@ -32,7 +32,7 @@ def test_attack_pattern_example():
|
|||
name="Spear Phishing",
|
||||
external_references=[{
|
||||
"source_name": "capec",
|
||||
"external_id": "CAPEC-163"
|
||||
"external_id": "CAPEC-163",
|
||||
}],
|
||||
description="...",
|
||||
)
|
||||
|
@ -40,24 +40,26 @@ def test_attack_pattern_example():
|
|||
assert str(ap) == EXPECTED
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"type": "attack-pattern",
|
||||
"spec_version": "2.1",
|
||||
"id": "attack-pattern--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
|
||||
"created": "2016-05-12T08:17:27.000Z",
|
||||
"modified": "2016-05-12T08:17:27.000Z",
|
||||
"description": "...",
|
||||
"external_references": [
|
||||
{
|
||||
"external_id": "CAPEC-163",
|
||||
"source_name": "capec"
|
||||
}
|
||||
],
|
||||
"name": "Spear Phishing",
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"type": "attack-pattern",
|
||||
"spec_version": "2.1",
|
||||
"id": "attack-pattern--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
|
||||
"created": "2016-05-12T08:17:27.000Z",
|
||||
"modified": "2016-05-12T08:17:27.000Z",
|
||||
"description": "...",
|
||||
"external_references": [
|
||||
{
|
||||
"external_id": "CAPEC-163",
|
||||
"source_name": "capec",
|
||||
},
|
||||
],
|
||||
"name": "Spear Phishing",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_attack_pattern(data):
|
||||
ap = stix2.parse(data, version="2.1")
|
||||
|
||||
|
@ -79,7 +81,7 @@ def test_attack_pattern_invalid_labels():
|
|||
created="2016-05-12T08:17:27Z",
|
||||
modified="2016-05-12T08:17:27Z",
|
||||
name="Spear Phishing",
|
||||
labels=1
|
||||
labels=1,
|
||||
)
|
||||
|
||||
# TODO: Add other examples
|
||||
|
|
|
@ -58,8 +58,8 @@ EXPECTED_BUNDLE_DICT = {
|
|||
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
||||
"valid_from": "2017-01-01T12:34:56Z",
|
||||
"indicator_types": [
|
||||
"malicious-activity"
|
||||
]
|
||||
"malicious-activity",
|
||||
],
|
||||
},
|
||||
{
|
||||
"type": "malware",
|
||||
|
@ -69,9 +69,9 @@ EXPECTED_BUNDLE_DICT = {
|
|||
"modified": "2017-01-01T12:34:56.000Z",
|
||||
"name": "Cryptolocker",
|
||||
"malware_types": [
|
||||
"ransomware"
|
||||
"ransomware",
|
||||
],
|
||||
"is_family": True
|
||||
"is_family": True,
|
||||
},
|
||||
{
|
||||
"type": "relationship",
|
||||
|
@ -81,9 +81,9 @@ EXPECTED_BUNDLE_DICT = {
|
|||
"modified": "2017-01-01T12:34:56.000Z",
|
||||
"relationship_type": "indicates",
|
||||
"source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
|
||||
"target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e"
|
||||
}
|
||||
]
|
||||
"target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -26,25 +26,27 @@ def test_campaign_example():
|
|||
created="2016-04-06T20:03:00Z",
|
||||
modified="2016-04-06T20:03:00Z",
|
||||
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
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"type": "campaign",
|
||||
"spec_version": "2.1",
|
||||
"id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"created": "2016-04-06T20:03:00Z",
|
||||
"modified": "2016-04-06T20:03:00Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"description": "Campaign by Green Group against a series of targets in the financial services sector.",
|
||||
"name": "Green Group Attacks Against Finance",
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"type": "campaign",
|
||||
"spec_version": "2.1",
|
||||
"id": "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"created": "2016-04-06T20:03:00Z",
|
||||
"modified": "2016-04-06T20:03:00Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"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):
|
||||
cmpn = stix2.parse(data, version="2.1")
|
||||
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import pytest
|
||||
|
||||
from stix2.confidence.scales import (admiralty_credibility_to_value,
|
||||
dni_to_value, none_low_med_high_to_value,
|
||||
value_to_admiralty_credibility,
|
||||
value_to_dni,
|
||||
value_to_none_low_medium_high,
|
||||
value_to_wep, value_to_zero_ten,
|
||||
wep_to_value, zero_ten_to_value)
|
||||
from stix2.confidence.scales import (
|
||||
admiralty_credibility_to_value, dni_to_value, none_low_med_high_to_value,
|
||||
value_to_admiralty_credibility, value_to_dni,
|
||||
value_to_none_low_medium_high, 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"
|
||||
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.mark.parametrize("scale_value,result", [
|
||||
("None", 0),
|
||||
("Low", 15),
|
||||
("Med", 50),
|
||||
("High", 85)
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"scale_value,result", [
|
||||
("None", 0),
|
||||
("Low", 15),
|
||||
("Med", 50),
|
||||
("High", 85),
|
||||
],
|
||||
)
|
||||
def test_confidence_scale_valid_none_low_med_high(scale_value, result):
|
||||
val = none_low_med_high_to_value(scale_value)
|
||||
assert val == result
|
||||
|
||||
|
||||
@pytest.mark.parametrize("scale_value", [
|
||||
"Super",
|
||||
"none",
|
||||
""
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"scale_value", [
|
||||
"Super",
|
||||
"none",
|
||||
"",
|
||||
],
|
||||
)
|
||||
def test_confidence_scale_invalid_none_low_med_high(scale_value):
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
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.mark.parametrize("scale_value,result", [
|
||||
("0", 0),
|
||||
("1", 10),
|
||||
("2", 20),
|
||||
("3", 30),
|
||||
("4", 40),
|
||||
("5", 50),
|
||||
("6", 60),
|
||||
("7", 70),
|
||||
("8", 80),
|
||||
("9", 90),
|
||||
("10", 100)
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"scale_value,result", [
|
||||
("0", 0),
|
||||
("1", 10),
|
||||
("2", 20),
|
||||
("3", 30),
|
||||
("4", 40),
|
||||
("5", 50),
|
||||
("6", 60),
|
||||
("7", 70),
|
||||
("8", 80),
|
||||
("9", 90),
|
||||
("10", 100),
|
||||
],
|
||||
)
|
||||
def test_confidence_scale_valid_zero_ten(scale_value, result):
|
||||
val = zero_ten_to_value(scale_value)
|
||||
assert val == result
|
||||
|
||||
|
||||
@pytest.mark.parametrize("scale_value", [
|
||||
"11",
|
||||
8,
|
||||
""
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"scale_value", [
|
||||
"11",
|
||||
8,
|
||||
"",
|
||||
],
|
||||
)
|
||||
def test_confidence_scale_invalid_zero_ten(scale_value):
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
zero_ten_to_value(scale_value)
|
||||
|
@ -154,23 +161,27 @@ def test_confidence_range_admiralty_credibility():
|
|||
pytest.fail("Unexpected behavior %s" % val)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("scale_value,result", [
|
||||
("5 - Improbable", 10),
|
||||
("4 - Doubtful", 30),
|
||||
("3 - Possibly True", 50),
|
||||
("2 - Probably True", 70),
|
||||
("1 - Confirmed by other sources", 90)
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"scale_value,result", [
|
||||
("5 - Improbable", 10),
|
||||
("4 - Doubtful", 30),
|
||||
("3 - Possibly True", 50),
|
||||
("2 - Probably True", 70),
|
||||
("1 - Confirmed by other sources", 90),
|
||||
],
|
||||
)
|
||||
def test_confidence_scale_valid_admiralty_credibility(scale_value, result):
|
||||
val = admiralty_credibility_to_value(scale_value)
|
||||
assert val == result
|
||||
|
||||
|
||||
@pytest.mark.parametrize("scale_value", [
|
||||
"5 - improbable",
|
||||
"6 - Truth cannot be judged",
|
||||
""
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"scale_value", [
|
||||
"5 - improbable",
|
||||
"6 - Truth cannot be judged",
|
||||
"",
|
||||
],
|
||||
)
|
||||
def test_confidence_scale_invalid_admiralty_credibility(scale_value):
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
admiralty_credibility_to_value(scale_value)
|
||||
|
@ -207,25 +218,29 @@ def test_confidence_range_wep():
|
|||
pytest.fail("Unexpected behavior %s" % val)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("scale_value,result", [
|
||||
("Impossible", 0),
|
||||
("Highly Unlikely/Almost Certainly Not", 10),
|
||||
("Unlikely/Probably Not", 30),
|
||||
("Even Chance", 50),
|
||||
("Likely/Probable", 70),
|
||||
("Highly likely/Almost Certain", 90),
|
||||
("Certain", 100)
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"scale_value,result", [
|
||||
("Impossible", 0),
|
||||
("Highly Unlikely/Almost Certainly Not", 10),
|
||||
("Unlikely/Probably Not", 30),
|
||||
("Even Chance", 50),
|
||||
("Likely/Probable", 70),
|
||||
("Highly likely/Almost Certain", 90),
|
||||
("Certain", 100),
|
||||
],
|
||||
)
|
||||
def test_confidence_scale_valid_wep(scale_value, result):
|
||||
val = wep_to_value(scale_value)
|
||||
assert val == result
|
||||
|
||||
|
||||
@pytest.mark.parametrize("scale_value", [
|
||||
"Unlikely / Probably Not",
|
||||
"Almost certain",
|
||||
""
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"scale_value", [
|
||||
"Unlikely / Probably Not",
|
||||
"Almost certain",
|
||||
"",
|
||||
],
|
||||
)
|
||||
def test_confidence_scale_invalid_wep(scale_value):
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
wep_to_value(scale_value)
|
||||
|
@ -262,25 +277,29 @@ def test_confidence_range_dni():
|
|||
pytest.fail("Unexpected behavior %s" % val)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("scale_value,result", [
|
||||
("Almost No Chance / Remote", 5),
|
||||
("Very Unlikely / Highly Improbable", 15),
|
||||
("Unlikely / Improbable", 30),
|
||||
("Roughly Even Change / Roughly Even Odds", 50),
|
||||
("Likely / Probable", 70),
|
||||
("Very Likely / Highly Probable", 85),
|
||||
("Almost Certain / Nearly Certain", 95)
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"scale_value,result", [
|
||||
("Almost No Chance / Remote", 5),
|
||||
("Very Unlikely / Highly Improbable", 15),
|
||||
("Unlikely / Improbable", 30),
|
||||
("Roughly Even Change / Roughly Even Odds", 50),
|
||||
("Likely / Probable", 70),
|
||||
("Very Likely / Highly Probable", 85),
|
||||
("Almost Certain / Nearly Certain", 95),
|
||||
],
|
||||
)
|
||||
def test_confidence_scale_valid_dni(scale_value, result):
|
||||
val = dni_to_value(scale_value)
|
||||
assert val == result
|
||||
|
||||
|
||||
@pytest.mark.parametrize("scale_value", [
|
||||
"Almost Certain/Nearly Certain",
|
||||
"Almost Certain / nearly Certain",
|
||||
""
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"scale_value", [
|
||||
"Almost Certain/Nearly Certain",
|
||||
"Almost Certain / nearly Certain",
|
||||
"",
|
||||
],
|
||||
)
|
||||
def test_confidence_scale_invalid_none_dni(scale_value):
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
dni_to_value(scale_value)
|
||||
|
|
|
@ -26,25 +26,27 @@ def test_course_of_action_example():
|
|||
created="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",
|
||||
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
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2016-04-06T20:03:48.000Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"description": "This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ...",
|
||||
"id": "course-of-action--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"modified": "2016-04-06T20:03:48.000Z",
|
||||
"name": "Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter",
|
||||
"spec_version": "2.1",
|
||||
"type": "course-of-action"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2016-04-06T20:03:48.000Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"description": "This is how to add a filter rule to block inbound access to TCP port 80 to the existing UDP 1434 filter ...",
|
||||
"id": "course-of-action--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"modified": "2016-04-06T20:03:48.000Z",
|
||||
"name": "Add TCP port 80 Filter Rule to the existing Block UDP 1434 Filter",
|
||||
"spec_version": "2.1",
|
||||
"type": "course-of-action",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_course_of_action(data):
|
||||
coa = stix2.parse(data, version="2.1")
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ def test_identity_custom_property():
|
|||
"foo": "bar",
|
||||
},
|
||||
foo="bar",
|
||||
)
|
||||
)
|
||||
assert "Unexpected properties for Identity" in str(excinfo.value)
|
||||
|
||||
identity = stix2.v21.Identity(
|
||||
|
@ -80,8 +80,9 @@ def test_identity_custom_property_allowed():
|
|||
assert identity.x_foo == "bar"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
"""{
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
"""{
|
||||
"type": "identity",
|
||||
"spec_version": "2.1",
|
||||
"id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c",
|
||||
|
@ -91,7 +92,8 @@ def test_identity_custom_property_allowed():
|
|||
"identity_class": "individual",
|
||||
"foo": "bar"
|
||||
}""",
|
||||
])
|
||||
],
|
||||
)
|
||||
def test_parse_identity_custom_property(data):
|
||||
with pytest.raises(stix2.exceptions.ExtraPropertiesError) as excinfo:
|
||||
stix2.parse(data, version="2.1")
|
||||
|
@ -116,7 +118,7 @@ def test_custom_properties_object_in_bundled_object():
|
|||
identity_class="individual",
|
||||
custom_properties={
|
||||
"x_foo": "bar",
|
||||
}
|
||||
},
|
||||
)
|
||||
bundle = stix2.v21.Bundle(obj, allow_custom=True)
|
||||
|
||||
|
@ -164,7 +166,7 @@ def test_custom_property_in_observed_data():
|
|||
artifact = stix2.v21.File(
|
||||
allow_custom=True,
|
||||
name='test',
|
||||
x_foo='bar'
|
||||
x_foo='bar',
|
||||
)
|
||||
observed_data = stix2.v21.ObservedData(
|
||||
allow_custom=True,
|
||||
|
@ -208,7 +210,7 @@ def test_custom_property_dict_in_observable_extension():
|
|||
'ntfs-ext': {
|
||||
'sid': 1,
|
||||
'x_foo': 'bar',
|
||||
}
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -220,7 +222,7 @@ def test_custom_property_dict_in_observable_extension():
|
|||
'allow_custom': True,
|
||||
'sid': 1,
|
||||
'x_foo': 'bar',
|
||||
}
|
||||
},
|
||||
},
|
||||
)
|
||||
observed_data = stix2.v21.ObservedData(
|
||||
|
@ -244,12 +246,12 @@ def test_identity_custom_property_edit_markings():
|
|||
marking_obj = stix2.v21.MarkingDefinition(
|
||||
id=MARKING_DEFINITION_ID,
|
||||
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(
|
||||
id=MARKING_DEFINITION_ID,
|
||||
definition_type="statement",
|
||||
definition=stix2.v21.StatementMarking(statement="Another one")
|
||||
definition=stix2.v21.StatementMarking(statement="Another one"),
|
||||
)
|
||||
|
||||
# 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():
|
||||
@stix2.v21.CustomMarking('x-new-obj', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v21.CustomMarking(
|
||||
'x-new-obj', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewObj():
|
||||
pass
|
||||
|
||||
|
@ -273,9 +277,11 @@ def test_custom_marking_no_init_1():
|
|||
|
||||
|
||||
def test_custom_marking_no_init_2():
|
||||
@stix2.v21.CustomMarking('x-new-obj2', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v21.CustomMarking(
|
||||
'x-new-obj2', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewObj2(object):
|
||||
pass
|
||||
|
||||
|
@ -283,10 +289,12 @@ def test_custom_marking_no_init_2():
|
|||
assert no2.property1 == 'something'
|
||||
|
||||
|
||||
@stix2.v21.CustomObject('x-new-type', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
])
|
||||
@stix2.v21.CustomObject(
|
||||
'x-new-type', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
],
|
||||
)
|
||||
class NewType(object):
|
||||
def __init__(self, property2=None, **kwargs):
|
||||
if property2 and property2 < 10:
|
||||
|
@ -316,9 +324,11 @@ def test_custom_object_type():
|
|||
|
||||
|
||||
def test_custom_object_no_init_1():
|
||||
@stix2.v21.CustomObject('x-new-obj', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v21.CustomObject(
|
||||
'x-new-obj', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewObj():
|
||||
pass
|
||||
|
||||
|
@ -327,9 +337,11 @@ def test_custom_object_no_init_1():
|
|||
|
||||
|
||||
def test_custom_object_no_init_2():
|
||||
@stix2.v21.CustomObject('x-new-obj2', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v21.CustomObject(
|
||||
'x-new-obj2', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewObj2(object):
|
||||
pass
|
||||
|
||||
|
@ -339,17 +351,21 @@ def test_custom_object_no_init_2():
|
|||
|
||||
def test_custom_object_invalid_type_name():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v21.CustomObject('x', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v21.CustomObject(
|
||||
'x', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewObj(object):
|
||||
pass # pragma: no cover
|
||||
assert "Invalid type name 'x': " in str(excinfo.value)
|
||||
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v21.CustomObject('x_new_object', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v21.CustomObject(
|
||||
'x_new_object', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewObj2(object):
|
||||
pass # pragma: no cover
|
||||
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"
|
||||
|
||||
|
||||
@stix2.v21.CustomObservable('x-new-observable', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
('x_property3', stix2.properties.BooleanProperty()),
|
||||
])
|
||||
@stix2.v21.CustomObservable(
|
||||
'x-new-observable', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
('x_property3', stix2.properties.BooleanProperty()),
|
||||
],
|
||||
)
|
||||
class NewObservable():
|
||||
def __init__(self, property2=None, **kwargs):
|
||||
if property2 and property2 < 10:
|
||||
|
@ -432,9 +450,11 @@ def test_custom_observable_raises_exception():
|
|||
|
||||
|
||||
def test_custom_observable_object_no_init_1():
|
||||
@stix2.v21.CustomObservable('x-new-observable', [
|
||||
('property1', stix2.properties.StringProperty()),
|
||||
])
|
||||
@stix2.v21.CustomObservable(
|
||||
'x-new-observable', [
|
||||
('property1', stix2.properties.StringProperty()),
|
||||
],
|
||||
)
|
||||
class NewObs():
|
||||
pass
|
||||
|
||||
|
@ -443,9 +463,11 @@ def test_custom_observable_object_no_init_1():
|
|||
|
||||
|
||||
def test_custom_observable_object_no_init_2():
|
||||
@stix2.v21.CustomObservable('x-new-obs2', [
|
||||
('property1', stix2.properties.StringProperty()),
|
||||
])
|
||||
@stix2.v21.CustomObservable(
|
||||
'x-new-obs2', [
|
||||
('property1', stix2.properties.StringProperty()),
|
||||
],
|
||||
)
|
||||
class NewObs2(object):
|
||||
pass
|
||||
|
||||
|
@ -455,17 +477,21 @@ def test_custom_observable_object_no_init_2():
|
|||
|
||||
def test_custom_observable_object_invalid_type_name():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v21.CustomObservable('x', [
|
||||
('property1', stix2.properties.StringProperty()),
|
||||
])
|
||||
@stix2.v21.CustomObservable(
|
||||
'x', [
|
||||
('property1', stix2.properties.StringProperty()),
|
||||
],
|
||||
)
|
||||
class NewObs(object):
|
||||
pass # pragma: no cover
|
||||
assert "Invalid observable type name 'x':" in str(excinfo.value)
|
||||
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v21.CustomObservable('x_new_obs', [
|
||||
('property1', stix2.properties.StringProperty()),
|
||||
])
|
||||
@stix2.v21.CustomObservable(
|
||||
'x_new_obs', [
|
||||
('property1', stix2.properties.StringProperty()),
|
||||
],
|
||||
)
|
||||
class NewObs2(object):
|
||||
pass # pragma: no cover
|
||||
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():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v21.CustomObservable('x-new-obs', [
|
||||
('property_ref', stix2.properties.StringProperty()),
|
||||
])
|
||||
@stix2.v21.CustomObservable(
|
||||
'x-new-obs', [
|
||||
('property_ref', stix2.properties.StringProperty()),
|
||||
],
|
||||
)
|
||||
class NewObs():
|
||||
pass
|
||||
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():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v21.CustomObservable('x-new-obs', [
|
||||
('property_refs', stix2.properties.StringProperty()),
|
||||
])
|
||||
@stix2.v21.CustomObservable(
|
||||
'x-new-obs', [
|
||||
('property_refs', stix2.properties.StringProperty()),
|
||||
],
|
||||
)
|
||||
class NewObs():
|
||||
pass
|
||||
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():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v21.CustomObservable('x-new-obs', [
|
||||
('property_refs', stix2.properties.ListProperty(stix2.properties.StringProperty)),
|
||||
])
|
||||
@stix2.v21.CustomObservable(
|
||||
'x-new-obs', [
|
||||
('property_refs', stix2.properties.ListProperty(stix2.properties.StringProperty)),
|
||||
],
|
||||
)
|
||||
class NewObs():
|
||||
pass
|
||||
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():
|
||||
@stix2.v21.CustomObservable('x-new-obs', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property_ref', stix2.properties.ObjectReferenceProperty(valid_types='email-addr')),
|
||||
])
|
||||
@stix2.v21.CustomObservable(
|
||||
'x-new-obs', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property_ref', stix2.properties.ObjectReferenceProperty(valid_types='email-addr')),
|
||||
],
|
||||
)
|
||||
class NewObs():
|
||||
pass
|
||||
|
||||
with pytest.raises(Exception) as excinfo:
|
||||
NewObs(_valid_refs=['1'],
|
||||
property1='something',
|
||||
property_ref='1')
|
||||
NewObs(
|
||||
_valid_refs=['1'],
|
||||
property1='something',
|
||||
property_ref='1',
|
||||
)
|
||||
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'
|
||||
|
||||
|
||||
@stix2.v21.CustomExtension(stix2.v21.DomainName, 'x-new-ext', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
])
|
||||
@stix2.v21.CustomExtension(
|
||||
stix2.v21.DomainName, 'x-new-ext', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
],
|
||||
)
|
||||
class NewExtension():
|
||||
def __init__(self, property2=None, **kwargs):
|
||||
if property2 and property2 < 10:
|
||||
|
@ -689,13 +727,15 @@ def test_custom_extension_wrong_observable_type():
|
|||
name="abc.txt",
|
||||
extensions={
|
||||
"ntfs-ext": ext,
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
assert 'Cannot determine extension type' in excinfo.value.reason
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
"""{
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
"""{
|
||||
"keys": [
|
||||
{
|
||||
"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):
|
||||
@stix2.v21.CustomExtension(stix2.v21.UserAccount, 'some-extension', [
|
||||
('keys', stix2.properties.ListProperty(stix2.properties.DictionaryProperty, required=True))
|
||||
])
|
||||
@stix2.v21.CustomExtension(
|
||||
stix2.v21.UserAccount, 'some-extension', [
|
||||
('keys', stix2.properties.ListProperty(stix2.properties.DictionaryProperty, required=True)),
|
||||
],
|
||||
)
|
||||
class SomeCustomExtension:
|
||||
pass
|
||||
|
||||
|
@ -721,9 +764,11 @@ def test_custom_extension_invalid_observable():
|
|||
class Foo(object):
|
||||
pass
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v21.CustomExtension(Foo, 'x-new-ext', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v21.CustomExtension(
|
||||
Foo, 'x-new-ext', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class FooExtension():
|
||||
pass # pragma: no cover
|
||||
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):
|
||||
pass
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v21.CustomExtension(Bar, 'x-new-ext', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v21.CustomExtension(
|
||||
Bar, 'x-new-ext', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class BarExtension():
|
||||
pass
|
||||
assert "Unknown observable type" in str(excinfo.value)
|
||||
|
@ -742,9 +789,11 @@ def test_custom_extension_invalid_observable():
|
|||
class Baz(stix2.v21.observables._Observable):
|
||||
_type = 'Baz'
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v21.CustomExtension(Baz, 'x-new-ext', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v21.CustomExtension(
|
||||
Baz, 'x-new-ext', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class BazExtension():
|
||||
pass
|
||||
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():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v21.CustomExtension(stix2.v21.File, 'x', {
|
||||
'property1': stix2.properties.StringProperty(required=True),
|
||||
})
|
||||
@stix2.v21.CustomExtension(
|
||||
stix2.v21.File, 'x', {
|
||||
'property1': stix2.properties.StringProperty(required=True),
|
||||
},
|
||||
)
|
||||
class FooExtension():
|
||||
pass # pragma: no cover
|
||||
assert "Invalid extension type name 'x':" in str(excinfo.value)
|
||||
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
@stix2.v21.CustomExtension(stix2.v21.File, 'x_new_ext', {
|
||||
'property1': stix2.properties.StringProperty(required=True),
|
||||
})
|
||||
@stix2.v21.CustomExtension(
|
||||
stix2.v21.File, 'x_new_ext', {
|
||||
'property1': stix2.properties.StringProperty(required=True),
|
||||
},
|
||||
)
|
||||
class BlaExtension():
|
||||
pass # pragma: no cover
|
||||
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():
|
||||
@stix2.v21.CustomExtension(stix2.v21.DomainName, 'x-new-extension', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v21.CustomExtension(
|
||||
stix2.v21.DomainName, 'x-new-extension', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewExt():
|
||||
pass
|
||||
|
||||
|
@ -805,9 +860,11 @@ def test_custom_extension_no_init_1():
|
|||
|
||||
|
||||
def test_custom_extension_no_init_2():
|
||||
@stix2.v21.CustomExtension(stix2.v21.DomainName, 'x-new-ext2', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v21.CustomExtension(
|
||||
stix2.v21.DomainName, 'x-new-ext2', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewExt2(object):
|
||||
pass
|
||||
|
||||
|
@ -867,8 +924,9 @@ def test_extension_property_location():
|
|||
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",
|
||||
"spec_version": "2.1",
|
||||
"id": "x-example--336d8a9f-91f1-46c5-b142-6441bb9f8b8d",
|
||||
|
@ -881,18 +939,23 @@ def test_extension_property_location():
|
|||
}
|
||||
}
|
||||
}""",
|
||||
])
|
||||
],
|
||||
)
|
||||
def test_custom_object_nested_dictionary(data):
|
||||
@stix2.v21.CustomObject('x-example', [
|
||||
('dictionary', stix2.properties.DictionaryProperty()),
|
||||
])
|
||||
@stix2.v21.CustomObject(
|
||||
'x-example', [
|
||||
('dictionary', stix2.properties.DictionaryProperty()),
|
||||
],
|
||||
)
|
||||
class Example(object):
|
||||
def __init__(self, **kwargs):
|
||||
pass
|
||||
|
||||
example = Example(id='x-example--336d8a9f-91f1-46c5-b142-6441bb9f8b8d',
|
||||
created='2018-06-12T16:20:58.059Z',
|
||||
modified='2018-06-12T16:20:58.059Z',
|
||||
dictionary={'key': {'key_b': 'value', 'key_a': 'value'}})
|
||||
example = Example(
|
||||
id='x-example--336d8a9f-91f1-46c5-b142-6441bb9f8b8d',
|
||||
created='2018-06-12T16:20:58.059Z',
|
||||
modified='2018-06-12T16:20:58.059Z',
|
||||
dictionary={'key': {'key_b': 'value', 'key_a': 'value'}},
|
||||
)
|
||||
|
||||
assert data == str(example)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import pytest
|
||||
|
||||
from stix2.datastore import (CompositeDataSource, DataSink, DataSource,
|
||||
DataStoreMixin)
|
||||
from stix2.datastore import (
|
||||
CompositeDataSource, DataSink, DataSource, DataStoreMixin,
|
||||
)
|
||||
from stix2.datastore.filters import Filter
|
||||
from stix2.test.v21.constants import CAMPAIGN_MORE_KWARGS
|
||||
|
||||
|
@ -46,15 +47,19 @@ def test_datastore_creator_of_raises():
|
|||
|
||||
def test_datastore_relationships_raises():
|
||||
with pytest.raises(AttributeError) as excinfo:
|
||||
DataStoreMixin().relationships(obj="indicator--00000000-0000-4000-8000-000000000001",
|
||||
target_only=True)
|
||||
DataStoreMixin().relationships(
|
||||
obj="indicator--00000000-0000-4000-8000-000000000001",
|
||||
target_only=True,
|
||||
)
|
||||
assert "DataStoreMixin has no data source to query" == str(excinfo.value)
|
||||
|
||||
|
||||
def test_datastore_related_to_raises():
|
||||
with pytest.raises(AttributeError) as excinfo:
|
||||
DataStoreMixin().related_to(obj="indicator--00000000-0000-4000-8000-000000000001",
|
||||
target_only=True)
|
||||
DataStoreMixin().related_to(
|
||||
obj="indicator--00000000-0000-4000-8000-000000000001",
|
||||
target_only=True,
|
||||
)
|
||||
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():
|
||||
with pytest.raises(AttributeError) as excinfo:
|
||||
CompositeDataSource().relationships(obj="indicator--00000000-0000-4000-8000-000000000001",
|
||||
target_only=True)
|
||||
CompositeDataSource().relationships(
|
||||
obj="indicator--00000000-0000-4000-8000-000000000001",
|
||||
target_only=True,
|
||||
)
|
||||
assert "CompositeDataSource has no data sources" == str(excinfo.value)
|
||||
|
||||
|
||||
def test_composite_datastore_related_to_raises_error():
|
||||
with pytest.raises(AttributeError) as excinfo:
|
||||
CompositeDataSource().related_to(obj="indicator--00000000-0000-4000-8000-000000000001",
|
||||
target_only=True)
|
||||
CompositeDataSource().related_to(
|
||||
obj="indicator--00000000-0000-4000-8000-000000000001",
|
||||
target_only=True,
|
||||
)
|
||||
assert "CompositeDataSource has no data sources" == str(excinfo.value)
|
||||
|
||||
|
||||
|
|
|
@ -13,8 +13,10 @@ def test_add_remove_composite_datasource():
|
|||
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
cds.add_data_sources([ds1, ds2, ds1, ds3])
|
||||
assert str(excinfo.value) == ("DataSource (to be added) is not of type "
|
||||
"stix2.DataSource. DataSource type is '<class 'stix2.datastore.memory.MemorySink'>'")
|
||||
assert str(excinfo.value) == (
|
||||
"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])
|
||||
|
||||
|
@ -26,9 +28,11 @@ def test_add_remove_composite_datasource():
|
|||
|
||||
|
||||
def test_composite_datasource_operations(stix_objs1, stix_objs2):
|
||||
BUNDLE1 = dict(id="bundle--%s" % make_id(),
|
||||
objects=stix_objs1,
|
||||
type="bundle")
|
||||
BUNDLE1 = dict(
|
||||
id="bundle--%s" % make_id(),
|
||||
objects=stix_objs1,
|
||||
type="bundle",
|
||||
)
|
||||
cds1 = CompositeDataSource()
|
||||
ds1_1 = MemorySource(stix_data=BUNDLE1)
|
||||
ds1_2 = MemorySource(stix_data=stix_objs2)
|
||||
|
@ -54,11 +58,11 @@ def test_composite_datasource_operations(stix_objs1, stix_objs2):
|
|||
assert indicator["type"] == "indicator"
|
||||
|
||||
query1 = [
|
||||
Filter("type", "=", "indicator")
|
||||
Filter("type", "=", "indicator"),
|
||||
]
|
||||
|
||||
query2 = [
|
||||
Filter("valid_from", "=", "2017-01-27T13:49:53.935382Z")
|
||||
Filter("valid_from", "=", "2017-01-27T13:49:53.935382Z"),
|
||||
]
|
||||
|
||||
cds1.filters.add(query2)
|
||||
|
|
|
@ -5,11 +5,10 @@ import shutil
|
|||
import pytest
|
||||
|
||||
import stix2
|
||||
from stix2.test.v21.constants import (CAMPAIGN_ID, CAMPAIGN_KWARGS,
|
||||
IDENTITY_ID, IDENTITY_KWARGS,
|
||||
INDICATOR_ID, INDICATOR_KWARGS,
|
||||
MALWARE_ID, MALWARE_KWARGS,
|
||||
RELATIONSHIP_IDS)
|
||||
from stix2.test.v21.constants import (
|
||||
CAMPAIGN_ID, CAMPAIGN_KWARGS, IDENTITY_ID, IDENTITY_KWARGS, INDICATOR_ID,
|
||||
INDICATOR_KWARGS, MALWARE_ID, MALWARE_KWARGS, RELATIONSHIP_IDS,
|
||||
)
|
||||
|
||||
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
|
||||
stix_obj = {
|
||||
"id": "intrusion-set--test-bad-stix",
|
||||
"spec_version": "2.0"
|
||||
"spec_version": "2.0",
|
||||
# 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):
|
||||
# add python stix object
|
||||
camp1 = stix2.v21.Campaign(name="Hannibal",
|
||||
objective="Targeting Italian and Spanish Diplomat internet accounts",
|
||||
aliases=["War Elephant"])
|
||||
camp1 = stix2.v21.Campaign(
|
||||
name="Hannibal",
|
||||
objective="Targeting Italian and Spanish Diplomat internet accounts",
|
||||
aliases=["War Elephant"],
|
||||
)
|
||||
|
||||
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",
|
||||
"aliases": ["Purple Robes"],
|
||||
"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)
|
||||
|
@ -226,9 +227,9 @@ def test_filesystem_sink_add_stix_bundle_dict(fs_sink, fs_source):
|
|||
"objective": "Bulgarian, Albanian and Romanian Intelligence Services",
|
||||
"aliases": ["Huns"],
|
||||
"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)
|
||||
|
@ -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):
|
||||
# add list of objects
|
||||
camp6 = stix2.v21.Campaign(name="Comanche",
|
||||
objective="US Midwest manufacturing firms, oil refineries, and businesses",
|
||||
aliases=["Horse Warrior"])
|
||||
camp6 = stix2.v21.Campaign(
|
||||
name="Comanche",
|
||||
objective="US Midwest manufacturing firms, oil refineries, and businesses",
|
||||
aliases=["Horse Warrior"],
|
||||
)
|
||||
|
||||
camp7 = {
|
||||
"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",
|
||||
"aliases": ["The Frenchmen"],
|
||||
"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])
|
||||
|
@ -365,9 +368,11 @@ def test_filesystem_store_query_dont_include_type_folder(fs_store):
|
|||
|
||||
def test_filesystem_store_add(fs_store):
|
||||
# add()
|
||||
camp1 = stix2.v21.Campaign(name="Great Heathen Army",
|
||||
objective="Targeting the government of United Kingdom and insitutions affiliated with the Church Of England",
|
||||
aliases=["Ragnar"])
|
||||
camp1 = stix2.v21.Campaign(
|
||||
name="Great Heathen Army",
|
||||
objective="Targeting the government of United Kingdom and insitutions affiliated with the Church Of England",
|
||||
aliases=["Ragnar"],
|
||||
)
|
||||
fs_store.add(camp1)
|
||||
|
||||
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():
|
||||
fs_store = stix2.FileSystemStore(FS_PATH, bundlify=True)
|
||||
|
||||
camp1 = stix2.v21.Campaign(name="Great Heathen Army",
|
||||
objective="Targeting the government of United Kingdom and insitutions affiliated with the Church Of England",
|
||||
aliases=["Ragnar"])
|
||||
camp1 = stix2.v21.Campaign(
|
||||
name="Great Heathen Army",
|
||||
objective="Targeting the government of United Kingdom and insitutions affiliated with the Church Of England",
|
||||
aliases=["Ragnar"],
|
||||
)
|
||||
fs_store.add(camp1)
|
||||
|
||||
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):
|
||||
camp = stix2.v21.Campaign(name="Scipio Africanus",
|
||||
objective="Defeat the Carthaginians",
|
||||
x_empire="Roman",
|
||||
allow_custom=True)
|
||||
camp = stix2.v21.Campaign(
|
||||
name="Scipio Africanus",
|
||||
objective="Defeat the Carthaginians",
|
||||
x_empire="Roman",
|
||||
allow_custom=True,
|
||||
)
|
||||
|
||||
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):
|
||||
camp = stix2.v21.Campaign(name="Scipio Africanus",
|
||||
objective="Defeat the Carthaginians",
|
||||
x_empire="Roman",
|
||||
allow_custom=True)
|
||||
camp = stix2.v21.Campaign(
|
||||
name="Scipio Africanus",
|
||||
objective="Defeat the Carthaginians",
|
||||
x_empire="Roman",
|
||||
allow_custom=True,
|
||||
)
|
||||
|
||||
bundle = stix2.v21.Bundle(camp, allow_custom=True)
|
||||
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):
|
||||
@stix2.v21.CustomObject('x-new-obj', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
])
|
||||
@stix2.v21.CustomObject(
|
||||
'x-new-obj', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewObj():
|
||||
pass
|
||||
|
||||
|
|
|
@ -11,25 +11,25 @@ stix_objs = [
|
|||
"id": "malware--fdd60b30-b67c-41e3-b0b9-f01faf20d111",
|
||||
"spec_version": "2.1",
|
||||
"malware_types": [
|
||||
"remote-access-trojan"
|
||||
"remote-access-trojan",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.997Z",
|
||||
"name": "Poison Ivy",
|
||||
"type": "malware",
|
||||
"is_family": False
|
||||
"is_family": False,
|
||||
},
|
||||
{
|
||||
"created": "2014-05-08T09:00:00.000Z",
|
||||
"id": "indicator--a932fcc6-e032-476c-826f-cb970a5a1ade",
|
||||
"indicator_types": [
|
||||
"file-hash-watchlist"
|
||||
"file-hash-watchlist",
|
||||
],
|
||||
"modified": "2014-05-08T09:00:00.000Z",
|
||||
"name": "File hash for Poison Ivy variant",
|
||||
"pattern": "[file:hashes.'SHA-256' = 'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c']",
|
||||
"spec_version": "2.1",
|
||||
"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",
|
||||
|
@ -37,21 +37,21 @@ stix_objs = [
|
|||
{
|
||||
"marking_ref": "marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed",
|
||||
"selectors": [
|
||||
"relationship_type"
|
||||
]
|
||||
}
|
||||
"relationship_type",
|
||||
],
|
||||
},
|
||||
],
|
||||
"id": "relationship--2f9a9aa9-108a-4333-83e2-4fb25add0463",
|
||||
"modified": "2014-05-08T09:00:00.000Z",
|
||||
"object_marking_refs": [
|
||||
"marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9"
|
||||
"marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
|
||||
],
|
||||
"relationship_type": "indicates",
|
||||
"revoked": True,
|
||||
"source_ref": "indicator--a932fcc6-e032-476c-826f-cb970a5a1ade",
|
||||
"spec_version": "2.1",
|
||||
"target_ref": "malware--fdd60b30-b67c-41e3-b0b9-f01faf20d111",
|
||||
"type": "relationship"
|
||||
"type": "relationship",
|
||||
},
|
||||
{
|
||||
"id": "vulnerability--ee916c28-c7a4-4d0d-ad56-a8d357f89fef",
|
||||
|
@ -65,10 +65,10 @@ stix_objs = [
|
|||
"external_references": [
|
||||
{
|
||||
"source_name": "cve",
|
||||
"external_id": "CVE-2014-0160"
|
||||
}
|
||||
"external_id": "CVE-2014-0160",
|
||||
},
|
||||
],
|
||||
"labels": ["heartbleed", "has-logo"]
|
||||
"labels": ["heartbleed", "has-logo"],
|
||||
},
|
||||
{
|
||||
"type": "observed-data",
|
||||
|
@ -83,11 +83,11 @@ stix_objs = [
|
|||
"objects": {
|
||||
"0": {
|
||||
"type": "file",
|
||||
"name": "HAL 9000.exe"
|
||||
}
|
||||
}
|
||||
"name": "HAL 9000.exe",
|
||||
},
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
|
@ -420,8 +420,10 @@ def test_filters4():
|
|||
# Assert invalid Filter cannot be created
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
Filter("modified", "?", "2017-01-27T13:49:53.935Z")
|
||||
assert str(excinfo.value) == ("Filter operator '?' not supported "
|
||||
"for specified property: 'modified'")
|
||||
assert str(excinfo.value) == (
|
||||
"Filter operator '?' not supported "
|
||||
"for specified property: 'modified'"
|
||||
)
|
||||
|
||||
|
||||
def test_filters5(stix_objs2, real_stix_objs2):
|
||||
|
@ -462,7 +464,7 @@ def test_filters7(stix_objs2, real_stix_objs2):
|
|||
"0": {
|
||||
"type": "file",
|
||||
"hashes": {
|
||||
"SHA-256": "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f"
|
||||
"SHA-256": "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f",
|
||||
},
|
||||
"extensions": {
|
||||
"pdf-ext": {
|
||||
|
@ -472,14 +474,14 @@ def test_filters7(stix_objs2, real_stix_objs2):
|
|||
"Author": "Adobe Systems Incorporated",
|
||||
"Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh",
|
||||
"Producer": "Acrobat Distiller 3.01 for Power Macintosh",
|
||||
"CreationDate": "20070412090123-02"
|
||||
"CreationDate": "20070412090123-02",
|
||||
},
|
||||
"pdfid0": "DFCE52BD827ECF765649852119D",
|
||||
"pdfid1": "57A1E0F9ED2AE523E313C"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"pdfid1": "57A1E0F9ED2AE523E313C",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
stix_objects = list(stix_objs2) + [obsvd_data_obj]
|
||||
|
|
|
@ -5,116 +5,118 @@ import pytest
|
|||
|
||||
from stix2 import Filter, MemorySource, MemoryStore, properties
|
||||
from stix2.datastore import make_id
|
||||
from stix2.v21 import (Bundle, Campaign, CustomObject, Identity, Indicator,
|
||||
Malware, Relationship)
|
||||
from stix2.v21 import (
|
||||
Bundle, Campaign, CustomObject, Identity, Indicator, Malware, Relationship,
|
||||
)
|
||||
|
||||
from .constants import (CAMPAIGN_ID, CAMPAIGN_KWARGS, IDENTITY_ID,
|
||||
IDENTITY_KWARGS, INDICATOR_ID, INDICATOR_KWARGS,
|
||||
MALWARE_ID, MALWARE_KWARGS, RELATIONSHIP_IDS)
|
||||
from .constants import (
|
||||
CAMPAIGN_ID, CAMPAIGN_KWARGS, IDENTITY_ID, IDENTITY_KWARGS, INDICATOR_ID,
|
||||
INDICATOR_KWARGS, MALWARE_ID, MALWARE_KWARGS, RELATIONSHIP_IDS,
|
||||
)
|
||||
|
||||
IND1 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||
"indicator_types": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"spec_version": "2.1",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
IND2 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||
"indicator_types": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"spec_version": "2.1",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
IND3 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||
"indicator_types": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.936Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"spec_version": "2.1",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
IND4 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||
"indicator_types": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"spec_version": "2.1",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
IND5 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||
"indicator_types": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"spec_version": "2.1",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
IND6 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000001",
|
||||
"indicator_types": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-31T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"spec_version": "2.1",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
IND7 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||
"indicator_types": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"spec_version": "2.1",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
IND8 = {
|
||||
"created": "2017-01-27T13:49:53.935Z",
|
||||
"id": "indicator--00000000-0000-4000-8000-000000000002",
|
||||
"indicator_types": [
|
||||
"url-watchlist"
|
||||
"url-watchlist",
|
||||
],
|
||||
"modified": "2017-01-27T13:49:53.935Z",
|
||||
"name": "Malicious site hosting downloader",
|
||||
"pattern": "[url:value = 'http://x4z9arb.cn/4712']",
|
||||
"spec_version": "2.1",
|
||||
"type": "indicator",
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z"
|
||||
"valid_from": "2017-01-27T13:49:53.935382Z",
|
||||
}
|
||||
|
||||
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):
|
||||
# Add bundle of items to sink
|
||||
mem_store.add(dict(id="bundle--%s" % make_id(),
|
||||
objects=STIX_OBJS2,
|
||||
spec_version="2.0",
|
||||
type="bundle"))
|
||||
mem_store.add(dict(
|
||||
id="bundle--%s" % make_id(),
|
||||
objects=STIX_OBJS2,
|
||||
spec_version="2.0",
|
||||
type="bundle",
|
||||
))
|
||||
|
||||
resp = mem_store.all_versions("indicator--00000000-0000-4000-8000-000000000001")
|
||||
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):
|
||||
camp = Campaign(name="Scipio Africanus",
|
||||
objective="Defeat the Carthaginians",
|
||||
x_empire="Roman",
|
||||
allow_custom=True)
|
||||
camp = Campaign(
|
||||
name="Scipio Africanus",
|
||||
objective="Defeat the Carthaginians",
|
||||
x_empire="Roman",
|
||||
allow_custom=True,
|
||||
)
|
||||
|
||||
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):
|
||||
camp = Campaign(name="Scipio Africanus",
|
||||
objective="Defeat the Carthaginians",
|
||||
x_empire="Roman",
|
||||
allow_custom=True)
|
||||
camp = Campaign(
|
||||
name="Scipio Africanus",
|
||||
objective="Defeat the Carthaginians",
|
||||
x_empire="Roman",
|
||||
allow_custom=True,
|
||||
)
|
||||
|
||||
bundle = Bundle(camp, allow_custom=True)
|
||||
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):
|
||||
@CustomObject('x-new-obj', [
|
||||
('property1', properties.StringProperty(required=True)),
|
||||
])
|
||||
@CustomObject(
|
||||
'x-new-obj', [
|
||||
('property1', properties.StringProperty(required=True)),
|
||||
],
|
||||
)
|
||||
class NewObj():
|
||||
pass
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ class MockTAXIICollectionEndpoint(Collection):
|
|||
objs = full_filter.process_filter(
|
||||
self.objects,
|
||||
("id", "type", "version"),
|
||||
[]
|
||||
[],
|
||||
)
|
||||
if objs:
|
||||
return stix2.v21.Bundle(objects=objs)
|
||||
|
@ -56,7 +56,7 @@ class MockTAXIICollectionEndpoint(Collection):
|
|||
objs = full_filter.process_filter(
|
||||
self.objects,
|
||||
("version",),
|
||||
[]
|
||||
[],
|
||||
)
|
||||
if objs:
|
||||
return stix2.v21.Bundle(objects=objs)
|
||||
|
@ -68,16 +68,18 @@ class MockTAXIICollectionEndpoint(Collection):
|
|||
|
||||
@pytest.fixture
|
||||
def collection(stix_objs1):
|
||||
mock = MockTAXIICollectionEndpoint(COLLECTION_URL, **{
|
||||
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
|
||||
"title": "Writable Collection",
|
||||
"description": "This collection is a dropbox for submitting indicators",
|
||||
"can_read": True,
|
||||
"can_write": True,
|
||||
"media_types": [
|
||||
"application/vnd.oasis.stix+json; version=2.0"
|
||||
]
|
||||
})
|
||||
mock = MockTAXIICollectionEndpoint(
|
||||
COLLECTION_URL, **{
|
||||
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
|
||||
"title": "Writable Collection",
|
||||
"description": "This collection is a dropbox for submitting indicators",
|
||||
"can_read": True,
|
||||
"can_write": True,
|
||||
"media_types": [
|
||||
"application/vnd.oasis.stix+json; version=2.0",
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
mock.objects.extend(stix_objs1)
|
||||
return mock
|
||||
|
@ -85,16 +87,18 @@ def collection(stix_objs1):
|
|||
|
||||
@pytest.fixture
|
||||
def collection_no_rw_access(stix_objs1):
|
||||
mock = MockTAXIICollectionEndpoint(COLLECTION_URL, **{
|
||||
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
|
||||
"title": "Not writeable or readable Collection",
|
||||
"description": "This collection is a dropbox for submitting indicators",
|
||||
"can_read": False,
|
||||
"can_write": False,
|
||||
"media_types": [
|
||||
"application/vnd.oasis.stix+json; version=2.0"
|
||||
]
|
||||
})
|
||||
mock = MockTAXIICollectionEndpoint(
|
||||
COLLECTION_URL, **{
|
||||
"id": "91a7b528-80eb-42ed-a74d-c6fbd5a26116",
|
||||
"title": "Not writeable or readable Collection",
|
||||
"description": "This collection is a dropbox for submitting indicators",
|
||||
"can_read": False,
|
||||
"can_write": False,
|
||||
"media_types": [
|
||||
"application/vnd.oasis.stix+json; version=2.0",
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
mock.objects.extend(stix_objs1)
|
||||
return mock
|
||||
|
@ -109,14 +113,16 @@ def test_add_stix2_object(collection):
|
|||
tc_sink = stix2.TAXIICollectionSink(collection)
|
||||
|
||||
# create new STIX threat-actor
|
||||
ta = stix2.v21.ThreatActor(name="Teddy Bear",
|
||||
threat_actor_types=["nation-state"],
|
||||
sophistication="innovator",
|
||||
resource_level="government",
|
||||
goals=[
|
||||
"compromising environment NGOs",
|
||||
"water-hole attacks geared towards energy sector",
|
||||
])
|
||||
ta = stix2.v21.ThreatActor(
|
||||
name="Teddy Bear",
|
||||
threat_actor_types=["nation-state"],
|
||||
sophistication="innovator",
|
||||
resource_level="government",
|
||||
goals=[
|
||||
"compromising environment NGOs",
|
||||
"water-hole attacks geared towards energy sector",
|
||||
],
|
||||
)
|
||||
|
||||
tc_sink.add(ta)
|
||||
|
||||
|
@ -125,16 +131,18 @@ def test_add_stix2_with_custom_object(collection):
|
|||
tc_sink = stix2.TAXIICollectionStore(collection, allow_custom=True)
|
||||
|
||||
# create new STIX threat-actor
|
||||
ta = stix2.v21.ThreatActor(name="Teddy Bear",
|
||||
threat_actor_types=["nation-state"],
|
||||
sophistication="innovator",
|
||||
resource_level="government",
|
||||
goals=[
|
||||
"compromising environment NGOs",
|
||||
"water-hole attacks geared towards energy sector",
|
||||
],
|
||||
foo="bar",
|
||||
allow_custom=True)
|
||||
ta = stix2.v21.ThreatActor(
|
||||
name="Teddy Bear",
|
||||
threat_actor_types=["nation-state"],
|
||||
sophistication="innovator",
|
||||
resource_level="government",
|
||||
goals=[
|
||||
"compromising environment NGOs",
|
||||
"water-hole attacks geared towards energy sector",
|
||||
],
|
||||
foo="bar",
|
||||
allow_custom=True,
|
||||
)
|
||||
|
||||
tc_sink.add(ta)
|
||||
|
||||
|
@ -143,14 +151,16 @@ def test_add_list_object(collection, indicator):
|
|||
tc_sink = stix2.TAXIICollectionSink(collection)
|
||||
|
||||
# create new STIX threat-actor
|
||||
ta = stix2.v21.ThreatActor(name="Teddy Bear",
|
||||
threat_actor_types=["nation-state"],
|
||||
sophistication="innovator",
|
||||
resource_level="government",
|
||||
goals=[
|
||||
"compromising environment NGOs",
|
||||
"water-hole attacks geared towards energy sector",
|
||||
])
|
||||
ta = stix2.v21.ThreatActor(
|
||||
name="Teddy Bear",
|
||||
threat_actor_types=["nation-state"],
|
||||
sophistication="innovator",
|
||||
resource_level="government",
|
||||
goals=[
|
||||
"compromising environment NGOs",
|
||||
"water-hole attacks geared towards energy sector",
|
||||
],
|
||||
)
|
||||
|
||||
tc_sink.add([ta, indicator])
|
||||
|
||||
|
@ -159,14 +169,16 @@ def test_add_stix2_bundle_object(collection):
|
|||
tc_sink = stix2.TAXIICollectionSink(collection)
|
||||
|
||||
# create new STIX threat-actor
|
||||
ta = stix2.v21.ThreatActor(name="Teddy Bear",
|
||||
threat_actor_types=["nation-state"],
|
||||
sophistication="innovator",
|
||||
resource_level="government",
|
||||
goals=[
|
||||
"compromising environment NGOs",
|
||||
"water-hole attacks geared towards energy sector",
|
||||
])
|
||||
ta = stix2.v21.ThreatActor(
|
||||
name="Teddy Bear",
|
||||
threat_actor_types=["nation-state"],
|
||||
sophistication="innovator",
|
||||
resource_level="government",
|
||||
goals=[
|
||||
"compromising environment NGOs",
|
||||
"water-hole attacks geared towards energy sector",
|
||||
],
|
||||
)
|
||||
|
||||
tc_sink.add(stix2.v21.Bundle(objects=[ta]))
|
||||
|
||||
|
@ -208,13 +220,13 @@ def test_add_dict_object(collection):
|
|||
"name": "Teddy Bear",
|
||||
"goals": [
|
||||
"compromising environment NGOs",
|
||||
"water-hole attacks geared towards energy sector"
|
||||
"water-hole attacks geared towards energy sector",
|
||||
],
|
||||
"sophistication": "innovator",
|
||||
"resource_level": "government",
|
||||
"threat_actor_types": [
|
||||
"nation-state"
|
||||
]
|
||||
"nation-state",
|
||||
],
|
||||
}
|
||||
|
||||
tc_sink.add(ta)
|
||||
|
@ -236,15 +248,15 @@ def test_add_dict_bundle_object(collection):
|
|||
"name": "Teddy Bear",
|
||||
"goals": [
|
||||
"compromising environment NGOs",
|
||||
"water-hole attacks geared towards energy sector"
|
||||
"water-hole attacks geared towards energy sector",
|
||||
],
|
||||
"sophistication": "innovator",
|
||||
"resource_level": "government",
|
||||
"threat_actor_types": [
|
||||
"nation-state"
|
||||
]
|
||||
}
|
||||
]
|
||||
"nation-state",
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
tc_sink.add(ta)
|
||||
|
@ -271,7 +283,7 @@ def test_parse_taxii_filters(collection):
|
|||
Filter("added_after", "=", "2016-02-01T00:00:01.000Z"),
|
||||
Filter("id", "=", "taxii stix object ID"),
|
||||
Filter("type", "=", "taxii stix object ID"),
|
||||
Filter("version", "=", "first")
|
||||
Filter("version", "=", "first"),
|
||||
]
|
||||
|
||||
ds = stix2.TAXIICollectionSource(collection)
|
||||
|
|
|
@ -2,9 +2,11 @@ import pytest
|
|||
|
||||
import stix2
|
||||
|
||||
from .constants import (CAMPAIGN_ID, CAMPAIGN_KWARGS, FAKE_TIME, IDENTITY_ID,
|
||||
IDENTITY_KWARGS, INDICATOR_ID, INDICATOR_KWARGS,
|
||||
MALWARE_ID, MALWARE_KWARGS, RELATIONSHIP_IDS)
|
||||
from .constants import (
|
||||
CAMPAIGN_ID, CAMPAIGN_KWARGS, FAKE_TIME, IDENTITY_ID, IDENTITY_KWARGS,
|
||||
INDICATOR_ID, INDICATOR_KWARGS, MALWARE_ID, MALWARE_KWARGS,
|
||||
RELATIONSHIP_IDS,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -48,8 +50,10 @@ def test_object_factory_created():
|
|||
|
||||
|
||||
def test_object_factory_external_reference():
|
||||
ext_ref = stix2.v21.ExternalReference(source_name="ACME Threat Intel",
|
||||
description="Threat report")
|
||||
ext_ref = stix2.v21.ExternalReference(
|
||||
source_name="ACME Threat Intel",
|
||||
description="Threat report",
|
||||
)
|
||||
factory = stix2.ObjectFactory(external_references=ext_ref)
|
||||
ind = factory.create(stix2.v21.Indicator, **INDICATOR_KWARGS)
|
||||
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():
|
||||
stmt_marking = stix2.v21.StatementMarking("Copyright 2016, Example Corp")
|
||||
mark_def = stix2.v21.MarkingDefinition(definition_type="statement",
|
||||
definition=stmt_marking)
|
||||
mark_def = stix2.v21.MarkingDefinition(
|
||||
definition_type="statement",
|
||||
definition=stmt_marking,
|
||||
)
|
||||
factory = stix2.ObjectFactory(object_marking_refs=[mark_def, stix2.v21.TLP_AMBER])
|
||||
ind = factory.create(stix2.v21.Indicator, **INDICATOR_KWARGS)
|
||||
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():
|
||||
ext_ref = stix2.v21.ExternalReference(source_name="ACME Threat Intel",
|
||||
description="Threat report from ACME")
|
||||
ext_ref2 = stix2.v21.ExternalReference(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")
|
||||
ext_ref = stix2.v21.ExternalReference(
|
||||
source_name="ACME Threat Intel",
|
||||
description="Threat report from ACME",
|
||||
)
|
||||
ext_ref2 = stix2.v21.ExternalReference(
|
||||
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)
|
||||
ind = factory.create(stix2.v21.Indicator, external_references=ext_ref2, **INDICATOR_KWARGS)
|
||||
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():
|
||||
ext_ref = stix2.v21.ExternalReference(source_name="ACME Threat Intel",
|
||||
description="Threat report from ACME")
|
||||
ext_ref2 = stix2.v21.ExternalReference(source_name="Yet Another Threat Report",
|
||||
description="Threat report from YATR")
|
||||
ext_ref = stix2.v21.ExternalReference(
|
||||
source_name="ACME Threat Intel",
|
||||
description="Threat report from ACME",
|
||||
)
|
||||
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)
|
||||
ind = factory.create(stix2.v21.Indicator, external_references=ext_ref2, **INDICATOR_KWARGS)
|
||||
assert len(ind.external_references) == 1
|
||||
|
@ -100,8 +116,10 @@ def test_object_factory_list_replace():
|
|||
|
||||
|
||||
def test_environment_functions():
|
||||
env = stix2.Environment(stix2.ObjectFactory(created_by_ref=IDENTITY_ID),
|
||||
stix2.MemoryStore())
|
||||
env = stix2.Environment(
|
||||
stix2.ObjectFactory(created_by_ref=IDENTITY_ID),
|
||||
stix2.MemoryStore(),
|
||||
)
|
||||
|
||||
# Create a STIX object
|
||||
ind = env.create(stix2.v21.Indicator, id=INDICATOR_ID, **INDICATOR_KWARGS)
|
||||
|
@ -125,8 +143,10 @@ def test_environment_functions():
|
|||
assert len(resp) == 0
|
||||
|
||||
# See different results after adding filters to the environment
|
||||
env.add_filters([stix2.Filter('type', '=', 'indicator'),
|
||||
stix2.Filter('created_by_ref', '=', IDENTITY_ID)])
|
||||
env.add_filters([
|
||||
stix2.Filter('type', '=', 'indicator'),
|
||||
stix2.Filter('created_by_ref', '=', IDENTITY_ID),
|
||||
])
|
||||
env.add_filter(stix2.Filter('labels', '=', 'benign')) # should be 'malicious-activity'
|
||||
resp = env.get(INDICATOR_ID)
|
||||
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():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
stix2.Environment(factory=stix2.ObjectFactory(),
|
||||
store=stix2.MemoryStore(), sink=stix2.MemorySink)
|
||||
stix2.Environment(
|
||||
factory=stix2.ObjectFactory(),
|
||||
store=stix2.MemoryStore(), sink=stix2.MemorySink,
|
||||
)
|
||||
assert 'Data store already provided' in str(excinfo.value)
|
||||
|
||||
|
||||
|
@ -265,7 +287,7 @@ def test_relationships_no_id(ds):
|
|||
env = stix2.Environment(store=ds)
|
||||
mal = {
|
||||
"type": "malware",
|
||||
"name": "some variant"
|
||||
"name": "some variant",
|
||||
}
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
env.relationships(mal)
|
||||
|
@ -329,7 +351,7 @@ def test_related_to_no_id(ds):
|
|||
env = stix2.Environment(store=ds)
|
||||
mal = {
|
||||
"type": "malware",
|
||||
"name": "some variant"
|
||||
"name": "some variant",
|
||||
}
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
env.related_to(mal)
|
||||
|
|
|
@ -21,7 +21,7 @@ def test_external_reference_veris():
|
|||
source_name="veris",
|
||||
external_id="0001AA7F-C601-424A-B2B8-BE6C9F5164E7",
|
||||
hashes={
|
||||
"SHA-256": "6db12788c37247f2316052e142f42f4b259d6561751e5f401a1ae2a6df9c674b"
|
||||
"SHA-256": "6db12788c37247f2316052e142f42f4b259d6561751e5f401a1ae2a6df9c674b",
|
||||
},
|
||||
url="https://github.com/vz-risk/VCDB/blob/master/data/json/0001AA7F-C601-424A-B2B8-BE6C9F5164E7.json",
|
||||
)
|
||||
|
|
|
@ -20,11 +20,11 @@ def test_add_marking_mark_one_selector_multiple_refs():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
|
@ -35,44 +35,49 @@ def test_add_marking_mark_one_selector_multiple_refs():
|
|||
assert m in after["granular_markings"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
(
|
||||
Malware(**MALWARE_KWARGS),
|
||||
Malware(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "name"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS),
|
||||
MARKING_IDS[0],
|
||||
),
|
||||
(
|
||||
MALWARE_KWARGS,
|
||||
dict(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "name"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS),
|
||||
MARKING_IDS[0],
|
||||
),
|
||||
(
|
||||
Malware(**MALWARE_KWARGS),
|
||||
Malware(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "name"],
|
||||
"marking_ref": TLP_RED.id,
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS),
|
||||
TLP_RED,
|
||||
),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
(
|
||||
Malware(**MALWARE_KWARGS),
|
||||
Malware(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "name"],
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
MARKING_IDS[0],
|
||||
),
|
||||
(
|
||||
MALWARE_KWARGS,
|
||||
dict(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "name"],
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
MARKING_IDS[0],
|
||||
),
|
||||
(
|
||||
Malware(**MALWARE_KWARGS),
|
||||
Malware(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "name"],
|
||||
"marking_ref": TLP_RED.id,
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
TLP_RED,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_add_marking_mark_multiple_selector_one_refs(data):
|
||||
before = data[0]
|
||||
after = data[1]
|
||||
|
@ -91,12 +96,12 @@ def test_add_marking_mark_multiple_selector_multiple_refs():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "name"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["description", "name"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -111,7 +116,7 @@ def test_add_marking_mark_another_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
|
@ -120,7 +125,7 @@ def test_add_marking_mark_another_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "name"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
|
@ -136,7 +141,7 @@ def test_add_marking_mark_same_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
|
@ -145,7 +150,7 @@ def test_add_marking_mark_same_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
|
@ -156,17 +161,22 @@ def test_add_marking_mark_same_property_same_marking():
|
|||
assert m in after["granular_markings"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data,marking", [
|
||||
({"description": "test description"},
|
||||
[["title"], ["marking-definition--1", "marking-definition--2"],
|
||||
"", ["marking-definition--1", "marking-definition--2"],
|
||||
[], ["marking-definition--1", "marking-definition--2"],
|
||||
[""], ["marking-definition--1", "marking-definition--2"],
|
||||
["description"], [""],
|
||||
["description"], [],
|
||||
["description"], ["marking-definition--1", 456]
|
||||
])
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data,marking", [
|
||||
(
|
||||
{"description": "test description"},
|
||||
[
|
||||
["title"], ["marking-definition--1", "marking-definition--2"],
|
||||
"", ["marking-definition--1", "marking-definition--2"],
|
||||
[], ["marking-definition--1", "marking-definition--2"],
|
||||
[""], ["marking-definition--1", "marking-definition--2"],
|
||||
["description"], [""],
|
||||
["description"], [],
|
||||
["description"], ["marking-definition--1", 456],
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_add_marking_bad_selector(data, marking):
|
||||
with pytest.raises(AssertionError):
|
||||
markings.add_markings(data, marking[0], marking[1])
|
||||
|
@ -180,61 +190,61 @@ GET_MARKINGS_TEST_DATA = {
|
|||
"list value",
|
||||
{
|
||||
"g": "nested",
|
||||
"h": 45
|
||||
}
|
||||
"h": 45,
|
||||
},
|
||||
],
|
||||
"x": {
|
||||
"y": [
|
||||
"hello",
|
||||
88
|
||||
88,
|
||||
],
|
||||
"z": {
|
||||
"foo1": "bar",
|
||||
"foo2": 65
|
||||
}
|
||||
"foo2": 65,
|
||||
},
|
||||
},
|
||||
"granular_markings": [
|
||||
{
|
||||
"marking_ref": "1",
|
||||
"selectors": ["a"]
|
||||
"selectors": ["a"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "2",
|
||||
"selectors": ["c"]
|
||||
"selectors": ["c"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "3",
|
||||
"selectors": ["c.[1]"]
|
||||
"selectors": ["c.[1]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "4",
|
||||
"selectors": ["c.[2]"]
|
||||
"selectors": ["c.[2]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "5",
|
||||
"selectors": ["c.[2].g"]
|
||||
"selectors": ["c.[2].g"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "6",
|
||||
"selectors": ["x"]
|
||||
"selectors": ["x"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "7",
|
||||
"selectors": ["x.y"]
|
||||
"selectors": ["x.y"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "8",
|
||||
"selectors": ["x.y.[1]"]
|
||||
"selectors": ["x.y.[1]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "9",
|
||||
"selectors": ["x.z"]
|
||||
"selectors": ["x.z"],
|
||||
},
|
||||
{
|
||||
"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"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
GET_MARKINGS_TEST_DATA,
|
||||
{"b": 1234},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
GET_MARKINGS_TEST_DATA,
|
||||
{"b": 1234},
|
||||
],
|
||||
)
|
||||
def test_get_markings_not_marked(data):
|
||||
"""Test selector that is not marked returns empty list."""
|
||||
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)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data,selector", [
|
||||
(GET_MARKINGS_TEST_DATA, "foo"),
|
||||
(GET_MARKINGS_TEST_DATA, ""),
|
||||
(GET_MARKINGS_TEST_DATA, []),
|
||||
(GET_MARKINGS_TEST_DATA, [""]),
|
||||
(GET_MARKINGS_TEST_DATA, "x.z.[-2]"),
|
||||
(GET_MARKINGS_TEST_DATA, "c.f"),
|
||||
(GET_MARKINGS_TEST_DATA, "c.[2].i"),
|
||||
(GET_MARKINGS_TEST_DATA, "c.[3]"),
|
||||
(GET_MARKINGS_TEST_DATA, "d"),
|
||||
(GET_MARKINGS_TEST_DATA, "x.[0]"),
|
||||
(GET_MARKINGS_TEST_DATA, "z.y.w"),
|
||||
(GET_MARKINGS_TEST_DATA, "x.z.[1]"),
|
||||
(GET_MARKINGS_TEST_DATA, "x.z.foo3")
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data,selector", [
|
||||
(GET_MARKINGS_TEST_DATA, "foo"),
|
||||
(GET_MARKINGS_TEST_DATA, ""),
|
||||
(GET_MARKINGS_TEST_DATA, []),
|
||||
(GET_MARKINGS_TEST_DATA, [""]),
|
||||
(GET_MARKINGS_TEST_DATA, "x.z.[-2]"),
|
||||
(GET_MARKINGS_TEST_DATA, "c.f"),
|
||||
(GET_MARKINGS_TEST_DATA, "c.[2].i"),
|
||||
(GET_MARKINGS_TEST_DATA, "c.[3]"),
|
||||
(GET_MARKINGS_TEST_DATA, "d"),
|
||||
(GET_MARKINGS_TEST_DATA, "x.[0]"),
|
||||
(GET_MARKINGS_TEST_DATA, "z.y.w"),
|
||||
(GET_MARKINGS_TEST_DATA, "x.z.[1]"),
|
||||
(GET_MARKINGS_TEST_DATA, "x.z.foo3"),
|
||||
],
|
||||
)
|
||||
def test_get_markings_bad_selector(data, selector):
|
||||
"""Test bad selectors raise exception"""
|
||||
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"])
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
(
|
||||
Malware(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
},
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
(
|
||||
Malware(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
[MARKING_IDS[0], MARKING_IDS[1]],
|
||||
),
|
||||
[MARKING_IDS[0], MARKING_IDS[1]],
|
||||
),
|
||||
(
|
||||
dict(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
},
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
(
|
||||
dict(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**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):
|
||||
before = markings.remove_markings(data[0], data[1], ["description"])
|
||||
assert "granular_markings" not in before
|
||||
|
@ -406,8 +422,8 @@ def test_remove_marking_remove_multiple_selector_one_ref():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -420,8 +436,8 @@ def test_remove_marking_mark_one_selector_from_multiple_ones():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -429,8 +445,8 @@ def test_remove_marking_mark_one_selector_from_multiple_ones():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -444,12 +460,12 @@ def test_remove_marking_mark_one_selector_markings_from_multiple_ones():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -457,12 +473,12 @@ def test_remove_marking_mark_one_selector_markings_from_multiple_ones():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -476,12 +492,12 @@ def test_remove_marking_mark_mutilple_selector_multiple_refs():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -494,8 +510,8 @@ def test_remove_marking_mark_another_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -503,12 +519,12 @@ def test_remove_marking_mark_another_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["modified"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -522,8 +538,8 @@ def test_remove_marking_mark_same_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -552,8 +568,8 @@ def test_remove_marking_not_present():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -566,15 +582,15 @@ IS_MARKED_TEST_DATA = [
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
{
|
||||
"selectors": ["malware_types", "description"],
|
||||
"marking_ref": MARKING_IDS[2]
|
||||
"marking_ref": MARKING_IDS[2],
|
||||
},
|
||||
{
|
||||
"selectors": ["malware_types", "description"],
|
||||
"marking_ref": MARKING_IDS[3]
|
||||
"marking_ref": MARKING_IDS[3],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
|
@ -583,15 +599,15 @@ IS_MARKED_TEST_DATA = [
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
{
|
||||
"selectors": ["malware_types", "description"],
|
||||
"marking_ref": MARKING_IDS[2]
|
||||
"marking_ref": MARKING_IDS[2],
|
||||
},
|
||||
{
|
||||
"selectors": ["malware_types", "description"],
|
||||
"marking_ref": MARKING_IDS[3]
|
||||
"marking_ref": MARKING_IDS[3],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
|
@ -606,21 +622,23 @@ def test_is_marked_smoke(data):
|
|||
assert markings.is_marked(data, selectors=["modified"]) is False
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data,selector", [
|
||||
(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], "x.z.[-2]"),
|
||||
(IS_MARKED_TEST_DATA[0], "c.f"),
|
||||
(IS_MARKED_TEST_DATA[0], "c.[2].i"),
|
||||
(IS_MARKED_TEST_DATA[1], "c.[3]"),
|
||||
(IS_MARKED_TEST_DATA[1], "d"),
|
||||
(IS_MARKED_TEST_DATA[1], "x.[0]"),
|
||||
(IS_MARKED_TEST_DATA[1], "z.y.w"),
|
||||
(IS_MARKED_TEST_DATA[1], "x.z.[1]"),
|
||||
(IS_MARKED_TEST_DATA[1], "x.z.foo3")
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data,selector", [
|
||||
(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], "x.z.[-2]"),
|
||||
(IS_MARKED_TEST_DATA[0], "c.f"),
|
||||
(IS_MARKED_TEST_DATA[0], "c.[2].i"),
|
||||
(IS_MARKED_TEST_DATA[1], "c.[3]"),
|
||||
(IS_MARKED_TEST_DATA[1], "d"),
|
||||
(IS_MARKED_TEST_DATA[1], "x.[0]"),
|
||||
(IS_MARKED_TEST_DATA[1], "z.y.w"),
|
||||
(IS_MARKED_TEST_DATA[1], "x.z.[1]"),
|
||||
(IS_MARKED_TEST_DATA[1], "x.z.foo3"),
|
||||
],
|
||||
)
|
||||
def test_is_marked_invalid_selector(data, selector):
|
||||
"""Test invalid selector raises an error."""
|
||||
with pytest.raises(AssertionError):
|
||||
|
@ -688,61 +706,61 @@ def test_is_marked_positional_arguments_combinations():
|
|||
"list value",
|
||||
{
|
||||
"g": "nested",
|
||||
"h": 45
|
||||
}
|
||||
"h": 45,
|
||||
},
|
||||
],
|
||||
"x": {
|
||||
"y": [
|
||||
"hello",
|
||||
88
|
||||
88,
|
||||
],
|
||||
"z": {
|
||||
"foo1": "bar",
|
||||
"foo2": 65
|
||||
}
|
||||
"foo2": 65,
|
||||
},
|
||||
},
|
||||
"granular_markings": [
|
||||
{
|
||||
"marking_ref": "1",
|
||||
"selectors": ["a"]
|
||||
"selectors": ["a"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "2",
|
||||
"selectors": ["c"]
|
||||
"selectors": ["c"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "3",
|
||||
"selectors": ["c.[1]"]
|
||||
"selectors": ["c.[1]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "4",
|
||||
"selectors": ["c.[2]"]
|
||||
"selectors": ["c.[2]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "5",
|
||||
"selectors": ["c.[2].g"]
|
||||
"selectors": ["c.[2].g"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "6",
|
||||
"selectors": ["x"]
|
||||
"selectors": ["x"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "7",
|
||||
"selectors": ["x.y"]
|
||||
"selectors": ["x.y"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "8",
|
||||
"selectors": ["x.y.[1]"]
|
||||
"selectors": ["x.y.[1]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "9",
|
||||
"selectors": ["x.z"]
|
||||
"selectors": ["x.z"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "10",
|
||||
"selectors": ["x.z.foo2"]
|
||||
"selectors": ["x.z.foo2"],
|
||||
},
|
||||
]
|
||||
],
|
||||
}
|
||||
|
||||
assert markings.is_marked(test_sdo, ["1"], "a", False, False)
|
||||
|
@ -822,8 +840,8 @@ def test_create_sdo_with_invalid_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["foo"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -838,12 +856,12 @@ def test_set_marking_mark_one_selector_multiple_refs():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -857,8 +875,8 @@ def test_set_marking_mark_multiple_selector_one_refs():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -866,8 +884,8 @@ def test_set_marking_mark_multiple_selector_one_refs():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -884,12 +902,12 @@ def test_set_marking_mark_multiple_selector_multiple_refs_from_none():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["description", "modified"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -903,8 +921,8 @@ def test_set_marking_mark_another_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -912,12 +930,12 @@ def test_set_marking_mark_another_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[2]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[2],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -927,19 +945,21 @@ def test_set_marking_mark_another_property_same_marking():
|
|||
assert m in after["granular_markings"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("marking", [
|
||||
([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]], [""]),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"marking", [
|
||||
([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]], [""]),
|
||||
],
|
||||
)
|
||||
def test_set_marking_bad_selector(marking):
|
||||
before = Malware(
|
||||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -947,8 +967,8 @@ def test_set_marking_bad_selector(marking):
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -964,8 +984,8 @@ def test_set_marking_mark_same_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -973,8 +993,8 @@ def test_set_marking_mark_same_property_same_marking():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -988,15 +1008,15 @@ CLEAR_MARKINGS_TEST_DATA = [
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["modified", "description"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
{
|
||||
"selectors": ["modified", "description", "type"],
|
||||
"marking_ref": MARKING_IDS[2]
|
||||
"marking_ref": MARKING_IDS[2],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
|
@ -1005,19 +1025,19 @@ CLEAR_MARKINGS_TEST_DATA = [
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["description"],
|
||||
"marking_ref": MARKING_IDS[0]
|
||||
"marking_ref": MARKING_IDS[0],
|
||||
},
|
||||
{
|
||||
"selectors": ["modified", "description"],
|
||||
"marking_ref": MARKING_IDS[1]
|
||||
"marking_ref": MARKING_IDS[1],
|
||||
},
|
||||
{
|
||||
"selectors": ["modified", "description", "type"],
|
||||
"marking_ref": MARKING_IDS[2]
|
||||
"marking_ref": MARKING_IDS[2],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
@ -1049,12 +1069,14 @@ def test_clear_marking_all_selectors(data):
|
|||
assert "granular_markings" not in data
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data,selector", [
|
||||
(CLEAR_MARKINGS_TEST_DATA[0], "foo"),
|
||||
(CLEAR_MARKINGS_TEST_DATA[0], ""),
|
||||
(CLEAR_MARKINGS_TEST_DATA[1], []),
|
||||
(CLEAR_MARKINGS_TEST_DATA[1], [""]),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data,selector", [
|
||||
(CLEAR_MARKINGS_TEST_DATA[0], "foo"),
|
||||
(CLEAR_MARKINGS_TEST_DATA[0], ""),
|
||||
(CLEAR_MARKINGS_TEST_DATA[1], []),
|
||||
(CLEAR_MARKINGS_TEST_DATA[1], [""]),
|
||||
],
|
||||
)
|
||||
def test_clear_marking_bad_selector(data, selector):
|
||||
"""Test bad selector raises exception."""
|
||||
with pytest.raises(AssertionError):
|
||||
|
|
|
@ -30,18 +30,20 @@ def test_identity_example():
|
|||
assert str(identity) == EXPECTED
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2015-12-21T19:59:11.000Z",
|
||||
"id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c",
|
||||
"identity_class": "individual",
|
||||
"modified": "2015-12-21T19:59:11.000Z",
|
||||
"name": "John Smith",
|
||||
"spec_version": "2.1",
|
||||
"type": "identity"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2015-12-21T19:59:11.000Z",
|
||||
"id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c",
|
||||
"identity_class": "individual",
|
||||
"modified": "2015-12-21T19:59:11.000Z",
|
||||
"name": "John Smith",
|
||||
"spec_version": "2.1",
|
||||
"type": "identity",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_identity(data):
|
||||
identity = stix2.parse(data, version="2.1")
|
||||
|
||||
|
@ -55,21 +57,23 @@ def test_parse_identity(data):
|
|||
|
||||
def test_parse_no_type():
|
||||
with pytest.raises(stix2.exceptions.ParseError):
|
||||
stix2.parse("""
|
||||
stix2.parse(
|
||||
"""
|
||||
{
|
||||
"id": "identity--311b2d2d-f010-4473-83ec-1edf84858f4c",
|
||||
"created": "2015-12-21T19:59:11.000Z",
|
||||
"modified": "2015-12-21T19:59:11.000Z",
|
||||
"name": "John Smith",
|
||||
"identity_class": "individual"
|
||||
}""", version="2.1")
|
||||
}""", version="2.1",
|
||||
)
|
||||
|
||||
|
||||
def test_identity_with_custom():
|
||||
identity = stix2.v21.Identity(
|
||||
name="John Smith",
|
||||
identity_class="individual",
|
||||
custom_properties={'x_foo': 'bar'}
|
||||
custom_properties={'x_foo': 'bar'},
|
||||
)
|
||||
|
||||
assert identity.x_foo == "bar"
|
||||
|
|
|
@ -152,20 +152,22 @@ def test_created_modified_time_are_identical_by_default():
|
|||
assert ind.created == ind.modified
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED_INDICATOR,
|
||||
{
|
||||
"type": "indicator",
|
||||
"id": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
|
||||
"created": "2017-01-01T00:00:01Z",
|
||||
"modified": "2017-01-01T00:00:01Z",
|
||||
"indicator_types": [
|
||||
"malicious-activity"
|
||||
],
|
||||
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
||||
"valid_from": "1970-01-01T00:00:01Z"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED_INDICATOR,
|
||||
{
|
||||
"type": "indicator",
|
||||
"id": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
|
||||
"created": "2017-01-01T00:00:01Z",
|
||||
"modified": "2017-01-01T00:00:01Z",
|
||||
"indicator_types": [
|
||||
"malicious-activity",
|
||||
],
|
||||
"pattern": "[file:hashes.MD5 = 'd41d8cd98f00b204e9800998ecf8427e']",
|
||||
"valid_from": "1970-01-01T00:00:01Z",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_indicator(data):
|
||||
idctr = stix2.parse(data, version="2.1")
|
||||
|
||||
|
|
|
@ -36,33 +36,35 @@ def test_intrusion_set_example():
|
|||
name="Bobcat Breakin",
|
||||
description="Incidents usually feature a shared TTP of a bobcat being released...",
|
||||
aliases=["Zookeeper"],
|
||||
goals=["acquisition-theft", "harassment", "damage"]
|
||||
goals=["acquisition-theft", "harassment", "damage"],
|
||||
)
|
||||
|
||||
assert str(intrusion_set) == EXPECTED
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"aliases": [
|
||||
"Zookeeper"
|
||||
],
|
||||
"created": "2016-04-06T20:03:48.000Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"description": "Incidents usually feature a shared TTP of a bobcat being released...",
|
||||
"goals": [
|
||||
"acquisition-theft",
|
||||
"harassment",
|
||||
"damage"
|
||||
],
|
||||
"id": "intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29",
|
||||
"modified": "2016-04-06T20:03:48.000Z",
|
||||
"name": "Bobcat Breakin",
|
||||
"spec_version": "2.1",
|
||||
"type": "intrusion-set"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"aliases": [
|
||||
"Zookeeper",
|
||||
],
|
||||
"created": "2016-04-06T20:03:48.000Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"description": "Incidents usually feature a shared TTP of a bobcat being released...",
|
||||
"goals": [
|
||||
"acquisition-theft",
|
||||
"harassment",
|
||||
"damage",
|
||||
],
|
||||
"id": "intrusion-set--4e78f46f-a023-4e5f-bc24-71b3ca22ec29",
|
||||
"modified": "2016-04-06T20:03:48.000Z",
|
||||
"name": "Bobcat Breakin",
|
||||
"spec_version": "2.1",
|
||||
"type": "intrusion-set",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_intrusion_set(data):
|
||||
intset = stix2.parse(data)
|
||||
|
||||
|
|
|
@ -55,13 +55,13 @@ def test_language_content_campaign():
|
|||
contents={
|
||||
'de': {
|
||||
'name': 'Bank Angriff 1',
|
||||
'description': 'Weitere Informationen über Banküberfall'
|
||||
'description': 'Weitere Informationen über Banküberfall',
|
||||
},
|
||||
'fr': {
|
||||
'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')
|
||||
|
|
|
@ -55,7 +55,7 @@ def test_location_with_some_required_properties():
|
|||
created=now,
|
||||
modified=now,
|
||||
latitude=48.8566,
|
||||
longitude=2.3522
|
||||
longitude=2.3522,
|
||||
)
|
||||
|
||||
assert str(loc) == EXPECTED_LOCATION_1
|
||||
|
@ -63,17 +63,19 @@ def test_location_with_some_required_properties():
|
|||
assert rep == EXPECTED_LOCATION_1_REPR
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED_LOCATION_2,
|
||||
{
|
||||
"type": "location",
|
||||
"spec_version": "2.1",
|
||||
"id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64",
|
||||
"created": "2016-04-06T20:03:00.000Z",
|
||||
"modified": "2016-04-06T20:03:00.000Z",
|
||||
"region": "north-america"
|
||||
}
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED_LOCATION_2,
|
||||
{
|
||||
"type": "location",
|
||||
"spec_version": "2.1",
|
||||
"id": "location--a6e9345f-5a15-4c29-8bb3-7dcc5d168d64",
|
||||
"created": "2016-04-06T20:03:00.000Z",
|
||||
"modified": "2016-04-06T20:03:00.000Z",
|
||||
"region": "north-america",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_location(data):
|
||||
location = stix2.parse(data, version="2.1")
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ def test_malware_with_all_required_properties():
|
|||
modified=now,
|
||||
malware_types=["ransomware"],
|
||||
name="Cryptolocker",
|
||||
is_family=True
|
||||
is_family=True,
|
||||
)
|
||||
|
||||
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)."
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED_MALWARE,
|
||||
{
|
||||
"type": "malware",
|
||||
"spec_version": "2.1",
|
||||
"id": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
|
||||
"created": "2016-05-12T08:17:27.000Z",
|
||||
"modified": "2016-05-12T08:17:27.000Z",
|
||||
"malware_types": ["ransomware"],
|
||||
"name": "Cryptolocker",
|
||||
"is_family": True
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED_MALWARE,
|
||||
{
|
||||
"type": "malware",
|
||||
"spec_version": "2.1",
|
||||
"id": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
|
||||
"created": "2016-05-12T08:17:27.000Z",
|
||||
"modified": "2016-05-12T08:17:27.000Z",
|
||||
"malware_types": ["ransomware"],
|
||||
"name": "Cryptolocker",
|
||||
"is_family": True,
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_malware(data):
|
||||
mal = stix2.parse(data)
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ def test_marking_def_example_with_statement_positional_argument():
|
|||
id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
|
||||
created="2017-01-20T00:00:00.000Z",
|
||||
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
|
||||
|
@ -95,7 +95,7 @@ def test_marking_def_example_with_kwargs_statement():
|
|||
id="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
|
||||
created="2017-01-20T00:00:00.000Z",
|
||||
definition_type="statement",
|
||||
definition=stix2.StatementMarking(**kwargs)
|
||||
definition=stix2.StatementMarking(**kwargs),
|
||||
)
|
||||
|
||||
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",
|
||||
created="2017-01-20T00:00:00.000Z",
|
||||
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",
|
||||
name="Green Group Attacks Against Finance",
|
||||
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
|
||||
|
||||
|
@ -127,7 +127,7 @@ def test_campaign_with_markings_example():
|
|||
def test_granular_example():
|
||||
granular_marking = stix2.v21.GranularMarking(
|
||||
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
|
||||
|
@ -137,7 +137,7 @@ def test_granular_example_with_bad_selector():
|
|||
with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo:
|
||||
stix2.v21.GranularMarking(
|
||||
marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
|
||||
selectors=["abc[0]"] # missing "."
|
||||
selectors=["abc[0]"], # missing "."
|
||||
)
|
||||
|
||||
assert excinfo.value.cls == stix2.v21.GranularMarking
|
||||
|
@ -157,24 +157,28 @@ def test_campaign_with_granular_markings_example():
|
|||
granular_markings=[
|
||||
stix2.v21.GranularMarking(
|
||||
marking_ref="marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
|
||||
selectors=["description"])
|
||||
])
|
||||
selectors=["description"],
|
||||
),
|
||||
],
|
||||
)
|
||||
assert str(campaign) == EXPECTED_CAMPAIGN_WITH_GRANULAR_MARKINGS
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED_TLP_MARKING_DEFINITION,
|
||||
{
|
||||
"id": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
|
||||
"spec_version": "2.1",
|
||||
"type": "marking-definition",
|
||||
"created": "2017-01-20T00:00:00Z",
|
||||
"definition": {
|
||||
"tlp": "white"
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED_TLP_MARKING_DEFINITION,
|
||||
{
|
||||
"id": "marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9",
|
||||
"spec_version": "2.1",
|
||||
"type": "marking-definition",
|
||||
"created": "2017-01-20T00:00:00Z",
|
||||
"definition": {
|
||||
"tlp": "white",
|
||||
},
|
||||
"definition_type": "tlp",
|
||||
},
|
||||
"definition_type": "tlp",
|
||||
},
|
||||
])
|
||||
],
|
||||
)
|
||||
def test_parse_marking_definition(data):
|
||||
gm = stix2.parse(data, version="2.1")
|
||||
|
||||
|
@ -186,10 +190,12 @@ def test_parse_marking_definition(data):
|
|||
assert gm.definition_type == "tlp"
|
||||
|
||||
|
||||
@stix2.v21.CustomMarking('x-new-marking-type', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
])
|
||||
@stix2.v21.CustomMarking(
|
||||
'x-new-marking-type', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
],
|
||||
)
|
||||
class NewMarking(object):
|
||||
def __init__(self, property2=None, **kwargs):
|
||||
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",
|
||||
created="2017-01-22T00:00:00.000Z",
|
||||
definition_type="x-new-marking-type",
|
||||
definition=nm
|
||||
definition=nm,
|
||||
)
|
||||
|
||||
assert marking_def.type == "marking-definition"
|
||||
|
@ -224,10 +230,12 @@ def test_registered_custom_marking_raises_exception():
|
|||
def test_not_registered_marking_raises_exception():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
# Used custom object on purpose to demonstrate a not-registered marking
|
||||
@stix2.v21.CustomObject('x-new-marking-type2', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
])
|
||||
@stix2.v21.CustomObject(
|
||||
'x-new-marking-type2', [
|
||||
('property1', stix2.properties.StringProperty(required=True)),
|
||||
('property2', stix2.properties.IntegerProperty()),
|
||||
],
|
||||
)
|
||||
class NewObject2(object):
|
||||
def __init__(self, property2=None, **kwargs):
|
||||
return
|
||||
|
@ -238,7 +246,7 @@ def test_not_registered_marking_raises_exception():
|
|||
id="marking-definition--00000000-0000-4000-8000-000000000012",
|
||||
created="2017-01-22T00:00:00.000Z",
|
||||
definition_type="x-new-marking-type2",
|
||||
definition=no
|
||||
definition=no,
|
||||
)
|
||||
|
||||
assert str(excinfo.value) == "definition_type must be a valid marking type"
|
||||
|
|
|
@ -8,10 +8,12 @@ import stix2
|
|||
|
||||
from .constants import CAMPAIGN_ID, NOTE_ID
|
||||
|
||||
DESCRIPTION = ('This note indicates the various steps taken by the threat'
|
||||
' analyst team to investigate this specific campaign. Step'
|
||||
' 1) Do a scan 2) Review scanned results for identified '
|
||||
'hosts not known by external intel... etc')
|
||||
DESCRIPTION = (
|
||||
'This note indicates the various steps taken by the threat'
|
||||
' analyst team to investigate this specific campaign. Step'
|
||||
' 1) Do a scan 2) Review scanned results for identified '
|
||||
'hosts not known by external intel... etc'
|
||||
)
|
||||
|
||||
EXPECTED_NOTE = """{
|
||||
"type": "note",
|
||||
|
@ -35,7 +37,8 @@ EXPECTED_NOTE = """{
|
|||
]
|
||||
}""" % DESCRIPTION
|
||||
|
||||
EXPECTED_OPINION_REPR = "Note(" + " ".join(("""
|
||||
EXPECTED_OPINION_REPR = "Note(" + " ".join((
|
||||
"""
|
||||
type='note',
|
||||
spec_version='2.1',
|
||||
id='note--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061',
|
||||
|
@ -46,7 +49,8 @@ EXPECTED_OPINION_REPR = "Note(" + " ".join(("""
|
|||
authors=['John Doe'],
|
||||
object_refs=['campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f'],
|
||||
external_references=[ExternalReference(source_name='job-tracker', external_id='job-id-1234')]
|
||||
""" % DESCRIPTION).split()) + ")"
|
||||
""" % DESCRIPTION
|
||||
).split()) + ")"
|
||||
|
||||
|
||||
def test_note_with_required_properties():
|
||||
|
@ -64,9 +68,9 @@ def test_note_with_required_properties():
|
|||
external_references=[
|
||||
{
|
||||
'source_name': 'job-tracker',
|
||||
'external_id': 'job-id-1234'
|
||||
}
|
||||
]
|
||||
'external_id': 'job-id-1234',
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
assert str(note) == EXPECTED_NOTE
|
||||
|
@ -74,30 +78,32 @@ def test_note_with_required_properties():
|
|||
assert rep == EXPECTED_OPINION_REPR
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED_NOTE,
|
||||
{
|
||||
"type": "note",
|
||||
"spec_version": "2.1",
|
||||
"id": "note--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
|
||||
"created": "2016-05-12T08:17:27.000Z",
|
||||
"modified": "2016-05-12T08:17:27.000Z",
|
||||
"summary": "Tracking Team Note#1",
|
||||
"description": DESCRIPTION,
|
||||
"authors": [
|
||||
"John Doe"
|
||||
],
|
||||
"object_refs": [
|
||||
"campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f"
|
||||
],
|
||||
"external_references": [
|
||||
{
|
||||
"source_name": "job-tracker",
|
||||
"external_id": "job-id-1234"
|
||||
}
|
||||
]
|
||||
}
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED_NOTE,
|
||||
{
|
||||
"type": "note",
|
||||
"spec_version": "2.1",
|
||||
"id": "note--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
|
||||
"created": "2016-05-12T08:17:27.000Z",
|
||||
"modified": "2016-05-12T08:17:27.000Z",
|
||||
"summary": "Tracking Team Note#1",
|
||||
"description": DESCRIPTION,
|
||||
"authors": [
|
||||
"John Doe",
|
||||
],
|
||||
"object_refs": [
|
||||
"campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
],
|
||||
"external_references": [
|
||||
{
|
||||
"source_name": "job-tracker",
|
||||
"external_id": "job-id-1234",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_note(data):
|
||||
note = stix2.parse(data, version="2.1")
|
||||
|
||||
|
|
|
@ -17,26 +17,34 @@ MALWARE_KWARGS.update({
|
|||
})
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
(
|
||||
Malware(**MALWARE_KWARGS),
|
||||
Malware(object_marking_refs=[MARKING_IDS[0]],
|
||||
**MALWARE_KWARGS),
|
||||
MARKING_IDS[0],
|
||||
),
|
||||
(
|
||||
MALWARE_KWARGS,
|
||||
dict(object_marking_refs=[MARKING_IDS[0]],
|
||||
**MALWARE_KWARGS),
|
||||
MARKING_IDS[0],
|
||||
),
|
||||
(
|
||||
Malware(**MALWARE_KWARGS),
|
||||
Malware(object_marking_refs=[TLP_AMBER.id],
|
||||
**MALWARE_KWARGS),
|
||||
TLP_AMBER,
|
||||
),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
(
|
||||
Malware(**MALWARE_KWARGS),
|
||||
Malware(
|
||||
object_marking_refs=[MARKING_IDS[0]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
MARKING_IDS[0],
|
||||
),
|
||||
(
|
||||
MALWARE_KWARGS,
|
||||
dict(
|
||||
object_marking_refs=[MARKING_IDS[0]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
MARKING_IDS[0],
|
||||
),
|
||||
(
|
||||
Malware(**MALWARE_KWARGS),
|
||||
Malware(
|
||||
object_marking_refs=[TLP_AMBER.id],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
TLP_AMBER,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_add_markings_one_marking(data):
|
||||
before = data[0]
|
||||
after = data[1]
|
||||
|
@ -72,12 +80,12 @@ def test_add_markings_combination():
|
|||
granular_markings=[
|
||||
{
|
||||
"selectors": ["malware_types"],
|
||||
"marking_ref": MARKING_IDS[2]
|
||||
"marking_ref": MARKING_IDS[2],
|
||||
},
|
||||
{
|
||||
"selectors": ["name"],
|
||||
"marking_ref": MARKING_IDS[3]
|
||||
}
|
||||
"marking_ref": MARKING_IDS[3],
|
||||
},
|
||||
],
|
||||
**MALWARE_KWARGS
|
||||
)
|
||||
|
@ -94,12 +102,14 @@ def test_add_markings_combination():
|
|||
assert m in after["object_marking_refs"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
([""]),
|
||||
(""),
|
||||
([]),
|
||||
([MARKING_IDS[0], 456])
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
([""]),
|
||||
(""),
|
||||
([]),
|
||||
([MARKING_IDS[0], 456]),
|
||||
],
|
||||
)
|
||||
def test_add_markings_bad_markings(data):
|
||||
before = Malware(
|
||||
**MALWARE_KWARGS
|
||||
|
@ -119,62 +129,62 @@ GET_MARKINGS_TEST_DATA = \
|
|||
"list value",
|
||||
{
|
||||
"g": "nested",
|
||||
"h": 45
|
||||
}
|
||||
"h": 45,
|
||||
},
|
||||
],
|
||||
"x": {
|
||||
"y": [
|
||||
"hello",
|
||||
88
|
||||
88,
|
||||
],
|
||||
"z": {
|
||||
"foo1": "bar",
|
||||
"foo2": 65
|
||||
}
|
||||
"foo2": 65,
|
||||
},
|
||||
},
|
||||
"object_marking_refs": ["11"],
|
||||
"granular_markings": [
|
||||
{
|
||||
"marking_ref": "1",
|
||||
"selectors": ["a"]
|
||||
"selectors": ["a"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "2",
|
||||
"selectors": ["c"]
|
||||
"selectors": ["c"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "3",
|
||||
"selectors": ["c.[1]"]
|
||||
"selectors": ["c.[1]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "4",
|
||||
"selectors": ["c.[2]"]
|
||||
"selectors": ["c.[2]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "5",
|
||||
"selectors": ["c.[2].g"]
|
||||
"selectors": ["c.[2].g"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "6",
|
||||
"selectors": ["x"]
|
||||
"selectors": ["x"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "7",
|
||||
"selectors": ["x.y"]
|
||||
"selectors": ["x.y"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "8",
|
||||
"selectors": ["x.y.[1]"]
|
||||
"selectors": ["x.y.[1]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "9",
|
||||
"selectors": ["x.z"]
|
||||
"selectors": ["x.z"],
|
||||
},
|
||||
{
|
||||
"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"])
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
(
|
||||
Malware(object_marking_refs=[MARKING_IDS[0]],
|
||||
**MALWARE_KWARGS),
|
||||
Malware(**MALWARE_KWARGS),
|
||||
),
|
||||
(
|
||||
dict(object_marking_refs=[MARKING_IDS[0]],
|
||||
**MALWARE_KWARGS),
|
||||
MALWARE_KWARGS,
|
||||
),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
(
|
||||
Malware(
|
||||
object_marking_refs=[MARKING_IDS[0]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
Malware(**MALWARE_KWARGS),
|
||||
),
|
||||
(
|
||||
dict(
|
||||
object_marking_refs=[MARKING_IDS[0]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
MALWARE_KWARGS,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_remove_markings_object_level(data):
|
||||
before = data[0]
|
||||
after = data[1]
|
||||
|
@ -283,29 +299,43 @@ def test_remove_markings_object_level(data):
|
|||
modified == after['modified']
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
(
|
||||
Malware(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS),
|
||||
Malware(object_marking_refs=[MARKING_IDS[1]],
|
||||
**MALWARE_KWARGS),
|
||||
[MARKING_IDS[0], MARKING_IDS[2]],
|
||||
),
|
||||
(
|
||||
dict(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS),
|
||||
dict(object_marking_refs=[MARKING_IDS[1]],
|
||||
**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],
|
||||
),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
(
|
||||
Malware(
|
||||
object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
Malware(
|
||||
object_marking_refs=[MARKING_IDS[1]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
[MARKING_IDS[0], MARKING_IDS[2]],
|
||||
),
|
||||
(
|
||||
dict(
|
||||
object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
dict(
|
||||
object_marking_refs=[MARKING_IDS[1]],
|
||||
**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):
|
||||
before = data[0]
|
||||
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]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
(
|
||||
Malware(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS),
|
||||
Malware(**MALWARE_KWARGS),
|
||||
),
|
||||
(
|
||||
dict(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS),
|
||||
MALWARE_KWARGS,
|
||||
),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
(
|
||||
Malware(
|
||||
object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
Malware(**MALWARE_KWARGS),
|
||||
),
|
||||
(
|
||||
dict(
|
||||
object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
MALWARE_KWARGS,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_clear_markings(data):
|
||||
before = data[0]
|
||||
after = data[1]
|
||||
|
@ -358,62 +394,62 @@ def test_is_marked_object_and_granular_combinations():
|
|||
"list value",
|
||||
{
|
||||
"g": "nested",
|
||||
"h": 45
|
||||
}
|
||||
"h": 45,
|
||||
},
|
||||
],
|
||||
"x": {
|
||||
"y": [
|
||||
"hello",
|
||||
88
|
||||
88,
|
||||
],
|
||||
"z": {
|
||||
"foo1": "bar",
|
||||
"foo2": 65
|
||||
}
|
||||
"foo2": 65,
|
||||
},
|
||||
},
|
||||
"object_marking_refs": "11",
|
||||
"granular_markings": [
|
||||
{
|
||||
"marking_ref": "1",
|
||||
"selectors": ["a"]
|
||||
"selectors": ["a"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "2",
|
||||
"selectors": ["c"]
|
||||
"selectors": ["c"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "3",
|
||||
"selectors": ["c.[1]"]
|
||||
"selectors": ["c.[1]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "4",
|
||||
"selectors": ["c.[2]"]
|
||||
"selectors": ["c.[2]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "5",
|
||||
"selectors": ["c.[2].g"]
|
||||
"selectors": ["c.[2].g"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "6",
|
||||
"selectors": ["x"]
|
||||
"selectors": ["x"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "7",
|
||||
"selectors": ["x.y"]
|
||||
"selectors": ["x.y"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "8",
|
||||
"selectors": ["x.y.[1]"]
|
||||
"selectors": ["x.y.[1]"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "9",
|
||||
"selectors": ["x.z"]
|
||||
"selectors": ["x.z"],
|
||||
},
|
||||
{
|
||||
"marking_ref": "10",
|
||||
"selectors": ["x.z.foo2"]
|
||||
"selectors": ["x.z.foo2"],
|
||||
},
|
||||
]
|
||||
],
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
(
|
||||
Malware(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS),
|
||||
Malware(**MALWARE_KWARGS),
|
||||
),
|
||||
(
|
||||
dict(object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS),
|
||||
MALWARE_KWARGS,
|
||||
),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
(
|
||||
Malware(
|
||||
object_marking_refs=[MARKING_IDS[0], MARKING_IDS[1], MARKING_IDS[2]],
|
||||
**MALWARE_KWARGS
|
||||
),
|
||||
Malware(**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):
|
||||
marked = data[0]
|
||||
nonmarked = data[1]
|
||||
|
@ -531,12 +573,14 @@ def test_set_marking():
|
|||
assert x in after["object_marking_refs"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
([]),
|
||||
([""]),
|
||||
(""),
|
||||
([MARKING_IDS[4], 687])
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
([]),
|
||||
([""]),
|
||||
(""),
|
||||
([MARKING_IDS[4], 687]),
|
||||
],
|
||||
)
|
||||
def test_set_marking_bad_input(data):
|
||||
before = Malware(
|
||||
object_marking_refs=[MARKING_IDS[0]],
|
||||
|
|
|
@ -42,7 +42,7 @@ def test_observed_data_example():
|
|||
objects={
|
||||
"0": {
|
||||
"name": "foo.exe",
|
||||
"type": "file"
|
||||
"type": "file",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
@ -88,13 +88,13 @@ def test_observed_data_example_with_refs():
|
|||
objects={
|
||||
"0": {
|
||||
"name": "foo.exe",
|
||||
"type": "file"
|
||||
"type": "file",
|
||||
},
|
||||
"1": {
|
||||
"type": "directory",
|
||||
"path": "/usr/home",
|
||||
"contains_refs": ["0"]
|
||||
}
|
||||
"contains_refs": ["0"],
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -114,13 +114,13 @@ def test_observed_data_example_with_bad_refs():
|
|||
objects={
|
||||
"0": {
|
||||
"type": "file",
|
||||
"name": "foo.exe"
|
||||
"name": "foo.exe",
|
||||
},
|
||||
"1": {
|
||||
"type": "directory",
|
||||
"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
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"type": "observed-data",
|
||||
"spec_version": "2.1",
|
||||
"id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
|
||||
"created": "2016-04-06T19:58:16.000Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"first_observed": "2015-12-21T19:00:00Z",
|
||||
"last_observed": "2015-12-21T19:00:00Z",
|
||||
"modified": "2016-04-06T19:58:16.000Z",
|
||||
"number_observed": 50,
|
||||
"objects": {
|
||||
"0": {
|
||||
"name": "foo.exe",
|
||||
"type": "file"
|
||||
}
|
||||
}
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"type": "observed-data",
|
||||
"spec_version": "2.1",
|
||||
"id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
|
||||
"created": "2016-04-06T19:58:16.000Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"first_observed": "2015-12-21T19:00:00Z",
|
||||
"last_observed": "2015-12-21T19:00:00Z",
|
||||
"modified": "2016-04-06T19:58:16.000Z",
|
||||
"number_observed": 50,
|
||||
"objects": {
|
||||
"0": {
|
||||
"name": "foo.exe",
|
||||
"type": "file",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_observed_data(data):
|
||||
odata = stix2.parse(data, version="2.1")
|
||||
|
||||
|
@ -199,13 +201,14 @@ def test_parse_observed_data(data):
|
|||
assert odata.objects["0"].type == "file"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
""""0": {
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
""""0": {
|
||||
"type": "artifact",
|
||||
"mime_type": "image/jpeg",
|
||||
"payload_bin": "VBORw0KGgoAAAANSUhEUgAAADI=="
|
||||
}""",
|
||||
""""0": {
|
||||
""""0": {
|
||||
"type": "artifact",
|
||||
"mime_type": "image/jpeg",
|
||||
"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"
|
||||
}
|
||||
}""",
|
||||
])
|
||||
],
|
||||
)
|
||||
def test_parse_artifact_valid(data):
|
||||
odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED)
|
||||
odata = stix2.parse(odata_str, version="2.1")
|
||||
assert odata.objects["0"].type == "artifact"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
""""0": {
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
""""0": {
|
||||
"type": "artifact",
|
||||
"mime_type": "image/jpeg",
|
||||
"payload_bin": "abcVBORw0KGgoAAAANSUhEUgAAADI=="
|
||||
}""",
|
||||
""""0": {
|
||||
""""0": {
|
||||
"type": "artifact",
|
||||
"mime_type": "image/jpeg",
|
||||
"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"
|
||||
}
|
||||
}""",
|
||||
])
|
||||
],
|
||||
)
|
||||
def test_parse_artifact_invalid(data):
|
||||
odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED)
|
||||
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."
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
""""0": {
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
""""0": {
|
||||
"type": "autonomous-system",
|
||||
"number": 15139,
|
||||
"name": "Slime Industries",
|
||||
"rir": "ARIN"
|
||||
}""",
|
||||
])
|
||||
],
|
||||
)
|
||||
def test_parse_autonomous_system_valid(data):
|
||||
odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED)
|
||||
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"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
"""{
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
"""{
|
||||
"type": "email-addr",
|
||||
"value": "john@example.com",
|
||||
"display_name": "John Doe",
|
||||
"belongs_to_ref": "0"
|
||||
}""",
|
||||
])
|
||||
],
|
||||
)
|
||||
def test_parse_email_address(data):
|
||||
odata = stix2.parse_observable(data, {"0": "user-account"}, version='2.1')
|
||||
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')
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
"""
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
"""
|
||||
{
|
||||
"type": "email-message",
|
||||
"is_multipart": true,
|
||||
|
@ -321,8 +332,9 @@ def test_parse_email_address(data):
|
|||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
])
|
||||
""",
|
||||
],
|
||||
)
|
||||
def test_parse_email_message(data):
|
||||
valid_refs = {
|
||||
"0": "email-message",
|
||||
|
@ -337,8 +349,9 @@ def test_parse_email_message(data):
|
|||
assert odata.body_multipart[0].content_disposition == "inline"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
"""
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
"""
|
||||
{
|
||||
"type": "email-message",
|
||||
"from_ref": "0",
|
||||
|
@ -348,8 +361,9 @@ def test_parse_email_message(data):
|
|||
"subject": "Saying Hello",
|
||||
"body": "Cats are funny!"
|
||||
}
|
||||
"""
|
||||
])
|
||||
""",
|
||||
],
|
||||
)
|
||||
def test_parse_email_message_not_multipart(data):
|
||||
valid_refs = {
|
||||
"0": "email-addr",
|
||||
|
@ -362,8 +376,9 @@ def test_parse_email_message_not_multipart(data):
|
|||
assert excinfo.value.dependencies == [("is_multipart", "body")]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
""""0": {
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
""""0": {
|
||||
"type": "file",
|
||||
"hashes": {
|
||||
"SHA-256": "ceafbfd424be2ca4a5f0402cae090dda2fb0526cf521b60b60077c0f622b285a"
|
||||
|
@ -399,15 +414,17 @@ def test_parse_email_message_not_multipart(data):
|
|||
}
|
||||
}
|
||||
}""",
|
||||
])
|
||||
],
|
||||
)
|
||||
def test_parse_file_archive(data):
|
||||
odata_str = OBJECTS_REGEX.sub('"objects": { %s }' % data, EXPECTED)
|
||||
odata = stix2.parse(odata_str, version="2.1")
|
||||
assert odata.objects["3"].extensions['archive-ext'].version == "5.0"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
"""
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
"""
|
||||
{
|
||||
"type": "email-message",
|
||||
"is_multipart": true,
|
||||
|
@ -443,8 +460,9 @@ def test_parse_file_archive(data):
|
|||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
])
|
||||
""",
|
||||
],
|
||||
)
|
||||
def test_parse_email_message_with_at_least_one_error(data):
|
||||
valid_refs = {
|
||||
"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)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
"""
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
"""
|
||||
{
|
||||
"type": "network-traffic",
|
||||
"src_ref": "0",
|
||||
|
@ -473,11 +492,14 @@ def test_parse_email_message_with_at_least_one_error(data):
|
|||
"tcp"
|
||||
]
|
||||
}
|
||||
"""
|
||||
])
|
||||
""",
|
||||
],
|
||||
)
|
||||
def test_parse_basic_tcp_traffic(data):
|
||||
odata = stix2.parse_observable(data, {"0": "ipv4-addr", "1": "ipv4-addr"},
|
||||
version='2.1')
|
||||
odata = stix2.parse_observable(
|
||||
data, {"0": "ipv4-addr", "1": "ipv4-addr"},
|
||||
version='2.1',
|
||||
)
|
||||
|
||||
assert odata.type == "network-traffic"
|
||||
assert odata.src_ref == "0"
|
||||
|
@ -485,8 +507,9 @@ def test_parse_basic_tcp_traffic(data):
|
|||
assert odata.protocols == ["tcp"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
"""
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
"""
|
||||
{
|
||||
"type": "network-traffic",
|
||||
"src_port": 2487,
|
||||
|
@ -501,8 +524,9 @@ def test_parse_basic_tcp_traffic(data):
|
|||
"4"
|
||||
]
|
||||
}
|
||||
"""
|
||||
])
|
||||
""",
|
||||
],
|
||||
)
|
||||
def test_parse_basic_tcp_traffic_with_error(data):
|
||||
with pytest.raises(stix2.exceptions.AtLeastOnePropertyError) as excinfo:
|
||||
stix2.parse_observable(data, {"4": "network-traffic"}, version='2.1')
|
||||
|
@ -555,7 +579,7 @@ def test_observed_data_with_process_example():
|
|||
"0": {
|
||||
"type": "file",
|
||||
"hashes": {
|
||||
"SHA-256": "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f"
|
||||
"SHA-256": "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f",
|
||||
},
|
||||
},
|
||||
"1": {
|
||||
|
@ -564,11 +588,12 @@ def test_observed_data_with_process_example():
|
|||
"name": "gedit-bin",
|
||||
"created": "2016-01-20T14:11:25.55Z",
|
||||
"arguments": [
|
||||
"--new-window"
|
||||
"--new-window",
|
||||
],
|
||||
"image_ref": "0"
|
||||
}
|
||||
})
|
||||
"image_ref": "0",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert observed_data.objects["0"].type == "file"
|
||||
assert observed_data.objects["0"].hashes["SHA-256"] == "35a01331e9ad96f751278b891b6ea09699806faedfa237d40513d92ad1b7100f"
|
||||
|
@ -585,8 +610,9 @@ def test_artifact_example():
|
|||
mime_type="image/jpeg",
|
||||
url="https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg",
|
||||
hashes={
|
||||
"MD5": "6826f9a05da08134006557758bb3afbb"
|
||||
})
|
||||
"MD5": "6826f9a05da08134006557758bb3afbb",
|
||||
},
|
||||
)
|
||||
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.hashes["MD5"] == "6826f9a05da08134006557758bb3afbb"
|
||||
|
@ -598,9 +624,10 @@ def test_artifact_mutual_exclusion_error():
|
|||
mime_type="image/jpeg",
|
||||
url="https://upload.wikimedia.org/wikipedia/commons/b/b4/JPEG_example_JPG_RIP_100.jpg",
|
||||
hashes={
|
||||
"MD5": "6826f9a05da08134006557758bb3afbb"
|
||||
"MD5": "6826f9a05da08134006557758bb3afbb",
|
||||
},
|
||||
payload_bin="VBORw0KGgoAAAANSUhEUgAAADI==")
|
||||
payload_bin="VBORw0KGgoAAAANSUhEUgAAADI==",
|
||||
)
|
||||
|
||||
assert excinfo.value.cls == stix2.v21.Artifact
|
||||
assert excinfo.value.properties == ["payload_bin", "url"]
|
||||
|
@ -614,7 +641,8 @@ def test_directory_example():
|
|||
created="2015-12-21T19:00:00Z",
|
||||
modified="2015-12-24T19:00:00Z",
|
||||
accessed="2015-12-21T20:00:00Z",
|
||||
contains_refs=["1"])
|
||||
contains_refs=["1"],
|
||||
)
|
||||
|
||||
assert dir.path == '/usr/lib'
|
||||
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",
|
||||
modified="2015-12-24T19:00:00Z",
|
||||
accessed="2015-12-21T20:00:00Z",
|
||||
contains_refs=["1"])
|
||||
contains_refs=["1"],
|
||||
)
|
||||
|
||||
assert excinfo.value.cls == stix2.v21.Directory
|
||||
assert excinfo.value.prop_name == "contains_refs"
|
||||
|
@ -641,7 +670,8 @@ def test_domain_name_example():
|
|||
dn = stix2.v21.DomainName(
|
||||
_valid_refs={"1": 'domain-name'},
|
||||
value="example.com",
|
||||
resolves_to_refs=["1"])
|
||||
resolves_to_refs=["1"],
|
||||
)
|
||||
|
||||
assert dn.value == "example.com"
|
||||
assert dn.resolves_to_refs == ["1"]
|
||||
|
@ -652,7 +682,8 @@ def test_domain_name_example_invalid_ref_type():
|
|||
stix2.v21.DomainName(
|
||||
_valid_refs={"1": "file"},
|
||||
value="example.com",
|
||||
resolves_to_refs=["1"])
|
||||
resolves_to_refs=["1"],
|
||||
)
|
||||
|
||||
assert excinfo.value.cls == stix2.v21.DomainName
|
||||
assert excinfo.value.prop_name == "resolves_to_refs"
|
||||
|
@ -662,14 +693,14 @@ def test_file_example():
|
|||
f = stix2.v21.File(
|
||||
name="qwerty.dll",
|
||||
hashes={
|
||||
"SHA-256": "ceafbfd424be2ca4a5f0402cae090dda2fb0526cf521b60b60077c0f622b285a"
|
||||
"SHA-256": "ceafbfd424be2ca4a5f0402cae090dda2fb0526cf521b60b60077c0f622b285a",
|
||||
},
|
||||
size=100,
|
||||
magic_number_hex="1C",
|
||||
mime_type="application/msword",
|
||||
created="2016-12-21T19: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"
|
||||
|
@ -690,11 +721,12 @@ def test_file_example_with_NTFSExt():
|
|||
"alternate_data_streams": [
|
||||
{
|
||||
"name": "second.stream",
|
||||
"size": 25536
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
"size": 25536,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert f.name == "abc.txt"
|
||||
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(
|
||||
name="abc.txt",
|
||||
extensions={
|
||||
"ntfs-ext": {}
|
||||
})
|
||||
"ntfs-ext": {},
|
||||
},
|
||||
)
|
||||
|
||||
assert excinfo.value.cls == stix2.NTFSExt
|
||||
assert excinfo.value.properties == sorted(list(stix2.NTFSExt._properties.keys()))
|
||||
|
@ -723,12 +756,13 @@ def test_file_example_with_PDFExt():
|
|||
"Author": "Adobe Systems Incorporated",
|
||||
"Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh",
|
||||
"Producer": "Acrobat Distiller 3.01 for Power Macintosh",
|
||||
"CreationDate": "20070412090123-02"
|
||||
"CreationDate": "20070412090123-02",
|
||||
},
|
||||
"pdfid0": "DFCE52BD827ECF765649852119D",
|
||||
"pdfid1": "57A1E0F9ED2AE523E313C"
|
||||
}
|
||||
})
|
||||
"pdfid1": "57A1E0F9ED2AE523E313C",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert f.name == "qwerty.dll"
|
||||
assert f.extensions["pdf-ext"].version == "1.7"
|
||||
|
@ -746,11 +780,13 @@ def test_file_example_with_PDFExt_Object():
|
|||
"Author": "Adobe Systems Incorporated",
|
||||
"Creator": "Adobe FrameMaker 5.5.3 for Power Macintosh",
|
||||
"Producer": "Acrobat Distiller 3.01 for Power Macintosh",
|
||||
"CreationDate": "20070412090123-02"
|
||||
"CreationDate": "20070412090123-02",
|
||||
},
|
||||
pdfid0="DFCE52BD827ECF765649852119D",
|
||||
pdfid1="57A1E0F9ED2AE523E313C")
|
||||
})
|
||||
pdfid1="57A1E0F9ED2AE523E313C",
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
assert f.name == "qwerty.dll"
|
||||
assert f.extensions["pdf-ext"].version == "1.7"
|
||||
|
@ -767,10 +803,11 @@ def test_file_example_with_RasterImageExt_Object():
|
|||
"Make": "Nikon",
|
||||
"Model": "D7000",
|
||||
"XResolution": 4928,
|
||||
"YResolution": 3264
|
||||
}
|
||||
}
|
||||
})
|
||||
"YResolution": 3264,
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
assert f.name == "qwerty.jpeg"
|
||||
assert f.extensions["raster-image-ext"].bits_per_pixel == 123
|
||||
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_commit": 4096,
|
||||
"loader_flags_hex": "abdbffde",
|
||||
"number_of_rva_and_sizes": 3758087646
|
||||
"number_of_rva_and_sizes": 3758087646,
|
||||
},
|
||||
"sections": [
|
||||
{
|
||||
"name": "CODE",
|
||||
"entropy": 0.061089
|
||||
"entropy": 0.061089,
|
||||
},
|
||||
{
|
||||
"name": "DATA",
|
||||
"entropy": 7.980693
|
||||
"entropy": 7.980693,
|
||||
},
|
||||
{
|
||||
"name": "NicolasB",
|
||||
"entropy": 0.607433
|
||||
"entropy": 0.607433,
|
||||
},
|
||||
{
|
||||
"name": ".idata",
|
||||
"entropy": 0.607433
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
"entropy": 0.607433,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
)
|
||||
assert f.name == "qwerty.dll"
|
||||
assert f.extensions["windows-pebinary-ext"].sections[2].entropy == 0.607433
|
||||
|
||||
|
@ -903,7 +941,8 @@ def test_ip4_address_example():
|
|||
ip4 = stix2.v21.IPv4Address(
|
||||
_valid_refs={"4": "mac-addr", "5": "mac-addr"},
|
||||
value="198.51.100.3",
|
||||
resolves_to_refs=["4", "5"])
|
||||
resolves_to_refs=["4", "5"],
|
||||
)
|
||||
|
||||
assert ip4.value == "198.51.100.3"
|
||||
assert ip4.resolves_to_refs == ["4", "5"]
|
||||
|
@ -932,7 +971,8 @@ def test_network_traffic_example():
|
|||
_valid_refs={"0": "ipv4-addr", "1": "ipv4-addr"},
|
||||
protocols="tcp",
|
||||
src_ref="0",
|
||||
dst_ref="1")
|
||||
dst_ref="1",
|
||||
)
|
||||
assert nt.protocols == ["tcp"]
|
||||
assert nt.src_ref == "0"
|
||||
assert nt.dst_ref == "1"
|
||||
|
@ -946,13 +986,15 @@ def test_network_traffic_http_request_example():
|
|||
request_header={
|
||||
"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"
|
||||
})
|
||||
"Host": "www.example.com",
|
||||
},
|
||||
)
|
||||
nt = stix2.v21.NetworkTraffic(
|
||||
_valid_refs={"0": "ipv4-addr"},
|
||||
protocols="tcp",
|
||||
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_value == "/download.html"
|
||||
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"},
|
||||
protocols="tcp",
|
||||
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_code_hex == "00"
|
||||
|
||||
|
@ -977,12 +1020,14 @@ def test_network_traffic_socket_example():
|
|||
is_listening=True,
|
||||
address_family="AF_INET",
|
||||
protocol_family="PF_INET",
|
||||
socket_type="SOCK_STREAM")
|
||||
socket_type="SOCK_STREAM",
|
||||
)
|
||||
nt = stix2.v21.NetworkTraffic(
|
||||
_valid_refs={"0": "ipv4-addr"},
|
||||
protocols="tcp",
|
||||
src_ref="0",
|
||||
extensions={'socket-ext': h})
|
||||
extensions={'socket-ext': h},
|
||||
)
|
||||
assert nt.extensions['socket-ext'].is_listening
|
||||
assert nt.extensions['socket-ext'].address_family == "AF_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"},
|
||||
protocols="tcp",
|
||||
src_ref="0",
|
||||
extensions={'tcp-ext': h})
|
||||
extensions={'tcp-ext': h},
|
||||
)
|
||||
assert nt.extensions['tcp-ext'].src_flags_hex == "00000002"
|
||||
|
||||
|
||||
|
@ -1012,7 +1058,8 @@ def test_process_example():
|
|||
name="gedit-bin",
|
||||
created="2016-01-20T14:11:25.55Z",
|
||||
arguments=["--new-window"],
|
||||
image_ref="0")
|
||||
image_ref="0",
|
||||
)
|
||||
|
||||
assert p.name == "gedit-bin"
|
||||
assert p.arguments == ["--new-window"]
|
||||
|
@ -1027,15 +1074,17 @@ def test_process_example_empty_error():
|
|||
properties_of_process.remove("type")
|
||||
assert excinfo.value.properties == sorted(properties_of_process)
|
||||
msg = "At least one of the ({1}) properties for {0} must be populated."
|
||||
msg = msg.format(stix2.v21.Process.__name__,
|
||||
", ".join(sorted(properties_of_process)))
|
||||
msg = msg.format(
|
||||
stix2.v21.Process.__name__,
|
||||
", ".join(sorted(properties_of_process)),
|
||||
)
|
||||
assert str(excinfo.value) == msg
|
||||
|
||||
|
||||
def test_process_example_empty_with_extensions():
|
||||
with pytest.raises(stix2.exceptions.AtLeastOnePropertyError) as excinfo:
|
||||
stix2.v21.Process(extensions={
|
||||
"windows-process-ext": {}
|
||||
"windows-process-ext": {},
|
||||
})
|
||||
|
||||
assert excinfo.value.cls == stix2.v21.WindowsProcessExt
|
||||
|
@ -1052,9 +1101,10 @@ def test_process_example_windows_process_ext():
|
|||
"aslr_enabled": True,
|
||||
"dep_enabled": True,
|
||||
"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"].dep_enabled
|
||||
assert proc.extensions["windows-process-ext"].priority == "HIGH_PRIORITY_CLASS"
|
||||
|
@ -1067,8 +1117,9 @@ def test_process_example_windows_process_ext_empty():
|
|||
pid=1221,
|
||||
name="gedit-bin",
|
||||
extensions={
|
||||
"windows-process-ext": {}
|
||||
})
|
||||
"windows-process-ext": {},
|
||||
},
|
||||
)
|
||||
|
||||
assert excinfo.value.cls == stix2.v21.WindowsProcessExt
|
||||
properties_of_extension = list(stix2.v21.WindowsProcessExt._properties.keys())
|
||||
|
@ -1090,7 +1141,8 @@ def test_process_example_with_WindowsProcessExt_Object():
|
|||
aslr_enabled=True,
|
||||
dep_enabled=True,
|
||||
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
|
||||
|
@ -1104,8 +1156,8 @@ def test_process_example_with_WindowsServiceExt():
|
|||
"display_name": "Sirvizio",
|
||||
"start_type": "SERVICE_AUTO_START",
|
||||
"service_type": "SERVICE_WIN32_OWN_PROCESS",
|
||||
"service_status": "SERVICE_RUNNING"
|
||||
}
|
||||
"service_status": "SERVICE_RUNNING",
|
||||
},
|
||||
})
|
||||
|
||||
assert p.extensions["windows-service-ext"].service_name == "sirvizio"
|
||||
|
@ -1119,14 +1171,14 @@ def test_process_example_with_WindowsProcessServiceExt():
|
|||
"display_name": "Sirvizio",
|
||||
"start_type": "SERVICE_AUTO_START",
|
||||
"service_type": "SERVICE_WIN32_OWN_PROCESS",
|
||||
"service_status": "SERVICE_RUNNING"
|
||||
"service_status": "SERVICE_RUNNING",
|
||||
},
|
||||
"windows-process-ext": {
|
||||
"aslr_enabled": True,
|
||||
"dep_enabled": True,
|
||||
"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"
|
||||
|
@ -1140,7 +1192,8 @@ def test_software_example():
|
|||
name="Word",
|
||||
cpe="cpe:2.3:a:microsoft:word:2000:*:*:*:*:*:*:*",
|
||||
version="2002",
|
||||
vendor="Microsoft")
|
||||
vendor="Microsoft",
|
||||
)
|
||||
|
||||
assert s.name == "Word"
|
||||
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",
|
||||
credential_last_changed="2016-01-20T14:27:43Z",
|
||||
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.account_login == "jdoe"
|
||||
|
@ -1187,12 +1241,14 @@ def test_user_account_unix_account_ext_example():
|
|||
gid=1001,
|
||||
groups=["wheel"],
|
||||
home_dir="/home/jdoe",
|
||||
shell="/bin/bash")
|
||||
shell="/bin/bash",
|
||||
)
|
||||
a = stix2.v21.UserAccount(
|
||||
user_id="1001",
|
||||
account_login="jdoe",
|
||||
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'].groups == ["wheel"]
|
||||
assert a.extensions['unix-account-ext'].home_dir == "/home/jdoe"
|
||||
|
@ -1204,16 +1260,17 @@ def test_windows_registry_key_example():
|
|||
stix2.v21.WindowsRegistryValueType(
|
||||
name="Foo",
|
||||
data="qwerty",
|
||||
data_type="string")
|
||||
data_type="string",
|
||||
)
|
||||
|
||||
v = stix2.v21.WindowsRegistryValueType(
|
||||
name="Foo",
|
||||
data="qwerty",
|
||||
data_type="REG_SZ"
|
||||
data_type="REG_SZ",
|
||||
)
|
||||
w = stix2.v21.WindowsRegistryKey(
|
||||
key="hkey_local_machine\\system\\bar\\foo",
|
||||
values=[v]
|
||||
values=[v],
|
||||
)
|
||||
assert w.key == "hkey_local_machine\\system\\bar\\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
|
||||
validity_not_before="2016-03-12T12: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.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={
|
||||
'src_ip': {
|
||||
'type': 'ipv4-addr',
|
||||
'value': '127.0.0.1/32'
|
||||
'value': '127.0.0.1/32',
|
||||
},
|
||||
'domain': {
|
||||
'type': 'domain-name',
|
||||
'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")
|
||||
assert new_version.last_observed.year == 2017
|
||||
|
|
|
@ -8,11 +8,13 @@ import stix2
|
|||
|
||||
from .constants import OPINION_ID
|
||||
|
||||
DESCRIPTION = ('This doesn\'t seem like it is feasible. We\'ve seen how '
|
||||
'PandaCat has attacked Spanish infrastructure over the '
|
||||
'last 3 years, so this change in targeting seems too great'
|
||||
' to be viable. The methods used are more commonly '
|
||||
'associated with the FlameDragonCrew.')
|
||||
DESCRIPTION = (
|
||||
'This doesn\'t seem like it is feasible. We\'ve seen how '
|
||||
'PandaCat has attacked Spanish infrastructure over the '
|
||||
'last 3 years, so this change in targeting seems too great'
|
||||
' to be viable. The methods used are more commonly '
|
||||
'associated with the FlameDragonCrew.'
|
||||
)
|
||||
|
||||
EXPECTED_OPINION = """{
|
||||
"type": "opinion",
|
||||
|
@ -27,7 +29,8 @@ EXPECTED_OPINION = """{
|
|||
"opinion": "strongly-disagree"
|
||||
}""" % DESCRIPTION
|
||||
|
||||
EXPECTED_OPINION_REPR = "Opinion(" + " ".join(("""
|
||||
EXPECTED_OPINION_REPR = "Opinion(" + " ".join((
|
||||
"""
|
||||
type='opinion',
|
||||
spec_version='2.1',
|
||||
id='opinion--b01efc25-77b4-4003-b18b-f6e24b5cd9f7',
|
||||
|
@ -35,7 +38,8 @@ EXPECTED_OPINION_REPR = "Opinion(" + " ".join(("""
|
|||
modified='2016-05-12T08:17:27.000Z',
|
||||
description="%s",
|
||||
object_refs=['relationship--16d2358f-3b0d-4c88-b047-0da2f7ed4471'],
|
||||
opinion='strongly-disagree'""" % DESCRIPTION).split()) + ")"
|
||||
opinion='strongly-disagree'""" % DESCRIPTION
|
||||
).split()) + ")"
|
||||
|
||||
|
||||
def test_opinion_with_required_properties():
|
||||
|
@ -48,7 +52,7 @@ def test_opinion_with_required_properties():
|
|||
modified=now,
|
||||
object_refs=['relationship--16d2358f-3b0d-4c88-b047-0da2f7ed4471'],
|
||||
opinion='strongly-disagree',
|
||||
description=DESCRIPTION
|
||||
description=DESCRIPTION,
|
||||
)
|
||||
|
||||
assert str(opi) == EXPECTED_OPINION
|
||||
|
@ -56,21 +60,23 @@ def test_opinion_with_required_properties():
|
|||
assert rep == EXPECTED_OPINION_REPR
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED_OPINION,
|
||||
{
|
||||
"type": "opinion",
|
||||
"spec_version": "2.1",
|
||||
"id": "opinion--b01efc25-77b4-4003-b18b-f6e24b5cd9f7",
|
||||
"created": "2016-05-12T08:17:27.000Z",
|
||||
"modified": "2016-05-12T08:17:27.000Z",
|
||||
"description": DESCRIPTION,
|
||||
"object_refs": [
|
||||
"relationship--16d2358f-3b0d-4c88-b047-0da2f7ed4471"
|
||||
],
|
||||
"opinion": "strongly-disagree"
|
||||
}
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED_OPINION,
|
||||
{
|
||||
"type": "opinion",
|
||||
"spec_version": "2.1",
|
||||
"id": "opinion--b01efc25-77b4-4003-b18b-f6e24b5cd9f7",
|
||||
"created": "2016-05-12T08:17:27.000Z",
|
||||
"modified": "2016-05-12T08:17:27.000Z",
|
||||
"description": DESCRIPTION,
|
||||
"object_refs": [
|
||||
"relationship--16d2358f-3b0d-4c88-b047-0da2f7ed4471",
|
||||
],
|
||||
"opinion": "strongly-disagree",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_opinion(data):
|
||||
opinion = stix2.parse(data, version="2.1")
|
||||
|
||||
|
|
|
@ -7,37 +7,55 @@ import stix2
|
|||
|
||||
def test_create_comparison_expression():
|
||||
|
||||
exp = stix2.EqualityComparisonExpression("file:hashes.'SHA-256'",
|
||||
stix2.HashConstant("aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f", "SHA-256")) # noqa
|
||||
exp = stix2.EqualityComparisonExpression(
|
||||
"file:hashes.'SHA-256'",
|
||||
stix2.HashConstant("aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f", "SHA-256"),
|
||||
) # noqa
|
||||
assert str(exp) == "file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f'"
|
||||
|
||||
|
||||
def test_boolean_expression():
|
||||
exp1 = stix2.MatchesComparisonExpression("email-message:from_ref.value",
|
||||
stix2.StringConstant(".+\\@example\\.com$"))
|
||||
exp2 = stix2.MatchesComparisonExpression("email-message:body_multipart[*].body_raw_ref.name",
|
||||
stix2.StringConstant("^Final Report.+\\.exe$"))
|
||||
exp1 = stix2.MatchesComparisonExpression(
|
||||
"email-message:from_ref.value",
|
||||
stix2.StringConstant(".+\\@example\\.com$"),
|
||||
)
|
||||
exp2 = stix2.MatchesComparisonExpression(
|
||||
"email-message:body_multipart[*].body_raw_ref.name",
|
||||
stix2.StringConstant("^Final Report.+\\.exe$"),
|
||||
)
|
||||
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
|
||||
|
||||
|
||||
def test_boolean_expression_with_parentheses():
|
||||
exp1 = stix2.MatchesComparisonExpression(stix2.ObjectPath("email-message",
|
||||
[stix2.ReferenceObjectPathComponent("from_ref"),
|
||||
stix2.BasicObjectPathComponent("value")]),
|
||||
stix2.StringConstant(".+\\@example\\.com$"))
|
||||
exp2 = stix2.MatchesComparisonExpression("email-message:body_multipart[*].body_raw_ref.name",
|
||||
stix2.StringConstant("^Final Report.+\\.exe$"))
|
||||
exp1 = stix2.MatchesComparisonExpression(
|
||||
stix2.ObjectPath(
|
||||
"email-message",
|
||||
[
|
||||
stix2.ReferenceObjectPathComponent("from_ref"),
|
||||
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]))
|
||||
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():
|
||||
hash_exp = stix2.EqualityComparisonExpression("file:hashes.MD5",
|
||||
stix2.HashConstant("79054025255fb1a26e4bc422aef54eb4", "MD5"))
|
||||
hash_exp = stix2.EqualityComparisonExpression(
|
||||
"file:hashes.MD5",
|
||||
stix2.HashConstant("79054025255fb1a26e4bc422aef54eb4", "MD5"),
|
||||
)
|
||||
o_exp1 = stix2.ObservationExpression(hash_exp)
|
||||
reg_exp = stix2.EqualityComparisonExpression(stix2.ObjectPath("windows-registry-key", ["key"]),
|
||||
stix2.StringConstant("HKEY_LOCAL_MACHINE\\foo\\bar"))
|
||||
reg_exp = stix2.EqualityComparisonExpression(
|
||||
stix2.ObjectPath("windows-registry-key", ["key"]),
|
||||
stix2.StringConstant("HKEY_LOCAL_MACHINE\\foo\\bar"),
|
||||
)
|
||||
o_exp2 = stix2.ObservationExpression(reg_exp)
|
||||
fb_exp = stix2.FollowedByObservationExpression([o_exp1, o_exp2])
|
||||
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():
|
||||
hash_exp = stix2.EqualityComparisonExpression("file:hashes.MD5",
|
||||
stix2.HashConstant("79054025255fb1a26e4bc422aef54eb4", "MD5"))
|
||||
hash_exp = stix2.EqualityComparisonExpression(
|
||||
"file:hashes.MD5",
|
||||
stix2.HashConstant("79054025255fb1a26e4bc422aef54eb4", "MD5"),
|
||||
)
|
||||
o_exp1 = stix2.ObservationExpression(hash_exp)
|
||||
reg_exp = stix2.EqualityComparisonExpression(stix2.ObjectPath("windows-registry-key", ["key"]),
|
||||
stix2.StringConstant("HKEY_LOCAL_MACHINE\\foo\\bar"))
|
||||
reg_exp = stix2.EqualityComparisonExpression(
|
||||
stix2.ObjectPath("windows-registry-key", ["key"]),
|
||||
stix2.StringConstant("HKEY_LOCAL_MACHINE\\foo\\bar"),
|
||||
)
|
||||
o_exp2 = stix2.ObservationExpression(reg_exp)
|
||||
fb_exp = stix2.FollowedByObservationExpression([o_exp1, o_exp2])
|
||||
para_exp = stix2.ParentheticalExpression(fb_exp)
|
||||
|
@ -61,32 +83,45 @@ def test_hash_followed_by_registryKey_expression():
|
|||
|
||||
|
||||
def test_file_observable_expression():
|
||||
exp1 = stix2.EqualityComparisonExpression("file:hashes.'SHA-256'",
|
||||
stix2.HashConstant(
|
||||
"aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f",
|
||||
'SHA-256'))
|
||||
exp1 = stix2.EqualityComparisonExpression(
|
||||
"file:hashes.'SHA-256'",
|
||||
stix2.HashConstant(
|
||||
"aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f",
|
||||
'SHA-256',
|
||||
),
|
||||
)
|
||||
exp2 = stix2.EqualityComparisonExpression("file:mime_type", stix2.StringConstant("application/x-pdf"))
|
||||
bool_exp = stix2.AndBooleanExpression([exp1, exp2])
|
||||
exp = stix2.ObservationExpression(bool_exp)
|
||||
assert str(exp) == "[file:hashes.'SHA-256' = 'aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f' AND file:mime_type = 'application/x-pdf']" # noqa
|
||||
|
||||
|
||||
@pytest.mark.parametrize("observation_class, op", [
|
||||
(stix2.AndObservationExpression, 'AND'),
|
||||
(stix2.OrObservationExpression, 'OR'),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"observation_class, op", [
|
||||
(stix2.AndObservationExpression, 'AND'),
|
||||
(stix2.OrObservationExpression, 'OR'),
|
||||
],
|
||||
)
|
||||
def test_multiple_file_observable_expression(observation_class, op):
|
||||
exp1 = stix2.EqualityComparisonExpression("file:hashes.'SHA-256'",
|
||||
stix2.HashConstant(
|
||||
"bf07a7fbb825fc0aae7bf4a1177b2b31fcf8a3feeaf7092761e18c859ee52a9c",
|
||||
'SHA-256'))
|
||||
exp2 = stix2.EqualityComparisonExpression("file:hashes.MD5",
|
||||
stix2.HashConstant("cead3f77f6cda6ec00f57d76c9a6879f", "MD5"))
|
||||
exp1 = stix2.EqualityComparisonExpression(
|
||||
"file:hashes.'SHA-256'",
|
||||
stix2.HashConstant(
|
||||
"bf07a7fbb825fc0aae7bf4a1177b2b31fcf8a3feeaf7092761e18c859ee52a9c",
|
||||
'SHA-256',
|
||||
),
|
||||
)
|
||||
exp2 = stix2.EqualityComparisonExpression(
|
||||
"file:hashes.MD5",
|
||||
stix2.HashConstant("cead3f77f6cda6ec00f57d76c9a6879f", "MD5"),
|
||||
)
|
||||
bool1_exp = stix2.OrBooleanExpression([exp1, exp2])
|
||||
exp3 = stix2.EqualityComparisonExpression("file:hashes.'SHA-256'",
|
||||
stix2.HashConstant(
|
||||
"aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f",
|
||||
'SHA-256'))
|
||||
exp3 = stix2.EqualityComparisonExpression(
|
||||
"file:hashes.'SHA-256'",
|
||||
stix2.HashConstant(
|
||||
"aec070645fe53ee3b3763059376134f058cc337247c978add178b6ccdfb0019f",
|
||||
'SHA-256',
|
||||
),
|
||||
)
|
||||
op1_exp = stix2.ObservationExpression(bool1_exp)
|
||||
op2_exp = stix2.ObservationExpression(exp3)
|
||||
exp = observation_class([op1_exp, op2_exp])
|
||||
|
@ -96,111 +131,177 @@ def test_multiple_file_observable_expression(observation_class, op):
|
|||
def test_root_types():
|
||||
ast = stix2.ObservationExpression(
|
||||
stix2.AndBooleanExpression(
|
||||
[stix2.ParentheticalExpression(
|
||||
stix2.OrBooleanExpression([
|
||||
stix2.EqualityComparisonExpression("a:b", stix2.StringConstant("1")),
|
||||
stix2.EqualityComparisonExpression("b:c", stix2.StringConstant("2"))])),
|
||||
stix2.EqualityComparisonExpression(u"b:d", stix2.StringConstant("3"))]))
|
||||
[
|
||||
stix2.ParentheticalExpression(
|
||||
stix2.OrBooleanExpression([
|
||||
stix2.EqualityComparisonExpression("a:b", stix2.StringConstant("1")),
|
||||
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']"
|
||||
|
||||
|
||||
def test_artifact_payload():
|
||||
exp1 = stix2.EqualityComparisonExpression("artifact:mime_type",
|
||||
"application/vnd.tcpdump.pcap")
|
||||
exp2 = stix2.MatchesComparisonExpression("artifact:payload_bin",
|
||||
stix2.StringConstant("\\xd4\\xc3\\xb2\\xa1\\x02\\x00\\x04\\x00"))
|
||||
exp1 = stix2.EqualityComparisonExpression(
|
||||
"artifact:mime_type",
|
||||
"application/vnd.tcpdump.pcap",
|
||||
)
|
||||
exp2 = stix2.MatchesComparisonExpression(
|
||||
"artifact:payload_bin",
|
||||
stix2.StringConstant("\\xd4\\xc3\\xb2\\xa1\\x02\\x00\\x04\\x00"),
|
||||
)
|
||||
and_exp = stix2.AndBooleanExpression([exp1, exp2])
|
||||
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
|
||||
|
||||
|
||||
def test_greater_than_python_constant():
|
||||
exp1 = stix2.GreaterThanComparisonExpression("file:extensions.windows-pebinary-ext.sections[*].entropy",
|
||||
7.0)
|
||||
exp1 = stix2.GreaterThanComparisonExpression(
|
||||
"file:extensions.windows-pebinary-ext.sections[*].entropy",
|
||||
7.0,
|
||||
)
|
||||
exp = stix2.ObservationExpression(exp1)
|
||||
assert str(exp) == "[file:extensions.windows-pebinary-ext.sections[*].entropy > 7.0]"
|
||||
|
||||
|
||||
def test_greater_than():
|
||||
exp1 = stix2.GreaterThanComparisonExpression("file:extensions.windows-pebinary-ext.sections[*].entropy",
|
||||
stix2.FloatConstant(7.0))
|
||||
exp1 = stix2.GreaterThanComparisonExpression(
|
||||
"file:extensions.windows-pebinary-ext.sections[*].entropy",
|
||||
stix2.FloatConstant(7.0),
|
||||
)
|
||||
exp = stix2.ObservationExpression(exp1)
|
||||
assert str(exp) == "[file:extensions.windows-pebinary-ext.sections[*].entropy > 7.0]"
|
||||
|
||||
|
||||
def test_less_than():
|
||||
exp = stix2.LessThanComparisonExpression("file:size",
|
||||
1024)
|
||||
exp = stix2.LessThanComparisonExpression(
|
||||
"file:size",
|
||||
1024,
|
||||
)
|
||||
assert str(exp) == "file:size < 1024"
|
||||
|
||||
|
||||
def test_greater_than_or_equal():
|
||||
exp = stix2.GreaterThanEqualComparisonExpression("file:size",
|
||||
1024)
|
||||
exp = stix2.GreaterThanEqualComparisonExpression(
|
||||
"file:size",
|
||||
1024,
|
||||
)
|
||||
assert str(exp) == "file:size >= 1024"
|
||||
|
||||
|
||||
def test_less_than_or_equal():
|
||||
exp = stix2.LessThanEqualComparisonExpression("file:size",
|
||||
1024)
|
||||
exp = stix2.LessThanEqualComparisonExpression(
|
||||
"file:size",
|
||||
1024,
|
||||
)
|
||||
assert str(exp) == "file:size <= 1024"
|
||||
|
||||
|
||||
def test_not():
|
||||
exp = stix2.LessThanComparisonExpression("file:size",
|
||||
1024,
|
||||
negated=True)
|
||||
exp = stix2.LessThanComparisonExpression(
|
||||
"file:size",
|
||||
1024,
|
||||
negated=True,
|
||||
)
|
||||
assert str(exp) == "file:size NOT < 1024"
|
||||
|
||||
|
||||
def test_and_observable_expression():
|
||||
exp1 = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("user-account:account_type",
|
||||
"unix"),
|
||||
stix2.EqualityComparisonExpression("user-account:user_id",
|
||||
stix2.StringConstant("1007")),
|
||||
stix2.EqualityComparisonExpression("user-account:account_login",
|
||||
"Peter")])
|
||||
exp2 = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("user-account:account_type",
|
||||
"unix"),
|
||||
stix2.EqualityComparisonExpression("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)])
|
||||
exp1 = stix2.AndBooleanExpression([
|
||||
stix2.EqualityComparisonExpression(
|
||||
"user-account:account_type",
|
||||
"unix",
|
||||
),
|
||||
stix2.EqualityComparisonExpression(
|
||||
"user-account:user_id",
|
||||
stix2.StringConstant("1007"),
|
||||
),
|
||||
stix2.EqualityComparisonExpression(
|
||||
"user-account:account_login",
|
||||
"Peter",
|
||||
),
|
||||
])
|
||||
exp2 = stix2.AndBooleanExpression([
|
||||
stix2.EqualityComparisonExpression(
|
||||
"user-account:account_type",
|
||||
"unix",
|
||||
),
|
||||
stix2.EqualityComparisonExpression(
|
||||
"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
|
||||
|
||||
|
||||
def test_invalid_and_observable_expression():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("user-account:display_name",
|
||||
"admin"),
|
||||
stix2.EqualityComparisonExpression("email-addr:display_name",
|
||||
stix2.StringConstant("admin"))])
|
||||
stix2.AndBooleanExpression([
|
||||
stix2.EqualityComparisonExpression(
|
||||
"user-account:display_name",
|
||||
"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)
|
||||
|
||||
|
||||
def test_hex():
|
||||
exp_and = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("file:mime_type",
|
||||
"image/bmp"),
|
||||
stix2.EqualityComparisonExpression("file:magic_number_hex",
|
||||
stix2.HexConstant("ffd8"))])
|
||||
exp_and = stix2.AndBooleanExpression([
|
||||
stix2.EqualityComparisonExpression(
|
||||
"file:mime_type",
|
||||
"image/bmp",
|
||||
),
|
||||
stix2.EqualityComparisonExpression(
|
||||
"file:magic_number_hex",
|
||||
stix2.HexConstant("ffd8"),
|
||||
),
|
||||
])
|
||||
exp = stix2.ObservationExpression(exp_and)
|
||||
assert str(exp) == "[file:mime_type = 'image/bmp' AND file:magic_number_hex = h'ffd8']"
|
||||
|
||||
|
||||
def test_multiple_qualifiers():
|
||||
exp_and = stix2.AndBooleanExpression([stix2.EqualityComparisonExpression("network-traffic:dst_ref.type",
|
||||
"domain-name"),
|
||||
stix2.EqualityComparisonExpression("network-traffic:dst_ref.value",
|
||||
"example.com")])
|
||||
exp_and = stix2.AndBooleanExpression([
|
||||
stix2.EqualityComparisonExpression(
|
||||
"network-traffic:dst_ref.type",
|
||||
"domain-name",
|
||||
),
|
||||
stix2.EqualityComparisonExpression(
|
||||
"network-traffic:dst_ref.value",
|
||||
"example.com",
|
||||
),
|
||||
])
|
||||
exp_ob = stix2.ObservationExpression(exp_and)
|
||||
qual_rep = stix2.RepeatQualifier(5)
|
||||
qual_within = stix2.WithinQualifier(stix2.IntegerConstant(1800))
|
||||
|
@ -209,8 +310,10 @@ def test_multiple_qualifiers():
|
|||
|
||||
|
||||
def test_set_op():
|
||||
exp = stix2.ObservationExpression(stix2.IsSubsetComparisonExpression("network-traffic:dst_ref.value",
|
||||
"2001:0db8:dead:beef:0000:0000:0000:0000/64"))
|
||||
exp = stix2.ObservationExpression(stix2.IsSubsetComparisonExpression(
|
||||
"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']"
|
||||
|
||||
|
||||
|
@ -220,35 +323,45 @@ def test_timestamp():
|
|||
|
||||
|
||||
def test_boolean():
|
||||
exp = stix2.EqualityComparisonExpression("email-message:is_multipart",
|
||||
True)
|
||||
exp = stix2.EqualityComparisonExpression(
|
||||
"email-message:is_multipart",
|
||||
True,
|
||||
)
|
||||
assert str(exp) == "email-message:is_multipart = true"
|
||||
|
||||
|
||||
def test_binary():
|
||||
const = stix2.BinaryConstant("dGhpcyBpcyBhIHRlc3Q=")
|
||||
exp = stix2.EqualityComparisonExpression("artifact:payload_bin",
|
||||
const)
|
||||
exp = stix2.EqualityComparisonExpression(
|
||||
"artifact:payload_bin",
|
||||
const,
|
||||
)
|
||||
assert str(exp) == "artifact:payload_bin = b'dGhpcyBpcyBhIHRlc3Q='"
|
||||
|
||||
|
||||
def test_list():
|
||||
exp = stix2.InComparisonExpression("process:name",
|
||||
['proccy', 'proximus', 'badproc'])
|
||||
exp = stix2.InComparisonExpression(
|
||||
"process:name",
|
||||
['proccy', 'proximus', 'badproc'],
|
||||
)
|
||||
assert str(exp) == "process:name IN ('proccy', 'proximus', 'badproc')"
|
||||
|
||||
|
||||
def test_list2():
|
||||
# alternate way to construct an "IN" Comparison Expression
|
||||
exp = stix2.EqualityComparisonExpression("process:name",
|
||||
['proccy', 'proximus', 'badproc'])
|
||||
exp = stix2.EqualityComparisonExpression(
|
||||
"process:name",
|
||||
['proccy', 'proximus', 'badproc'],
|
||||
)
|
||||
assert str(exp) == "process:name IN ('proccy', 'proximus', 'badproc')"
|
||||
|
||||
|
||||
def test_invalid_constant_type():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
stix2.EqualityComparisonExpression("artifact:payload_bin",
|
||||
{'foo': 'bar'})
|
||||
stix2.EqualityComparisonExpression(
|
||||
"artifact:payload_bin",
|
||||
{'foo': 'bar'},
|
||||
)
|
||||
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)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data, result", [
|
||||
(True, True),
|
||||
(False, False),
|
||||
('True', True),
|
||||
('False', False),
|
||||
('true', True),
|
||||
('false', False),
|
||||
('t', True),
|
||||
('f', False),
|
||||
('T', True),
|
||||
('F', False),
|
||||
(1, True),
|
||||
(0, False),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data, result", [
|
||||
(True, True),
|
||||
(False, False),
|
||||
('True', True),
|
||||
('False', False),
|
||||
('true', True),
|
||||
('false', False),
|
||||
('t', True),
|
||||
('f', False),
|
||||
('T', True),
|
||||
('F', False),
|
||||
(1, True),
|
||||
(0, False),
|
||||
],
|
||||
)
|
||||
def test_boolean_constant(data, result):
|
||||
boolean = stix2.BooleanConstant(data)
|
||||
assert boolean.value == result
|
||||
|
@ -295,10 +410,12 @@ def test_invalid_boolean_constant():
|
|||
assert 'must be a boolean' in str(excinfo)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("hashtype, data", [
|
||||
('MD5', 'zzz'),
|
||||
('ssdeep', 'zzz=='),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"hashtype, data", [
|
||||
('MD5', 'zzz'),
|
||||
('ssdeep', 'zzz=='),
|
||||
],
|
||||
)
|
||||
def test_invalid_hash_constant(hashtype, data):
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
stix2.HashConstant(data, hashtype)
|
||||
|
@ -318,20 +435,26 @@ def test_invalid_binary_constant():
|
|||
|
||||
|
||||
def test_escape_quotes_and_backslashes():
|
||||
exp = stix2.MatchesComparisonExpression("file:name",
|
||||
"^Final Report.+\\.exe$")
|
||||
exp = stix2.MatchesComparisonExpression(
|
||||
"file:name",
|
||||
"^Final Report.+\\.exe$",
|
||||
)
|
||||
assert str(exp) == "file:name MATCHES '^Final Report.+\\\\.exe$'"
|
||||
|
||||
|
||||
def test_like():
|
||||
exp = stix2.LikeComparisonExpression("directory:path",
|
||||
"C:\\Windows\\%\\foo")
|
||||
exp = stix2.LikeComparisonExpression(
|
||||
"directory:path",
|
||||
"C:\\Windows\\%\\foo",
|
||||
)
|
||||
assert str(exp) == "directory:path LIKE 'C:\\\\Windows\\\\%\\\\foo'"
|
||||
|
||||
|
||||
def test_issuperset():
|
||||
exp = stix2.IsSupersetComparisonExpression("ipv4-addr:value",
|
||||
"198.51.100.0/24")
|
||||
exp = stix2.IsSupersetComparisonExpression(
|
||||
"ipv4-addr:value",
|
||||
"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():
|
||||
qual = stix2.StartStopQualifier(stix2.TimestampConstant('2016-06-01T00:00:00Z'),
|
||||
datetime.datetime(2017, 3, 12, 8, 30, 0))
|
||||
qual = stix2.StartStopQualifier(
|
||||
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'"
|
||||
|
||||
qual2 = stix2.StartStopQualifier(datetime.date(2016, 6, 1),
|
||||
stix2.TimestampConstant('2016-07-01T00:00:00Z'))
|
||||
qual2 = stix2.StartStopQualifier(
|
||||
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'"
|
||||
|
||||
|
||||
def test_invalid_startstop_qualifier():
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
stix2.StartStopQualifier('foo',
|
||||
stix2.TimestampConstant('2016-06-01T00:00:00Z'))
|
||||
stix2.StartStopQualifier(
|
||||
'foo',
|
||||
stix2.TimestampConstant('2016-06-01T00:00:00Z'),
|
||||
)
|
||||
assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo)
|
||||
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
stix2.StartStopQualifier(datetime.date(2016, 6, 1),
|
||||
'foo')
|
||||
stix2.StartStopQualifier(
|
||||
datetime.date(2016, 6, 1),
|
||||
'foo',
|
||||
)
|
||||
assert 'is not a valid argument for a Start/Stop Qualifier' in str(excinfo)
|
||||
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ def test_pickling():
|
|||
id="identity--d66cb89d-5228-4983-958c-fa84ef75c88c",
|
||||
name="alice",
|
||||
description="this is a pickle test",
|
||||
identity_class="some_class"
|
||||
identity_class="some_class",
|
||||
)
|
||||
|
||||
pickle.loads(pickle.dumps(identity))
|
||||
|
|
|
@ -4,14 +4,13 @@ import pytest
|
|||
|
||||
import stix2
|
||||
from stix2.exceptions import AtLeastOnePropertyError, DictionaryKeyError
|
||||
from stix2.properties import (ERROR_INVALID_ID, BinaryProperty,
|
||||
BooleanProperty, DictionaryProperty,
|
||||
EmbeddedObjectProperty, EnumProperty,
|
||||
ExtensionsProperty, FloatProperty,
|
||||
HashesProperty, HexProperty, IDProperty,
|
||||
IntegerProperty, ListProperty, Property,
|
||||
ReferenceProperty, StringProperty,
|
||||
TimestampProperty, TypeProperty)
|
||||
from stix2.properties import (
|
||||
ERROR_INVALID_ID, BinaryProperty, BooleanProperty, DictionaryProperty,
|
||||
EmbeddedObjectProperty, EnumProperty, ExtensionsProperty, FloatProperty,
|
||||
HashesProperty, HexProperty, IDProperty, IntegerProperty, ListProperty,
|
||||
Property, ReferenceProperty, StringProperty, TimestampProperty,
|
||||
TypeProperty,
|
||||
)
|
||||
|
||||
from . import constants
|
||||
|
||||
|
@ -93,10 +92,12 @@ ID_PROP = IDProperty('my-type')
|
|||
MY_ID = 'my-type--232c9d3f-49fc-4440-bb01-607f638778e7'
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
MY_ID,
|
||||
'my-type--00000000-0000-4000-8000-000000000000',
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
MY_ID,
|
||||
'my-type--00000000-0000-4000-8000-000000000000',
|
||||
],
|
||||
)
|
||||
def test_id_property_valid(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--'."
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
'my-type--foo',
|
||||
# Not a v4 UUID
|
||||
'my-type--00000000-0000-0000-0000-000000000000',
|
||||
'my-type--' + str(uuid.uuid1()),
|
||||
'my-type--' + str(uuid.uuid3(uuid.NAMESPACE_DNS, "example.org")),
|
||||
'my-type--' + str(uuid.uuid5(uuid.NAMESPACE_DNS, "example.org")),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
'my-type--foo',
|
||||
# Not a v4 UUID
|
||||
'my-type--00000000-0000-0000-0000-000000000000',
|
||||
'my-type--' + str(uuid.uuid1()),
|
||||
'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):
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
ID_PROP.clean(value)
|
||||
|
@ -153,77 +156,89 @@ def test_id_property_default():
|
|||
assert ID_PROP.clean(default) == default
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
2,
|
||||
-1,
|
||||
3.14,
|
||||
False,
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
2,
|
||||
-1,
|
||||
3.14,
|
||||
False,
|
||||
],
|
||||
)
|
||||
def test_integer_property_valid(value):
|
||||
int_prop = IntegerProperty()
|
||||
assert int_prop.clean(value) is not None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
"something",
|
||||
StringProperty(),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
"something",
|
||||
StringProperty(),
|
||||
],
|
||||
)
|
||||
def test_integer_property_invalid(value):
|
||||
int_prop = IntegerProperty()
|
||||
with pytest.raises(ValueError):
|
||||
int_prop.clean(value)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
2,
|
||||
-1,
|
||||
3.14,
|
||||
False,
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
2,
|
||||
-1,
|
||||
3.14,
|
||||
False,
|
||||
],
|
||||
)
|
||||
def test_float_property_valid(value):
|
||||
int_prop = FloatProperty()
|
||||
assert int_prop.clean(value) is not None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
"something",
|
||||
StringProperty(),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
"something",
|
||||
StringProperty(),
|
||||
],
|
||||
)
|
||||
def test_float_property_invalid(value):
|
||||
int_prop = FloatProperty()
|
||||
with pytest.raises(ValueError):
|
||||
int_prop.clean(value)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
True,
|
||||
False,
|
||||
'True',
|
||||
'False',
|
||||
'true',
|
||||
'false',
|
||||
'TRUE',
|
||||
'FALSE',
|
||||
'T',
|
||||
'F',
|
||||
't',
|
||||
'f',
|
||||
1,
|
||||
0,
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
True,
|
||||
False,
|
||||
'True',
|
||||
'False',
|
||||
'true',
|
||||
'false',
|
||||
'TRUE',
|
||||
'FALSE',
|
||||
'T',
|
||||
'F',
|
||||
't',
|
||||
'f',
|
||||
1,
|
||||
0,
|
||||
],
|
||||
)
|
||||
def test_boolean_property_valid(value):
|
||||
bool_prop = BooleanProperty()
|
||||
|
||||
assert bool_prop.clean(value) is not None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
'abc',
|
||||
['false'],
|
||||
{'true': 'true'},
|
||||
2,
|
||||
-1,
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
'abc',
|
||||
['false'],
|
||||
{'true': 'true'},
|
||||
2,
|
||||
-1,
|
||||
],
|
||||
)
|
||||
def test_boolean_property_invalid(value):
|
||||
bool_prop = BooleanProperty()
|
||||
with pytest.raises(ValueError):
|
||||
|
@ -242,11 +257,13 @@ def test_reference_property():
|
|||
ref_prop.clean("my-type--00000000-0000-0000-0000-000000000000")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
'2017-01-01T12:34:56Z',
|
||||
'2017-01-01 12:34:56',
|
||||
'Jan 1 2017 12:34:56',
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
'2017-01-01T12:34:56Z',
|
||||
'2017-01-01 12:34:56',
|
||||
'Jan 1 2017 12:34:56',
|
||||
],
|
||||
)
|
||||
def test_timestamp_property_valid(value):
|
||||
ts_prop = TimestampProperty()
|
||||
assert ts_prop.clean(value) == constants.FAKE_TIME
|
||||
|
@ -276,18 +293,22 @@ def test_hex_property():
|
|||
hex_prop.clean("foobar")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("d", [
|
||||
{'description': 'something'},
|
||||
[('abc', 1), ('bcd', 2), ('cde', 3)],
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"d", [
|
||||
{'description': 'something'},
|
||||
[('abc', 1), ('bcd', 2), ('cde', 3)],
|
||||
],
|
||||
)
|
||||
def test_dictionary_property_valid(d):
|
||||
dict_prop = DictionaryProperty(spec_version='2.1')
|
||||
assert dict_prop.clean(d)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("d", [
|
||||
[{'a': 'something'}, "Invalid dictionary key a: (shorter than 3 characters)."],
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"d", [
|
||||
[{'a': 'something'}, "Invalid dictionary key a: (shorter than 3 characters)."],
|
||||
],
|
||||
)
|
||||
def test_dictionary_no_longer_raises(d):
|
||||
dict_prop = DictionaryProperty(spec_version='2.1')
|
||||
|
||||
|
@ -297,15 +318,21 @@ def test_dictionary_no_longer_raises(d):
|
|||
pytest.fail("Unexpected DictionaryKeyError...")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("d", [
|
||||
[{'a'*300: 'something'}, "Invalid dictionary key aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"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 (_))."],
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"d", [
|
||||
[
|
||||
{'a'*300: 'something'}, "Invalid dictionary key aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"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):
|
||||
dict_prop = DictionaryProperty(spec_version='2.1')
|
||||
|
||||
|
@ -315,18 +342,20 @@ def test_dictionary_property_invalid_key(d):
|
|||
assert str(excinfo.value) == d[1]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("d", [
|
||||
({}, "The dictionary property must contain a non-empty dictionary"),
|
||||
# TODO: This error message could be made more helpful. The error is caused
|
||||
# because `json.loads()` doesn't like the *single* quotes around the key
|
||||
# name, even though they are valid in a Python dictionary. While technically
|
||||
# accurate (a string is not a dictionary), if we want to be able to load
|
||||
# string-encoded "dictionaries" that are, we need a better error message
|
||||
# or an alternative to `json.loads()` ... and preferably *not* `eval()`. :-)
|
||||
# Changing the following to `'{"description": "something"}'` does not cause
|
||||
# any ValueError to be raised.
|
||||
("{'description': 'something'}", "The dictionary property must contain a dictionary"),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"d", [
|
||||
({}, "The dictionary property must contain a non-empty dictionary"),
|
||||
# TODO: This error message could be made more helpful. The error is caused
|
||||
# because `json.loads()` doesn't like the *single* quotes around the key
|
||||
# name, even though they are valid in a Python dictionary. While technically
|
||||
# accurate (a string is not a dictionary), if we want to be able to load
|
||||
# string-encoded "dictionaries" that are, we need a better error message
|
||||
# or an alternative to `json.loads()` ... and preferably *not* `eval()`. :-)
|
||||
# Changing the following to `'{"description": "something"}'` does not cause
|
||||
# any ValueError to be raised.
|
||||
("{'description': 'something'}", "The dictionary property must contain a dictionary"),
|
||||
],
|
||||
)
|
||||
def test_dictionary_property_invalid(d):
|
||||
dict_prop = DictionaryProperty(spec_version='2.1')
|
||||
|
||||
|
@ -336,9 +365,11 @@ def test_dictionary_property_invalid(d):
|
|||
|
||||
|
||||
def test_property_list_of_dictionary():
|
||||
@stix2.v21.CustomObject('x-new-obj', [
|
||||
('property1', ListProperty(DictionaryProperty(spec_version='2.1'), required=True)),
|
||||
])
|
||||
@stix2.v21.CustomObject(
|
||||
'x-new-obj', [
|
||||
('property1', ListProperty(DictionaryProperty(spec_version='2.1'), required=True)),
|
||||
],
|
||||
)
|
||||
class NewObj():
|
||||
pass
|
||||
|
||||
|
@ -346,19 +377,23 @@ def test_property_list_of_dictionary():
|
|||
assert test_obj.property1[0]['foo'] == 'bar'
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
{"sha256": "6db12788c37247f2316052e142f42f4b259d6561751e5f401a1ae2a6df9c674b"},
|
||||
[('MD5', '2dfb1bcc980200c6706feee399d41b3f'), ('RIPEMD-160', 'b3a8cd8a27c90af79b3c81754f267780f443dfef')],
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
{"sha256": "6db12788c37247f2316052e142f42f4b259d6561751e5f401a1ae2a6df9c674b"},
|
||||
[('MD5', '2dfb1bcc980200c6706feee399d41b3f'), ('RIPEMD-160', 'b3a8cd8a27c90af79b3c81754f267780f443dfef')],
|
||||
],
|
||||
)
|
||||
def test_hashes_property_valid(value):
|
||||
hash_prop = HashesProperty()
|
||||
assert hash_prop.clean(value)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
{"MD5": "a"},
|
||||
{"SHA-256": "2dfb1bcc980200c6706feee399d41b3f"},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
{"MD5": "a"},
|
||||
{"SHA-256": "2dfb1bcc980200c6706feee399d41b3f"},
|
||||
],
|
||||
)
|
||||
def test_hashes_property_invalid(value):
|
||||
hash_prop = HashesProperty()
|
||||
|
||||
|
@ -371,7 +406,7 @@ def test_embedded_property():
|
|||
mime = stix2.v21.EmailMIMEComponent(
|
||||
content_type="text/plain; charset=utf-8",
|
||||
content_disposition="inline",
|
||||
body="Cats are funny!"
|
||||
body="Cats are funny!",
|
||||
)
|
||||
assert emb_prop.clean(mime)
|
||||
|
||||
|
@ -379,11 +414,13 @@ def test_embedded_property():
|
|||
emb_prop.clean("string")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
['a', 'b', 'c'],
|
||||
('a', 'b', 'c'),
|
||||
'b',
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"value", [
|
||||
['a', 'b', 'c'],
|
||||
('a', 'b', 'c'),
|
||||
'b',
|
||||
],
|
||||
)
|
||||
def test_enum_property_valid(value):
|
||||
enum_prop = EnumProperty(value)
|
||||
assert enum_prop.clean('b')
|
||||
|
@ -399,17 +436,19 @@ def test_extension_property_valid():
|
|||
ext_prop = ExtensionsProperty(spec_version='2.1', enclosing_type='file')
|
||||
assert ext_prop({
|
||||
'windows-pebinary-ext': {
|
||||
'pe_type': 'exe'
|
||||
'pe_type': 'exe',
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
1,
|
||||
{'foobar-ext': {
|
||||
'pe_type': 'exe'
|
||||
}},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
1,
|
||||
{'foobar-ext': {
|
||||
'pe_type': 'exe',
|
||||
}},
|
||||
],
|
||||
)
|
||||
def test_extension_property_invalid(data):
|
||||
ext_prop = ExtensionsProperty(spec_version='2.1', enclosing_type='file')
|
||||
with pytest.raises(ValueError):
|
||||
|
@ -419,10 +458,12 @@ def test_extension_property_invalid(data):
|
|||
def test_extension_property_invalid_type():
|
||||
ext_prop = ExtensionsProperty(spec_version='2.1', enclosing_type='indicator')
|
||||
with pytest.raises(ValueError) as excinfo:
|
||||
ext_prop.clean({
|
||||
'windows-pebinary-ext': {
|
||||
'pe_type': 'exe'
|
||||
}}
|
||||
ext_prop.clean(
|
||||
{
|
||||
'windows-pebinary-ext': {
|
||||
'pe_type': 'exe',
|
||||
},
|
||||
},
|
||||
)
|
||||
assert 'no extensions defined' in str(excinfo.value)
|
||||
|
||||
|
|
|
@ -5,8 +5,9 @@ import pytz
|
|||
|
||||
import stix2
|
||||
|
||||
from .constants import (FAKE_TIME, INDICATOR_ID, MALWARE_ID, RELATIONSHIP_ID,
|
||||
RELATIONSHIP_KWARGS)
|
||||
from .constants import (
|
||||
FAKE_TIME, INDICATOR_ID, MALWARE_ID, RELATIONSHIP_ID, RELATIONSHIP_KWARGS,
|
||||
)
|
||||
|
||||
EXPECTED_RELATIONSHIP = """{
|
||||
"type": "relationship",
|
||||
|
@ -94,7 +95,7 @@ def test_relationship_required_properties_target_ref():
|
|||
with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo:
|
||||
stix2.v21.Relationship(
|
||||
relationship_type='indicates',
|
||||
source_ref=INDICATOR_ID
|
||||
source_ref=INDICATOR_ID,
|
||||
)
|
||||
|
||||
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'
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED_RELATIONSHIP,
|
||||
{
|
||||
"created": "2016-04-06T20:06:37Z",
|
||||
"id": "relationship--df7c87eb-75d2-4948-af81-9d49d246f301",
|
||||
"modified": "2016-04-06T20:06:37Z",
|
||||
"relationship_type": "indicates",
|
||||
"source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
|
||||
"target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
|
||||
"spec_version": "2.1",
|
||||
"type": "relationship"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED_RELATIONSHIP,
|
||||
{
|
||||
"created": "2016-04-06T20:06:37Z",
|
||||
"id": "relationship--df7c87eb-75d2-4948-af81-9d49d246f301",
|
||||
"modified": "2016-04-06T20:06:37Z",
|
||||
"relationship_type": "indicates",
|
||||
"source_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
|
||||
"target_ref": "malware--9c4638ec-f1de-4ddb-abf4-1b760417654e",
|
||||
"spec_version": "2.1",
|
||||
"type": "relationship",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_relationship(data):
|
||||
rel = stix2.parse(data, version="2.1")
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ def test_report_example():
|
|||
object_refs=[
|
||||
"indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2",
|
||||
"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=[
|
||||
stix2.v21.Indicator(id="indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", **INDICATOR_KWARGS),
|
||||
"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=[
|
||||
stix2.v21.Indicator(id="indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2", **INDICATOR_KWARGS),
|
||||
"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
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2015-12-21T19:59:11.000Z",
|
||||
"created_by_ref": "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283",
|
||||
"description": "A simple report with an indicator and campaign",
|
||||
"id": "report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3",
|
||||
"report_types": [
|
||||
"campaign"
|
||||
],
|
||||
"modified": "2015-12-21T19:59:11.000Z",
|
||||
"name": "The Black Vine Cyberespionage Group",
|
||||
"object_refs": [
|
||||
"indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2",
|
||||
"campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c",
|
||||
"relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a"
|
||||
],
|
||||
"published": "2016-01-20T17:00:00Z",
|
||||
"spec_version": "2.1",
|
||||
"type": "report"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2015-12-21T19:59:11.000Z",
|
||||
"created_by_ref": "identity--a463ffb3-1bd9-4d94-b02d-74e4f1658283",
|
||||
"description": "A simple report with an indicator and campaign",
|
||||
"id": "report--84e4d88f-44ea-4bcd-bbf3-b2c1c320bcb3",
|
||||
"report_types": [
|
||||
"campaign",
|
||||
],
|
||||
"modified": "2015-12-21T19:59:11.000Z",
|
||||
"name": "The Black Vine Cyberespionage Group",
|
||||
"object_refs": [
|
||||
"indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2",
|
||||
"campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c",
|
||||
"relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a",
|
||||
],
|
||||
"published": "2016-01-20T17:00:00Z",
|
||||
"spec_version": "2.1",
|
||||
"type": "report",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_report(data):
|
||||
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.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.object_refs == ["indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2",
|
||||
"campaign--83422c77-904c-4dc1-aff5-5c38f3a2c55c",
|
||||
"relationship--f82356ae-fe6c-437c-9c24-6b64314ae68a"]
|
||||
assert rept.object_refs == [
|
||||
"indicator--26ffb872-1dd9-446e-b6f5-d58527e5b5d2",
|
||||
"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.report_types == ["campaign"]
|
||||
assert rept.name == "The Black Vine Cyberespionage Group"
|
||||
|
|
|
@ -41,7 +41,7 @@ def test_sighting_all_required_properties():
|
|||
created=now,
|
||||
modified=now,
|
||||
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
|
||||
|
||||
|
@ -56,7 +56,7 @@ def test_sighting_bad_where_sighted_refs():
|
|||
created=now,
|
||||
modified=now,
|
||||
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
|
||||
|
@ -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'
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED_SIGHTING,
|
||||
{
|
||||
"created": "2016-04-06T20:06:37Z",
|
||||
"id": "sighting--bfbc19db-ec35-4e45-beed-f8bde2a772fb",
|
||||
"modified": "2016-04-06T20:06:37Z",
|
||||
"sighting_of_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
|
||||
"spec_version": "2.1",
|
||||
"type": "sighting",
|
||||
"where_sighted_refs": [
|
||||
"identity--8cc7afd6-5455-4d2b-a736-e614ee631d99"
|
||||
]
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED_SIGHTING,
|
||||
{
|
||||
"created": "2016-04-06T20:06:37Z",
|
||||
"id": "sighting--bfbc19db-ec35-4e45-beed-f8bde2a772fb",
|
||||
"modified": "2016-04-06T20:06:37Z",
|
||||
"sighting_of_ref": "indicator--a740531e-63ff-4e49-a9e1-a0a3eed0e3e7",
|
||||
"spec_version": "2.1",
|
||||
"type": "sighting",
|
||||
"where_sighted_refs": [
|
||||
"identity--8cc7afd6-5455-4d2b-a736-e614ee631d99",
|
||||
],
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_sighting(data):
|
||||
sighting = stix2.parse(data, version="2.1")
|
||||
|
||||
|
|
|
@ -36,22 +36,24 @@ def test_threat_actor_example():
|
|||
assert str(threat_actor) == EXPECTED
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2016-04-06T20:03:48.000Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"description": "The Evil Org threat actor group",
|
||||
"id": "threat-actor--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"threat_actor_types": [
|
||||
"crime-syndicate"
|
||||
],
|
||||
"modified": "2016-04-06T20:03:48.000Z",
|
||||
"name": "Evil Org",
|
||||
"spec_version": "2.1",
|
||||
"type": "threat-actor"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2016-04-06T20:03:48.000Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"description": "The Evil Org threat actor group",
|
||||
"id": "threat-actor--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"threat_actor_types": [
|
||||
"crime-syndicate",
|
||||
],
|
||||
"modified": "2016-04-06T20:03:48.000Z",
|
||||
"name": "Evil Org",
|
||||
"spec_version": "2.1",
|
||||
"type": "threat-actor",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_threat_actor(data):
|
||||
actor = stix2.parse(data, version="2.1")
|
||||
|
||||
|
|
|
@ -48,21 +48,23 @@ def test_tool_example():
|
|||
assert str(tool) == EXPECTED
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2016-04-06T20:03:48Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"id": "tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"tool_types": [
|
||||
"remote-access"
|
||||
],
|
||||
"modified": "2016-04-06T20:03:48Z",
|
||||
"name": "VNC",
|
||||
"spec_version": "2.1",
|
||||
"type": "tool"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2016-04-06T20:03:48Z",
|
||||
"created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
"id": "tool--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
||||
"tool_types": [
|
||||
"remote-access",
|
||||
],
|
||||
"modified": "2016-04-06T20:03:48Z",
|
||||
"name": "VNC",
|
||||
"spec_version": "2.1",
|
||||
"type": "tool",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_tool(data):
|
||||
tool = stix2.parse(data, version="2.1")
|
||||
|
||||
|
|
|
@ -12,76 +12,90 @@ amsterdam = pytz.timezone('Europe/Amsterdam')
|
|||
eastern = pytz.timezone('US/Eastern')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('dttm, timestamp', [
|
||||
(dt.datetime(2017, 1, 1, tzinfo=pytz.utc), '2017-01-01T00:00:00Z'),
|
||||
(amsterdam.localize(dt.datetime(2017, 1, 1)), '2016-12-31T23:00:00Z'),
|
||||
(eastern.localize(dt.datetime(2017, 1, 1, 12, 34, 56)), '2017-01-01T17:34:56Z'),
|
||||
(eastern.localize(dt.datetime(2017, 7, 1)), '2017-07-01T04:00:00Z'),
|
||||
(dt.datetime(2017, 7, 1), '2017-07-01T00:00:00Z'),
|
||||
(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='millisecond'), '2017-07-01T00:00:00.000Z'),
|
||||
(stix2.utils.STIXdatetime(2017, 7, 1, 0, 0, 0, 1, precision='second'), '2017-07-01T00:00:00Z'),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'dttm, timestamp', [
|
||||
(dt.datetime(2017, 1, 1, tzinfo=pytz.utc), '2017-01-01T00:00:00Z'),
|
||||
(amsterdam.localize(dt.datetime(2017, 1, 1)), '2016-12-31T23:00:00Z'),
|
||||
(eastern.localize(dt.datetime(2017, 1, 1, 12, 34, 56)), '2017-01-01T17:34:56Z'),
|
||||
(eastern.localize(dt.datetime(2017, 7, 1)), '2017-07-01T04:00:00Z'),
|
||||
(dt.datetime(2017, 7, 1), '2017-07-01T00:00:00Z'),
|
||||
(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='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):
|
||||
assert stix2.utils.format_datetime(dttm) == timestamp
|
||||
|
||||
|
||||
@pytest.mark.parametrize('timestamp, dttm', [
|
||||
(dt.datetime(2017, 1, 1, 0, tzinfo=pytz.utc), 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-01T00:00:00Z', 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)),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'timestamp, dttm', [
|
||||
(dt.datetime(2017, 1, 1, 0, tzinfo=pytz.utc), 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-01T00:00:00Z', 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):
|
||||
assert stix2.utils.parse_into_datetime(timestamp) == dttm
|
||||
|
||||
|
||||
@pytest.mark.parametrize('timestamp, dttm, precision', [
|
||||
('2017-01-01T01:02:03.000001', dt.datetime(2017, 1, 1, 1, 2, 3, 0, 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.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, 450000, tzinfo=pytz.utc), 'millisecond'),
|
||||
('2017-01-01T01:02:03.45', dt.datetime(2017, 1, 1, 1, 2, 3, tzinfo=pytz.utc), 'second'),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'timestamp, dttm, precision', [
|
||||
('2017-01-01T01:02:03.000001', dt.datetime(2017, 1, 1, 1, 2, 3, 0, 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.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, 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):
|
||||
assert stix2.utils.parse_into_datetime(timestamp, precision) == dttm
|
||||
|
||||
|
||||
@pytest.mark.parametrize('ts', [
|
||||
'foobar',
|
||||
1,
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'ts', [
|
||||
'foobar',
|
||||
1,
|
||||
],
|
||||
)
|
||||
def test_parse_datetime_invalid(ts):
|
||||
with pytest.raises(ValueError):
|
||||
stix2.utils.parse_into_datetime('foobar')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('data', [
|
||||
{"a": 1},
|
||||
'{"a": 1}',
|
||||
StringIO(u'{"a": 1}'),
|
||||
[("a", 1,)],
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'data', [
|
||||
{"a": 1},
|
||||
'{"a": 1}',
|
||||
StringIO(u'{"a": 1}'),
|
||||
[("a", 1,)],
|
||||
],
|
||||
)
|
||||
def test_get_dict(data):
|
||||
assert stix2.utils._get_dict(data)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('data', [
|
||||
1,
|
||||
[1],
|
||||
['a', 1],
|
||||
"foobar",
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'data', [
|
||||
1,
|
||||
[1],
|
||||
['a', 1],
|
||||
"foobar",
|
||||
],
|
||||
)
|
||||
def test_get_dict_invalid(data):
|
||||
with pytest.raises(ValueError):
|
||||
stix2.utils._get_dict(data)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('stix_id, type', [
|
||||
('malware--d69c8146-ab35-4d50-8382-6fc80e641d43', 'malware'),
|
||||
('intrusion-set--899ce53f-13a0-479b-a0e4-67d46e241542', 'intrusion-set')
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'stix_id, type', [
|
||||
('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):
|
||||
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
|
||||
|
||||
|
||||
@pytest.mark.parametrize('object, tuple_to_find, expected_index', [
|
||||
(stix2.v21.ObservedData(
|
||||
id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
|
||||
created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
created="2016-04-06T19:58:16.000Z",
|
||||
modified="2016-04-06T19:58:16.000Z",
|
||||
first_observed="2015-12-21T19:00:00Z",
|
||||
last_observed="2015-12-21T19:00:00Z",
|
||||
number_observed=50,
|
||||
objects={
|
||||
"0": {
|
||||
"name": "foo.exe",
|
||||
"type": "file"
|
||||
},
|
||||
"1": {
|
||||
"type": "ipv4-addr",
|
||||
"value": "198.51.100.3"
|
||||
},
|
||||
"2": {
|
||||
"type": "network-traffic",
|
||||
"src_ref": "1",
|
||||
"protocols": [
|
||||
"tcp",
|
||||
"http"
|
||||
],
|
||||
"extensions": {
|
||||
"http-request-ext": {
|
||||
"request_method": "get",
|
||||
"request_value": "/download.html",
|
||||
"request_version": "http/1.1",
|
||||
"request_header": {
|
||||
"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",
|
||||
"id": "x-example--d5413db2-c26c-42e0-b0e0-ec800a310bfb",
|
||||
"created": "2018-06-11T01:25:22.063Z",
|
||||
"modified": "2018-06-11T01:25:22.063Z",
|
||||
"dictionary": {
|
||||
"key": {
|
||||
"key_one": "value",
|
||||
"key_two": "value"
|
||||
}
|
||||
}
|
||||
}, ('key', {'key_one': 'value', 'key_two': 'value'}), 0),
|
||||
({
|
||||
"type": "language-content",
|
||||
"spec_version": "2.1",
|
||||
"id": "language-content--b86bd89f-98bb-4fa9-8cb2-9ad421da981d",
|
||||
"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",
|
||||
"contents": {
|
||||
"de": {
|
||||
"name": "Bank Angriff 1",
|
||||
"description": "Weitere Informationen über Banküberfall"
|
||||
},
|
||||
"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)
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'object, tuple_to_find, expected_index', [
|
||||
(
|
||||
stix2.v21.ObservedData(
|
||||
id="observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
|
||||
created_by_ref="identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
|
||||
created="2016-04-06T19:58:16.000Z",
|
||||
modified="2016-04-06T19:58:16.000Z",
|
||||
first_observed="2015-12-21T19:00:00Z",
|
||||
last_observed="2015-12-21T19:00:00Z",
|
||||
number_observed=50,
|
||||
objects={
|
||||
"0": {
|
||||
"name": "foo.exe",
|
||||
"type": "file",
|
||||
},
|
||||
"1": {
|
||||
"type": "ipv4-addr",
|
||||
"value": "198.51.100.3",
|
||||
},
|
||||
"2": {
|
||||
"type": "network-traffic",
|
||||
"src_ref": "1",
|
||||
"protocols": [
|
||||
"tcp",
|
||||
"http",
|
||||
],
|
||||
"extensions": {
|
||||
"http-request-ext": {
|
||||
"request_method": "get",
|
||||
"request_value": "/download.html",
|
||||
"request_version": "http/1.1",
|
||||
"request_header": {
|
||||
"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",
|
||||
"id": "x-example--d5413db2-c26c-42e0-b0e0-ec800a310bfb",
|
||||
"created": "2018-06-11T01:25:22.063Z",
|
||||
"modified": "2018-06-11T01:25:22.063Z",
|
||||
"dictionary": {
|
||||
"key": {
|
||||
"key_one": "value",
|
||||
"key_two": "value",
|
||||
},
|
||||
},
|
||||
}, ('key', {'key_one': 'value', 'key_two': 'value'}), 0,
|
||||
),
|
||||
(
|
||||
{
|
||||
"type": "language-content",
|
||||
"spec_version": "2.1",
|
||||
"id": "language-content--b86bd89f-98bb-4fa9-8cb2-9ad421da981d",
|
||||
"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",
|
||||
"contents": {
|
||||
"de": {
|
||||
"name": "Bank Angriff 1",
|
||||
"description": "Weitere Informationen über Banküberfall",
|
||||
},
|
||||
"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):
|
||||
assert stix2.utils.find_property_index(
|
||||
object,
|
||||
|
@ -183,29 +205,35 @@ def test_find_property_index(object, tuple_to_find, expected_index):
|
|||
) == expected_index
|
||||
|
||||
|
||||
@pytest.mark.parametrize('dict_value, tuple_to_find, expected_index', [
|
||||
({
|
||||
"contents": {
|
||||
"de": {
|
||||
"name": "Bank Angriff 1",
|
||||
"description": "Weitere Informationen über Banküberfall"
|
||||
},
|
||||
"fr": {
|
||||
"name": "Attaque Bank 1",
|
||||
"description": "Plus d'informations sur la crise bancaire"
|
||||
},
|
||||
"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': [
|
||||
{"key_one": 1},
|
||||
{"key_two": 2}
|
||||
]
|
||||
}, ('key_one', 1), 0)
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
'dict_value, tuple_to_find, expected_index', [
|
||||
(
|
||||
{
|
||||
"contents": {
|
||||
"de": {
|
||||
"name": "Bank Angriff 1",
|
||||
"description": "Weitere Informationen über Banküberfall",
|
||||
},
|
||||
"fr": {
|
||||
"name": "Attaque Bank 1",
|
||||
"description": "Plus d'informations sur la crise bancaire",
|
||||
},
|
||||
"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': [
|
||||
{"key_one": 1},
|
||||
{"key_two": 2},
|
||||
],
|
||||
}, ('key_one', 1), 0,
|
||||
),
|
||||
],
|
||||
)
|
||||
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
|
||||
|
|
|
@ -39,15 +39,15 @@ def test_making_new_version_with_embedded_object():
|
|||
campaign_v1 = stix2.v21.Campaign(
|
||||
external_references=[{
|
||||
"source_name": "capec",
|
||||
"external_id": "CAPEC-163"
|
||||
"external_id": "CAPEC-163",
|
||||
}],
|
||||
**CAMPAIGN_MORE_KWARGS
|
||||
)
|
||||
|
||||
campaign_v2 = campaign_v1.new_version(external_references=[{
|
||||
"source_name": "capec",
|
||||
"external_id": "CAPEC-164"
|
||||
}])
|
||||
"external_id": "CAPEC-164",
|
||||
}])
|
||||
|
||||
assert campaign_v1.id == campaign_v2.id
|
||||
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.prop_name == "modified"
|
||||
assert excinfo.value.reason == ("The new modified datetime cannot be before than or equal to the current modified datetime."
|
||||
"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 excinfo.value.reason == (
|
||||
"The new modified datetime cannot be before than or equal to the current modified datetime."
|
||||
"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 = msg.format(stix2.v21.Campaign.__name__, "modified",
|
||||
"The new modified datetime cannot be before than or equal to the current modified datetime."
|
||||
"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 = msg.format(
|
||||
stix2.v21.Campaign.__name__, "modified",
|
||||
"The new modified datetime cannot be before than or equal to the current modified datetime."
|
||||
"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
|
||||
|
||||
|
||||
|
@ -221,11 +225,13 @@ def test_revoke_invalid_cls():
|
|||
|
||||
|
||||
def test_remove_custom_stix_property():
|
||||
mal = stix2.v21.Malware(name="ColePowers",
|
||||
malware_types=["rootkit"],
|
||||
is_family=False,
|
||||
x_custom="armada",
|
||||
allow_custom=True)
|
||||
mal = stix2.v21.Malware(
|
||||
name="ColePowers",
|
||||
malware_types=["rootkit"],
|
||||
is_family=False,
|
||||
x_custom="armada",
|
||||
allow_custom=True,
|
||||
)
|
||||
|
||||
mal_nc = stix2.utils.remove_custom_stix(mal)
|
||||
|
||||
|
@ -235,10 +241,12 @@ def test_remove_custom_stix_property():
|
|||
|
||||
|
||||
def test_remove_custom_stix_object():
|
||||
@stix2.v21.CustomObject("x-animal", [
|
||||
("species", stix2.properties.StringProperty(required=True)),
|
||||
("animal_class", stix2.properties.StringProperty()),
|
||||
])
|
||||
@stix2.v21.CustomObject(
|
||||
"x-animal", [
|
||||
("species", stix2.properties.StringProperty(required=True)),
|
||||
("animal_class", stix2.properties.StringProperty()),
|
||||
],
|
||||
)
|
||||
class Animal(object):
|
||||
pass
|
||||
|
||||
|
|
|
@ -30,31 +30,35 @@ def test_vulnerability_example():
|
|||
modified="2016-05-12T08:17:27.000Z",
|
||||
name="CVE-2016-1234",
|
||||
external_references=[
|
||||
stix2.ExternalReference(source_name='cve',
|
||||
external_id="CVE-2016-1234"),
|
||||
stix2.ExternalReference(
|
||||
source_name='cve',
|
||||
external_id="CVE-2016-1234",
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
assert str(vulnerability) == EXPECTED
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2016-05-12T08:17:27Z",
|
||||
"external_references": [
|
||||
{
|
||||
"external_id": "CVE-2016-1234",
|
||||
"source_name": "cve"
|
||||
}
|
||||
],
|
||||
"id": "vulnerability--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
|
||||
"modified": "2016-05-12T08:17:27Z",
|
||||
"name": "CVE-2016-1234",
|
||||
"spec_version": "2.1",
|
||||
"type": "vulnerability"
|
||||
},
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"data", [
|
||||
EXPECTED,
|
||||
{
|
||||
"created": "2016-05-12T08:17:27Z",
|
||||
"external_references": [
|
||||
{
|
||||
"external_id": "CVE-2016-1234",
|
||||
"source_name": "cve",
|
||||
},
|
||||
],
|
||||
"id": "vulnerability--0c7b5b88-8ff7-4a4d-aa9d-feb398cd0061",
|
||||
"modified": "2016-05-12T08:17:27Z",
|
||||
"name": "CVE-2016-1234",
|
||||
"spec_version": "2.1",
|
||||
"type": "vulnerability",
|
||||
},
|
||||
],
|
||||
)
|
||||
def test_parse_vulnerability(data):
|
||||
vuln = stix2.parse(data, version="2.1")
|
||||
|
||||
|
|
|
@ -1,29 +1,25 @@
|
|||
import os
|
||||
|
||||
import stix2
|
||||
from stix2.workbench import (AttackPattern, Campaign, CourseOfAction,
|
||||
ExternalReference, FileSystemSource, Filter,
|
||||
Identity, Indicator, IntrusionSet, Malware,
|
||||
MarkingDefinition, ObservedData, Relationship,
|
||||
Report, StatementMarking, ThreatActor, Tool,
|
||||
Vulnerability, add_data_source, all_versions,
|
||||
attack_patterns, campaigns, courses_of_action,
|
||||
create, get, identities, indicators,
|
||||
intrusion_sets, malware, observed_data, query,
|
||||
reports, save, set_default_created,
|
||||
set_default_creator, set_default_external_refs,
|
||||
set_default_object_marking_refs, threat_actors,
|
||||
tools, vulnerabilities)
|
||||
from stix2.workbench import (
|
||||
AttackPattern, Campaign, CourseOfAction, ExternalReference,
|
||||
FileSystemSource, Filter, Identity, Indicator, IntrusionSet, Malware,
|
||||
MarkingDefinition, ObservedData, Relationship, Report, StatementMarking,
|
||||
ThreatActor, Tool, Vulnerability, add_data_source, all_versions,
|
||||
attack_patterns, campaigns, courses_of_action, create, get, identities,
|
||||
indicators, intrusion_sets, malware, observed_data, query, 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,
|
||||
CAMPAIGN_KWARGS, COURSE_OF_ACTION_ID,
|
||||
COURSE_OF_ACTION_KWARGS, IDENTITY_ID, IDENTITY_KWARGS,
|
||||
INDICATOR_ID, INDICATOR_KWARGS, INTRUSION_SET_ID,
|
||||
INTRUSION_SET_KWARGS, MALWARE_ID, MALWARE_KWARGS,
|
||||
OBSERVED_DATA_ID, OBSERVED_DATA_KWARGS, REPORT_ID,
|
||||
REPORT_KWARGS, THREAT_ACTOR_ID, THREAT_ACTOR_KWARGS,
|
||||
TOOL_ID, TOOL_KWARGS, VULNERABILITY_ID,
|
||||
VULNERABILITY_KWARGS)
|
||||
from .constants import (
|
||||
ATTACK_PATTERN_ID, ATTACK_PATTERN_KWARGS, CAMPAIGN_ID, CAMPAIGN_KWARGS,
|
||||
COURSE_OF_ACTION_ID, COURSE_OF_ACTION_KWARGS, IDENTITY_ID, IDENTITY_KWARGS,
|
||||
INDICATOR_ID, INDICATOR_KWARGS, INTRUSION_SET_ID, INTRUSION_SET_KWARGS,
|
||||
MALWARE_ID, MALWARE_KWARGS, OBSERVED_DATA_ID, OBSERVED_DATA_KWARGS,
|
||||
REPORT_ID, REPORT_KWARGS, THREAT_ACTOR_ID, THREAT_ACTOR_KWARGS, TOOL_ID,
|
||||
TOOL_KWARGS, VULNERABILITY_ID, VULNERABILITY_KWARGS,
|
||||
)
|
||||
|
||||
|
||||
def test_workbench_environment():
|
||||
|
@ -190,8 +186,10 @@ def test_workbench_related():
|
|||
|
||||
|
||||
def test_workbench_related_with_filters():
|
||||
malware = Malware(malware_types=["ransomware"], name="CryptorBit",
|
||||
created_by_ref=IDENTITY_ID, is_family=False)
|
||||
malware = Malware(
|
||||
malware_types=["ransomware"], name="CryptorBit",
|
||||
created_by_ref=IDENTITY_ID, is_family=False,
|
||||
)
|
||||
rel = Relationship(malware.id, 'variant-of', MALWARE_ID)
|
||||
save([malware, rel])
|
||||
|
||||
|
@ -226,8 +224,10 @@ def test_additional_filter():
|
|||
|
||||
|
||||
def test_additional_filters_list():
|
||||
resp = tools([Filter('created_by_ref', '=', 'identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5'),
|
||||
Filter('name', '=', 'Windows Credential Editor')])
|
||||
resp = tools([
|
||||
Filter('created_by_ref', '=', 'identity--c78cb6e5-0c4b-4611-8297-d1b8b55e40b5'),
|
||||
Filter('name', '=', 'Windows Credential Editor'),
|
||||
])
|
||||
assert len(resp) == 1
|
||||
|
||||
|
||||
|
@ -250,8 +250,10 @@ def test_default_created_timestamp():
|
|||
|
||||
|
||||
def test_default_external_refs():
|
||||
ext_ref = ExternalReference(source_name="ACME Threat Intel",
|
||||
description="Threat report")
|
||||
ext_ref = ExternalReference(
|
||||
source_name="ACME Threat Intel",
|
||||
description="Threat report",
|
||||
)
|
||||
set_default_external_refs(ext_ref)
|
||||
campaign = Campaign(**CAMPAIGN_KWARGS)
|
||||
|
||||
|
@ -261,8 +263,10 @@ def test_default_external_refs():
|
|||
|
||||
def test_default_object_marking_refs():
|
||||
stmt_marking = StatementMarking("Copyright 2016, Example Corp")
|
||||
mark_def = MarkingDefinition(definition_type="statement",
|
||||
definition=stmt_marking)
|
||||
mark_def = MarkingDefinition(
|
||||
definition_type="statement",
|
||||
definition=stmt_marking,
|
||||
)
|
||||
set_default_object_marking_refs(mark_def)
|
||||
campaign = Campaign(**CAMPAIGN_KWARGS)
|
||||
|
||||
|
@ -300,7 +304,7 @@ def test_workbench_custom_property_dict_in_observable_extension():
|
|||
'allow_custom': True,
|
||||
'sid': 1,
|
||||
'x_foo': 'bar',
|
||||
}
|
||||
},
|
||||
},
|
||||
)
|
||||
observed_data = ObservedData(
|
||||
|
|
|
@ -7,8 +7,9 @@ import json
|
|||
from dateutil import parser
|
||||
import pytz
|
||||
|
||||
from .exceptions import (InvalidValueError, RevokeError,
|
||||
UnmodifiablePropertyError)
|
||||
from .exceptions import (
|
||||
InvalidValueError, RevokeError, UnmodifiablePropertyError,
|
||||
)
|
||||
|
||||
# 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
|
||||
|
@ -26,8 +27,10 @@ class STIXdatetime(dt.datetime):
|
|||
precision = kwargs.pop('precision', None)
|
||||
if isinstance(args[0], dt.datetime): # Allow passing in a datetime object
|
||||
dttm = args[0]
|
||||
args = (dttm.year, dttm.month, dttm.day, dttm.hour, dttm.minute,
|
||||
dttm.second, dttm.microsecond, dttm.tzinfo)
|
||||
args = (
|
||||
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 = dt.datetime.__new__(cls, *args, **kwargs)
|
||||
self.precision = precision
|
||||
|
@ -117,8 +120,10 @@ def parse_into_datetime(value, precision=None):
|
|||
parsed = parser.parse(value)
|
||||
except (TypeError, ValueError):
|
||||
# Unknown format
|
||||
raise ValueError("must be a datetime object, date object, or "
|
||||
"timestamp string in a recognizable format.")
|
||||
raise ValueError(
|
||||
"must be a datetime object, date object, or "
|
||||
"timestamp string in a recognizable format.",
|
||||
)
|
||||
if parsed.tzinfo:
|
||||
ts = parsed.astimezone(pytz.utc)
|
||||
else:
|
||||
|
@ -250,8 +255,10 @@ def new_version(data, **kwargs):
|
|||
"""
|
||||
|
||||
if not isinstance(data, Mapping):
|
||||
raise ValueError("cannot create new version of object of this type! "
|
||||
"Try a dictionary or instance of an SDO or SRO class.")
|
||||
raise ValueError(
|
||||
"cannot create new version of object of this type! "
|
||||
"Try a dictionary or instance of an SDO or SRO class.",
|
||||
)
|
||||
|
||||
unchangable_properties = []
|
||||
if data.get('revoked'):
|
||||
|
@ -276,10 +283,12 @@ def new_version(data, **kwargs):
|
|||
old_modified_property = parse_into_datetime(data.get('modified'), precision='millisecond')
|
||||
new_modified_property = parse_into_datetime(kwargs['modified'], precision='millisecond')
|
||||
if new_modified_property <= old_modified_property:
|
||||
raise InvalidValueError(cls, 'modified',
|
||||
"The new modified datetime cannot be before than or equal to the current modified datetime."
|
||||
"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.")
|
||||
raise InvalidValueError(
|
||||
cls, 'modified',
|
||||
"The new modified datetime cannot be before than or equal to the current modified datetime."
|
||||
"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)
|
||||
# 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})
|
||||
|
@ -292,8 +301,10 @@ def revoke(data):
|
|||
A new version of the object with ``revoked`` set to ``True``.
|
||||
"""
|
||||
if not isinstance(data, Mapping):
|
||||
raise ValueError("cannot revoke object of this type! Try a dictionary "
|
||||
"or instance of an SDO or SRO class.")
|
||||
raise ValueError(
|
||||
"cannot revoke object of this type! Try a dictionary "
|
||||
"or instance of an SDO or SRO class.",
|
||||
)
|
||||
|
||||
if data.get('revoked'):
|
||||
raise RevokeError("revoke")
|
||||
|
|
|
@ -2,24 +2,27 @@
|
|||
# flake8: noqa
|
||||
|
||||
from .bundle import Bundle
|
||||
from .common import (TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking,
|
||||
ExternalReference, GranularMarking, KillChainPhase,
|
||||
MarkingDefinition, StatementMarking, TLPMarking)
|
||||
from .observables import (URL, AlternateDataStream, ArchiveExt, Artifact,
|
||||
AutonomousSystem, CustomExtension, CustomObservable,
|
||||
Directory, DomainName, EmailAddress, EmailMessage,
|
||||
EmailMIMEComponent, File, HTTPRequestExt, ICMPExt,
|
||||
IPv4Address, IPv6Address, MACAddress, Mutex,
|
||||
NetworkTraffic, NTFSExt, PDFExt, Process,
|
||||
RasterImageExt, SocketExt, Software, TCPExt,
|
||||
UNIXAccountExt, UserAccount, WindowsPEBinaryExt,
|
||||
WindowsPEOptionalHeaderType, WindowsPESection,
|
||||
WindowsProcessExt, WindowsRegistryKey,
|
||||
WindowsRegistryValueType, WindowsServiceExt,
|
||||
X509Certificate, X509V3ExtenstionsType)
|
||||
from .sdo import (AttackPattern, Campaign, CourseOfAction, CustomObject,
|
||||
Identity, Indicator, IntrusionSet, Malware, ObservedData,
|
||||
Report, ThreatActor, Tool, Vulnerability)
|
||||
from .common import (
|
||||
TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, ExternalReference,
|
||||
GranularMarking, KillChainPhase, MarkingDefinition, StatementMarking,
|
||||
TLPMarking,
|
||||
)
|
||||
from .observables import (
|
||||
URL, AlternateDataStream, ArchiveExt, Artifact, AutonomousSystem,
|
||||
CustomExtension, CustomObservable, Directory, DomainName, EmailAddress,
|
||||
EmailMessage, EmailMIMEComponent, File, HTTPRequestExt, ICMPExt,
|
||||
IPv4Address, IPv6Address, MACAddress, Mutex, NetworkTraffic, NTFSExt,
|
||||
PDFExt, Process, RasterImageExt, SocketExt, Software, TCPExt,
|
||||
UNIXAccountExt, UserAccount, WindowsPEBinaryExt,
|
||||
WindowsPEOptionalHeaderType, WindowsPESection, WindowsProcessExt,
|
||||
WindowsRegistryKey, WindowsRegistryValueType, WindowsServiceExt,
|
||||
X509Certificate, X509V3ExtenstionsType,
|
||||
)
|
||||
from .sdo import (
|
||||
AttackPattern, Campaign, CourseOfAction, CustomObject, Identity, Indicator,
|
||||
IntrusionSet, Malware, ObservedData, Report, ThreatActor, Tool,
|
||||
Vulnerability,
|
||||
)
|
||||
from .sro import Relationship, Sighting
|
||||
|
||||
OBJ_MAP = {
|
||||
|
@ -68,7 +71,7 @@ EXT_MAP = {
|
|||
'ntfs-ext': NTFSExt,
|
||||
'pdf-ext': PDFExt,
|
||||
'raster-image-ext': RasterImageExt,
|
||||
'windows-pebinary-ext': WindowsPEBinaryExt
|
||||
'windows-pebinary-ext': WindowsPEBinaryExt,
|
||||
},
|
||||
'network-traffic': {
|
||||
'http-request-ext': HTTPRequestExt,
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
from collections import OrderedDict
|
||||
|
||||
from ..base import _STIXBase
|
||||
from ..properties import (IDProperty, ListProperty, STIXObjectProperty,
|
||||
StringProperty, TypeProperty)
|
||||
from ..properties import (
|
||||
IDProperty, ListProperty, STIXObjectProperty, StringProperty, TypeProperty,
|
||||
)
|
||||
|
||||
|
||||
class Bundle(_STIXBase):
|
||||
|
|
|
@ -5,9 +5,10 @@ from collections import OrderedDict
|
|||
from ..base import _STIXBase
|
||||
from ..custom import _custom_marking_builder
|
||||
from ..markings import _MarkingsMixin
|
||||
from ..properties import (HashesProperty, IDProperty, ListProperty, Property,
|
||||
ReferenceProperty, SelectorProperty, StringProperty,
|
||||
TimestampProperty, TypeProperty)
|
||||
from ..properties import (
|
||||
HashesProperty, IDProperty, ListProperty, Property, ReferenceProperty,
|
||||
SelectorProperty, StringProperty, TimestampProperty, TypeProperty,
|
||||
)
|
||||
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
|
||||
_type = 'tlp'
|
||||
_properties = OrderedDict([
|
||||
('tlp', StringProperty(required=True))
|
||||
('tlp', StringProperty(required=True)),
|
||||
])
|
||||
|
||||
|
||||
|
@ -70,7 +71,7 @@ class StatementMarking(_STIXBase):
|
|||
|
||||
_type = 'statement'
|
||||
_properties = OrderedDict([
|
||||
('statement', StringProperty(required=True))
|
||||
('statement', StringProperty(required=True)),
|
||||
])
|
||||
|
||||
def __init__(self, statement=None, **kwargs):
|
||||
|
@ -157,26 +158,26 @@ TLP_WHITE = MarkingDefinition(
|
|||
id='marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9',
|
||||
created='2017-01-20T00:00:00.000Z',
|
||||
definition_type='tlp',
|
||||
definition=TLPMarking(tlp='white')
|
||||
definition=TLPMarking(tlp='white'),
|
||||
)
|
||||
|
||||
TLP_GREEN = MarkingDefinition(
|
||||
id='marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da',
|
||||
created='2017-01-20T00:00:00.000Z',
|
||||
definition_type='tlp',
|
||||
definition=TLPMarking(tlp='green')
|
||||
definition=TLPMarking(tlp='green'),
|
||||
)
|
||||
|
||||
TLP_AMBER = MarkingDefinition(
|
||||
id='marking-definition--f88d31f6-486f-44da-b317-01333bde0b82',
|
||||
created='2017-01-20T00:00:00.000Z',
|
||||
definition_type='tlp',
|
||||
definition=TLPMarking(tlp='amber')
|
||||
definition=TLPMarking(tlp='amber'),
|
||||
)
|
||||
|
||||
TLP_RED = MarkingDefinition(
|
||||
id='marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed',
|
||||
created='2017-01-20T00:00:00.000Z',
|
||||
definition_type='tlp',
|
||||
definition=TLPMarking(tlp='red')
|
||||
definition=TLPMarking(tlp='red'),
|
||||
)
|
||||
|
|
|
@ -11,12 +11,12 @@ import itertools
|
|||
from ..base import _Extension, _Observable, _STIXBase
|
||||
from ..custom import _custom_extension_builder, _custom_observable_builder
|
||||
from ..exceptions import AtLeastOnePropertyError, DependentPropertiesError
|
||||
from ..properties import (BinaryProperty, BooleanProperty, DictionaryProperty,
|
||||
EmbeddedObjectProperty, EnumProperty,
|
||||
ExtensionsProperty, FloatProperty, HashesProperty,
|
||||
HexProperty, IntegerProperty, ListProperty,
|
||||
ObjectReferenceProperty, StringProperty,
|
||||
TimestampProperty, TypeProperty)
|
||||
from ..properties import (
|
||||
BinaryProperty, BooleanProperty, DictionaryProperty,
|
||||
EmbeddedObjectProperty, EnumProperty, ExtensionsProperty, FloatProperty,
|
||||
HashesProperty, HexProperty, IntegerProperty, ListProperty,
|
||||
ObjectReferenceProperty, StringProperty, TimestampProperty, TypeProperty,
|
||||
)
|
||||
|
||||
|
||||
class Artifact(_Observable):
|
||||
|
@ -423,34 +423,42 @@ class SocketExt(_Extension):
|
|||
|
||||
_type = 'socket-ext'
|
||||
_properties = OrderedDict([
|
||||
('address_family', EnumProperty(allowed=[
|
||||
"AF_UNSPEC",
|
||||
"AF_INET",
|
||||
"AF_IPX",
|
||||
"AF_APPLETALK",
|
||||
"AF_NETBIOS",
|
||||
"AF_INET6",
|
||||
"AF_IRDA",
|
||||
"AF_BTH",
|
||||
], required=True)),
|
||||
(
|
||||
'address_family', EnumProperty(
|
||||
allowed=[
|
||||
"AF_UNSPEC",
|
||||
"AF_INET",
|
||||
"AF_IPX",
|
||||
"AF_APPLETALK",
|
||||
"AF_NETBIOS",
|
||||
"AF_INET6",
|
||||
"AF_IRDA",
|
||||
"AF_BTH",
|
||||
], required=True,
|
||||
),
|
||||
),
|
||||
('is_blocking', BooleanProperty()),
|
||||
('is_listening', BooleanProperty()),
|
||||
('protocol_family', EnumProperty(allowed=[
|
||||
"PF_INET",
|
||||
"PF_IPX",
|
||||
"PF_APPLETALK",
|
||||
"PF_INET6",
|
||||
"PF_AX25",
|
||||
"PF_NETROM"
|
||||
])),
|
||||
(
|
||||
'protocol_family', EnumProperty(allowed=[
|
||||
"PF_INET",
|
||||
"PF_IPX",
|
||||
"PF_APPLETALK",
|
||||
"PF_INET6",
|
||||
"PF_AX25",
|
||||
"PF_NETROM",
|
||||
]),
|
||||
),
|
||||
('options', DictionaryProperty()),
|
||||
('socket_type', EnumProperty(allowed=[
|
||||
"SOCK_STREAM",
|
||||
"SOCK_DGRAM",
|
||||
"SOCK_RAW",
|
||||
"SOCK_RDM",
|
||||
"SOCK_SEQPACKET",
|
||||
])),
|
||||
(
|
||||
'socket_type', EnumProperty(allowed=[
|
||||
"SOCK_STREAM",
|
||||
"SOCK_DGRAM",
|
||||
"SOCK_RAW",
|
||||
"SOCK_RDM",
|
||||
"SOCK_SEQPACKET",
|
||||
]),
|
||||
),
|
||||
('socket_descriptor', IntegerProperty()),
|
||||
('socket_handle', IntegerProperty()),
|
||||
])
|
||||
|
@ -528,29 +536,35 @@ class WindowsServiceExt(_Extension):
|
|||
('descriptions', ListProperty(StringProperty)),
|
||||
('display_name', StringProperty()),
|
||||
('group_name', StringProperty()),
|
||||
('start_type', EnumProperty(allowed=[
|
||||
"SERVICE_AUTO_START",
|
||||
"SERVICE_BOOT_START",
|
||||
"SERVICE_DEMAND_START",
|
||||
"SERVICE_DISABLED",
|
||||
"SERVICE_SYSTEM_ALERT",
|
||||
])),
|
||||
(
|
||||
'start_type', EnumProperty(allowed=[
|
||||
"SERVICE_AUTO_START",
|
||||
"SERVICE_BOOT_START",
|
||||
"SERVICE_DEMAND_START",
|
||||
"SERVICE_DISABLED",
|
||||
"SERVICE_SYSTEM_ALERT",
|
||||
]),
|
||||
),
|
||||
('service_dll_refs', ListProperty(ObjectReferenceProperty(valid_types='file'))),
|
||||
('service_type', EnumProperty(allowed=[
|
||||
"SERVICE_KERNEL_DRIVER",
|
||||
"SERVICE_FILE_SYSTEM_DRIVER",
|
||||
"SERVICE_WIN32_OWN_PROCESS",
|
||||
"SERVICE_WIN32_SHARE_PROCESS",
|
||||
])),
|
||||
('service_status', EnumProperty(allowed=[
|
||||
"SERVICE_CONTINUE_PENDING",
|
||||
"SERVICE_PAUSE_PENDING",
|
||||
"SERVICE_PAUSED",
|
||||
"SERVICE_RUNNING",
|
||||
"SERVICE_START_PENDING",
|
||||
"SERVICE_STOP_PENDING",
|
||||
"SERVICE_STOPPED",
|
||||
])),
|
||||
(
|
||||
'service_type', EnumProperty(allowed=[
|
||||
"SERVICE_KERNEL_DRIVER",
|
||||
"SERVICE_FILE_SYSTEM_DRIVER",
|
||||
"SERVICE_WIN32_OWN_PROCESS",
|
||||
"SERVICE_WIN32_SHARE_PROCESS",
|
||||
]),
|
||||
),
|
||||
(
|
||||
'service_status', EnumProperty(allowed=[
|
||||
"SERVICE_CONTINUE_PENDING",
|
||||
"SERVICE_PAUSE_PENDING",
|
||||
"SERVICE_PAUSED",
|
||||
"SERVICE_RUNNING",
|
||||
"SERVICE_START_PENDING",
|
||||
"SERVICE_STOP_PENDING",
|
||||
"SERVICE_STOPPED",
|
||||
]),
|
||||
),
|
||||
])
|
||||
|
||||
|
||||
|
@ -672,21 +686,23 @@ class WindowsRegistryValueType(_STIXBase):
|
|||
_properties = OrderedDict([
|
||||
('name', StringProperty(required=True)),
|
||||
('data', StringProperty()),
|
||||
('data_type', EnumProperty(allowed=[
|
||||
"REG_NONE",
|
||||
"REG_SZ",
|
||||
"REG_EXPAND_SZ",
|
||||
"REG_BINARY",
|
||||
"REG_DWORD",
|
||||
"REG_DWORD_BIG_ENDIAN",
|
||||
"REG_LINK",
|
||||
"REG_MULTI_SZ",
|
||||
"REG_RESOURCE_LIST",
|
||||
"REG_FULL_RESOURCE_DESCRIPTION",
|
||||
"REG_RESOURCE_REQUIREMENTS_LIST",
|
||||
"REG_QWORD",
|
||||
"REG_INVALID_TYPE",
|
||||
])),
|
||||
(
|
||||
'data_type', EnumProperty(allowed=[
|
||||
"REG_NONE",
|
||||
"REG_SZ",
|
||||
"REG_EXPAND_SZ",
|
||||
"REG_BINARY",
|
||||
"REG_DWORD",
|
||||
"REG_DWORD_BIG_ENDIAN",
|
||||
"REG_LINK",
|
||||
"REG_MULTI_SZ",
|
||||
"REG_RESOURCE_LIST",
|
||||
"REG_FULL_RESOURCE_DESCRIPTION",
|
||||
"REG_RESOURCE_REQUIREMENTS_LIST",
|
||||
"REG_QWORD",
|
||||
"REG_INVALID_TYPE",
|
||||
]),
|
||||
),
|
||||
])
|
||||
|
||||
|
||||
|
@ -782,7 +798,7 @@ def CustomObservable(type='x-custom-observable', properties=None):
|
|||
_properties = list(itertools.chain.from_iterable([
|
||||
[('type', TypeProperty(type))],
|
||||
properties,
|
||||
[('extensions', ExtensionsProperty(enclosing_type=type))]
|
||||
[('extensions', ExtensionsProperty(enclosing_type=type))],
|
||||
]))
|
||||
return _custom_observable_builder(cls, type, _properties, '2.0')
|
||||
return wrapper
|
||||
|
|
|
@ -6,10 +6,11 @@ import itertools
|
|||
|
||||
from ..core import STIXDomainObject
|
||||
from ..custom import _custom_object_builder
|
||||
from ..properties import (BooleanProperty, IDProperty, IntegerProperty,
|
||||
ListProperty, ObservableProperty, PatternProperty,
|
||||
ReferenceProperty, StringProperty, TimestampProperty,
|
||||
TypeProperty)
|
||||
from ..properties import (
|
||||
BooleanProperty, IDProperty, IntegerProperty, ListProperty,
|
||||
ObservableProperty, PatternProperty, ReferenceProperty, StringProperty,
|
||||
TimestampProperty, TypeProperty,
|
||||
)
|
||||
from ..utils import NOW
|
||||
from .common import ExternalReference, GranularMarking, KillChainPhase
|
||||
|
||||
|
@ -354,7 +355,7 @@ def CustomObject(type='x-custom-type', properties=None):
|
|||
('id', IDProperty(type)),
|
||||
('created_by_ref', ReferenceProperty(type='identity')),
|
||||
('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_')],
|
||||
[
|
||||
|
@ -364,7 +365,7 @@ def CustomObject(type='x-custom-type', properties=None):
|
|||
('object_marking_refs', ListProperty(ReferenceProperty(type='marking-definition'))),
|
||||
('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')
|
||||
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
from collections import OrderedDict
|
||||
|
||||
from ..core import STIXRelationshipObject
|
||||
from ..properties import (BooleanProperty, IDProperty, IntegerProperty,
|
||||
ListProperty, ReferenceProperty, StringProperty,
|
||||
TimestampProperty, TypeProperty)
|
||||
from ..properties import (
|
||||
BooleanProperty, IDProperty, IntegerProperty, ListProperty,
|
||||
ReferenceProperty, StringProperty, TimestampProperty, TypeProperty,
|
||||
)
|
||||
from ..utils import NOW
|
||||
from .common import ExternalReference, GranularMarking
|
||||
|
||||
|
@ -34,8 +35,10 @@ class Relationship(STIXRelationshipObject):
|
|||
])
|
||||
|
||||
# Explicitly define the first three kwargs to make readable Relationship declarations.
|
||||
def __init__(self, source_ref=None, relationship_type=None,
|
||||
target_ref=None, **kwargs):
|
||||
def __init__(
|
||||
self, source_ref=None, relationship_type=None,
|
||||
target_ref=None, **kwargs
|
||||
):
|
||||
# Allow (source_ref, relationship_type, target_ref) as positional args.
|
||||
if source_ref and not kwargs.get('source_ref'):
|
||||
kwargs['source_ref'] = source_ref
|
||||
|
|
|
@ -2,26 +2,27 @@
|
|||
# flake8: noqa
|
||||
|
||||
from .bundle import Bundle
|
||||
from .common import (TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking,
|
||||
ExternalReference, GranularMarking, KillChainPhase,
|
||||
LanguageContent, MarkingDefinition, StatementMarking,
|
||||
TLPMarking)
|
||||
from .observables import (URL, AlternateDataStream, ArchiveExt, Artifact,
|
||||
AutonomousSystem, CustomExtension, CustomObservable,
|
||||
Directory, DomainName, EmailAddress, EmailMessage,
|
||||
EmailMIMEComponent, File, HTTPRequestExt, ICMPExt,
|
||||
IPv4Address, IPv6Address, MACAddress, Mutex,
|
||||
NetworkTraffic, NTFSExt, PDFExt, Process,
|
||||
RasterImageExt, SocketExt, Software, TCPExt,
|
||||
UNIXAccountExt, UserAccount, WindowsPEBinaryExt,
|
||||
WindowsPEOptionalHeaderType, WindowsPESection,
|
||||
WindowsProcessExt, WindowsRegistryKey,
|
||||
WindowsRegistryValueType, WindowsServiceExt,
|
||||
X509Certificate, X509V3ExtenstionsType)
|
||||
from .sdo import (AttackPattern, Campaign, CourseOfAction, CustomObject,
|
||||
Identity, Indicator, IntrusionSet, Location, Malware, Note,
|
||||
ObservedData, Opinion, Report, ThreatActor, Tool,
|
||||
Vulnerability)
|
||||
from .common import (
|
||||
TLP_AMBER, TLP_GREEN, TLP_RED, TLP_WHITE, CustomMarking, ExternalReference,
|
||||
GranularMarking, KillChainPhase, LanguageContent, MarkingDefinition,
|
||||
StatementMarking, TLPMarking,
|
||||
)
|
||||
from .observables import (
|
||||
URL, AlternateDataStream, ArchiveExt, Artifact, AutonomousSystem,
|
||||
CustomExtension, CustomObservable, Directory, DomainName, EmailAddress,
|
||||
EmailMessage, EmailMIMEComponent, File, HTTPRequestExt, ICMPExt,
|
||||
IPv4Address, IPv6Address, MACAddress, Mutex, NetworkTraffic, NTFSExt,
|
||||
PDFExt, Process, RasterImageExt, SocketExt, Software, TCPExt,
|
||||
UNIXAccountExt, UserAccount, WindowsPEBinaryExt,
|
||||
WindowsPEOptionalHeaderType, WindowsPESection, WindowsProcessExt,
|
||||
WindowsRegistryKey, WindowsRegistryValueType, WindowsServiceExt,
|
||||
X509Certificate, X509V3ExtenstionsType,
|
||||
)
|
||||
from .sdo import (
|
||||
AttackPattern, Campaign, CourseOfAction, CustomObject, Identity, Indicator,
|
||||
IntrusionSet, Location, Malware, Note, ObservedData, Opinion, Report,
|
||||
ThreatActor, Tool, Vulnerability,
|
||||
)
|
||||
from .sro import Relationship, Sighting
|
||||
|
||||
OBJ_MAP = {
|
||||
|
@ -74,7 +75,7 @@ EXT_MAP = {
|
|||
'ntfs-ext': NTFSExt,
|
||||
'pdf-ext': PDFExt,
|
||||
'raster-image-ext': RasterImageExt,
|
||||
'windows-pebinary-ext': WindowsPEBinaryExt
|
||||
'windows-pebinary-ext': WindowsPEBinaryExt,
|
||||
},
|
||||
'network-traffic': {
|
||||
'http-request-ext': HTTPRequestExt,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue