StellarCyber

Fetches and mirrors in Cases from Stellar Cyber to XSOAR. In addition, provides a command to update Case severity/status/assignee/tags, and a command to query an Alert.

Analytics & SIEM · Stellar Cyber

Details

IDStellarCyber
ProviderStellar Cyber
CategoryAnalytics & SIEM
From Version6.10.0
Docker Imagedemisto/python3:3.12.13.10116658

README

Fetches and mirrors in Cases from Stellar Cyber to XSOAR. In addition, provides a command to update Case severity/status/assignee/tags, and a command to query an Alert.
This integration was integrated and tested with version >= 4.3.7/5.0.4 of StellarCyber.

Configure Stellar Cyber in Cortex

Parameter Description Required
Fetch incidents    
Incident type    
Mirroring Direction If set to Incoming, will mirror Cases from Stellar Cyber to XSOAR. If set to None, will not mirror Cases from Stellar Cyber to XSOAR. Default is None. False
Stellar Cyber Host (e.g. example.stellarcyber.cloud) Your Stellar Cyber Host FQDN. True
API User (Email Address)   True
API Key   True
First fetch time The period of time to look back for initial pull of cases. (<number> <time unit>, i.e. 1 day, 5 hours, 30 minutes, etc.) False
Trust any certificate (not secure)   False
Use system proxy settings If set to true, will use the system proxy settings. False
Incidents Fetch Interval The interval in minutes for fetching incidents from Stellar Cyber. False
Optional - Tenant ID Supply a Tenant ID to restrict Fetch and Mirror operations to a specific Tenant. If not supplied, all Tenants will be included. False
Maximum number of incidents per fetch The maximum number of incidents to fetch per fetch. False

Incident Mirroring

You can enable incident mirroring between Cortex XSOAR incidents and Stellar Cyber corresponding events (available from Cortex XSOAR version 6.0.0).
To set up the mirroring:

  1. Enable Fetching incidents in your instance configuration.
  2. In the Mirroring Direction integration parameter, select in which direction the incidents should be mirrored:

    Option Description
    None Turns off incident mirroring.
    Incoming Any changes in Stellar Cyber events (mirroring incoming fields) will be reflected in Cortex XSOAR incidents.

Newly fetched incidents will be mirrored in the chosen direction. However, this selection does not affect existing incidents.
Important Note: To ensure the mirroring works as expected, mappers are required, both for incoming and outgoing, to map the expected fields in Cortex XSOAR and Stellar Cyber.

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.

stellar-get-alert


Retrieve an alert from Stellar Cyber.

Base Command

stellar-get-alert

Input

Argument Name Description Required
alert_id The ID of the alert to retrieve. Required

Context Output

Path Type Description
StellarCyber.Alert.alert_id String ID of the Stellar Cyber Alert.
StellarCyber.Alert.alert_index String Index of the Stellar Cyber Alert.
StellarCyber.Alert.alert_metadata.description String Description of the Stellar Cyber Alert.
StellarCyber.Alert.alert_metadata.display_name String Display Name of the Stellar Cyber Alert.
StellarCyber.Alert.alert_metadata.framework_version String Framework Version of the Stellar Cyber Alert.
StellarCyber.Alert.alert_metadata.name String Name of the Stellar Cyber Alert.
StellarCyber.Alert.alert_metadata.scope String Scope of the Stellar Cyber Alert.
StellarCyber.Alert.alert_metadata.tactic.id String Tactic ID of the Stellar Cyber Alert.
StellarCyber.Alert.alert_metadata.tactic.name String Tactic Name of the Stellar Cyber Alert.
StellarCyber.Alert.alert_metadata.tags String Tags of the Stellar Cyber Alert.
StellarCyber.Alert.alert_metadata.technique.id String Technique ID of the Stellar Cyber Alert.
StellarCyber.Alert.alert_metadata.technique.name String Technique Name of the Stellar Cyber Alert.
StellarCyber.Alert.alert_metadata.ttps.tactic.id String Tactic ID of the Stellar Cyber Alert.
StellarCyber.Alert.alert_metadata.ttps.tactic.name String Tactic Name of the Stellar Cyber Alert.
StellarCyber.Alert.alert_metadata.ttps.technique.id String Technique ID of the Stellar Cyber Alert.
StellarCyber.Alert.alert_metadata.ttps.technique.name String Technique Name of the Stellar Cyber Alert.
StellarCyber.Alert.alert_metadata.xdr_killchain_stage String XDR Killchain Stage.
StellarCyber.Alert.alert_metadata.xdr_killchain_version String XDR Killchain Version.
StellarCyber.Alert.alert_url String URL to the Stellar Cyber Alert.
StellarCyber.Alert.description String Description of the Stellar Cyber Alert.
StellarCyber.Alert.detected_field String Detected Field(s) of the Stellar Cyber Alert.
StellarCyber.Alert.detected_value String Detected Value(s) of the Stellar Cyber Alert.
StellarCyber.Alert.display_name String Display Name of the Stellar Cyber Alert.
StellarCyber.Alert.tenant_id String Tenant ID of the Stellar Cyber Alert.
StellarCyber.Alert.tenant_name String Tenant Name of the Stellar Cyber Alert.
StellarCyber.Alert.xdr_tactic_id String XDR Tactic ID of the Stellar Cyber Alert.
StellarCyber.Alert.xdr_tactic_name String XDR Tactic Name of the Stellar Cyber Alert.
StellarCyber.Alert.xdr_technique_id String XDR Technique ID of the Stellar Cyber Alert.
StellarCyber.Alert.xdr_technique_name String XDR Technique Name of the Stellar Cyber Alert.

