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,122 @@
"""
Get Activity Status action for Abnormal Security Google SecOps SOAR Integration.

Checks the status of a remediation operation using the activity_log_id
returned by the Remediate Messages action.
"""

from __future__ import annotations

import json

from soar_sdk.ScriptResult import EXECUTION_STATE_COMPLETED, EXECUTION_STATE_FAILED
from soar_sdk.SiemplifyAction import SiemplifyAction
from soar_sdk.SiemplifyUtils import output_handler
from TIPCommon import extract_action_param, extract_configuration_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

According to the repository style guide, TIPCommon imports should use submodules for new integrations. Please update the import to follow the modern convention.

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


from ..core.AbnormalManager import (
AbnormalAuthenticationError,
AbnormalConnectionError,
AbnormalManager,
AbnormalValidationError,
)
from ..core.constants import (
GET_ACTIVITY_STATUS_SCRIPT_NAME,
INTEGRATION_NAME,
TERMINAL_STATUSES,
)


@output_handler
def main():
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 main function is missing a docstring and a return type annotation, which is required by the repository style guide. All functions must have docstrings and be fully type-annotated.

Suggested change
def main():
@output_handler
def main() -> None:
"""
Main execution logic for the Get Activity Status action.
"""
References
  1. All function parameters and return types must be annotated. Use triple double quotes for all function docstrings. (link)

siemplify = SiemplifyAction()
siemplify.script_name = GET_ACTIVITY_STATUS_SCRIPT_NAME
siemplify.LOGGER.info(f"Action: {GET_ACTIVITY_STATUS_SCRIPT_NAME} started")

# Integration config
api_url = extract_configuration_param(
siemplify,
provider_name=INTEGRATION_NAME,
param_name="API URL",
is_mandatory=True,
print_value=True,
)
api_key = extract_configuration_param(
siemplify,
provider_name=INTEGRATION_NAME,
param_name="API Key",
is_mandatory=True,
)
verify_ssl = extract_configuration_param(
siemplify,
provider_name=INTEGRATION_NAME,
param_name="Verify SSL",
input_type=bool,
is_mandatory=False,
default_value=True,
)

# Action parameters
activity_log_id = extract_action_param(
siemplify, param_name="Activity Log ID", is_mandatory=True, print_value=True
)
tenant_ids_raw = extract_action_param(
siemplify, param_name="Tenant IDs", is_mandatory=True, print_value=True
)
tenant_ids = [t.strip() for t in tenant_ids_raw.split(",") if t.strip()]

result_value = False
status = EXECUTION_STATE_FAILED
output_message = ""

try:
manager = AbnormalManager(api_url=api_url, api_key=api_key, verify_ssl=verify_ssl)

response = manager.get_activity_status(
activity_log_id=activity_log_id,
tenant_ids=tenant_ids,
)

activity_status = response.get("status", "unknown")
siemplify.result.add_result_json(json.dumps(response))
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.

high

The add_result_json method handles the JSON serialization internally. By passing json.dumps(response), you are creating a double-encoded JSON string, which will likely cause issues in the playbook. Please pass the dictionary object directly.

Suggested change
siemplify.result.add_result_json(json.dumps(response))
siemplify.result.add_result_json(response)
References
  1. If an action returns a JSON result by calling result.add_result_json(...), it must be a valid JSON structure. Double-encoding can break playbook placeholders. (link)


if activity_status in TERMINAL_STATUSES:
output_message = (
f"Remediation activity {activity_log_id} completed with status: "
f"{activity_status}."
)
result_value = activity_status != "failed"
else:
output_message = (
f"Remediation activity {activity_log_id} is still in progress. "
f"Status: {activity_status}."
)
result_value = True # Not an error — just not done yet

status = EXECUTION_STATE_COMPLETED
siemplify.LOGGER.info(output_message)

except AbnormalValidationError as e:
output_message = f"Invalid parameters: {e}"
siemplify.LOGGER.error(output_message)

except AbnormalAuthenticationError as e:
output_message = f"Authentication failed: {e}"
siemplify.LOGGER.error(output_message)

except AbnormalConnectionError as e:
output_message = f"Connection error: {e}"
siemplify.LOGGER.error(output_message)

