TaegisXDR Deprecated

Deprecated. Use TaegisXDR v2 instead.

Data Enrichment & Threat Intelligence · Secureworks

Details

IDTaegisXDR
ProviderSophos
CategoryData Enrichment & Threat Intelligence
From Version5.5.0
Docker Imagedemisto/python3:3.10.12.65389
Supported ModulesAgentix XSIAM

README

Configure Taegis XDR in Cortex

Parameter Description Required
Taegis Environment The environment to utilize True
Client ID Client ID as described in the Taegis Documentation True
Client Secret Client Secret as described in the Taegis Documentation True
Use system proxy settings Defines whether the system proxy is used or not 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.

taegis-archive-investigation

Base Command

!taegis-archive-investigation

Inputs

Argument Name Description Required
id The investigation id to archive True

Command Example

!taegis-archive-investigation id=c207ca4c-8a78-4408-a056-49f05d6eb77d

Context Example

{
    "TaegisXDR": {
        "ArchivedInvestigation": {
            "id": "c207ca4c-8a78-4408-a056-49f05d6eb77d"
        }
    }
}

taegis-create-comment

Base Command

!taegis-create-comment

Inputs

Argument Name Description Required
comment The comment string to add to the investigation True
parent_id The investigation ID to add the comment to True

Command Example

!taegis-create-comment comment="This is a test comment" parent_id="219da0ee-8642-4363-827c-8a6fbd479082"

Context Example

{
    "TaegisXDR": {
        "CommentCreate": {
            "id": "593fa115-abad-4a52-9fc4-2ec403a8a1e4"
        }
    }
}

taegis-create-investigation

Base Command

!taegis-create-investigation

Inputs

Argument Name Description Required
description The subject or description of the investigation True
priority The priority for the investigiation [Default: 3] False

Command Example

!taegis-create-investigation priority=1 description="XSOAR Created Investigation"

Context Example

{
    "TaegisXDR": {
        "Investigation": {
            "id": "593fa115-abad-4a52-9fc4-2ec403a8a1e4"
        }
    }
}

taegis-execute-playbook

Base Command

!taegis-execute-playbook

Inputs

Argument Name Description Required
id Playbook instance ID to execute True
inputs JSON object of inputs to pass into the playbook execution False

Command Example

!taegis-execute-playbook id=UGxheWJvb2tJbnN0YW5jZTphZDNmNzBlZi1mN2U0LTQ0OWYtODJiMi1hYWQwMjQzZTA2NTg=
!taegis-execute-playbook id=UGxheWJvb2tJbnN0YW5jZTphZDNmNzBlZi1mN2U0LTQ0OWYtODJiMi1hYWQwMjQzZTA2NTg= inputs=`{'myvar': 'myval'}`

Context Example

{
    "id": "UGxheWJvb2tFeGVjdXRpb246NGYwZDZiNGQtNWNiZS00NDkxLTg3YzYtMDZkNjkxYzMwMTg4"
}

taegis-fetch-alerts

Base Command

!taegis-fetch-alerts

Input

Argument Name Description Default Required
ids A list of alerts by IDs 936c1cc1-db8f-430c-837c-1c914fcca35a False
limit Number of results to when ids is not defined 10 False
offset The result to start from when ids is not defined 0 False
cql_query The query to utilize when searching for Alerts from alert severity >= 0.6 and status='OPEN' False

Command Examples

!taegis-fetch-alerts ids=`["6594e97f-a898-5b28-82b2-ea03293cdaa1"]`

Context Example

{
    "TaegisXDR": {
        "Alerts": [
            {
                "id": "c4f33b53-eaba-47ac-8272-199af0f7935b",
                "metadata": {
                    "title": "Test Alert",
                    "description": "This is a test alert",
                    "severity": 0.5,
                }
            }
        ]
    }
}

taegis-fetch-assets

Base Command

!taegis-fetch-assets

Input

Argument Name Description Default Required
page   0 False
page_size   10 False
endpoint_type     False
host_id ID of the asset to fetch e43b545a-580a-4047-b489-4338c1cc4ba1 False
hostname     False
investigation_id     False
ip_address     False
mac_address     False
os_family     False
os_version     False
sensor_version     False
username     False

Command Examples

!taegis-fetch-assets
!taegis-fetch-assets page=1 page_size=5
!taegis-fetch-assets hostname=MyHostname01
!taegis-fetch-assets host_id=e43b545a-580a-4047-b489-4338c1cc4ba1

Context Example