stellar-update-case


Update the severity, status, assignee, or tags of a Case in Stellar Cyber.

Base Command

stellar-update-case

Input

Argument Name Description Required
stellar_case_id The ID of the Case to update. Required
stellar_case_severity The severity to set the Case to in Stellar Cyber. Possible values are: Low, Medium, High, Critical. Optional
stellar_case_status The status to set the Case to. Possible values are: New, In Progress, Resolved, Cancelled. Optional
stellar_case_assignee The email or username in to assign to Case in Stellar Cyber. Optional
stellar_case_tags_add List of tags to add to Case in Stellar Cyber. Optional
stellar_case_tags_remove List of tags to add remove from Case in Stellar Cyber. Optional

Context Output

Path Type Description
StellarCyber.Case.Update._id String Case ID.
StellarCyber.Case.Update.assignee String Case Assignee.
StellarCyber.Case.Update.created_at Date Case Created Timestamp.
StellarCyber.Case.Update.created_by String Case Created By.
StellarCyber.Case.Update.cust_id String Case Tenant ID.
StellarCyber.Case.Update.modified_at Date Case Modified Timestamp.
StellarCyber.Case.Update.modified_by String Case Modified By.
StellarCyber.Case.Update.name String Case Name.
StellarCyber.Case.Update.size Number Case Size (Number of Alerts).
StellarCyber.Case.Update.status String Case Status.
StellarCyber.Case.Update.tags Unknown Case Tags.
StellarCyber.Case.Update.ticket_id Number Case Ticket ID.
StellarCyber.Case.Update.version Number Case Version.
StellarCyber.Case.Update.priority String Case Priority.
StellarCyber.Case.Update.incident_score Number Case Score.
StellarCyber.Case.Update.assignee_name String Case Assignee Name.

get-remote-data


Gets remote data from a remote incident. This method is only used for debugging purposes and will not update the current incident.

Base Command

get-remote-data

Input

Argument Name Description Required
id The remote incident ID. Required
lastUpdate UTC timestamp in seconds. The incident is only updated if it was modified after the last update time. Default is 0. Optional

Context Output

There is no context output for this command.

get-modified-remote-data


Available from Cortex XSOAR version 6.1.0. This command queries for incidents that were modified since the last update. This method is only used for debugging purposes.

Base Command

get-modified-remote-data

Input

Argument Name Description Required
lastUpdate UTC timestamp in seconds. The incident is only updated if it was modified after the last update time. Required

Context Output

There is no context output for this command.

Configuration parameters

  • isFetch — Fetch incidents
  • incidentType — Incident type
  • mirror_direction — Mirroring Direction
  • stellar_dp — Stellar Cyber Host (e.g. example.stellarcyber.cloud) (required)
  • credentials — API User (Email Address) (required)
  • first_fetch — First fetch time
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • incidentFetchInterval — Incidents Fetch Interval
  • tenantid — Optional - Tenant ID
  • max_fetch — Maximum number of incidents per fetch

Commands (4)

  • get-modified-remote-data

    Available from Cortex XSOAR version 6.1.0. This command queries for incidents that were modified since the last update. This method is only used for debugging purposes.

  • get-remote-data

    Gets remote data from a remote incident. This method is only used for debugging purposes and will not update the current incident.

  • stellar-get-alert

    Retrieve an alert from Stellar Cyber.

  • stellar-update-case

    Update the severity, status, assignee, or tags of a Case in Stellar Cyber.