except Exception as e:
output_message = f"An unexpected error occurred: {e}"
siemplify.LOGGER.error(output_message)
siemplify.LOGGER.exception(e)
Comment on lines +99 to +114
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 error messages in the except blocks do not follow the standard format specified in the style guide. For consistency in playbook outputs, please prefix error messages with Error executing action "{action name}". Reason: {error}.

Suggested change
except AbnormalValidationError as e:
output_message = f"Invalid parameters: {e}"
siemplify.LOGGER.error(output_message)
except AbnormalAuthenticationError as e:
output_message = f"Authentication failed: {e}"
siemplify.LOGGER.error(output_message)
except AbnormalConnectionError as e:
output_message = f"Connection error: {e}"
siemplify.LOGGER.error(output_message)
except Exception as e:
output_message = f"An unexpected error occurred: {e}"
siemplify.LOGGER.error(output_message)
siemplify.LOGGER.exception(e)
except AbnormalValidationError as e:
output_message = f'Error executing action "{siemplify.script_name}". Reason: {e}'
siemplify.LOGGER.error(output_message)
except AbnormalAuthenticationError as e:
output_message = f'Error executing action "{siemplify.script_name}". Reason: {e}'
siemplify.LOGGER.error(output_message)
except AbnormalConnectionError as e:
output_message = f'Error executing action "{siemplify.script_name}". Reason: {e}'
siemplify.LOGGER.error(output_message)
except Exception as e:
output_message = f'Error executing action "{siemplify.script_name}". Reason: An unexpected error occurred: {e}'
siemplify.LOGGER.error(output_message)
siemplify.LOGGER.exception(e)
References
  1. Error messages should follow a standard template for consistency. The required prefix is Error executing action "{action name}". Reason: {error}. (link)


siemplify.LOGGER.info("----------------- Main - Finished -----------------")
siemplify.LOGGER.info(f"Status: {status} Result: {result_value}")
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: Get Activity Status
description: Check the status of a remediation operation using the Activity Log ID
returned by Remediate Messages. Poll this action until the status reaches a terminal
state (success, failed, or completed).
integration_identifier: AbnormalSecurity
parameters:
- name: Activity Log ID
default_value: ''
type: string
description: Activity Log ID returned by the Remediate Messages action.
is_mandatory: true
- name: Tenant IDs
default_value: ''
type: string
description: Comma-separated list of tenant IDs to query for remediation status.
is_mandatory: true
dynamic_results_metadata:
- result_example_path: resources/GetActivityStatus_JsonResult_example.json
result_name: JsonResult
show_result: true
creator: AbnormalSecurity
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"""
Ping action for Abnormal Security Google SecOps SOAR Integration.

Tests connectivity and authentication to the Abnormal Security API.
"""

from __future__ import annotations

from soar_sdk.ScriptResult import EXECUTION_STATE_COMPLETED, EXECUTION_STATE_FAILED
from soar_sdk.SiemplifyAction import SiemplifyAction
from soar_sdk.SiemplifyUtils import output_handler
from TIPCommon import extract_configuration_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

According to the repository style guide, TIPCommon imports should use submodules for new integrations. Please update the import to follow the modern convention.

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


from ..core.AbnormalManager import (
AbnormalAuthenticationError,
AbnormalConnectionError,
AbnormalManager,
)
from ..core.constants import (
INTEGRATION_DISPLAY_NAME,
INTEGRATION_NAME,
PING_SCRIPT_NAME,
)


@output_handler
def main():
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 main function is missing a docstring and a return type annotation, which is required by the repository style guide. All functions must have docstrings and be fully type-annotated.

Suggested change
def main():
@output_handler
def main() -> None:
"""
Main execution logic for the Ping action.
"""
References
  1. All function parameters and return types must be annotated. Use triple double quotes for all function docstrings. (link)

siemplify = SiemplifyAction()
siemplify.script_name = PING_SCRIPT_NAME
siemplify.LOGGER.info(f"Action: {PING_SCRIPT_NAME} started")

api_url = extract_configuration_param(
siemplify,
provider_name=INTEGRATION_NAME,
param_name="API URL",
is_mandatory=True,
print_value=True,
)
api_key = extract_configuration_param(
siemplify,
provider_name=INTEGRATION_NAME,
param_name="API Key",
is_mandatory=True,
)
verify_ssl = extract_configuration_param(
siemplify,
provider_name=INTEGRATION_NAME,
param_name="Verify SSL",
input_type=bool,
is_mandatory=False,
default_value=True,
print_value=True,
)

