WIP - finding more issues with allowing dicts as filters
							parent
							
								
									27647091a5
								
							
						
					
					
						commit
						ba6fa595c6
					
				| 
						 | 
				
			
			@ -5,11 +5,13 @@ Filters for Python STIX 2.0 DataSources, DataSinks, DataStores
 | 
			
		|||
 | 
			
		||||
import collections
 | 
			
		||||
 | 
			
		||||
from stix2.utils import STIXdatetime
 | 
			
		||||
 | 
			
		||||
"""Supported filter operations"""
 | 
			
		||||
FILTER_OPS = ['=', '!=', 'in', '>', '<', '>=', '<=']
 | 
			
		||||
 | 
			
		||||
"""Supported filter value types"""
 | 
			
		||||
FILTER_VALUE_TYPES = [bool, dict, float, int, list, str, tuple]
 | 
			
		||||
FILTER_VALUE_TYPES = [bool, dict, float, int, list, str, tuple, STIXdatetime]
 | 
			
		||||
try:
 | 
			
		||||
    FILTER_VALUE_TYPES.append(unicode)
 | 
			
		||||
except NameError:
 | 
			
		||||
| 
						 | 
				
			
			@ -169,19 +171,26 @@ def _check_filter(filter_, stix_obj):
 | 
			
		|||
        # Check embedded properties, from e.g. granular_markings or external_references
 | 
			
		||||
        sub_property = filter_.property.split(".", 1)[1]
 | 
			
		||||
        sub_filter = filter_._replace(property=sub_property)
 | 
			
		||||
 | 
			
		||||
        if isinstance(stix_obj[prop], list):
 | 
			
		||||
            for elem in stix_obj[prop]:
 | 
			
		||||
                if _check_filter(sub_filter, elem) is True:
 | 
			
		||||
                    return True
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
        elif isinstance(stix_obj[prop], dict):
 | 
			
		||||
            return _check_filter(sub_filter, stix_obj[prop])
 | 
			
		||||
 | 
			
		||||
        else:
 | 
			
		||||
            return _check_filter(sub_filter, stix_obj[prop])
 | 
			
		||||
 | 
			
		||||
    elif isinstance(stix_obj[prop], list):
 | 
			
		||||
        # Check each item in list property to see if it matches
 | 
			
		||||
        for elem in stix_obj[prop]:
 | 
			
		||||
            if filter_._check_property(elem) is True:
 | 
			
		||||
                return True
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    else:
 | 
			
		||||
        # Check if property matches
 | 
			
		||||
        return filter_._check_property(stix_obj[prop])
 | 
			
		||||
| 
						 | 
				
			
			@ -201,6 +210,10 @@ class FilterSet(object):
 | 
			
		|||
        for f in self._filters:
 | 
			
		||||
            yield f
 | 
			
		||||
 | 
			
		||||
    def __len__(self):
 | 
			
		||||
        """ """
 | 
			
		||||
        return len(self._filters)
 | 
			
		||||
 | 
			
		||||
    def add(self, filters):
 | 
			
		||||
        """ """
 | 
			
		||||
        if not isinstance(filters, FilterSet) and not isinstance(filters, list):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -115,7 +115,7 @@ class Environment(DataStoreMixin):
 | 
			
		|||
 | 
			
		||||
    def add_filters(self, *args, **kwargs):
 | 
			
		||||
        try:
 | 
			
		||||
            return self.source.filters.update(*args, **kwargs)
 | 
			
		||||
            return self.source.filters.add(*args, **kwargs)
 | 
			
		||||
        except AttributeError:
 | 
			
		||||
            raise AttributeError('Environment has no data source')
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,10 +2,11 @@ import pytest
 | 
			
		|||
from taxii2client import Collection
 | 
			
		||||
 | 
			
		||||
from stix2 import Filter, MemorySink, MemorySource
 | 
			
		||||
from stix2.core import parse
 | 
			
		||||
from stix2.datastore import (CompositeDataSource, DataSink, DataSource,
 | 
			
		||||
                             make_id, taxii)
 | 
			
		||||
from stix2.datastore.filters import apply_common_filters
 | 
			
		||||
from stix2.utils import deduplicate
 | 
			
		||||