"""Stellar Cyber Integration for Cortex XSOAR (aka Demisto)"""

import demistomock as demisto
from CommonServerUserPython import *
from CommonServerPython import *

import dateparser
import json
import urllib3
import base64
from datetime import datetime, timedelta, UTC


# Disable insecure warnings
urllib3.disable_warnings()


""" CONSTANTS """

# Constants

""" CLIENT CLASS """


class AccessToken:
    def __init__(self, token: str, expiration: int):
        self._expiration = expiration
        self._token = token

    def __str__(self):
        return self._token

    @property
    def expired(self) -> bool:
        return self._expiration < int(datetime.now(UTC).timestamp())


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 __init__(self, dp_host: str, username: str, password: str, verify: bool, proxy: bool, tenantid: str | None):
        self.dp_host = dp_host
        super().__init__(base_url=f"https://{dp_host}", verify=verify, proxy=proxy)
        self._tenantid = tenantid
        self._is_saas = True
        self._basic = base64.b64encode(bytes(username + ":" + password, "utf-8")).decode("utf-8")
        # self._auth = (username, password)
        self._token: AccessToken = AccessToken("", 0)

    def _get_auth_header(self):
        if self._is_saas:
            if self._token.expired:
                headers = {"Accept": "application/json", "Content-type": "application/json"}
                headers["Authorization"] = f"Basic {self._basic}"
                token_url = f"https://{self.dp_host}/connect/api/v1/access_token"
                response = self._http_request(method="POST", full_url=token_url, headers=headers)
                current_token = response.get("access_token", "")
                current_exp = int(response.get("exp", 0))
                self._token = AccessToken(current_token, current_exp)
                header_string = f"Bearer {current_token}"
            else:
                header_string = f"Bearer {self._token}"
        else:
            header_string = f"Basic {self._basic}"

        return header_string

    def test_incidents(self):
        incident_url = f"https://{self.dp_host}/connect/api/data/aella-ser-*/_search?q=fidelity:<0"
        headers = {"Accept": "application/json", "Content-type": "application/json"}
        headers["Authorization"] = self._get_auth_header()
        self._http_request(method="GET", full_url=incident_url, headers=headers)
        return True

    def get_new_incidents(self, last_run: int, limit: int):
        if self._tenantid:
            incident_url = f"https://{self.dp_host}/connect/api/v1/incidents?tenantid={self._tenantid}&FROM~created_at={last_run}&sort=created_at&order=asc&limit={limit}"  # noqa: E501
        else:
            incident_url = f"https://{self.dp_host}/connect/api/v1/incidents?FROM~created_at={last_run}&sort=created_at&order=asc&limit={limit}"  # noqa: E501
        headers = {"Accept": "application/json", "Content-type": "application/json"}
        headers["Authorization"] = self._get_auth_header()
        response = self._http_request(method="GET", full_url=incident_url, headers=headers)
        return response["data"]["incidents"]

    def get_updated_incidents(self, last_run: int):
        if self._tenantid:
            incident_url = f"https://{self.dp_host}/connect/api/v1/incidents?tenantid={self._tenantid}&FROM~modified_at={last_run}&sort=modified_at&order=asc"  # noqa: E501
        else:
            incident_url = (
                f"https://{self.dp_host}/connect/api/v1/incidents?FROM~modified_at={last_run}&sort=modified_at&order=asc"
            )
        headers = {"Accept": "application/json", "Content-type": "application/json"}
        headers["Authorization"] = self._get_auth_header()
        response = self._http_request(method="GET", full_url=incident_url, headers=headers)
        response_incidents = response["data"].get("incidents", [])
        updated_incidents = [incident for incident in response_incidents if incident["created_at"] < incident["modified_at"]]
        return updated_incidents

    def get_incident(self, remote_ticket_id: str):
        ticket_id, cust_id = remote_ticket_id.split(":")
        incident_url = f"https://{self.dp_host}/connect/api/v1/incidents?ticket_id={ticket_id}&cust_id={cust_id}"
        headers = {"Accept": "application/json", "Content-type": "application/json"}
        headers["Authorization"] = self._get_auth_header()
        response = self._http_request(method="GET", full_url=incident_url, headers=headers)
        response_incidents = response["data"].get("incidents", [])
        if len(response_incidents):
            return response_incidents[0]
        else:
            return {}

    def get_incident_summary(self, incident_id: str):
        incident_summary_url = f"https://{self.dp_host}/connect/api/v1/cases/{incident_id}/summary?formatted=true"
        headers = {"Accept": "application/json", "Content-type": "application/json"}
        headers["Authorization"] = self._get_auth_header()
        response = self._http_request(method="GET", full_url=incident_summary_url, headers=headers)
        return response["data"]

    def get_alert(self, alert_id: str, alert_index: str) -> dict:
        hit = {}
        alert_url = f"https://{self.dp_host}/connect/api/data/{alert_index}/_search?q=_id:{alert_id}"
        headers = {"Accept": "application/json", "Content-type": "application/json"}
        headers["Authorization"] = self._get_auth_header()
        response = self._http_request(method="GET", full_url=alert_url, headers=headers)
        hits = response.get("hits", None).get("hits", None)
        # timed_out = response.get("timed_out", False)
        if hits:
            hit = hits[0].get("_source", None)
            alert_index = hits[0].get("_index", "")
            hit = demisto_alert_normalization(hit, alert_id, alert_index, self.dp_host)
        return hit

    def update_case(
        self,
        case_id,
        case_severity=None,
        case_status=None,
        case_assignee=None,
        case_tags_add: list = [],
        case_tags_remove: list = [],
    ):
        update_data: Dict[str, Any] = {}
        if case_severity:
            update_data["priority"] = str(case_severity)
        if case_status:
            update_data["status"] = str(case_status)
        if case_assignee:
            update_data["assignee"] = str(case_assignee)
        if len(case_tags_add) or len(case_tags_remove):
            if len(case_tags_add):
                update_data.update({"tags": {"add": case_tags_add}})
            if len(case_tags_remove):
                update_data.update({"tags": {"add": case_tags_add}})
        incident_url = f"https://{self.dp_host}/connect/api/v1/incidents?id={case_id}"
        headers = {"Accept": "application/json", "Content-type": "application/json"}
        headers["Authorization"] = self._get_auth_header()
        response = self._http_request(method="POST", full_url=incident_url, headers=headers, json_data=update_data)
        return response["data"]