result_value = False
status = EXECUTION_STATE_FAILED
output_message = ""

try:
manager = AbnormalManager(api_url=api_url, api_key=api_key, verify_ssl=verify_ssl)
manager.test_connectivity()

output_message = (
f"Successfully connected to the {INTEGRATION_DISPLAY_NAME} API at {api_url}."
)
Comment on lines +63 to +65
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.

high

The success message for the Ping action does not conform to the exact format required by the repository style guide. Using the standard format ensures consistent and predictable output for playbook designers.

Suggested change
output_message = (
f"Successfully connected to the {INTEGRATION_DISPLAY_NAME} API at {api_url}."
)
output_message = (
f"Successfully connected to the {INTEGRATION_DISPLAY_NAME} server with the provided "
f"connection parameters!"
)
References
  1. The Ping action success message must be exactly: "Successfully connected to the {integration name} server with the provided connection parameters!" (link)

result_value = True
status = EXECUTION_STATE_COMPLETED
siemplify.LOGGER.info(output_message)

except AbnormalAuthenticationError as e:
output_message = (
f"Failed to connect to the {INTEGRATION_DISPLAY_NAME} server! "
f"Authentication failed — please verify the API key. Error: {e}"
)
siemplify.LOGGER.error(output_message)

except AbnormalConnectionError as e:
output_message = (
f"Failed to connect to the {INTEGRATION_DISPLAY_NAME} server! "
f"Cannot reach {api_url} — check the URL and network. Error: {e}"
)
siemplify.LOGGER.error(output_message)
Comment on lines +70 to +82
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.

high

The failure messages for the Ping action do not conform to the exact format required by the repository style guide. While providing detailed messages for different error types is helpful for debugging, the style guide mandates a single, standard failure message format for consistency in playbooks.

Suggested change
except AbnormalAuthenticationError as e:
output_message = (
f"Failed to connect to the {INTEGRATION_DISPLAY_NAME} server! "
f"Authentication failed — please verify the API key. Error: {e}"
)
siemplify.LOGGER.error(output_message)
except AbnormalConnectionError as e:
output_message = (
f"Failed to connect to the {INTEGRATION_DISPLAY_NAME} server! "
f"Cannot reach {api_url} — check the URL and network. Error: {e}"
)
siemplify.LOGGER.error(output_message)
except (AbnormalAuthenticationError, AbnormalConnectionError) as e:
output_message = (
f"Failed to connect to the {INTEGRATION_DISPLAY_NAME} server! Error is {e}"
)
siemplify.LOGGER.error(output_message)
References
  1. The Ping action failure message must be exactly: "Failed to connect to the {product name} server! Error is {error}" (link)


except Exception as e:
output_message = (
f"Failed to connect to the {INTEGRATION_DISPLAY_NAME} server! "
f"An unexpected error occurred: {e}"
)
siemplify.LOGGER.error(output_message)
siemplify.LOGGER.exception(e)

siemplify.LOGGER.info("----------------- Main - Finished -----------------")
siemplify.LOGGER.info(f"Status: {status} Result: {result_value}")
siemplify.end(output_message, result_value, status)


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name: Ping
description: Test connectivity and authentication to the Abnormal Security API. Run
this action after configuring the integration to verify the API URL and API key
are valid before building playbooks.
integration_identifier: AbnormalSecurity
parameters: []
dynamic_results_metadata: []
creator: AbnormalSecurity
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
"""
Remediate Messages action for Abnormal Security Google SecOps SOAR Integration.

Takes automated remediation action on email messages. Returns an activity_log_id
that should be passed to Get Activity Status to verify the operation completed.
"""

from __future__ import annotations

import json

from soar_sdk.ScriptResult import EXECUTION_STATE_COMPLETED, EXECUTION_STATE_FAILED
from soar_sdk.SiemplifyAction import SiemplifyAction
from soar_sdk.SiemplifyUtils import output_handler
from TIPCommon import extract_action_param, extract_configuration_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

According to the repository style guide, TIPCommon imports should use submodules for new integrations. Please update the import to follow the modern convention.

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


from ..core.AbnormalManager import (
AbnormalAuthenticationError,
AbnormalConnectionError,
AbnormalManager,
AbnormalValidationError,
)
from ..core.constants import (
INTEGRATION_NAME,
REMEDIATE_MESSAGES_SCRIPT_NAME,
)