from stix2.utils import deduplicate, parse_into_datetime
 | 
			
		||||
 | 
			
		||||
COLLECTION_URL = 'https://example.com/api1/collections/91a7b528-80eb-42ed-a74d-c6fbd5a26116/'
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -120,6 +121,9 @@ IND8 = {
 | 
			
		|||
STIX_OBJS2 = [IND6, IND7, IND8]
 | 
			
		||||
STIX_OBJS1 = [IND1, IND2, IND3, IND4, IND5]
 | 
			
		||||
 | 
			
		||||
REAL_STIX_OBJS2 = [parse(IND6), parse(IND7), parse(IND8)]
 | 
			
		||||
REAL_STIX_OBJS1 = [parse(IND1), parse(IND2), parse(IND3), parse(IND4), parse(IND5)]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_ds_abstract_class_smoke():
 | 
			
		||||
    with pytest.raises(TypeError):
 | 
			
		||||
| 
						 | 
				
			
			@ -148,12 +152,12 @@ def test_parse_taxii_filters():
 | 
			
		|||
        Filter("created_by_ref", "=", "Bane"),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    taxii_filters_expected = set([
 | 
			
		||||
    taxii_filters_expected = [
 | 
			
		||||
        Filter("added_after", "=", "2016-02-01T00:00:01.000Z"),
 | 
			
		||||
        Filter("id", "=", "taxii stix object ID"),
 | 
			
		||||
        Filter("type", "=", "taxii stix object ID"),
 | 
			
		||||
        Filter("version", "=", "first")
 | 
			
		||||
    ])
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    ds = taxii.TAXIICollectionSource(collection)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -177,7 +181,7 @@ def test_add_get_remove_filter():
 | 
			
		|||
    ds.filters.add(valid_filters[0])
 | 
			
		||||
    assert len(ds.filters) == 1
 | 
			
		||||
 | 
			
		||||
    # Addin the same filter again will have no effect since `filters` uses a set
 | 
			
		||||
    # Addin the same filter again will have no effect since `filters` acts like a set
 | 
			
		||||
    ds.filters.add(valid_filters[0])
 | 
			
		||||
    assert len(ds.filters) == 1
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -186,14 +190,14 @@ def test_add_get_remove_filter():
 | 
			
		|||
    ds.filters.add(valid_filters[2])
 | 
			
		||||
    assert len(ds.filters) == 3
 | 
			
		||||
 | 
			
		||||
    assert set(valid_filters) == ds.filters
 | 
			
		||||
    assert valid_filters == [f for f in ds.filters]
 | 
			
		||||
 | 
			
		||||
    # remove
 | 
			
		||||
    ds.filters.remove(valid_filters[0])
 | 
			
		||||
 | 
			
		||||
    assert len(ds.filters) == 2
 | 
			
		||||
 | 
			
		||||
    ds.filters.update(valid_filters)
 | 
			
		||||
    ds.filters.add(valid_filters)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_filter_ops_check():
 | 
			
		||||
| 
						 | 
				
			
			@ -297,9 +301,32 @@ def test_apply_common_filters():
 | 
			
		|||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "labels": ["heartbleed", "has-logo"]
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "type": "observed-data",
 | 
			
		||||
            "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": 1,
 | 
			
		||||
            "objects": {
 | 
			
		||||
                "0": {
 | 
			
		||||
                    "type": "file",
 | 
			
		||||
                    "name": "HAL 9000.exe"
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    # same as above objects but converted to real Python STIX2 objects
 | 
			
		||||
    # to test filters against true Python STIX2 objects
 | 
			
		||||
    print(stix_objs)
 | 
			
		||||
    real_stix_objs = [parse(stix_obj) for stix_obj in stix_objs]
 | 
			
		||||
    print("after\n\n")
 | 
			
		||||
    print(stix_objs)
 | 
			
		||||
    filters = [
 | 
			
		||||
        Filter("type", "!=", "relationship"),
 | 
			
		||||
        Filter("id", "=", "relationship--2f9a9aa9-108a-4333-83e2-4fb25add0463"),
 | 
			
		||||
| 
						 | 
				
			
			@ -315,6 +342,7 @@ def test_apply_common_filters():
 | 
			
		|||
        Filter("object_marking_refs", "=", "marking-definition--613f2e26-0000-0000-0000-b8e91df99dc9"),
 | 
			
		||||
        Filter("granular_markings.selectors", "in", "description"),
 | 
			
		||||
        Filter("external_references.source_name", "=", "CVE"),
 | 
			
		||||
        Filter("objects", "=", {"0": {"type": "file", "name": "HAL 9000.exe"}})
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    # "Return any object whose type is not relationship"
 | 
			
		||||
| 
						 | 
				
			
			@ -323,66 +351,125 @@ def test_apply_common_filters():
 | 
			
		|||
    assert stix_objs[0]['id'] in ids
 | 
			
		||||
    assert stix_objs[1]['id'] in ids
 | 
			
		||||
    assert stix_objs[3]['id'] in ids
 | 
			
		||||
    assert len(ids) == 3
 | 
			
		||||
    assert len(ids) == 4
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(real_stix_objs, [filters[0]]))
 | 
			
		||||
    ids = [r.id for r in resp]
 | 
			
		||||
    assert real_stix_objs[0].id in ids
 | 
			
		||||
    assert real_stix_objs[1].id in ids
 | 
			
		||||
    assert real_stix_objs[3].id in ids
 | 
			
		||||
    assert len(ids) == 4
 | 
			
		||||
 | 
			
		||||
    # "Return any object that matched id relationship--2f9a9aa9-108a-4333-83e2-4fb25add0463"
 | 
			
		||||
    resp = list(apply_common_filters(stix_objs, [filters[1]]))
 | 
			
		||||
    assert resp[0]['id'] == stix_objs[2]['id']
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(real_stix_objs, [filters[1]]))
 | 
			
		||||
    assert resp[0].id == real_stix_objs[2].id
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
    # "Return any object that contains remote-access-trojan in labels"
 | 
			
		||||
    resp = list(apply_common_filters(stix_objs, [filters[2]]))
 | 
			
		||||
    assert resp[0]['id'] == stix_objs[0]['id']
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(real_stix_objs, [filters[2]]))
 | 
			
		||||
    assert resp[0].id == real_stix_objs[0].id
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
    # "Return any object created after 2015-01-01T01:00:00.000Z"
 | 
			
		||||
    resp = list(apply_common_filters(stix_objs, [filters[3]]))
 | 
			
		||||
    assert resp[0]['id'] == stix_objs[0]['id']
 | 
			
		||||
    assert len(resp) == 2
 | 
			
		||||
    assert len(resp) == 3
 | 
			
		||||
 | 
			
		||||
    # "Return any revoked object"
 | 
			
		||||
    resp = list(apply_common_filters(stix_objs, [filters[4]]))
 | 
			
		||||
    assert resp[0]['id'] == stix_objs[2]['id']
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(real_stix_objs, [filters[4]]))
 | 
			
		||||
    assert resp[0].id == real_stix_objs[2].id
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
    # "Return any object whose not revoked"
 | 
			
		||||
    # Note that if 'revoked' property is not present in object.
 | 
			
		||||
    # Currently we can't use such an expression to filter for... :(
 | 
			
		||||
    resp = list(apply_common_filters(stix_objs, [filters[5]]))
 | 
			
		||||
    assert len(resp) == 0
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(real_stix_objs, [filters[5]]))
 | 
			
		||||
    assert len(resp) == 0
 | 
			
		||||
 | 
			
		||||
    # "Return any object that matches marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9 in object_marking_refs"
 | 
			
		||||
    resp = list(apply_common_filters(stix_objs, [filters[6]]))
 | 
			
		||||
    assert resp[0]['id'] == stix_objs[2]['id']
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(real_stix_objs, [filters[6]]))
 | 
			
		||||
    assert resp[0].id == real_stix_objs[2].id
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
    # "Return any object that contains relationship_type in their selectors AND
 | 
			
		||||
    # also has marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed in marking_ref"
 | 
			
		||||
    resp = list(apply_common_filters(stix_objs, [filters[7], filters[8]]))
 | 
			
		||||
    assert resp[0]['id'] == stix_objs[2]['id']
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(real_stix_objs, [filters[7], filters[8]]))
 | 
			
		||||
    assert resp[0].id == real_stix_objs[2].id
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
    # "Return any object that contains CVE-2014-0160,CVE-2017-6608 in their external_id"
 | 
			
		||||
    resp = list(apply_common_filters(stix_objs, [filters[9]]))
 | 
			
		||||
    assert resp[0]['id'] == stix_objs[3]['id']
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(real_stix_objs, [filters[9]]))
 | 
			
		||||
    assert resp[0].id == real_stix_objs[3].id
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
    # "Return any object that matches created_by_ref identity--00000000-0000-0000-0000-b8e91df99dc9"
 | 
			
		||||
    resp = list(apply_common_filters(stix_objs, [filters[10]]))
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(real_stix_objs, [filters[10]]))
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
    # "Return any object that matches marking-definition--613f2e26-0000-0000-0000-b8e91df99dc9 in object_marking_refs" (None)
 | 
			
		||||
    resp = list(apply_common_filters(stix_objs, [filters[11]]))
 | 
			
		||||
    assert len(resp) == 0
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(real_stix_objs, [filters[11]]))
 | 
			
		||||
    assert len(resp) == 0
 | 
			
		||||
 | 
			
		||||
    # "Return any object that contains description in its selectors" (None)
 | 
			
		||||
    resp = list(apply_common_filters(stix_objs, [filters[12]]))
 | 
			
		||||
    assert len(resp) == 0
 | 
			
		||||
 | 
			
		||||
    # "Return any object that object that matches CVE in source_name" (None, case sensitive)
 | 
			
		||||
    resp = list(apply_common_filters(real_stix_objs, [filters[12]]))
 | 
			
		||||
    assert len(resp) == 0
 | 
			
		||||
 | 
			
		||||
    # "Return any object that matches CVE in source_name" (None, case sensitive)
 | 
			
		||||
    resp = list(apply_common_filters(stix_objs, [filters[13]]))
 | 
			
		||||
    assert len(resp) == 0
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(real_stix_objs, [filters[13]]))
 | 
			
		||||
    assert len(resp) == 0
 | 
			
		||||
 | 
			
		||||
    # Return any object that matches file object in "objects"
 | 
			
		||||
    # BUG: This test is brokem , weird behavior, the file obj
 | 
			
		||||
    # in stix_objs is being parsed into real python-stix2 obj even though
 | 
			
		||||
    # it never goes through parse() --> BAD <_<
 | 
			
		||||
    print(stix_objs)
 | 
			
		||||
    resp = list(apply_common_filters(stix_objs, [filters[14]]))
 | 
			
		||||
    assert resp[0]["id"] == stix_objs[14]["id"]
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(real_stix_objs, [filters[14]]))
 | 
			
		||||
    assert resp[0].id == real_stix_objs[14].id
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_filters0():
 | 
			
		||||
    # "Return any object modified before 2017-01-28T13:49:53.935Z"
 | 
			
		||||