""" HELPER FUNCTIONS """


def get_xsoar_severity(severity):
    sev_map = {"Low": 1, "Medium": 2, "High": 3, "Critical": 4}
    return sev_map[severity]


def demisto_alert_normalization(alert, alert_id, alert_index, dp_host):
    """
    Normalizes an alert from Stellar Cyber into a format that can be ingested by Demisto.

    Args:
        alert (dict): The alert from Stellar Cyber.
        alert_id (str): The ID of the alert.
        alert_index (str): The index of the alert.
        dp_host (str): The hostname of the Stellar Cyber platform.

    Returns:
        dict: The normalized alert in a format that can be ingested by Demisto.
    """
    ret_alert = {
        "alert_metadata": alert["xdr_event"],
        "alert_id": alert_id,
        "alert_index": alert_index,
        "tenant_id": alert["tenantid"],
        "tenant_name": alert["tenant_name"],
        "detected_field": alert.get("detected_field", ""),
        "detected_value": alert.get("detected_value", ""),
        "xdr_tactic_name": alert["xdr_event"].get("tactic", {}).get("name", ""),
        "xdr_tactic_id": alert["xdr_event"].get("tactic", {}).get("id", ""),
        "xdr_technique_name": alert["xdr_event"].get("technique", {}).get("name", ""),
        "xdr_technique_id": alert["xdr_event"].get("technique", {}).get("id", ""),
        "display_name": alert["xdr_event"].get("display_name", ""),
        "description": alert["xdr_event"].get("description", ""),
        "alert_url": f"https://{dp_host}/alerts/alert/{alert_index}/amsg/{alert_id}",
    }

    # workaround for some alerts (e.g.: uncommon process anomaly)
    if not ret_alert["detected_field"]:
        ret_alert["detected_field"] = alert.get("detected_fields", [])
        ret_alert["detected_value"] = alert.get("detected_values", [])

    return ret_alert


""" COMMAND FUNCTIONS """


