Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.11
Original file line number Diff line number Diff line change
@@ -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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

TIPCommon imports should use submodules (e.g., TIPCommon.extraction) instead of flat imports for integrations using TIPCommon 2.x+.

Suggested change
from TIPCommon import extract_configuration_param, extract_action_param
from TIPCommon.extraction import extract_configuration_param, extract_action_param
References
  1. TIPCommon imports should use submodules (for TIPCommon 2.x+). (link)



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,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The default value for the "Verify SSL" parameter should be True to adhere to the repository style guide.

Suggested change
default_value=False,
default_value=True,
References
  1. All integrations must have a Verify SSL boolean parameter, default true. (link)

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()
Original file line number Diff line number Diff line change
@@ -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":[]}'
Original file line number Diff line number Diff line change
@@ -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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Import pathlib to handle file system operations as required by the style guide.

Suggested change
from urllib.parse import urljoin
import pathlib
from urllib.parse import urljoin
References
  1. Always use pathlib.Path for file system operations. (link)


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")),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

zip_content.content is a bytes object and does not have an encode method. This will cause an AttributeError at runtime. It should be base64 encoded directly and then decoded to a string for the attachment.

Suggested change
base64.b64encode(zip_content.content.encode("utf-8")),
base64.b64encode(zip_content.content).decode("utf-8"),

)

absolute_path = urljoin(download_path, f"Alert_Artifacts_{alert_uuid}.zip")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

urljoin is intended for URL manipulation. For local filesystem paths, use pathlib.Path and the / operator as required by the style guide.

Suggested change
absolute_path = urljoin(download_path, f"Alert_Artifacts_{alert_uuid}.zip")
absolute_path = str(pathlib.Path(download_path) / f"Alert_Artifacts_{alert_uuid}.zip")
References
  1. Always use pathlib.Path for file system operations. Avoid String Concatenation. (link)


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()
Original file line number Diff line number Diff line change
@@ -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":[]}'
Loading
Loading