@output_handler
def main():
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 main function is missing a docstring and a return type annotation, which is required by the repository style guide. All functions must have docstrings and be fully type-annotated.

Suggested change
def main():
@output_handler
def main() -> None:
"""
Main execution logic for the Remediate Messages action.
"""
References
  1. All function parameters and return types must be annotated. Use triple double quotes for all function docstrings. (link)

siemplify = SiemplifyAction()
siemplify.script_name = REMEDIATE_MESSAGES_SCRIPT_NAME
siemplify.LOGGER.info(f"Action: {REMEDIATE_MESSAGES_SCRIPT_NAME} started")

# Integration config
api_url = extract_configuration_param(
siemplify,
provider_name=INTEGRATION_NAME,
param_name="API URL",
is_mandatory=True,
print_value=True,
)
api_key = extract_configuration_param(
siemplify,
provider_name=INTEGRATION_NAME,
param_name="API Key",
is_mandatory=True,
)
verify_ssl = extract_configuration_param(
siemplify,
provider_name=INTEGRATION_NAME,
param_name="Verify SSL",
input_type=bool,
is_mandatory=False,
default_value=True,
)

# Action parameters
action = extract_action_param(
siemplify, param_name="Action", is_mandatory=True, print_value=True
)
messages_raw = extract_action_param(
siemplify, param_name="Messages", is_mandatory=True, print_value=True
)
remediation_reason = extract_action_param(
siemplify, param_name="Remediation Reason", is_mandatory=True, print_value=True
)
tenant_ids_raw = extract_action_param(
siemplify, param_name="Tenant IDs", is_mandatory=False
)

messages = [m.strip() for m in messages_raw.split(",") if m.strip()]
tenant_ids = [t.strip() for t in tenant_ids_raw.split(",")] if tenant_ids_raw else None
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Inconsistent tenant ID parsing allows empty strings

Medium Severity

The tenant_ids parsing in RemediateMessages.py and SearchMessages.py does not filter out empty strings from the split result (e.g., "id1,,id2" produces ["id1", "", "id2"]). In contrast, GetActivityStatus.py correctly uses if t.strip() to filter them out. Empty strings in the tenant IDs list would be sent to the API, potentially causing errors or unexpected behavior.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4282490. Configure here.


result_value = False
status = EXECUTION_STATE_FAILED
output_message = ""

try:
manager = AbnormalManager(api_url=api_url, api_key=api_key, verify_ssl=verify_ssl)

response = manager.remediate_messages(
action=action,
messages=messages,
remediation_reason=remediation_reason,
tenant_ids=tenant_ids,
)

activity_log_id = response.get("activity_log_id", "")
siemplify.result.add_result_json(json.dumps(response))
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.

high

The add_result_json method handles the JSON serialization internally. By passing json.dumps(response), you are creating a double-encoded JSON string, which will likely cause issues in the playbook. Please pass the dictionary object directly.

Suggested change
siemplify.result.add_result_json(json.dumps(response))
siemplify.result.add_result_json(response)
References
  1. If an action returns a JSON result by calling result.add_result_json(...), it must be a valid JSON structure. Double-encoding can break playbook placeholders. (link)


output_message = (
f"Remediation request submitted for {len(messages)} message(s) with action "
f"'{action}'. Activity Log ID: {activity_log_id}. "
f"Use Get Activity Status to track completion."
)
result_value = True
status = EXECUTION_STATE_COMPLETED
siemplify.LOGGER.info(output_message)

except AbnormalValidationError as e:
output_message = f"Invalid remediation parameters: {e}"
siemplify.LOGGER.error(output_message)

except AbnormalAuthenticationError as e:
output_message = f"Authentication failed: {e}"
siemplify.LOGGER.error(output_message)

except AbnormalConnectionError as e:
output_message = f"Connection error: {e}"
siemplify.LOGGER.error(output_message)

except Exception as e:
output_message = f"An unexpected error occurred: {e}"
siemplify.LOGGER.error(output_message)
siemplify.LOGGER.exception(e)

siemplify.LOGGER.info("----------------- Main - Finished -----------------")
siemplify.LOGGER.info(f"Status: {status} Result: {result_value}")
siemplify.end(output_message, result_value, status)


if __name__ == "__main__":
main()
Loading
Loading