def fetch_incidents(client: Client, params: dict) -> list[dict]:
    """
    Retrieves incidents from the Stellar Cyber platform and maps them to XSOAR incidents.

    Returns:
        List[dict]: A list of XSOAR incidents.
    """
    last_run = demisto.getLastRun()
    last_incident_ids = last_run.get("last_incidents", [])
    first_fetch_time = params.get("first_fetch", "3 days").strip()
    last_fetch = last_run.get("last_fetch", None)
    fetch_limit = params.get("max_fetch", 200)
    mirror_direction = params.get("mirror_direction", "None")
    # new_last_fetch = int(datetime.utcnow().timestamp() * 1000)
    if not last_fetch:
        first_fetch = dateparser.parse(first_fetch_time, settings={"TIMEZONE": "UTC"})
        assert first_fetch is not None
        last_fetch = int(first_fetch.timestamp() * 1000)
    else:
        last_fetch = int(last_fetch)  # Convert last_fetch to an integer
    incidents = client.get_new_incidents(last_run=last_fetch, limit=fetch_limit)
    demisto_incidents = []
    number_of_incidents = len(incidents)
    demisto.info(f"Retrieved incidents: [{number_of_incidents}]")
    incident_ids = []

    for incident in incidents:
        incident_id = incident["_id"]
        incident["case_url"] = f"https://{client.dp_host}/cases/case-detail/{incident_id}"
        incident_ticket_id = str(incident["ticket_id"])
        if len(incident["metadata"].get("name_auto", [])):
            incident_name = incident["metadata"]["name_auto"][0]
        else:
            incident_name = incident["name"]
        incident["name"] = incident_name
        incident_ts = incident["created_at"]
        if last_fetch < incident_ts:
            last_fetch = incident_ts
        incident_summary = client.get_incident_summary(incident_id)
        incident["summary"] = incident_summary
        event_ids = incident.get("event_ids", None)
        incident["security_alerts"] = []
        for event in event_ids:
            incident["security_alerts"].append(client.get_alert(alert_id=event["_id"], alert_index=event["_index"]))
        case_severity = get_xsoar_severity(incident["priority"])
        case_mirror_id = f"{incident_ticket_id}:{incident['cust_id']}"
        case_mirror_direction = None
        if mirror_direction == "Incoming":
            case_mirror_direction = "In"
        incident["severity"] = case_severity
        incident["mirror_id"] = case_mirror_id
        incident["mirror_direction"] = case_mirror_direction
        incident["mirror_instance"] = demisto.integrationInstance()
        if case_mirror_id not in last_incident_ids:
            demisto_incident = {"occurred": timestamp_to_datestring(incident_ts), "rawJSON": json.dumps(incident)}
            demisto_incidents.append(demisto_incident)
            incident_ids.append(case_mirror_id)
    if len(incident_ids) == 0:
        incident_ids = last_incident_ids
    demisto.setLastRun({"last_fetch": last_fetch, "last_incidents": incident_ids})
    return demisto_incidents


def get_alert_command(client: Client, args: dict) -> CommandResults:
    """
    Retrieves an alert from the Stellar Cyber platform by its ID.

    Args:
        alert_id (str): The ID of the alert to retrieve.

    Returns:
        dict: A dictionary containing the details of the retrieved alert.

    Raises:
        Exception: If there is an issue with retrieving the alert.
    """
    alert_id = args.get("alert_id", "")
    demisto.info(f"Getting alert: {alert_id}")
    hit = client.get_alert(alert_id, "aella-ser-*")
    return CommandResults(outputs_prefix="StellarCyber.Alert", outputs_key_field="alert_id", outputs=[hit])


def test_module_command(client: Client) -> str:
    try:
        client.test_incidents()
    except Exception as e:
        if "Unauthorized" in str(e):
            return "Authorization Error: make sure the credentials and host are correct"
        else:
            raise e
    return "ok"


def update_case_command(client: Client, args: dict) -> CommandResults:
    case_id = args.get("stellar_case_id")
    case_severity = args.get("stellar_case_severity")
    case_status = args.get("stellar_case_status")
    case_assignee = args.get("stellar_case_assignee")
    case_tags_add = args.get("stellar_case_tags_add", [])
    case_tags_remove = args.get("stellar_case_tags_remove", [])
    if not (case_severity or case_status or case_assignee or len(case_tags_add) or len(case_tags_remove)):
        raise Exception(f"No values to update for stellar case with id: [{case_id}]")
    demisto.info(f"Updating stellar case with id: [{case_id}]")
    response = client.update_case(case_id, case_severity, case_status, case_assignee, case_tags_add, case_tags_remove)
    return CommandResults(outputs_prefix="StellarCyber.Case.Update", outputs_key_field="_id", outputs=response)