{
    "TaegisXDR": {
        "Assets": [
            {
              "id": "",
              "ingestTime": "",
              "createdAt": "",
              "updatedAt": "",
              "deletedAt": "",
              "biosSerial": "",
              "firstDiskSerial": "",
              "systemVolumeSerial": "",
              "sensorVersion": "",
              "endpointPlatform": "",
              "hostnames": [{"id": ", "hostname": ""],
              "architecture": "",
              "osFamily": "",
              "osVersion": "",
              "osDistributor": "",
              "osRelease": "",
              "systemType": "",
              "osCodename": "",
              "kernelRelease": "",
              "kernelVersion": "",
              "tags": [ "key": "", "tag": ""],
              "endpointType": "",
              "hostId": "",
              "sensorId": "",
            }
        ]
    }
}

taegis-fetch-comment

Base Command

!taegis-fetch-comment

Inputs

Argument Name Description Required
id The ID of the comment to fetch True

Command Example

!taegis-fetch-comment id=ff9ca818-4749-4ccb-883a-2ccc6f6c9e0f

Context Example

{
    "TaegisXDR": {
        "Comment": {
            "author_user": {
                "email_normalized": "myuser@email.com",
                "given_name": "John",
                "family_name": "Smith",
                "id": "auth0|000000000000000000000001",
            },
            "id": "ff9ca818-4749-4ccb-883a-2ccc6f6c9e0f",
            "comment": "This is a comment in an investigation",
            "created_at": "2022-01-01T13:04:57.17234Z",
            "deleted_at": None,
            "modified_at": None,
            "parent_id": "c2e09554-833e-41a1-bc9d-8160aec0d70d",
            "parent_type": "investigation",
        }
    }
}

taegis-fetch-comments

Base Command

!taegis-create-comments

Inputs

Argument Name Description Required
parent_id The investigation ID to fetch comments for True

Command Example

!taegis-fetch-comments parent_id=c2e09554-833e-41a1-bc9d-8160aec0d70d

Context Example

{
    "TaegisXDR": {
        "Comments": [
            {
                "author_user": {
                    "email_normalized": "myuser@email.com",
                    "given_name": "John",
                    "family_name": "Smith",
                    "id": "auth0|000000000000000000000001",
                },
                "id": "ff9ca818-4749-4ccb-883a-2ccc6f6c9e0f",
                "comment": "This is a comment in an investigation",
                "created_at": "2022-01-01T13:04:57.17234Z",
                "deleted_at": None,
                "modified_at": None,
                "parent_id": "c2e09554-833e-41a1-bc9d-8160aec0d70d",
                "parent_type": "investigation",
            },
            {
                "author_user": {
                    "email_normalized": "myuser@email.com",
                    "given_name": "John",
                    "family_name": "Smith",
                    "id": "auth0|000000000000000000000001",
                },
                "id": "ff9ca818-4749-4ccb-883a-2ccc6f6c1234",
                "comment": "This is another comment",
                "created_at": "2022-01-02T13:04:57.17234Z",
                "deleted_at": None,
                "modified_at": None,
                "parent_id": "c2e09554-833e-41a1-bc9d-8160aec0d70d",
                "parent_type": "investigation",
            }
        ]
    }
}

taegis-fetch-endpoint

Base Command

!taegis-fetch-endpoint

Inputs

Argument Name Description Required
id Endpoint ID to fetch True

Command Example

!taegis-fetch-endpoint id=ff9ca818-4749-4ccb-883a-2ccc6f6c9e0f

Context Example

{
    "TaegisXDR": {
        "assetEndpointInfo": {
            "hostId": "",
            "hostName": "",
            "actualIsolationStatus": "",
            "allowedDomain": "",
            "desiredIsolationStatus": "",
            "firstConnectTime": "",
            "moduleHealth": {
                "enabled": ""
                "lastRunningTime": "",
                "moduleDisplayName": "",
            }
            "lastConnectAddress": "",
            "lastConnectTime": "",
            "sensorVersion": ""
        }
    }
}

taegis-fetch-investigation

Base Command

!taegis-fetch-investigation

Inputs

Argument Name Description Required
id Investigation ID to lookup True

Command Example

!taegis-fetch-investigation id=936c1cc1-db8f-430c-837c-1c914fcca35a

Context Example

{
    "TaegisXDR": {
        "Investigations": [
            {
                "archived_at": None,
                "created_at": "2022-02-02T13:53:35Z",
                "description": "Test Investigation",
                "id": "c2e09554-833e-41a1-bc9d-8160aec0d70d",
                "key_findings": "",
                "priority": 2,
                "service_desk_id": "",
                "service_desk_type": "",
                "status": "Open",
                "alerts2": [],
                "url": "https://ctpx.secureworks.com/investigations/c2e09554-833e-41a1-bc9d-8160aec0d70d",
            }
        ]
    }
}

taegis-fetch-investigation-alerts

Base Command

!taegis-fetch-investigation-alerts

Inputs

Argument Name Description Required
id Investigation ID to lookup True

Command Example

!taegis-fetch-investigation-alerts id=936c1cc1-db8f-430c-837c-1c914fcca35a

Context Example

{
    "TaegisXDR": {
        "InvestigationAlerts": [
            {
                "id": "c4f33b53-eaba-47ac-8272-199af0f7935b",
                "description": "Test Alert",
                "message": "This is a test alert",
                "severity": 0.5,
            }
        ]
    }
}

taegis-fetch-investigations

Base Command

!taegis-fetch-investigations

Inputs

Argument Name Description Required
page   False
page_size   False

Command Example

!taegis-fetch-investigations

Context Example

{
    "TaegisXDR": {
        "Investigations": [
            {
                "description": "Test Investigation",
                "id": "c2e09554-833e-41a1-bc9d-8160aec0d70d",
                "key_findings": "",
                "priority": 2,
                "service_desk_id": "",
                "service_desk_type": "",
                "status": "Open"
            }
        ]
    }
}

taegis-fetch-playbook-execution

Base Command

!taegis-fetch-playbook-execution

Inputs

Argument Name Description Required
id Playbook execution ID to fetch True

Command Example

!taegis-fetch-playbook-execution id=UGxheWJvb2tFeGVjdXRpb246NGYwZDZiNGQtNWNiZS00NDkxLTg3YzYtMDZkNjkxYzMwMTg4

Context Example

{
    "TaegisXDR": {
        "PlaybookExecution": {
            "createdAt": "2022-01-01T13:51:24Z",
            "executionTime": 1442,
            "id": "UGxheWJvb2tFeGVjdXRpb246NGYwZDZiNGQtNWNiZS00NDkxLTg3YzYtMDZkNjkxYzMwMTg4",
            "inputs": {
                "alert": {
                    "message": "Test Alert",
                }
            },
            "instance": {
                "name": "Test Alert Instance",
                "playbook": {
                    "name": "Taegis.PagerDutyAlertEvent"
                }
            },
            "outputs": "d6b65662-c1da-4109-8553-c5664918c952",
            "state": "Completed",
            "updatedAt": "2022-01-01T13:51:31Z"
        }
    }
}

taegis-fetch-users

Base Command

!taegis-fetch-users

Inputs

Argument Name Description Required
id The id of the user, in auth0 format False
email The email of the user False
status The users to find based on status False
page   False
page_size   False

Command Example

!taegis-fetch-users id="auth0|123456"

Context Example

{
    "TaegisXDR": {
        "Users": [
            {
                "email": "myuser@email.com",
                "family_name": "Smith",
                "given_name": "John",
                "status": "Registered",
                "user_id": "auth0|123456"
            }
        ]
    }
}

taegis-isolate-asset

Base Command

!taegis-isolate-asset

Input

Argument Name Description Default Required
id ID of the asset to isolate e43b545a-580a-4047-b489-4338c1cc4ba1 True
reason The reason for the isolation See ticket 12345 True

Command Examples

!taegis-isolate-asset id="e43b545a-580a-4047-b489-4338c1cc4ba1" reason="See ticket 12345"

Context Example

{
    "TaegisXDR": {
        "AssetIsolation": {
            "id": "e43b545a-580a-4047-b489-4338c1cc4ba1"
        }
    }
}

taegis-update-alert-status

Base Command

!taegis-update-alert-status

Input

Argument Name Description Default Required
ids A comma-separated list of alerts by IDs alert://priv:crowdstrike:11772:1666269058114:59284e28-4ec8-542b-a4a1-452c3688bc1a True
status The status to update the alert(s) with FALSE_POSITIVE True
reason A comment/reason for the alert status update See ticket 13245 False
Permitted Status Values
  • FALSE_POSITIVE
  • NOT_ACTIONABLE
  • OPEN
  • TRUE_POSITIVE_BENIGN
  • TRUE_POSITIVE_MALICIOUS

Command Examples

!taegis-update-alert-status ids="alert://priv:crowdstrike:11772:1677742145475:07e2d9cc-0a04-55ec-890a-97f39d63698e" status=NOT_ACTIONABLE reason="Test Reason"

Context Example

{
    "TaegisXDR": {
        "AlertStatusUpdate": {
            "reason": "feedback updates successfully applied",
            "resolution_status": "SUCCESS"
        }
    }
}

taegis-update-comment

Base Command

!taegis-update-comment

Inputs

Argument Name Description Required
comment The comment string to add to the investigation True
id The comment ID to update True

Command Example

!taegis-update-comment id="ff9ca818-4749-4ccb-883a-2ccc6f6c9e0f" comment="Newly updated comment"

Context Example

{
    "TaegisXDR": {
        "CommentUpdate": {
            "id": "593fa115-abad-4a52-9fc4-2ec403a8a1e4"
        }
    }
}

taegis-update-investigation

Base Command

!taegis-update-investigation

Inputs

Argument Name Description Required
id Investigation ID to update True
key_findings   False
prioirity The priority of the Investigation (1-5) False
service_desk_id An ID or ticket # to relate to an Investigation False
service_desk_type The type of id related to an investigation (e.g. Jira) False
status The current status of the Investigation False
assignee_id The id of a user to assign, in auth0|12345 format False

Note: At least 1 of the above inputs (in addition to id) must be defined

Permitted Status Values
  • Active
  • Awaiting Action
  • Closed: Authorized Activity
  • Closed: Confirmed Security Incident
  • Closed: False Positive Alert
  • Closed: Inconclusive
  • Closed: Informational
  • Closed: Not Vulnerable
  • Closed: Threat Mitigated
  • Open
  • Suspended

Command Example

!taegis-update-investigation id="936c1cc1-db8f-430c-837c-1c914fcca35a" priority=3 status="Open" service_desk_id="XDR-1234" service_desk_type="Jira"

Context Example

{
    "TaegisXDR": {
        "InvestigationUpdate": {
            "id": "c2e09554-833e-41a1-bc9d-8160aec0d70d"
        }
    }
}

taegis-unarchive-investigation

Base Command

!taegis-unarchive-investigation

Inputs

Argument Name Description Required
id The investigation id to unarchive True

Command Example

!taegis-unarchive-investigation id=c207ca4c-8a78-4408-a056-49f05d6eb77d

Context Example

{
    "TaegisXDR": {
        "UnarchivedInvestigation": {
            "id": "c207ca4c-8a78-4408-a056-49f05d6eb77d"
        }
    }
}

Configuration parameters

  • environment — Taegis Environment (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • client_id — Client ID (required)
  • client_secret — Client Secret (required)
  • isFetch — Fetch incidents
  • max_fetch — Maximum number of incidents per fetch
  • first_fetch — First fetch time interval
  • incidentFetchInterval — Incidents Fetch Interval
  • incidentType — Incident type
  • include_assets — Include Assets in Fetch

Commands (18)

  • taegis-archive-investigation

    Archive an investigation

  • taegis-create-comment

    Create a comment on an investigation

  • taegis-create-investigation

    Create an Investigation within Taegis

  • taegis-execute-playbook

    Executes a Taegis playbook instance

  • taegis-fetch-alerts

    List Taegis alerts by ID

  • taegis-fetch-assets

    Fetch assets based on search criteria

  • taegis-fetch-comment

    Fetch comment by comment ID

  • taegis-fetch-comments

    Fetch comments by Parent Type and ID

  • taegis-fetch-endpoint

    Fetch endpoint information

  • taegis-fetch-investigation

    Fetch all investigations or a specific investigation

  • taegis-fetch-investigation-alerts

    Fetch Alert IDs related to a specific investigation

  • taegis-fetch-playbook-execution

    Fetch the results of a Taegis playbook instance execution

  • taegis-fetch-users

    Fetch a user by ID or email address

  • taegis-isolate-asset

    Isolate a specific asset

  • taegis-unarchive-investigation

    Unarchive an investigation

  • taegis-update-alert-status

    Update the status of an alert

  • taegis-update-comment

    Update an existing comment

  • taegis-update-investigation

    Update an existing investigation

import pytest

from CommonServerPython import DemistoException

from TaegisXDR import (
    Client,
    execute_playbook_command,
    fetch_alerts_command,
    fetch_assets_command,
    create_comment_command,
    fetch_comment_command,
    fetch_comments_command,
    update_comment_command,
    fetch_endpoint_command,
    fetch_incidents,
    fetch_investigation_command,
    fetch_investigation_alerts_command,
    fetch_users_command,
    fetch_playbook_execution_command,
    isolate_asset_command,
    create_investigation_command,
    update_investigation_command,
    archive_investigation_command,
    unarchive_investigation_command,
    update_alert_status_command,
    test_module as connectivity_test,
)

from test_data.data import *


''' UTILITY FUNCTIONS '''


def mock_client(requests_mock, mock_response):
    base_url = "https://api.ctpx.secureworks.com"

    requests_mock.post(f"{base_url}/graphql", json=mock_response)
    requests_mock.get(f"{base_url}/assets/version", json=mock_response)
    client = Client(
        client_id="TestID",
        client_secret="TestSecret",
        base_url=base_url,
    )
    return client


''' TESTS '''


def test_execute_playbook(requests_mock):
    """Tests taegis-execute-playbook command function
    """
    client = mock_client(requests_mock, EXECUTE_PLAYBOOK_RESPONSE)
    args = {
        "id": TAEGIS_PLAYBOOK_INSTANCE_ID,
        "inputs": {
            "MyInput": "MyValue",
        }
    }

    response = execute_playbook_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs["id"] == TAEGIS_PLAYBOOK_EXECUTION_ID

    with pytest.raises(ValueError, match="Cannot execute playbook, missing playbook_id"):
        assert execute_playbook_command(client=client, env=TAEGIS_ENVIRONMENT, args={})

    client = mock_client(requests_mock, EXECUTE_PLAYBOOK_BAD_RESPONSE)
    with pytest.raises(ValueError, match="Failed to execute playbook: must be defined"):
        assert execute_playbook_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)


def test_fetch_alerts(requests_mock):
    client = mock_client(requests_mock, FETCH_ALERTS_RESPONSE)
    args = {
        "limit": 1,
        "offset": 0,
        "cql_query": "from alert severity >= 0.6 and status='OPEN'",
    }

    # Test with no IDs set
    response = fetch_alerts_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs[0] == TAEGIS_ALERT
    assert len(response.outputs) == len([TAEGIS_ALERT])


def test_fetch_alerts_by_id(requests_mock):
    """Tests taegis-fetch-alert command function
    """
    client = mock_client(requests_mock, FETCH_ALERTS_BY_ID_RESPONSE)

    # Test with IDs set (list)
    args = {
        "ids": ["alert://priv:crowdstrike:11772:1666247222095:4e41ec02-ca53-5ff7-95cc-eda434221ba6"]
    }
    response = fetch_alerts_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs[0] == TAEGIS_ALERT
    assert len(response.outputs) == len([TAEGIS_ALERT])

    # Test with IDs set (comma separated list)
    args = {
        "ids": "alert://priv:crowdstrike:11772:1666247222095:4e41ec02-ca53-5ff7-95cc-eda434221ba6"
    }
    response = fetch_alerts_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs[0] == TAEGIS_ALERT
    assert len(response.outputs) == len([TAEGIS_ALERT])


def test_fetch_assets(requests_mock):
    """Tests taegis-fetch-assets command function
    """

    client = mock_client(requests_mock, FETCH_ASSETS_RESPONSE)
    args = {
        "page": 0,
        "page_size": 1,
    }

    response = fetch_assets_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs == [TAEGIS_ASSET]

    # Test allowed search fields
    args = {
        "host_id": TAEGIS_ASSET["hostId"]
    }
    response = fetch_assets_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs[0] == TAEGIS_ASSET
    assert len(response.outputs) == len([TAEGIS_ASSET])

    # Asset Query Failure
    client = mock_client(requests_mock, FETCH_ASSETS_BAD_RESPONSE)
    with pytest.raises(ValueError, match="Failed to fetch assets:"):
        assert fetch_assets_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)


def test_create_comment(requests_mock):
    """Tests taegis-create-comment command function
    """
    client = mock_client(requests_mock, CREATE_COMMENT_RESPONSE)

    # comment not set
    with pytest.raises(ValueError, match="Cannot create comment, comment cannot be empty"):
        assert create_comment_command(client=client, env=TAEGIS_ENVIRONMENT, args={})

    # parent_id not set
    with pytest.raises(ValueError, match="Cannot create comment, parent_id cannot be empty"):
        assert create_comment_command(client=client, env=TAEGIS_ENVIRONMENT, args={"comment": "test"})

    args = {
        "comment": FETCH_COMMENT_RESPONSE["data"]["comment"]["comment"],
        "parent_id": FETCH_COMMENT_RESPONSE["data"]["comment"]["parent_id"],
        "parent_type": "bad_parent_type",
    }

    # Invalid parent type
    with pytest.raises(ValueError, match="The provided comment parent type, bad_parent_type, is not valid."):
        assert create_comment_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)

    args["parent_type"] = "investigation"

    #  # Successful fetch - Comment created
    response = create_comment_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs == CREATE_COMMENT_RESPONSE["data"]["createComment"]

    # Comment creation failed
    client = mock_client(requests_mock, CREATE_UPDATE_COMMENT_BAD_RESPONSE)
    with pytest.raises(ValueError, match="Failed to create comment:"):
        assert create_comment_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)


