Details
| ID | Perch |
|---|---|
| Provider | Razor Group |
| Category | Network Security |
| From Version | 5.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM |
README
Use the Perch integration to manage alerts, indicators, and communities.
This integration was integrated and tested with the latest version of Perch.
Configure Perch on Cortex XSOAR
- Navigate to Settings > Integrations > Servers & Services.
- Search for Perch.
- Click Add instance to create and configure a new integration instance.
- Name: a textual name for the integration instance.
- Server URL (e.g., https://api.perch.rocks/)
- API Token
- Trust any certificate (not secure)
- Use system proxy
- Previous days to fetch
- Credentials
- Incident Soc Statuses to Fetch
- Click Test to validate the URLs, token, and connection.
Commands
You can execute these commands from the Cortex XSOAR 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.
- Search for alerts: perch-search-alerts
- Get information for a community: perch-get-community
- Get a list of all communities: perch-list-communities
- Create an indicator: perch-create-indicator
1. Search for alerts
Searches for alerts in Perch.
Base Command
perch-search-alerts
Input
| Argument Name | Description | Required |
|---|---|---|
| page | Page of results to return. | Optional |
| page_size | Number of results to return per page. | Optional |
| closed | Whether the alert is closed. | Optional |
| closed_at | Time that the alert was closed. | Optional |
| community_id | Community ID that generated the alert. | Optional |
| created_at | Time that the alert was created. | Optional |
| dest_ip | Destination IP address. | Optional |
| dest_port | Destination port. | Optional |
| full_url | Full URL of the alert. | Optional |
| id | ID of the alert. | Optional |
| indicator_id | ID of the indicator. | Optional |
| indicator_loaded | Whether the indicator is loaded. | Optional |
| observable_id | Observable ID. | Optional |
| protocol | Protocol effected by the alert. | Optional |
| sensor_id | ID of the sensor that generated the alert. | Optional |
| sensor_name | Name of the sensor that generated the alert. | Optional |
| soc_status | Status in the SOC. | Optional |
| src_ip | Source IP address. | Optional |
| src_port | Source port. | Optional |
| status | Status of the alert. | Optional |
| status_updated_at | Time that the status was last updated. | Optional |
| team_id | ID of the team that generated the alert. | Optional |
| title | Title of the alert. | Optional |
| ts | Timestamp of the alert. | Optional |
| ordering | Order of the returned alerts. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Perch.Alert.DestPort | Number | Destination port of the alert. |
| Perch.Alert.SrcPort | Number | Source port of the alert. |
| Perch.Alert.DestIP | Number | Destination IP of the alert. |
| Perch.Alert.IndicatorID | Number | Indicator ID of the alert. |
| Perch.Alert.SrcIP | String | IP address of the source. |
| Perch.Alert.SrcGeo.Country | String | Country of the threat. |
| Perch.Alert.SrcGeo.Latitude | Number | Latitude of the detected threat. |
| Perch.Alert.SrcGeo.Longitude | Number | Longitude of the detected threat. |
| Perch.Alert.SensorID | Number | ID of the sensor that reported the threat. |
| Perch.Alert.Title | String | Title of the alert. |
| Perch.Alert.Protocol | String | Protocol on which the alert was detected. |
| Perch.Alert.ID | Number | ID of the alert. |
| Perch.Alert.ObservableID | Number | ID of the observable event. |
| Perch.Alert.TS | Date | Timestamp of the alert. |
Command Example
!perch-search-alerts page_size=1
Context Example
{
"Perch": {
"Alert": [
{
"Protocol": "TCP",
"Title": "ET TOR Known Tor Relay/Router (Not Exit) Node Traffic group 82",
"SrcPort": 30834,
"TS": "2019-07-22T08:49:28.518216+0000",
"ID": 854408,
"ObservableID": 908757,
"DestIP": "172.31.46.243",
"IndicatorID": "EmergingThreats:Indicator-2522162",
"SrcIP": "77.247.181.163",
"SensorID": 9185,
"SrcGeo": {
"Latitude": 52.3824,
"Country": "Netherlands",
"Longitude": 4.8995
},
"DestPort": 22
}
]
}
}
Human Readable Output
ET TOR Known Tor Relay/Router (Not Exit) Node Traffic group 82
| Destination IP | Destination Port | ID | Indicator ID | Observable ID | Protocol | Sensor ID | Source Geo | Source IP | Source Port | Timestamp | Title |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 172.31.46.243 | 22 | 854408 | EmergingThreats:Indicator-2522162 | 908757 | TCP | 9185 | Latitude: 52.3824<br>Longitude: 4.8995<br>Country Name: Netherlands | 77.247.181.163 | 30834 | 2019-07-22T08:49:28.518216+0000 | ET TOR Known Tor Relay/Router (Not Exit) Node Traffic group 82 |
2. Get information for a community
Gets community information by ID.
Base Command
perch-get-community
Input
| Argument Name | Description | Required |
|---|---|---|
| id | ID of the community. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Perch.Community.Allsectors | Boolean | Indicates if the community covers all sectors. |
| Perch.Community.Credentialreq | Number | Credentials required to interact with the community. |
| Perch.Community.Desc | String | Description of the community. |
| Perch.Community.Id | Number | ID of the community. |
| Perch.Community.Name | String | Name of the community. |
| Perch.Community.Poweredby | String | Organization providing the feed. |
| Perch.Community.Selectablefeeds | Boolean | Whether the feeds are selectable. |
Command Example
!perch-get-community id=1
Context Example
{
"Perch": {
"Community": {
"Selectablefeeds": true,
"Allsectors": true,
"Name": "Hail-a-TAXII",
"Credentialreq": 2,
"Poweredby": "Soltra Edge",
"Id": 1,
"Desc": "A repository of Open Source Cyber Threat Intellegence feeds in STIX format"
}
}
}
Human Readable Output
Communities Found
| Allsectors | Credentialreq | Desc | Id | Name | Poweredby | Selectablefeeds |
|---|---|---|---|---|---|---|
| true | 2 | A repository of Open Source Cyber Threat Intelligence feeds in STIX format | 1 | Hail-a-TAXII | Soltra Edge | true |
3. Get a list of all communities
Returns a list of all communities.
Base Command
perch-list-communities
Input
There are no input arguments for this command.
Context Output
| Path | Type | Description |
|---|---|---|
| Perch.Community.Allsectors | Boolean | Indicates if the community covers all sectors. |
| Perch.Community.Credentialreq | Number | Credentials required to interact with the community. |
| Perch.Community.Desc | String | Description of the community. |
| Perch.Community.Id | Number | ID of the community. |
| Perch.Community.Name | String | Name of the community. |
| Perch.Community.Poweredby | String | Organization providing the feed. |
| Perch.Community.Selectablefeeds | Boolean | Whether the feeds are selectable. |
Command Example
!perch-list-communities
Context Example
{
"Perch": {
"Community": [
{
"Selectablefeeds": true,
"Allsectors": true,
"Name": "Hail-a-TAXII",
"Credentialreq": 2,
"Poweredby": "Soltra Edge",
"Id": 1,
"Desc": "A repository of Open Source Cyber Threat Intellegence feeds in STIX format"
},
{
"Selectablefeeds": false,
"Allsectors": true,
"Name": "DHS AIS",
"Credentialreq": 2,
"Poweredby": "Flare",
"Id": 5,
"Desc": "Department of Homeland Security - Automated Indicator Sharing"
},
{
"Selectablefeeds": true,
"Allsectors": true,
"Name": "Emerging Threats",
"Credentialreq": 0,
"Poweredby": "Emerging Threats",
"Id": 8,
"Desc": "Open source intelligence data provided by Emerging Threats/ProofPoint"
}
]
}
}
Human Readable Output
Communities Found
| Allsectors | Credentialreq | Desc | Id | Name | Poweredby | Selectablefeeds |
|---|---|---|---|---|---|---|
| true | 2 | A repository of Open Source Cyber Threat Intellegence feeds in STIX format | 1 | Hail-a-TAXII | Soltra Edge | true |
| true | 2 | Department of Homeland Security - Automated Indicator Sharing | 5 | DHS AIS | Flare | false |
| true | 0 | Open source intelligence data provided by Emerging Threats/ProofPoint | 8 | Emerging Threats | Emerging Threats | true |
4. Create an indicator
Creates an indicator in Perch.
Base Command
perch-create-indicator
Input
| Argument Name | Description | Required |
|---|---|---|
| communities | Communities to report the indicator to. | Required |
| confidence | Confidence of the findings. | Required |
| type | Type of indicator. | Required |
| value | The value of the indicator. | Required |
| title | The title of the indicator. | Required |
| description | Description of the indicator. | Required |
| tlp | TLP of the Indicator. | Required |
| operator | Operator of the indicator. | Optional |
| first_sighting | When the indicator was first sighted. | Optional |
| email_summary | Sends an email with the summary of the indicator. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Perch.Indicator.Confidence | Unknown | Confidence of the indicator. |
| Perch.Indicator.UpdatedAt | Date | Date and time that the indicator was last updated. |
| Perch.Indicator.TLP | String | TLP of the Indicator. |
| Perch.Indicator.Title | String | Title of the indicator. |
| Perch.Indicator.ID | Number | ID of the indicator. |
| Perch.Indicator.CreatedAt | Date | Date that the indicator was created. |
| Perch.Indicator.Team | Number | ID of the team. |
| Perch.Indicator.PerchID | String | The Perch ID for the incident. |
| Perch.Indicator.CreatedBy | Number | ID of the user that created the incident. |
Command Example
!perch-create-indicator communities=8 confidence=LOW description="Sample Alert Generated via Demisto" title="Sample Alert" tlp=WHITE type=Domain value="sample.com"
Context Example
{
"Perch": {
"Indicator": [
{
"Description": "Sample Alert Generated via Demisto",
"Title": "Sample Alert",
"UpdatedAt": "2019-07-23T20:06:26.046774Z",
"PerchID": "41716ec9-4001-4d20-8aba-04137fa47c83",
"CreatedBy": 11728,
"Team": 5394,
"ID": 1236830,
"CreatedAt": "2019-07-23T20:06:26.046757Z"
}
]
}
}
Human Readable Output
Sample Alert
| Created At | Created By | Description | ID | Perch ID | Team | Title | Updated At |
|---|---|---|---|---|---|---|---|
| 2019-07-23T20:06:26.046757Z | 11728 | Sample Alert Generated via Demisto | 1236830 | 41716ec9-4001-4d20-8aba-04137fa47c83 | 5394 | Sample Alert | 2019-07-23T20:06:26.046774Z |
Configuration parameters
url— Server URL (e.g., https://api.perch.rocks/) (required)api-key— API Tokenapi-key_creds—insecure— Trust any certificate (not secure)proxy— Use system proxy settingsfetch_time— Previous days to fetchcredentials— CredentialsisFetch— Fetch incidentsincidentType— Incident typeincidentFetchInterval— Incidents Fetch Intervalsoc_status— Incident Soc Statuses to Fetch
Commands (4)
-
perch-create-indicatorCreates an indicator in Perch.
-
perch-get-communityGets community information by ID.
-
perch-list-communitiesLists all communities.
-
perch-search-alertsSearches for alerts in Perch.
import demistomock as demisto from CommonServerPython import * from CommonServerUserPython import * """ IMPORTS """ import requests import json import collections import urllib3 # Disable insecure warnings urllib3.disable_warnings() """ GLOBALS/PARAMS """ PARAMS = demisto.params() USERNAME = PARAMS.get("credentials").get("identifier") PASSWORD = PARAMS.get("credentials").get("password") API_KEY = PARAMS.get("api-key_creds", {}).get("password") or PARAMS.get("api-key") FETCH_TIME = int(PARAMS.get("fetch_time", "7")) SERVER = PARAMS["url"].removesuffix("/") USE_SSL = not PARAMS.get("insecure", False) BASE_URL = SERVER + "/v1" # Remove proxy if not set to true in params handle_proxy() STATUSES = {"Not Reviewed": "0", "Investigating": "1", "On hold": "2", "False Positive": "3", "Escalated": "4"} TLP_MAP = {"WHITE": 0, "GREEN": 1, "AMBER": 2, "RED": 3} CONFIDENCE_MAP = {"LOW": 0, "MEDIUM": 1, "HIGH": 2} OBSERVABLE_TYPES_MAP = {"IP": 0, "Domain": 1, "URL": 2, "REGEX": 3, "File Hash": 4} """ HELPER FUNCTIONS """ # Allows nested keys to be accessible def makehash(): return collections.defaultdict(makehash) def http_request(method, url_suffix, params=None, data=None, headers=None): try: res = requests.request(method, BASE_URL + url_suffix, verify=USE_SSL, params=params, data=data, headers=headers) if res.status_code == 403: return_error("Connection forbidden. Please verify your API key is valid.") elif res.status_code not in {200, 201}: return_error(f"Error in API call to Perch Integration [{res.status_code}] - {res.reason}") except requests.exceptions.ConnectionError as error: return_error(f"Failed to establish a new connection: {type(error)}") try: response = res.json() except Exception as e: return_error(f"Failed to parse JSON response: {str(e)}") return response def find_key_by_value(val, dic_map): for key, value in dic_map.items(): if value == val: return key return None def format_alerts(alert): hr = makehash() # type: dict ec = makehash() # type: dict if alert.get("id"): hr["ID"] = alert.get("id") ec["ID"] = alert.get("id") if alert.get("sensor_id"): hr["Sensor ID"] = alert.get("sensor_id") ec["SensorID"] = alert.get("sensor_id") if alert.get("observable_id"): hr["Observable ID"] = alert.get("observable_id") ec["ObservableID"] = alert.get("observable_id") if alert.get("indicator_id"): hr["Indicator ID"] = alert.get("indicator_id") ec["IndicatorID"] = alert.get("indicator_id") if alert.get("status"): hr["Status"] = alert.get("status") ec["Status"] = alert.get("status") if alert.get("ts"): hr["Timestamp"] = alert.get("ts") ec["TS"] = alert.get("ts") if alert.get("title"): hr["Title"] = alert.get("title") ec["Title"] = alert.get("title") if alert.get("protocol"): hr["Protocol"] = alert.get("protocol") ec["Protocol"] = alert.get("protocol") if alert.get("src_ip"): hr["Source IP"] = alert.get("src_ip") ec["SrcIP"] = alert.get("src_ip") if alert.get("src_port"): hr["Source Port"] = alert.get("src_port") ec["SrcPort"] = alert.get("src_port") if alert.get("src_geo_ip"): src_geo = alert["src_geo_ip"] if src_geo.get("latitude"): hr["Source Geo"]["Latitude"] = src_geo.get("latitude") ec["SrcGeo"]["Latitude"] = src_geo.get("latitude") if src_geo.get("longitude"): hr["Source Geo"]["Longitude"] = src_geo.get("longitude") ec["SrcGeo"]["Longitude"] = src_geo.get("longitude") if src_geo.get("country_name"): hr["Source Geo"]["Country Name"] = src_geo.get("country_name") ec["SrcGeo"]["Country"] = src_geo.get("country_name") if alert.get("dest_ip"): hr["Destination IP"] = alert.get("dest_ip") ec["DestIP"] = alert.get("dest_ip") if alert.get("dest_port"): hr["Destination Port"] = alert.get("dest_port") ec["DestPort"] = alert.get("dest_port") if alert.get("dest_geo_ip"): dest_geo = alert["dest_geo_ip"] if dest_geo.get("latitude"): hr["Destination Geo"]["Latitude"] = dest_geo.get("latitude") ec["DestGeo"]["Latitude"] = dest_geo.get("latitude") if dest_geo.get("longitude"): hr["Destination Geo"]["Longitude"] = dest_geo.get("longitude") ec["DestGeo"]["Longitude"] = dest_geo.get("longitude") if dest_geo.get("country_name"): hr["Destination Geo"]["Country Name"] = dest_geo.get("country_name") ec["DestGeo"]["Country"] = dest_geo.get("country_name") return hr, ec def alerts_params(args): params = {} # type:dict if args.get("page"): params["page"] = args.get("page") if args.get("page_size"): params["page_size"] = args.get("page_size") if args.get("closed"): params["closed"] = args.get("closed") if args.get("closed_at"): params["closed_at"] = args.get("closed_at") if args.get("community_id"): params["community_id"] = args.get("community_id") if args.get("created_at"): params["created_at"] = args.get("created_at") if args.get("dest_ip"): params["dest_ip"] = args.get("dest_ip") if args.get("dest_port"): params["dest_port"] = args.get("dest_port") if args.get("full_url"): params["full_url"] = args.get("full_url") if args.get("id"): params["id"] = args.get("id") if args.get("indicator_id"): params["indicator_id"] = args.get("indicator_id") if args.get("indicator_loaded"): params["indicator_loaded"] = args.get("indicator_loaded") if args.get("observable_id"): params["observable_id"] = args.get("observable_id") if args.get("protocol"): params["protocol"] = args.get("protocol") if args.get("sensor_id"): params["sensor_id"] = args.get("sensor_id") if args.get("sensor_name"): params["sensor_name"] = args.get("sensor_name") if args.get("soc_status"): params["soc_status"] = args.get("soc_status") if args.get("src_ip"): params["src_ip"] = args.get("src_ip") if args.get("src_port"): params["src_port"] = args.get("src_port") if args.get("status"): params["status"] = args.get("status") if args.get("status_updated_at"): params["status_updated_at"] = args.get("status_updated_at") if args.get("team_id"): params["team_id"] = args.get("team_id") if args.get("title"): params["title"] = args.get("title") if args.get("ts"): params["ts"] = args.get("ts") if args.get("closed_at__gte"): params["closed_at__gte"] = args.get("closed_at__gte") if args.get("closed_at__lte"): params["closed_at__lte"] = args.get("closed_at__lte") if args.get("created_at__gte"): params["created_at__gte"] = args.get("created_at__gte") if args.get("created_at__lte"): params["created_at__lte"] = args.get("created_at__lte") if args.get("status_updated_at__gte"): params["status_updated_at__gte"] = args.get("status_updated_at__gte") if args.get("status_updated_at__lte"): params["status_updated_at__lte"] = args.get("status_updated_at__lte") if args.get("status_updated_at__gt"): params["status_updated_at__gt"] = args.get("status_updated_at__gt") if args.get("status_updated_at__lt"): params["status_updated_at__lt"] = args.get("status_updated_at__lt") if args.get("ordering"): params["ordering"] = args.get("ordering") return params def indicator_params(args): params = [] param = {} observables = [] communities = [] if args.get("communities"): community = {"id": args.get("communities")} communities.append(community) param["communities"] = communities if args.get("type"): observable = {"type": OBSERVABLE_TYPES_MAP[args.get("type")], "details": {"value": args.get("value")}} observables.append(observable) param["observables"] = observables if args.get("title"): param["title"] = args.get("title") if args.get("description"): param["description"] = args.get("description") if args.get("tlp"): param["tlp"] = TLP_MAP[args.get("tlp")] # type: ignore if args.get("confidence"): param["confidence"] = CONFIDENCE_MAP[args.get("confidence")] # type: ignore if args.get("operator"): param["operator"] = args.get("operator") if args.get("first_sighting"): param["first_sighting"] = args.get("first_sighting") if args.get("email_summary"): param["email_summary"] = args.get("email_summary") params.append(param) return params def authenticate(): headers = {"Content-Type": "application/json", "x-api-key": API_KEY} req_body = json.dumps({"username": USERNAME, "password": PASSWORD}) url = "/auth/access_token" res_body = http_request("POST", url, data=req_body, headers=headers) headers["Authorization"] = "Bearer " + res_body["access_token"] return headers def format_indicator(indicator): hr = makehash() # type: dict ec = makehash() # type: dict if indicator.get("id"): hr["ID"] = indicator.get("id") ec["ID"] = indicator.get("id") if indicator.get("confidence"): hr["Confidence"] = find_key_by_value(indicator.get("confidence"), CONFIDENCE_MAP) ec["Confidence"] = find_key_by_value(indicator.get("confidence"), CONFIDENCE_MAP) if indicator.get("created_at"): hr["Created At"] = indicator.get("created_at") ec["CreatedAt"] = indicator.get("created_at") if indicator.get("created_by"): hr["Created By"] = indicator.get("created_by") ec["CreatedBy"] = indicator.get("created_by") if indicator.get("description"): hr["Description"] = indicator.get("description") ec["Description"] = indicator.get("description") if indicator.get("email_summary"): hr["Email Summary"] = indicator.get("email_summary") ec["EmailSummary"] = indicator.get("email_summary") if indicator.get("title"): hr["Title"] = indicator.get("title") ec["Title"] = indicator.get("title") if indicator.get("first_sighting"): hr["First Sighting"] = indicator.get("first_sighting") ec["FirstSighting"] = indicator.get("first_sighting") if indicator.get("perch_id"): hr["Perch ID"] = indicator.get("perch_id") ec["PerchID"] = indicator.get("perch_id") if indicator.get("team"): hr["Team"] = indicator.get("team") ec["Team"] = indicator.get("team") if indicator.get("tlp"): hr["TLP"] = find_key_by_value(indicator.get("tlp"), TLP_MAP) ec["TLP"] = find_key_by_value(indicator.get("tlp"), TLP_MAP) if indicator.get("updated_at"): hr["Updated At"] = indicator.get("updated_at") ec["UpdatedAt"] = indicator.get("updated_at") if indicator.get("operator"): hr["Operator"] = indicator.get("operator") ec["Operator"] = indicator.get("operator") return hr, ec def item_to_incident(item): incident = {"name": "Perch Incident: " + item.get("title"), "occurred": item.get("created_at"), "rawJSON": json.dumps(item)} return incident """COMMAND FUNCTIONS""" def search_alerts_command(): headers = authenticate() args = demisto.args() params = alerts_params(args) url = "/alerts" res = http_request("GET", url, headers=headers, params=params) res_results = res.get("results") hr = "" ec = {"Perch": {"Alert": []}} # type: dict for alert in res_results: alert_hr, alert_ec = format_alerts(alert) ec["Perch"]["Alert"].append(alert_ec) hr += tableToMarkdown(f'{alert_ec.get("Title")}', alert_hr) if len(res_results) == 0: demisto.results("No results were found") else: demisto.results( { "Type": entryTypes["note"], "ContentsFormat": formats["markdown"], "Contents": res_results, "HumanReadable": hr, "EntryContext": ec, } ) def list_communities_command(): headers = authenticate() args = demisto.args() params = alerts_params(args) url = "/communities" res = http_request("GET", url, headers=headers, params=params) res_results = res.get("results") hr = tableToMarkdown("Communities Found", res_results, headerTransform=string_to_table_header, removeNull=True) ec = {"Perch": {"Community": []}} # type: dict for alert in res_results: ec["Perch"]["Community"].append(createContext(alert, keyTransform=string_to_context_key, removeNull=True)) if len(res_results) == 0: demisto.results("No communities were found") else: demisto.results( { "Type": entryTypes["note"], "ContentsFormat": formats["markdown"], "Contents": res_results, "HumanReadable": hr, "EntryContext": ec, } ) def get_community_command(): headers = authenticate() args = demisto.args() params = alerts_params(args) community_id = args.get("id") url = f"/communities/{community_id}" res = http_request("GET", url, headers=headers, params=params) if len(res) > 0: hr = tableToMarkdown("Communities Found", res, headerTransform=string_to_table_header, removeNull=True) ec = {"Perch": {"Community": createContext(res, keyTransform=string_to_context_key, removeNull=True)}} # type: dict demisto.results( { "Type": entryTypes["note"], "ContentsFormat": formats["markdown"], "Contents": res, "HumanReadable": hr, "EntryContext": ec, } ) else: demisto.results("No communities were found") def create_indicator_command(): headers = authenticate() args = demisto.args() raw_data = indicator_params(args) data = json.dumps(raw_data) url = "/indicators" res = http_request("POST", url, headers=headers, data=data) indicator_hr, indicator_ec = format_indicator(res[0]) hr = "" ec = {"Perch": {"Indicator": []}} # type: dict ec["Perch"]["Indicator"].append(indicator_ec) hr += tableToMarkdown(f'{indicator_hr.get("Title")}', indicator_hr) demisto.results( { "Type": entryTypes["note"], "ContentsFormat": formats["markdown"], "Contents": res, "HumanReadable": hr, "EntryContext": ec, } ) def fetch_alerts(last_run, headers): last_fetch = last_run.get("time") url = "/alerts" statuses_to_fetch = PARAMS.get("soc_status", []) if statuses_to_fetch: items = [] for status in statuses_to_fetch: res = http_request("GET", url, headers=headers, params=alerts_params({"soc_status": STATUSES[status]})) items += res.get("results") else: res = http_request("GET", url, headers=headers) items = res.get("results") items.sort(key=lambda r: r["created_at"]) if last_fetch is None: last_fetch_raw = datetime.now() - timedelta(days=FETCH_TIME) last_fetch = date_to_timestamp(last_fetch_raw, "%Y-%m-%dT%H:%M:%S.%fZ") incidents = [] for item in items: incident = item_to_incident(item) incident_date = date_to_timestamp(incident["occurred"], "%Y-%m-%dT%H:%M:%S.%fZ") if incident_date > last_fetch: incidents.append(incident) last_fetch = incident_date return last_fetch, incidents def fetch_alerts_command(): last_run = demisto.getLastRun() headers = authenticate() last_fetch, incidents = fetch_alerts(last_run, headers) demisto.setLastRun({"time": last_fetch}) demisto.incidents(incidents) def test_module(): try: headers = authenticate() if PARAMS.get("isFetch"): last_run = {"time": 1561017202} fetch_alerts(last_run, headers) demisto.results("ok") except Exception as err: return_error(str(err)) """ COMMANDS MANAGER / SWITCH PANEL """ demisto.info(f"Command being called is {demisto.command()}") try: if demisto.command() == "perch-search-alerts": search_alerts_command() elif demisto.command() == "perch-get-community": get_community_command() elif demisto.command() == "perch-list-communities": list_communities_command() elif demisto.command() == "perch-create-indicator": create_indicator_command() elif demisto.command() == "fetch-incidents": fetch_alerts_command() elif demisto.command() == "test-module": test_module() # Log exceptions except Exception as e: LOG(str(e)) LOG.print_log() raise