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,42 @@
from __future__ import annotations
from soar_sdk.SiemplifyAction import SiemplifyAction
from soar_sdk.SiemplifyUtils import output_handler
from soar_sdk.ScriptResult import EXECUTION_STATE_COMPLETED, EXECUTION_STATE_FAILED
from ..core.ApiManager import ApiManager


@output_handler
def main():
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

This new integration is missing the required unit tests. The repository style guide mandates that all new features in the content/response_integrations/** directory must include corresponding pytest unit tests to ensure production stability. Please add a test suite that covers the new actions and core logic, ensuring that network calls are mocked as per the guide's reference examples.

References
  1. All new features, bug fixes, or integrations added to content/response_integrations/** must include corresponding unit tests to ensure production stability. (link)

Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The main function is missing a return type annotation (-> None) and a Google-style docstring. The repository style guide requires both for all functions to improve readability and maintainability. Please add them. This applies to all action scripts in this PR.

Suggested change
def main():
def main() -> None:
References
  1. All function parameters and return types must be annotated. (link)
  2. Use """Docstring""" for all modules, classes, and functions. (link)

siemplify = SiemplifyAction()
siemplify.LOGGER.info("----------------- RRS - Check Job Status: Init -----------------")
rrsManager = ApiManager(siemplify)
siemplify.LOGGER.info("----------------- RRS - Check Job Status: Started -----------------")

job_status_result = None
try:

# call check job status api
job_status_result = rrsManager.check_job_status()

status = EXECUTION_STATE_COMPLETED # used to flag back to siemplify system, the action final status
output_message = "Successfully retrieved job status" # human readable message, showed in UI as the action result
result_value = True # Set a simple result value, used for playbook if\else and placeholders.

except Exception as e:
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The try...except block catches the generic Exception, which can mask underlying issues and make debugging difficult. Please catch more specific exceptions, such as requests.exceptions.RequestException for network errors, and other potential exceptions from the ApiManager. This will improve error handling and resilience, as per the style guide's "Production-Ready SecOps" principle. This comment applies to all action scripts in this PR.

References
  1. Code must be resilient. Implement defensive programming, proactive error handling, and structured logging. (link)

output_message = f"Failed to check job status. Error: {e}"
siemplify.LOGGER.error(f"Check Job Status: Failed to check job status. Error: {e}")
siemplify.LOGGER.exception(e)
status = EXECUTION_STATE_FAILED
result_value = False
job_status_result = {}

siemplify.LOGGER.info("----------------- RRS - Check Job Status: End -----------------")
siemplify.LOGGER.info(f"Check Job Status output: \n status: {status}\n result_value: {result_value}\n output_message: {output_message}")

# Add result to action output.
siemplify.result.add_result_json(job_status_result)
siemplify.end(output_message, result_value, status)


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Check Job Status
description: Check status of asynchronous jobs
integration_identifier: netapp-ransomware-resilience
parameters:
- name: Source
default_value: ''
type: string
description: Source string (eg. rps-agent)
is_mandatory: true
- name: Agent ID
default_value: ''
type: string
description: Console Agent ID
is_mandatory: true
- name: Job ID
default_value: ''
type: string
description: Job ID for which status to be fetched
is_mandatory: true
dynamic_results_metadata:
- result_example_path: resources/check_job_status_JsonResult_example.json
result_name: JsonResult
show_result: true
default_result_value: ''
creator: 5c86e1e4-dd8c-4181-8fc9-f5e8f008caae
script_result_name: ScriptResult
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from __future__ import annotations
from soar_sdk.SiemplifyAction import SiemplifyAction
from soar_sdk.SiemplifyUtils import unix_now, convert_unixtime_to_datetime, output_handler
from soar_sdk.ScriptResult import EXECUTION_STATE_COMPLETED, EXECUTION_STATE_FAILED,EXECUTION_STATE_TIMEDOUT
from ..core.ApiManager import ApiManager


@output_handler
def main():
siemplify = SiemplifyAction()
siemplify.LOGGER.info("----------------- RRS - Enrich IP: Init -----------------")
rrsManager = ApiManager(siemplify)
ip_address = siemplify.extract_action_param("IP Address", print_value=True)
siemplify.LOGGER.info("----------------- RRS - Enrich IP: Started -----------------")

enrich_results = None
try:

# call enrich api
enrich_results = rrsManager.enrich_ip(ip_address)

status = EXECUTION_STATE_COMPLETED # used to flag back to siemplify system, the action final status
output_message = f"Successfully enriched IP - {ip_address}" # human readable message, showed in UI as the action result
result_value = True # Set a simple result value, used for playbook if\else and placeholders.

except Exception as e:
output_message = f"Failed to enrich IP - {ip_address}. Error: {e}"
siemplify.LOGGER.error(f"Enrich IP: Failed to enrich IP - {ip_address}. Error: {e}")
siemplify.LOGGER.exception(e)
status = EXECUTION_STATE_FAILED
result_value = False
enrich_results = []

siemplify.LOGGER.info("----------------- RRS - Enrich IP: End -----------------")
siemplify.LOGGER.info(f"Enrich IP output: \n status: {status}\n result_value: {result_value}\n output_message: {output_message}")

# Add result to action output.
siemplify.result.add_result_json(enrich_results)
siemplify.end(output_message, result_value, status)


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Enrich IP Address
description: Enrich IP with threat intelligence
integration_identifier: netapp-ransomware-resilience
parameters:
- name: IP Address
default_value: ''
type: string
description: IP Address for enrichment
is_mandatory: true
dynamic_results_metadata:
- result_example_path: resources/enrich_ip_address_JsonResult_example.json
result_name: JsonResult
show_result: true
default_result_value: ''
creator: 5c86e1e4-dd8c-4181-8fc9-f5e8f008caae
script_result_name: ScriptResult
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from __future__ import annotations
from soar_sdk.SiemplifyAction import SiemplifyAction
from soar_sdk.SiemplifyUtils import unix_now, convert_unixtime_to_datetime, output_handler
from soar_sdk.ScriptResult import EXECUTION_STATE_COMPLETED, EXECUTION_STATE_FAILED,EXECUTION_STATE_TIMEDOUT
from ..core.ApiManager import ApiManager


@output_handler
def main():
siemplify = SiemplifyAction()
siemplify.LOGGER.info("----------------- RRS - Enrich Storage: Init -----------------")
rrsManager = ApiManager(siemplify)
siemplify.LOGGER.info("----------------- RRS - Enrich Storage: Started -----------------")

enrich_results = None
try:

# call enrich storage api
enrich_results = rrsManager.enrich_storage()

status = EXECUTION_STATE_COMPLETED # used to flag back to siemplify system, the action final status
output_message = "Successfully enriched storage information" # human readable message, showed in UI as the action result
result_value = True # Set a simple result value, used for playbook if\else and placeholders.

except Exception as e:
siemplify.LOGGER.error(f"Enrich Storage: Failed to enrich storage. Error: {e}")
output_message = f"Failed to enrich storage. Error: {e}"
siemplify.LOGGER.exception(e)
status = EXECUTION_STATE_FAILED
result_value = False
enrich_results = []

siemplify.LOGGER.info("----------------- RRS - Enrich Storage: End -----------------")
siemplify.LOGGER.info(f"Enrich Storage output: \n status: {status}\n result_value: {result_value}\n output_message: {output_message}")

# Add result to action output.
siemplify.result.add_result_json(enrich_results)
siemplify.end(output_message, result_value, status)


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Enrich Storage
description: Get volume information for agent/system
integration_identifier: netapp-ransomware-resilience
parameters:
- name: Agent ID
default_value: ''
type: string
description: Console Agent ID
is_mandatory: true
- name: System ID
default_value: ''
type: string
description: Storage System ID
is_mandatory: true
dynamic_results_metadata:
- result_example_path: resources/enrich_storage_JsonResult_example.json
result_name: JsonResult
show_result: true
default_result_value: ''
creator: 5c86e1e4-dd8c-4181-8fc9-f5e8f008caae
script_result_name: ScriptResult
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from __future__ import annotations
from soar_sdk.SiemplifyAction import SiemplifyAction
from soar_sdk.SiemplifyUtils import output_handler
from soar_sdk.ScriptResult import EXECUTION_STATE_COMPLETED, EXECUTION_STATE_FAILED
from ..core.ApiManager import ApiManager

@output_handler
def main():
siemplify = SiemplifyAction()

siemplify.LOGGER.info("----------------- RRS - Test connection: Init -----------------")
rrsManager = ApiManager(siemplify)
siemplify.LOGGER.info("----------------- RRS - Test connection: Started -----------------")

try:
is_token_valid = rrsManager.is_token_valid()
siemplify.LOGGER.info(f"Ping: {is_token_valid=}")

status = EXECUTION_STATE_COMPLETED # used to flag back to siemplify system, the action final status
output_message = "Successfully connected to Ransomware Resilience server!" # human readable message, showed in UI as the action result
result_value = True # Set a simple result value, used for playbook if\else and placeholders.

except Exception as e:
output_message = f"Failed to connect to the Ransomware Resilience server! {e}"
siemplify.LOGGER.error(f"Connection to API failed, performing action {e}")
siemplify.LOGGER.exception(e)
status = EXECUTION_STATE_FAILED
result_value = False

siemplify.LOGGER.info("----------------- RRS - Test connection: End -----------------")

siemplify.LOGGER.info(f"Ping: \n status: {status}\n result_value: {result_value}\n 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,11 @@
name: Ping
description: Ping action to test connection to Ransomware resilience service.
integration_identifier: netapp-ransomware-resilience
parameters: []
dynamic_results_metadata:
- result_example_path: null
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

If the Ping action is intended to return a JSON result (implied by dynamic_results_metadata), a corresponding JSON example file must exist in the resources/ directory. If no JSON result is produced, consider setting show_result: false or removing the dynamic_results_metadata section. Refer to the style guide for JSON result requirements (line 160).

References
  1. If a JSON result is detected, a corresponding JSON example file must exist in the integration's resources/ directory. (link)

result_name: JsonResult
show_result: true
default_result_value: ''
creator: 5c86e1e4-dd8c-4181-8fc9-f5e8f008caae
script_result_name: ScriptResult
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from __future__ import annotations
from soar_sdk.SiemplifyAction import SiemplifyAction
from soar_sdk.SiemplifyUtils import unix_now, convert_unixtime_to_datetime, output_handler
from soar_sdk.ScriptResult import EXECUTION_STATE_COMPLETED, EXECUTION_STATE_FAILED,EXECUTION_STATE_TIMEDOUT
from ..core.ApiManager import ApiManager


@output_handler
def main():
siemplify = SiemplifyAction()
siemplify.LOGGER.info("----------------- RRS - Take Snapshot: Init -----------------")
rrsManager = ApiManager(siemplify)
siemplify.LOGGER.info("----------------- RRS - Take Snapshot: Started -----------------")

snapshot_result = None
try:

# call take snapshot api
snapshot_result = rrsManager.take_snapshot()

status = EXECUTION_STATE_COMPLETED # used to flag back to siemplify system, the action final status
output_message = "Successfully triggered snapshot creation" # human readable message, showed in UI as the action result
result_value = True # Set a simple result value, used for playbook if\else and placeholders.

except Exception as e:
output_message = f"Failed to take snapshot. Error: {e}"
siemplify.LOGGER.error(f"Take Snapshot: Failed to take snapshot. Error: {e}")
siemplify.LOGGER.exception(e)
status = EXECUTION_STATE_FAILED
result_value = False
snapshot_result = {}

siemplify.LOGGER.info("----------------- RRS - Take Snapshot: End -----------------")
siemplify.LOGGER.info(f"Take Snapshot: \n status: {status}\n result_value: {result_value}\n output_message: {output_message}")

# Add result to action output.
siemplify.result.add_result_json(snapshot_result)
siemplify.end(output_message, result_value, status)


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Take Snapshot
description: Create volume snapshot
integration_identifier: netapp-ransomware-resilience
parameters:
- name: Volume ID
default_value: ''
type: string
description: Volume ID
is_mandatory: true
- name: Agent ID
default_value: ''
type: string
description: Console agent ID
is_mandatory: true
Copy link
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 volume_id appears to be a specific ID. Please replace this with a generic example or clearly mark it as a placeholder to ensure the configuration is suitable for a public repository. Refer to the style guide for generic examples (line 20).

References
  1. All code examples, comments, and messages are generic and suitable for a public repository. (link)

- name: System ID
default_value: ''
type: string
description: Storage System ID
is_mandatory: true
dynamic_results_metadata:
- result_example_path: resources/take_snapshot_JsonResult_example.json
result_name: JsonResult
show_result: true
default_result_value: ''
creator: 5c86e1e4-dd8c-4181-8fc9-f5e8f008caae
script_result_name: ScriptResult
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from __future__ import annotations
from soar_sdk.SiemplifyAction import SiemplifyAction
from soar_sdk.SiemplifyUtils import unix_now, convert_unixtime_to_datetime, output_handler
from soar_sdk.ScriptResult import EXECUTION_STATE_COMPLETED, EXECUTION_STATE_FAILED,EXECUTION_STATE_TIMEDOUT
from ..core.ApiManager import ApiManager


@output_handler
def main():
siemplify = SiemplifyAction()
siemplify.LOGGER.info("----------------- RRS - Volume Offline: Init -----------------")
rrsManager = ApiManager(siemplify)
siemplify.LOGGER.info("----------------- RRS - Volume Offline: Started -----------------")

volume_offline_result = None
try:

# call volume offline api
volume_offline_result = rrsManager.volume_offline()

status = EXECUTION_STATE_COMPLETED # used to flag back to siemplify system, the action final status
output_message = "Successfully took volume offline" # human readable message, showed in UI as the action result
result_value = True # Set a simple result value, used for playbook if\else and placeholders.

except Exception as e:
output_message = f"Failed to take volume offline. Error: {e}"
siemplify.LOGGER.error(f"Volume Offline: Failed to take volume offline. Error: {e}")
siemplify.LOGGER.exception(e)
status = EXECUTION_STATE_FAILED
result_value = False
volume_offline_result = {}

siemplify.LOGGER.info("----------------- RRS - Volume Offline: End -----------------")
siemplify.LOGGER.info(f"Volume Offline: \n status: {status}\n result_value: {result_value}\n output_message: {output_message}")

# Add result to action output.
siemplify.result.add_result_json(volume_offline_result)
siemplify.end(output_message, result_value, status)


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Volume Offline
description: Take volume offline
integration_identifier: netapp-ransomware-resilience
parameters:
- name: Volume ID
default_value: ''
type: string
description: ID of Volume
is_mandatory: true
- name: Agent ID
default_value: ''
type: string
description: Console Agent ID
is_mandatory: true
Copy link
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 system_id appears to be a specific ID. Please replace this with a generic example or clearly mark it as a placeholder to ensure the configuration is suitable for a public repository. Refer to the style guide for generic examples (line 20).

References
  1. All code examples, comments, and messages are generic and suitable for a public repository. (link)

- name: System ID
default_value: ''
type: string
description: System ID
is_mandatory: true
dynamic_results_metadata:
- result_example_path: resources/volume_offline_JsonResult_example.json
result_name: JsonResult
show_result: true
default_result_value: ''
creator: 5c86e1e4-dd8c-4181-8fc9-f5e8f008caae
script_result_name: ScriptResult
Copy link
Contributor

Choose a reason for hiding this comment

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

please change actions file names to snake case

Empty file.
Loading
Loading