def test_fetch_comment_by_id(requests_mock):
    """Tests taegis-fetch-comment command function
    """
    client = mock_client(requests_mock, FETCH_COMMENT_RESPONSE)

    # comment_id not set
    with pytest.raises(ValueError, match="Cannot fetch comment, missing comment_id"):
        assert fetch_comment_command(client=client, env=TAEGIS_ENVIRONMENT, args={})

    args = {"id": "ff9ca818-4749-4ccb-883a-2ccc6f6c9e0f"}

    # Successful fetch - Comment found
    response = fetch_comment_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs == FETCH_COMMENT_RESPONSE["data"]["comment"]

    # Comment not found
    client = mock_client(requests_mock, {})
    with pytest.raises(ValueError, match="Could not locate comment by provided ID"):
        assert fetch_comment_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)


def test_fetch_comments_by_parent(requests_mock):
    """Tests taegis-fetch-comments command function
    """
    client = mock_client(requests_mock, FETCH_COMMENTS_RESPONSE)

    # comment_id not set
    with pytest.raises(ValueError, match="Cannot fetch comments, missing parent_id"):
        assert fetch_comments_command(client=client, env=TAEGIS_ENVIRONMENT, args={})

    args = {
        "parent_id": "c2e09554-833e-41a1-bc9d-8160aec0d70d",
        "parent_type": "bad_parent_type",
    }

    # Invalid parent type
    with pytest.raises(ValueError, match="The provided comment parent type, bad_parent_type, is not valid."):
        assert fetch_comments_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)

    # Successful fetch
    args["parent_type"] = "investigation"
    response = fetch_comments_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs == FETCH_COMMENTS_RESPONSE["data"]["commentsByParent"]

    # Comment not found, bad response
    client = mock_client(requests_mock, FETCH_COMMENTS_BAD_RESPONSE)
    with pytest.raises(ValueError, match="Failed to fetch comments:"):
        assert fetch_comments_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)


