diff --git a/integrations/sentinelone/manifest.yaml b/integrations/sentinelone/manifest.yaml index d161839..7590f67 100644 --- a/integrations/sentinelone/manifest.yaml +++ b/integrations/sentinelone/manifest.yaml @@ -2,7 +2,7 @@ id: sentinelone name: SentinelOne version: 1.16.0 description: "SentinelOne Singularity (API v2.1) — endpoint detection & response: triage threats, enrich, isolate/reconnect hosts, mitigate, scan." -changelog: "1.16.0 — count_agents takes an agentVersion__lte filter, the other end of the agentVersion__gt range it already had: agents on the given version or older, so a target build counts as still to be upgraded rather than as already done. Left empty the filter is not sent. 1.15.0 — The incident's process-tree block now draws itself for a unified alert. It rendered the chain already, reading actor.process.file.name, but it places itself automatically only on a mapper declaring actor.process.name next to the parent's, which this one did not — so a generated layout left the block out and the chain went unseen. Mapping the process name to both, plus certSubject to the node's signer badge. Checked by running the block's own reader over the mapper's output on a real alert: explorer.exe to powershell.exe, with the host, the user, and paths and hashes on both nodes when the fetch ran with_details. 1.14.0 — OCSF mapper corrected against a real STAR alert. Its alert-level observables list was empty while every observable sat under the indicators, so the two are now appended instead of reading the alert level alone — 12 observables where the mapper saw none. The same alert had process.username null while its indicators named the user, and named its parent process without hashing it anywhere else, so actor.user.name, actor.process.parent_process.file.path and its three hashes are read from the indicator observables, with the alert's own field winning when filled in. attacks and relatedAlerts are guarded on $count rather than $exists: that alert carries attacks: null, which exists in JSONata and would have written an empty array. Verified end to end through the scheduler's own jsonata-go build, with and without with_details. 1.13.0 — get_unified_alerts takes with_details, which enriches every alert it returns with what only the per-alert view carries: the indicators behind the detection, their MITRE ATT&CK tactic and technique, the observables, the related alerts and the process user. The list nodes alone were too thin to triage on. Read in aliased batches of ten, so a default-limit fetch costs ten extra requests rather than a hundred, and merged under the list node so the richer list fields win on the fields both carry. Best effort: an alert the console will not detail keeps its list fields and the shortfall is reported in pagination.details, rather than failing a fetch that already succeeded. Off by default — a rule that does not set it sends the same queries as before. The OCSF mapper maps the new fields: evidences, finding_info.attacks, finding_info.related_events, the full observables list and the process user. 1.12.0 — get_unified_alerts takes an account_ids filter, so a multi-tenant console can be ingested one account at a time, as get_threats and get_alerts already allowed. Filtered on the scope the alert sits in now (realTime.scope.account.id), falling back to the scope it was detected in and then to a filter over the fetched alerts, the same ladder as the category; pagination.accountFilter reports which ran. 1.11.0 — Absorbs the SentinelOne SDL package, which covered the same unified (UAM) alerts from a second integration: one console, one instance, one set of credentials. get_unified_alerts gains the SDL filters — classification, attack_surface, os_type, asset_id, external_id, search_text, unassigned_only, unmitigated_only and a detectedAt window — status, severity, analyst_verdict and analytics_category take comma-separated lists, and every time input also reads a relative window ('24 hours'). Three capabilities the SDL package had and this one did not: get_unified_alert_details (indicators, their MITRE mapping, observables, related alerts), add_uam_alert_note and trigger_uam_alert_action (any console action by ID). update_uam_alert_assignee completes the status/verdict pair. update_uam_alert_status and _verdict now report a GraphQL error instead of printing it as a successful update. analytics_category filters the fetch to one analytic category, e.g. only the platform-rule alerts (analyticsCategory=Platform Rule, the console's own filter): sent as a server-side filter under either fieldId spelling, and applied to the fetched alerts if the console rejects both, rather than failing the fetch — pagination.categoryFilter reports which ran. The sort argument is likewise tried in both spellings. 1.9.0 — Every command now declares its risk tier, so the agent approval gate can tell a lookup from an action. Only test_connection and get_unified_alerts did; the other 83 were unset, and an unset risk is treated as destructive, which put get-threats and get-alerts behind the same gate as isolate-agent and run-remote-script. 39 read, 22 safe_write, 24 destructive. Destructive covers what removes detection or protection (exclusions, disabling or editing a STAR rule), what adds blocking (blocklist, firewall rule), what changes containment in either direction (isolate and reconnect both), what reboots or shuts a host down, and every delete. 1.8.0 — get_unified_alerts fetches the unified (UAM) alerts: the console-wide alert model served by the unifiedalerts GraphQL endpoint, which get_alerts (cloud-detection) does not cover. Walks the cursor to the requested limit, sorts ascending so a truncated run leaves the watermark on the oldest unseen alert, and flattens edges/node to a plain data[] so the alert rule dedups on a top-level id. Ships with an OCSF mapper (74 fields) and a 'SentinelOne Unified Alert' incident type. 1.7.1 — count_agents' isActive filter is a text field again: declared as a boolean it rendered as a checkbox, which has no empty state, so the count could never be asked for both the active and the inactive agents. Left empty the filter is not sent. 1.7.0 — count_agents takes an accountIds filter, so a multi-tenant console can be counted one account at a time. 1.6.0 — count_agents takes an isActive filter, to count the active agents apart from the inactive ones; left unset, the count still covers both. 1.5.0 — count_agents takes four more filters: agentVersion__gt to count the fleet still below a target build, networkStatuses to count only the endpoints in a given connection state, operationalStatesNin to leave states out of the count, and machineTypes to count servers apart from laptops. 1.4.0 — get_threats and get_alerts accept an optional account_ids filter (accountIds), so a multi-tenant console can be scoped to one or more accounts at fetch time. 1.3.0 — Exhaustive OCSF mappers: get_threats (38 fields) and get_alerts (58 fields) now cover device, finding, malware, actor/target process, file, registry, network, indicators and container. 1.2.4 — Re-modelled the OCSF mappers to OCSF actor/target semantics: the initiating process maps to actor.* (actor.process, actor.user), and the process/file acted upon maps to the target (process.*, file.*, user.*). 1.2.3 — Expanded the OCSF mappers (get_threats, get_alerts) with more fields: file hashes (sha1/md5), file ext/size, finding/rule ids, confidence, status, parent process and device/user identity. 1.2.2 — Added pre-built OCSF mappers (get_threats, get_alerts) for the mapper library. 1.2.1 — Added test_connection for the instance Test button. 1.2.0 — Added 13 commands: threat-analysis, threat-download-from-cloud, abort-endpoint-scan, endpoint-fetch-logs, fetch-file, get-remote-script-task-status/results, get-service-users, list-installed-singularity-marketplace-applications, update-uam-alert-status/verdict, run-powerquery and create-tag-rule (83 commands total). 1.1.0 — Command names prefixed with 'sentinelone-' (e.g. sentinelone-isolate-agent) for easier toolbox search; command IDs unchanged. 1.0.0 — Initial release: 70 commands covering agents, threats, alerts, blocklist/exclusions, IOCs, STAR rules, Deep Visibility, remote scripts, tags, firewall and network discovery based on the SentinelOne API v2.1." +changelog: "1.16.0 — count_agents takes the three version comparators missing beside the agentVersion__gt it already had: agentVersion__gte, agentVersion__lt and agentVersion__lte. Sent together they bound a range, so a fleet can be counted on a band of builds rather than only above one; alone, __lte or __lt answers what is still to be upgraded to a target build, which __gt could not ask. Each is left out of the query when empty. 1.15.0 — The incident's process-tree block now draws itself for a unified alert. It rendered the chain already, reading actor.process.file.name, but it places itself automatically only on a mapper declaring actor.process.name next to the parent's, which this one did not — so a generated layout left the block out and the chain went unseen. Mapping the process name to both, plus certSubject to the node's signer badge. Checked by running the block's own reader over the mapper's output on a real alert: explorer.exe to powershell.exe, with the host, the user, and paths and hashes on both nodes when the fetch ran with_details. 1.14.0 — OCSF mapper corrected against a real STAR alert. Its alert-level observables list was empty while every observable sat under the indicators, so the two are now appended instead of reading the alert level alone — 12 observables where the mapper saw none. The same alert had process.username null while its indicators named the user, and named its parent process without hashing it anywhere else, so actor.user.name, actor.process.parent_process.file.path and its three hashes are read from the indicator observables, with the alert's own field winning when filled in. attacks and relatedAlerts are guarded on $count rather than $exists: that alert carries attacks: null, which exists in JSONata and would have written an empty array. Verified end to end through the scheduler's own jsonata-go build, with and without with_details. 1.13.0 — get_unified_alerts takes with_details, which enriches every alert it returns with what only the per-alert view carries: the indicators behind the detection, their MITRE ATT&CK tactic and technique, the observables, the related alerts and the process user. The list nodes alone were too thin to triage on. Read in aliased batches of ten, so a default-limit fetch costs ten extra requests rather than a hundred, and merged under the list node so the richer list fields win on the fields both carry. Best effort: an alert the console will not detail keeps its list fields and the shortfall is reported in pagination.details, rather than failing a fetch that already succeeded. Off by default — a rule that does not set it sends the same queries as before. The OCSF mapper maps the new fields: evidences, finding_info.attacks, finding_info.related_events, the full observables list and the process user. 1.12.0 — get_unified_alerts takes an account_ids filter, so a multi-tenant console can be ingested one account at a time, as get_threats and get_alerts already allowed. Filtered on the scope the alert sits in now (realTime.scope.account.id), falling back to the scope it was detected in and then to a filter over the fetched alerts, the same ladder as the category; pagination.accountFilter reports which ran. 1.11.0 — Absorbs the SentinelOne SDL package, which covered the same unified (UAM) alerts from a second integration: one console, one instance, one set of credentials. get_unified_alerts gains the SDL filters — classification, attack_surface, os_type, asset_id, external_id, search_text, unassigned_only, unmitigated_only and a detectedAt window — status, severity, analyst_verdict and analytics_category take comma-separated lists, and every time input also reads a relative window ('24 hours'). Three capabilities the SDL package had and this one did not: get_unified_alert_details (indicators, their MITRE mapping, observables, related alerts), add_uam_alert_note and trigger_uam_alert_action (any console action by ID). update_uam_alert_assignee completes the status/verdict pair. update_uam_alert_status and _verdict now report a GraphQL error instead of printing it as a successful update. analytics_category filters the fetch to one analytic category, e.g. only the platform-rule alerts (analyticsCategory=Platform Rule, the console's own filter): sent as a server-side filter under either fieldId spelling, and applied to the fetched alerts if the console rejects both, rather than failing the fetch — pagination.categoryFilter reports which ran. The sort argument is likewise tried in both spellings. 1.9.0 — Every command now declares its risk tier, so the agent approval gate can tell a lookup from an action. Only test_connection and get_unified_alerts did; the other 83 were unset, and an unset risk is treated as destructive, which put get-threats and get-alerts behind the same gate as isolate-agent and run-remote-script. 39 read, 22 safe_write, 24 destructive. Destructive covers what removes detection or protection (exclusions, disabling or editing a STAR rule), what adds blocking (blocklist, firewall rule), what changes containment in either direction (isolate and reconnect both), what reboots or shuts a host down, and every delete. 1.8.0 — get_unified_alerts fetches the unified (UAM) alerts: the console-wide alert model served by the unifiedalerts GraphQL endpoint, which get_alerts (cloud-detection) does not cover. Walks the cursor to the requested limit, sorts ascending so a truncated run leaves the watermark on the oldest unseen alert, and flattens edges/node to a plain data[] so the alert rule dedups on a top-level id. Ships with an OCSF mapper (74 fields) and a 'SentinelOne Unified Alert' incident type. 1.7.1 — count_agents' isActive filter is a text field again: declared as a boolean it rendered as a checkbox, which has no empty state, so the count could never be asked for both the active and the inactive agents. Left empty the filter is not sent. 1.7.0 — count_agents takes an accountIds filter, so a multi-tenant console can be counted one account at a time. 1.6.0 — count_agents takes an isActive filter, to count the active agents apart from the inactive ones; left unset, the count still covers both. 1.5.0 — count_agents takes four more filters: agentVersion__gt to count the fleet still below a target build, networkStatuses to count only the endpoints in a given connection state, operationalStatesNin to leave states out of the count, and machineTypes to count servers apart from laptops. 1.4.0 — get_threats and get_alerts accept an optional account_ids filter (accountIds), so a multi-tenant console can be scoped to one or more accounts at fetch time. 1.3.0 — Exhaustive OCSF mappers: get_threats (38 fields) and get_alerts (58 fields) now cover device, finding, malware, actor/target process, file, registry, network, indicators and container. 1.2.4 — Re-modelled the OCSF mappers to OCSF actor/target semantics: the initiating process maps to actor.* (actor.process, actor.user), and the process/file acted upon maps to the target (process.*, file.*, user.*). 1.2.3 — Expanded the OCSF mappers (get_threats, get_alerts) with more fields: file hashes (sha1/md5), file ext/size, finding/rule ids, confidence, status, parent process and device/user identity. 1.2.2 — Added pre-built OCSF mappers (get_threats, get_alerts) for the mapper library. 1.2.1 — Added test_connection for the instance Test button. 1.2.0 — Added 13 commands: threat-analysis, threat-download-from-cloud, abort-endpoint-scan, endpoint-fetch-logs, fetch-file, get-remote-script-task-status/results, get-service-users, list-installed-singularity-marketplace-applications, update-uam-alert-status/verdict, run-powerquery and create-tag-rule (83 commands total). 1.1.0 — Command names prefixed with 'sentinelone-' (e.g. sentinelone-isolate-agent) for easier toolbox search; command IDs unchanged. 1.0.0 — Initial release: 70 commands covering agents, threats, alerts, blocklist/exclusions, IOCs, STAR rules, Deep Visibility, remote scripts, tags, firewall and network discovery based on the SentinelOne API v2.1." category: endpoint # Per-instance configuration. The scripts build the API base as /web/api/v2.1. @@ -204,6 +204,8 @@ commands: groupIds: { type: string, description: "Comma-separated group IDs" } accountIds: { type: string, description: "Comma-separated account IDs, to scope the count to one or more accounts" } agentVersion__gt: { type: string, description: "Only agents on a version strictly greater than this one, e.g. 23.4.2.6" } + agentVersion__gte: { type: string, description: "Only agents on this version or newer, e.g. 23.4.2.6" } + agentVersion__lt: { type: string, description: "Only agents on a version strictly older than this one, e.g. 23.4.2.6" } agentVersion__lte: { type: string, description: "Only agents on this version or older, e.g. 23.4.2.6 — the fleet still to be upgraded to it" } networkStatuses: { type: string, description: "Comma-separated network statuses: connected | connecting | disconnected | disconnecting" } operationalStatesNin: { type: string, description: "Comma-separated operational states to exclude, e.g. na" } diff --git a/integrations/sentinelone/scripts/count_agents.py b/integrations/sentinelone/scripts/count_agents.py index 8a8c5f2..41e6efe 100644 --- a/integrations/sentinelone/scripts/count_agents.py +++ b/integrations/sentinelone/scripts/count_agents.py @@ -35,11 +35,14 @@ def main(): "groupIds": inputs.get("groupIds"), # Scopes the count to one or more accounts of a multi-tenant console. "accountIds": ",".join(csv(inputs.get("accountIds"))), - # Agents strictly newer than the given version, e.g. 23.4.2.6 — the console - # answers with the fleet still trailing behind a target build. + # The four version comparators the console accepts, e.g. 23.4.2.6. Sent + # together they bound a range: __gte with __lte counts the fleet on a + # band of builds, __gt alone what is already past a target, __lte alone + # what is still to be upgraded to it. The strict and inclusive pairs + # differ only on the boundary version itself. "agentVersion__gt": inputs.get("agentVersion__gt"), - # The other end of the same range: agents on that version or older, so a - # target build counts as still to be upgraded rather than as done. + "agentVersion__gte": inputs.get("agentVersion__gte"), + "agentVersion__lt": inputs.get("agentVersion__lt"), "agentVersion__lte": inputs.get("agentVersion__lte"), # Comma-separated lists are re-joined so a hand-typed "connected, disconnected" # does not reach the API with the space inside the value.