Sekoia XDR
Fetch alerts and events from SEKOIA.IO XDR.\nTo use this integration, please create an API Key with the appropriate permissions.
Analytics & SIEM · SekoiaXDR
Details
| ID | Sekoia XDR |
|---|---|
| Provider | Sekoia |
| Category | Analytics & SIEM |
| From Version | 6.10.0 |
| Docker Image | demisto/python3:3.12.13.10404775 |
| Supported Modules | Agentix XSIAM |
README
Fetch alerts and events from SEKOIA.IO XDR.
To use this integration, please create an API Key with the appropriate permissions.
This integration was integrated and tested with version 1.0 of Sekoia XDR.
Configure Sekoia XDR in Cortex
| Parameter | Description | Required |
|---|---|---|
| API Key | True | |
| Server URL (i.e. https://api.sekoia.io) | True | |
| Trust any certificate (not secure) | False | |
| Use system proxy settings | False | |
| Fetch incidents | False | |
| Incident type | False | |
| First fetch timestamp (<sign + or -><number><time unit>, e.g., -7d, -1h) | True | |
| Maximum incidents to fetch per interval. | By default the max_fetch is set to 10 | True |
| Incidents Fetch Interval | False | |
| Alerts status. | Filter alerts to fetch by status. You can write and press enter to insert new types. | False |
| Alerts types. | Filter alerts to fetch by types. You can write and press enter to insert new types. | False |
| Alerts urgency levels ( “MINurgency,MAXurgency”. i.e: 80,100 ). | Filter alerts by their urgency levels. Use the format “MINurgency, MAXurgency” | False |
| Fetch mode | If there’s no max_fetch it will fetch 10 incidents by default. | True |
| Replace “dots” in event field names with another character. | Replacing dots in events will make names look pretty good for users | True |
| Events fields to exclude from the events search result. | These are the names of the headers presented in the events table. If the header is not in the dropdown list write it and press enter. | False |
| Include assets information in the alerts when fetching. | When selected, it includes the assets information in the alert when fetched from Sekoia. And also If there’s no max_fetch it will fetch 10 incidents by default. |
False |
| Include kill chain information in the alerts when fetching. | When selected, it includes the kill chain information in the alert when fetched from Sekoia. And also If there’s no max_fetch it will fetch 10 incidents by default. |
False |
| Incident Mirroring Direction. | Choose the direction to mirror the incident: None(Disable mirroring), Incoming (from Sekoia XDR to Cortex XSOAR) , Outgoing (from Cortex XSOAR to Sekoia XDR), or Incoming and Outgoing (from/to Cortex XSOAR and Sekoia XDR). Cortex XSOAR only parameter. | False |
| Include events in the mirroring of the alerts. | When selected, it includes the events in the mirrored alerts when an alert is updated in Sekoia. | False |
| Include kill chain information in the mirroring of the alerts. | When selected, it includes the kill chain information of the alert in the mirrored alerts when an alert is updated in Sekoia. | False |
| Reopen Mirrored Cortex XSOAR Incidents (Incoming Mirroring) | When selected, reopening the Sekoia XDR alert will reopen the Cortex XSOAR incident. | False |
| Close Mirrored Cortex XSOAR Incidents (Incoming Mirroring) | When selected, closing the Sekoia XDR alert with a “Closed” or “Reject” status will close the Cortex XSOAR incident. Cortex XSOAR only parameter. | False |
| Close notes. | Change the closing notes that will be added to the tickets closed automatically by the automation. | True |
| Timezone ( TZ format ) | This will be used to present dates in the appropiate timezones, used for comment timestamps, etc. | True |
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.
sekoia-xdr-list-alerts
Command to retrieve a list of Alerts from Sekoia XDR.
Base Command
sekoia-xdr-list-alerts
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | The number of alerts to return. The allowed range is 1-100, default is 20. Default is 20. | Optional |
| status | Match alerts by their status name (separated by commas). Possible values are: Pending, Acknowledged, Ongoing, Rejected, Closed. | Optional |
| created_at | Filter alerts by their creation dates, starting date followed by ending date, i.e: “-3d,now” , “-1w,now” or “2023-01-15,2023-01-17”. | Optional |
| updated_at | Filter alerts by their update dates starting date followed by ending date, i.e: “-3d,now” , “-1w,now” or “2023-01-15,2023-01-17”. | Optional |
| urgency | Filter alerts by their urgencies range in the following format: “MINurgency,MAXurgency”. i.e: 80,100. | Optional |
| Alerts type | Match alerts by their categories (separated by commas). Possible values are: spam, ddos, outage, phishing, unauthorized-use-of-resources, unauthorised-information-access, appscan, scanner, brute-force, exploit. | Optional |
| sort_by | Sort the alerts by any information. Possible values are: created_at, updated_at, target, urgency, status. Default is created_at. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SekoiaXDR.ListAlerts.updated_at | unknown | The time at which the alert was updated. |
| SekoiaXDR.ListAlerts.updated_by | unknown | The user who last updated the alert. |
| SekoiaXDR.ListAlerts.uuid | unknown | The unique identifier of the alert. |
| SekoiaXDR.ListAlerts.title | unknown | The title of the alert. |
| SekoiaXDR.ListAlerts.time_to_respond | unknown | The time it took to respond to the alert. |
| SekoiaXDR.ListAlerts.short_id | unknown | The short identifier of the alert. |
| SekoiaXDR.ListAlerts.community_uuid | unknown | The unique identifier of the community associated with the alert. |
| SekoiaXDR.ListAlerts.kill_chain_short_id | unknown | The short identifier of the kill chain associated with the alert. |
| SekoiaXDR.ListAlerts.number_of_unseen_comments | unknown | The number of unseen comments on the alert. |
| SekoiaXDR.ListAlerts.updated_by_type | unknown | The type of user who last updated the alert. |
| SekoiaXDR.ListAlerts.source | unknown | The source of the alert. |
| SekoiaXDR.ListAlerts.alert_type.value | unknown | The type of the alert. |
| SekoiaXDR.ListAlerts.alert_type.category | unknown | The category type of the alert. |
| SekoiaXDR.ListAlerts.time_to_acknowledge | unknown | The time it took to acknowledge the alert. |
| SekoiaXDR.ListAlerts.stix | unknown | The STIX data associated with the alert. |
| SekoiaXDR.ListAlerts.first_seen_at | unknown | The time the alert was first seen. |
| SekoiaXDR.ListAlerts.ttps.type | unknown | The type of the TTP associated with the alert. |
| SekoiaXDR.ListAlerts.ttps.name | unknown | The name of the TTP associated with the alert. |
| SekoiaXDR.ListAlerts.ttps.id | unknown | The unique identifier of the TTP associated with the alert. |
| SekoiaXDR.ListAlerts.ttps.description | unknown | The description of the TTP associated with the alert. |
| SekoiaXDR.ListAlerts.adversaries.type | unknown | The type of the adversary associated with the alert. |
| SekoiaXDR.ListAlerts.adversaries.name | unknown | The name of the adversary associated with the alert. |
| SekoiaXDR.ListAlerts.adversaries.id | unknown | The unique identifier of the adversary associated with the alert. |
| SekoiaXDR.ListAlerts.adversaries.description | unknown | The description of the adversary associated with the alert. |
| SekoiaXDR.ListAlerts.time_to_ingest | unknown | The time it took to ingest the alert. |
| SekoiaXDR.ListAlerts.target | unknown | The target of the alert. |
| SekoiaXDR.ListAlerts.time_to_resolve | unknown | The time it took to resolve the alert. |
| SekoiaXDR.ListAlerts.created_at | unknown | The time at which the alert was created. |
| SekoiaXDR.ListAlerts.last_seen_at | unknown | The time at which the alert was last seen. |
| SekoiaXDR.ListAlerts.assets | unknown | The assets associated with the alert. |
| SekoiaXDR.ListAlerts.rule.severity | unknown | The severity level of the rule that triggered the alert. |
| SekoiaXDR.ListAlerts.rule.type | unknown | The type of rule that triggered the alert. |
| SekoiaXDR.ListAlerts.rule.uuid | unknown | The unique identifier of the rule that triggered the alert. |
| SekoiaXDR.ListAlerts.rule.name | unknown | The name of the rule that triggered the alert. |
| SekoiaXDR.ListAlerts.rule.description | unknown | The description of the rule that triggered the alert. |
| SekoiaXDR.ListAlerts.rule.pattern | unknown | The pattern of the rule that triggered the alert. |
| SekoiaXDR.ListAlerts.similar | unknown | The number of similar alerts to this one. |
| SekoiaXDR.ListAlerts.status.name | unknown | The name of the status of the alert. |
| SekoiaXDR.ListAlerts.status.description | unknown | The description of the status of the alert. |
| SekoiaXDR.ListAlerts.status.uuid | unknown | The unique identifier of the status of the alert. |
| SekoiaXDR.ListAlerts.urgency.criticity | unknown | The level of criticity of the urgency of the alert. |
| SekoiaXDR.ListAlerts.urgency.current_value | unknown | The current value of the urgency of the alert. |
| SekoiaXDR.ListAlerts.urgency.severity | unknown | The severity level of the urgency of the alert. |
| SekoiaXDR.ListAlerts.urgency.display | unknown | The display of the urgency of the alert. |
| SekoiaXDR.ListAlerts.urgency.value | unknown | The value of the urgency of the alert. |
| SekoiaXDR.ListAlerts.created_by | unknown | The user who created the alert. |
| SekoiaXDR.ListAlerts.number_of_total_comments | unknown | The total number of comments on the alert. |
| SekoiaXDR.ListAlerts.time_to_detect | unknown | The time it took to detect the alert. |
| SekoiaXDR.ListAlerts.entity.name | unknown | The name of the entity associated with the alert. |
| SekoiaXDR.ListAlerts.entity.uuid | unknown | The unique identifier of the entity associated with the alert. |
| SekoiaXDR.ListAlerts.created_by_type | unknown | The type of user who created the alert. |
| SekoiaXDR.ListAlerts.details | unknown | The details of the alert. |
sekoia-xdr-get-alert
Command to retrieve a specific alert by uuid or short_id from Sekoia XDR.
Base Command
sekoia-xdr-get-alert
Input
| Argument Name | Description | Required |
|---|---|---|
| id | The uuid or short_id of the alert to retrieve from sekoia-xdr-list-alerts or from sekoia plateform. i.e: “f5dcb81c-8d81-4332-9f1e-f119a1b31217” or “ALUnyZCYZ9Ga”. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SekoiaXDR.Alert.short_id | string | Short ID of the alert. |
| SekoiaXDR.Alert.title | string | Title of the alert. |
| SekoiaXDR.Alert.urgency | string | urgency of the alert. |
sekoia-xdr-events-execute-query
Command to create an event search job on Sekoia XDR, after this execute “sekoia-xdr-status-events-query” to see the status of the query job and “sekoia-xdr-results-events-query” to retrieve the results..
Base Command
sekoia-xdr-events-execute-query
Input
| Argument Name | Description | Required |
|---|---|---|
| earliest_time | Valid formats <sign + or -><number><time unit> or ISO 8601 e.g -3d, -2w, -7d, 2023-01-15T00:00:00Z. | Required |
| lastest_time | Valid formats <sign + or -><number><time unit> or ISO 8601 e.g +3d, +2w, now, 2023-01-15T00:00:00Z. | Required |
| query | The query to use, i.e: “alert_short_ids:ALUnyZCYZ9Ga”. | Optional |
| max_last_events | Maximum number of listed events. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SekoiaXDR.Events.Query.uuid | unknown | The unique identifier for the event. |
| SekoiaXDR.Events.Query.term | unknown | The search term associated with the event. |
| SekoiaXDR.Events.Query.started_at | unknown | The time at which the event started. |
| SekoiaXDR.Events.Query.short_histogram.cases | unknown | The number of cases associated with the event. |
| SekoiaXDR.Events.Query.short_histogram.total | unknown | The total number of events associated with the search term. |
| SekoiaXDR.Events.Query.short_histogram.alerts | unknown | The number of alerts associated with the event. |
| SekoiaXDR.Events.Query.short_histogram.earliest_time | unknown | The earliest time associated with the event. |
| SekoiaXDR.Events.Query.short_histogram.length | unknown | The length of the histogram for the event. |
| SekoiaXDR.Events.Query.created_by | unknown | The user who created the event. |
| SekoiaXDR.Events.Query.expired | unknown | A boolean indicating whether the event has expired. |
| SekoiaXDR.Events.Query.latest_time | unknown | The latest time associated with the event. |
| SekoiaXDR.Events.Query.expiration_date | unknown | The date on which the event will expire. |
| SekoiaXDR.Events.Query.created_at | unknown | The time at which the event was created. |
| SekoiaXDR.Events.Query.status | unknown | The status of the event. |
| SekoiaXDR.Events.Query.view_uuid | unknown | The unique identifier for the view associated with the event. |
| SekoiaXDR.Events.Query.canceled_at | unknown | The time at which the event was canceled. |
| SekoiaXDR.Events.Query.only_eternal | unknown | A boolean indicating whether the event is only eternal. |
| SekoiaXDR.Events.Query.results_ttl | unknown | The time-to-live for the event results. |
| SekoiaXDR.Events.Query.canceled_by | unknown | The user who canceled the event. |
| SekoiaXDR.Events.Query.term_lang | unknown | The language of the search term associated with the event. |
| SekoiaXDR.Events.Query.ended_at | unknown | The time at which the event ended. |
| SekoiaXDR.Events.Query.earliest_time | unknown | The earliest time associated with the event. |
| SekoiaXDR.Events.Query.max_last_events | unknown | The maximum number of events to include in the results. |
| SekoiaXDR.Events.Query.canceled_by_type | unknown | The type of the user who canceled the event. |
| SekoiaXDR.Events.Query.total | unknown | The total number of events associated with the event. |
| SekoiaXDR.Events.Query.created_by_type | unknown | The type of the user who created the event. |
| SekoiaXDR.Events.Query.community_uuids | unknown | The list of community UUIDs associated with the event. |
| SekoiaXDR.Events.Query.filters.field | unknown | The field associated with the filter. |
| SekoiaXDR.Events.Query.filters.value | unknown | The value associated with the filter. |
| SekoiaXDR.Events.Query.filters.operator | unknown | The operator used in the filter. |
| SekoiaXDR.Events.Query.filters.excluded | unknown | Indicates whether the filter is excluded or not. |
| SekoiaXDR.Events.Query.filters.disabled | unknown | Indicates whether the filter is disabled or not. |
sekoia-xdr-events-status-query
Command to query the status of the search job on Sekoia XDR.
Base Command
sekoia-xdr-events-status-query
Input
| Argument Name | Description | Required |
|---|---|---|
| uuid | UUID of the query executed previously with the “sekoia-xdr-query-events” command. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SekoiaXDR.Events.Status.uuid | unknown | The unique identifier for the event. |
| SekoiaXDR.Events.Status.term | unknown | The term associated with the event. |
| SekoiaXDR.Events.Status.started_at | unknown | The time at which the event started. |
| SekoiaXDR.Events.Status.short_histogram.cases | unknown | The number of cases associated with the event. |
| SekoiaXDR.Events.Status.short_histogram.total | unknown | The total number of events associated with the event. |
| SekoiaXDR.Events.Status.short_histogram.alerts | unknown | The number of alerts associated with the event. |
| SekoiaXDR.Events.Status.short_histogram.earliest_time | unknown | The earliest time associated with the event. |
| SekoiaXDR.Events.Status.short_histogram.length | unknown | The length associated with the event. |
| SekoiaXDR.Events.Status.created_by | unknown | The user who created the event. |
| SekoiaXDR.Events.Status.expired | unknown | Whether the event is expired. |
| SekoiaXDR.Events.Status.latest_time | unknown | The latest time associated with the event. |
| SekoiaXDR.Events.Status.expiration_date | unknown | The date when the event expires. |
| SekoiaXDR.Events.Status.created_at | unknown | The time when the event was created. |
| SekoiaXDR.Events.Status.status | unknown | The current status of the event. |
| SekoiaXDR.Events.Status.view_uuid | unknown | The view associated with the event. |
| SekoiaXDR.Events.Status.canceled_at | unknown | The time when the event was canceled. |
| SekoiaXDR.Events.Status.only_eternal | unknown | Whether only eternal events are associated with the event. |
| SekoiaXDR.Events.Status.results_ttl | unknown | The time-to-live for the event results. |
| SekoiaXDR.Events.Status.canceled_by | unknown | The user who canceled the event. |
| SekoiaXDR.Events.Status.term_lang | unknown | The language associated with the term for the event. |
| SekoiaXDR.Events.Status.ended_at | unknown | The time when the event ended. |
| SekoiaXDR.Events.Status.earliest_time | unknown | The earliest time associated with the event. |
| SekoiaXDR.Events.Status.max_last_events | unknown | The maximum number of events to retrieve. |
| SekoiaXDR.Events.Status.canceled_by_type | unknown | The type of user who canceled the event. |
| SekoiaXDR.Events.Status.total | unknown | The total number of events associated with the event. |
| SekoiaXDR.Events.Status.created_by_type | unknown | The type of user who created the event. |
| SekoiaXDR.Events.Status.community_uuids[0] | unknown | The community associated with the event. |
| SekoiaXDR.Events.Status.filters.field | unknown | The field used for filtering events. |
| SekoiaXDR.Events.Status.filters.field | unknown | The field used in the filter. |
| SekoiaXDR.Events.Status.filters.value | unknown | The value of the filter. |
| SekoiaXDR.Events.Status.filters.operator | unknown | The operator used in the filter. |
| SekoiaXDR.Events.Status.filters.excluded | unknown | A boolean indicating whether the filter is excluded or not. |
| SekoiaXDR.Events.Status.filters.disabled | unknown | A boolean indicating whether the filter is disabled or not. |
sekoia-xdr-events-results-query
Command to retrieve the events from the search job “sekoia-xdr-execute-events-query” previously done on Sekoia XDR.
Base Command
sekoia-xdr-events-results-query
Input
| Argument Name | Description | Required |
|---|---|---|
| uuid | UUID from response of the query executed previously with the “sekoia-xdr-query-events” command. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SekoiaXDR.Events.Results | unknown | The outputs are different for each event, they will be output inside SekoiaXDR.Events.Results. |
sekoia-xdr-search-events
Command to search and retrieve the events from an alert. This is a combination of 3 commands: sekoia-xdr-events-execute-query, sekoia-xdr-events-status-query and sekoia-xdr-events-results-query.
Base Command
sekoia-xdr-search-events
Input
| Argument Name | Description | Required |
|---|---|---|
| earliest_time | Valid formats <sign + or -><number><time unit> or ISO 8601 e.g -3d, -2w, -7d, 2023-01-15T00:00:00Z. | Required |
| lastest_time | Valid formats <sign + or -><number><time unit> or ISO 8601 e.g +3d, +2w, now, 2023-01-15T00:00:00Z. | Required |
| query | The query to use, i.e: “alert_short_ids:ALUnyZCYZ9Ga”. | Optional |
| max_last_events | Maximum number of listed events. | Optional |
| exclude_info | Indicate if there is any information you want to exclude from the results of the events. i.e: original.message, message, agent.name, etc. These are the names of the headers presented in the table. If the header you want to exclude is not in the list write it and press enter. Possible values are: original.message, message, __event_id, agent.name, alert_short_ids, client.address, client.ip, client.user.id, customer.community_name, customer.community_uuid, customer.id, customer.intake_key, customer.intake_name, customer.intake_uuid, ecs.version, entity.id, entity.name, entity.uuid, event.created, event.dialect, event.dialect_uuid, event.id, event.outcome, http.request.method, http.request.referrer, related.ip, sekoiaio.activity.client.id, sekoiaio.activity.client.type, sekoiaio.customer.community_name, sekoiaio.customer.community_uuid, sekoiaio.customer.id, sekoiaio.entity.id, sekoiaio.entity.name, sekoiaio.entity.uuid, sekoiaio.intake.dialect, sekoiaio.intake.dialect_uuid, sekoiaio.intake.key, sekoiaio.intake.name, sekoiaio.intake.parsing_status, sekoiaio.intake.uuid, timestamp, url.domain, url.original, url.path, url.port, url.query, url.registered_domain, url.scheme, url.subdomain, url.top_level_domain, user_agent.original. | Optional |
| job_uuid | The job UUID to retrieve query results. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SekoiaXDR.Events.Results | unknown | The outputs are different for each event, they will be output inside SekoiaXDR.Events.Results. |
sekoia-xdr-update-status-alert
Command to update the status of a specific Alert by uuid or short_id.
Base Command
sekoia-xdr-update-status-alert
Input
| Argument Name | Description | Required |
|---|---|---|
| id | The uuid or short_id of the alert to retrieve from sekoia-xdr-list-alerts or from sekoia plateform. i.e: “f5dcb81c-8d81-4332-9f1e-f119a1b31217” or “ALUnyZCYZ9Ga”. | Required |
| status | The status you want to apply. (Acknowledged, Rejected, Ongoing, Closed)). Possible values are: Acknowledged, Rejected, Ongoing, Closed. | Required |
| comment | Comment to describe why the alert status has changed. | Optional |
Context Output
There is no context output for this command.
sekoia-xdr-post-comment-alert
Command to post comments to alerts in Sekoia XDR.
Base Command
sekoia-xdr-post-comment-alert
Input
| Argument Name | Description | Required |
|---|---|---|
| id | The uuid or short_id of the alert to retrieve from sekoia-xdr-list-alerts command. i.e: “f5dcb81c-8d81-4332-9f1e-f119a1b31217” or “ALUnyZCYZ9Ga”. | Required |
| comment | Content of the comment to be posted on the alert. | Required |
| author | Author of the comment. | Optional |
Context Output
There is no context output for this command.
sekoia-xdr-get-comments
Command to get all the comments from an alert in Sekoia XDR.
Base Command
sekoia-xdr-get-comments
Input
| Argument Name | Description | Required |
|---|---|---|
| id | The uuid or short_id of the alert to retrieve from sekoia-xdr-list-alerts command or from sekoia plateform. i.e: “f5dcb81c-8d81-4332-9f1e-f119a1b31217” or “ALUnyZCYZ9Ga”. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SekoiaXDR.Comments.total | unknown | The total number of items in the comments. |
| SekoiaXDR.Comments.items.date | unknown | The date at which the comment was created. |
| SekoiaXDR.Comments.items.created_by | unknown | The user who created the comment. |
| SekoiaXDR.Comments.items.uuid | unknown | The unique identifier for the comment. |
| SekoiaXDR.Comments.items.content | unknown | The content of the comment. |
| SekoiaXDR.Comments.items.created_by_type | unknown | The type of the user who created the comment. |
| SekoiaXDR.Comments.items.unseen | unknown | Indicates whether the comment has been seen by the user. |
| SekoiaXDR.Comments.items.author | unknown | The author of the comment. |
sekoia-xdr-get-workflow-alert
Command to get the possible transitions of status on the alert.
Base Command
sekoia-xdr-get-workflow-alert
Input
| Argument Name | Description | Required |
|---|---|---|
| id | The uuid or short_id of the alert to retrieve from sekoia-xdr-list-alerts command or from sekoia plateform. i.e: “f5dcb81c-8d81-4332-9f1e-f119a1b31217” or “ALUnyZCYZ9Ga”. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SekoiaXDR.StatusTransitions.actions.name | unknown | The name of the action. |
| SekoiaXDR.StatusTransitions.actions.description | unknown | The description of the action. |
| SekoiaXDR.StatusTransitions.actions.id | unknown | The ID of the action. |
sekoia-xdr-get-cases-alert
Command to retrieve the cases related to an Alert from Sekoia XDR. If a case_id is given, returns the information about it, and if not it will give all cases in this alert.
Base Command
sekoia-xdr-get-cases-alert
Input
| Argument Name | Description | Required |
|---|---|---|
| alert_id | The uuid or short_id of the alert to retrieve from sekoia-xdr-list-alerts command or from sekoia plateform. i.e: “f5dcb81c-8d81-4332-9f1e-f119a1b31217” or “ALUnyZCYZ9Ga”. | Required |
| case_id | The short_id of the case to retrieve from sekoia plateform or from this command without case_is param i.e: “CAQNurTJM8q2”. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SekoiaXDR.Cases.updated_at | unknown | The time at which the case was updated. |
| SekoiaXDR.Cases.updated_by | unknown | The user who updated the case. |
| SekoiaXDR.Cases.uuid | unknown | The unique identifier of the case. |
| SekoiaXDR.Cases.title | unknown | The title of the case. |
| SekoiaXDR.Cases.priority | unknown | The priority level of the case. |
| SekoiaXDR.Cases.short_id | unknown | The short ID of the case. |
| SekoiaXDR.Cases.community_uuid | unknown | The unique identifier of the community to which the case belongs. |
| SekoiaXDR.Cases.updated_by_type | unknown | The type of user who updated the case. |
| SekoiaXDR.Cases.first_seen_at | unknown | The time at which the case was first seen. |
| SekoiaXDR.Cases.number_of_comments | unknown | The number of comments on the case. |
| SekoiaXDR.Cases.alerts.updated_at | unknown | The time at which the alert was updated. |
| SekoiaXDR.Cases.alerts.updated_by | unknown | The user who updated the alert. |
| SekoiaXDR.Cases.alerts.uuid | unknown | The unique identifier of the alert. |
| SekoiaXDR.Cases.alerts.title | unknown | The title of the alert. |
| SekoiaXDR.Cases.alerts.time_to_respond | unknown | The time it took to respond to the alert. |
| SekoiaXDR.Cases.alerts.short_id | unknown | The short ID of the alert. |
| SekoiaXDR.Cases.alerts.community_uuid | unknown | The unique identifier of the community to which the alert belongs. |
| SekoiaXDR.Cases.alerts.kill_chain_short_id | unknown | The short ID of the kill chain. |
| SekoiaXDR.Cases.alerts.number_of_unseen_comments | unknown | The number of unseen comments on the alert. |
| SekoiaXDR.Cases.alerts.updated_by_type | unknown | The type of user who updated the alert. |
| SekoiaXDR.Cases.alerts.source | unknown | The source of the alert. |
| SekoiaXDR.Cases.alerts.alert_type.value | unknown | The type of the alert. |
| SekoiaXDR.Cases.alerts.alert_type.category | unknown | The category type of the alert. |
| SekoiaXDR.Cases.alerts.time_to_acknowledge | unknown | The time it took to acknowledge the alert. |
| SekoiaXDR.Cases.alerts.stix | unknown | The STIX data of the alert. |
| SekoiaXDR.Cases.alerts.first_seen_at | unknown | The time at which the alert was first seen. |
| SekoiaXDR.Cases.alerts.ttps.type | unknown | The type of TTP associated with the alert. |
| SekoiaXDR.Cases.alerts.ttps.name | unknown | The name of the TTP associated with the alert. |
| SekoiaXDR.Cases.alerts.ttps.id | unknown | The ID of the TTP associated with the alert. |
| SekoiaXDR.Cases.alerts.ttps.description | unknown | The description of the TTP associated with the alert. |
| SekoiaXDR.Cases.alerts.adversaries.type | unknown | The type of adversary associated with the alert. |
| SekoiaXDR.Cases.alerts.adversaries.name | unknown | The name of the adversary associated with the alert. |
| SekoiaXDR.Cases.alerts.adversaries.id | unknown | The ID of the adversary associated with the alert. |
| SekoiaXDR.Cases.alerts.adversaries.description | unknown | The description of the adversary associated with the alert. |
| SekoiaXDR.Cases.alerts.time_to_ingest | unknown | The time it took to ingest the alert. |
| SekoiaXDR.Cases.alerts.target | unknown | The target of the alert. |
| SekoiaXDR.Cases.alerts.time_to_resolve | unknown | The time it took to resolve the alert. |
| SekoiaXDR.Cases.alerts.created_at | unknown | The time at which the alert was created. |
| SekoiaXDR.Cases.alerts.last_seen_at | unknown | The time at which the alert was last seen. |
| SekoiaXDR.Cases.alerts.assets | unknown | The assets associated with the alert. |
| SekoiaXDR.Cases.alerts.rule.severity | unknown | The severity level of the rule associated with the alert. |
| SekoiaXDR.Cases.alerts.rule.type | unknown | The type of rule associated with the alert. |
| SekoiaXDR.Cases.alerts.rule.uuid | unknown | The unique identifier of the rule associated with the alert. |
| SekoiaXDR.Cases.alerts.rule.name | unknown | The name of the rule associated with the alert. |
| SekoiaXDR.Cases.alerts.rule.description | unknown | The description of the rule associated with the alert. |
| SekoiaXDR.Cases.alerts.rule.pattern | unknown | The pattern of the rule associated with the alert. |
| SekoiaXDR.Cases.alerts.similar | unknown | The number of similar alerts. |
| SekoiaXDR.Cases.alerts.status.name | unknown | The name of the status of the alert. |
| SekoiaXDR.Cases.alerts.status.description | unknown | The description of the status of the alert. |
| SekoiaXDR.Cases.alerts.status.uuid | unknown | The unique identifier of the status of the alert. |
| SekoiaXDR.Cases.alerts.urgency.criticity | unknown | The level of criticality of the urgency of the alert. |
| SekoiaXDR.Cases.alerts.urgency.current_value | unknown | The current value of the urgency of the alert. |
| SekoiaXDR.Cases.alerts.urgency.severity | unknown | The severity level of the urgency of the alert. |
| SekoiaXDR.Cases.alerts.urgency.display | unknown | The display value of the urgency of the alert. |
| SekoiaXDR.Cases.alerts.urgency.value | unknown | The value of the urgency of the alert. |
| SekoiaXDR.Cases.alerts.created_by | unknown | The user who created the alert. |
| SekoiaXDR.Cases.alerts.number_of_total_comments | unknown | The total number of comments on the alert. |
| SekoiaXDR.Cases.alerts.time_to_detect | unknown | The time it took to detect the alert. |
| SekoiaXDR.Cases.alerts.entity.name | unknown | The name of the entity associated with the alert. |
| SekoiaXDR.Cases.alerts.entity.uuid | unknown | The unique identifier of the entity associated with the alert. |
| SekoiaXDR.Cases.alerts.created_by_type | unknown | The type of user who created the alert. |
| SekoiaXDR.Cases.alerts.details | unknown | The details of the alert. |
| SekoiaXDR.Cases.number_of_alerts | unknown | The number of alerts in the case. |
| SekoiaXDR.Cases.created_at | unknown | The time at which the case was created. |
| SekoiaXDR.Cases.last_seen_at | unknown | The time at which the case was last seen. |
| SekoiaXDR.Cases.status | unknown | The status of the case. |
| SekoiaXDR.Cases.description | unknown | The description of the case. |
| SekoiaXDR.Cases.status_uuid | unknown | The unique identifier of the status of the case. |
| SekoiaXDR.Cases.created_by | unknown | The user who created the case. |
| SekoiaXDR.Cases.tags | unknown | The tags associated with the case. |
| SekoiaXDR.Cases.created_by_type | unknown | The type of user who created the case. |
| SekoiaXDR.Cases.subscribers.avatar_uuid | unknown | The unique identifier of the avatar of the subscriber. |
| SekoiaXDR.Cases.subscribers.type | unknown | The type of subscriber. |
sekoia-xdr-get-asset
Get an asset by its UUID from Sekoia XDR.
Base Command
sekoia-xdr-get-asset
Input
| Argument Name | Description | Required |
|---|---|---|
| asset_uuid | UUID of the asset to get, the UUID should appear with “sekoia-xdr-list-assets” if that alert have assets related, example: “d4cc3b05-a78d-4f29-b27c-c637d86fa03a”. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SekoiaXDR.Asset.owners | unknown | The owners of the asset. |
| SekoiaXDR.Asset.category.types.description | unknown | The description of the category type of the asset. |
| SekoiaXDR.Asset.category.types.name | unknown | The name of the category type of the asset. |
| SekoiaXDR.Asset.category.types.uuid | unknown | The UUID of the category type of the asset. |
| SekoiaXDR.Asset.category.description | unknown | The description of the category of the asset. |
| SekoiaXDR.Asset.category.name | unknown | The name of the category of the asset. |
| SekoiaXDR.Asset.category.uuid | unknown | The UUID of the category of the asset. |
| SekoiaXDR.Asset.created_at | unknown | The time at which the asset was created. |
| SekoiaXDR.Asset.keys.value | unknown | The value of the keys of the asset. |
| SekoiaXDR.Asset.keys.name | unknown | The name of the keys of the asset. |
| SekoiaXDR.Asset.keys.uuid | unknown | The UUID of the keys of the asset. |
| SekoiaXDR.Asset.attributes.value | unknown | The value of the attributes of the asset. |
| SekoiaXDR.Asset.attributes.name | unknown | The name of the attributes of the asset. |
| SekoiaXDR.Asset.attributes.uuid | unknown | The UUID of the attributes of the asset. |
| SekoiaXDR.Asset.updated_at | unknown | The time at which the asset was updated. |
| SekoiaXDR.Asset.asset_type.description | unknown | The description of the asset type. |
| SekoiaXDR.Asset.asset_type.name | unknown | The name of the asset type. |
| SekoiaXDR.Asset.asset_type.uuid | unknown | The UUID of the asset type. |
| SekoiaXDR.Asset.criticity.value | unknown | The criticality value of the asset. |
| SekoiaXDR.Asset.criticity.display | unknown | The display value of the criticality of the asset. |
| SekoiaXDR.Asset.description | unknown | The description of the asset. |
| SekoiaXDR.Asset.community_uuid | unknown | The UUID of the community of the asset. |
| SekoiaXDR.Asset.name | unknown | The name of the asset. |
| SekoiaXDR.Asset.uuid | unknown | The UUID of the asset. |
get-remote-data
This command gets new information about the incidents in the remote system and updates existing incidents in Cortex XSOAR.
Base Command
get-remote-data
Input
| Argument Name | Description | Required |
|---|---|---|
| id | The remote alert ID. | Optional |
| lastUpdate | ISO format date with timezone, e.g., 2023-03-01T16:41:30.589575+02:00. 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.
Base Command
get-modified-remote-data
Input
| Argument Name | Description | Required |
|---|---|---|
| lastUpdate | ISO format date with timezone, e.g., 2023-03-01T16:41:30.589575+02:00. The incident is only returned if it was modified after the last update time. Default is 0. | Optional |
Context Output
There is no context output for this command.
get-mapping-fields
This command pulls the remote schema for the different incident types, and their associated incident fields, from the remote system.
Base Command
get-mapping-fields
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
There is no context output for this command.
sekoia-xdr-list-assets
Command to retrieve a list of Assets from Sekoia XDR.
Base Command
sekoia-xdr-list-assets
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | Limit a number of items. Default is 10. | Optional |
| assets_type | Type of assets to list (computer, network, etc). | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SekoiaXDR.Assets.total | unknown | The total number of items in the response. |
| SekoiaXDR.Assets.items.0.owners.0 | unknown | The ID of the owner of the asset. |
| SekoiaXDR.Assets.items.0.category.types.0.description | unknown | The description of the type of the asset category. |
| SekoiaXDR.Assets.items.0.category.types.0.name | unknown | The name of the type of the asset category. |
| SekoiaXDR.Assets.items.0.category.types.0.uuid | unknown | The UUID of the type of the asset category. |
| SekoiaXDR.Assets.items.0.category.description | unknown | The description of the asset category. |
| SekoiaXDR.Assets.items.0.category.name | unknown | The name of the asset category. |
| SekoiaXDR.Assets.items.0.category.uuid | unknown | The UUID of the asset category. |
| SekoiaXDR.Assets.items.0.created_at | unknown | The time at which the asset was created. |
| SekoiaXDR.Assets.items.0.keys.0.value | unknown | The value of the asset key. |
| SekoiaXDR.Assets.items.0.keys.0.name | unknown | The name of the asset key. |
| SekoiaXDR.Assets.items.0.keys.0.uuid | unknown | The UUID of the asset key. |
| SekoiaXDR.Assets.items.0.attributes.0.value | unknown | The value of the asset attribute. |
| SekoiaXDR.Assets.items.0.attributes.0.name | unknown | The name of the asset attribute. |
| SekoiaXDR.Assets.items.0.attributes.0.uuid | unknown | The UUID of the asset attribute. |
| SekoiaXDR.Assets.items.0.updated_at | unknown | The time at which the asset was last updated. |
| SekoiaXDR.Assets.items.0.asset_type.description | unknown | The description of the asset type. |
| SekoiaXDR.Assets.items.0.asset_type.name | unknown | The name of the asset type. |
| SekoiaXDR.Assets.items.0.asset_type.uuid | unknown | The UUID of the asset type. |
| SekoiaXDR.Assets.items.0.criticity.value | unknown | The numeric value of the asset criticality. |
| SekoiaXDR.Assets.items.0.criticity.display | unknown | The display value of the asset criticality. |
| SekoiaXDR.Assets.items.0.description | unknown | The description of the asset. |
| SekoiaXDR.Assets.items.0.community_uuid | unknown | The UUID of the community to which the asset belongs. |
| SekoiaXDR.Assets.items.0.name | unknown | The name of the asset. |
| SekoiaXDR.Assets.items.0.uuid | unknown | The UUID of the asset. |
sekoia-xdr-get-user
Command to get information about a user in Sekoia XDR. Used also in the command !sekoia-xdr-get-comments to have the name of the persons who made the comments.
Base Command
sekoia-xdr-get-user
Input
| Argument Name | Description | Required |
|---|---|---|
| user_uuid | UUID of the user, you get it from sekoia-xdr-get-comments for example. But make sure that created_by_type field is user. |
Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SekoiaXDR.User.creator.description | unknown | The description of the creator. |
| SekoiaXDR.User.creator.name | unknown | The name of the creator. |
| SekoiaXDR.User.creator.uuid | unknown | The UUID of the creator. |
| SekoiaXDR.User.updated_at | unknown | The time at which the object was last updated. |
| SekoiaXDR.User.created_by | unknown | The UUID of the user who created the object. |
| SekoiaXDR.User.total_members | unknown | The total number of members in the community. |
| SekoiaXDR.User.subcommunities | unknown | The UUIDs of the subcommunities. |
| SekoiaXDR.User.parent_community_uuid | unknown | The UUID of the parent community. |
| SekoiaXDR.User.applications.description | unknown | The description of the application. |
| SekoiaXDR.User.applications.name | unknown | The name of the application. |
| SekoiaXDR.User.applications.uuid | unknown | The UUID of the application. |
| SekoiaXDR.User.is_parent | unknown | Whether the community is a parent community. |
| SekoiaXDR.User.name | unknown | The name of the community. |
| SekoiaXDR.User.members.uuid | unknown | The UUID of the member. |
| SekoiaXDR.User.members.created_at | unknown | The time at which the member was created. |
| SekoiaXDR.User.members.user.firstname | unknown | The first name of the user associated with the member. |
| SekoiaXDR.User.members.user.mfa_enabled | unknown | Whether multi-factor authentication is enabled for the user associated with the member. |
| SekoiaXDR.User.members.user.uuid | unknown | The UUID of the user associated with the member. |
| SekoiaXDR.User.members.user.company_name | unknown | The company name of the user associated with the member. |
| SekoiaXDR.User.members.user.lastname | unknown | The last name of the user associated with the member. |
| SekoiaXDR.User.members.user.created_at | unknown | The time at which the user associated with the member was created. |
| SekoiaXDR.User.members.user.picture_mode | unknown | The picture mode of the user associated with the member. |
| SekoiaXDR.User.members.user.last_activity | unknown | The last activity time of the user associated with the member. |
| SekoiaXDR.User.members.user.updated_at | unknown | The time at which the user associated with the member was last updated. |
| SekoiaXDR.User.members.user.auth_provider | unknown | The authentication provider of the user associated with the member. |
| SekoiaXDR.User.members.user.email | unknown | The email address of the user associated with the member. |
| SekoiaXDR.User.members.user.invitation_v2.email | unknown | The email address for the invitation associated with the user associated with the member. |
| SekoiaXDR.User.members.name | unknown | The name of the member. |
| SekoiaXDR.User.members.updated_at | unknown | The time at which the member was last updated. |
| SekoiaXDR.User.members.status_changed_at | unknown | The time at which the status of the member was last changed. |
| SekoiaXDR.User.members.status | unknown | The status of the member. |
| SekoiaXDR.User.session_timeout | unknown | The session timeout for the community. |
| SekoiaXDR.User.is_mfa_enforced | unknown | Whether multi-factor authentication is enforced for the community. |
| SekoiaXDR.User.uuid | unknown | The UUID of the community. |
| SekoiaXDR.User.created_at | unknown | The time at which the community was created. |
| SekoiaXDR.User.picture_mode | unknown | The picture mode for the community. |
| SekoiaXDR.User.homepage_url | unknown | The homepage URL for the community. |
| SekoiaXDR.User.created_by_type | unknown | The type of the user who created the community. |
| SekoiaXDR.User.disable_inactive_avatars | unknown | Whether inactive avatars are disabled for the community. |
| SekoiaXDR.User.description | unknown | The description of the community. |
sekoia-xdr-add-attributes-asset
Command to add attributes to an asset in Sekoia XDR.
Base Command
sekoia-xdr-add-attributes-asset
Input
| Argument Name | Description | Required |
|---|---|---|
| asset_uuid | UUID of the asset to get, the UUID should appear with “sekoia-xdr-list-assets” if that alert have assets related, example: “d4cc3b05-a78d-4f29-b27c-c637d86fa03a”. | Required |
| name | The name of attributes. | Required |
| value | The value of attributes. | Required |
Context Output
There is no context output for this command.
sekoia-xdr-add-keys-asset
Command to add keys to an asset in Sekoia XDR.
Base Command
sekoia-xdr-add-keys-asset
Input
| Argument Name | Description | Required |
|---|---|---|
| asset_uuid | UUID of the asset to get, the UUID should appear with “sekoia-xdr-list-assets” if that alert have assets related, example: “d4cc3b05-a78d-4f29-b27c-c637d86fa03a”. | Required |
| name | The name of the key to be added. | Required |
| value | The value of the key to be added. | Required |
Context Output
There is no context output for this command.
sekoia-xdr-get-kill-chain
Command to retrieve the definition of a Cyber Kill Chain Step.
Base Command
sekoia-xdr-get-kill-chain
Input
| Argument Name | Description | Required |
|---|---|---|
| kill_chain_uuid | UUID or short_id of the kill chain the UUID should appear with “sekoia-xdr-list-alerts”. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SekoiaXDR.KillChain.stix_name | unknown | The name of the STIX object. |
| SekoiaXDR.KillChain.description | unknown | The description of the STIX object. |
| SekoiaXDR.KillChain.name | unknown | The common name of the STIX object. |
| SekoiaXDR.KillChain.uuid | unknown | The unique identifier of the STIX object. |
| SekoiaXDR.KillChain.short_id | unknown | The short identifier of the STIX object. |
| SekoiaXDR.KillChain.order_id | unknown | The order identifier of the STIX object. |
sekoia-xdr-remove-attribute-asset
Command to remove an attribute from an asset in Sekoia XDR. Note: use !sekoia-xdr-get-asset to find the attribute_uuid to delete.
Base Command
sekoia-xdr-remove-attribute-asset
Input
| Argument Name | Description | Required |
|---|---|---|
| asset_uuid | UUID of the asset, the UUID should appear with “sekoia-xdr-list-assets” if that alert have assets related, example: “d4cc3b05-a78d-4f29-b27c-c637d86fa03a”. | Required |
| attribute_uuid | UUID of the attribute to delete. Note: use !sekoia-xdr-get-asset to find the attribute_uuid to delete. | Required |
Context Output
There is no context output for this command.
sekoia-xdr-remove-key-asset
Command to remove a key from an asset in Sekoia XDR. Note: use !sekoia-xdr-get-asset to find the key_uuid to delete.
Base Command
sekoia-xdr-remove-key-asset
Input
| Argument Name | Description | Required |
|---|---|---|
| asset_uuid | UUID of the asset, the UUID should appear with “sekoia-xdr-list-assets” if that alert have assets related, example: “d4cc3b05-a78d-4f29-b27c-c637d86fa03a”. | Required |
| key_uuid | UUID of the key to remove. Note: use !sekoia-xdr-get-asset to find the key_uuid to delete. | Required |
Context Output
There is no context output for this command.
sekoia-xdr-http-request
Command that performs a HTTP request to Sekoia using the integration authentication configured.
Base Command
sekoia-xdr-http-request
Input
| Argument Name | Description | Required |
|---|---|---|
| method | Method to use with the http request (GET,POST,etc). Default is GET. | Required |
| url_sufix | The URL suffix after https://api.sekoia.io, i.e. /v1/sic/alerts/ or /v1/asset-management/assets/. | Required |
| parameters | Query parameters, i.e. limit -> 10 , match[‘status_name’] -> Ongoing. | Optional |
| data | Body of the request | Optional |
Context Output
There is no context output for this command.
Incident Mirroring
You can enable incident mirroring between Cortex XSOAR incidents and Sekoia XDR corresponding events (available from Cortex XSOAR version 6.0.0).
To set up the mirroring:
- Enable Fetching incidents in your instance configuration.
-
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 Sekoia XDR events (mirroring incoming fields) will be reflected in Cortex XSOAR incidents. Outgoing Any changes in Cortex XSOAR incidents will be reflected in Sekoia XDR events (outgoing mirrored fields). Incoming and Outgoing Changes made in Sekoia will be reflected in Cortex, and vice versa, ensuring status updates are synchronized between both systems. -
Optional: Check the Close Mirrored XSOAR Incident integration parameter to close the Cortex XSOAR incident when the corresponding event is closed in Sekoia XDR.
- Optional: Check the Reopen Mirrored Cortex XSOAR Incidents integration parameter to reopen the Cortex XSOAR incident when the matching Sekoia XDR alert is reopened.
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 Sekoia XDR.
Troubleshooting
To troubleshoot possible issues with the SEKOIA XDR integration, consider the following steps:
- Debug Mode:
- In your integration instance, enable the Debug option.
- Navigate to
Settings > About > Troubleshooting > Download logsto download the logs. Analyzing these logs can provide valuable insights into any issues.
- Mirror Values:
- To diagnose mirroring issues beyond what debug mode offers, you can inspect specific fields in the context data. Check if the following dbot fields are set:
- dbotMirrorInstance: Indicates the instance managing the mirroring.
- dbotMirrorDirection: Shows the direction of mirroring.
- dbotMirrorId: The unique identifier for the mirroring process.
- If these fields are not set, review the mappers to ensure that they are configured correctly.
- To diagnose mirroring issues beyond what debug mode offers, you can inspect specific fields in the context data. Check if the following dbot fields are set:
- dbotMirrorLastSync Field:
- The
dbotMirrorLastSyncfield in the context data will update when the mirroring process updates an incident. - You can observe these updates in the War Room as well, which will provide a log of the mirroring activity.
- The
By following these troubleshooting steps, you can effectively diagnose and resolve issues within the SEKOIA XDR integration.
Best Practices
To make the most out of your SEKOIA XDR integration, consider the following best practices:
-
Mirroring Changes: When mirroring is enabled, please allow at least 1 minute for changes to be reflected. The mirroring process runs every 1 minute, ensuring that data between SEKOIA and Cortex is kept in sync.
-
Handling Reopened Incidents: If you have enabled the reopening option, the Cortex incident will be reopened under two specific conditions:
- Reopened Alert in SEKOIA: If an alert is reopened in SEKOIA, the corresponding incident in Cortex will also be reopened. This ensures that the incident tracking is consistent across both platforms.
- Reopened Incident in Cortex: If you reopen an incident directly in Cortex, you need to be cautious. After reopening the incident in Cortex, you should promptly change the status of the SEKOIA alert. Failing to do so might lead to the incident being automatically closed by the mirroring process.
By adhering to these best practices, you can ensure a smoother and more effective synchronization between SEKOIA and your incident management platform.
Additional documentation
The following documentation can be useful to understand the integration:
| Information | Description |
|---|---|
| Mirroring | Adittional information for mirroring |
| Post process scripts | Adittional information for post process scripts |
| Sekoia XDR documentation | Sekoia XDR Documentation |
| Rest API Documentation | Sekoia XDR API Documentation |
Configuration parameters
credentials— API key (required)url— Server URL (i.e. https://api.sekoia.io) (required)insecure— Trust any certificate (not secure)proxy— Use system proxy settingsisFetch— Fetch incidentsincidentType— Incident typefirst_fetch— First fetch timestamp (<sign + or -><number><time unit>, e.g., -7d, -1h) (required)max_fetch— Maximum incidents to fetch per interval. (required)incidentFetchInterval— Incidents Fetch Intervalalerts_status— Alerts status.alerts_type— Alerts types.alerts_urgency— Alerts urgency levels ( "MINurgency,MAXurgency". i.e: 80,100 ).fetch_mode— Fetch mode (required)replace_dots_event— Replace "dots" in event field names with another character. (required)exclude_info_events— Events fields to exclude from the events search result.fetch_with_assets— Include assets information in the alerts when fetching.fetch_with_kill_chain— Include kill chain information in the alerts when fetching.mirror_direction— Incident Mirroring Direction.mirror_events— Include events in the mirroring of the alerts.mirror_kill_chain— Include kill chain information in the mirroring of the alerts.reopen_incident— Reopen Mirrored Cortex XSOAR Incidents (Incoming Mirroring)close_incident— Close Mirrored Cortex XSOAR Incidents (Incoming Mirroring)close_notes— Close notes. (required)timezone— Timezone ( TZ format ) (required)
Commands (23)
-
get-mapping-fieldsThis command pulls the remote schema for the different incident types, and their associated incident fields, from the remote system.
-
get-modified-remote-dataavailable from Cortex XSOAR version 6.1.0. This command queries for incidents that were modified since the last update.
-
get-remote-dataThis command gets new information about the incidents in the remote system and updates existing incidents in Cortex XSOAR.
-
sekoia-xdr-add-attributes-assetCommand to add attributes to an asset in Sekoia XDR.
-
sekoia-xdr-add-keys-assetCommand to add keys to an asset in Sekoia XDR.
-
sekoia-xdr-events-execute-queryCommand to create an event search job on Sekoia XDR, after this execute "sekoia-xdr-status-events-query" to see the status of the query job and "sekoia-xdr-results-events-query" to retrieve the results..
-
sekoia-xdr-events-results-queryCommand to retrieve the events from the search job "sekoia-xdr-execute-events-query" previously done on Sekoia XDR.
-
sekoia-xdr-events-status-queryCommand to query the status of the search job on Sekoia XDR.
-
sekoia-xdr-get-alertCommand to retrieve a specific alert by uuid or short_id from Sekoia XDR.
-
sekoia-xdr-get-assetGet an asset by its UUID from Sekoia XDR.
-
sekoia-xdr-get-cases-alertCommand to retrieve the cases related to an Alert from Sekoia XDR. If a case_id is given, returns the information about it, and if not it will give all cases in this alert.
-
sekoia-xdr-get-commentsCommand to get all the comments from an alert in Sekoia XDR.
-
sekoia-xdr-get-kill-chainCommand to retrieve the definition of a Cyber Kill Chain Step.
-
sekoia-xdr-get-userCommand to get information about a user in Sekoia XDR. Used also in the command !sekoia-xdr-get-comments to have the name of the persons who made the comments.
-
sekoia-xdr-get-workflow-alertCommand to get the possible transitions of status on the alert.
-
sekoia-xdr-http-requestCommand that performs a HTTP request to Sekoia using the integration authentication configured.
-
sekoia-xdr-list-alertsCommand to retrieve a list of Alerts from Sekoia XDR.
-
sekoia-xdr-list-assetsCommand to retrieve a list of Assets from Sekoia XDR.
-
sekoia-xdr-post-comment-alertCommand to post comments to alerts in Sekoia XDR.
-
sekoia-xdr-remove-attribute-assetCommand to remove an attribute from an asset in Sekoia XDR. Note: use !sekoia-xdr-get-asset to find the attribute_uuid to delete.
-
sekoia-xdr-remove-key-assetCommand to remove a key from an asset in Sekoia XDR. Note: use !sekoia-xdr-get-asset to find the key_uuid to delete.
-
sekoia-xdr-search-eventsCommand to search and retrieve the events from an alert. This is a combination of 3 commands: sekoia-xdr-events-execute-query, sekoia-xdr-events-status-query and sekoia-xdr-events-results-query.
-
sekoia-xdr-update-status-alertCommand to update the status of a specific Alert by uuid or short_id.
from CommonServerPython import * import SekoiaXDR # type: ignore from freezegun import freeze_time from datetime import datetime import pytest import json MOCK_URL = "https://api.sekoia.io" def util_load_json(path) -> dict: with open(path, encoding="utf-8") as f: return json.loads(f.read()) @pytest.fixture(scope="session") def client(): api_key = "test_api_key" headers = {"Authorization": f"Bearer {api_key}"} client = SekoiaXDR.Client( base_url=MOCK_URL, headers=headers, ) return client @pytest.fixture() def context_cache_with_mirroring(): alert = util_load_json("test_data/SekoiaXDR_get_alert.json") return {"mirroring_cache": [{"alert": alert, "entries": {}}]} @pytest.fixture() def context_cache_without_mirroring(): return {} """ TEST HELPER FUNCTIONS """ @freeze_time("2024-09-24 11:25:31 UTC") def test_arg_to_timestamp(): assert SekoiaXDR.arg_to_timestamp("2024-04-25T09:20:55", "lastupdate", True) == 1714036855 assert SekoiaXDR.arg_to_timestamp(1714036855.55, "lastupdate", True) == 1714036855 three_days_ago = datetime.now() - timedelta(days=3) assert SekoiaXDR.arg_to_timestamp("3 days", "lastupdate", True) == int(three_days_ago.timestamp()) with pytest.raises(ValueError): assert SekoiaXDR.arg_to_timestamp(None, "lastupdate", True) == 1714036855 def test_timezone_format(): assert SekoiaXDR.timezone_format(1714036855) == "2024-04-25T09:20:55" assert SekoiaXDR.timezone_format(1710494455) == "2024-03-15T09:20:55" assert SekoiaXDR.timezone_format(1678872055) == "2023-03-15T09:20:55" def test_time_converter(): assert SekoiaXDR.time_converter("2024-04-20T15:30:00+00:00") == "2024-04-20T15:30:00" assert SekoiaXDR.time_converter("1678872055") == "2023-03-15T09:20:55" with pytest.raises(ValueError): assert SekoiaXDR.time_converter("2024-04-20T15:30:00") == "2024-04-20T15:30:00" def test_convert_to_demisto_severity(): assert SekoiaXDR.convert_to_demisto_severity("Low") == 1 assert SekoiaXDR.convert_to_demisto_severity("Moderate") == 2 assert SekoiaXDR.convert_to_demisto_severity("High") == 3 assert SekoiaXDR.convert_to_demisto_severity("Major") == 3 assert SekoiaXDR.convert_to_demisto_severity("Urgent") == 4 def test_exclude_info_events(): upload_test_data = util_load_json("test_data/SekoiaXDR_retrieve_events.json") result = SekoiaXDR.exclude_info_events(upload_test_data, "sekoiaio.any_asset.name") assert "sekoiaio.any_asset.name" not in result second_result = SekoiaXDR.exclude_info_events(upload_test_data, "sekoiaio.tags.related.ip,sekoiaio.tags.host.ip") assert "sekoiaio.tags.related.ip" not in second_result assert "sekoiaio.tags.host.ip" not in second_result def test_undot(): upload_test_data = util_load_json("test_data/SekoiaXDR_retrieve_events.json") result = SekoiaXDR.undot(upload_test_data) assert type(result) is dict assert result["items"][0]["agent_id"] def test_filter_list_by_keys(): dicts_list = [ {"key1": "value1", "key2": "value2", "key3": "value3"}, {"key1": "value4", "key2": "value5", "key3": "value6"}, {"key1": "value7", "key2": "value8", "key3": "value9"}, ] keys_to_keep = ["key1", "key3"] expected_result = [ {"key1": "value1", "key3": "value3"}, {"key1": "value4", "key3": "value6"}, {"key1": "value7", "key3": "value9"}, ] assert SekoiaXDR.filter_list_by_keys(dicts_list, keys_to_keep) == expected_result def test_filter_list_by_keys_with_empty_list(): dicts_list = [] keys_to_keep = ["key1", "key3"] expected_result = [] assert SekoiaXDR.filter_list_by_keys(dicts_list, keys_to_keep) == expected_result def test_filter_dict_by_keys(): dict = { "key1": "value1", "key2": "value2", "key3": "value3", } keys_to_keep = ["key1", "key3"] expected_result = { "key1": "value1", "key3": "value3", } assert SekoiaXDR.filter_dict_by_keys(dict, keys_to_keep) == expected_result def test_filter_dict_by_keys_with_empty_dict(): dict = {} keys_to_keep = ["key1", "key3"] expected_result = {} assert SekoiaXDR.filter_dict_by_keys(dict, keys_to_keep) == expected_result def test_check_id_in_context_with_mirroring(context_cache_with_mirroring): assert SekoiaXDR.check_id_in_context("ALL1A4SKUiU2", context_cache_with_mirroring) == ( context_cache_with_mirroring["mirroring_cache"][0], 0, ) def test_fetch_alerts_asc_mode(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_get_alerts.json") requests_mock.get(MOCK_URL + "/v1/sic/alerts", json=mock_response) args = { "client": client, "alert_status": None, "alert_urgency": None, "alert_type": None, "max_results": 100, "alerts_created_at": None, "alerts_updated_at": None, "sort_by": None, } result = SekoiaXDR.fetch_alerts_asc_mode(**args) assert len(result) == 2 assert result[0]["created_at"] < result[1]["created_at"] def test_handle_alert_events_query_finished_status(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_query_events.json") requests_mock.post(MOCK_URL + "/v1/sic/conf/events/search/jobs", json=mock_response) mock_response_query_events_status = util_load_json("test_data/SekoiaXDR_query_events_status.json") requests_mock.get( MOCK_URL + "/v1/sic/conf/events/search/jobs/df904d2e-2c57-488f", json=mock_response_query_events_status, ) mock_response_retrieve_events = util_load_json("test_data/SekoiaXDR_retrieve_events.json") requests_mock.get( MOCK_URL + "/v1/sic/conf/events/search/jobs/df904d2e-2c57-488f/events", json=mock_response_retrieve_events, ) alert = util_load_json("test_data/SekoiaXDR_get_alert.json") args = { "client": client, "alert": alert, "earliest_time": "2024-04-25T10:00:23", "latest_time": "2024-04-25T15:00:23", "events_term": "sekoiaio.intake.uuid:834a2d7f-3623-4b26", } result_alert, is_ready = SekoiaXDR.handle_alert_events_query(**args) assert "events" in result_alert assert is_ready is True def test_handle_alert_events_query_in_progress_status(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_query_events.json") requests_mock.post(MOCK_URL + "/v1/sic/conf/events/search/jobs", json=mock_response) mock_response_query_events_status = util_load_json("test_data/SekoiaXDR_query_events_status_in_progress.json") requests_mock.get( MOCK_URL + "/v1/sic/conf/events/search/jobs/df904d2e-2c57-488f", json=mock_response_query_events_status, ) alert = util_load_json("test_data/SekoiaXDR_get_alert.json") args = { "client": client, "alert": alert, "earliest_time": "2024-04-25T10:00:23", "latest_time": "2024-04-25T15:00:23", "events_term": "sekoiaio.intake.uuid:834a2d7f-3623-4b26", } result_alert, is_ready = SekoiaXDR.handle_alert_events_query(**args) assert is_ready is False assert "job_uuid" in result_alert assert result_alert["job_uuid"] == "df904d2e-2c57-488f" assert "events" not in result_alert def test_check_id_in_context_without_mirroring(context_cache_without_mirroring): assert not SekoiaXDR.check_id_in_context("ALL1A4SKUiU2", context_cache_without_mirroring) """ TEST COMMANDS FUNCTIONS """ def test_test_module_ok(client, requests_mock): response = { "csrf": "aaa", "fresh": False, "iat": 123456, "identity": "apikey:123456", "jti": "123456", "nbf": 123456, "type": "access", "user_claims": None, } requests_mock.get(MOCK_URL + "/v1/auth/validate", json=response) assert SekoiaXDR.test_module(client) == "ok" @pytest.mark.parametrize( "api_response, expected", [ ({"message": "The token is invalid", "code": "T300"}, "The token is invalid."), ( {"message": "The token has expired", "code": "T301"}, "The token has expired.", ), ({"message": "Token revoked", "code": "T302"}, "The token has been revoked."), ], ) def test_test_module_nok(client, requests_mock, api_response, expected): requests_mock.get(MOCK_URL + "/v1/auth/validate", json=api_response, status_code=401) assert expected in SekoiaXDR.test_module(client) @pytest.mark.parametrize( "method, url_suffix, params, json_test_file", [ ("GET", "/v1/sic/alerts", {}, "test_data/SekoiaXDR_get_alerts.json"), ( "GET", "/v1/asset-management/assets", {}, "test_data/SekoiaXDR_get_assets.json", ), ], ) def test_http_request_list(client, requests_mock, method, url_suffix, params, json_test_file): mock_response = util_load_json(json_test_file) requests_mock.get(MOCK_URL + url_suffix, json=mock_response) args = {"url_suffix": url_suffix, "method": method, "params": params} result = SekoiaXDR.http_request_command(client=client, args=args) assert result.outputs == mock_response["items"] def test_list_alerts(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_get_alerts.json") requests_mock.get(MOCK_URL + "/v1/sic/alerts", json=mock_response) args = {} result = SekoiaXDR.list_alerts_command(client=client, args=args) assert result.outputs == mock_response["items"] def test_get_alert(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_get_alert.json") requests_mock.get(MOCK_URL + "/v1/sic/alerts/ALL1A4SKUiU2", json=mock_response) args = {"id": "ALL1A4SKUiU2"} result = SekoiaXDR.get_alert_command(client=client, args=args) assert result.outputs == mock_response def test_get_workflow_alert(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_get_alert_workflow.json") requests_mock.get(MOCK_URL + "/v1/sic/alerts/ALWVYiP2Msz4/workflow", json=mock_response) args = {"id": "ALWVYiP2Msz4"} result = SekoiaXDR.get_workflow_alert_command(client=client, args=args) assert len(result.outputs) == len(mock_response["actions"]) def test_get_cases_alert(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_get_alert_cases.json") requests_mock.get( MOCK_URL + "/v1/sic/cases?match[alert_uuid]=4fb686e0-ab0c-479c-9afe-856beef9d592&match[short_id]=CAs3AT1XeGCp", json=mock_response, ) args = { "alert_id": "4fb686e0-ab0c-479c-9afe-856beef9d592", "case_id": "CAs3AT1XeGCp", } result = SekoiaXDR.get_cases_alert_command(client=client, args=args) assert len(result.outputs) > 0 def test_update_status_alert(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_get_alert_workflow.json") requests_mock.get(MOCK_URL + "/v1/sic/alerts/ALWVYiP2Msz4/workflow", json=mock_response) requests_mock.patch(MOCK_URL + "/v1/sic/alerts/ALWVYiP2Msz4/workflow", json={}) args = {"id": "ALWVYiP2Msz4", "status": "Acknowledged", "comment": "test cortex"} result = SekoiaXDR.update_status_alert_command(client=client, args=args) assert result.outputs == {} def test_comments_alert_command(client, requests_mock): mock_response_alert_comments = util_load_json("test_data/SekoiaXDR_get_alert_comments.json") requests_mock.get( MOCK_URL + "/v1/sic/alerts/ALL1A4SKUiU2/comments", json=mock_response_alert_comments, ) args = {"id": "ALL1A4SKUiU2"} result = SekoiaXDR.get_comments_alert_command(client=client, args=args) for item in result.outputs: if item["author"].startswith("user"): assert item["user"] == "User with id 7114c307-d86c-4c55" if item["author"].startswith("apikey"): assert item["user"] == "Commented via API" if item["author"].startswith("application"): assert item["user"] == "Sekoia.io" def test_post_comment_alert(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_post_alert_comment.json") requests_mock.post(MOCK_URL + "/v1/sic/alerts/ALU9FpFZoApW/comments", json=mock_response) args = { "id": "ALU9FpFZoApW", "comment": "This alert is always on ongoing status", "author": "Joe", } result = SekoiaXDR.post_comment_alert_command(client=client, args=args) assert result.outputs["author"] == args["author"] assert result.outputs["content"] == args["comment"] def kill_chain_command(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_get_killchain.json") requests_mock.get(MOCK_URL + "/v1/sic/kill-chains/73708d4f-419f-44aa", json=mock_response) args = {"kill_chain_uuid": "73708d4f-419f-44aa"} result = SekoiaXDR.get_kill_chain_command(client=client, args=args) assert result.outputs["uuid"] == args["73708d4f-419f-44aa"] def test_query_events(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_query_events.json") requests_mock.post(MOCK_URL + "/v1/sic/conf/events/search/jobs", json=mock_response) args = { "query": "sekoiaio.intake.uuid:834a2d7f-3623-4b26", "earliest_time": "2024-04-25T10:00:23", "lastest_time": "2024-04-25T15:00:23", } result = SekoiaXDR.query_events_command(client=client, args=args) assert result.outputs == mock_response def test_query_events_status(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_query_events_status.json") requests_mock.get( MOCK_URL + "/v1/sic/conf/events/search/jobs/df904d2e-2c57-488f", json=mock_response, ) args = {"uuid": "df904d2e-2c57-488f"} result = SekoiaXDR.query_events_status_command(client=client, args=args) assert result.outputs == mock_response def test_retrieve_events(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_retrieve_events.json") requests_mock.get( MOCK_URL + "/v1/sic/conf/events/search/jobs/df904d2e-2c57-488f/events", json=mock_response, ) args = {"uuid": "df904d2e-2c57-488f"} result = SekoiaXDR.retrieve_events_command(client=client, args=args) assert result.outputs == mock_response def test_search_events(client, requests_mock, mocker): mock_response_query_events = util_load_json("test_data/SekoiaXDR_query_events.json") mock_response_query_events_status = util_load_json("test_data/SekoiaXDR_query_events_status.json") mock_response_retrieve_events = util_load_json("test_data/SekoiaXDR_retrieve_events.json") requests_mock.post(MOCK_URL + "/v1/sic/conf/events/search/jobs", json=mock_response_query_events) requests_mock.get( MOCK_URL + "/v1/sic/conf/events/search/jobs/df904d2e-2c57-488f", json=mock_response_query_events_status, ) requests_mock.get( MOCK_URL + "/v1/sic/conf/events/search/jobs/df904d2e-2c57-488f/events", json=mock_response_retrieve_events, ) params = {"exclude_info_events": "False", "replace_dots_event": "_"} mocker.patch.object(demisto, "params", return_value=params) args = { "earliest_time": "2024-04-25T10:00:23", "lastest_time": "2024-04-25T15:00:23", "query": "sekoiaio.intake.uuid:834a2d7f-3623-4b26", "max_last_events": "100", "timeout_in_seconds": "5", "exclude_info": "False", "interval_in_seconds": "3", } result: PollResult = SekoiaXDR.search_events_command(client=client, args=args) assert result.outputs[0]["action_id"] assert result.outputs[0]["action_outcome"] assert result.outputs[0]["action_name"] def test_list_assets(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_list_assets.json") requests_mock.get( MOCK_URL + "/v1/asset-management/assets?limit=5&match[type_name]=computer", json=mock_response, ) args = {"limit": "5", "assets_type": "computer"} result = SekoiaXDR.list_asset_command(client=client, args=args) assert len(result.outputs) == 2 def test_get_asset(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_get_asset.json") requests_mock.get(MOCK_URL + "/v1/asset-management/assets/015ea33b-a7a2-4e34", json=mock_response) args = {"asset_uuid": "015ea33b-a7a2-4e34"} result = SekoiaXDR.get_asset_command(client=client, args=args) assert result.outputs["uuid"] == args["asset_uuid"] def test_add_keys_asset(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_post_asset_key.json") requests_mock.post( MOCK_URL + "/v1/asset-management/assets/015ea33b-a7a2-4e34-8beb-0197a93a1011/keys?name=host&value=computer1", json=mock_response, ) args = { "asset_uuid": "015ea33b-a7a2-4e34-8beb-0197a93a1011", "name": "host", "value": "computer1", } result = SekoiaXDR.add_keys_asset_command(client=client, args=args) assert result.outputs["name"] == args["name"] assert result.outputs["value"] == args["value"] def test_remove_keys_asset(client, requests_mock): requests_mock.delete( MOCK_URL + "/v1/asset-management/assets/015ea33b-a7a2-4e34-8beb-0197a93a1011/keys/8007222c-f135-4f5f", json={}, ) args = { "asset_uuid": "015ea33b-a7a2-4e34-8beb-0197a93a1011", "key_uuid": "8007222c-f135-4f5f", } result = SekoiaXDR.remove_key_asset_command(client=client, args=args) assert not result.outputs def test_add_attr_asset(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_post_asset_attr.json") requests_mock.post( MOCK_URL + "/v1/asset-management/assets/015ea33b-a7a2-4e34-8beb-0197a93a1011/attr?name=attr_test_4&value=value4", json=mock_response, ) args = { "asset_uuid": "015ea33b-a7a2-4e34-8beb-0197a93a1011", "name": "attr_test_4", "value": "value4", } result = SekoiaXDR.add_attributes_asset_command(client=client, args=args) assert result.outputs["name"] == args["name"] assert result.outputs["value"] == args["value"] def test_remove_attr_asset(client, requests_mock): requests_mock.delete( MOCK_URL + "/v1/asset-management/assets/015ea33b-a7a2-4e34-8beb-0197a93a1011/attr/8007222c-f135-4f5f", json={}, ) args = { "asset_uuid": "015ea33b-a7a2-4e34-8beb-0197a93a1011", "attribute_uuid": "8007222c-f135-4f5f", } result = SekoiaXDR.remove_attribute_asset_command(client=client, args=args) assert not result.outputs def test_get_user(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_get_user.json") requests_mock.get(MOCK_URL + "/v1/users/7114c307-d86c-4c55", json=mock_response) args = {"user_uuid": "7114c307-d86c-4c55"} result = SekoiaXDR.get_user_command(client=client, args=args) assert result.outputs["firstname"] == "Joe" assert result.outputs["lastname"] == "done" def test_modified_remote_data(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_get_alerts.json") requests_mock.get(MOCK_URL + "/v1/sic/alerts", json=mock_response) args = {"lastUpdate": "2023-06-28T13:21:45"} results = SekoiaXDR.get_modified_remote_data_command(client, args) assert len(results.modified_incident_ids) == 2 @pytest.mark.parametrize( "close_incident, close_note, mirror_events, mirror_kill_chain, reopen_incident", [ (False, "Closed by Sekoia.", True, True, False), (False, "Closed by Sekoia.", False, False, False), ], ) def test_get_remote_data( client, mocker, requests_mock, close_incident, close_note, mirror_events, mirror_kill_chain, reopen_incident, ): mock_response = util_load_json("test_data/SekoiaXDR_get_alert.json") mock_response_query_events = util_load_json("test_data/SekoiaXDR_query_events.json") mock_response_query_events_status = util_load_json("test_data/SekoiaXDR_query_events_status.json") mock_response_retrieve_events = util_load_json("test_data/SekoiaXDR_retrieve_events.json") mock_response_killchain = util_load_json("test_data/SekoiaXDR_get_killchain_mirroring.json") requests_mock.get(MOCK_URL + "/v1/sic/kill-chains/KCXKNfnJuUUU", json=mock_response_killchain) requests_mock.get(MOCK_URL + "/v1/sic/alerts/ALL1A4SKUiU2", json=mock_response) requests_mock.post(MOCK_URL + "/v1/sic/conf/events/search/jobs", json=mock_response_query_events) requests_mock.get( MOCK_URL + "/v1/sic/conf/events/search/jobs/df904d2e-2c57-488f", json=mock_response_query_events_status, ) requests_mock.get( MOCK_URL + "/v1/sic/conf/events/search/jobs/df904d2e-2c57-488f/events", json=mock_response_retrieve_events, ) params = {"exclude_info_events": "False", "replace_dots_event": "_"} mocker.patch.object(demisto, "params", return_value=params) invistagation = { "cacheVersn": 0, "category": "", "closed": "0001-01-01T00:00:00Z", "created": "2024-04-09T15:58:41.908148032Z", "creatingUserId": "admin", "details": "", "entryUsers": ["admin"], "highPriority": False, "id": "5721bf3c-f9ef-4b9e-8942-712ac829e0b7", "isDebug": False, "lastOpen": "0001-01-01T00:00:00Z", "mirrorAutoClose": None, "mirrorTypes": None, "modified": "2024-04-10T09:10:14.357270528Z", "name": "Playground", "rawCategory": "", "reason": None, "runStatus": "", "sizeInBytes": 0, "slackMirrorAutoClose": False, "slackMirrorType": "", "status": 0, "systems": None, "tags": None, "type": 9, "users": ["admin"], "version": 2, } mocker.patch.object(demisto, "investigation", return_value=invistagation) args = {"lastUpdate": "2023-06-28T13:21:45", "id": "ALL1A4SKUiU2"} results = SekoiaXDR.get_remote_data_command( client, args, close_incident, close_note, mirror_events, mirror_kill_chain, reopen_incident, ) assert len(results.mirrored_object) > 0 if mirror_kill_chain: assert results.mirrored_object.get("kill_chain") if mirror_events: assert results.mirrored_object.get("events") @pytest.mark.parametrize( "max_results, last_run, first_fetch_time, alert_status, alert_urgency, alert_type, fetch_mode, \ mirror_direction, fetch_with_assets, fetch_with_kill_chain", [ ( 100, {"last_fetch": 1574065501}, None, None, None, None, None, None, None, None, ), ( 100, {"last_fetch": None}, 1574065501, None, None, None, None, None, None, None, ), ], ) def test_fetch_incidents( client, requests_mock, max_results, last_run, first_fetch_time, alert_status, alert_urgency, alert_type, fetch_mode, mirror_direction, fetch_with_assets, fetch_with_kill_chain, ): mock_response = util_load_json("test_data/SekoiaXDR_get_alerts.json") requests_mock.get(MOCK_URL + "/v1/sic/alerts", json=mock_response) results = SekoiaXDR.fetch_incidents( client, max_results, last_run, first_fetch_time, alert_status, alert_urgency, alert_type, fetch_mode, mirror_direction, fetch_with_assets, fetch_with_kill_chain, ) assert results[0]["last_fetch"] assert len(results[1]) == 2 def test_fetch_incidents_with_same_time(client, requests_mock): mock_response = util_load_json("test_data/SekoiaXDR_get_alerts_same_time.json") requests_mock.get(MOCK_URL + "/v1/sic/alerts", json=mock_response) last_run = {"last_fetch": 1714036855} results = SekoiaXDR.fetch_incidents(client, 100, last_run, None, None, None, None, None, None, None, None) assert results[0]["last_fetch"] == 1747057948 assert len(results[1]) == 2 def test_fetch_incidents_with_all_events_uses_now_as_latest_time(client, requests_mock, mocker): """When fetching with all events, the event search upper bound must be "now". Regression test: a window capped at the alert's last_seen_at could miss events whose timestamp is slightly later (or indexed with a small delay), producing alerts without events. """ # Isolate the integration context so the cached (pending) incidents do not leak to other tests mocker.patch.object(SekoiaXDR, "get_integration_context", return_value={}) mocker.patch.object(SekoiaXDR, "set_integration_context") mock_alerts = util_load_json("test_data/SekoiaXDR_get_alerts.json") requests_mock.get(MOCK_URL + "/v1/sic/alerts", json=mock_alerts) query_job = util_load_json("test_data/SekoiaXDR_query_events.json") post_mock = requests_mock.post(MOCK_URL + "/v1/sic/conf/events/search/jobs", json=query_job) # Keep the search job pending so the alerts are cached (no event retrieval needed for this test) status_pending = util_load_json("test_data/SekoiaXDR_query_events_status_in_progress.json") requests_mock.get( MOCK_URL + "/v1/sic/conf/events/search/jobs/df904d2e-2c57-488f", json=status_pending, ) last_run = {"last_fetch": 1574065501} SekoiaXDR.fetch_incidents(client, 100, last_run, None, None, None, None, "Fetch With All Events", None, None, None) assert post_mock.called assert post_mock.last_request.json()["latest_time"] == "now" """ TEST BACKWARD COMPATIBILITY - url_sufix vs url_suffix """ def test_http_request_with_url_suffix_new_param(client, requests_mock): """Test http_request_command with the NEW corrected parameter 'url_suffix'""" mock_response = util_load_json("test_data/SekoiaXDR_get_alerts.json") requests_mock.get(MOCK_URL + "/v1/sic/alerts", json=mock_response) args = { "method": "GET", "url_suffix": "/v1/sic/alerts", # ← NEW parameter (correct spelling) "parameters": {}, } result = SekoiaXDR.http_request_command(client=client, args=args) assert result.outputs == mock_response["items"] assert result.readable_output is not None def test_http_request_with_url_sufix_old_param(client, requests_mock): """Test http_request_command with the OLD deprecated parameter 'url_sufix' (typo)""" mock_response = util_load_json("test_data/SekoiaXDR_get_alerts.json") requests_mock.get(MOCK_URL + "/v1/sic/alerts", json=mock_response) args = { "method": "GET", "url_sufix": "/v1/sic/alerts", # ← OLD parameter (with typo - backward compatibility) "parameters": {}, } result = SekoiaXDR.http_request_command(client=client, args=args) assert result.outputs == mock_response["items"] assert result.readable_output is not None def test_http_request_missing_both_params(): """Test http_request_command with BOTH parameters missing - should raise error""" client = SekoiaXDR.Client(base_url=MOCK_URL, headers={}) args = { "method": "GET", # Neither url_suffix nor url_sufix provided "parameters": {}, } with pytest.raises(DemistoException, match="Either 'url_suffix' or 'url_sufix' parameter must be provided"): SekoiaXDR.http_request_command(client=client, args=args) def test_http_request_with_post_and_json_data(client, requests_mock): """Test http_request_command with POST method and JSON data""" mock_response = {"status": "created", "id": "12345"} requests_mock.post(MOCK_URL + "/v1/sic/alerts/test/comments", json=mock_response) args = { "method": "POST", "url_suffix": "/v1/sic/alerts/test/comments", "parameters": {}, "data": '{"content": "Test comment", "author": "TestUser"}', } result = SekoiaXDR.http_request_command(client=client, args=args) assert result.outputs == mock_response def test_http_request_with_invalid_json_data(client): """Test http_request_command with invalid JSON data - should raise error""" client = SekoiaXDR.Client(base_url=MOCK_URL, headers={}) args = { "method": "POST", "url_suffix": "/v1/sic/alerts/test/comments", "parameters": {}, "data": "{'invalid': json}", # ← Invalid JSON format } with pytest.raises(DemistoException, match="Data argument is not a valid JSON"): SekoiaXDR.http_request_command(client=client, args=args) """ TEST DUPLICATE HANDLING WITH processed_ids """ def test_fetch_incidents_duplicate_same_timestamp(client, requests_mock): """Test fetch_incidents correctly handles duplicate alerts with same created_at timestamp""" # Load alerts that have the SAME created_at timestamp mock_response = util_load_json("test_data/SekoiaXDR_get_alerts_same_time.json") requests_mock.get(MOCK_URL + "/v1/sic/alerts", json=mock_response) # First fetch - should process all alerts with the same timestamp last_run = {"last_fetch": 1747057948, "processed_ids": []} next_run, incidents = SekoiaXDR.fetch_incidents( client=client, max_results=100, last_run=last_run, first_fetch_time=None, alert_status=None, alert_urgency=None, alert_type=None, fetch_mode=None, mirror_direction=None, fetch_with_assets=None, fetch_with_kill_chain=None, ) # Verify processed_ids are tracked assert "processed_ids" in next_run processed_ids = next_run.get("processed_ids", []) assert isinstance(processed_ids, list), f"processed_ids should be a list, got {type(processed_ids)}" assert len(processed_ids) > 0, "processed_ids should not be empty" # Verify incidents assert len(incidents) == 2 def test_fetch_incidents_skip_already_processed(client, requests_mock): """Test fetch_incidents skips alerts that were already processed""" mock_response = util_load_json("test_data/SekoiaXDR_get_alerts_same_time.json") requests_mock.get(MOCK_URL + "/v1/sic/alerts", json=mock_response) # Use actual alert ID from test data alert_to_skip = "ALL1A4SKUUUU" # ✅ Correspond au fichier JSON last_run = { "last_fetch": 1747057948, "processed_ids": [alert_to_skip], } next_run, incidents = SekoiaXDR.fetch_incidents( client=client, max_results=100, last_run=last_run, first_fetch_time=None, alert_status=None, alert_urgency=None, alert_type=None, fetch_mode=None, mirror_direction=None, fetch_with_assets=None, fetch_with_kill_chain=None, ) # Verify that the skipped alert is not in the results incident_ids = [json.loads(inc["rawJSON"]).get("short_id") for inc in incidents] assert alert_to_skip not in incident_ids, f"Alert '{alert_to_skip}' should have been skipped but was included" # Verify that the other alert is still processed assert len(incidents) == 1 assert json.loads(incidents[0]["rawJSON"]).get("short_id") == "ALN1JwGVLxxx" def test_fetch_incidents_reset_processed_ids_for_new_timestamp(client, requests_mock): """Test that processed_ids list is reset when timestamp changes to a newer one""" # Create two different mock responses for sequential calls old_alerts = util_load_json("test_data/SekoiaXDR_get_alerts_old_time.json") new_alerts = util_load_json("test_data/SekoiaXDR_get_alerts_new_time.json") requests_mock.get( MOCK_URL + "/v1/sic/alerts", [ {"json": old_alerts}, {"json": new_alerts}, ], ) # First fetch last_run_1 = {"last_fetch": 1714036855, "processed_ids": []} next_run_1, _ = SekoiaXDR.fetch_incidents( client=client, max_results=100, last_run=last_run_1, first_fetch_time=None, alert_status=None, alert_urgency=None, alert_type=None, fetch_mode=None, mirror_direction=None, fetch_with_assets=None, fetch_with_kill_chain=None, ) # Second fetch with new timestamp last_run_2 = { "last_fetch": next_run_1["last_fetch"], "processed_ids": next_run_1.get("processed_ids", []), } next_run_2, _ = SekoiaXDR.fetch_incidents( client=client, max_results=100, last_run=last_run_2, first_fetch_time=None, alert_status=None, alert_urgency=None, alert_type=None, fetch_mode=None, mirror_direction=None, fetch_with_assets=None, fetch_with_kill_chain=None, ) processed_ids_1 = next_run_1.get("processed_ids", []) processed_ids_2 = next_run_2.get("processed_ids", []) assert isinstance(processed_ids_1, list) assert isinstance(processed_ids_2, list) assert processed_ids_2 != processed_ids_1 def test_fetch_incidents_accumulate_processed_ids_same_timestamp(client, requests_mock): """Test that processed_ids accumulates for alerts with the same timestamp""" mock_response = util_load_json("test_data/SekoiaXDR_get_alerts_same_time.json") requests_mock.get(MOCK_URL + "/v1/sic/alerts", json=mock_response) last_run = {"last_fetch": 1714036855, "processed_ids": []} next_run, incidents = SekoiaXDR.fetch_incidents( client=client, max_results=100, last_run=last_run, first_fetch_time=None, alert_status=None, alert_urgency=None, alert_type=None, fetch_mode=None, mirror_direction=None, fetch_with_assets=None, fetch_with_kill_chain=None, ) # Both alerts have the same timestamp, so both should be in processed_ids processed_ids = next_run.get("processed_ids", []) assert isinstance(processed_ids, list), f"Expected list, got {type(processed_ids)}" assert len(processed_ids) == 2, f"Expected 2 processed IDs, got {len(processed_ids)}" assert len(incidents) == 2 """ TEST APPLY_TIME_BUFFER FUNCTION """ def test_apply_time_buffer_positive_delta(): """Test apply_time_buffer with positive delta (future)""" iso_time = "2024-04-25T10:00:00Z" result = SekoiaXDR.apply_time_buffer(iso_time, 5) # Add 5 minutes # Result should be 5 minutes later assert "10:05:00" in result def test_apply_time_buffer_negative_delta(): """Test apply_time_buffer with negative delta (past)""" iso_time = "2024-04-25T10:00:00Z" result = SekoiaXDR.apply_time_buffer(iso_time, -5) # Subtract 5 minutes # Result should be 5 minutes earlier assert "09:55:00" in result def test_apply_time_buffer_with_offset(): """Test apply_time_buffer with timezone offset""" iso_time = "2024-04-25T10:00:00+02:00" result = SekoiaXDR.apply_time_buffer(iso_time, 1) # Should handle offset correctly assert "10:01:00" in result def test_apply_time_buffer_preserves_format(): """Test apply_time_buffer preserves ISO format""" iso_time = "2024-04-25T10:00:00Z" result = SekoiaXDR.apply_time_buffer(iso_time, 30) # Should return valid ISO format ending with Z assert result.endswith("Z") assert "T" in result def test_apply_time_buffer_invalid_format(): """Test apply_time_buffer with invalid format - should return original""" invalid_time = "invalid-time-format" result = SekoiaXDR.apply_time_buffer(invalid_time, 5) # Should return the original string if parsing fails assert result == invalid_time """ TEST HANDLE_ALERT_EVENTS_QUERY WITH BUFFERING """ def test_handle_alert_events_query_with_buffer(client, requests_mock): """Test handle_alert_events_query applies time buffer correctly""" mock_response_query = util_load_json("test_data/SekoiaXDR_query_events.json") mock_response_status = util_load_json("test_data/SekoiaXDR_query_events_status.json") mock_response_retrieve = util_load_json("test_data/SekoiaXDR_retrieve_events.json") requests_mock.post(MOCK_URL + "/v1/sic/conf/events/search/jobs", json=mock_response_query) requests_mock.get( MOCK_URL + "/v1/sic/conf/events/search/jobs/df904d2e-2c57-488f", json=mock_response_status, ) requests_mock.get( MOCK_URL + "/v1/sic/conf/events/search/jobs/df904d2e-2c57-488f/events", json=mock_response_retrieve, ) alert = util_load_json("test_data/SekoiaXDR_get_alert.json") result_alert, is_ready = SekoiaXDR.handle_alert_events_query( client=client, alert=alert, earliest_time="2024-04-25T10:00:00Z", latest_time="2024-04-25T15:00:00Z", events_term="test_term", ) # Should have successfully retrieved events assert "events" in result_alert assert is_ready is True def test_handle_alert_events_query_pending_status(client, requests_mock): """Test handle_alert_events_query when job is still pending""" mock_response_query = util_load_json("test_data/SekoiaXDR_query_events.json") mock_response_status_pending = util_load_json("test_data/SekoiaXDR_query_events_status_in_progress.json") requests_mock.post(MOCK_URL + "/v1/sic/conf/events/search/jobs", json=mock_response_query) requests_mock.get( MOCK_URL + "/v1/sic/conf/events/search/jobs/df904d2e-2c57-488f", json=mock_response_status_pending, ) alert = util_load_json("test_data/SekoiaXDR_get_alert.json") result_alert, is_ready = SekoiaXDR.handle_alert_events_query( client=client, alert=alert, earliest_time="2024-04-25T10:00:00Z", latest_time="2024-04-25T15:00:00Z", events_term="test_term", ) assert "job_uuid" in result_alert assert result_alert["job_uuid"] == "df904d2e-2c57-488f" assert "events" not in result_alert assert is_ready is False """ TEST MIRRORING WITH CACHE """ def test_get_remote_data_with_cached_alert(client, requests_mock, mocker): """Test get_remote_data when alert is in cache waiting for events""" alert_cached = util_load_json("test_data/SekoiaXDR_get_alert.json") alert_cached["job_uuid"] = "df904d2e-2c57-488f" mock_response_status = util_load_json("test_data/SekoiaXDR_query_events_status.json") mock_response_retrieve = util_load_json("test_data/SekoiaXDR_retrieve_events.json") requests_mock.get( MOCK_URL + "/v1/sic/conf/events/search/jobs/df904d2e-2c57-488f", json=mock_response_status, ) requests_mock.get( MOCK_URL + "/v1/sic/conf/events/search/jobs/df904d2e-2c57-488f/events", json=mock_response_retrieve, ) # Mock the cache with the alert cache_with_alert = { "mirroring_cache": [ { "alert": alert_cached, "entries": [], } ] } mocker.patch.object(SekoiaXDR, "get_integration_context", return_value=cache_with_alert) mocker.patch.object(SekoiaXDR, "set_integration_context") args = {"lastUpdate": "2023-06-28T13:21:45", "id": "ALL1A4SKUiU2"} result = SekoiaXDR.get_remote_data_command( client=client, args=args, close_incident=False, close_note="Closed by Sekoia", mirror_events=True, mirror_kill_chain=False, reopen_incident=False, ) # Should return the alert with events assert result is not None assert "events" in result.mirrored_object def test_get_remote_data_close_incident_when_closed(client, requests_mock, mocker): """Test get_remote_data closes XSOAR incident when Sekoia alert is closed""" alert = util_load_json("test_data/SekoiaXDR_get_alert.json") alert["status"]["name"] = "Closed" # Set status to Closed requests_mock.get(MOCK_URL + "/v1/sic/alerts/ALL1A4SKUiU2", json=alert) # Mock investigation as OPEN investigation = { "id": "5721bf3c-f9ef-4b9e-8942-712ac829e0b7", "status": 0, # 0 = Open, 1 = Closed } mocker.patch.object(demisto, "investigation", return_value=investigation) args = {"lastUpdate": "2023-06-28T13:21:45", "id": "ALL1A4SKUiU2"} result = SekoiaXDR.get_remote_data_command( client=client, args=args, close_incident=True, # ← Should close the incident close_note="Closed by Sekoia", mirror_events=False, mirror_kill_chain=False, reopen_incident=False, ) # Should have entries requesting to close the incident assert len(result.entries) > 0 assert result.entries[0]["Contents"]["dbotIncidentClose"] is True def test_get_remote_data_reopen_incident_when_reopened(client, requests_mock, mocker): """Test get_remote_data reopens XSOAR incident when Sekoia alert is reopened""" alert = util_load_json("test_data/SekoiaXDR_get_alert.json") alert["status"]["name"] = "Ongoing" # Set status to Ongoing (reopened) requests_mock.get(MOCK_URL + "/v1/sic/alerts/ALL1A4SKUiU2", json=alert) # Mock investigation as CLOSED investigation = { "id": "5721bf3c-f9ef-4b9e-8942-712ac829e0b7", "status": 1, # 1 = Closed } mocker.patch.object(demisto, "investigation", return_value=investigation) args = {"lastUpdate": "2023-06-28T13:21:45", "id": "ALL1A4SKUiU2"} result = SekoiaXDR.get_remote_data_command( client=client, args=args, close_incident=False, close_note="", mirror_events=False, mirror_kill_chain=False, reopen_incident=True, # ← Should reopen the incident ) # Should have entries requesting to reopen the incident assert len(result.entries) > 0 assert result.entries[0]["Contents"]["dbotIncidentReopen"] is True def test_get_modified_remote_data_includes_cached(client, requests_mock, mocker): """Test get_modified_remote_data includes cached mirroring alerts""" mock_response = util_load_json("test_data/SekoiaXDR_get_alerts.json") requests_mock.get(MOCK_URL + "/v1/sic/alerts", json=mock_response) # Mock cache with a mirroring alert cached_alert_id = "CACHED_ALERT_ID" cache = { "mirroring_cache": [ { "alert": {"short_id": cached_alert_id}, "entries": [], } ] } mocker.patch.object(SekoiaXDR, "get_integration_context", return_value=cache) args = {"lastUpdate": "2023-06-28T13:21:45"} result = SekoiaXDR.get_modified_remote_data_command(client, args) # Should include the cached alert ID assert cached_alert_id in result.modified_incident_ids # Should also include the ones from API response assert len(result.modified_incident_ids) >= 3 # 1 cached + 2 from API def test_http_request_applies_retry_defaults(client, mocker): """The Client should inject retry defaults into every _http_request call.""" super_request = mocker.patch.object(SekoiaXDR.BaseClient, "_http_request", return_value={}) client.get_alert(alert_uuid="ALERT-ID") _, kwargs = super_request.call_args assert kwargs["retries"] == SekoiaXDR.API_RETRIES assert kwargs["status_list_to_retry"] == SekoiaXDR.API_STATUS_LIST_TO_RETRY assert kwargs["backoff_factor"] == SekoiaXDR.API_BACKOFF_FACTOR def test_http_request_preserves_explicit_retry_args(client, mocker): """Explicit retry arguments passed by a caller must take precedence over defaults.""" super_request = mocker.patch.object(SekoiaXDR.BaseClient, "_http_request", return_value="ok") client._http_request(method="GET", url_suffix="/v1/auth/validate", retries=0) _, kwargs = super_request.call_args assert kwargs["retries"] == 0 assert kwargs["status_list_to_retry"] == SekoiaXDR.API_STATUS_LIST_TO_RETRY assert kwargs["backoff_factor"] == SekoiaXDR.API_BACKOFF_FACTOR