def test_update_comment(requests_mock):
    """Tests taegis-update-comment command function
    """
    client = mock_client(requests_mock, UPDATE_COMMENT_RESPONSE)

    # comment not set
    with pytest.raises(ValueError, match="Cannot update comment, comment id cannot be empty"):
        assert update_comment_command(client=client, env=TAEGIS_ENVIRONMENT, args={})

    # comment_id not set
    with pytest.raises(ValueError, match="Cannot update comment, comment cannot be empty"):
        assert update_comment_command(client=client, env=TAEGIS_ENVIRONMENT, args={"id": "test"})

    args = {
        "comment": FETCH_COMMENT_RESPONSE["data"]["comment"]["comment"],
        "id": FETCH_COMMENT_RESPONSE["data"]["comment"]["id"],
    }

    #  # Successful fetch - Comment created
    response = update_comment_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs == UPDATE_COMMENT_RESPONSE["data"]["updateComment"]

    # Comment creation failed
    client = mock_client(requests_mock, CREATE_UPDATE_COMMENT_BAD_RESPONSE)
    with pytest.raises(ValueError, match="Failed to locate/update comment:"):
        assert update_comment_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)


def test_fetch_endpoint(requests_mock):
    """Tests taegis-fetch-endpoint command function
    """
    client = mock_client(requests_mock, FETCH_ENDPOINT_RESPONSE)

    # comment_id not set
    with pytest.raises(ValueError, match="Cannot fetch endpoint information, missing id"):
        assert fetch_endpoint_command(client=client, env=TAEGIS_ENVIRONMENT, args={})

    args = {"id": "110d1fd3a23c95c0120d0d10451cb001"}

    # Successful fetch - Endpoint found
    response = fetch_endpoint_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs == FETCH_ENDPOINT_RESPONSE["data"]["assetEndpointInfo"]

    # Endpoint not found
    client = mock_client(requests_mock, FETCH_ENDPOINT_BAD_RESPONSE)
    with pytest.raises(ValueError, match="Failed to fetch endpoint information"):
        assert fetch_endpoint_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)


