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

Commit d005cba

Browse files
[client] Allow internal id in the split (#741)
1 parent 2082b5f commit d005cba

File tree

4 files changed

+100
-4
lines changed

4 files changed

+100
-4
lines changed

pycti/utils/opencti_stix2_splitter.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
SUPPORTED_STIX_ENTITY_OBJECTS,
1414
)
1515

16+
OPENCTI_EXTENSION = "extension-definition--ea279b3e-5c71-4632-ac08-831c66a786ba"
17+
1618
supported_types = (
1719
SUPPORTED_STIX_ENTITY_OBJECTS # entities
1820
+ list(STIX_CYBER_OBSERVABLE_MAPPING.keys()) # observables
@@ -21,8 +23,11 @@
2123

2224

2325
def is_id_supported(key):
24-
id_type = key.split("--")[0]
25-
return id_type in supported_types
26+
if "--" in key:
27+
id_type = key.split("--")[0]
28+
return id_type in supported_types
29+
# If not a stix id, don't try to filter
30+
return True
2631

2732

2833
class OpenCTIStix2Splitter:
@@ -31,6 +36,18 @@ def __init__(self):
3136
self.cache_refs = {}
3237
self.elements = []
3338

39+
def get_internal_ids_in_extension(self, item):
40+
ids = []
41+
if item.get("x_opencti_id"):
42+
ids.append(item["x_opencti_id"])
43+
if (
44+
item.get("extensions")
45+
and item["extensions"].get(OPENCTI_EXTENSION)
46+
and item["extensions"].get(OPENCTI_EXTENSION).get("id")
47+
):
48+
ids.append(item["extensions"][OPENCTI_EXTENSION]["id"])
49+
return ids
50+
3451
def enlist_element(
3552
self, item_id, raw_data, cleanup_inconsistent_bundle, parent_acc
3653
):
@@ -173,6 +190,8 @@ def enlist_element(
173190
if is_compatible:
174191
self.elements.append(item)
175192
self.cache_index[item_id] = item
193+
for internal_id in self.get_internal_ids_in_extension(item):
194+
self.cache_index[internal_id] = item
176195

177196
return nb_deps
178197

@@ -202,6 +221,8 @@ def split_bundle_with_expectations(
202221
# Build flat list of elements
203222
for item in bundle_data["objects"]:
204223
raw_data[item["id"]] = item
224+
for internal_id in self.get_internal_ids_in_extension(item):
225+
raw_data[internal_id] = item
205226
for item in bundle_data["objects"]:
206227
self.enlist_element(item["id"], raw_data, cleanup_inconsistent_bundle, [])
207228

tests/01-unit/utils/test_opencti_stix2_splitter.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def test_split_mono_entity_bundle():
4343
expectations, bundles = stix_splitter.split_bundle_with_expectations(content)
4444
assert expectations == 1
4545
json_bundle = json.loads(bundles[0])["objects"][0]
46-
assert json_bundle["created_by_ref"] == "identity--not-available"
46+
assert json_bundle["created_by_ref"] == "fa42a846-8d90-4e51-bc29-71d5b4802168"
4747
# Split with cleanup_inconsistent_bundle
4848
stix_splitter = OpenCTIStix2Splitter()
4949
expectations, bundles = stix_splitter.split_bundle_with_expectations(
@@ -76,6 +76,27 @@ def test_split_capec_bundle():
7676
assert expectations == 2610
7777

7878

79+
def test_split_internal_ids_bundle():
80+
stix_splitter = OpenCTIStix2Splitter()
81+
with open("./tests/data/bundle_with_internal_ids.json") as file:
82+
content = file.read()
83+
expectations, bundles = stix_splitter.split_bundle_with_expectations(content)
84+
assert expectations == 4
85+
# Split with cleanup_inconsistent_bundle
86+
stix_splitter = OpenCTIStix2Splitter()
87+
expectations, bundles = stix_splitter.split_bundle_with_expectations(
88+
bundle=content, cleanup_inconsistent_bundle=True
89+
)
90+
assert expectations == 4
91+
for bundle in bundles:
92+
json_bundle = json.loads(bundle)
93+
object_json = json_bundle["objects"][0]
94+
if object_json["id"] == "relationship--10e8c71d-a1b4-4e35-bca8-2e4a3785ea04":
95+
assert (
96+
object_json["created_by_ref"] == "ced3e53e-9663-4c96-9c60-07d2e778d931"
97+
)
98+
99+
79100
def test_split_missing_refs_bundle():
80101
stix_splitter = OpenCTIStix2Splitter()
81102
with open("./tests/data/missing_refs.json") as file:
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"type": "bundle",
3+
"id": "bundle--8c939929-688f-4a72-badb-3dd1bd6af0fa",
4+
"objects": [
5+
{
6+
"id": "identity--67ffc076-1fba-5164-9df5-b7523092931e",
7+
"spec_version": "2.1",
8+
"type": "identity",
9+
"extensions": {
10+
"extension-definition--ea279b3e-5c71-4632-ac08-831c66a786ba": {
11+
"extension_type": "property-extension",
12+
"id": "ced3e53e-9663-4c96-9c60-07d2e778d931",
13+
"type": "Organization",
14+
"created_at": "2024-09-26T17:36:32.107Z",
15+
"updated_at": "2024-09-26T17:36:32.107Z",
16+
"is_inferred": false,
17+
"creator_ids": [
18+
"88ec0c6a-13ce-5e39-b486-354fe4a7084f"
19+
]
20+
}
21+
},
22+
"created": "2024-09-26T17:36:32.107Z",
23+
"modified": "2024-09-26T17:36:32.107Z",
24+
"revoked": false,
25+
"confidence": 100,
26+
"lang": "en",
27+
"name": "JRI",
28+
"identity_class": "organization"
29+
},
30+
{
31+
"id": "malware--faa5b705-cf44-4e50-8472-29e5fec43c3c",
32+
"type": "malware",
33+
"name": "malware 01",
34+
"created": "2019-09-30T16:38:26.000Z",
35+
"modified": "2020-01-14T14:01:48.288Z",
36+
"x_opencti_id": "82316ffd-a0ec-4519-a454-6566f8f5676c"
37+
},
38+
{
39+
"id": "malware--faa5b705-cf44-4e50-8472-29e5fec43c3d",
40+
"type": "malware",
41+
"name": "malware 02",
42+
"created": "2019-09-30T16:38:26.000Z",
43+
"modified": "2020-01-14T14:01:48.288Z"
44+
},
45+
{
46+
"id": "relationship--10e8c71d-a1b4-4e35-bca8-2e4a3785ea04",
47+
"type": "relationship",
48+
"relationship_type": "part-of",
49+
"created_by_ref": "ced3e53e-9663-4c96-9c60-07d2e778d931",
50+
"source_ref": "82316ffd-a0ec-4519-a454-6566f8f5676c",
51+
"target_ref": "malware--faa5b705-cf44-4e50-8472-29e5fec43c3d"
52+
}
53+
]
54+
}

tests/data/mono-bundle-entity.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
{
55
"id": "marking-definition--fa42a846-8d90-4e51-bc29-71d5b4802168",
66
"created": "2017-06-01T00:00:00.000Z",
7-
"created_by_ref": "identity--not-available",
7+
"created_by_ref": "fa42a846-8d90-4e51-bc29-71d5b4802168",
88
"definition": {
99
"statement": "Copyright 2015-2024, The MITRE Corporation. MITRE ATT&CK and ATT&CK are registered trademarks of The MITRE Corporation."
1010
},

0 commit comments

Comments
 (0)