Skip to content
This repository was archived by the owner on Dec 5, 2025. It is now read-only.

Commit 44315c6

Browse files
committed
[client] move nb refs computation from splitter to static utils method
1 parent b36a15f commit 44315c6

File tree

5 files changed

+52
-54
lines changed

5 files changed

+52
-54
lines changed

pycti/connector/opencti_connector_helper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2096,7 +2096,7 @@ def send_stix2_bundle(self, bundle: str, **kwargs) -> list:
20962096
os.rename(write_file, final_write_file)
20972097

20982098
stix2_splitter = OpenCTIStix2Splitter()
2099-
(expectations_number, _, bundles, _) = (
2099+
(expectations_number, _, bundles) = (
21002100
stix2_splitter.split_bundle_with_expectations(
21012101
bundle=bundle,
21022102
use_json=True,

pycti/utils/opencti_stix2.py

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
STIX_CORE_OBJECTS,
3333
STIX_CYBER_OBSERVABLE_MAPPING,
3434
STIX_META_OBJECTS,
35+
OpenCTIStix2Utils,
3536
)
3637

3738
datefinder.ValueError = ValueError, OverflowError
@@ -3076,8 +3077,8 @@ def import_bundle(
30763077
else None
30773078
)
30783079

3079-
stix2_splitter = OpenCTIStix2Splitter(objects_max_refs)
3080-
_, incompatible_elements, bundles, too_large_elements_bundles = (
3080+
stix2_splitter = OpenCTIStix2Splitter()
3081+
_, incompatible_elements, bundles = (
30813082
stix2_splitter.split_bundle_with_expectations(
30823083
stix_bundle, False, event_version
30833084
)
@@ -3095,23 +3096,27 @@ def import_bundle(
30953096
+ " is incompatible and couldn't be processed",
30963097
},
30973098
)
3098-
for too_large_elements_bundle in too_large_elements_bundles:
3099-
self.opencti.work.report_expectation(
3100-
work_id,
3101-
{
3102-
"error": "Too large element in bundle",
3103-
"source": "Element "
3104-
+ too_large_elements_bundle["id"]
3105-
+ " is too large and couldn't be processed",
3106-
},
3107-
)
31083099

31093100
# Import every element in a specific order
31103101
imported_elements = []
3102+
too_large_elements_bundles = []
31113103
for bundle in bundles:
31123104
for item in bundle["objects"]:
3113-
self.import_item(item, update, types, 0, work_id)
3114-
imported_elements.append({"id": item["id"], "type": item["type"]})
3105+
nb_refs = OpenCTIStix2Utils.compute_object_refs_number(item)
3106+
if 0 < objects_max_refs <= nb_refs:
3107+
self.opencti.work.report_expectation(
3108+
work_id,
3109+
{
3110+
"error": "Too large element in bundle",
3111+
"source": "Element "
3112+
+ item["id"]
3113+
+ " is too large and couldn't be processed",
3114+
},
3115+
)
3116+
too_large_elements_bundles.append(item)
3117+
else:
3118+
self.import_item(item, update, types, 0, work_id)
3119+
imported_elements.append({"id": item["id"], "type": item["type"]})
31153120

31163121
return imported_elements, too_large_elements_bundles
31173122

pycti/utils/opencti_stix2_splitter.py

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,17 @@ def is_id_supported(key):
3333
return True
3434

3535

36-
class OpenCTIStix2Splitter: # pylint: disable=too-many-instance-attributes
36+
class OpenCTIStix2Splitter:
3737
"""STIX2 bundle splitter for OpenCTI
3838
3939
Splits large STIX2 bundles into smaller chunks for processing.
4040
"""
4141

42-
def __init__(self, objects_max_refs: int = 0):
43-
self.objects_max_refs = objects_max_refs
42+
def __init__(self):
4443
self.cache_index = {}
4544
self.cache_refs = {}
4645
self.elements = []
4746
self.incompatible_items = []
48-
self.too_large_elements = []
4947

5048
def get_internal_ids_in_extension(self, item):
5149
ids = []
@@ -63,7 +61,6 @@ def enlist_element(
6361
self, item_id, raw_data, cleanup_inconsistent_bundle, parent_acc
6462
):
6563
nb_deps = 1
66-
raw_nb_refs = 0
6764
if item_id not in raw_data:
6865
return 0
6966

@@ -80,7 +77,6 @@ def enlist_element(
8077
if key.endswith("_refs") and item[key] is not None:
8178
to_keep = []
8279
for element_ref in item[key]:
83-
raw_nb_refs += 1
8480
# We need to check if this ref is not already a reference
8581
is_missing_ref = raw_data.get(element_ref) is None
8682
must_be_cleaned = is_missing_ref and cleanup_inconsistent_bundle
@@ -107,7 +103,6 @@ def enlist_element(
107103
to_keep.append(element_ref)
108104
item[key] = to_keep
109105
elif key.endswith("_ref"):
110-
raw_nb_refs += 1
111106
is_missing_ref = raw_data.get(value) is None
112107
must_be_cleaned = is_missing_ref and cleanup_inconsistent_bundle
113108
not_dependency_ref = (
@@ -134,7 +129,6 @@ def enlist_element(
134129
item[key] = None
135130
# Case for embedded elements (deduplicating and cleanup)
136131
elif key == "external_references" and item[key] is not None:
137-
raw_nb_refs += 1
138132
# specific case of splitting external references
139133
# reference_ids = []
140134
deduplicated_references = []
@@ -161,7 +155,6 @@ def enlist_element(
161155
# nb_deps += self.enlist_element(reference_id, raw_data)
162156
item[key] = deduplicated_references
163157
elif key == "kill_chain_phases" and item[key] is not None:
164-
raw_nb_refs += 1
165158
# specific case of splitting kill_chain phases
166159
# kill_chain_ids = []
167160
deduplicated_kill_chain = []
@@ -203,9 +196,8 @@ def enlist_element(
203196
)
204197
else:
205198
is_compatible = is_id_supported(item_id)
206-
if 0 < self.objects_max_refs <= raw_nb_refs:
207-
self.too_large_elements.append(item)
208-
elif is_compatible:
199+
200+
if is_compatible:
209201
self.elements.append(item)
210202
else:
211203
self.incompatible_items.append(item)
@@ -221,7 +213,7 @@ def split_bundle_with_expectations(
221213
use_json=True,
222214
event_version=None,
223215
cleanup_inconsistent_bundle=False,
224-
) -> Tuple[int, list, list, list]:
216+
) -> Tuple[int, list, list]:
225217
"""splits a valid stix2 bundle into a list of bundles"""
226218
if use_json:
227219
try:
@@ -271,28 +263,15 @@ def by_dep_size(elem):
271263
)
272264
)
273265

274-
too_large_elements_bundles = []
275-
for too_large_element in self.too_large_elements:
276-
too_large_elements_bundles.append(
277-
self.stix2_create_bundle(
278-
bundle_data["id"],
279-
too_large_element["nb_deps"],
280-
[too_large_element],
281-
use_json,
282-
event_version,
283-
)
284-
)
285-
286266
return (
287267
number_expectations,
288268
self.incompatible_items,
289269
bundles,
290-
too_large_elements_bundles,
291270
)
292271

293272
@deprecated("Use split_bundle_with_expectations instead")
294273
def split_bundle(self, bundle, use_json=True, event_version=None) -> list:
295-
_, _, bundles, _ = self.split_bundle_with_expectations(
274+
_, _, bundles = self.split_bundle_with_expectations(
296275
bundle, use_json, event_version
297276
)
298277
return bundles

pycti/utils/opencti_stix2_utils.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,17 @@ def retrieveClassForMethod(
233233
if hasattr(attribute, method):
234234
return attribute
235235
return None
236+
237+
@staticmethod
238+
def compute_object_refs_number(entity: Dict):
239+
refs_number = 0
240+
for key in list(entity.keys()):
241+
if key.endswith("_refs") and entity[key] is not None:
242+
refs_number += len(entity[key])
243+
elif key.endswith("_ref"):
244+
refs_number += 1
245+
elif key == "external_references" and entity[key] is not None:
246+
refs_number += len(entity[key])
247+
elif key == "kill_chain_phases" and entity[key] is not None:
248+
refs_number += len(entity[key])
249+
return refs_number

tests/01-unit/utils/test_opencti_stix2_splitter.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ def test_split_bundle():
1010
stix_splitter = OpenCTIStix2Splitter()
1111
with open("./tests/data/enterprise-attack.json") as file:
1212
content = file.read()
13-
expectations, _, bundles, _ = stix_splitter.split_bundle_with_expectations(content)
13+
expectations, _, bundles = stix_splitter.split_bundle_with_expectations(content)
1414
assert expectations == 7016
1515

1616

1717
def test_split_test_bundle():
1818
stix_splitter = OpenCTIStix2Splitter()
1919
with open("./tests/data/DATA-TEST-STIX2_v2.json") as file:
2020
content = file.read()
21-
expectations, _, bundles, _ = stix_splitter.split_bundle_with_expectations(content)
21+
expectations, _, bundles = stix_splitter.split_bundle_with_expectations(content)
2222
assert expectations == 59
2323
base_bundles = json.loads(content)["objects"]
2424
for base in base_bundles:
@@ -40,13 +40,13 @@ def test_split_mono_entity_bundle():
4040
stix_splitter = OpenCTIStix2Splitter()
4141
with open("./tests/data/mono-bundle-entity.json") as file:
4242
content = file.read()
43-
expectations, _, bundles, _ = stix_splitter.split_bundle_with_expectations(content)
43+
expectations, _, bundles = stix_splitter.split_bundle_with_expectations(content)
4444
assert expectations == 1
4545
json_bundle = json.loads(bundles[0])["objects"][0]
4646
assert json_bundle["created_by_ref"] == "fa42a846-8d90-4e51-bc29-71d5b4802168"
4747
# Split with cleanup_inconsistent_bundle
4848
stix_splitter = OpenCTIStix2Splitter()
49-
expectations, _, bundles, _ = stix_splitter.split_bundle_with_expectations(
49+
expectations, _, bundles = stix_splitter.split_bundle_with_expectations(
5050
bundle=content, cleanup_inconsistent_bundle=True
5151
)
5252
assert expectations == 1
@@ -58,11 +58,11 @@ def test_split_mono_relationship_bundle():
5858
stix_splitter = OpenCTIStix2Splitter()
5959
with open("./tests/data/mono-bundle-relationship.json") as file:
6060
content = file.read()
61-
expectations, _, bundles, _ = stix_splitter.split_bundle_with_expectations(content)
61+
expectations, _, bundles = stix_splitter.split_bundle_with_expectations(content)
6262
assert expectations == 1
6363
# Split with cleanup_inconsistent_bundle
6464
stix_splitter = OpenCTIStix2Splitter()
65-
expectations, _, bundles, _ = stix_splitter.split_bundle_with_expectations(
65+
expectations, _, bundles = stix_splitter.split_bundle_with_expectations(
6666
bundle=content, cleanup_inconsistent_bundle=True
6767
)
6868
assert expectations == 0
@@ -72,19 +72,19 @@ def test_split_capec_bundle():
7272
stix_splitter = OpenCTIStix2Splitter()
7373
with open("./tests/data/mitre_att_capec.json") as file:
7474
content = file.read()
75-
expectations, _, bundles, _ = stix_splitter.split_bundle_with_expectations(content)
75+
expectations, _, bundles = stix_splitter.split_bundle_with_expectations(content)
7676
assert expectations == 2610
7777

7878

7979
def test_split_internal_ids_bundle():
8080
stix_splitter = OpenCTIStix2Splitter()
8181
with open("./tests/data/bundle_with_internal_ids.json") as file:
8282
content = file.read()
83-
expectations, _, bundles, _ = stix_splitter.split_bundle_with_expectations(content)
83+
expectations, _, bundles = stix_splitter.split_bundle_with_expectations(content)
8484
assert expectations == 4
8585
# Split with cleanup_inconsistent_bundle
8686
stix_splitter = OpenCTIStix2Splitter()
87-
expectations, _, bundles, _ = stix_splitter.split_bundle_with_expectations(
87+
expectations, _, bundles = stix_splitter.split_bundle_with_expectations(
8888
bundle=content, cleanup_inconsistent_bundle=True
8989
)
9090
assert expectations == 4
@@ -101,11 +101,11 @@ def test_split_missing_refs_bundle():
101101
stix_splitter = OpenCTIStix2Splitter()
102102
with open("./tests/data/missing_refs.json") as file:
103103
content = file.read()
104-
expectations, _, bundles, _ = stix_splitter.split_bundle_with_expectations(content)
104+
expectations, _, bundles = stix_splitter.split_bundle_with_expectations(content)
105105
assert expectations == 4
106106
# Split with cleanup_inconsistent_bundle
107107
stix_splitter = OpenCTIStix2Splitter()
108-
expectations, _, bundles, _ = stix_splitter.split_bundle_with_expectations(
108+
expectations, _, bundles = stix_splitter.split_bundle_with_expectations(
109109
bundle=content, cleanup_inconsistent_bundle=True
110110
)
111111
assert expectations == 3
@@ -115,7 +115,7 @@ def test_split_cyclic_bundle():
115115
stix_splitter = OpenCTIStix2Splitter()
116116
with open("./tests/data/cyclic-bundle.json") as file:
117117
content = file.read()
118-
expectations, _, bundles, _ = stix_splitter.split_bundle_with_expectations(content)
118+
expectations, _, bundles = stix_splitter.split_bundle_with_expectations(content)
119119
assert expectations == 6
120120
for bundle in bundles:
121121
json_bundle = json.loads(bundle)

0 commit comments

Comments
 (0)