def test_connectivity(requests_mock):
    response = {"revision": "1e9c12c7f3f51d5ecc0da91d1ac8bcb27e3566a7", "timestamp": "2022-01-01T17:02:01Z"}
    client = mock_client(requests_mock, response)
    assert connectivity_test(client=client) == "ok"


def test_fetch_incidents(requests_mock):
    """Tests taegis-fetch-incidents command function
    """
    client = mock_client(requests_mock, FETCH_INCIDENTS_RESPONSE)
    response = fetch_incidents(client=client)
    assert response[0]['name'] == FETCH_INCIDENTS_RESPONSE["data"]["allInvestigations"][0]['description']

    with pytest.raises(ValueError, match="Max Fetch must be between 1 and 200"):
        assert fetch_incidents(client=client, max_fetch=0)

    with pytest.raises(ValueError, match="Max Fetch must be between 1 and 200"):
        assert fetch_incidents(client=client, max_fetch=201)

    # Failure from Taegis API
    client = mock_client(requests_mock, FETCH_INCIDENTS_BAD_RESPONSE)
    error = f"Error when fetching investigations: {FETCH_INCIDENTS_BAD_RESPONSE['errors'][0]['message']}"
    with pytest.raises(DemistoException, match=error):
        assert fetch_incidents(client=client, max_fetch=200)

    # Ignore incidents that have been archived
    FETCH_INCIDENTS_RESPONSE["data"]["allInvestigations"][0]["archived_at"] = "2022-02-03T13:53:35Z"
    client = mock_client(requests_mock, FETCH_INCIDENTS_RESPONSE)
    response = fetch_incidents(client=client)
    assert len(response) == 0