| 
						 | 
				
			
			@ -390,6 +477,10 @@ def test_filters0():
 | 
			
		|||
    assert resp[0]['id'] == STIX_OBJS2[1]['id']
 | 
			
		||||
    assert len(resp) == 2
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(REAL_STIX_OBJS2, [Filter("modified", "<", parse_into_datetime("2017-01-28T13:49:53.935Z"))]))
 | 
			
		||||
    assert resp[0].id == REAL_STIX_OBJS2[1].id
 | 
			
		||||
    assert len(resp) == 2
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_filters1():
 | 
			
		||||
    # "Return any object modified after 2017-01-28T13:49:53.935Z"
 | 
			
		||||
| 
						 | 
				
			
			@ -397,6 +488,10 @@ def test_filters1():
 | 
			
		|||
    assert resp[0]['id'] == STIX_OBJS2[0]['id']
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(REAL_STIX_OBJS2, [Filter("modified", ">", parse_into_datetime("2017-01-28T13:49:53.935Z"))]))
 | 
			
		||||
    assert resp[0].id == REAL_STIX_OBJS2[0].id
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_filters2():
 | 
			
		||||
    # "Return any object modified after or on 2017-01-28T13:49:53.935Z"
 | 
			
		||||
| 
						 | 
				
			
			@ -404,6 +499,10 @@ def test_filters2():
 | 
			
		|||
    assert resp[0]['id'] == STIX_OBJS2[0]['id']
 | 
			
		||||
    assert len(resp) == 3
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(REAL_STIX_OBJS2, [Filter("modified", ">=", parse_into_datetime("2017-01-27T13:49:53.935Z"))]))
 | 
			
		||||
    assert resp[0].id == REAL_STIX_OBJS2[0].id
 | 
			
		||||
    assert len(resp) == 3
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_filters3():
 | 
			
		||||
    # "Return any object modified before or on 2017-01-28T13:49:53.935Z"
 | 
			
		||||
