GreatHorn
The only cloud-native security platform that stops targeted social engineering and phishing attacks on cloud email platforms like Office 365 and G Suite.
Network Security · GreatHorn
Details
| ID | GreatHorn |
|---|---|
| Provider | SF2 GH Holdings |
| Category | Network Security |
| From Version | 6.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM |
README
The only cloud-native security platform that stops targeted social engineering and phishing attacks on cloud email platforms like Office 365 and G Suite.
This integration was integrated and tested with version 2.0 of GreatHorn
Configure GreatHorn in Cortex
| Parameter | Description | Required |
|---|---|---|
| url | Base URL | True |
| api_version | API Version | True |
| apikey | API Key | True |
| insecure | Trust any certificate (not secure) | False |
| proxy | Use system proxy settings | False |
Commands
You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
gh-get-message
Return message details for the specified event
Base Command
gh-get-message
Input
| Argument Name | Description | Required |
|---|---|---|
| id | GreatHorn eventId, multiple values supported via CSV. | Required |
| includeheaders | Whether or not to include full message headers in the War Room output. Possible values are: true, false. Default is false. | Optional |
| showalllinks | Whether or not to show all links in the War Room output. When false only suspicious and malicious links will be returned to the War Room. Possible values are: true, false. Default is false. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| GreatHorn.Message.eventId | Number | The GreatHorn event id |
| GreatHorn.Message.origin | String | Mailbox email was discovered |
| GreatHorn.Message.status | String | Has the system taken action on the event |
| GreatHorn.Message.xMailer | Unknown | X-Mailer header entry |
| GreatHorn.Message.sourcePath | String | GreatHorn discovered domain of sender |
| GreatHorn.Message.ip | String | GreatHorn discovered originating ip of sender |
| GreatHorn.Message.bodyOnlyWhitespace | Number | Body of email content is only whitespace |
| GreatHorn.Message.collector | Unknown | Email provider email discovered |
| GreatHorn.Message.dkim | String | dmarc authentication result |
| GreatHorn.Message.spf | String | spf authentication result |
| GreatHorn.Message.contentHash | String | Hash of email body conten |
| GreatHorn.Message.violations | Number | All body of email policy matches |
| GreatHorn.Message.workflow | String | Current action of event |
| GreatHorn.Message.targets | String | All recepients of the email |
| GreatHorn.Message.source | String | Email sender address |
| GreatHorn.Message.location | String | Location of sender ip origin |
| GreatHorn.Message.quarReleasedBy | Unknown | Who released the quarantined email |
| GreatHorn.Message.quarDeleted | Unknown | Has the event been deleted from quarantined |
| GreatHorn.Message.quarDeletedBy | Unknown | Who deleted the quarantined email |
| GreatHorn.Message.quarDenied | Unknown | Has the event been denied released from quarantined |
| GreatHorn.Message.subject | String | Email subject |
| GreatHorn.Message.xAuthResults | Unknown | X-Original-Authentication-Results header entry |
| GreatHorn.Message.dmarc | String | dmarc authentication result |
| GreatHorn.Message.returnPath | String | Return-Path header entry’ |
| GreatHorn.Message.received | String | Received header entry |
| GreatHorn.Message.replyTo | String | Reply-To header entry |
| GreatHorn.Message.timestamp | Date | timestamp of the event, usually receivedTime |
| GreatHorn.Message.flag | Number | All policies the event matched |
| GreatHorn.Message.homographScore | Number | GreatHorn homograph score |
| GreatHorn.Message.owlScore | Number | GreatHorn threat score |
| GreatHorn.Message.anomalyScore | Number | GreatHorn anomaly score |
| GreatHorn.Message.authScore | Number | GreatHorn illegitmacy score |
| GreatHorn.Message.remediation | Unknown | Remediation action taken |
| GreatHorn.Message.quarantined | Unknown | Has the event been quarantined |
| GreatHorn.Message.quarExpired | Unknown | Has the event been expired from quarantined |
| GreatHorn.Message.quarReleaseRequested | Unknown | Has the event been requested to be relased from quarantined |
| GreatHorn.Message.quarReleased | Unknown | Has the event been released from quarantined |
| GreatHorn.Message.displayName | String | Display name of sender |
| GreatHorn.Message.country | String | Country of sender ip country |
| GreatHorn.Message.region | String | Region of sender ip origin |
| GreatHorn.Message.authenticationResults | String | Authentication-Results header entry |
| GreatHorn.Message.messageId | String | Message-Id header entry |
| GreatHorn.Message.headers | Object | Full set of headers for the email |
| GreatHorn.Message.links.resolvedUrl | Unknown | The URL of the resolved link if it points elsewhere |
| GreatHorn.Message.links.text | String | The text showing for the link discovered in the body of the email |
| GreatHorn.Message.links.url | String | URL of link discovered in body of email |
| GreatHorn.Message.links.tags | String | List of tags describing the analysis of the event |
Command Example
!gh-get-message id="12345" includeheaders="true"
Context Example
{}
Human Readable Output
GreatHorn event not found
gh-search-message
Search for message based on filtering input
Base Command
gh-search-message
Input
| Argument Name | Description | Required |
|---|---|---|
| fields | The fields to include in the response. By default, all fields are returned. | Optional |
| filters | The criteria to use in filtering search results. This should be input as a dictionary. | Optional |
| limit | The maximum number of entries to return per page of results. Default is 10; max is 200. Default is 10. | Optional |
| offset | The zero-based offset of the first item in the collection. Default is 0; max is 10000. | Optional |
| sort | The field to use in sorting results. Default is eventId. Default is eventId. | Optional |
| sortDir | Indicates if the sort direction is ascending or descending. Default is descending. Possible values are: desc, asc. Default is desc. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| GreatHorn.Message.eventId | Number | The GreatHorn event id |
| GreatHorn.Message.origin | String | Mailbox email was discovered |
| GreatHorn.Message.status | String | Has the system taken action on the event |
| GreatHorn.Message.xMailer | Unknown | X-Mailer header entry |
| GreatHorn.Message.sourcePath | String | GreatHorn discovered domain of sender |
| GreatHorn.Message.ip | String | GreatHorn discovered originating ip of sender |
| GreatHorn.Message.bodyOnlyWhitespace | Number | Body of email content is only whitespace |
| GreatHorn.Message.collector | Unknown | Email provider email discovered |
| GreatHorn.Message.dkim | String | dmarc authentication result |
| GreatHorn.Message.spf | String | spf authentication result |
| GreatHorn.Message.contentHash | String | Hash of email body conten |
| GreatHorn.Message.violations | Number | All body of email policy matches |
| GreatHorn.Message.workflow | String | Current action of event |
| GreatHorn.Message.targets | String | All recepients of the email |
| GreatHorn.Message.source | String | Email sender address |
| GreatHorn.Message.location | String | Location of sender ip origin |
| GreatHorn.Message.quarReleasedBy | Unknown | Who released the quarantined email |
| GreatHorn.Message.quarDeleted | Unknown | Has the event been deleted from quarantined |
| GreatHorn.Message.quarDeletedBy | Unknown | Who deleted the quarantined email |
| GreatHorn.Message.quarDenied | Unknown | Has the event been denied released from quarantined |
| GreatHorn.Message.subject | String | Email subject |
| GreatHorn.Message.xAuthResults | Unknown | X-Original-Authentication-Results header entry |
| GreatHorn.Message.dmarc | String | dmarc authentication result |
| GreatHorn.Message.returnPath | String | Return-Path header entry’ |
| GreatHorn.Message.received | String | Received header entry |
| GreatHorn.Message.replyTo | String | Reply-To header entry |
| GreatHorn.Message.timestamp | Date | timestamp of the event, usually receivedTime |
| GreatHorn.Message.flag | Number | All policies the event matched |
| GreatHorn.Message.homographScore | Number | GreatHorn homograph score |
| GreatHorn.Message.owlScore | Number | GreatHorn threat score |
| GreatHorn.Message.anomalyScore | Number | GreatHorn anomaly score |
| GreatHorn.Message.authScore | Number | GreatHorn illegitmacy score |
| GreatHorn.Message.remediation | Unknown | Remediation action taken |
| GreatHorn.Message.quarantined | Unknown | Has the event been quarantined |
| GreatHorn.Message.quarExpired | Unknown | Has the event been expired from quarantined |
| GreatHorn.Message.quarReleaseRequested | Unknown | Has the event been requested to be relased from quarantined |
| GreatHorn.Message.quarReleased | Unknown | Has the event been released from quarantined |
| GreatHorn.Message.displayName | String | Display name of sender |
| GreatHorn.Message.country | String | Country of sender ip country |
| GreatHorn.Message.region | String | Region of sender ip origin |
| GreatHorn.Message.authenticationResults | String | Authentication-Results header entry |
| GreatHorn.Message.messageId | String | Message-Id header entry |
| GreatHorn.Message.headers | Object | Full set of headers for the email |
| GreatHorn.Message.links.resolvedUrl | Unknown | The URL of the resolved link if it points elsewhere |
| GreatHorn.Message.links.text | String | The text showing for the link discovered in the body of the email |
| GreatHorn.Message.links.url | String | URL of link discovered in body of email |
| GreatHorn.Message.links.tags | String | List of tags describing the analysis of the event |
Command Example
!gh-search-message filters="[{\"targets\": [\"penguin@scuftysails.com\"], \"origin\": [\"action@ifttt.com\"]}]"
Context Example
{
"GreatHorn": {
"Message": {
"Message": [],
"SearchCount": 0
}
}
}
Human Readable Output
Events
No entries.
gh-remediate-message
Perform the specified remediation action on message
Base Command
gh-remediate-message
Input
| Argument Name | Description | Required |
|---|---|---|
| action | The action to take on the given message. Possible values are: archive, banner, delete, label, move, quarantine, delete, removeattachments, review, trash. | Required |
| eventId | The GreatHorn event ID. | Required |
| hasButton | If true, the banner will include a button enabling the end-user to remove the banner. Default is True. Possible values are: True, False. Default is True. | Optional |
| message | The text to display in the email’s banner. | Optional |
| label | The name of the label to add. If the label name does not exist, it will be created. | Optional |
| location | The target location in the user’s mailbox. If the location does not exist, it will be created. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| GreatHorn.Remediation.action | String | Remediation action requested to be taken on the event |
| GreatHorn.Remediation.eventId | String | The Greathorn event ID |
| GreatHorn.Remediation.reason | String | Details of error seen if any |
| GreatHorn.Remediation.success | Number | Indication if the request was successful |
Command Example
!gh-remediate-message action="banner" message="This email may be a phishing attempt" eventId="20128"
Context Example
{
"GreatHorn": {
"Remediation": {
"action": "banner",
"eventId": "20128",
"reason": "completed",
"success": true
}
}
}
Human Readable Output
Remediate action banner applied successfully to message 20128
gh-revert-remediate-message
Revert the specified remediation action on the given message
Base Command
gh-revert-remediate-message
Input
| Argument Name | Description | Required |
|---|---|---|
| action | Remediation action to revert. Possible values are: banner, quarantinerequest, quarantinerelease, quarantinedeny, removeattachments, review. | Required |
| eventId | The GreatHorn event ID. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| GreatHorn.Remediation.action | String | Remediation action that was reverted |
| GreatHorn.Remediation.eventId | String | The GreatHorn event ID |
| GreatHorn.Remediation.reason | String | Details of error seen if any |
| GreatHorn.Remediation.success | Number | Indication if the request was successful |
Command Example
!gh-revert-remediate-message action="banner" eventId="20128"
Context Example
{
"GreatHorn": {
"Remediation": {
"action": "banner",
"eventId": "20128",
"reason": "completed",
"success": true
}
}
}
Human Readable Output
Revert action banner applied successfully to message 20128
gh-get-policy
Retrieve details about the policy specified
Base Command
gh-get-policy
Input
| Argument Name | Description | Required |
|---|---|---|
| policyid | The ID of the policy. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| GreatHorn.Policy.name | String | The user-defined name of the policy |
| GreatHorn.Policy.enabled | Number | Whether the policy is enabled |
| GreatHorn.Policy.config | String | The match configuration of the policy |
| GreatHorn.Policy.id | Number | The ID of the policy |
| GreatHorn.Policy.description | String | The user-defined description of the policy |
Command Example
!gh-get-policy policyid="16567"
Context Example
{
"GreatHorn": {
"Policy": {
"actions": [
{
"addresses": [
""
],
"quarantineNotification": false,
"releaseNotification": false,
"type": "quarantine"
}
],
"config": [
"or",
[
"and",
{
"opt": "from",
"type": "regex",
"values": [
"asdf2@asdf2.com",
"asdf@asdf.com"
]
}
]
],
"description": "",
"enabled": true,
"id": 16567,
"name": "Penalty box policy"
}
}
}
Human Readable Output
Policy
ID Name Enabled Description Actions 16567 Penalty box policy true quarantine
gh-set-policy
Retrieve details about the policy specified.
Base Command
gh-set-policy
Input
| Argument Name | Description | Required |
|---|---|---|
| updatemethod | Update method for the given policy. Possible values are: patch, put. | Required |
| policyid | The ID of the policy. | Required |
| policyjson | Policy defintion or policy change defintion. Input as a dictionary. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| GreatHorn.Policy.id | Number | The ID of the policy. |
Command Example
!gh-set-policy policyid="16567" updatemethod="patch" policyjson="{\"config\": [\"or\", [\"and\", {\"opt\": \"from\", \"values\": [\"asdf@asdf.com\",\"asdf2@asdf2.com\"], \"type\": \"regex\"}]]}"
Context Example
{
"GreatHorn": {
"Policy": {
"id": "16567",
"success": true
}
}
}
Human Readable Output
Update applied successfully to policy 16567
Configuration parameters
url— Base URL (required)api_version— API Version (required)apikey— API Key (required)insecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (6)
-
gh-get-messageReturn message details for the specified event
-
gh-get-policyRetrieve details about the policy specified
-
gh-remediate-messagePerform the specified remediation action on message
-
gh-revert-remediate-messageRevert the specified remediation action on the given message
-
gh-search-messageSearch for message based on filtering input
-
gh-set-policyRetrieve details about the policy specified.
import json import traceback from typing import Any import demistomock as demisto # noqa: F401 import urllib3 from CommonServerPython import * # noqa: F401 # Disable insecure warnings urllib3.disable_warnings() """ CLIENT CLASS """ class Client(BaseClient): """Client class to interact with the service API This Client implements API calls, and does not contain any Demisto logic. Should only do requests and return data. It inherits from BaseClient defined in CommonServer Python. Most calls use _http_request() that handles proxy, SSL verification, etc. """ def get_policy(self, policy_id: str | None = None) -> dict[str, Any]: if policy_id: return self._http_request(method="GET", url_suffix=f"/policy/{policy_id}") else: return self._http_request(method="GET", url_suffix="/policy") def set_policy(self, policy_id: str, update_method: str, policy_json: dict[str, Any]) -> dict[str, Any]: update_method = update_method.upper() return self._http_request(method=update_method, url_suffix=f"/policy/{policy_id}", json_data=policy_json) def search_events(self, args: dict | None) -> dict[str, Any]: return self._http_request(method="POST", url_suffix="/search/events", json_data=args) def remediate_message(self, action: str, action_args: dict | None) -> dict[str, Any]: return self._http_request(method="POST", url_suffix=f"/remediation/{action}", json_data=action_args) def revert_remediate_message(self, action: str, action_args: dict | None) -> dict[str, Any]: return self._http_request(method="POST", url_suffix=f"/remediation/revert/{action}", json_data=action_args) """ COMMAND FUNCTIONS """ def test_module(client: Client) -> str: """Tests API connectivity and authentication' Returning 'ok' indicates that the integration works like it is supposed to. Connection to the service is successful. Raises exceptions if something goes wrong. :type client: ``Client`` :param Client: GreatHorn client to use :return: 'ok' if test passed, anything else will fail the test. :rtype: ``str`` """ try: client.get_policy() except DemistoException as e: if "Forbidden" in str(e): raise ValueError("Authorization Error: make sure API Key is correctly set") else: raise e return "ok" def gh_search_message_command(client: Client, args: dict[str, Any]) -> CommandResults: fields = argToList(args.get("fields")) limit = args.get("limit") sort = args.get("sort") sortDir = args.get("sortDir") offset = args.get("offset") filters = json.loads(args.get("filters", "[]")) args = {"filters": filters} if fields is not None and len(fields) > 0: if "eventId" not in fields: fields.append("eventId") args["fields"] = fields if limit is not None: args["limit"] = limit if offset is not None: args["offset"] = offset if sort is not None: args["sort"] = sort if sortDir is not None: args["sortDir"] = sortDir results = client.search_events(args) events = [] if fields is None or len(fields) == 0: for event in results.get("results", []): e = { "ID": event.get("eventId"), "From Address": event.get("source"), "Mailbox": event.get("origin"), "Return Path": event.get("sourcePath"), "Subject": event.get("subject"), "Occurred": event.get("timestamp"), } policy_names = [] policy_actions = [] if event.get("flag") is not None: for policy_id in event.get("flag", []): policy = client.get_policy(policy_id).get("policy", {}) actions = [] for action in policy.get("actions"): actions.append(action.get("type")) policy_names.append(policy.get("name")) policy_actions.extend(actions) e["Policy Hits"] = policy_names e["Policy Actions"] = policy_actions if len(event.get("files", [])) > 0: e["Has Attachments"] = True else: e["Has Attachments"] = False if len(event.get("links", [])) > 0: e["Has Links"] = True else: e["Has Links"] = False events.append(e) events_md = tableToMarkdown( "Events", events, [ "ID", "From Address", "Mailbox", "Return Path", "Subject", "Policy Hits", "Policy Actions", "Occurred", "Has Attachments", "Has Links", ], ) else: events_md = tableToMarkdown("Events", results.get("results", []), fields) result = {"Message": results.get("results"), "SearchCount": results.get("total")} return CommandResults( readable_output=events_md, outputs_prefix="GreatHorn.Message", outputs_key_field="eventId", outputs=result ) def gh_revert_remediate_message_command(client: Client, args: dict[str, Any]) -> CommandResults: valid_actions: dict[str, list] = { "banner": [], "quarantinerequest": [], "quarantinerelease": [], "quarantinedeny": [], "removeattachments": [], "review": [], } if args.get("action", "").lower() not in valid_actions: raise ValueError('Invalid action "{}" specified'.format(args.get("action"))) action = args.get("action", "").lower() for arg in valid_actions.get(action, []): if args.get(arg) is None: raise ValueError(f'Revert action "{action}" requires argument "{arg}" to be specified') del args["action"] if action == "quarantinerequest": action = "quarantine/request" if action == "quarantinerelease": action = "quarantine" if action == "quarantinedeny": action = "quarantine/deny" results = client.revert_remediate_message(action, args) human_readable = "" if results.get("success") is True: human_readable = "Revert action {} applied successfully to message {}".format(action, args.get("eventId")) else: if results.get("reason") == "alreadyDone": human_readable = "Revert action {} has already been performed on message {}".format(action, args.get("eventId")) results["action"] = action results["eventId"] = args.get("eventId") return CommandResults( readable_output=human_readable, outputs_prefix="GreatHorn.Remediation", outputs_key_field="eventId", outputs=results ) def gh_remediate_message_command(client: Client, args: dict[str, Any]) -> CommandResults: valid_actions: dict[str, list] = { "archive": [], "banner": ["hasButton", "message"], "delete": [], "label": ["label"], "move": ["location"], "quarantine": [], "removeattachments": [], "review": [], "trash": [], } if args.get("action", "").lower() not in valid_actions: raise ValueError('Invalid action "{}" specified'.format(args.get("action"))) action = args.get("action", "").lower() for arg in valid_actions.get(action, []): if args.get(arg) is None: raise ValueError(f'Remediate action "{action}" requires argument "{arg}" to be specified') del args["action"] if action != "banner": args.pop("hasButton", None) results = client.remediate_message(action, args) human_readable = "" if results.get("success") is True: human_readable = "Remediate action {} applied successfully to message {}".format(action, args.get("eventId")) else: if results.get("reason") == "alreadyDone": human_readable = "Remediate action {} has already been performed on message {}".format(action, args.get("eventId")) results["action"] = action results["eventId"] = args.get("eventId") return CommandResults( readable_output=human_readable, outputs_prefix="GreatHorn.Remediation", outputs_key_field="eventId", outputs=results ) def gh_set_policy_command(client: Client, args: dict[str, Any]) -> CommandResults: update_method = args.get("updatemethod", "").lower() policy_id = args.get("policyid", "") policy_json = json.loads(args.get("policyjson", {})) if update_method not in ["patch", "put"]: raise ValueError("Invalid updatemethod specified, please use either put or patch.") results = client.set_policy(policy_id, update_method, policy_json) human_readable = "" if results.get("success") is True: human_readable = "Update applied successfully to policy {}".format(args.get("policyid")) results["id"] = args.get("policyid") return CommandResults( readable_output=human_readable, outputs_prefix="GreatHorn.Policy", outputs_key_field="id", outputs=results ) def gh_get_policy_command(client: Client, args: dict[str, Any]) -> CommandResults: policy_ids = argToList(args.get("policyid")) results = [] if policy_ids: for policy_id in policy_ids: result = client.get_policy(policy_id) results.append(result.get("policy")) else: results = client.get_policy().get("policies", []) policies = [] for r in results: if not isinstance(r, dict): # Make mypy calm down about the policy dict continue actions = [] for action in r.get("actions", []): actions.append(action.get("type")) policy = { "ID": r.get("id", ""), "Name": r.get("name", ""), "Enabled": r.get("enabled", ""), "Description": r.get("description", ""), "Actions": ",".join(actions), } policies.append(policy) policies_md = tableToMarkdown("Policy", policies, ["ID", "Name", "Enabled", "Description", "Actions"]) return CommandResults(readable_output=policies_md, outputs_prefix="GreatHorn.Policy", outputs_key_field="id", outputs=results) def gh_get_message_command(client: Client, args: dict[str, Any]) -> CommandResults: ghid = argToList(args.get("id")) includeheaders = args.get("includeheaders", "false").lower() == "true" showalllinks = args.get("showalllinks", "false").lower() == "true" result = client.search_events({"filters": [{"eventId": ghid}]}) if len(result.get("results", [])) > 0: message = result.get("results", [None])[0] envelope = { "ID": message.get("eventId"), "Received": message.get("timestamp"), "Mailbox": message.get("origin"), "Recipients": message.get("targets"), "Subject": message.get("subject"), "Display Name": message.get("displayName"), "From Address": message.get("source"), "From Domain": message.get("source").split("@")[-1], "Reply-To": message.get("replyTo"), "Return-Path": message.get("sourcePath"), "IP Address": message.get("ip"), } envelope_md = tableToMarkdown("Message Details", envelope, envelope.keys()) authentication = { "SPF": message.get("spf"), "DKIM": message.get("dkim"), "DMARC": message.get("dmarc"), "Authentication Results": message.get("authenticationResults"), } authentication_md = tableToMarkdown("Message Authentication", authentication, authentication.keys()) scores = { "OWL": message.get("owlScore"), "Sender Anomaly": message.get("anomalyScore"), "Authenication Risk": message.get("authScore"), "Name Spoofing": message.get("homographScore"), } scores_md = tableToMarkdown("Risk Analysis Factors", scores, scores.keys()) links = [] for link in message.get("links"): link_dict = {"Text": link.get("text"), "Url": link.get("url"), "Tags": ", ".join(link.get("tags", []))} if showalllinks: links.append(link_dict) else: if "suspicious" in link_dict["Tags"] or "malicious" in link_dict["Tags"]: links.append(link_dict) # break if showalllinks: links_md = tableToMarkdown("Links", links, ["Text", "Url", "Tags"]) else: links_md = tableToMarkdown("Suspicious/Malicious Links", links, ["Text", "Url", "Tags"]) files = [] for file in message.get("files"): f = {"Name": file.get("fileName"), "Type": file.get("fileType"), "SHA256": file.get("fileHash")} files.append(f) files_md = tableToMarkdown("Files", files, ["Name", "Type", "SHA256"]) policies = [] if message.get("flag") is not None: for policy_id in message.get("flag"): policy = client.get_policy(policy_id).get("policy", {}) actions = [] for action in policy.get("actions"): actions.append(action.get("type")) p = {"ID": policy.get("id"), "Name": policy.get("name"), "Actions": ",".join(actions)} policies.append(p) policies_md = tableToMarkdown("Policies", policies, ["ID", "Name", "Actions"]) headers = [] msgheaders = message.get("headers") for header in message.get("headers"): h = {"Name": header, "Value": msgheaders[header]} headers.append(h) if includeheaders: headers_md = tableToMarkdown("Headers", headers, ["Name", "Value"]) else: headers_md = "" message_md = envelope_md + authentication_md + scores_md + links_md + files_md + policies_md + headers_md return CommandResults( readable_output=message_md, outputs_prefix="GreatHorn.Message", outputs_key_field="eventId", outputs=result.get("results", [None])[0], ) else: return CommandResults(readable_output="GreatHorn event not found", outputs={}) """ MAIN FUNCTION """ def main(): """main function, parses params and runs command functions :return: :rtype: """ api_key = demisto.params().get("apikey") # get the service API url base_url = urljoin(demisto.params()["url"], demisto.params()["api_version"]) # if your Client class inherits from BaseClient, SSL verification is # handled out of the box by it, just pass ``verify_certificate`` to # the Client constructor verify_certificate = not demisto.params().get("insecure", False) # if your Client class inherits from BaseClient, system proxy is handled # out of the box by it, just pass ``proxy`` to the Client constructor proxy = demisto.params().get("proxy", False) demisto.debug(f"Command being called is {demisto.command()}") try: headers = {"Authorization": f"Bearer {api_key}"} client = Client(base_url=base_url, verify=verify_certificate, headers=headers, proxy=proxy) if demisto.command() == "test-module": # This is the call made when pressing the integration Test button. result = test_module(client) return_results(result) elif demisto.command() == "gh-get-message": return_results(gh_get_message_command(client, demisto.args())) elif demisto.command() == "gh-get-policy": return_results(gh_get_policy_command(client, demisto.args())) elif demisto.command() == "gh-set-policy": return_results(gh_set_policy_command(client, demisto.args())) elif demisto.command() == "gh-remediate-message": return_results(gh_remediate_message_command(client, demisto.args())) elif demisto.command() == "gh-revert-remediate-message": return_results(gh_revert_remediate_message_command(client, demisto.args())) elif demisto.command() == "gh-search-message": return_results(gh_search_message_command(client, demisto.args())) # Log exceptions and return errors except Exception as e: demisto.error(traceback.format_exc()) # print the traceback return_error(f"Failed to execute {demisto.command()} command.\nError:\n{e!s}") """ ENTRY POINT """ if __name__ in ("__main__", "__builtin__", "builtins"): main()