def test_fetch_investigaton(requests_mock):
    """Tests taegis-fetch-investigation command function

    Test fetching of a single incident
    """
    client = mock_client(requests_mock, FETCH_INVESTIGATION_RESPONSE)
    args = {
        "id": "c2e09554-833e-41a1-bc9d-8160aec0d70d",
        "page": 0,
        "page_sie": 1,
    }

    response = fetch_investigation_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs[0] == TAEGIS_INVESTIGATION

    # Investigation not found
    client = mock_client(requests_mock, {})
    response = fetch_investigation_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert len(response.outputs) == 0


def test_fetch_investigatons(requests_mock):
    """Tests taegis-fetch-investigations command function

    Test fetching of all incidents
    """

    client = mock_client(requests_mock, FETCH_INVESTIGATIONS)
    args = {
        "page": 0,
        "page_size": 1,
    }

    response = fetch_investigation_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs == [TAEGIS_INVESTIGATION]


def test_fetch_investigation_alerts(requests_mock):
    """Tests taegis-fetch-investigation-alerts command function
    """
    client = mock_client(requests_mock, FETCH_INVESTIGATION_ALERTS_RESPONSE)
    args = {
        "id": "c2e09554-833e-41a1-bc9d-8160aec0d70d",
    }

    response = fetch_investigation_alerts_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs[0] == TAEGIS_ALERT
    assert len(response.outputs) == len([TAEGIS_ALERT])

    # No alerts returned
    client = mock_client(requests_mock, {})
    response = fetch_investigation_alerts_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert len(response.outputs) == 0

    # Investigation ID not provided
    with pytest.raises(ValueError, match="Cannot fetch investigation, missing investigation_id"):
        assert fetch_investigation_alerts_command(client=client, env=TAEGIS_ENVIRONMENT, args={})