| 
						 | 
				
			
			@ -411,6 +510,11 @@ def test_filters3():
 | 
			
		|||
    assert resp[0]['id'] == STIX_OBJS2[1]['id']
 | 
			
		||||
    assert len(resp) == 2
 | 
			
		||||
 | 
			
		||||
    # "Return any object modified before or on 2017-01-28T13:49:53.935Z"
 | 
			
		||||
    resp = list(apply_common_filters(REAL_STIX_OBJS2, [Filter("modified", "<=", parse_into_datetime("2017-01-27T13:49:53.935Z"))]))
 | 
			
		||||
    assert resp[0].id == REAL_STIX_OBJS2[1].id
 | 
			
		||||
    assert len(resp) == 2
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_filters4():
 | 
			
		||||
    # Assert invalid Filter cannot be created
 | 
			
		||||
| 
						 | 
				
			
			@ -426,6 +530,10 @@ def test_filters5():
 | 
			
		|||
    assert resp[0]['id'] == STIX_OBJS2[0]['id']
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(REAL_STIX_OBJS2, [Filter("id", "!=", "indicator--d81f86b8-975b-bc0b-775e-810c5ad45a4f")]))
 | 
			
		||||
    assert resp[0].id == REAL_STIX_OBJS2[0].id
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_filters6():
 | 
			
		||||
    # Test filtering on non-common property
 | 
			
		||||
