pycti 6.7.20__py3-none-any.whl → 6.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pycti might be problematic. Click here for more details.

Files changed (54) hide show
  1. pycti/__init__.py +1 -1
  2. pycti/connector/opencti_connector_helper.py +190 -3
  3. pycti/connector/opencti_metric_handler.py +44 -15
  4. pycti/entities/opencti_attack_pattern.py +32 -6
  5. pycti/entities/opencti_campaign.py +30 -6
  6. pycti/entities/opencti_case_incident.py +7 -0
  7. pycti/entities/opencti_case_rfi.py +7 -0
  8. pycti/entities/opencti_case_rft.py +7 -0
  9. pycti/entities/opencti_channel.py +7 -0
  10. pycti/entities/opencti_course_of_action.py +7 -0
  11. pycti/entities/opencti_data_component.py +7 -0
  12. pycti/entities/opencti_data_source.py +7 -0
  13. pycti/entities/opencti_event.py +32 -6
  14. pycti/entities/opencti_external_reference.py +8 -0
  15. pycti/entities/opencti_feedback.py +7 -0
  16. pycti/entities/opencti_grouping.py +7 -0
  17. pycti/entities/opencti_identity.py +34 -6
  18. pycti/entities/opencti_incident.py +7 -0
  19. pycti/entities/opencti_indicator.py +19 -5
  20. pycti/entities/opencti_intrusion_set.py +58 -19
  21. pycti/entities/opencti_kill_chain_phase.py +7 -0
  22. pycti/entities/opencti_label.py +7 -0
  23. pycti/entities/opencti_language.py +7 -0
  24. pycti/entities/opencti_location.py +7 -0
  25. pycti/entities/opencti_malware.py +60 -18
  26. pycti/entities/opencti_malware_analysis.py +7 -0
  27. pycti/entities/opencti_marking_definition.py +7 -0
  28. pycti/entities/opencti_narrative.py +7 -0
  29. pycti/entities/opencti_note.py +7 -0
  30. pycti/entities/opencti_observed_data.py +7 -0
  31. pycti/entities/opencti_opinion.py +7 -0
  32. pycti/entities/opencti_report.py +7 -0
  33. pycti/entities/opencti_stix.py +7 -0
  34. pycti/entities/opencti_stix_core_object.py +8 -0
  35. pycti/entities/opencti_stix_core_relationship.py +7 -0
  36. pycti/entities/opencti_stix_cyber_observable.py +9 -0
  37. pycti/entities/opencti_stix_domain_object.py +8 -0
  38. pycti/entities/opencti_stix_nested_ref_relationship.py +7 -0
  39. pycti/entities/opencti_stix_object_or_stix_relationship.py +7 -0
  40. pycti/entities/opencti_stix_sighting_relationship.py +7 -0
  41. pycti/entities/opencti_task.py +7 -0
  42. pycti/entities/opencti_tool.py +52 -18
  43. pycti/entities/opencti_vocabulary.py +7 -0
  44. pycti/entities/opencti_vulnerability.py +7 -0
  45. pycti/utils/opencti_logger.py +57 -0
  46. pycti/utils/opencti_stix2.py +41 -0
  47. pycti/utils/opencti_stix2_splitter.py +5 -0
  48. pycti/utils/opencti_stix2_utils.py +41 -6
  49. {pycti-6.7.20.dist-info → pycti-6.8.0.dist-info}/METADATA +1 -1
  50. pycti-6.8.0.dist-info/RECORD +86 -0
  51. pycti-6.7.20.dist-info/RECORD +0 -86
  52. {pycti-6.7.20.dist-info → pycti-6.8.0.dist-info}/WHEEL +0 -0
  53. {pycti-6.7.20.dist-info → pycti-6.8.0.dist-info}/licenses/LICENSE +0 -0
  54. {pycti-6.7.20.dist-info → pycti-6.8.0.dist-info}/top_level.txt +0 -0