def test_fetch_playbook_execution(requests_mock):
    """Tests taegis-fetch-playbook-execution command function
    """
    client = mock_client(requests_mock, FETCH_PLAYBOOK_EXECUTION_RESPONSE)
    args = {
        "id": TAEGIS_PLAYBOOK_EXECUTION_ID,
    }

    response = fetch_playbook_execution_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs == TAEGIS_PLAYBOOK_EXECUTION

    client = mock_client(requests_mock, FETCH_PLAYBOOK_EXECUTION_RESPONSE)
    with pytest.raises(ValueError, match="Cannot fetch playbook execution, missing execution id"):
        assert fetch_playbook_execution_command(client=client, env=TAEGIS_ENVIRONMENT, args={})

    client = mock_client(requests_mock, FETCH_PLAYBOOK_EXECUTION_BAD_RESPONSE)
    with pytest.raises(ValueError, match="Failed to fetch playbook execution"):
        assert fetch_playbook_execution_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)


def test_create_investigation(requests_mock):
    """Tests taegis-create-investigation command function
    """
    client = mock_client(requests_mock, CREATE_INVESTIGATION_RESPONSE)
    args = {
        "description": "Test Investigation",
        "priority": 3,
    }

    response = create_investigation_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)

    assert response.outputs["id"] == CREATE_INVESTIGATION_RESPONSE["data"]["createInvestigation"]["id"]

    # Investigation creation failed
    client = mock_client(requests_mock, FETCH_INCIDENTS_BAD_RESPONSE)
    with pytest.raises(ValueError, match="Failed to create investigation:"):
        assert create_investigation_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)


def test_update_investigation(requests_mock):
    """Tests taegis-update-investigation command function
    """
    client = mock_client(requests_mock, UPDATE_INVESTIGATION_RESPONSE)
    args = {
        "id": UPDATE_INVESTIGATION_RESPONSE["data"]["updateInvestigation"]["id"],
        "description": "Test Investigation Updated",
        "priority": 2,
        "status": "Active",
    }
    response = update_investigation_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)

    assert response.outputs["id"] == args["id"]

    # investigation_id not set
    with pytest.raises(ValueError, match="Cannot fetch investigation without investigation_id defined"):
        assert update_investigation_command(client=client, env=TAEGIS_ENVIRONMENT, args={})

    # Investigation update failure
    client = mock_client(requests_mock, FETCH_COMMENTS_BAD_RESPONSE)
    with pytest.raises(ValueError, match="Failed to locate/update investigation"):
        assert update_investigation_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)

    # Invalid investigation status
    args["status"] = "BadStatus"
    bad_status = r"The provided status, BadStatus, is not valid for updating an investigation. Supported Status Values:.*"
    with pytest.raises(ValueError, match=bad_status):
        assert update_investigation_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)

    # Invalid Assignee ID Format
    args["assignee_id"] = "BadAssigneeIDFormat"
    invalid_fields = r"assignee_id MUST be in 'auth0|12345' format or '@secureworks'"
    with pytest.raises(ValueError, match=invalid_fields):
        assert update_investigation_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)

    # No valid update fields set
    args = {"id": UPDATE_INVESTIGATION_RESPONSE["data"]["updateInvestigation"]["id"]}
    invalid_fields = r"No valid investigation fields provided. Supported Update Fields:.*"
    with pytest.raises(ValueError, match=invalid_fields):
        assert update_investigation_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)


def test_archive_investigation(requests_mock):
    """Tests taegis-archive-investigation command function
    """
    client = mock_client(requests_mock, INVESTIGATION_ARCHIVE_RESPONSE)

    # Test Archiving
    args = {"id": TAEGIS_INVESTIGATION["id"]}
    response = archive_investigation_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs["id"] == args["id"]
    assert response.raw_response["data"]["archiveInvestigation"]

    # investigation id not set
    with pytest.raises(ValueError, match="Cannot archive investigation, missing investigation id"):
        assert archive_investigation_command(client=client, env=TAEGIS_ENVIRONMENT, args={})

    # Investigation archive not found
    client = mock_client(requests_mock, INVESTIGATION_ARCHIVE_ALREADY_COMPLETE)
    with pytest.raises(ValueError, match="Could not locate investigation with id:.*"):
        assert archive_investigation_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)