def get_remote_data_command(client: Client, args) -> GetRemoteDataResponse | str:
    try:
        parsed_args = GetRemoteDataArgs(args)
        remote_incident_id = parsed_args.remote_incident_id
        incident = client.get_incident(remote_incident_id)
        if len(incident):
            incident_id = incident["_id"]
            incident["case_url"] = f"https://{client.dp_host}/cases/case-detail/{incident_id}"
            incident_ticket_id = str(incident["ticket_id"])
            demisto.info(f"Retrieved case: {str(incident['ticket_id'])}")
            if len(incident["metadata"].get("name_auto", [])):
                incident_name = incident["metadata"]["name_auto"][0]
            else:
                incident_name = incident["name"]
            incident["name"] = incident_name
            incident_summary = client.get_incident_summary(incident_id)
            incident["summary"] = incident_summary
            event_ids = incident.get("event_ids", None)
            security_event_cnt = len(event_ids)
            demisto.info(
                f"Pulling security event info for case: [{incident_id}] [ticket id: {incident_ticket_id}] [event_cnt: [{security_event_cnt}]"  # noqa: E501
            )
            incident["security_alerts"] = []
            for event in event_ids:
                incident["security_alerts"].append(client.get_alert(alert_id=event["_id"], alert_index=event["_index"]))
            incident["severity"] = get_xsoar_severity(incident["priority"])
            return GetRemoteDataResponse(mirrored_object=incident, entries=[])
        else:
            return f"Failed to retrieve case: {str(incident['ticket_id'])}"
    except Exception as e:
        if "Rate limit exceeded" in str(e):
            return "API rate limit"
        else:
            return f"Failed to update case with error: {str(e)}"


def get_modified_remote_data_command(client: Client, args) -> GetModifiedRemoteDataResponse | str:
    try:
        remote_args = GetModifiedRemoteDataArgs(args)
        last_update = remote_args.last_update
        demisto.debug(f"last_update: {last_update}")
        last_update_utc = dateparser.parse(last_update, settings={"TIMEZONE": "UTC"})  # type: ignore
        demisto.debug(f"last_update_utc: {last_update_utc}")
        assert last_update_utc is not None
        last_run_ts = int((last_update_utc - timedelta(minutes=1)).timestamp() * 1000)
        modified_incidents = client.get_updated_incidents(last_run=last_run_ts)
        if len(modified_incidents):
            modified_incident_ids = [f"{str(i['ticket_id'])}:{i['cust_id']}" for i in modified_incidents]
        else:
            modified_incident_ids = []
        return GetModifiedRemoteDataResponse(modified_incident_ids)
    except Exception:
        return "No Results, skip update"


""" MAIN FUNCTION """


def main() -> None:
    """
    main function, parses params and runs command functions
    """
    try:
        _STELLAR_DP_ = demisto.params().get("stellar_dp", "")
        _ALERT_API_USER_ = demisto.getParam("credentials")["identifier"]  # type: ignore
        _ALERT_API_TOKEN_ = demisto.getParam("credentials")["password"]  # type: ignore
        _VALIDATE_CERT_ = not demisto.params().get("insecure", True)
        _PROXY_ = demisto.params().get("proxy", False)
        _TENANTID_ = demisto.params().get("tenantid", None)
        client = Client(
            dp_host=_STELLAR_DP_,
            username=_ALERT_API_USER_,
            password=_ALERT_API_TOKEN_,
            verify=_VALIDATE_CERT_,
            proxy=_PROXY_,
            tenantid=_TENANTID_,
        )
        if demisto.command() == "test-module":
            result = test_module_command(client)
            return_results(result)
        elif demisto.command() == "fetch-incidents":
            incidents = fetch_incidents(client, params=demisto.params())
            demisto.incidents(incidents)
        elif demisto.command() == "stellar-get-alert":
            return_results(get_alert_command(client, demisto.args()))
        elif demisto.command() == "stellar-update-case":
            return_results(update_case_command(client, demisto.args()))
        elif demisto.command() == "get-modified-remote-data":
            return_results(get_modified_remote_data_command(client, demisto.args()))
        elif demisto.command() == "get-remote-data":
            return_results(get_remote_data_command(client, demisto.args()))

    except Exception as e:
        return_error(str(e))


""" ENTRY POINT """

if __name__ in ("__main__", "__builtin__", "builtins"):
    main()