pycti/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
- __version__ = "6.7.20"
2
+ __version__ = "6.8.0"
3
3
 
4
4
  from .api.opencti_api_client import OpenCTIApiClient
5
5
  from .api.opencti_api_connector import OpenCTIApiConnector
@@ -37,10 +37,21 @@ app = FastAPI()
37
37
 
38
38
 
39
39
  def killProgramHook(etype, value, tb):
40
+ """Exception hook to terminate the program.
41
+
42
+ :param etype: Exception type
43
+ :param value: Exception value
44
+ :param tb: Traceback object
45
+ """
40
46
  os.kill(os.getpid(), signal.SIGTERM)
41
47
 
42
48
 
43
49
  def start_loop(loop):
50
+ """Start an asyncio event loop.
51
+
52
+ :param loop: The asyncio event loop to start
53
+ :type loop: asyncio.AbstractEventLoop
54
+ """
44
55
  asyncio.set_event_loop(loop)
45
56
  loop.run_forever()
46
57
 
@@ -93,10 +104,24 @@ def get_config_variable(
93
104
 
94
105
 
95
106
  def is_memory_certificate(certificate):
107
+ """Check if a certificate is provided as a PEM string in memory.
108
+
109
+ :param certificate: The certificate data to check
110
+ :type certificate: str
111
+ :return: True if the certificate is a PEM string, False otherwise
112
+ :rtype: bool
113
+ """
96
114
  return certificate.startswith("-----BEGIN")
97
115
 
98
116
 
99
117
  def ssl_verify_locations(ssl_context, certdata):
118
+ """Load certificate verification locations into SSL context.
119
+
120
+ :param ssl_context: The SSL context to configure
121
+ :type ssl_context: ssl.SSLContext
122
+ :param certdata: Certificate data (file path or PEM string)
123
+ :type certdata: str or None
124
+ """
100
125
  if certdata is None:
101
126
  return
102
127
 
@@ -106,9 +131,17 @@ def ssl_verify_locations(ssl_context, certdata):
106
131
  ssl_context.load_verify_locations(cafile=certdata)
107
132
 
108
133
 
109
- # As cert must be written in files to be loaded in ssl context
110
- # Creates a temporary file in the most secure manner possible
111
134
  def data_to_temp_file(data):
135
+ """Write data to a temporary file securely.
136
+
137
+ Creates a temporary file in the most secure manner possible.
138
+ The file is readable and writable only by the creating user ID.
139
+
140
+ :param data: The data to write to the temporary file
141
+ :type data: str
142
+ :return: Path to the created temporary file
143
+ :rtype: str
144
+ """
112
145
  # The file is readable and writable only by the creating user ID.
113
146
  # If the operating system uses permission bits to indicate whether a
114
147
  # file is executable, the file is executable by no one. The file
@@ -121,6 +154,17 @@ def data_to_temp_file(data):
121
154
 
122
155
 
123
156
  def ssl_cert_chain(ssl_context, cert_data, key_data, passphrase):
157
+ """Load certificate chain into SSL context.
158
+
159
+ :param ssl_context: The SSL context to configure
160
+ :type ssl_context: ssl.SSLContext
161
+ :param cert_data: Certificate data (file path or PEM string)
162
+ :type cert_data: str or None
163
+ :param key_data: Private key data (file path or PEM string)
164
+ :type key_data: str or None
165
+ :param passphrase: Passphrase for the private key
166
+ :type passphrase: str or None
167
+ """
124
168
  if cert_data is None:
125
169
  return
126
170
 
@@ -147,6 +191,13 @@ def ssl_cert_chain(ssl_context, cert_data, key_data, passphrase):
147
191
 
148
192
 
149
193
  def create_callback_ssl_context(config) -> ssl.SSLContext:
194
+ """Create SSL context for API callback server.
195
+
196
+ :param config: Configuration dictionary
197
+ :type config: dict
198
+ :return: Configured SSL context
199
+ :rtype: ssl.SSLContext
200
+ """
150
201
  listen_protocol_api_ssl_key = get_config_variable(
151
202
  "LISTEN_PROTOCOL_API_SSL_KEY",
152
203
  ["connector", "listen_protocol_api_ssl_key"],
@@ -176,6 +227,13 @@ def create_callback_ssl_context(config) -> ssl.SSLContext:
176
227
 
177
228
 
178
229
  def create_mq_ssl_context(config) -> ssl.SSLContext:
230
+ """Create SSL context for message queue connections.
231
+
232
+ :param config: Configuration dictionary
233
+ :type config: dict
234
+ :return: Configured SSL context for MQ connections
235
+ :rtype: ssl.SSLContext
236
+ """
179
237
  use_ssl_ca = get_config_variable("MQ_USE_SSL_CA", ["mq", "use_ssl_ca"], config)
180
238
  use_ssl_cert = get_config_variable(
181
239
  "MQ_USE_SSL_CERT", ["mq", "use_ssl_cert"], config
@@ -292,6 +350,11 @@ class ListenQueue(threading.Thread):
292
350
  )
293
351
 
294
352
  def _set_draft_id(self, draft_id):
353
+ """Set the draft ID for the helper and API instances.
354
+
355
+ :param draft_id: The draft ID to set
356
+ :type draft_id: str
357
+ """
295
358
  self.helper.draft_id = draft_id
296
359
  self.helper.api.set_draft_id(draft_id)
297
360
  self.helper.api_impersonate.set_draft_id(draft_id)
@@ -546,6 +609,11 @@ class ListenQueue(threading.Thread):
546
609
  raise ValueError("Unsupported listen protocol type")
547
610
 
548
611
  def stop(self):
612
+ """Stop the ListenQueue thread and close connections.
613
+
614
+ This method sets the exit event, closes the RabbitMQ connection,
615
+ and waits for the processing thread to complete.
616
+ """
549
617
  self.helper.connector_logger.info("Preparing ListenQueue for clean shutdown")
550
618
  self.exit_event.set()
551
619
  self.pika_connection.close()
@@ -794,6 +862,10 @@ class ListenStream(threading.Thread):
794
862
  sys.excepthook(*sys.exc_info())
795
863
 
796
864
  def stop(self):
865
+ """Stop the ListenStream thread.
866
+
867
+ This method sets the exit event to signal the stream listening thread to stop.
868
+ """
797
869
  self.helper.connector_logger.info("Preparing ListenStream for clean shutdown")
798
870
  self.exit_event.set()
799
871
 
@@ -817,6 +889,11 @@ class ConnectorInfo:
817
889
 
818
890
  @property
819
891
  def all_details(self):
892
+ """Get all connector information details as a dictionary.
893
+
894
+ :return: Dictionary containing all connector status information
895
+ :rtype: dict
896
+ """
820
897
  return {
821
898
  "run_and_terminate": self._run_and_terminate,
822
899
  "buffering": self._buffering,
@@ -832,6 +909,11 @@ class ConnectorInfo:
832
909
 
833
910
  @run_and_terminate.setter
834
911
  def run_and_terminate(self, value):
912
+ """Set the run_and_terminate flag.
913
+
914
+ :param value: Whether the connector should run once and terminate
915
+ :type value: bool
916
+ """
835
917
  self._run_and_terminate = value
836
918
 
837
919
  @property
@@ -840,6 +922,11 @@ class ConnectorInfo:
840
922
 
841
923
  @buffering.setter
842
924
  def buffering(self, value):
925
+ """Set the buffering status.
926
+
927
+ :param value: Whether the connector is currently buffering
928
+ :type value: bool
929
+ """
843
930
  self._buffering = value
844
931
 
845
932
  @property
@@ -848,6 +935,11 @@ class ConnectorInfo:
848
935
 
849
936
  @queue_threshold.setter
850
937
  def queue_threshold(self, value):
938
+ """Set the queue threshold value.
939
+
940
+ :param value: The queue size threshold in MB
941
+ :type value: float
942
+ """
851
943
  self._queue_threshold = value
852
944
 
853
945
  @property
@@ -856,6 +948,11 @@ class ConnectorInfo:
856
948
 
857
949
  @queue_messages_size.setter
858
950
  def queue_messages_size(self, value):
951
+ """Set the current queue messages size.
952
+
953
+ :param value: The current size of messages in the queue in MB
954
+ :type value: float
955
+ """
859
956
  self._queue_messages_size = value
860
957
 
861
958
  @property
@@ -864,6 +961,11 @@ class ConnectorInfo:
864
961
 
865
962
  @next_run_datetime.setter
866
963
  def next_run_datetime(self, value):
964
+ """Set the next scheduled run datetime.
965
+
966
+ :param value: The datetime for the next scheduled run
967
+ :type value: datetime
968
+ """
867
969
  self._next_run_datetime = value
868
970
 
869
971
  @property
@@ -872,6 +974,11 @@ class ConnectorInfo:
872
974
 
873
975
  @last_run_datetime.setter
874
976
  def last_run_datetime(self, value):
977
+ """Set the last run datetime.
978
+
979
+ :param value: The datetime of the last run
980
+ :type value: datetime
981
+ """
875
982
  self._last_run_datetime = value
876
983
 
877
984
 
@@ -1062,6 +1169,20 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
1062
1169
  config,
1063
1170
  default=False,
1064
1171
  )
1172
+ metrics_namespace = get_config_variable(
1173
+ "CONNECTOR_METRICS_NAMESPACE",
1174
+ ["connector", "metrics_namespace"],
1175
+ config,
1176
+ False,
1177
+ "",
1178
+ )
1179
+ metrics_subsystem = get_config_variable(
1180
+ "CONNECTOR_METRICS_SUBSYSTEM",
1181
+ ["connector", "metrics_subsystem"],
1182
+ config,
1183
+ False,
1184
+ "",
1185
+ )
1065
1186
  metrics_port = get_config_variable(
1066
1187
  "CONNECTOR_METRICS_PORT",
1067
1188
  ["connector", "metrics_port"],
@@ -1102,7 +1223,11 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
1102
1223
  # For retro compatibility
1103
1224
 
1104
1225
  self.metric = OpenCTIMetricHandler(
1105
- self.connector_logger, expose_metrics, metrics_port
1226
+ self.connector_logger,
1227
+ expose_metrics,
1228
+ metrics_namespace,
1229
+ metrics_subsystem,
1230
+ metrics_port,
1106
1231
  )
1107
1232
  # Register the connector in OpenCTI
1108
1233
  self.connector = OpenCTIConnector(
@@ -1226,6 +1351,11 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
1226
1351
  self.listen_queue = None
1227
1352
 
1228
1353
  def stop(self) -> None:
1354
+ """Stop the connector and clean up resources.
1355
+
1356
+ This method stops all running threads (listen queue, ping thread) and
1357
+ unregisters the connector from OpenCTI.
1358
+ """
1229
1359
  self.connector_logger.info("Preparing connector for clean shutdown")
1230
1360
  if self.listen_queue:
1231
1361
  self.listen_queue.stop()
@@ -1235,9 +1365,20 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
1235
1365
  self.api.connector.unregister(self.connector_id)
1236
1366
 
1237
1367
  def get_name(self) -> Optional[Union[bool, int, str]]:
1368
+ """Get the connector name.
1369
+
1370
+ :return: The name of the connector
1371
+ :rtype: Optional[Union[bool, int, str]]
1372
+ """
1238
1373
  return self.connect_name
1239
1374
 
1240
1375
  def get_stream_collection(self):
1376
+ """Get the stream collection configuration.
1377
+
1378
+ :return: Stream collection configuration dictionary
1379
+ :rtype: dict
1380
+ :raises ValueError: If no stream is connected
1381
+ """
1241
1382
  if self.connect_live_stream_id is not None:
1242
1383
  if self.connect_live_stream_id in ["live", "raw"]:
1243
1384
  return {
@@ -1272,12 +1413,27 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
1272
1413
  raise ValueError("This connector is not connected to any stream")
1273
1414
 
1274
1415
  def get_only_contextual(self) -> Optional[Union[bool, int, str]]:
1416
+ """Get the only_contextual configuration value.
1417
+
1418
+ :return: Whether the connector processes only contextual data
1419
+ :rtype: Optional[Union[bool, int, str]]
1420
+ """
1275
1421
  return self.connect_only_contextual
1276
1422
 
1277
1423
  def get_run_and_terminate(self) -> Optional[Union[bool, int, str]]:
1424
+ """Get the run_and_terminate configuration value.
1425
+
1426
+ :return: Whether the connector should run once and terminate
1427
+ :rtype: Optional[Union[bool, int, str]]
1428
+ """
1278
1429
  return self.connect_run_and_terminate
1279
1430
 
1280
1431
  def get_validate_before_import(self) -> Optional[Union[bool, int, str]]:
1432
+ """Get the validate_before_import configuration value.
1433
+
1434
+ :return: Whether to validate data before importing
1435
+ :rtype: Optional[Union[bool, int, str]]
1436
+ """
1281
1437
  return self.connect_validate_before_import
1282
1438
 
1283
1439
  def set_state(self, state) -> None:
@@ -1308,6 +1464,11 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
1308
1464
  return None
1309
1465
 
1310
1466
  def force_ping(self):
1467
+ """Force a ping to the OpenCTI API to update connector state.
1468
+
1469
+ This method manually triggers a ping to synchronize the connector state
1470
+ with the OpenCTI platform.
1471
+ """
1311
1472
  try:
1312
1473
  initial_state = self.get_state()
1313
1474
  connector_info = self.connector_info.all_details
@@ -1720,12 +1881,27 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
1720
1881
  return self.listen_stream
1721
1882
 
1722
1883
  def get_opencti_url(self) -> Optional[Union[bool, int, str]]:
1884
+ """Get the OpenCTI URL.
1885
+
1886
+ :return: The URL of the OpenCTI platform
1887
+ :rtype: Optional[Union[bool, int, str]]
1888
+ """
1723
1889
  return self.opencti_url
1724
1890
 
1725
1891
  def get_opencti_token(self) -> Optional[Union[bool, int, str]]:
1892
+ """Get the OpenCTI API token.
1893
+
1894
+ :return: The API token for OpenCTI authentication
1895
+ :rtype: Optional[Union[bool, int, str]]
1896
+ """
1726
1897
  return self.opencti_token
1727
1898
 
1728
1899
  def get_connector(self) -> OpenCTIConnector:
1900
+ """Get the OpenCTIConnector instance.
1901
+
1902
+ :return: The OpenCTIConnector instance
1903
+ :rtype: OpenCTIConnector
1904
+ """
1729
1905
  return self.connector
1730
1906
 
1731
1907
  def date_now(self) -> str:
@@ -2275,6 +2451,17 @@ class OpenCTIConnectorHelper: # pylint: disable=too-many-public-methods
2275
2451
  return None
2276
2452
 
2277
2453
  def get_data_from_enrichment(self, data, standard_id, opencti_entity):
2454
+ """Extract STIX entity and objects from enrichment data.
2455
+
2456
+ :param data: The enrichment data containing a bundle
2457
+ :type data: dict
2458
+ :param standard_id: The STIX standard ID of the entity
2459
+ :type standard_id: str
2460
+ :param opencti_entity: The OpenCTI entity object
2461
+ :type opencti_entity: dict
2462
+ :return: Dictionary containing stix_entity and stix_objects
2463
+ :rtype: dict
2464
+ """
2278
2465
  bundle = data.get("bundle", None)
2279
2466
  # Extract main entity from bundle in case of playbook
2280
2467
  if bundle is None:
@@ -4,7 +4,14 @@ from prometheus_client import Counter, Enum, start_http_server
4
4
 
5
5
 
6
6
  class OpenCTIMetricHandler:
7
- def __init__(self, connector_logger, activated: bool = False, port: int = 9095):
7
+ def __init__(
8
+ self,
9
+ connector_logger,
10
+ activated: bool = False,
11
+ namespace: str = "",
12
+ subsystem: str = "",
13
+ port: int = 9095,
14
+ ):
8
15
  """
9
16
  Init of OpenCTIMetricHandler class.
10
17
 
@@ -12,6 +19,10 @@ class OpenCTIMetricHandler:
12
19
  ----------
13
20
  activated : bool, default False
14
21
  If True use metrics in client and connectors.
22
+ namespace: str, default empty
23
+ Namespace for the prometheus metrics.
24
+ subsystem: str, default empty
25
+ Subsystem for the prometheus metrics.
15
26
  port : int, default 9095
16
27
  Port for prometheus server.
17
28
  """
@@ -22,35 +33,53 @@ class OpenCTIMetricHandler:
22
33
  start_http_server(port)
23
34
  self._metrics = {
24
35
  "bundle_send": Counter(
25
- "bundle_send",
26
- "Number of bundle send",
36
+ "bundles_sent_total",
37
+ "Number of bundles sent",
38
+ namespace=namespace,
39
+ subsystem=subsystem,
27
40
  ),
28
41
  "record_send": Counter(
29
- "record_send",
30
- "Number of record (objects per bundle) send",
42
+ "records_sent_total",
43
+ "Number of records (objects per bundle) sent",
44
+ namespace=namespace,
45
+ subsystem=subsystem,
31
46
  ),
32
47
  "run_count": Counter(
33
- "run_count",
48
+ "runs_total",
34
49
  "Number of run",
50
+ namespace=namespace,
51
+ subsystem=subsystem,
35
52
  ),
36
53
  "ping_api_count": Counter(
37
- "ping_api_count",
38
- "Number of ping to the api",
54
+ "ping_api_total",
55
+ "Number of pings to the API",
56
+ namespace=namespace,
57
+ subsystem=subsystem,
39
58
  ),
40
59
  "ping_api_error": Counter(
41
- "ping_api_error",
42
- "Number of error when pinging the api",
60
+ "ping_api_errors_total",
61
+ "Number of errors when pinging the API",
62
+ namespace=namespace,
63
+ subsystem=subsystem,
43
64
  ),
44
65
  "error_count": Counter(
45
- "error_count",
46
- "Number of error",
66
+ "errors_total",
67
+ "Number of errors",
68
+ namespace=namespace,
69
+ subsystem=subsystem,
47
70
  ),
48
71
  "client_error_count": Counter(
49
- "client_error_count",
50
- "Number of client error",
72
+ "client_errors_total",
73
+ "Number of client errors",
74
+ namespace=namespace,
75
+ subsystem=subsystem,
51
76
  ),
52
77
  "state": Enum(
53
- "state", "State of connector", states=["idle", "running", "stopped"]
78
+ "state",
79
+ "State of connector",
80
+ states=["idle", "running", "stopped"],
81
+ namespace=namespace,
82
+ subsystem=subsystem,
54
83
  ),
55
84
  }
56
85
 
@@ -7,6 +7,11 @@ from stix2.canonicalization.Canonicalize import canonicalize
7
7
 
8
8
 
9
9
  class AttackPattern:
10
+ """Main AttackPattern class for OpenCTI
11
+
12
+ :param opencti: instance of :py:class:`~pycti.api.opencti_api_client.OpenCTIApiClient`
13
+ """
14
+
10
15
  def __init__(self, opencti):
11
16
  self.opencti = opencti
12
17
  self.properties = """
@@ -238,6 +243,15 @@ class AttackPattern:
238
243
 
239
244
  @staticmethod
240
245
  def generate_id(name, x_mitre_id=None):
246
+ """Generate a STIX ID for an Attack Pattern.
247
+
248
+ :param name: The name of the attack pattern
249
+ :type name: str
250
+ :param x_mitre_id: Optional MITRE ATT&CK ID
251
+ :type x_mitre_id: str or None
252
+ :return: STIX ID for the attack pattern
253
+ :rtype: str
254
+ """
241
255
  if x_mitre_id is not None:
242
256
  data = {"x_mitre_id": x_mitre_id.strip()}
243
257
  else:
@@ -248,20 +262,32 @@ class AttackPattern:
248
262
 
249
263
  @staticmethod
250
264
  def generate_id_from_data(data):
265
+ """Generate a STIX ID from attack pattern data.
266
+
267
+ :param data: Dictionary containing 'name' and optionally 'x_mitre_id' keys
268
+ :type data: dict
269
+ :return: STIX ID for the attack pattern
270
+ :rtype: str
271
+ """
251
272
  external_id = data.get("x_mitre_id") or data.get("x_opencti_external_id")
252
273
  return AttackPattern.generate_id(data.get("name"), external_id)
253
274
 
254
- """
255
- List Attack-Pattern objects
275
+ def list(self, **kwargs):
276
+ """List Attack Pattern objects.
256
277
 
257
278
  :param filters: the filters to apply
258
279
  :param search: the search keyword
259
280
  :param first: return the first n rows from the after ID (or the beginning if not set)
260
281
  :param after: ID of the first row for pagination
261
- :return List of Attack-Pattern objects
262
- """
263
-
264
- def list(self, **kwargs):
282
+ :param orderBy: field to order results by
283
+ :param orderMode: ordering mode (asc/desc)
284
+ :param customAttributes: custom attributes to return
285
+ :param getAll: whether to retrieve all results
286
+ :param withPagination: whether to include pagination info
287
+ :param withFiles: whether to include files
288
+ :return: List of Attack Pattern objects
289
+ :rtype: list
290
+ """
265
291
  filters = kwargs.get("filters", None)
266
292
  search = kwargs.get("search", None)
267
293
  first = kwargs.get("first", 500)
@@ -7,6 +7,11 @@ from stix2.canonicalization.Canonicalize import canonicalize
7
7
 
8
8
 
9
9
  class Campaign:
10
+ """Main Campaign class for OpenCTI
11
+
12
+ :param opencti: instance of :py:class:`~pycti.api.opencti_api_client.OpenCTIApiClient`
13
+ """
14
+
10
15
  def __init__(self, opencti):
11
16
  self.opencti = opencti
12
17
  self.properties = """
@@ -226,6 +231,13 @@ class Campaign:
226
231
 
227
232
  @staticmethod
228
233
  def generate_id(name):
234
+ """Generate a STIX ID for a Campaign.
235
+
236
+ :param name: The name of the campaign
237
+ :type name: str
238
+ :return: STIX ID for the campaign
239
+ :rtype: str
240
+ """
229
241
  name = name.lower().strip()
230
242
  data = {"name": name}
231
243
  data = canonicalize(data, utf8=False)
@@ -234,19 +246,31 @@ class Campaign:
234
246
 
235
247
  @staticmethod
236
248
  def generate_id_from_data(data):
249
+ """Generate a STIX ID from campaign data.
250
+
251
+ :param data: Dictionary containing 'name' key
252
+ :type data: dict
253
+ :return: STIX ID for the campaign
254
+ :rtype: str
255
+ """
237
256
  return Campaign.generate_id(data["name"])
238
257
 
239
- """
240
- List Campaign objects
258
+ def list(self, **kwargs):
259
+ """List Campaign objects.
241
260
 
242
261
  :param filters: the filters to apply
243
262
  :param search: the search keyword
244
263
  :param first: return the first n rows from the after ID (or the beginning if not set)
245
264
  :param after: ID of the first row for pagination
246
- :return List of Campaign objects
247
- """
248
-
249
- def list(self, **kwargs):
265
+ :param orderBy: field to order results by
266
+ :param orderMode: ordering mode (asc/desc)
267
+ :param customAttributes: custom attributes to return
268
+ :param getAll: whether to retrieve all results
269
+ :param withPagination: whether to include pagination info
270
+ :param withFiles: whether to include files
271
+ :return: List of Campaign objects
272
+ :rtype: list
273
+ """
250
274
  filters = kwargs.get("filters", None)
251
275
  search = kwargs.get("search", None)
252
276
  first = kwargs.get("first", 500)
@@ -7,6 +7,13 @@ from stix2.canonicalization.Canonicalize import canonicalize
7
7
 
8
8
 
9
9
  class CaseIncident:
10
+ """Main CaseIncident class for OpenCTI
11
+
12
+ Manages incident response cases in the OpenCTI platform.
13
+
14
+ :param opencti: instance of :py:class:`~pycti.api.opencti_api_client.OpenCTIApiClient`
15
+ """
16
+
10
17
  def __init__(self, opencti):
11
18
  self.opencti = opencti
12
19
  self.properties = """
@@ -7,6 +7,13 @@ from stix2.canonicalization.Canonicalize import canonicalize
7
7
 
8
8
 
9
9
  class CaseRfi:
10
+ """Main CaseRfi (Request for Information) class for OpenCTI
11
+
12
+ Manages RFI cases in the OpenCTI platform.
13
+
14
+ :param opencti: instance of :py:class:`~pycti.api.opencti_api_client.OpenCTIApiClient`
15
+ """
16
+
10
17
  def __init__(self, opencti):
11
18
  self.opencti = opencti
12
19
  self.properties = """
@@ -7,6 +7,13 @@ from stix2.canonicalization.Canonicalize import canonicalize
7
7
 
8
8
 
9
9
  class CaseRft:
10
+ """Main CaseRft (Request for Takedown) class for OpenCTI
11
+
12
+ Manages RFT cases in the OpenCTI platform.
13
+
14
+ :param opencti: instance of :py:class:`~pycti.api.opencti_api_client.OpenCTIApiClient`
15
+ """
16
+
10
17
  def __init__(self, opencti):
11
18
  self.opencti = opencti
12
19
  self.properties = """
@@ -7,6 +7,13 @@ from stix2.canonicalization.Canonicalize import canonicalize
7
7
 
8
8
 
9
9
  class Channel:
10
+ """Main Channel class for OpenCTI
11
+
12
+ Manages communication channels used by threat actors in the OpenCTI platform.
13
+
14
+ :param opencti: instance of :py:class:`~pycti.api.opencti_api_client.OpenCTIApiClient`
15
+ """
16
+
10
17
  def __init__(self, opencti):
11
18
  self.opencti = opencti
12
19
  self.properties = """
@@ -7,6 +7,13 @@ from stix2.canonicalization.Canonicalize import canonicalize
7
7
 
8
8
 
9
9
  class CourseOfAction:
10
+ """Main CourseOfAction class for OpenCTI
11
+
12
+ Manages courses of action (mitigations) in the OpenCTI platform.
13
+
14
+ :param opencti: instance of :py:class:`~pycti.api.opencti_api_client.OpenCTIApiClient`
15
+ """
16
+
10
17
  def __init__(self, opencti):
11
18
  self.opencti = opencti
12
19
  self.properties = """