From d5a129343d97dd5af8b80295bd7a74db67678de0 Mon Sep 17 00:00:00 2001 From: Landry Trebon Date: Thu, 15 May 2025 15:28:02 +0200 Subject: [PATCH 01/12] [client-python] WIP PIR api --- pycti/api/opencti_api_client.py | 2 ++ pycti/api/opencti_api_pir.py | 37 +++++++++++++++++++++++++++++++++ pycti/utils/opencti_stix2.py | 8 +++++++ 3 files changed, 47 insertions(+) create mode 100644 pycti/api/opencti_api_pir.py diff --git a/pycti/api/opencti_api_client.py b/pycti/api/opencti_api_client.py index bbde7d68..553328de 100644 --- a/pycti/api/opencti_api_client.py +++ b/pycti/api/opencti_api_client.py @@ -9,6 +9,7 @@ import requests from pycti import __version__ +from pycti.api.opencti_api_pir import OpenCTIApiPir from pycti.api.opencti_api_connector import OpenCTIApiConnector from pycti.api.opencti_api_playbook import OpenCTIApiPlaybook from pycti.api.opencti_api_work import OpenCTIApiWork @@ -170,6 +171,7 @@ def __init__( self.playbook = OpenCTIApiPlaybook(self) self.connector = OpenCTIApiConnector(self) self.stix2 = OpenCTIStix2(self) + self.pir = OpenCTIApiPir(self) # Define the entities self.vocabulary = Vocabulary(self) diff --git a/pycti/api/opencti_api_pir.py b/pycti/api/opencti_api_pir.py new file mode 100644 index 00000000..8b754a2b --- /dev/null +++ b/pycti/api/opencti_api_pir.py @@ -0,0 +1,37 @@ +class OpenCTIApiPir: + """OpenCTIApiPir""" + + def __init__(self, api): + self.api = api + + def add_pir_dependency(self, **kwargs): + id = kwargs.get("id", None) + input = kwargs.get("input", None) + query = """ + mutation PirAddDependency($id: ID!, $input: PirAddDependencyInput!) { + pirAddDependency(id: $id, input: $input) + } + """ + self.api.query( + query, + { + "id": id, + "input": input, + }, + ) + + def delete_pir_dependency(self, **kwargs): + id = kwargs.get("id", None) + input = kwargs.get("input", None) + query = """ + mutation PirDeleteDependency($id: ID!, $input: PirDeleteDependencyInput!) { + pirDeleteDependency(id: $id, input: $input) + } + """ + self.api.query( + query, + { + "id": id, + "input": input, + }, + ) \ No newline at end of file diff --git a/pycti/utils/opencti_stix2.py b/pycti/utils/opencti_stix2.py index a303844c..f4d1d82a 100644 --- a/pycti/utils/opencti_stix2.py +++ b/pycti/utils/opencti_stix2.py @@ -2484,6 +2484,14 @@ def apply_opencti_operation(self, item, operation): self.opencti.stix.merge(id=target_id, object_ids=source_ids) elif operation == "patch": self.apply_patch(item=item) + elif operation == "add_pir_dependency": + id = item["id"] + input = item["input"] + self.opencti.pir.add_pir_dependency(id=id, input=input) + elif operation == "delete_pir_dependency": + id = item["id"] + input = item["input"] + self.opencti.pir.delete_pir_dependency(id=id, input=input) else: raise ValueError("Not supported opencti_operation") From b25ea26c5a315fc1082ac08a40b1ee60264cd0a1 Mon Sep 17 00:00:00 2001 From: Cathia Archidoit Date: Thu, 15 May 2025 17:02:05 +0200 Subject: [PATCH 02/12] [client & backend] DEBUG LOGS --- pycti/utils/opencti_stix2.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pycti/utils/opencti_stix2.py b/pycti/utils/opencti_stix2.py index f4d1d82a..a8d7ea4d 100644 --- a/pycti/utils/opencti_stix2.py +++ b/pycti/utils/opencti_stix2.py @@ -2475,6 +2475,7 @@ def apply_patch(self, item): self.apply_patch_files(item) def apply_opencti_operation(self, item, operation): + self.opencti.app_logger.info("-- apply_opencti_opeartion --") if operation == "delete": delete_id = item["id"] self.opencti.stix.delete(id=delete_id) @@ -2485,6 +2486,7 @@ def apply_opencti_operation(self, item, operation): elif operation == "patch": self.apply_patch(item=item) elif operation == "add_pir_dependency": + self.opencti.app_logger.info("add_pir_dependency operation !!") id = item["id"] input = item["input"] self.opencti.pir.add_pir_dependency(id=id, input=input) @@ -2504,6 +2506,7 @@ def import_item( work_id: str = None, ): worker_logger = self.opencti.logger_class("worker") + self.opencti.app_logger.info("------import item----------") # Ultimate protection to avoid infinite retry if processing_count > MAX_PROCESSING_COUNT: if work_id is not None: @@ -2744,6 +2747,7 @@ def import_bundle( types: List = None, work_id: str = None, ) -> List: + self.opencti.app_logger.info("---import bundle------") # Check if the bundle is correctly formatted if "type" not in stix_bundle or stix_bundle["type"] != "bundle": raise ValueError("JSON data type is not a STIX2 bundle") @@ -2759,10 +2763,13 @@ def import_bundle( _, bundles = stix2_splitter.split_bundle_with_expectations( stix_bundle, False, event_version ) - # Import every element in a specific order + self.opencti.app_logger.info("---import bundle after splitter------", { "bundles": json.dumps(bundles) }) + # Import every element in a specific order imported_elements = [] for bundle in bundles: + self.opencti.app_logger.info("---bundle------") for item in bundle["objects"]: + self.opencti.app_logger.info("---item------", { "item": item["id"] }) self.import_item(item, update, types, 0, work_id) imported_elements.append({"id": item["id"], "type": item["type"]}) From 4527e3e9698310a922a201015860f8c95acbef13 Mon Sep 17 00:00:00 2001 From: Souad Hadjiat Date: Thu, 15 May 2025 17:59:45 +0200 Subject: [PATCH 03/12] [backend] add pir to supported types --- pycti/utils/opencti_stix2_splitter.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pycti/utils/opencti_stix2_splitter.py b/pycti/utils/opencti_stix2_splitter.py index 10a65590..5cc074c7 100644 --- a/pycti/utils/opencti_stix2_splitter.py +++ b/pycti/utils/opencti_stix2_splitter.py @@ -19,6 +19,7 @@ SUPPORTED_STIX_ENTITY_OBJECTS # entities + list(STIX_CYBER_OBSERVABLE_MAPPING.keys()) # observables + ["relationship", "sighting"] # relationships + + ["pir"] ) From e4e48f98fb4a7bfcca2c892e5d9bf81901c70818 Mon Sep 17 00:00:00 2001 From: Cathia Archidoit Date: Fri, 16 May 2025 09:18:29 +0200 Subject: [PATCH 04/12] [client] fix --- pycti/api/opencti_api_pir.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pycti/api/opencti_api_pir.py b/pycti/api/opencti_api_pir.py index 8b754a2b..3472f755 100644 --- a/pycti/api/opencti_api_pir.py +++ b/pycti/api/opencti_api_pir.py @@ -8,7 +8,7 @@ def add_pir_dependency(self, **kwargs): id = kwargs.get("id", None) input = kwargs.get("input", None) query = """ - mutation PirAddDependency($id: ID!, $input: PirAddDependencyInput!) { + mutation PirAddDependency($id: ID!, $input: PirDependencyAddInput!) { pirAddDependency(id: $id, input: $input) } """ From f04f5384668d02f0b820dee21a6b2e13ab5062a3 Mon Sep 17 00:00:00 2001 From: Landry Trebon Date: Fri, 16 May 2025 09:32:25 +0200 Subject: [PATCH 05/12] [client-python] remove logs --- pycti/utils/opencti_stix2.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/pycti/utils/opencti_stix2.py b/pycti/utils/opencti_stix2.py index a8d7ea4d..eb0d5c96 100644 --- a/pycti/utils/opencti_stix2.py +++ b/pycti/utils/opencti_stix2.py @@ -2475,7 +2475,6 @@ def apply_patch(self, item): self.apply_patch_files(item) def apply_opencti_operation(self, item, operation): - self.opencti.app_logger.info("-- apply_opencti_opeartion --") if operation == "delete": delete_id = item["id"] self.opencti.stix.delete(id=delete_id) @@ -2486,7 +2485,6 @@ def apply_opencti_operation(self, item, operation): elif operation == "patch": self.apply_patch(item=item) elif operation == "add_pir_dependency": - self.opencti.app_logger.info("add_pir_dependency operation !!") id = item["id"] input = item["input"] self.opencti.pir.add_pir_dependency(id=id, input=input) @@ -2506,7 +2504,6 @@ def import_item( work_id: str = None, ): worker_logger = self.opencti.logger_class("worker") - self.opencti.app_logger.info("------import item----------") # Ultimate protection to avoid infinite retry if processing_count > MAX_PROCESSING_COUNT: if work_id is not None: @@ -2747,7 +2744,6 @@ def import_bundle( types: List = None, work_id: str = None, ) -> List: - self.opencti.app_logger.info("---import bundle------") # Check if the bundle is correctly formatted if "type" not in stix_bundle or stix_bundle["type"] != "bundle": raise ValueError("JSON data type is not a STIX2 bundle") @@ -2763,13 +2759,10 @@ def import_bundle( _, bundles = stix2_splitter.split_bundle_with_expectations( stix_bundle, False, event_version ) - self.opencti.app_logger.info("---import bundle after splitter------", { "bundles": json.dumps(bundles) }) # Import every element in a specific order imported_elements = [] for bundle in bundles: - self.opencti.app_logger.info("---bundle------") for item in bundle["objects"]: - self.opencti.app_logger.info("---item------", { "item": item["id"] }) self.import_item(item, update, types, 0, work_id) imported_elements.append({"id": item["id"], "type": item["type"]}) From 4230dea33c66f1c1638c4e21f6ab5cf15f2b186c Mon Sep 17 00:00:00 2001 From: Landry Trebon Date: Fri, 16 May 2025 09:34:33 +0200 Subject: [PATCH 06/12] [client-python] tab --- pycti/utils/opencti_stix2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pycti/utils/opencti_stix2.py b/pycti/utils/opencti_stix2.py index eb0d5c96..f4d1d82a 100644 --- a/pycti/utils/opencti_stix2.py +++ b/pycti/utils/opencti_stix2.py @@ -2759,7 +2759,7 @@ def import_bundle( _, bundles = stix2_splitter.split_bundle_with_expectations( stix_bundle, False, event_version ) - # Import every element in a specific order + # Import every element in a specific order imported_elements = [] for bundle in bundles: for item in bundle["objects"]: From f27eb32515eb956ab1ca19dbba5f79ecd2fb07ec Mon Sep 17 00:00:00 2001 From: Cathia Archidoit Date: Fri, 16 May 2025 10:34:40 +0200 Subject: [PATCH 07/12] [client] fix --- pycti/api/opencti_api_pir.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pycti/api/opencti_api_pir.py b/pycti/api/opencti_api_pir.py index 3472f755..b7276561 100644 --- a/pycti/api/opencti_api_pir.py +++ b/pycti/api/opencti_api_pir.py @@ -8,7 +8,7 @@ def add_pir_dependency(self, **kwargs): id = kwargs.get("id", None) input = kwargs.get("input", None) query = """ - mutation PirAddDependency($id: ID!, $input: PirDependencyAddInput!) { + mutation PirAddDependency($id: ID!, $input: PIRDependencyAddInput!) { pirAddDependency(id: $id, input: $input) } """ From d43642fc257aaa68693c7f22b0df71613a4f4d43 Mon Sep 17 00:00:00 2001 From: Landry Trebon Date: Fri, 16 May 2025 11:21:57 +0200 Subject: [PATCH 08/12] [client] sort import --- pycti/api/opencti_api_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pycti/api/opencti_api_client.py b/pycti/api/opencti_api_client.py index 553328de..ee0b2a44 100644 --- a/pycti/api/opencti_api_client.py +++ b/pycti/api/opencti_api_client.py @@ -9,8 +9,8 @@ import requests from pycti import __version__ -from pycti.api.opencti_api_pir import OpenCTIApiPir from pycti.api.opencti_api_connector import OpenCTIApiConnector +from pycti.api.opencti_api_pir import OpenCTIApiPir from pycti.api.opencti_api_playbook import OpenCTIApiPlaybook from pycti.api.opencti_api_work import OpenCTIApiWork from pycti.entities.opencti_attack_pattern import AttackPattern From 54b21d8a3e9e518acb1e06f4be3e4b8edb08575b Mon Sep 17 00:00:00 2001 From: Landry Trebon Date: Fri, 16 May 2025 11:30:25 +0200 Subject: [PATCH 09/12] [client] fix format --- pycti/api/opencti_api_pir.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pycti/api/opencti_api_pir.py b/pycti/api/opencti_api_pir.py index b7276561..1c6b9fab 100644 --- a/pycti/api/opencti_api_pir.py +++ b/pycti/api/opencti_api_pir.py @@ -34,4 +34,4 @@ def delete_pir_dependency(self, **kwargs): "id": id, "input": input, }, - ) \ No newline at end of file + ) From 96a2302f2df93ef6f40c4ca04888b2672ea7c068 Mon Sep 17 00:00:00 2001 From: Cathia Archidoit Date: Mon, 19 May 2025 16:53:18 +0200 Subject: [PATCH 10/12] [backend] delete pir dependency input typo --- pycti/api/opencti_api_pir.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pycti/api/opencti_api_pir.py b/pycti/api/opencti_api_pir.py index 1c6b9fab..39437742 100644 --- a/pycti/api/opencti_api_pir.py +++ b/pycti/api/opencti_api_pir.py @@ -24,7 +24,7 @@ def delete_pir_dependency(self, **kwargs): id = kwargs.get("id", None) input = kwargs.get("input", None) query = """ - mutation PirDeleteDependency($id: ID!, $input: PirDeleteDependencyInput!) { + mutation PirDeleteDependency($id: ID!, $input: PIRDependencyDeleteInput!) { pirDeleteDependency(id: $id, input: $input) } """ From c5b431feca3b7246774f9a843aa22a7abaa75079 Mon Sep 17 00:00:00 2001 From: Cathia Archidoit Date: Tue, 20 May 2025 16:55:15 +0200 Subject: [PATCH 11/12] [frontend/backend] PIR -> Pir --- pycti/api/opencti_api_pir.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pycti/api/opencti_api_pir.py b/pycti/api/opencti_api_pir.py index 39437742..11ea4c77 100644 --- a/pycti/api/opencti_api_pir.py +++ b/pycti/api/opencti_api_pir.py @@ -8,7 +8,7 @@ def add_pir_dependency(self, **kwargs): id = kwargs.get("id", None) input = kwargs.get("input", None) query = """ - mutation PirAddDependency($id: ID!, $input: PIRDependencyAddInput!) { + mutation PirAddDependency($id: ID!, $input: PirDependencyAddInput!) { pirAddDependency(id: $id, input: $input) } """ @@ -24,7 +24,7 @@ def delete_pir_dependency(self, **kwargs): id = kwargs.get("id", None) input = kwargs.get("input", None) query = """ - mutation PirDeleteDependency($id: ID!, $input: PIRDependencyDeleteInput!) { + mutation PirDeleteDependency($id: ID!, $input: PirDependencyDeleteInput!) { pirDeleteDependency(id: $id, input: $input) } """ From 08cebbf86df1357ee2c020e749600d25067e37f5 Mon Sep 17 00:00:00 2001 From: Landry Trebon Date: Thu, 22 May 2025 14:17:35 +0200 Subject: [PATCH 12/12] [backend/client] renaming --- pycti/api/opencti_api_pir.py | 12 ++++++------ pycti/utils/opencti_stix2.py | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pycti/api/opencti_api_pir.py b/pycti/api/opencti_api_pir.py index 11ea4c77..b3554e87 100644 --- a/pycti/api/opencti_api_pir.py +++ b/pycti/api/opencti_api_pir.py @@ -4,12 +4,12 @@ class OpenCTIApiPir: def __init__(self, api): self.api = api - def add_pir_dependency(self, **kwargs): + def pir_flag_element(self, **kwargs): id = kwargs.get("id", None) input = kwargs.get("input", None) query = """ - mutation PirAddDependency($id: ID!, $input: PirDependencyAddInput!) { - pirAddDependency(id: $id, input: $input) + mutation PirFlagElement($id: ID!, $input: PirFlagElementInput!) { + pirFlagElement(id: $id, input: $input) } """ self.api.query( @@ -20,12 +20,12 @@ def add_pir_dependency(self, **kwargs): }, ) - def delete_pir_dependency(self, **kwargs): + def pir_unflag_element(self, **kwargs): id = kwargs.get("id", None) input = kwargs.get("input", None) query = """ - mutation PirDeleteDependency($id: ID!, $input: PirDependencyDeleteInput!) { - pirDeleteDependency(id: $id, input: $input) + mutation PirUnflagElement($id: ID!, $input: PirUnflagElementInput!) { + pirUnflagElement(id: $id, input: $input) } """ self.api.query( diff --git a/pycti/utils/opencti_stix2.py b/pycti/utils/opencti_stix2.py index f4d1d82a..45483787 100644 --- a/pycti/utils/opencti_stix2.py +++ b/pycti/utils/opencti_stix2.py @@ -2484,14 +2484,14 @@ def apply_opencti_operation(self, item, operation): self.opencti.stix.merge(id=target_id, object_ids=source_ids) elif operation == "patch": self.apply_patch(item=item) - elif operation == "add_pir_dependency": + elif operation == "pir_flag_element": id = item["id"] input = item["input"] - self.opencti.pir.add_pir_dependency(id=id, input=input) - elif operation == "delete_pir_dependency": + self.opencti.pir.pir_flag_element(id=id, input=input) + elif operation == "pir_unflag_element": id = item["id"] input = item["input"] - self.opencti.pir.delete_pir_dependency(id=id, input=input) + self.opencti.pir.pir_unflag_element(id=id, input=input) else: raise ValueError("Not supported opencti_operation")