def test_unarchive_investigation(requests_mock):
    """Tests taegis-unarchive-investigation command function
    """
    client = mock_client(requests_mock, INVESTIGATION_UNARCHIVE_RESPONSE)

    # Test Unarchiving
    args = {"id": TAEGIS_INVESTIGATION["id"]}
    response = unarchive_investigation_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs["id"] == args["id"]
    assert response.raw_response["data"]["unArchiveInvestigation"]

    # investigation id not set
    with pytest.raises(ValueError, match="Cannot unarchive investigation, missing investigation id"):
        assert unarchive_investigation_command(client=client, env=TAEGIS_ENVIRONMENT, args={})

    # Investigation is not archived
    client = mock_client(requests_mock, INVESTIGATION_ARCHIVE_ALREADY_COMPLETE)
    response = unarchive_investigation_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs["id"] == args["id"]
    assert response.outputs["status"] == "Investigation is not currently archived"

    # Could not find investigation by investigation id
    args = {"id": "InvalidInvestigationId"}
    client = mock_client(requests_mock, INVESTIGATION_NOT_ARCHIVED_RESPONSE)
    with pytest.raises(ValueError, match="Could not locate investigation with id:.*"):
        assert unarchive_investigation_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)


def test_isolate_asset(requests_mock):
    """Tests taegis-isolate-asset command function
    """
    client = mock_client(requests_mock, ISOLATE_ASSET_RESPONSE)

    # asset id not set
    with pytest.raises(ValueError, match="Cannot isolate asset, missing id"):
        assert isolate_asset_command(client=client, env=TAEGIS_ENVIRONMENT, args={})
    args = {"id": TAEGIS_ASSET["id"]}

    # reason not set
    with pytest.raises(ValueError, match="Cannot isolate asset, missing reason"):
        assert isolate_asset_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    args["reason"] = "My isolation reason"

    # Successful isolation
    response = isolate_asset_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs == ISOLATE_ASSET_RESPONSE["data"]["isolateAsset"]

    # Endpoint not found
    client = mock_client(requests_mock, ISOLATE_ASSET_BAD_RESPONSE)
    with pytest.raises(ValueError, match="Failed to isolate asset"):
        assert isolate_asset_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)


def test_fetch_users(requests_mock):
    client = mock_client(requests_mock, FETCH_USERS_RESPONSE)
    args = {
        "limit": 1,
        "page_size": 0,
    }

    response = fetch_users_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs[0] == TAEGIS_USER
    assert len(response.outputs) == len([TAEGIS_USER])

    client = mock_client(requests_mock, FETCH_USERS_BAD_RESPONSE)
    with pytest.raises(ValueError, match="Failed to fetch user information:"):
        assert fetch_users_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)

    # Test user search by email
    client = mock_client(requests_mock, FETCH_USERS_RESPONSE)
    args["email"] = TAEGIS_USER["email"]
    response = fetch_users_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs[0] == TAEGIS_USER
    assert len(response.outputs) == len([TAEGIS_USER])

    # Test user search by auth0 user id
    client = mock_client(requests_mock, FETCH_USER_RESPONSE)
    args["id"] = TAEGIS_USER["user_id"]
    args.pop("email")
    response = fetch_users_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs[0] == TAEGIS_USER
    assert len(response.outputs) == len([TAEGIS_USER])

    # Invalid id Format
    args["id"] = "BadAssigneeIDFormat"
    invalid_fields = r"id MUST be in 'auth0|12345' format"
    with pytest.raises(ValueError, match=invalid_fields):
        assert fetch_users_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)


def test_update_alert_status(requests_mock):
    """Tests taegis-update-alert-status command function
    """
    client = mock_client(requests_mock, UPDATE_ALERT_STATUS_RESPONSE)

    args = {"ids": TAEGIS_ALERT['id']}

    # alert ids not set
    with pytest.raises(ValueError, match="Alert IDs must be defined"):
        assert update_alert_status_command(client=client, env=TAEGIS_ENVIRONMENT, args={})

    # status not set
    with pytest.raises(ValueError, match="Alert status must be defined"):
        assert update_alert_status_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)

    args["status"] = "Bad Status"
    with pytest.raises(ValueError, match="The provided status, Bad Status, is not valid for updating an alert"):
        assert update_alert_status_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)

    # Successful update
    args["status"] = "NOT_ACTIONABLE"
    response = update_alert_status_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)
    assert response.outputs == UPDATE_ALERT_STATUS_RESPONSE["data"]["alertsServiceUpdateResolutionInfo"]

    # Alert not updated
    client = mock_client(requests_mock, UPDATE_ALERT_STATUS_BAD_RESPONSE)
    with pytest.raises(ValueError, match="Failed to locate/update alert"):
        assert update_alert_status_command(client=client, env=TAEGIS_ENVIRONMENT, args=args)