| 
						 | 
				
			
			@ -433,10 +541,14 @@ def test_filters6():
 | 
			
		|||
    assert resp[0]['id'] == STIX_OBJS2[0]['id']
 | 
			
		||||
    assert len(resp) == 3
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(REAL_STIX_OBJS2, [Filter("name", "=", "Malicious site hosting downloader")]))
 | 
			
		||||
    assert resp[0].id == REAL_STIX_OBJS2[0].id
 | 
			
		||||
    assert len(resp) == 3
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_filters7():
 | 
			
		||||
    # Test filtering on embedded property
 | 
			
		||||
    stix_objects = list(STIX_OBJS2) + [{
 | 
			
		||||
    obsvd_data_obj = {
 | 
			
		||||
        "type": "observed-data",
 | 
			
		||||
        "id": "observed-data--b67d30ff-02ac-498a-92f9-32f845f448cf",
 | 
			
		||||
        "created_by_ref": "identity--f431f809-377b-45e0-aa1c-6a4751cae5ff",
 | 
			
		||||
| 
						 | 
				
			
			@ -467,11 +579,19 @@ def test_filters7():
 | 
			
		|||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    stix_objects = list(STIX_OBJS2) + [obsvd_data_obj]
 | 
			
		||||
    real_stix_objects = list(REAL_STIX_OBJS2) + [parse(obsvd_data_obj)]
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(stix_objects, [Filter("objects.0.extensions.pdf-ext.version", ">", "1.2")]))
 | 
			
		||||
    assert resp[0]['id'] == stix_objects[3]['id']
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
    resp = list(apply_common_filters(real_stix_objects, [Filter("objects.0.extensions.pdf-ext.version", ">", "1.2")]))
 | 
			
		||||
    assert resp[0].id == real_stix_objects[3].id
 | 
			
		||||
    assert len(resp) == 1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_deduplicate():
 | 
			
		||||
    unique = deduplicate(STIX_OBJS1)
 | 
			
		||||
| 
						 | 
				
			
			@ -548,7 +668,7 @@ def test_composite_datasource_operations():
 | 
			
		|||
        Filter("valid_from", "=", "2017-01-27T13:49:53.935382Z")
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    cds1.filters.update(query2)
 | 
			
		||||
    cds1.filters.add(query2)
 | 
			
		||||
 | 
			
		||||
    results = cds1.query(query1)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue