diff --git a/content/response_integrations/google/fire_eye_ex/.python-version b/content/response_integrations/google/fire_eye_ex/.python-version
new file mode 100644
index 000000000..902b2c90c
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/.python-version
@@ -0,0 +1 @@
+3.11
\ No newline at end of file
diff --git a/content/response_integrations/google/fire_eye_ex/actions/DeleteQuarantinedEmail.py b/content/response_integrations/google/fire_eye_ex/actions/DeleteQuarantinedEmail.py
new file mode 100644
index 000000000..3a583ce24
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/actions/DeleteQuarantinedEmail.py
@@ -0,0 +1,114 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import annotations
+from soar_sdk.SiemplifyUtils import output_handler
+from ..core.FireEyeEXManager import FireEyeEXManager, FireEyeEXUnsuccessfulOperationError
+from soar_sdk.SiemplifyAction import SiemplifyAction
+from soar_sdk.ScriptResult import EXECUTION_STATE_COMPLETED, EXECUTION_STATE_FAILED
+from TIPCommon import extract_configuration_param, extract_action_param
+
+
+INTEGRATION_NAME = "FireEyeEX"
+SCRIPT_NAME = "Delete Quarantined Email"
+
+
+@output_handler
+def main():
+ siemplify = SiemplifyAction()
+ siemplify.script_name = f"{INTEGRATION_NAME} - {SCRIPT_NAME}"
+ siemplify.LOGGER.info("================= Main - Param Init =================")
+
+ # INIT INTEGRATION CONFIGURATION:
+ api_root = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="API Root",
+ is_mandatory=True,
+ input_type=str,
+ )
+ username = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="Username",
+ is_mandatory=True,
+ input_type=str,
+ )
+ password = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="Password",
+ is_mandatory=True,
+ input_type=str,
+ )
+ verify_ssl = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="Verify SSL",
+ default_value=False,
+ input_type=bool,
+ )
+
+ queue_id = extract_action_param(
+ siemplify,
+ param_name="Queue ID",
+ is_mandatory=True,
+ input_type=str,
+ print_value=True,
+ )
+
+ siemplify.LOGGER.info("----------------- Main - Started -----------------")
+
+ status = EXECUTION_STATE_COMPLETED
+
+ try:
+ ex_manager = FireEyeEXManager(
+ api_root=api_root,
+ username=username,
+ password=password,
+ verify_ssl=verify_ssl,
+ )
+ ex_manager.delete_quarantined_email(queue_id)
+ output_message = f"Successfully deleted FireEye EX quarantined email with queue id {queue_id}!"
+ result_value = "true"
+
+ ex_manager.logout()
+
+ except FireEyeEXUnsuccessfulOperationError as e:
+ siemplify.LOGGER.error(f"Email with queue id {queue_id} was not deleted.")
+ siemplify.LOGGER.exception(e)
+ status = EXECUTION_STATE_FAILED
+ output_message = f"Email with queue id {queue_id} was not deleted. Reason: {e}"
+ result_value = "false"
+
+ except Exception as e:
+ siemplify.LOGGER.error(
+ f'Error executing action "Delete Quarantined Email". Reason: {e}'
+ )
+ siemplify.LOGGER.exception(e)
+ status = EXECUTION_STATE_FAILED
+ result_value = "false"
+ output_message = (
+ f'Error executing action "Delete Quarantined Email". Reason: {e}'
+ )
+
+ siemplify.LOGGER.info("----------------- Main - Finished -----------------")
+ siemplify.LOGGER.info(f"Status: {status}:")
+ siemplify.LOGGER.info(f"Result Value: {result_value}")
+ siemplify.LOGGER.info(f"Output Message: {output_message}")
+ siemplify.end(output_message, result_value, status)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/content/response_integrations/google/fire_eye_ex/actions/DeleteQuarantinedEmail.yaml b/content/response_integrations/google/fire_eye_ex/actions/DeleteQuarantinedEmail.yaml
new file mode 100644
index 000000000..ab1904036
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/actions/DeleteQuarantinedEmail.yaml
@@ -0,0 +1,25 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+name: Delete Quarantined Email
+description: Deletes quarantined email.
+integration_identifier: FireEyeEX
+parameters:
+- name: Queue ID
+ type: string
+ description: Specify the queue id of the email that needs to be deleted.
+ is_mandatory: true
+dynamic_results_metadata: []
+creator: Admin
+simulation_data_json: '{"Entities":[]}'
diff --git a/content/response_integrations/google/fire_eye_ex/actions/DownloadAlertArtifacts.py b/content/response_integrations/google/fire_eye_ex/actions/DownloadAlertArtifacts.py
new file mode 100644
index 000000000..5266b5c0a
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/actions/DownloadAlertArtifacts.py
@@ -0,0 +1,146 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# coding=utf-8
+from __future__ import annotations
+from soar_sdk.SiemplifyUtils import output_handler
+from ..core.FireEyeEXManager import FireEyeEXManager, FireEyeEXDownloadFileError
+from soar_sdk.SiemplifyAction import SiemplifyAction
+from soar_sdk.ScriptResult import EXECUTION_STATE_COMPLETED, EXECUTION_STATE_FAILED
+from TIPCommon import extract_configuration_param, extract_action_param
+import base64
+from urllib.parse import urljoin
+
+INTEGRATION_NAME = "FireEyeEX"
+SCRIPT_NAME = "Download Alert Artifacts"
+
+
+@output_handler
+def main():
+ siemplify = SiemplifyAction()
+ siemplify.script_name = f"{INTEGRATION_NAME} - {SCRIPT_NAME}"
+ siemplify.LOGGER.info("================= Main - Param Init =================")
+
+ # INIT INTEGRATION CONFIGURATION:
+ api_root = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="API Root",
+ is_mandatory=True,
+ input_type=str,
+ )
+ username = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="Username",
+ is_mandatory=True,
+ input_type=str,
+ )
+ password = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="Password",
+ is_mandatory=True,
+ input_type=str,
+ )
+ verify_ssl = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="Verify SSL",
+ default_value=False,
+ input_type=bool,
+ )
+
+ alert_uuid = extract_action_param(
+ siemplify,
+ param_name="Alert UUID",
+ is_mandatory=True,
+ input_type=str,
+ print_value=True,
+ )
+ download_path = extract_action_param(
+ siemplify,
+ param_name="Download Path",
+ is_mandatory=False,
+ input_type=str,
+ print_value=True,
+ )
+
+ siemplify.LOGGER.info("----------------- Main - Started -----------------")
+
+ status = EXECUTION_STATE_COMPLETED
+ result_value = "true"
+
+ try:
+ ex_manager = FireEyeEXManager(
+ api_root=api_root,
+ username=username,
+ password=password,
+ verify_ssl=verify_ssl,
+ )
+ zip_content = ex_manager.download_alert_artifacts(alert_uuid)
+
+ try:
+ siemplify.result.add_attachment(
+ f"Alert_Artifacts_{alert_uuid}.zip",
+ f"Alert_Artifacts_{alert_uuid}.zip",
+ base64.b64encode(zip_content.content.encode("utf-8")),
+ )
+
+ absolute_path = urljoin(download_path, f"Alert_Artifacts_{alert_uuid}.zip")
+
+ if ex_manager.save_artifacts_to_file(zip_content, absolute_path):
+ siemplify.result.add_result_json({"file_path": absolute_path})
+ output_message = f"Successfully downloaded FireEye EX alert artifacts with alert id {alert_uuid}!"
+ else:
+ output_message = f"Action wasn’t able to download FireEye EX alert artifacts with alert id {alert_uuid}. Reason: File with that path already exists."
+ result_value = "false"
+
+ except FireEyeEXDownloadFileError as e:
+ siemplify.LOGGER.error(
+ f"Unable to attach downloaded artifacts. Reason: {e}"
+ )
+ output_message = f"Unable to attach downloaded artifacts. Reason: {e}"
+ result_value = "false"
+
+ except EnvironmentError:
+ # File size is too big
+ siemplify.LOGGER.error(
+ "Unable to attach downloaded artifacts. Reason: artifacts are too large in size."
+ )
+ output_message = "Unable to attach downloaded artifacts. Reason: artifacts are too large in size."
+ result_value = "false"
+
+ ex_manager.logout()
+
+ except Exception as e:
+ siemplify.LOGGER.error(
+ f'Error executing action "Download Alert Artifacts". Reason: {e}'
+ )
+ siemplify.LOGGER.exception(e)
+ status = EXECUTION_STATE_FAILED
+ result_value = "false"
+ output_message = (
+ f'Error executing action "Download Alert Artifacts". Reason: {e}'
+ )
+
+ siemplify.LOGGER.info("----------------- Main - Finished -----------------")
+ siemplify.LOGGER.info(f"Status: {status}:")
+ siemplify.LOGGER.info(f"Result Value: {result_value}")
+ siemplify.LOGGER.info(f"Output Message: {output_message}")
+ siemplify.end(output_message, result_value, status)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/content/response_integrations/google/fire_eye_ex/actions/DownloadAlertArtifacts.yaml b/content/response_integrations/google/fire_eye_ex/actions/DownloadAlertArtifacts.yaml
new file mode 100644
index 000000000..b7b6ff1f2
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/actions/DownloadAlertArtifacts.yaml
@@ -0,0 +1,34 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+name: Download Alert Artifacts
+description: Download alert artifacts.
+integration_identifier: FireEyeEX
+parameters:
+- name: Alert UUID
+ type: string
+ description: Specify the alert uuid from where we need to download artifacts.
+ is_mandatory: true
+- name: Download Path
+ default_value: ''
+ type: string
+ description: 'Specify where the action should save the files. If nothing is specified,
+ action will not save the file on the disk. '
+ is_mandatory: true
+dynamic_results_metadata:
+- result_example_path: resources/download_alert_artifacts_JsonResult_example.json
+ result_name: JsonResult
+ show_result: true
+creator: Admin
+simulation_data_json: '{"Entities":[]}'
diff --git a/content/response_integrations/google/fire_eye_ex/actions/DownloadQuarantinedEmail.py b/content/response_integrations/google/fire_eye_ex/actions/DownloadQuarantinedEmail.py
new file mode 100644
index 000000000..2ee0eef1e
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/actions/DownloadQuarantinedEmail.py
@@ -0,0 +1,160 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# coding=utf-8
+from __future__ import annotations
+from soar_sdk.SiemplifyUtils import output_handler
+from ..core.FireEyeEXManager import (
+ FireEyeEXManager,
+ FireEyeEXUnsuccessfulOperationError,
+ FireEyeEXDownloadFileError,
+)
+from soar_sdk.SiemplifyAction import SiemplifyAction
+from soar_sdk.ScriptResult import EXECUTION_STATE_COMPLETED, EXECUTION_STATE_FAILED
+from TIPCommon import extract_configuration_param, extract_action_param
+import base64
+from urllib.parse import urljoin
+
+INTEGRATION_NAME = "FireEyeEX"
+SCRIPT_NAME = "Download Quarantined Email"
+
+
+@output_handler
+def main():
+ siemplify = SiemplifyAction()
+ siemplify.script_name = f"{INTEGRATION_NAME} - {SCRIPT_NAME}"
+ siemplify.LOGGER.info("================= Main - Param Init =================")
+
+ # INIT INTEGRATION CONFIGURATION:
+ api_root = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="API Root",
+ is_mandatory=True,
+ input_type=str,
+ )
+ username = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="Username",
+ is_mandatory=True,
+ input_type=str,
+ )
+ password = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="Password",
+ is_mandatory=True,
+ input_type=str,
+ )
+ verify_ssl = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="Verify SSL",
+ default_value=False,
+ input_type=bool,
+ )
+
+ queue_id = extract_action_param(
+ siemplify,
+ param_name="Queue ID",
+ is_mandatory=True,
+ input_type=str,
+ print_value=True,
+ )
+ download_path = extract_action_param(
+ siemplify,
+ param_name="Download Path",
+ is_mandatory=False,
+ input_type=str,
+ print_value=True,
+ )
+
+ siemplify.LOGGER.info("----------------- Main - Started -----------------")
+
+ status = EXECUTION_STATE_COMPLETED
+ result_value = "true"
+
+ try:
+ ex_manager = FireEyeEXManager(
+ api_root=api_root,
+ username=username,
+ password=password,
+ verify_ssl=verify_ssl,
+ )
+ email_content = ex_manager.download_quarantined_email(queue_id)
+
+ try:
+ siemplify.result.add_attachment(
+ f"Quarantined_email_{queue_id}.eml",
+ f"Quarantined_email_{queue_id}.eml",
+ base64.b64encode(email_content.content.encode("utf-8")),
+ )
+ output_message = f"Successfully downloaded FireEye EX quarantined email with queue id {queue_id}!"
+
+ absolute_path = urljoin(download_path, f"Quarantined_email_{queue_id}.eml")
+
+ if ex_manager.save_artifacts_to_file(email_content, absolute_path):
+ siemplify.result.add_result_json({"file_path": absolute_path})
+ output_message = f"Successfully downloaded FireEye EX quarantined email with queue id {queue_id}!"
+ else:
+ output_message = f"Action wasn’t able to download FireEye EX alert quarantined email with queue id {queue_id}. Reason: File with that path already exists."
+ result_value = "false"
+
+ except FireEyeEXDownloadFileError as e:
+ siemplify.LOGGER.error(
+ f"Unable to attach downloaded artifacts. Reason: {e}"
+ )
+ output_message = f"Unable to attach downloaded artifacts. Reason: {e}"
+ result_value = "false"
+
+ except EnvironmentError:
+ # File size is too big
+ siemplify.LOGGER.error(
+ "Unable to attach quarantined email. Reason: email is too large in size."
+ )
+ output_message = "Unable to attach quarantined email. Reason: email is too large in size."
+ result_value = "false"
+
+ ex_manager.logout()
+
+ except FireEyeEXUnsuccessfulOperationError as e:
+ siemplify.LOGGER.error(f"Email with queue id {queue_id} was not downloaded.")
+ siemplify.LOGGER.exception(e)
+ status = EXECUTION_STATE_FAILED
+ output_message = (
+ f"Email with queue id {queue_id} was not downloaded. Reason: {e}"
+ )
+ result_value = "false"
+
+ except Exception as e:
+ siemplify.LOGGER.error(
+ f'Error executing action "Download Quarantined Email". Reason: {e}'
+ )
+ siemplify.LOGGER.exception(e)
+ status = EXECUTION_STATE_FAILED
+ result_value = "false"
+ output_message = (
+ f'Error executing action "Download Quarantined Email". Reason: {e}'
+ )
+
+ siemplify.LOGGER.info("----------------- Main - Finished -----------------")
+ siemplify.LOGGER.info(f"Status: {status}:")
+ siemplify.LOGGER.info(f"Result Value: {result_value}")
+ siemplify.LOGGER.info(f"Output Message: {output_message}")
+ siemplify.end(output_message, result_value, status)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/content/response_integrations/google/fire_eye_ex/actions/DownloadQuarantinedEmail.yaml b/content/response_integrations/google/fire_eye_ex/actions/DownloadQuarantinedEmail.yaml
new file mode 100644
index 000000000..22aed32eb
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/actions/DownloadQuarantinedEmail.yaml
@@ -0,0 +1,34 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+name: Download Quarantined Email
+description: Downloads quarantined email.
+integration_identifier: FireEyeEX
+parameters:
+- name: Queue ID
+ type: string
+ description: Specify the queue id of the email that needs to be downloaded.
+ is_mandatory: true
+- name: Download Path
+ default_value: ''
+ type: string
+ description: 'Specify where the action should save the files. If nothing is specified,
+ action will not save the file on the disk. '
+ is_mandatory: true
+dynamic_results_metadata:
+- result_example_path: resources/download_quarantined_email_JsonResult_example.json
+ result_name: JsonResult
+ show_result: true
+creator: Admin
+simulation_data_json: '{"Entities":[]}'
diff --git a/content/response_integrations/google/fire_eye_ex/actions/ListQuarantinedEmails.py b/content/response_integrations/google/fire_eye_ex/actions/ListQuarantinedEmails.py
new file mode 100644
index 000000000..7e604e676
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/actions/ListQuarantinedEmails.py
@@ -0,0 +1,155 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import annotations
+from soar_sdk.SiemplifyUtils import output_handler
+from ..core.FireEyeEXManager import FireEyeEXManager
+from soar_sdk.SiemplifyAction import SiemplifyAction
+from soar_sdk.ScriptResult import EXECUTION_STATE_COMPLETED, EXECUTION_STATE_FAILED
+from TIPCommon import extract_configuration_param, extract_action_param, construct_csv
+
+INTEGRATION_NAME = "FireEyeEX"
+SCRIPT_NAME = "List quarantined emails"
+
+
+@output_handler
+def main():
+ siemplify = SiemplifyAction()
+ siemplify.script_name = f"{INTEGRATION_NAME} - {SCRIPT_NAME}"
+ siemplify.LOGGER.info("================= Main - Param Init =================")
+
+ # INIT INTEGRATION CONFIGURATION:
+ api_root = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="API Root",
+ is_mandatory=True,
+ input_type=str,
+ )
+ username = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="Username",
+ is_mandatory=True,
+ input_type=str,
+ )
+ password = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="Password",
+ is_mandatory=True,
+ input_type=str,
+ )
+ verify_ssl = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="Verify SSL",
+ default_value=False,
+ input_type=bool,
+ )
+
+ start_time = extract_action_param(
+ siemplify,
+ param_name="Start Time",
+ is_mandatory=False,
+ input_type=str,
+ print_value=True,
+ )
+ end_time = extract_action_param(
+ siemplify,
+ param_name="End Time",
+ is_mandatory=False,
+ input_type=str,
+ print_value=True,
+ )
+ sender = extract_action_param(
+ siemplify,
+ param_name="Sender Filter",
+ is_mandatory=False,
+ input_type=str,
+ print_value=True,
+ )
+ subject = extract_action_param(
+ siemplify,
+ param_name="Subject Filter",
+ is_mandatory=False,
+ input_type=str,
+ print_value=True,
+ )
+ limit = extract_action_param(
+ siemplify,
+ param_name="Max Email to Return",
+ is_mandatory=False,
+ input_type=int,
+ print_value=True,
+ )
+
+ siemplify.LOGGER.info("----------------- Main - Started -----------------")
+
+ json_results = []
+ status = EXECUTION_STATE_COMPLETED
+ result_value = "true"
+
+ try:
+ ex_manager = FireEyeEXManager(
+ api_root=api_root,
+ username=username,
+ password=password,
+ verify_ssl=verify_ssl,
+ )
+ quarantined_emails = ex_manager.list_quarantined_emails(
+ start_time=start_time,
+ end_time=end_time,
+ sender=sender,
+ subject=subject,
+ limit=limit,
+ )
+
+ json_results = [email.raw_data for email in quarantined_emails]
+
+ siemplify.LOGGER.info(f"Found {len(quarantined_emails)} quarantined emails.")
+
+ if quarantined_emails:
+ siemplify.result.add_data_table(
+ "Quarantined Emails",
+ construct_csv([email.as_csv() for email in quarantined_emails]),
+ )
+ output_message = "Successfully listed FireEye EX quarantined emails!"
+
+ else:
+ output_message = "No quarantined emails were found in FireEye EX!"
+
+ ex_manager.logout()
+
+ except Exception as e:
+ siemplify.LOGGER.error(
+ f'Error executing action "List Quarantined Emails". Reason: {e}'
+ )
+ siemplify.LOGGER.exception(e)
+ status = EXECUTION_STATE_FAILED
+ result_value = "false"
+ output_message = (
+ f'Error executing action "List Quarantined Emails". Reason: {e}'
+ )
+
+ siemplify.result.add_result_json(json_results)
+ siemplify.LOGGER.info("----------------- Main - Finished -----------------")
+ siemplify.LOGGER.info(f"Status: {status}:")
+ siemplify.LOGGER.info(f"Result Value: {result_value}")
+ siemplify.LOGGER.info(f"Output Message: {output_message}")
+ siemplify.end(output_message, result_value, status)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/content/response_integrations/google/fire_eye_ex/actions/ListQuarantinedEmails.yaml b/content/response_integrations/google/fire_eye_ex/actions/ListQuarantinedEmails.yaml
new file mode 100644
index 000000000..d2ac3a0df
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/actions/ListQuarantinedEmails.yaml
@@ -0,0 +1,54 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+name: List Quarantined Emails
+description: List quarantined emails.
+integration_identifier: FireEyeEX
+parameters:
+- name: Start Time
+ default_value: ''
+ type: string
+ description: 'If specified, only emails that were created after start time will
+ be returned. If Start Time and End Time are not specified, action returns
+ quarantined emails from the last 24 hours. Format: YYYY-MM-DD''T''HH:MM:SS.SSS-HHMM'
+ is_mandatory: false
+- name: End Time
+ default_value: ''
+ type: string
+ description: 'If specified, only emails that were created before end time will
+ be returned. If Start Time and End Time are not specified, action returns
+ quarantined emails from the last 24 hours. Format: YYYY-MM-DD''T''HH:MM:SS.SSS-HHMM'
+ is_mandatory: false
+- name: Sender Filter
+ type: string
+ description: If specified, returns all of the quarantined emails only from this
+ sender.
+ is_mandatory: false
+- name: Subject Filter
+ default_value: ''
+ type: string
+ description: If specified, returns all of the quarantined emails only with this
+ subject.
+ is_mandatory: false
+- name: Max Email to Return
+ type: string
+ description: Specify how many emails to return. Limit is 10000. This is FireEye
+ EX limitation.
+ is_mandatory: false
+dynamic_results_metadata:
+- result_example_path: resources/list_quarantined_emails_JsonResult_example.json
+ result_name: JsonResult
+ show_result: true
+creator: Admin
+simulation_data_json: '{"Entities":[]}'
diff --git a/content/response_integrations/google/fire_eye_ex/actions/Ping.py b/content/response_integrations/google/fire_eye_ex/actions/Ping.py
new file mode 100644
index 000000000..bffe8d09f
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/actions/Ping.py
@@ -0,0 +1,93 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import annotations
+from soar_sdk.SiemplifyUtils import output_handler
+from soar_sdk.SiemplifyAction import SiemplifyAction
+from soar_sdk.ScriptResult import EXECUTION_STATE_COMPLETED, EXECUTION_STATE_FAILED
+from ..core.FireEyeEXManager import FireEyeEXManager
+from TIPCommon import extract_configuration_param
+
+
+INTEGRATION_NAME = "FireEyeEX"
+SCRIPT_NAME = "Ping"
+
+
+@output_handler
+def main():
+ siemplify = SiemplifyAction()
+ siemplify.script_name = f"{INTEGRATION_NAME} - {SCRIPT_NAME}"
+ siemplify.LOGGER.info("================= Main - Param Init =================")
+
+ # INIT INTEGRATION CONFIGURATION:
+ api_root = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="API Root",
+ is_mandatory=True,
+ input_type=str,
+ )
+ username = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="Username",
+ is_mandatory=True,
+ input_type=str,
+ )
+ password = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="Password",
+ is_mandatory=True,
+ input_type=str,
+ )
+ verify_ssl = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="Verify SSL",
+ default_value=False,
+ input_type=bool,
+ )
+ siemplify.LOGGER.info("----------------- Main - Started -----------------")
+
+ try:
+ ex_manager = FireEyeEXManager(
+ api_root=api_root,
+ username=username,
+ password=password,
+ verify_ssl=verify_ssl,
+ )
+ ex_manager.logout()
+ status = EXECUTION_STATE_COMPLETED
+ output_message = "Successfully connected to the FireEye EX server with the provided connection parameters!"
+ result_value = "true"
+
+ except Exception as e:
+ siemplify.LOGGER.error(
+ f"Failed to connect to the FireEye EX server! Error is {e}"
+ )
+ siemplify.LOGGER.exception(e)
+ status = EXECUTION_STATE_FAILED
+ result_value = "false"
+ output_message = f"Failed to connect to the FireEye EX server! Error is {e}"
+
+ siemplify.LOGGER.info("----------------- Main - Finished -----------------")
+ siemplify.LOGGER.info(f"Status: {status}:")
+ siemplify.LOGGER.info(f"Result Value: {result_value}")
+ siemplify.LOGGER.info(f"Output Message: {output_message}")
+ siemplify.end(output_message, result_value, status)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/content/response_integrations/google/fire_eye_ex/actions/Ping.yaml b/content/response_integrations/google/fire_eye_ex/actions/Ping.yaml
new file mode 100644
index 000000000..6edcd8682
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/actions/Ping.yaml
@@ -0,0 +1,22 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+name: Ping
+description: Test connectivity to the FireEye EX with parameters provided at the integration
+ configuration page on the Marketplace tab.
+integration_identifier: FireEyeEX
+parameters: []
+dynamic_results_metadata: []
+creator: Admin
+simulation_data_json: '{"Entities":[]}'
diff --git a/content/response_integrations/google/fire_eye_ex/actions/ReleaseQuarantinedEmail.py b/content/response_integrations/google/fire_eye_ex/actions/ReleaseQuarantinedEmail.py
new file mode 100644
index 000000000..25cfd529d
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/actions/ReleaseQuarantinedEmail.py
@@ -0,0 +1,114 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import annotations
+from soar_sdk.SiemplifyUtils import output_handler
+from ..core.FireEyeEXManager import FireEyeEXManager, FireEyeEXUnsuccessfulOperationError
+from soar_sdk.SiemplifyAction import SiemplifyAction
+from soar_sdk.ScriptResult import EXECUTION_STATE_COMPLETED, EXECUTION_STATE_FAILED
+from TIPCommon import extract_configuration_param, extract_action_param
+
+
+INTEGRATION_NAME = "FireEyeEX"
+SCRIPT_NAME = "Release Quarantined Email"
+
+
+@output_handler
+def main():
+ siemplify = SiemplifyAction()
+ siemplify.script_name = f"{INTEGRATION_NAME} - {SCRIPT_NAME}"
+ siemplify.LOGGER.info("================= Main - Param Init =================")
+
+ # INIT INTEGRATION CONFIGURATION:
+ api_root = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="API Root",
+ is_mandatory=True,
+ input_type=str,
+ )
+ username = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="Username",
+ is_mandatory=True,
+ input_type=str,
+ )
+ password = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="Password",
+ is_mandatory=True,
+ input_type=str,
+ )
+ verify_ssl = extract_configuration_param(
+ siemplify,
+ provider_name=INTEGRATION_NAME,
+ param_name="Verify SSL",
+ default_value=False,
+ input_type=bool,
+ )
+
+ queue_id = extract_action_param(
+ siemplify,
+ param_name="Queue ID",
+ is_mandatory=True,
+ input_type=str,
+ print_value=True,
+ )
+
+ siemplify.LOGGER.info("----------------- Main - Started -----------------")
+
+ status = EXECUTION_STATE_COMPLETED
+
+ try:
+ ex_manager = FireEyeEXManager(
+ api_root=api_root,
+ username=username,
+ password=password,
+ verify_ssl=verify_ssl,
+ )
+ ex_manager.release_quarantined_email(queue_id)
+ output_message = f"Successfully released FireEye EX quarantined email with queue id {queue_id}!"
+ result_value = "true"
+
+ ex_manager.logout()
+
+ except FireEyeEXUnsuccessfulOperationError as e:
+ siemplify.LOGGER.error(f"Email with queue id {queue_id} was not released.")
+ siemplify.LOGGER.exception(e)
+ status = EXECUTION_STATE_FAILED
+ output_message = f"Email with queue id {queue_id} was not released. Reason: {e}"
+ result_value = "false"
+
+ except Exception as e:
+ siemplify.LOGGER.error(
+ f'Error executing action "Release Quarantined Email". Reason: {e}'
+ )
+ siemplify.LOGGER.exception(e)
+ status = EXECUTION_STATE_FAILED
+ result_value = "false"
+ output_message = (
+ f'Error executing action "Release Quarantined Email". Reason: {e}'
+ )
+
+ siemplify.LOGGER.info("----------------- Main - Finished -----------------")
+ siemplify.LOGGER.info(f"Status: {status}:")
+ siemplify.LOGGER.info(f"Result Value: {result_value}")
+ siemplify.LOGGER.info(f"Output Message: {output_message}")
+ siemplify.end(output_message, result_value, status)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/content/response_integrations/google/fire_eye_ex/actions/ReleaseQuarantinedEmail.yaml b/content/response_integrations/google/fire_eye_ex/actions/ReleaseQuarantinedEmail.yaml
new file mode 100644
index 000000000..c293acebb
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/actions/ReleaseQuarantinedEmail.yaml
@@ -0,0 +1,25 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+name: Release Quarantined Email
+description: Releases quarantined email.
+integration_identifier: FireEyeEX
+parameters:
+- name: Queue ID
+ type: string
+ description: Specify the queue id of the email that needs to be released.
+ is_mandatory: true
+dynamic_results_metadata: []
+creator: Admin
+simulation_data_json: '{"Entities":[]}'
diff --git a/content/response_integrations/google/fire_eye_ex/actions/__init__.py b/content/response_integrations/google/fire_eye_ex/actions/__init__.py
new file mode 100644
index 000000000..9f71a2dc3
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/actions/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
diff --git a/content/response_integrations/google/fire_eye_ex/connectors/FireEyeEXAlertsConnector.py b/content/response_integrations/google/fire_eye_ex/connectors/FireEyeEXAlertsConnector.py
new file mode 100644
index 000000000..3451b7069
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/connectors/FireEyeEXAlertsConnector.py
@@ -0,0 +1,381 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import annotations
+import datetime
+import sys
+
+import arrow
+
+from EnvironmentCommon import GetEnvironmentCommonFactory
+from ..core.FireEyeEXManager import FireEyeEXManager
+from soar_sdk.SiemplifyConnectors import SiemplifyConnectorExecution
+from soar_sdk.SiemplifyConnectorsDataModel import AlertInfo
+from soar_sdk.SiemplifyUtils import (
+ output_handler,
+ unix_now,
+ dict_to_flat,
+ convert_unixtime_to_datetime,
+)
+from TIPCommon import (
+ extract_connector_param,
+ read_ids_by_timestamp,
+ write_ids_with_timestamp,
+ is_approaching_timeout,
+ filter_old_ids,
+ siemplify_save_timestamp,
+ get_last_success_time,
+)
+from ..core.consts import (
+ ALERTS_CONNECTOR_NAME,
+ DURATION,
+ MAP_FILE,
+ DEVICE_VENDOR,
+ DEVICE_PRODUCT,
+ ALERT_NAME,
+ PRINT_TIME_FORMAT,
+ HOURS_LIMIT_IN_IDS_FILE,
+)
+
+
+def filter_recent_alerts(siemplify, alerts, max_minutes_backwards=5):
+ filtered_alerts = []
+
+ for alert in alerts:
+ if (
+ alert.occurred_time_unix
+ < arrow.utcnow().shift(minutes=-max_minutes_backwards).timestamp * 1000
+ ):
+ filtered_alerts.append(alert)
+
+ else:
+ siemplify.LOGGER.info(
+ f"Alert {alert.uuid} occurred in the last {max_minutes_backwards} minutes ({alert.occurred}). Dropping."
+ )
+
+ return filtered_alerts
+
+
+def group_alerts(fetched_alerts):
+ alert_groups = set([alert.email_id for alert in fetched_alerts])
+ grouped_alerts = [
+ [alert for alert in fetched_alerts if alert.email_id == group]
+ for group in alert_groups
+ ]
+ # Sort groups by the occurred timeof the earliest alert in each group
+ return sorted(
+ grouped_alerts,
+ key=lambda alert_group: sorted(
+ alert_group, key=lambda alert: alert.occurred_time_unix
+ )[0].occurred_time_unix,
+ )
+
+
+def create_alert_info(environment_common, alerts_group):
+ sorted_alerts_group = sorted(
+ alerts_group, key=lambda alert: alert.occurred_time_unix
+ )
+
+ alert_info = AlertInfo()
+ alert_info.display_id = sorted_alerts_group[0].uuid
+ alert_info.ticket_id = sorted_alerts_group[0].uuid
+ alert_info.name = ALERT_NAME
+ alert_info.rule_generator = sorted_alerts_group[0].name
+ alert_info.priority = max([alert.priority for alert in alerts_group])
+ alert_info.start_time = sorted_alerts_group[0].occurred_time_unix
+ alert_info.end_time = sorted_alerts_group[-1].occurred_time_unix
+
+ alert_info.device_vendor = DEVICE_VENDOR
+ alert_info.device_product = DEVICE_PRODUCT
+
+ events = [alert.event for alert in sorted_alerts_group]
+ alert_info.events = list(map(dict_to_flat, events))
+ alert_info.environment = environment_common.get_environment(alert_info.events[0])
+
+ return alert_info
+
+
+@output_handler
+def main(is_test_run):
+ connector_starting_time = unix_now()
+ alerts = []
+ processed_alerts = []
+ siemplify = SiemplifyConnectorExecution()
+ siemplify.script_name = ALERTS_CONNECTOR_NAME
+
+ if is_test_run:
+ siemplify.LOGGER.info(
+ '***** This is an "IDE Play Button" "Run Connector once" test run ******'
+ )
+
+ siemplify.LOGGER.info("==================== Main - Param Init ====================")
+
+ environment_field = extract_connector_param(
+ siemplify,
+ param_name="Environment Field Name",
+ input_type=str,
+ is_mandatory=False,
+ print_value=True,
+ )
+
+ environment_regex = extract_connector_param(
+ siemplify,
+ param_name="Environment Regex Pattern",
+ input_type=str,
+ is_mandatory=False,
+ print_value=True,
+ )
+
+ api_root = extract_connector_param(
+ siemplify,
+ param_name="API Root",
+ input_type=str,
+ is_mandatory=True,
+ print_value=True,
+ )
+
+ username = extract_connector_param(
+ siemplify,
+ param_name="Username",
+ input_type=str,
+ is_mandatory=True,
+ print_value=True,
+ )
+
+ password = extract_connector_param(
+ siemplify,
+ param_name="Password",
+ input_type=str,
+ is_mandatory=True,
+ print_value=False,
+ )
+
+ verify_ssl = extract_connector_param(
+ siemplify,
+ param_name="Verify SSL",
+ input_type=bool,
+ is_mandatory=True,
+ print_value=True,
+ )
+
+ python_process_timeout = extract_connector_param(
+ siemplify,
+ param_name="PythonProcessTimeout",
+ input_type=int,
+ is_mandatory=True,
+ print_value=True,
+ )
+
+ max_hours_backwards = extract_connector_param(
+ siemplify,
+ param_name="Fetch Max Hours Backwards",
+ input_type=int,
+ default_value=1,
+ is_mandatory=False,
+ print_value=True,
+ )
+
+ if max_hours_backwards > 48:
+ warn_msg = '"Fetch Max Hours Backwards" Should be 48 or less due to API limitations. 48 will be used.'
+ siemplify.LOGGER.warn(warn_msg)
+ max_hours_backwards = 48
+
+ siemplify.LOGGER.info("------------------- Main - Started -------------------")
+
+ try:
+ environment_common = GetEnvironmentCommonFactory.create_environment_manager(
+ siemplify,
+ environment_field_name=environment_field,
+ environment_regex_pattern=environment_regex,
+ map_file=MAP_FILE,
+ )
+
+ last_success_time_datetime = get_last_success_time(
+ siemplify, offset_with_metric={"hours": max_hours_backwards}
+ )
+ siemplify.LOGGER.info(
+ f"Last success time: {last_success_time_datetime.strftime(PRINT_TIME_FORMAT)}"
+ )
+
+ # Read already existing alerts ids
+ siemplify.LOGGER.info("Loading existing ids from IDS file.")
+ existing_ids = read_ids_by_timestamp(
+ siemplify, offset_in_hours=HOURS_LIMIT_IN_IDS_FILE
+ )
+ siemplify.LOGGER.info(f"Found {len(existing_ids)} existing ids in ids.json")
+
+ siemplify.LOGGER.info("Connecting to FireEye EX.")
+ ex_manager = FireEyeEXManager(
+ api_root=api_root,
+ username=username,
+ password=password,
+ verify_ssl=verify_ssl,
+ )
+
+ siemplify.LOGGER.info("Fetching alerts.")
+
+ fetched_alerts = ex_manager.get_alerts(
+ duration=DURATION,
+ info_level="extended",
+ start_time=last_success_time_datetime,
+ )
+
+ siemplify.LOGGER.info(f"Found {len(fetched_alerts)} alerts.")
+
+ siemplify.LOGGER.info("Filtering already processed alerts")
+ new_ids = [alert.uuid for alert in fetched_alerts]
+ filtered_alerts_ids = filter_old_ids(new_ids, existing_ids)
+ filtered_alerts = [
+ alert for alert in fetched_alerts if alert.uuid in filtered_alerts_ids
+ ]
+ siemplify.LOGGER.info(f"Found {len(filtered_alerts)} new alerts")
+
+ siemplify.LOGGER.info("Filtering too recent alerts")
+ filtered_recent_alerts = filter_recent_alerts(siemplify, filtered_alerts, 5)
+ siemplify.LOGGER.info(f"Filtered to {len(filtered_recent_alerts)} alerts")
+
+ siemplify.LOGGER.info("Grouping alerts.")
+ grouped_alerts = group_alerts(filtered_recent_alerts)
+
+ siemplify.LOGGER.info(
+ f"Grouped into {len(grouped_alerts)} alert grouped based on subject, destination and sender"
+ )
+
+ for alert_group in grouped_alerts:
+ try:
+ if is_approaching_timeout(
+ connector_starting_time, python_process_timeout
+ ):
+ siemplify.LOGGER.info(
+ "Timeout is approaching. Connector will gracefully exit."
+ )
+ break
+
+ siemplify.LOGGER.info(
+ f"Processing alert group {alert_group[0].email_id}"
+ )
+ siemplify.LOGGER.info(
+ f"There are {len(alert_group)} alerts in this group"
+ )
+
+ existing_ids.update({alert.uuid: unix_now() for alert in alert_group})
+ processed_alerts.extend(alert_group)
+
+ is_overflowed = False
+ siemplify.LOGGER.info(
+ f"Creating AlertInfo for alert group {alert_group[0].email_id}"
+ )
+ alert_info = create_alert_info(environment_common, alert_group)
+
+ siemplify.LOGGER.info(
+ f"Finished creating AlertInfo for alert group {alert_group[0].email_id}"
+ )
+
+ try:
+ is_overflowed = siemplify.is_overflowed_alert(
+ environment=alert_info.environment,
+ alert_identifier=alert_info.ticket_id,
+ alert_name=alert_info.rule_generator,
+ product=alert_info.device_product,
+ )
+
+ except Exception as e:
+ error_msg = f"Failed to detect overflow for Alert Group {alert_group[0].email_id}"
+ siemplify.LOGGER.error(error_msg)
+ siemplify.LOGGER.exception(e)
+
+ if is_test_run:
+ raise
+
+ if is_overflowed:
+ siemplify.LOGGER.info(
+ f"{alert_info.rule_generator}-{alert_info.ticket_id}-{alert_info.environment}-{alert_info.device_product} found as overflow alert. Skipping..."
+ )
+ continue
+
+ else:
+ alerts.append(alert_info)
+ info_msg = f"Finished processing alert group {alert_group[0].email_id} was created."
+ siemplify.LOGGER.info(info_msg)
+
+ if is_test_run:
+ siemplify.LOGGER.info(
+ "This is a TEST run. Only 1 alert group will be processed."
+ )
+ break
+
+ except Exception as e:
+ siemplify.LOGGER.error(
+ f"Failed to process alert group {alert_group[0].email_id}"
+ )
+ siemplify.LOGGER.exception(e)
+
+ if is_test_run:
+ raise
+
+ if not is_test_run:
+ if filtered_alerts:
+ if processed_alerts:
+ # NOTICE - This logic might cause missed alerts. If the order of the EX alerts are:
+ # A A B B C C A A
+ # The after grouping the alert groups will be AAAA, BB, CC
+ # So if for some reason, only the first alert group was processed, then the timestamp that will
+ # be saved is the occurred time of the last A. Which means that in next iteration of the connector
+ # we will skip the B B C C EX alerts.
+ # Product team was notified but they decided that this is a rare situation, and that grouping
+ # feature is more important, and therefore we can take the risk.
+ new_timestamp = sorted(
+ processed_alerts, key=lambda alert: alert.occurred_time_unix
+ )[-1].occurred_time_unix
+ siemplify_save_timestamp(siemplify, new_timestamp)
+ siemplify.LOGGER.info(
+ f"New timestamp {convert_unixtime_to_datetime(new_timestamp).strftime(PRINT_TIME_FORMAT)} has been saved"
+ )
+
+ else:
+ if fetched_alerts:
+ # Alerts were found but none passed the existing ids filtering - this might mean that there are
+ # more than 200 alerts with the same timestamp, or that we got somehow into a loop.
+ # So to avoid looping forever, we will add 1 second to the timestamp to advance the timeline
+ siemplify.LOGGER.info(
+ "No new alerts were found. Timestamp will be increased by 1 second to avoid looping forever"
+ )
+ last_success_time_datetime += datetime.timedelta(minutes=1)
+ siemplify_save_timestamp(siemplify, last_success_time_datetime)
+ siemplify.LOGGER.info(
+ f"New timestamp {last_success_time_datetime.strftime(PRINT_TIME_FORMAT)} has been saved"
+ )
+ else:
+ siemplify.LOGGER.info(
+ "No alerts were fetched. Timestamp won't be updated."
+ )
+
+ write_ids_with_timestamp(siemplify, existing_ids)
+
+ siemplify.LOGGER.info(f"Created total of {len(alerts)} AlertInfos")
+
+ siemplify.LOGGER.info("------------------- Main - Finished -------------------")
+ siemplify.return_package(alerts)
+
+ except Exception as e:
+ siemplify.LOGGER.error(e)
+ siemplify.LOGGER.exception(e)
+
+ if is_test_run:
+ raise e
+
+
+if __name__ == "__main__":
+ is_test = not (len(sys.argv) < 2 or sys.argv[1] == "True")
+ main(is_test)
diff --git a/content/response_integrations/google/fire_eye_ex/connectors/FireEyeEXAlertsConnector.yaml b/content/response_integrations/google/fire_eye_ex/connectors/FireEyeEXAlertsConnector.yaml
new file mode 100644
index 000000000..d68b79af4
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/connectors/FireEyeEXAlertsConnector.yaml
@@ -0,0 +1,134 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+name: FireEye EX - Alerts Connector
+parameters:
+- name: DeviceProductField
+ default_value: Product Name
+ type: string
+ description: Enter the source field name in order to retrieve the Product Field
+ name.
+ is_mandatory: true
+ is_advanced: false
+ mode: regular
+- name: EventClassId
+ default_value: name
+ type: string
+ description: Enter the source field name in order to retrieve the Event Field
+ name.
+ is_mandatory: true
+ is_advanced: false
+ mode: regular
+- name: Environment Field Name
+ default_value: ''
+ type: string
+ description: 'Describes the name of the field where the environment name is stored.
+
+ If the environment field isn''t found, the environment is the default environment.
+
+ '
+ is_mandatory: false
+ is_advanced: false
+ mode: script
+- name: Environment Regex Pattern
+ default_value: .*
+ type: string
+ description: 'A regex pattern to run on the value found in the "Environment Field
+ Name" field.
+
+ Default is .* to catch all and return the value unchanged.
+
+ Used to allow the user to manipulate the environment field via regex logic.
+
+ If the regex pattern is null or empty, or the environment value is null, the
+ final environment result is the default environment.
+
+ '
+ is_mandatory: false
+ is_advanced: false
+ mode: script
+- name: PythonProcessTimeout
+ default_value: 180
+ type: integer
+ description: Timeout limit for the python process running the current script.
+ is_mandatory: true
+ is_advanced: false
+ mode: regular
+- name: API Root
+ default_value: https://x.x.x.x:x
+ type: string
+ description: API root of FireEye EX server.
+ is_mandatory: true
+ is_advanced: false
+ mode: script
+- name: Username
+ default_value: ''
+ type: string
+ description: Username of the FireEye EX account.
+ is_mandatory: true
+ is_advanced: false
+ mode: script
+- name: Password
+ default_value: ''
+ type: password
+ description: Password of the FireEye EX account.
+ is_mandatory: true
+ is_advanced: false
+ mode: script
+- name: Verify SSL
+ default_value: 'True'
+ type: boolean
+ description: If enabled, verify the SSL certificate for the connection to the
+ FireEye EX server is valid.
+ is_mandatory: true
+ is_advanced: false
+ mode: script
+- name: Fetch Max Hours Backwards
+ default_value: 1
+ type: integer
+ description: Number of hours before the first connector iteration to retrieve
+ alerts from. This parameter applies to the initial connector iteration after
+ you enable the connector for the first time, or used as a fallback value in
+ cases where connector's last run timestamp expires. Max supported value is
+ 48. This is the FireEye EX limitation.
+ is_mandatory: true
+ is_advanced: false
+ mode: regular
+- name: Proxy Server Address
+ default_value: ''
+ type: string
+ description: The address of the proxy server to use
+ is_mandatory: false
+ is_advanced: false
+ mode: script
+- name: Proxy Username
+ default_value: ''
+ type: string
+ description: The proxy username to authenticate with
+ is_mandatory: false
+ is_advanced: false
+ mode: script
+- name: Proxy Password
+ default_value: ''
+ type: password
+ description: The proxy password to authenticate with
+ is_mandatory: false
+ is_advanced: false
+ mode: script
+description: FireEye EX - Alerts Connector.
+integration: FireEyeEX
+documentation_link: null
+rules: []
+is_connector_rules_supported: false
+creator: admin
diff --git a/content/response_integrations/google/fire_eye_ex/connectors/__init__.py b/content/response_integrations/google/fire_eye_ex/connectors/__init__.py
new file mode 100644
index 000000000..9f71a2dc3
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/connectors/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
diff --git a/content/response_integrations/google/fire_eye_ex/core/FireEyeEXManager.py b/content/response_integrations/google/fire_eye_ex/core/FireEyeEXManager.py
new file mode 100644
index 000000000..462a45737
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/core/FireEyeEXManager.py
@@ -0,0 +1,357 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# ============================================================================#
+# title :FireEyeEXManager.py
+# description :This Module contain all FireEye EX operations functionality
+# author :avital@siemplify.co
+# date :18-06-2020
+# python_version :2.7
+# libreries :requests
+# requirments :
+# product_version :1.0
+# ============================================================================#
+
+# ============================= IMPORTS ===================================== #
+from __future__ import annotations
+import requests
+import os
+import defusedxml.ElementTree as ET
+
+from .FireEyeEXParser import FireEyeEXParser
+
+# ============================== CONSTS ===================================== #
+BASE_PATH = "{}/wsapis/{}"
+HEADERS = {"Content-type": "application/json"}
+API_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%f-00:00"
+
+# ============================= CLASSES ===================================== #
+
+
+class FireEyeEXManagerError(Exception):
+ """
+ General Exception for FireEye EX manager
+ """
+
+ pass
+
+
+class FireEyeEXNotFoundError(Exception):
+ """
+ Not Found Exception for FireEye EX manager
+ """
+
+ pass
+
+
+class FireEyeEXUnsuccessfulOperationError(Exception):
+ """
+ Unsuccessful operation exception for FireEye EX manager
+ """
+
+ pass
+
+
+class FireEyeEXDownloadFileError(Exception):
+ """
+ Unsuccessful download of a file exception for FireEye EX manager
+ """
+
+ pass
+
+
+class FireEyeEXManager:
+ """
+ FireEye EX Manager
+ """
+
+ def __init__(
+ self, api_root, username, password, version="v2.0.0", verify_ssl=False
+ ):
+ self.session = requests.Session()
+ self.session.verify = verify_ssl
+ self.session.headers = HEADERS
+ self.session.auth = (username, password)
+ self.api_root = BASE_PATH.format(
+ api_root[:-1] if api_root.endswith("/") else api_root, version
+ )
+ self.session.headers["X-FeApi-Token"] = self.get_token()
+ self.parser = FireEyeEXParser()
+
+ def get_token(self):
+ """
+ Get a token (equals to login)
+ """
+ url = f"{self.api_root}/auth/login"
+ response = self.session.post(url)
+ self.validate_response(response, "Unable to obtain token")
+ token = response.headers.get("X-FeApi-Token")
+
+ if not token:
+ raise FireEyeEXManagerError(
+ "Authentication failed. No X-FeApi-Token found."
+ )
+
+ return token
+
+ def test_connectivity(self):
+ """
+ Test connectivity to FireEye EX
+ :return: {bool} True if connection is successful, exception otherwise.
+ """
+ url = f"{self.api_root}/health/system"
+ response = self.session.get(url)
+ self.validate_response(response, "Unable to connect to the FireEye EX")
+ return True
+
+ def list_quarantined_emails(
+ self, limit=None, start_time=None, end_time=None, sender=None, subject=None
+ ):
+ """
+ Lists quarantined emails.
+ :param limit: {int} Number of records to return. Default - 10000.
+ :param start_time: {string} (YYYY-MM-DD'T'HH:MM:SS.SSS-HHMM). If specified, only emails that were created after
+ start time will be returned. If Start Time and End Time are not specified, action returns quarantined emails
+ from the last 24 hours.
+ :param end_time: {string} (YYYY-MM-DD'T'HH:MM:SS.SSS-HHMM). If specified, only emails that were created before
+ end time time will be returned. If Start Time and End Time are not specified, action returns quarantined
+ emails from the last 24 hours.
+ :param sender: {string} If specified, returns all of the quarantined emails only from this sender.
+ :param subject: {string} If specified, returns all of the quarantined emails only with this subject.
+ :return: {[QuarantinedEmail]} Found emails
+ """
+ url = f"{self.api_root}/emailmgmt/quarantine"
+
+ url_params = {
+ "limit": limit,
+ "subject": subject,
+ "sender": sender,
+ "start_time": start_time,
+ "end_time": end_time,
+ "from": sender,
+ }
+
+ # Remove None values
+ url_params = {k: v for k, v in list(url_params.items()) if v is not None}
+
+ response = self.session.get(url, params=url_params)
+ self.validate_response(response, "Unable to get quarantined emails")
+ return [
+ self.parser.build_siemplify_email_obj(email) for email in response.json()
+ ]
+
+ def release_quarantined_email(self, queue_id):
+ """
+ Release quarantined email based on queue ID.
+ :param queue_id: {str} The queue id
+ :return: {bool} True if successful, exception otherwise.
+ """
+ url = f"{self.api_root}/emailmgmt/quarantine/release"
+ response = self.session.post(url, json={"queue_ids": [queue_id]})
+ self.validate_response(response, f"Unable to release queue ID {queue_id}.")
+
+ if response.content:
+ try:
+ raise FireEyeEXUnsuccessfulOperationError(response.json()[queue_id])
+
+ except FireEyeEXUnsuccessfulOperationError:
+ raise
+
+ except Exception:
+ # Error is of unknown format
+ raise FireEyeEXUnsuccessfulOperationError(response.content)
+
+ return True
+
+ def delete_quarantined_email(self, queue_id):
+ """
+ Delete quarantined email based on queue ID.
+ :param queue_id: {str} The queue id
+ :return: {bool} True if successful, exception otherwise.
+ """
+ url = f"{self.api_root}/emailmgmt/quarantine/delete"
+ response = self.session.post(url, json={"queue_ids": [queue_id]})
+ self.validate_response(response, f"Unable to delete queue ID {queue_id}.")
+
+ if response.content:
+ try:
+ raise FireEyeEXUnsuccessfulOperationError(response.json()[queue_id])
+
+ except FireEyeEXUnsuccessfulOperationError:
+ raise
+
+ except Exception:
+ # Error is of unknown format
+ raise FireEyeEXUnsuccessfulOperationError(response.content)
+
+ return True
+
+ def download_quarantined_email(self, queue_id):
+ """
+ Download quarantined email based on queue ID.
+ :param queue_id: {str} The queue id
+ :return: {unicode} The content of the downloaded email.
+ """
+ url = f"{self.api_root}/emailmgmt/quarantine/{queue_id}"
+ response = self.session.get(url)
+ self.validate_response(response, f"Unable to download queue ID {queue_id}.")
+
+ content = response.content
+
+ try:
+ root = ET.fromstring(content)
+ message = root.find("message")
+
+ if message:
+ raise FireEyeEXUnsuccessfulOperationError(
+ message.text or response.content
+ )
+
+ raise FireEyeEXUnsuccessfulOperationError(response.content)
+
+ except FireEyeEXUnsuccessfulOperationError:
+ raise
+
+ except Exception:
+ # Response is valid - no XML (XML is error)
+ return response
+
+ def download_alert_artifacts(self, alert_uuid):
+ """
+ Download alert artifacts on alert UUID.
+ :param alert_uuid: {str} The alert UUID
+ :return: {unicode} The content of the downloaded zip of the alert's artifacts.
+ """
+ url = f"{self.api_root}/artifacts/{alert_uuid}"
+ response = self.session.get(url)
+ self.validate_response(
+ response, f"Unable to download artifacts for alert UUID {alert_uuid}."
+ )
+
+ return response
+
+ def logout(self):
+ """
+ Logout from FireEye HX
+ :return: {bool} True if successful, exception otherwise
+ """
+ url = f"{self.api_root}/auth/logout"
+ response = self.session.post(url)
+ self.validate_response(response, "Failed to logout with token")
+ return True
+
+ def get_alerts(self, duration="48_hours", info_level="extended", start_time=None):
+ """
+ Get alerts by filters
+ :param duration: {str} Specifies the time interval to search. This filter is used with either the start_time or
+ end_time filter. If duration, start time, and end time are not specified, the system defaults to
+ duration=48_hours, end_time=current_ time. If only duration is specified, the end_time defaults to the
+ current time. You cannot specify both a start_time filter and an end_time filter in the same request.
+ Syntax: duration=time_interval:
+ - 1_hour
+ - 2_hours
+ - 6_hours
+ - 12_hours
+ - 24_hours
+ - 48_hours
+ :param info_level: {str} Specifies the level of information to be returned. The default is concise.
+ - concise
+ - normal
+ - extended
+ :param start_time: {str} Specifies the start time of the search. This filter is used with the duration filter.
+ If the start_time is specified but not the duration, the system defaults to duration=12_hours, starting at
+ the specified start_time.
+ :return: {[Alert]} List of found alerts
+ """
+ url = f"{self.api_root}/alerts"
+
+ params = {"duration": duration, "info_level": info_level}
+
+ if start_time:
+ start_time = self._convert_datetime_to_api_format(start_time)
+ params.update({"start_time": start_time})
+
+ response = self.session.get(
+ url, params=params, headers={"Accept": "application/json"}
+ )
+ self.validate_response(response, "Unable to get alerts")
+
+ alerts_data = response.json().get("alert", [])
+ return [
+ self.parser.build_siemplify_alert_obj(alert_data)
+ for alert_data in alerts_data
+ ]
+
+ @staticmethod
+ def _convert_datetime_to_api_format(time):
+ """
+ Convert datetime object to the API time format of EX
+ :param time: {datetime.Datetime} The datetime object
+ :return: {unicode} The formatted time string
+ """
+ base_time, miliseconds_zone = time.strftime(API_TIME_FORMAT).split(".")
+ return f"{base_time}.{miliseconds_zone[:3] + miliseconds_zone[-6:]}"
+
+ @staticmethod
+ def validate_response(response, error_msg="An error occurred"):
+ """
+ Validate a response
+ :param response: {requests.Response} The response
+ :param error_msg: {unicode} The error message to display on failure
+ """
+ try:
+ response.raise_for_status()
+
+ except requests.HTTPError as error:
+ if response.content:
+ try:
+ root = ET.fromstring(response.content)
+ message = root.find("message")
+
+ if message:
+ raise FireEyeEXManagerError(message.text or response.content)
+
+ raise FireEyeEXManagerError(response.content)
+
+ except Exception:
+ try:
+ error_msg = response.json()["fireeyeapis"]["message"]
+ raise FireEyeEXManagerError(f"{error_msg}: {error} {error_msg}")
+
+ except FireEyeEXManagerError:
+ raise
+
+ except Exception:
+ raise FireEyeEXManagerError(
+ f"{error_msg}: {error} {response.content}"
+ )
+
+ raise FireEyeEXManagerError(f"{error_msg}: {error} {response.content}")
+
+ def save_artifacts_to_file(self, response, download_path):
+ """
+ Save raw data to a zip in defined path.
+ :param response: Download response.
+ :param download_path: Path to save the files.
+ :return: True if successful, exception otherwise
+ """
+ try:
+ if not os.path.exists(download_path):
+ with open(download_path, "wb") as f:
+ for chunk in response.iter_content():
+ f.write(chunk)
+ return True
+ return False
+ except Exception as e:
+ raise FireEyeEXDownloadFileError(e)
diff --git a/content/response_integrations/google/fire_eye_ex/core/FireEyeEXParser.py b/content/response_integrations/google/fire_eye_ex/core/FireEyeEXParser.py
new file mode 100755
index 000000000..c1faa700b
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/core/FireEyeEXParser.py
@@ -0,0 +1,54 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import annotations
+from .datamodels import QuarantinedEmail, Alert
+
+
+class FireEyeEXParser:
+ """
+ FireEye EX Transformation Layer.
+ """
+
+ @staticmethod
+ def build_siemplify_email_obj(email_data):
+ return QuarantinedEmail(
+ raw_data=email_data, sender=email_data.get("from"), **email_data
+ )
+
+ @staticmethod
+ def build_siemplify_alert_obj(alert_data):
+ return Alert(
+ raw_data=alert_data,
+ smtp_mail_from=alert_data.get("src", {}).get("smtpMailFrom"),
+ smtp_to=alert_data.get("dst", {}).get("smtpTo"),
+ malwares=alert_data.get("explanation", {})
+ .get("malwareDetected", {})
+ .get("malware", []),
+ url=alert_data.get("alertUrl"),
+ action=alert_data.get("action"),
+ occurred=alert_data.get("occurred"),
+ smtp_message_subject=alert_data.get("smtpMessage", {}).get("subject"),
+ appliance_id=alert_data.get("applianceId"),
+ id=alert_data.get("id"),
+ name=alert_data.get("name"),
+ retroactive=alert_data.get("retroactive"),
+ severity=alert_data.get("severity"),
+ uuid=alert_data.get("uuid"),
+ ack=alert_data.get("ack"),
+ product=alert_data.get("product"),
+ vlan=alert_data.get("vlan"),
+ malicious=alert_data.get("malicious"),
+ sc_version=alert_data.get("scVersion"),
+ )
diff --git a/content/response_integrations/google/fire_eye_ex/core/__init__.py b/content/response_integrations/google/fire_eye_ex/core/__init__.py
new file mode 100644
index 000000000..9f71a2dc3
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/core/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
diff --git a/content/response_integrations/google/fire_eye_ex/core/consts.py b/content/response_integrations/google/fire_eye_ex/core/consts.py
new file mode 100644
index 000000000..4e9bf1ced
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/core/consts.py
@@ -0,0 +1,26 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import annotations
+ALERTS_CONNECTOR_NAME = "FireEye EX - Alerts Connector"
+TIMEOUT_THRESHOLD = 0.9
+HOURS_LIMIT_IN_IDS_FILE = 72
+TEST_OFFSET_HOURS = 24
+DURATION = "48_hours"
+MAP_FILE = "map.json"
+IDS_FILE = "ids.json"
+DEVICE_VENDOR = "FireEye"
+DEVICE_PRODUCT = "FireEye EX"
+ALERT_NAME = "Malicious Email"
+PRINT_TIME_FORMAT = "%Y-%m-%d %H:%M:%S.%f"
diff --git a/content/response_integrations/google/fire_eye_ex/core/datamodels.py b/content/response_integrations/google/fire_eye_ex/core/datamodels.py
new file mode 100755
index 000000000..7e7fd1c6b
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/core/datamodels.py
@@ -0,0 +1,136 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import annotations
+from soar_sdk.SiemplifyUtils import convert_string_to_unix_time
+
+
+class QuarantinedEmail:
+ def __init__(
+ self,
+ raw_data,
+ email_uuid=None,
+ queue_id=None,
+ message_id=None,
+ completed_at=None,
+ timestamp=None,
+ sender=None,
+ subject=None,
+ appliance_id=None,
+ **kwargs
+ ):
+ self.raw_data = raw_data
+ self.email_uuid = email_uuid
+ self.queue_id = queue_id
+ self.message_id = message_id
+ self.completed_at = completed_at
+ self.timestamp = timestamp
+ self.sender = sender
+ self.subject = subject
+ self.appliance_id = appliance_id
+
+ def as_csv(self):
+ return {
+ "Sender": self.sender,
+ "Subject": self.subject,
+ "Completed At": self.completed_at or self.timestamp,
+ "Email UUID": self.email_uuid,
+ "Message ID": self.message_id,
+ "Queue ID": self.queue_id,
+ }
+
+
+class Alert:
+ def __init__(
+ self,
+ raw_data,
+ smtp_mail_from=None,
+ smtp_to=None,
+ malwares=None,
+ url=None,
+ action=None,
+ occurred=None,
+ smtp_message_subject=None,
+ appliance_id=None,
+ id=None,
+ name=None,
+ retroactive=None,
+ severity=None,
+ uuid=None,
+ ack=None,
+ product=None,
+ vlan=None,
+ malicious=None,
+ sc_version=None,
+ ):
+ self.raw_data = raw_data
+ self.smtp_mail_from = smtp_mail_from
+ self.smtp_to = smtp_to
+ self.malwares = malwares if malwares else []
+ self.url = url
+ self.action = action
+ self.occurred = occurred
+ self.smtp_message_subject = smtp_message_subject
+ self.appliance_id = appliance_id
+ self.id = id
+ self.name = name
+ self.retroactive = retroactive
+ self.severity = severity
+ self.uuid = uuid
+ self.ack = ack
+ self.product = product
+ self.vlan = vlan
+ self.malicious = malicious
+ self.sc_version = sc_version
+
+ @property
+ def priority(self):
+ if self.severity == "MAJR":
+ return 80
+ elif self.severity == "CRIT":
+ return 100
+
+ return 60
+
+ @property
+ def email_id(self):
+ return "-".join([self.smtp_message_subject, self.smtp_to, self.smtp_mail_from])
+
+ @property
+ def event(self):
+ event = {
+ "smtpTo": self.smtp_to,
+ "smtpMailFrom": self.smtp_mail_from,
+ "subject": self.smtp_message_subject,
+ "startTime": self.occurred_time_unix,
+ "endTime": self.occurred_time_unix,
+ "action": self.action,
+ "alert_uuid": self.uuid,
+ }
+
+ for malware in self.malwares:
+ if "type" not in malware:
+ event.update(malware)
+ else:
+ malware_type = malware["type"]
+ if not malware_type in event:
+ event[malware_type] = []
+
+ event[malware_type].append(malware)
+
+ return event
+
+ @property
+ def occurred_time_unix(self):
+ return convert_string_to_unix_time(self.occurred)
diff --git a/content/response_integrations/google/fire_eye_ex/definition.yaml b/content/response_integrations/google/fire_eye_ex/definition.yaml
new file mode 100644
index 000000000..d6e7793db
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/definition.yaml
@@ -0,0 +1,47 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+identifier: FireEyeEX
+name: FireEye EX
+parameters:
+- name: API Root
+ default_value: https://
:
+ type: url
+ description: ''
+ is_mandatory: true
+ integration_identifier: FireEyeEX
+- name: Username
+ default_value: ''
+ type: string
+ description: ''
+ is_mandatory: true
+ integration_identifier: FireEyeEX
+- name: Password
+ default_value: ''
+ type: password
+ description: ''
+ is_mandatory: true
+ integration_identifier: FireEyeEX
+- name: Verify SSL
+ default_value: ''
+ type: boolean
+ description: ''
+ is_mandatory: true
+ integration_identifier: FireEyeEX
+documentation_link: https://cloud.google.com/chronicle/docs/soar/marketplace-integrations/fireeye-ex
+categories:
+- Email Security
+- Security
+svg_logo_path: resources/logo.svg
+image_path: resources/image.png
diff --git a/content/response_integrations/google/fire_eye_ex/ontology_mapping.yaml b/content/response_integrations/google/fire_eye_ex/ontology_mapping.yaml
new file mode 100644
index 000000000..c9e332680
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/ontology_mapping.yaml
@@ -0,0 +1,406 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: SourceUserName
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: smtpMailFrom
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: false
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: DestinationUserName
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: smtpTo
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: false
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: SourceHostName
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: false
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: DestinationHostName
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: false
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: SourceDomain
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: true
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: DestinationDomain
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: true
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: SourceAddress
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: false
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: DestinationAddress
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: false
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: GenericEntity
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: false
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: ThreatSignature
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: true
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: ThreatCampaign
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: true
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: ThreatActor
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: true
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: CVE
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: true
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: PhoneNumber
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: true
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: CreditCard
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: true
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: SourceMacAddress
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: false
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: DestinationMacAddress
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: false
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: Deployment
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: true
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: USB
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: true
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: EmailSubject
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: subject
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: true
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: FileHash
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: md5Sum
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: sha256
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: true
+ extract_function_param: ','
+ extract_function: delimiter
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: FileName
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: true
+ extract_function_param: ','
+ extract_function: delimiter
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: DestinationURL
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: true
+ extract_function_param: ','
+ extract_function: delimiter
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: DestinationProcessName
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: true
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: SourceProcessName
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: ''
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: true
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: StartTime
+ transformation_function: from_unix_time_string_or_long
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: startTime
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: false
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: EndTime
+ transformation_function: from_unix_time_string_or_long
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: endTime
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: false
+ extract_function_param: ''
+ extract_function: none
+- source: FireEyeEX
+ product: FireEye EX
+ security_event_file_name: Name
+ transformation_function: to_string
+ transformation_function_param: ''
+ raw_data_primary_field_match_term: name
+ raw_data_primary_field_comparison_type: equal
+ raw_data_secondary_field_match_term: ''
+ raw_data_secondary_field_comparison_type: equal
+ raw_data_third_field_match_term: ''
+ raw_data_third_field_comparison_type: equal
+ is_artifact: false
+ extract_function_param: ''
+ extract_function: none
diff --git a/content/response_integrations/google/fire_eye_ex/pyproject.toml b/content/response_integrations/google/fire_eye_ex/pyproject.toml
new file mode 100644
index 000000000..548b5216f
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/pyproject.toml
@@ -0,0 +1,34 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+[project]
+name = "FireEyeEX"
+version = "14.0"
+description = "FireEye Email Security detects and blocks every kind of unwanted email, especially targeted advanced attacks. Time and again, this solution has proven itself capable of detecting corporate email threats in traffic accepted as safe by other products"
+requires-python = ">=3.11"
+dependencies = [ "arrow==1.3.0", "defusedxml==0.7.1", "requests==2.32.4", "tipcommon",]
+
+[dependency-groups]
+dev = [ "pytest>=9.0.3", "pytest-json-report>=1.5.0", "soar-sdk",]
+
+[tool.uv]
+[[tool.uv.index]]
+url = "https://pypi.org/simple"
+default = true
+
+[tool.uv.sources.tipcommon]
+path = "../../../../packages/tipcommon/whls/TIPCommon-1.0.12-py2.py3-none-any.whl"
+
+[tool.uv.sources.soar-sdk]
+git = "https://github.com/chronicle/soar-sdk.git"
diff --git a/content/response_integrations/google/fire_eye_ex/release_notes.yaml b/content/response_integrations/google/fire_eye_ex/release_notes.yaml
new file mode 100644
index 000000000..e7f34e040
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/release_notes.yaml
@@ -0,0 +1,169 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+- description: FireEye EX integration
+ integration_version: 1.0
+ item_name: FireEye EX
+ item_type: Integration
+ publish_time: '2020-06-18'
+ ticket_number: TIPG-3187
+ new: true
+ regressive: false
+ deprecated: false
+ removed: false
+- description: Added new parameter to actions "Download Alert Artifacts" and "Download
+ Quarantined Email", which allow users to define the download path, where the
+ action should save the files.
+ integration_version: 2.0
+ item_name: FireEye EX
+ item_type: Integration
+ publish_time: '2020-10-06'
+ ticket_number: TIPG-4344
+ new: false
+ regressive: false
+ deprecated: false
+ removed: false
+- description: ' Added integration support for the Playbook Simulator feature, allowing
+ you to build, test and edit your workflow logic in a pre-production environment.'
+ integration_version: 3.0
+ item_name: FireEye EX
+ item_type: Integration
+ publish_time: '2020-11-04'
+ ticket_number: TIPG-5303
+ new: false
+ regressive: false
+ deprecated: false
+ removed: false
+- description: Fixed a bug where the integration's SVG logo file was causing unexpected
+ behaviors in specific cases.
+ integration_version: 4.0
+ item_name: FireEye EX
+ item_type: Integration
+ publish_time: '2021-04-07'
+ ticket_number: TIPG-8062
+ new: false
+ regressive: false
+ deprecated: false
+ removed: false
+- description: Updated the integration's logo.
+ integration_version: 5.0
+ item_name: FireEye EX
+ item_type: Integration
+ publish_time: '2021-08-18'
+ ticket_number: TIPG-8868
+ new: false
+ regressive: false
+ deprecated: false
+ removed: false
+- description: Security enhancements throughout the integration
+ integration_version: 6.0
+ item_name: FireEye EX
+ item_type: Integration
+ publish_time: '2021-11-10'
+ ticket_number: TIPG-9841
+ new: false
+ regressive: false
+ deprecated: false
+ removed: false
+- description: Updated Integration's dependencies.
+ integration_version: 7.0
+ item_name: FireEye EX
+ item_type: Integration
+ publish_time: '2022-08-03'
+ ticket_number: TIPG-11787
+ new: false
+ regressive: false
+ deprecated: false
+ removed: false
+- description: 'Alerts Connector - Updated connector to better support Siemplify''s
+ SAAS deployment. Important - Before updating, please make sure to read our
+ white paper for stateless connectors here: https://cloud.google.com/chronicle/docs/soar/marketplace-integrations/stateless-connectors-white-paper.'
+ integration_version: 8.0
+ item_name: FireEyeEXAlertsConnector
+ item_type: Connector
+ publish_time: '2022-11-09'
+ ticket_number: TIPG-11948
+ new: false
+ regressive: false
+ deprecated: false
+ removed: false
+- description: 'FireEye EX integration - Important - Updated the integration code
+ to work with Python version 3.11. To ensure compatibility and avoid disruptions,
+ follow the upgrade best practices described in the following document: https://cloud.google.com/chronicle/docs/soar/respond/integrations-setup/upgrade-python-versions'
+ integration_version: 9.0
+ item_name: FireEyeEX
+ item_type: Integration
+ publish_time: '2024-07-14'
+ ticket_number: '336755007'
+ new: false
+ regressive: false
+ deprecated: false
+ removed: false
+- description: FireEye EX - Alerts Connector - Improved description for 'Fetch
+ Max Hours Backwards' parameter.
+ integration_version: 10.0
+ item_name: FireEye EX - Alerts Connector
+ item_type: Connector
+ publish_time: '2024-08-08'
+ ticket_number: '333133526'
+ new: false
+ regressive: false
+ deprecated: false
+ removed: false
+- description: Download Alert Artifacts, List Quarantined Emails, Download Quarantined
+ Email - Added Predefined Widgets.
+ integration_version: 11.0
+ item_name: Download Alert Artifacts, List Quarantined Emails, Download Quarantined
+ Email
+ item_type: Widget
+ publish_time: '2024-11-27'
+ ticket_number: '346749894'
+ new: true
+ regressive: false
+ deprecated: false
+ removed: false
+- description: List Quarantined Emails, Download Quarantined Email, Download Alert
+ Artifacts - Updated Predefined Widgets.
+ integration_version: 12.0
+ item_name: List Quarantined Emails, Download Quarantined Email, Download Alert
+ Artifacts
+ item_type: Widget
+ publish_time: '2026-03-12'
+ ticket_number: '487544122'
+ new: false
+ regressive: false
+ deprecated: false
+ removed: false
+- description: Updated integration metadata
+ integration_version: 13.0
+ item_name: FireEyeEX
+ item_type: Integration
+ publish_time: '2025-10-29'
+ ticket_number: ''
+ new: false
+ regressive: false
+ deprecated: false
+ removed: false
+
+- description: 'Integration - Source code for the integration is now available publicly
+ on Github. Link to repo: https://github.com/chronicle/content-hub'
+ integration_version: 14.0
+ item_name: FireEyeEX
+ item_type: Integration
+ publish_time: '2026-04-20'
+ new: false
+ regressive: false
+ deprecated: false
+ removed: false
+ ticket_number: '495762513'
diff --git a/content/response_integrations/google/fire_eye_ex/resources/ai/actions_ai_description.yaml b/content/response_integrations/google/fire_eye_ex/resources/ai/actions_ai_description.yaml
new file mode 100644
index 000000000..2911da0ad
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/resources/ai/actions_ai_description.yaml
@@ -0,0 +1,409 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+Delete Quarantined Email:
+ ai_description: >-
+ Deletes a specific quarantined email from the FireEye EX platform using its unique
+ Queue ID. This action is used to permanently remove emails that have been identified
+ as malicious or are no longer needed in the quarantine queue.
+
+
+ ### Parameters
+
+ | Parameter | Type | Mandatory | Description |
+
+ | --- | --- | --- | --- |
+
+ | Queue ID | String | Yes | The unique identifier of the email in the FireEye
+ EX quarantine queue that needs to be deleted. |
+
+
+ ### Flow Description
+
+ 1. **Initialization**: The action initializes the FireEye EX manager using the
+ provided API Root, Username, and Password.
+
+ 2. **Authentication**: It authenticates with the FireEye EX API to obtain a session
+ token.
+
+ 3. **Deletion**: It sends a POST request to the `/emailmgmt/quarantine/delete`
+ endpoint with the specified Queue ID.
+
+ 4. **Validation**: The action checks the API response to confirm if the deletion
+ was successful or if an error occurred (e.g., ID not found).
+
+ 5. **Cleanup**: It logs out of the FireEye EX session and returns the execution
+ status to Google SecOps.
+ capabilities:
+ can_create_case_comments: false
+ can_create_insight: false
+ can_modify_alert_data: false
+ can_mutate_external_data: true
+ can_mutate_internal_data: false
+ can_update_entities: false
+ external_data_mutation_explanation: >-
+ Permanently deletes an email record from the FireEye EX quarantine queue.
+ fetches_data: false
+ internal_data_mutation_explanation: null
+ categories:
+ enrichment: false
+ entity_usage:
+ entity_types: []
+ filters_by_additional_properties: false
+ filters_by_alert_identifier: false
+ filters_by_case_identifier: false
+ filters_by_creation_time: false
+ filters_by_entity_type: false
+ filters_by_identifier: false
+ filters_by_is_artifact: false
+ filters_by_is_enriched: false
+ filters_by_is_internal: false
+ filters_by_is_pivot: false
+ filters_by_is_suspicious: false
+ filters_by_is_vulnerable: false
+ filters_by_modification_time: false
+Download Alert Artifacts:
+ ai_description: >-
+ ### General Description
+
+ Downloads alert artifacts from FireEye EX for a specific alert identified by its
+ UUID. This action retrieves a ZIP file containing the artifacts, attaches it to
+ the case within Google SecOps, and saves the file to a specified local directory
+ on the execution environment.
+
+
+ ### Parameters Description
+
+ | Parameter | Type | Mandatory | Description |
+
+ | :--- | :--- | :--- | :--- |
+
+ | Alert UUID | String | Yes | The unique identifier (UUID) of the FireEye EX alert
+ from which to download artifacts. |
+
+ | Download Path | String | Yes | The local filesystem path where the action should
+ save the downloaded ZIP file. |
+
+
+ ### Additional Notes
+
+ - This action is specifically categorized as a download action and therefore is
+ not considered an enrichment action.
+
+ - If the file already exists at the specified `Download Path`, the action will
+ fail to save the file locally but may still succeed in attaching it to the case.
+
+
+ ### Flow Description
+
+ 1. **Authentication**: Connects to the FireEye EX API using provided credentials
+ and retrieves an API token.
+
+ 2. **Data Retrieval**: Calls the FireEye EX artifacts endpoint using the provided
+ `Alert UUID` to download the artifact ZIP content.
+
+ 3. **Case Attachment**: Encodes the ZIP content in Base64 and attaches it to the
+ Google SecOps case.
+
+ 4. **Local Storage**: Attempts to save the ZIP file to the local filesystem at
+ the location specified in the `Download Path` parameter.
+
+ 5. **Cleanup**: Logs out of the FireEye EX session.
+ capabilities:
+ can_create_case_comments: false
+ can_create_insight: false
+ can_modify_alert_data: false
+ can_mutate_external_data: false
+ can_mutate_internal_data: false
+ can_update_entities: false
+ external_data_mutation_explanation: null
+ fetches_data: true
+ internal_data_mutation_explanation: null
+ categories:
+ enrichment: false
+ entity_usage:
+ entity_types: []
+ filters_by_additional_properties: false
+ filters_by_alert_identifier: false
+ filters_by_case_identifier: false
+ filters_by_creation_time: false
+ filters_by_entity_type: false
+ filters_by_identifier: false
+ filters_by_is_artifact: false
+ filters_by_is_enriched: false
+ filters_by_is_internal: false
+ filters_by_is_pivot: false
+ filters_by_is_suspicious: false
+ filters_by_is_vulnerable: false
+ filters_by_modification_time: false
+Download Quarantined Email:
+ ai_description: >-
+ Downloads a quarantined email from FireEye EX based on a provided Queue ID. The
+ action retrieves the email content from the external system and integrates it
+ into the Google SecOps environment.
+
+
+ ### Parameters
+
+ | Parameter Name | Type | Mandatory | Description |
+
+ | :--- | :--- | :--- | :--- |
+
+ | Queue ID | String | Yes | The unique identifier of the email in the FireEye
+ EX quarantine queue that needs to be downloaded. |
+
+ | Download Path | String | No | The local directory path on the runner where the
+ action should save the .eml file. If left empty, the file is only attached to
+ the case and not saved to the disk. |
+
+
+ ### Flow Description
+
+ 1. **Authentication**: Connects to the FireEye EX API using provided credentials
+ and retrieves an API token.
+
+ 2. **Data Retrieval**: Calls the FireEye EX endpoint to fetch the raw content
+ of the quarantined email associated with the specified Queue ID.
+
+ 3. **Case Attachment**: Encodes the email content in Base64 and attaches it as
+ a file (with a .eml extension) to the current Google SecOps case.
+
+ 4. **Local Storage (Optional)**: If a 'Download Path' is provided, the action
+ attempts to save the email file to that specific location on the local file system.
+
+ 5. **Result Reporting**: Returns the local file path in the JSON results if saved
+ successfully and provides a status message regarding the attachment and download
+ status.
+ capabilities:
+ can_create_case_comments: false
+ can_create_insight: false
+ can_modify_alert_data: false
+ can_mutate_external_data: false
+ can_mutate_internal_data: true
+ can_update_entities: false
+ external_data_mutation_explanation: null
+ fetches_data: true
+ internal_data_mutation_explanation: >-
+ Adds the downloaded email as an attachment to the case and potentially saves
+ the file to the local disk of the execution environment.
+ categories:
+ enrichment: false
+ entity_usage:
+ entity_types: []
+ filters_by_additional_properties: false
+ filters_by_alert_identifier: false
+ filters_by_case_identifier: false
+ filters_by_creation_time: false
+ filters_by_entity_type: false
+ filters_by_identifier: false
+ filters_by_is_artifact: false
+ filters_by_is_enriched: false
+ filters_by_is_internal: false
+ filters_by_is_pivot: false
+ filters_by_is_suspicious: false
+ filters_by_is_vulnerable: false
+ filters_by_modification_time: false
+List Quarantined Emails:
+ ai_description: "### General Description\nThe **List Quarantined Emails** action\
+ \ retrieves a list of emails currently held in the FireEye EX quarantine. This\
+ \ investigative tool allows security analysts to search for and identify potentially\
+ \ malicious emails that have been isolated by the system. The action supports\
+ \ filtering by time range, sender, and subject line to narrow down results.\n\n\
+ ### Parameters Description\n| Parameter | Type | Mandatory | Description |\n|\
+ \ :--- | :--- | :--- | :--- |\n| **Start Time** | String | No | Only emails created\
+ \ after this time will be returned. Format: YYYY-MM-DD'T'HH:MM:SS.SSS-HHMM. |\n\
+ | **End Time** | String | No | Only emails created before this time will be returned.\
+ \ Format: YYYY-MM-DD'T'HH:MM:SS.SSS-HHMM. |\n| **Sender Filter** | String | No\
+ \ | If specified, returns only quarantined emails from this sender address. |\n\
+ | **Subject Filter** | String | No | If specified, returns only quarantined emails\
+ \ with this specific subject. |\n| **Max Email to Return** | Integer | No | Limits\
+ \ the number of records returned. The maximum limit is 10,000 per FireEye EX API\
+ \ constraints. |\n\n### Flow Description\n1. **Authentication**: The action authenticates\
+ \ with the FireEye EX API using the provided credentials to obtain a session token.\n\
+ 2. **Parameter Processing**: It extracts and validates the search filters (Start/End\
+ \ Time, Sender, Subject, and Limit).\n3. **Data Retrieval**: It executes a GET\
+ \ request to the `/emailmgmt/quarantine` endpoint on the FireEye EX appliance\
+ \ using the specified filters.\n4. **Result Formatting**: \n - If emails are\
+ \ found, it generates a data table named \"Quarantined Emails\" containing key\
+ \ details like Sender, Subject, and Queue ID.\n - It attaches the full raw\
+ \ data of the found emails as a JSON result.\n5. **Session Termination**: The\
+ \ action explicitly logs out of the FireEye EX API to ensure session security.\n\
+ \n### Additional Notes\n- If neither **Start Time** nor **End Time** is provided,\
+ \ the action defaults to returning quarantined emails from the last 24 hours.\n\
+ - This action does not require or process specific entities from the Google SecOps\
+ \ case; it performs a global search on the FireEye EX appliance."
+ capabilities:
+ can_create_case_comments: false
+ can_create_insight: false
+ can_modify_alert_data: false
+ can_mutate_external_data: false
+ can_mutate_internal_data: false
+ can_update_entities: false
+ external_data_mutation_explanation: null
+ fetches_data: true
+ internal_data_mutation_explanation: null
+ categories:
+ enrichment: false
+ entity_usage:
+ entity_types: []
+ filters_by_additional_properties: false
+ filters_by_alert_identifier: false
+ filters_by_case_identifier: false
+ filters_by_creation_time: false
+ filters_by_entity_type: false
+ filters_by_identifier: false
+ filters_by_is_artifact: false
+ filters_by_is_enriched: false
+ filters_by_is_internal: false
+ filters_by_is_pivot: false
+ filters_by_is_suspicious: false
+ filters_by_is_vulnerable: false
+ filters_by_modification_time: false
+Ping:
+ ai_description: >-
+ ### General Description
+
+ Tests the connectivity between Google SecOps and the FireEye EX instance using
+ the provided configuration parameters. This action ensures that the API root,
+ credentials, and network settings are correct by attempting a login and subsequent
+ logout.
+
+
+ ### Parameters Description
+
+ | Parameter | Type | Mandatory | Description |
+
+ | :--- | :--- | :--- | :--- |
+
+ | API Root | String | Yes | The base URL of the FireEye EX server. |
+
+ | Username | String | Yes | The username used for authentication. |
+
+ | Password | String | Yes | The password used for authentication. |
+
+ | Verify SSL | Boolean | No | If enabled, the action will verify the SSL certificate
+ of the server. Default is False. |
+
+
+ ### Additional Notes
+
+ This action is typically used during the initial setup of the integration to verify
+ that the environment can communicate with the FireEye EX API. It does not process
+ any entities.
+
+
+ ### Flow Description
+
+ 1. **Parameter Extraction**: Retrieves the API Root, Username, Password, and SSL
+ verification settings from the integration configuration.
+
+ 2. **Authentication**: Initializes the FireEye EX Manager, which automatically
+ performs a POST request to the `/auth/login` endpoint to retrieve an API token.
+
+ 3. **Session Termination**: Calls the logout method, which performs a POST request
+ to the `/auth/logout` endpoint to invalidate the session token.
+
+ 4. **Result Reporting**: If both steps succeed, the action reports a successful
+ connection. If any step fails (e.g., invalid credentials or unreachable URL),
+ it catches the exception and reports a failure.
+ capabilities:
+ can_create_case_comments: false
+ can_create_insight: false
+ can_modify_alert_data: false
+ can_mutate_external_data: false
+ can_mutate_internal_data: false
+ can_update_entities: false
+ external_data_mutation_explanation: null
+ fetches_data: false
+ internal_data_mutation_explanation: null
+ categories:
+ enrichment: false
+ entity_usage:
+ entity_types: []
+ filters_by_additional_properties: false
+ filters_by_alert_identifier: false
+ filters_by_case_identifier: false
+ filters_by_creation_time: false
+ filters_by_entity_type: false
+ filters_by_identifier: false
+ filters_by_is_artifact: false
+ filters_by_is_enriched: false
+ filters_by_is_internal: false
+ filters_by_is_pivot: false
+ filters_by_is_suspicious: false
+ filters_by_is_vulnerable: false
+ filters_by_modification_time: false
+Release Quarantined Email:
+ ai_description: >-
+ Releases a quarantined email from the FireEye EX platform using a specific Queue
+ ID. This action is used to deliver emails that were previously flagged and held
+ in quarantine by the FireEye EX appliance.
+
+
+ ### Parameters
+
+ | Parameter | Type | Mandatory | Description |
+
+ | :--- | :--- | :--- | :--- |
+
+ | Queue ID | String | Yes | The unique identifier of the email in the FireEye
+ EX quarantine queue that needs to be released. |
+
+
+ ### Flow Description
+
+ 1. **Initialization**: The action retrieves the FireEye EX connection details
+ (API Root, Username, Password) and the target Queue ID.
+
+ 2. **Authentication**: Connects to the FireEye EX API to obtain an authentication
+ token.
+
+ 3. **Release Request**: Sends a POST request to the FireEye EX management endpoint
+ to release the email associated with the provided Queue ID.
+
+ 4. **Validation**: Checks the response from the API to ensure the email was successfully
+ released. If the API returns an error message for the specific ID, the action
+ fails.
+
+ 5. **Cleanup**: Logs out of the FireEye EX session and reports the final status
+ to the SOAR.
+ capabilities:
+ can_create_case_comments: false
+ can_create_insight: false
+ can_modify_alert_data: false
+ can_mutate_external_data: true
+ can_mutate_internal_data: false
+ can_update_entities: false
+ external_data_mutation_explanation: >-
+ Changes the state of an email in FireEye EX from 'quarantined' to 'released',
+ allowing the email to be delivered to its recipient.
+ fetches_data: false
+ internal_data_mutation_explanation: null
+ categories:
+ enrichment: false
+ entity_usage:
+ entity_types: []
+ filters_by_additional_properties: false
+ filters_by_alert_identifier: false
+ filters_by_case_identifier: false
+ filters_by_creation_time: false
+ filters_by_entity_type: false
+ filters_by_identifier: false
+ filters_by_is_artifact: false
+ filters_by_is_enriched: false
+ filters_by_is_internal: false
+ filters_by_is_pivot: false
+ filters_by_is_suspicious: false
+ filters_by_is_vulnerable: false
+ filters_by_modification_time: false
diff --git a/content/response_integrations/google/fire_eye_ex/resources/download_alert_artifacts_JsonResult_example.json b/content/response_integrations/google/fire_eye_ex/resources/download_alert_artifacts_JsonResult_example.json
new file mode 100644
index 000000000..4f01144bb
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/resources/download_alert_artifacts_JsonResult_example.json
@@ -0,0 +1,5 @@
+[
+ {
+ "file_path": "/tmp/Alert_Artifacts_19d1e07a-2376-4fde-977c-87888e7xxx.zip"
+ }
+]
\ No newline at end of file
diff --git a/content/response_integrations/google/fire_eye_ex/resources/download_quarantined_email_JsonResult_example.json b/content/response_integrations/google/fire_eye_ex/resources/download_quarantined_email_JsonResult_example.json
new file mode 100644
index 000000000..83c0560a0
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/resources/download_quarantined_email_JsonResult_example.json
@@ -0,0 +1,5 @@
+[
+ {
+ "file_path": "/tmp/Quarantined_email_2376-4fde-977c-87888e7xxx.eml"
+ }
+]
\ No newline at end of file
diff --git a/content/response_integrations/google/fire_eye_ex/resources/image.png b/content/response_integrations/google/fire_eye_ex/resources/image.png
new file mode 100644
index 000000000..e8a27aae8
Binary files /dev/null and b/content/response_integrations/google/fire_eye_ex/resources/image.png differ
diff --git a/content/response_integrations/google/fire_eye_ex/resources/list_quarantined_emails_JsonResult_example.json b/content/response_integrations/google/fire_eye_ex/resources/list_quarantined_emails_JsonResult_example.json
new file mode 100644
index 000000000..fe9f37623
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/resources/list_quarantined_emails_JsonResult_example.json
@@ -0,0 +1,11 @@
+[
+ {
+ "from": "test.user1@fex2-lab.local",
+ "completed_at": "2020-06-03T15:39:15",
+ "quarantine_path": "/data/email-analysis/quarantine2/2020-06-03/15/49cY3l0dK9zxNgJ",
+ "queue_id": "49cY3l0dK9zxNgJ",
+ "email_uuid": "5f89bf79-32c7-4c61-86ac-f825dd4c6f4a",
+ "message_id": "274ebe82-8576-1ac8-491c-de03e080be89@fex2-lab.local",
+ "subject": "Yura"
+ }
+]
\ No newline at end of file
diff --git a/content/response_integrations/google/fire_eye_ex/resources/logo.svg b/content/response_integrations/google/fire_eye_ex/resources/logo.svg
new file mode 100644
index 000000000..24ad40e91
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/resources/logo.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/content/response_integrations/google/fire_eye_ex/tests/__init__.py b/content/response_integrations/google/fire_eye_ex/tests/__init__.py
new file mode 100644
index 000000000..9f71a2dc3
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/tests/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
diff --git a/content/response_integrations/google/fire_eye_ex/tests/common.py b/content/response_integrations/google/fire_eye_ex/tests/common.py
new file mode 100644
index 000000000..cb340e5ef
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/tests/common.py
@@ -0,0 +1,21 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import annotations
+import pathlib
+import json
+from integration_testing.common import get_def_file_content
+INTEGRATION_PATH: pathlib.Path = pathlib.Path(__file__).parent.parent
+CONFIG_PATH: pathlib.Path = pathlib.Path(__file__).parent / 'config.json'
+CONFIG: dict = get_def_file_content(CONFIG_PATH) if CONFIG_PATH.exists() else {}
\ No newline at end of file
diff --git a/content/response_integrations/google/fire_eye_ex/tests/config.json b/content/response_integrations/google/fire_eye_ex/tests/config.json
new file mode 100644
index 000000000..e509905da
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/tests/config.json
@@ -0,0 +1,6 @@
+{
+ "API Root": "https://:",
+ "Username": "",
+ "Password": "",
+ "Verify SSL": ""
+}
\ No newline at end of file
diff --git a/content/response_integrations/google/fire_eye_ex/tests/test_defaults/__init__.py b/content/response_integrations/google/fire_eye_ex/tests/test_defaults/__init__.py
new file mode 100644
index 000000000..9f71a2dc3
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/tests/test_defaults/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
diff --git a/content/response_integrations/google/fire_eye_ex/tests/test_defaults/test_imports.py b/content/response_integrations/google/fire_eye_ex/tests/test_defaults/test_imports.py
new file mode 100644
index 000000000..1243de833
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/tests/test_defaults/test_imports.py
@@ -0,0 +1,57 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import annotations
+
+import importlib
+import pathlib
+
+from .. import common
+
+
+VALID_SUFFIXES = (".py",)
+
+
+def import_all_integration_modules(integration: pathlib.Path) -> None:
+ if not integration.exists():
+ msg: str = f"Cannot find integration {integration.name}"
+ raise AssertionError(msg)
+
+ imports: list[str] = _get_integration_modules_import_strings(integration)
+ for import_ in imports:
+ importlib.import_module(import_)
+
+
+def _get_integration_modules_import_strings(integration: pathlib.Path) -> list[str]:
+ results: list[str] = []
+ for package in integration.iterdir():
+ if not package.is_dir():
+ continue
+
+ for module in package.iterdir():
+ if not module.is_file() or module.suffix not in VALID_SUFFIXES:
+ continue
+
+ import_: str = _get_import_string(integration.stem, package.stem, module.stem)
+ results.append(import_)
+
+ return results
+
+
+def _get_import_string(integration: str, package: str, module: str) -> str:
+ return f"{integration}.{package}.{module}"
+
+
+def test_imports() -> None:
+ import_all_integration_modules(common.INTEGRATION_PATH)
diff --git a/content/response_integrations/google/fire_eye_ex/uv.lock b/content/response_integrations/google/fire_eye_ex/uv.lock
new file mode 100644
index 000000000..09e4ed378
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/uv.lock
@@ -0,0 +1,592 @@
+version = 1
+revision = 3
+requires-python = ">=3.11"
+
+[[package]]
+name = "arrow"
+version = "1.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "python-dateutil" },
+ { name = "types-python-dateutil" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/2e/00/0f6e8fcdb23ea632c866620cc872729ff43ed91d284c866b515c6342b173/arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85", size = 131960, upload-time = "2023-09-30T22:11:18.25Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80", size = 66419, upload-time = "2023-09-30T22:11:16.072Z" },
+]
+
+[[package]]
+name = "certifi"
+version = "2026.2.25"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" },
+]
+
+[[package]]
+name = "cffi"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pycparser", marker = "implementation_name != 'PyPy'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" },
+ { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" },
+ { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" },
+ { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" },
+ { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" },
+ { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" },
+ { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" },
+ { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" },
+ { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" },
+ { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" },
+ { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" },
+ { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" },
+ { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" },
+ { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" },
+ { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" },
+ { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" },
+ { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" },
+ { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" },
+ { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" },
+ { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
+]
+
+[[package]]
+name = "chardet"
+version = "7.4.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/19/b6/9df434a8eeba2e6628c465a1dfa31034228ef79b26f76f46278f4ef7e49d/chardet-7.4.3.tar.gz", hash = "sha256:cc1d4eb92a4ec1c2df3b490836ffa46922e599d34ce0bb75cf41fd2bf6303d56", size = 784800, upload-time = "2026-04-13T21:33:39.803Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/19/52/505c207f334d51e937cbaa27ff95776e16e2d120e13cbe491cd7b3a70b50/chardet-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:25a862cddc6a9ac07023e808aedd297115345fbaabc2690479481ddc0f980e09", size = 870747, upload-time = "2026-04-13T21:32:56.916Z" },
+ { url = "https://files.pythonhosted.org/packages/14/4b/d3c79495dee4831b8bebca2790e72cb90f0c5849c940570a7c7e5b70b952/chardet-7.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7005c88da26fd95d8abb8acbe6281d833e9a9181b03cf49b4546c4555389bd97", size = 853210, upload-time = "2026-04-13T21:32:58.309Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/99/f6a822ad1bde25a4c38dc3e770485e78e0893dfd871cd6e18ed3ea3a795e/chardet-7.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc50f28bad067393cce0af9091052c3b8df7a23115afd8ba7b2e0947f0cef1f8", size = 873625, upload-time = "2026-04-13T21:32:59.606Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/10/31932775c94a86814f76b41c4a772b52abfb0e6125324f32c6da1196c297/chardet-7.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3da294de1a681097848ab58bd3f2771a674f8039d2d87a5538b28856b815e9", size = 883436, upload-time = "2026-04-13T21:33:01.351Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/63/0f43e3acf2c436fdb32a0f904aeb03a2904d2126eed34a042a194d235926/chardet-7.4.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:93c45e116dd51b66226a53ade3f9f635e870de5399b90e00ce45dcc311093bf4", size = 876589, upload-time = "2026-04-13T21:33:02.636Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/a6/e9b8f8a3e99602792b01fa7d0a731737615ab56d8bfd0b52935a0ef88b85/chardet-7.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:ccc1f83ab4bcfb901cf39e0c4ba6bc6e726fc6264735f10e24ceb5cb47387578", size = 941866, upload-time = "2026-04-13T21:33:04.282Z" },
+ { url = "https://files.pythonhosted.org/packages/61/33/29de185079e6675c3f375546e30a559b7ddc75ce972f18d6e566cd9ea4eb/chardet-7.4.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:75d3c65cc16bddf40b8da1fd25ba84fca5f8070f2b14e86083653c1c85aee971", size = 874870, upload-time = "2026-04-13T21:33:05.977Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/2f/4c5af01fd1a7506a1d5375403d68925eac70289229492db5aa68b58103d8/chardet-7.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:29af5999f654e8729d251f1724a62b538b1262d9292cccaefddf8a02aae1ef6a", size = 854859, upload-time = "2026-04-13T21:33:07.381Z" },
+ { url = "https://files.pythonhosted.org/packages/36/21/edb36ad5dfa48d7f8eed97ab43931ecdaa8c15166c21b1d614967e49d681/chardet-7.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:626f00299ad62dfe937058a09572beed442ccc7b58f87aa667949b20fd3db235", size = 875032, upload-time = "2026-04-13T21:33:08.741Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/59/a32a241d861cf180853a11c8e5a67641cb1b2af13c3a5ccce83ec07e2c9f/chardet-7.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9a4904dd5f071b7a7d7f50b4a67a86db3c902d243bf31708f1d5cde2f68239cb", size = 888283, upload-time = "2026-04-13T21:33:10.213Z" },
+ { url = "https://files.pythonhosted.org/packages/87/2e/e1ee6a77abf3782c00e05b89c4d4328c8353bf9500661c4348df1dd68614/chardet-7.4.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5d2879598bc220689e8ce509fe9c3f37ad2fca53a36be9c9bd91abdd91dd364f", size = 879974, upload-time = "2026-04-13T21:33:11.448Z" },
+ { url = "https://files.pythonhosted.org/packages/32/60/fca69c534602a7ced04280c952a246ad1edde2a6ca3a164f65d32ac41fe7/chardet-7.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:4b2799bd58e7245cfa8d4ab2e8ad1d76a5c3a5b1f32318eb6acca4c69a3e7101", size = 943973, upload-time = "2026-04-13T21:33:12.756Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/43/79ac9b4db5bc87020c9dbc419125371d80882d1d197e9c4765ba8682b605/chardet-7.4.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a9e4486df251b8962e86ea9f139ca235aa6e0542a00f7844c9a04160afb99aa9", size = 873769, upload-time = "2026-04-13T21:33:14.002Z" },
+ { url = "https://files.pythonhosted.org/packages/55/5f/25bdec773905bff0ff6cf35ca73b17bd05593b4f87bd8c5fa43705f7167d/chardet-7.4.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4fbff1907925b0c5a1064cffb5e040cd5e338585c9c552625f30de6bc2f3107a", size = 853991, upload-time = "2026-04-13T21:33:15.564Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/07/a29380ee0b215d23d77733b5ad60c5c0c7969650e080c667acdf9462040d/chardet-7.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:365135eaf37ba65a828f8e668eb0a8c38c479dcbec724dc25f4dfd781049c357", size = 874024, upload-time = "2026-04-13T21:33:16.915Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/b1/3338e121cbd4c8a126b8ccb1061170c2ce51a53f678c502793ea49c6fd6d/chardet-7.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfc134b70c846c21ead8e43ada3ae1a805fff732f6922f8abcf2ff27b8f6493d", size = 887410, upload-time = "2026-04-13T21:33:18.368Z" },
+ { url = "https://files.pythonhosted.org/packages/63/1c/44a9a9e0c59c185a5d307ceaeee8768afa1558f0a24f7a4b5fa11b67586b/chardet-7.4.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9acd9988a93e09390f3cd231201ea7166c415eb8da1b735928990ffc05cb9fbb", size = 879269, upload-time = "2026-04-13T21:33:20.377Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/b3/5d0e77ea774bd3224321c248880ea0c0379000ac5c2bb6d77609549de247/chardet-7.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:e1b98790c284ff813f18f7cf7de5f05ea2435a080030c7f1a8318f3a4f80b131", size = 944155, upload-time = "2026-04-13T21:33:21.694Z" },
+ { url = "https://files.pythonhosted.org/packages/70/a8/bf0811d859e13801279a2ae64f37a408027b282f2047bc0001c75dd356ad/chardet-7.4.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d892d3dcd652fdef53e3d6327d39b17c0df40a899dfc919abaeb64c974497531", size = 872887, upload-time = "2026-04-13T21:33:23.328Z" },
+ { url = "https://files.pythonhosted.org/packages/51/ac/b9d68ebddfe1b02c77af5bf81120e12b036b4432dc6af7a303d90e2bc38b/chardet-7.4.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:acc46d1b8b7d5783216afe15db56d1c179b9a40e5a1558bc13164c4fd20674c4", size = 853964, upload-time = "2026-04-13T21:33:24.724Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/81/17fa103ea9caf5d325a5e4051ab2ba65996fd66baa60b81ee41af1f54e10/chardet-7.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ac3bf11c645734a1701a3804e43eabd98851838192267d08c353a834ab79fea", size = 876006, upload-time = "2026-04-13T21:33:26.098Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/20/193faab46a68ea550587331a698c3dca8099f8901d10937c4443135c7ed9/chardet-7.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e3bd9f936e04bae89c254262af08d9e5b98f805175ba1e29d454e6cba3107b7", size = 887680, upload-time = "2026-04-13T21:33:27.49Z" },
+ { url = "https://files.pythonhosted.org/packages/40/c6/94a3c673327392652ee8bdea9a45bc8a5f5365197a7387d68f0eed007115/chardet-7.4.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:27cc23da03630cdecc9aa81a895aa86629c211f995cd57651f0fbc280717bf93", size = 879865, upload-time = "2026-04-13T21:33:29.052Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/2c/cad8b5e3623a987f3c930b68e2bdd06cfc388cd91cd42ed05f1227701b73/chardet-7.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:b95c934b9ad59e2ba8abb9be49df70d3ad1b0d95d864b9fdb7588d4fa8bd921c", size = 939594, upload-time = "2026-04-13T21:33:31.391Z" },
+ { url = "https://files.pythonhosted.org/packages/33/e0/d06e42fd6f02a58e5e227e5106587751cb38adcff0aaf949add744b78b6e/chardet-7.4.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c77867f0c1cb8bd819502249fcdc500364aedb07881e11b743726fa2148e7b6e", size = 889714, upload-time = "2026-04-13T21:33:32.772Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/ed/40d091954d48abea037baae6be8fb79905e5f78d34d12ea955132c7d8011/chardet-7.4.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cf1efeaf65a6ef2f5b9cc3a1df6f08ba2831b369ccaa4c7018eaf90aa757bb11", size = 872319, upload-time = "2026-04-13T21:33:34.427Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/77/82a46821dbfbdfe062710d2bf2ede13426304e3567a23c57d919c0c31630/chardet-7.4.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f3504c139a2ad544077dd2d9e412cd08b01786843d76997cd43bb6de311723c", size = 892021, upload-time = "2026-04-13T21:33:35.766Z" },
+ { url = "https://files.pythonhosted.org/packages/49/57/42d30c562bda5b4a839766c1aad8d5856b798ad2a1c3247b72a679afec94/chardet-7.4.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457f619882ba66327d4d8d14c6c342269bdb1e4e1c38e8117df941d14d351b04", size = 902509, upload-time = "2026-04-13T21:33:37.096Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/6c/0a40afdb50a0fe041ab95553b835a8160b6cf0e81edf2ae2fe9f5224cbf9/chardet-7.4.3-py3-none-any.whl", hash = "sha256:1173b74051570cf08099d7429d92e4882d375ad4217f92a6e5240ccfb26f231e", size = 626562, upload-time = "2026-04-13T21:33:38.559Z" },
+]
+
+[[package]]
+name = "charset-normalizer"
+version = "3.4.7"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7", size = 309705, upload-time = "2026-04-02T09:26:02.191Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/53/58c29116c340e5456724ecd2fff4196d236b98f3da97b404bc5e51ac3493/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7", size = 206419, upload-time = "2026-04-02T09:26:03.583Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/02/e8146dc6591a37a00e5144c63f29fb7c97a734ea8a111190783c0e60ab63/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e", size = 227901, upload-time = "2026-04-02T09:26:04.738Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/73/77486c4cd58f1267bf17db420e930c9afa1b3be3fe8c8b8ebbebc9624359/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c", size = 222742, upload-time = "2026-04-02T09:26:06.36Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/fa/f74eb381a7d94ded44739e9d94de18dc5edc9c17fb8c11f0a6890696c0a9/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df", size = 214061, upload-time = "2026-04-02T09:26:08.347Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/92/42bd3cefcf7687253fb86694b45f37b733c97f59af3724f356fa92b8c344/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265", size = 199239, upload-time = "2026-04-02T09:26:09.823Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/3d/069e7184e2aa3b3cddc700e3dd267413dc259854adc3380421c805c6a17d/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4", size = 210173, upload-time = "2026-04-02T09:26:10.953Z" },
+ { url = "https://files.pythonhosted.org/packages/62/51/9d56feb5f2e7074c46f93e0ebdbe61f0848ee246e2f0d89f8e20b89ebb8f/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e", size = 209841, upload-time = "2026-04-02T09:26:12.142Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/59/893d8f99cc4c837dda1fe2f1139079703deb9f321aabcb032355de13b6c7/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38", size = 200304, upload-time = "2026-04-02T09:26:13.711Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/1d/ee6f3be3464247578d1ed5c46de545ccc3d3ff933695395c402c21fa6b77/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c", size = 229455, upload-time = "2026-04-02T09:26:14.941Z" },
+ { url = "https://files.pythonhosted.org/packages/54/bb/8fb0a946296ea96a488928bdce8ef99023998c48e4713af533e9bb98ef07/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b", size = 210036, upload-time = "2026-04-02T09:26:16.478Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/bc/015b2387f913749f82afd4fcba07846d05b6d784dd16123cb66860e0237d/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c", size = 224739, upload-time = "2026-04-02T09:26:17.751Z" },
+ { url = "https://files.pythonhosted.org/packages/17/ab/63133691f56baae417493cba6b7c641571a2130eb7bceba6773367ab9ec5/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d", size = 216277, upload-time = "2026-04-02T09:26:18.981Z" },
+ { url = "https://files.pythonhosted.org/packages/06/6d/3be70e827977f20db77c12a97e6a9f973631a45b8d186c084527e53e77a4/charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad", size = 147819, upload-time = "2026-04-02T09:26:20.295Z" },
+ { url = "https://files.pythonhosted.org/packages/20/d9/5f67790f06b735d7c7637171bbfd89882ad67201891b7275e51116ed8207/charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00", size = 159281, upload-time = "2026-04-02T09:26:21.74Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/83/6413f36c5a34afead88ce6f66684d943d91f233d76dd083798f9602b75ae/charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1", size = 147843, upload-time = "2026-04-02T09:26:22.901Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328, upload-time = "2026-04-02T09:26:24.331Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061, upload-time = "2026-04-02T09:26:25.568Z" },
+ { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031, upload-time = "2026-04-02T09:26:26.865Z" },
+ { url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", size = 225239, upload-time = "2026-04-02T09:26:28.044Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", size = 216589, upload-time = "2026-04-02T09:26:29.239Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", size = 202733, upload-time = "2026-04-02T09:26:30.5Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", size = 212652, upload-time = "2026-04-02T09:26:31.709Z" },
+ { url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", size = 211229, upload-time = "2026-04-02T09:26:33.282Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", size = 203552, upload-time = "2026-04-02T09:26:34.845Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", size = 230806, upload-time = "2026-04-02T09:26:36.152Z" },
+ { url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", size = 212316, upload-time = "2026-04-02T09:26:37.672Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", size = 227274, upload-time = "2026-04-02T09:26:38.93Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", size = 218468, upload-time = "2026-04-02T09:26:40.17Z" },
+ { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", size = 148460, upload-time = "2026-04-02T09:26:41.416Z" },
+ { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", size = 159330, upload-time = "2026-04-02T09:26:42.554Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", size = 147828, upload-time = "2026-04-02T09:26:44.075Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", size = 309627, upload-time = "2026-04-02T09:26:45.198Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", size = 207008, upload-time = "2026-04-02T09:26:46.824Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", size = 228303, upload-time = "2026-04-02T09:26:48.397Z" },
+ { url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", size = 224282, upload-time = "2026-04-02T09:26:49.684Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", size = 215595, upload-time = "2026-04-02T09:26:50.915Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", size = 201986, upload-time = "2026-04-02T09:26:52.197Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", size = 211711, upload-time = "2026-04-02T09:26:53.49Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", size = 210036, upload-time = "2026-04-02T09:26:54.975Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", size = 202998, upload-time = "2026-04-02T09:26:56.303Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", size = 230056, upload-time = "2026-04-02T09:26:57.554Z" },
+ { url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", size = 211537, upload-time = "2026-04-02T09:26:58.843Z" },
+ { url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", size = 226176, upload-time = "2026-04-02T09:27:00.437Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", size = 217723, upload-time = "2026-04-02T09:27:02.021Z" },
+ { url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085, upload-time = "2026-04-02T09:27:03.192Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819, upload-time = "2026-04-02T09:27:04.454Z" },
+ { url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915, upload-time = "2026-04-02T09:27:05.971Z" },
+ { url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", size = 309234, upload-time = "2026-04-02T09:27:07.194Z" },
+ { url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", size = 208042, upload-time = "2026-04-02T09:27:08.749Z" },
+ { url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", size = 228706, upload-time = "2026-04-02T09:27:09.951Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", size = 224727, upload-time = "2026-04-02T09:27:11.175Z" },
+ { url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", size = 215882, upload-time = "2026-04-02T09:27:12.446Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", size = 200860, upload-time = "2026-04-02T09:27:13.721Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", size = 211564, upload-time = "2026-04-02T09:27:15.272Z" },
+ { url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", size = 211276, upload-time = "2026-04-02T09:27:16.834Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", size = 201238, upload-time = "2026-04-02T09:27:18.229Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", size = 230189, upload-time = "2026-04-02T09:27:19.445Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", size = 211352, upload-time = "2026-04-02T09:27:20.79Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", size = 227024, upload-time = "2026-04-02T09:27:22.063Z" },
+ { url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", size = 217869, upload-time = "2026-04-02T09:27:23.486Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", size = 148541, upload-time = "2026-04-02T09:27:25.146Z" },
+ { url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", size = 159634, upload-time = "2026-04-02T09:27:26.642Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", size = 148384, upload-time = "2026-04-02T09:27:28.271Z" },
+ { url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", size = 330133, upload-time = "2026-04-02T09:27:29.474Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", size = 216257, upload-time = "2026-04-02T09:27:30.793Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", size = 234851, upload-time = "2026-04-02T09:27:32.44Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", size = 233393, upload-time = "2026-04-02T09:27:34.03Z" },
+ { url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", size = 223251, upload-time = "2026-04-02T09:27:35.369Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", size = 206609, upload-time = "2026-04-02T09:27:36.661Z" },
+ { url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", size = 220014, upload-time = "2026-04-02T09:27:38.019Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", size = 218979, upload-time = "2026-04-02T09:27:39.37Z" },
+ { url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", size = 209238, upload-time = "2026-04-02T09:27:40.722Z" },
+ { url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", size = 236110, upload-time = "2026-04-02T09:27:42.33Z" },
+ { url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", size = 219824, upload-time = "2026-04-02T09:27:43.924Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", size = 233103, upload-time = "2026-04-02T09:27:45.348Z" },
+ { url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", size = 225194, upload-time = "2026-04-02T09:27:46.706Z" },
+ { url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", size = 159827, upload-time = "2026-04-02T09:27:48.053Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", size = 174168, upload-time = "2026-04-02T09:27:49.795Z" },
+ { url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", size = 153018, upload-time = "2026-04-02T09:27:51.116Z" },
+ { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" },
+]
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
+]
+
+[[package]]
+name = "cryptography"
+version = "46.0.7"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/47/93/ac8f3d5ff04d54bc814e961a43ae5b0b146154c89c61b47bb07557679b18/cryptography-46.0.7.tar.gz", hash = "sha256:e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5", size = 750652, upload-time = "2026-04-08T01:57:54.692Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0b/5d/4a8f770695d73be252331e60e526291e3df0c9b27556a90a6b47bccca4c2/cryptography-46.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:ea42cbe97209df307fdc3b155f1b6fa2577c0defa8f1f7d3be7d31d189108ad4", size = 7179869, upload-time = "2026-04-08T01:56:17.157Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/45/6d80dc379b0bbc1f9d1e429f42e4cb9e1d319c7a8201beffd967c516ea01/cryptography-46.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325", size = 4275492, upload-time = "2026-04-08T01:56:19.36Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/9a/1765afe9f572e239c3469f2cb429f3ba7b31878c893b246b4b2994ffe2fe/cryptography-46.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308", size = 4426670, upload-time = "2026-04-08T01:56:21.415Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/3e/af9246aaf23cd4ee060699adab1e47ced3f5f7e7a8ffdd339f817b446462/cryptography-46.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77", size = 4280275, upload-time = "2026-04-08T01:56:23.539Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/54/6bbbfc5efe86f9d71041827b793c24811a017c6ac0fd12883e4caa86b8ed/cryptography-46.0.7-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1", size = 4928402, upload-time = "2026-04-08T01:56:25.624Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/cf/054b9d8220f81509939599c8bdbc0c408dbd2bdd41688616a20731371fe0/cryptography-46.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef", size = 4459985, upload-time = "2026-04-08T01:56:27.309Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/46/4e4e9c6040fb01c7467d47217d2f882daddeb8828f7df800cb806d8a2288/cryptography-46.0.7-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de", size = 3990652, upload-time = "2026-04-08T01:56:29.095Z" },
+ { url = "https://files.pythonhosted.org/packages/36/5f/313586c3be5a2fbe87e4c9a254207b860155a8e1f3cca99f9910008e7d08/cryptography-46.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83", size = 4279805, upload-time = "2026-04-08T01:56:30.928Z" },
+ { url = "https://files.pythonhosted.org/packages/69/33/60dfc4595f334a2082749673386a4d05e4f0cf4df8248e63b2c3437585f2/cryptography-46.0.7-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb", size = 4892883, upload-time = "2026-04-08T01:56:32.614Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/0b/333ddab4270c4f5b972f980adef4faa66951a4aaf646ca067af597f15563/cryptography-46.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b", size = 4459756, upload-time = "2026-04-08T01:56:34.306Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/14/633913398b43b75f1234834170947957c6b623d1701ffc7a9600da907e89/cryptography-46.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85", size = 4410244, upload-time = "2026-04-08T01:56:35.977Z" },
+ { url = "https://files.pythonhosted.org/packages/10/f2/19ceb3b3dc14009373432af0c13f46aa08e3ce334ec6eff13492e1812ccd/cryptography-46.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e", size = 4674868, upload-time = "2026-04-08T01:56:38.034Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/bb/a5c213c19ee94b15dfccc48f363738633a493812687f5567addbcbba9f6f/cryptography-46.0.7-cp311-abi3-win32.whl", hash = "sha256:d23c8ca48e44ee015cd0a54aeccdf9f09004eba9fc96f38c911011d9ff1bd457", size = 3026504, upload-time = "2026-04-08T01:56:39.666Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/02/7788f9fefa1d060ca68717c3901ae7fffa21ee087a90b7f23c7a603c32ae/cryptography-46.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:397655da831414d165029da9bc483bed2fe0e75dde6a1523ec2fe63f3c46046b", size = 3488363, upload-time = "2026-04-08T01:56:41.893Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/56/15619b210e689c5403bb0540e4cb7dbf11a6bf42e483b7644e471a2812b3/cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:d151173275e1728cf7839aaa80c34fe550c04ddb27b34f48c232193df8db5842", size = 7119671, upload-time = "2026-04-08T01:56:44Z" },
+ { url = "https://files.pythonhosted.org/packages/74/66/e3ce040721b0b5599e175ba91ab08884c75928fbeb74597dd10ef13505d2/cryptography-46.0.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:db0f493b9181c7820c8134437eb8b0b4792085d37dbb24da050476ccb664e59c", size = 4268551, upload-time = "2026-04-08T01:56:46.071Z" },
+ { url = "https://files.pythonhosted.org/packages/03/11/5e395f961d6868269835dee1bafec6a1ac176505a167f68b7d8818431068/cryptography-46.0.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ebd6daf519b9f189f85c479427bbd6e9c9037862cf8fe89ee35503bd209ed902", size = 4408887, upload-time = "2026-04-08T01:56:47.718Z" },
+ { url = "https://files.pythonhosted.org/packages/40/53/8ed1cf4c3b9c8e611e7122fb56f1c32d09e1fff0f1d77e78d9ff7c82653e/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:b7b412817be92117ec5ed95f880defe9cf18a832e8cafacf0a22337dc1981b4d", size = 4271354, upload-time = "2026-04-08T01:56:49.312Z" },
+ { url = "https://files.pythonhosted.org/packages/50/46/cf71e26025c2e767c5609162c866a78e8a2915bbcfa408b7ca495c6140c4/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:fbfd0e5f273877695cb93baf14b185f4878128b250cc9f8e617ea0c025dfb022", size = 4905845, upload-time = "2026-04-08T01:56:50.916Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/ea/01276740375bac6249d0a971ebdf6b4dc9ead0ee0a34ef3b5a88c1a9b0d4/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:ffca7aa1d00cf7d6469b988c581598f2259e46215e0140af408966a24cf086ce", size = 4444641, upload-time = "2026-04-08T01:56:52.882Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/4c/7d258f169ae71230f25d9f3d06caabcff8c3baf0978e2b7d65e0acac3827/cryptography-46.0.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:60627cf07e0d9274338521205899337c5d18249db56865f943cbe753aa96f40f", size = 3967749, upload-time = "2026-04-08T01:56:54.597Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/2a/2ea0767cad19e71b3530e4cad9605d0b5e338b6a1e72c37c9c1ceb86c333/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:80406c3065e2c55d7f49a9550fe0c49b3f12e5bfff5dedb727e319e1afb9bf99", size = 4270942, upload-time = "2026-04-08T01:56:56.416Z" },
+ { url = "https://files.pythonhosted.org/packages/41/3d/fe14df95a83319af25717677e956567a105bb6ab25641acaa093db79975d/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:c5b1ccd1239f48b7151a65bc6dd54bcfcc15e028c8ac126d3fada09db0e07ef1", size = 4871079, upload-time = "2026-04-08T01:56:58.31Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/59/4a479e0f36f8f378d397f4eab4c850b4ffb79a2f0d58704b8fa0703ddc11/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:d5f7520159cd9c2154eb61eb67548ca05c5774d39e9c2c4339fd793fe7d097b2", size = 4443999, upload-time = "2026-04-08T01:57:00.508Z" },
+ { url = "https://files.pythonhosted.org/packages/28/17/b59a741645822ec6d04732b43c5d35e4ef58be7bfa84a81e5ae6f05a1d33/cryptography-46.0.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fcd8eac50d9138c1d7fc53a653ba60a2bee81a505f9f8850b6b2888555a45d0e", size = 4399191, upload-time = "2026-04-08T01:57:02.654Z" },
+ { url = "https://files.pythonhosted.org/packages/59/6a/bb2e166d6d0e0955f1e9ff70f10ec4b2824c9cfcdb4da772c7dd69cc7d80/cryptography-46.0.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:65814c60f8cc400c63131584e3e1fad01235edba2614b61fbfbfa954082db0ee", size = 4655782, upload-time = "2026-04-08T01:57:04.592Z" },
+ { url = "https://files.pythonhosted.org/packages/95/b6/3da51d48415bcb63b00dc17c2eff3a651b7c4fed484308d0f19b30e8cb2c/cryptography-46.0.7-cp314-cp314t-win32.whl", hash = "sha256:fdd1736fed309b4300346f88f74cd120c27c56852c3838cab416e7a166f67298", size = 3002227, upload-time = "2026-04-08T01:57:06.91Z" },
+ { url = "https://files.pythonhosted.org/packages/32/a8/9f0e4ed57ec9cebe506e58db11ae472972ecb0c659e4d52bbaee80ca340a/cryptography-46.0.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e06acf3c99be55aa3b516397fe42f5855597f430add9c17fa46bf2e0fb34c9bb", size = 3475332, upload-time = "2026-04-08T01:57:08.807Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/7f/cd42fc3614386bc0c12f0cb3c4ae1fc2bbca5c9662dfed031514911d513d/cryptography-46.0.7-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:462ad5cb1c148a22b2e3bcc5ad52504dff325d17daf5df8d88c17dda1f75f2a4", size = 7165618, upload-time = "2026-04-08T01:57:10.645Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/d0/36a49f0262d2319139d2829f773f1b97ef8aef7f97e6e5bd21455e5a8fb5/cryptography-46.0.7-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7", size = 4270628, upload-time = "2026-04-08T01:57:12.885Z" },
+ { url = "https://files.pythonhosted.org/packages/8a/6c/1a42450f464dda6ffbe578a911f773e54dd48c10f9895a23a7e88b3e7db5/cryptography-46.0.7-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832", size = 4415405, upload-time = "2026-04-08T01:57:14.923Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/92/4ed714dbe93a066dc1f4b4581a464d2d7dbec9046f7c8b7016f5286329e2/cryptography-46.0.7-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163", size = 4272715, upload-time = "2026-04-08T01:57:16.638Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/e6/a26b84096eddd51494bba19111f8fffe976f6a09f132706f8f1bf03f51f7/cryptography-46.0.7-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2", size = 4918400, upload-time = "2026-04-08T01:57:19.021Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/08/ffd537b605568a148543ac3c2b239708ae0bd635064bab41359252ef88ed/cryptography-46.0.7-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067", size = 4450634, upload-time = "2026-04-08T01:57:21.185Z" },
+ { url = "https://files.pythonhosted.org/packages/16/01/0cd51dd86ab5b9befe0d031e276510491976c3a80e9f6e31810cce46c4ad/cryptography-46.0.7-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0", size = 3985233, upload-time = "2026-04-08T01:57:22.862Z" },
+ { url = "https://files.pythonhosted.org/packages/92/49/819d6ed3a7d9349c2939f81b500a738cb733ab62fbecdbc1e38e83d45e12/cryptography-46.0.7-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba", size = 4271955, upload-time = "2026-04-08T01:57:24.814Z" },
+ { url = "https://files.pythonhosted.org/packages/80/07/ad9b3c56ebb95ed2473d46df0847357e01583f4c52a85754d1a55e29e4d0/cryptography-46.0.7-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006", size = 4879888, upload-time = "2026-04-08T01:57:26.88Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/c7/201d3d58f30c4c2bdbe9b03844c291feb77c20511cc3586daf7edc12a47b/cryptography-46.0.7-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0", size = 4449961, upload-time = "2026-04-08T01:57:29.068Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/ef/649750cbf96f3033c3c976e112265c33906f8e462291a33d77f90356548c/cryptography-46.0.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85", size = 4401696, upload-time = "2026-04-08T01:57:31.029Z" },
+ { url = "https://files.pythonhosted.org/packages/41/52/a8908dcb1a389a459a29008c29966c1d552588d4ae6d43f3a1a4512e0ebe/cryptography-46.0.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e", size = 4664256, upload-time = "2026-04-08T01:57:33.144Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/fa/f0ab06238e899cc3fb332623f337a7364f36f4bb3f2534c2bb95a35b132c/cryptography-46.0.7-cp38-abi3-win32.whl", hash = "sha256:f247c8c1a1fb45e12586afbb436ef21ff1e80670b2861a90353d9b025583d246", size = 3013001, upload-time = "2026-04-08T01:57:34.933Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/f1/00ce3bde3ca542d1acd8f8cfa38e446840945aa6363f9b74746394b14127/cryptography-46.0.7-cp38-abi3-win_amd64.whl", hash = "sha256:506c4ff91eff4f82bdac7633318a526b1d1309fc07ca76a3ad182cb5b686d6d3", size = 3472985, upload-time = "2026-04-08T01:57:36.714Z" },
+ { url = "https://files.pythonhosted.org/packages/63/0c/dca8abb64e7ca4f6b2978769f6fea5ad06686a190cec381f0a796fdcaaba/cryptography-46.0.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:fc9ab8856ae6cf7c9358430e49b368f3108f050031442eaeb6b9d87e4dcf4e4f", size = 3476879, upload-time = "2026-04-08T01:57:38.664Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/ea/075aac6a84b7c271578d81a2f9968acb6e273002408729f2ddff517fed4a/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d3b99c535a9de0adced13d159c5a9cf65c325601aa30f4be08afd680643e9c15", size = 4219700, upload-time = "2026-04-08T01:57:40.625Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/7b/1c55db7242b5e5612b29fc7a630e91ee7a6e3c8e7bf5406d22e206875fbd/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d02c738dacda7dc2a74d1b2b3177042009d5cab7c7079db74afc19e56ca1b455", size = 4385982, upload-time = "2026-04-08T01:57:42.725Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/da/9870eec4b69c63ef5925bf7d8342b7e13bc2ee3d47791461c4e49ca212f4/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:04959522f938493042d595a736e7dbdff6eb6cc2339c11465b3ff89343b65f65", size = 4219115, upload-time = "2026-04-08T01:57:44.939Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/72/05aa5832b82dd341969e9a734d1812a6aadb088d9eb6f0430fc337cc5a8f/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:3986ac1dee6def53797289999eabe84798ad7817f3e97779b5061a95b0ee4968", size = 4385479, upload-time = "2026-04-08T01:57:46.86Z" },
+ { url = "https://files.pythonhosted.org/packages/20/2a/1b016902351a523aa2bd446b50a5bc1175d7a7d1cf90fe2ef904f9b84ebc/cryptography-46.0.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:258514877e15963bd43b558917bc9f54cf7cf866c38aa576ebf47a77ddbc43a4", size = 3412829, upload-time = "2026-04-08T01:57:48.874Z" },
+]
+
+[[package]]
+name = "defusedxml"
+version = "0.7.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" },
+]
+
+[[package]]
+name = "fireeyeex"
+version = "14.0"
+source = { virtual = "." }
+dependencies = [
+ { name = "arrow" },
+ { name = "defusedxml" },
+ { name = "requests" },
+ { name = "tipcommon" },
+]
+
+[package.dev-dependencies]
+dev = [
+ { name = "pytest" },
+ { name = "pytest-json-report" },
+ { name = "soar-sdk" },
+]
+
+[package.metadata]
+requires-dist = [
+ { name = "arrow", specifier = "==1.3.0" },
+ { name = "defusedxml", specifier = "==0.7.1" },
+ { name = "requests", specifier = "==2.32.4" },
+ { name = "tipcommon", path = "../../../../../packages/tipcommon/whls/TIPCommon-1.0.12-py2.py3-none-any.whl" },
+]
+
+[package.metadata.requires-dev]
+dev = [
+ { name = "pytest", specifier = ">=9.0.3" },
+ { name = "pytest-json-report", specifier = ">=1.5.0" },
+ { name = "soar-sdk", git = "https://github.com/chronicle/soar-sdk.git" },
+]
+
+[[package]]
+name = "google-auth"
+version = "2.49.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cryptography" },
+ { name = "pyasn1-modules" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c6/fc/e925290a1ad95c975c459e2df070fac2b90954e13a0370ac505dff78cb99/google_auth-2.49.2.tar.gz", hash = "sha256:c1ae38500e73065dcae57355adb6278cf8b5c8e391994ae9cbadbcb9631ab409", size = 333958, upload-time = "2026-04-10T00:41:21.888Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/73/76/d241a5c927433420507215df6cac1b1fa4ac0ba7a794df42a84326c68da8/google_auth-2.49.2-py3-none-any.whl", hash = "sha256:c2720924dfc82dedb962c9f52cabb2ab16714fd0a6a707e40561d217574ed6d5", size = 240638, upload-time = "2026-04-10T00:41:14.501Z" },
+]
+
+[[package]]
+name = "idna"
+version = "3.11"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
+]
+
+[[package]]
+name = "iniconfig"
+version = "2.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
+]
+
+[[package]]
+name = "packaging"
+version = "26.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/df/de/0d2b39fb4af88a0258f3bac87dfcbb48e73fbdea4a2ed0e2213f9a4c2f9a/packaging-26.1.tar.gz", hash = "sha256:f042152b681c4bfac5cae2742a55e103d27ab2ec0f3d88037136b6bfe7c9c5de", size = 215519, upload-time = "2026-04-14T21:12:49.362Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7a/c2/920ef838e2f0028c8262f16101ec09ebd5969864e5a64c4c05fad0617c56/packaging-26.1-py3-none-any.whl", hash = "sha256:5d9c0669c6285e491e0ced2eee587eaf67b670d94a19e94e3984a481aba6802f", size = 95831, upload-time = "2026-04-14T21:12:47.56Z" },
+]
+
+[[package]]
+name = "pluggy"
+version = "1.6.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
+]
+
+[[package]]
+name = "pyasn1"
+version = "0.6.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", size = 148685, upload-time = "2026-03-17T01:06:53.382Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", size = 83997, upload-time = "2026-03-17T01:06:52.036Z" },
+]
+
+[[package]]
+name = "pyasn1-modules"
+version = "0.4.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pyasn1" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" },
+]
+
+[[package]]
+name = "pycparser"
+version = "3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
+]
+
+[[package]]
+name = "pygments"
+version = "2.20.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
+]
+
+[[package]]
+name = "pyopenssl"
+version = "26.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "cryptography" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/8e/11/a62e1d33b373da2b2c2cd9eb508147871c80f12b1cacde3c5d314922afdd/pyopenssl-26.0.0.tar.gz", hash = "sha256:f293934e52936f2e3413b89c6ce36df66a0b34ae1ea3a053b8c5020ff2f513fc", size = 185534, upload-time = "2026-03-15T14:28:26.353Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fb/7d/d4f7d908fa8415571771b30669251d57c3cf313b36a856e6d7548ae01619/pyopenssl-26.0.0-py3-none-any.whl", hash = "sha256:df94d28498848b98cc1c0ffb8ef1e71e40210d3b0a8064c9d29571ed2904bf81", size = 57969, upload-time = "2026-03-15T14:28:24.864Z" },
+]
+
+[[package]]
+name = "pytest"
+version = "9.0.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "iniconfig" },
+ { name = "packaging" },
+ { name = "pluggy" },
+ { name = "pygments" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" },
+]
+
+[[package]]
+name = "pytest-json-report"
+version = "1.5.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pytest" },
+ { name = "pytest-metadata" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/4f/d3/765dae9712fcd68d820338908c1337e077d5fdadccd5cacf95b9b0bea278/pytest-json-report-1.5.0.tar.gz", hash = "sha256:2dde3c647851a19b5f3700729e8310a6e66efb2077d674f27ddea3d34dc615de", size = 21241, upload-time = "2022-03-15T21:03:10.2Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/81/35/d07400c715bf8a88aa0c1ee9c9eb6050ca7fe5b39981f0eea773feeb0681/pytest_json_report-1.5.0-py3-none-any.whl", hash = "sha256:9897b68c910b12a2e48dd849f9a284b2c79a732a8a9cb398452ddd23d3c8c325", size = 13222, upload-time = "2022-03-15T21:03:08.65Z" },
+]
+
+[[package]]
+name = "pytest-metadata"
+version = "3.1.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "pytest" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a6/85/8c969f8bec4e559f8f2b958a15229a35495f5b4ce499f6b865eac54b878d/pytest_metadata-3.1.1.tar.gz", hash = "sha256:d2a29b0355fbc03f168aa96d41ff88b1a3b44a3b02acbe491801c98a048017c8", size = 9952, upload-time = "2024-02-12T19:38:44.887Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3e/43/7e7b2ec865caa92f67b8f0e9231a798d102724ca4c0e1f414316be1c1ef2/pytest_metadata-3.1.1-py3-none-any.whl", hash = "sha256:c8e0844db684ee1c798cfa38908d20d67d0463ecb6137c72e91f418558dd5f4b", size = 11428, upload-time = "2024-02-12T19:38:42.531Z" },
+]
+
+[[package]]
+name = "python-dateutil"
+version = "2.9.0.post0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "six" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
+]
+
+[[package]]
+name = "pytz"
+version = "2026.1.post1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/56/db/b8721d71d945e6a8ac63c0fc900b2067181dbb50805958d4d4661cf7d277/pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", size = 321088, upload-time = "2026-03-03T07:47:50.683Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/10/99/781fe0c827be2742bcc775efefccb3b048a3a9c6ce9aec0cbf4a101677e5/pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a", size = 510489, upload-time = "2026-03-03T07:47:49.167Z" },
+]
+
+[[package]]
+name = "requests"
+version = "2.32.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "certifi" },
+ { name = "charset-normalizer" },
+ { name = "idna" },
+ { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" },
+]
+
+[[package]]
+name = "requests-toolbelt"
+version = "1.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" },
+]
+
+[[package]]
+name = "six"
+version = "1.17.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
+]
+
+[[package]]
+name = "soar-sdk"
+version = "0.2.0"
+source = { git = "https://github.com/chronicle/soar-sdk.git#5c563da488afa729eeba2195d3569de1370ab106" }
+dependencies = [
+ { name = "arrow" },
+ { name = "chardet" },
+ { name = "cryptography" },
+ { name = "google-auth" },
+ { name = "pyopenssl" },
+ { name = "python-dateutil" },
+ { name = "pytz" },
+ { name = "requests" },
+ { name = "requests-toolbelt" },
+ { name = "six" },
+]
+
+[[package]]
+name = "tipcommon"
+version = "1.0.12"
+source = { path = "../../../../../packages/tipcommon/whls/TIPCommon-1.0.12-py2.py3-none-any.whl" }
+dependencies = [
+ { name = "chardet" },
+ { name = "requests" },
+]
+wheels = [
+ { filename = "tipcommon-1.0.12-py2.py3-none-any.whl", hash = "sha256:ac9c56a9ad2b6991a1ef2b4b927a18c13b145ffc9bb33b4e49dfda73b2964af8" },
+]
+
+[package.metadata]
+requires-dist = [
+ { name = "chardet" },
+ { name = "requests" },
+]
+
+[[package]]
+name = "types-python-dateutil"
+version = "2.9.0.20260408"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/88/f3/2427775f80cd5e19a0a71ba8e5ab7645a01a852f43a5fd0ffc24f66338e0/types_python_dateutil-2.9.0.20260408.tar.gz", hash = "sha256:8b056ec01568674235f64ecbcef928972a5fac412f5aab09c516dfa2acfbb582", size = 16981, upload-time = "2026-04-08T04:28:10.995Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/fd/c6/eeba37bfee282a6a97f889faef9352d6172c6a5088eb9a4daf570d9d748d/types_python_dateutil-2.9.0.20260408-py3-none-any.whl", hash = "sha256:473139d514a71c9d1fbd8bb328974bedcb1cc3dba57aad04ffa4157f483c216f", size = 18437, upload-time = "2026-04-08T04:28:10.095Z" },
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.15.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
+]
+
+[[package]]
+name = "urllib3"
+version = "2.6.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
+]
diff --git a/content/response_integrations/google/fire_eye_ex/widgets/DownloadAlertArtifacts.html b/content/response_integrations/google/fire_eye_ex/widgets/DownloadAlertArtifacts.html
new file mode 100644
index 000000000..8814bf513
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/widgets/DownloadAlertArtifacts.html
@@ -0,0 +1,1002 @@
+
+
+
+
+
+
+
+
+
+
+
+ FireEye EX - Download Alert Artifacts
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/content/response_integrations/google/fire_eye_ex/widgets/DownloadAlertArtifacts.yaml b/content/response_integrations/google/fire_eye_ex/widgets/DownloadAlertArtifacts.yaml
new file mode 100644
index 000000000..cb48c9b01
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/widgets/DownloadAlertArtifacts.yaml
@@ -0,0 +1,36 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+title: FireEye EX - Download Alert Artifacts
+type: html
+scope: alert
+action_identifier: Download Alert Artifacts
+description: This widget highlights the most important items in Download Alert Artifacts
+data_definition:
+ html_height: 400
+ safe_rendering: false
+ widget_definition_scope: both
+ type: html
+condition_group:
+ conditions:
+ - field_name: '[{stepInstanceName}.JsonResult]'
+ value: '['
+ match_type: starts_with
+ custom_operator_name: null
+ - field_name: '[{stepInstanceName}.JsonResult]'
+ value: '{'
+ match_type: contains
+ custom_operator_name: null
+ logical_operator: and
+default_size: half_width
diff --git a/content/response_integrations/google/fire_eye_ex/widgets/DownloadQuarantinedEmail.html b/content/response_integrations/google/fire_eye_ex/widgets/DownloadQuarantinedEmail.html
new file mode 100644
index 000000000..2788fca33
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/widgets/DownloadQuarantinedEmail.html
@@ -0,0 +1,1002 @@
+
+
+
+
+
+
+
+
+
+
+
+ FireEye EX - Download Quarantined Email
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/content/response_integrations/google/fire_eye_ex/widgets/DownloadQuarantinedEmail.yaml b/content/response_integrations/google/fire_eye_ex/widgets/DownloadQuarantinedEmail.yaml
new file mode 100644
index 000000000..7f83c77dd
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/widgets/DownloadQuarantinedEmail.yaml
@@ -0,0 +1,37 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+title: FireEye EX - Download Quarantined Email
+type: html
+scope: alert
+action_identifier: Download Quarantined Email
+description: This widget highlights the most important items in Download Quarantined
+ Email
+data_definition:
+ html_height: 400
+ safe_rendering: false
+ widget_definition_scope: both
+ type: html
+condition_group:
+ conditions:
+ - field_name: '[{stepInstanceName}.JsonResult]'
+ value: '['
+ match_type: starts_with
+ custom_operator_name: null
+ - field_name: '[{stepInstanceName}.JsonResult]'
+ value: '{'
+ match_type: contains
+ custom_operator_name: null
+ logical_operator: and
+default_size: half_width
diff --git a/content/response_integrations/google/fire_eye_ex/widgets/ListQuarantinedEmails.html b/content/response_integrations/google/fire_eye_ex/widgets/ListQuarantinedEmails.html
new file mode 100644
index 000000000..646728bbe
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/widgets/ListQuarantinedEmails.html
@@ -0,0 +1,1002 @@
+
+
+
+
+
+
+
+
+
+
+
+ FireEye EX - List Quarantined Emails
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/content/response_integrations/google/fire_eye_ex/widgets/ListQuarantinedEmails.yaml b/content/response_integrations/google/fire_eye_ex/widgets/ListQuarantinedEmails.yaml
new file mode 100644
index 000000000..f22869e4a
--- /dev/null
+++ b/content/response_integrations/google/fire_eye_ex/widgets/ListQuarantinedEmails.yaml
@@ -0,0 +1,36 @@
+# Copyright 2026 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+title: FireEye EX - List Quarantined Emails
+type: html
+scope: alert
+action_identifier: List Quarantined Emails
+description: This widget highlights the most important items in List Quarantined Emails
+data_definition:
+ html_height: 400
+ safe_rendering: false
+ widget_definition_scope: both
+ type: html
+condition_group:
+ conditions:
+ - field_name: '[{stepInstanceName}.JsonResult]'
+ value: '['
+ match_type: starts_with
+ custom_operator_name: null
+ - field_name: '[{stepInstanceName}.JsonResult]'
+ value: '{'
+ match_type: contains
+ custom_operator_name: null
+ logical_operator: and
+default_size: half_width
diff --git a/content/response_integrations/google/ruff.toml b/content/response_integrations/google/ruff.toml
index 66852f15d..7688bea6f 100644
--- a/content/response_integrations/google/ruff.toml
+++ b/content/response_integrations/google/ruff.toml
@@ -74,6 +74,7 @@ preview = true
]
# Specific Integrations
+"fire_eye_ex/**" = ["ALL"]
"cyber_x/**" = ["ALL"]
"juniper_vsrx/**" = ["ALL"]
"mc_afee_nsm/**" = ["ALL"]