diff --git a/plugins/s1-secops-skills/README.md b/plugins/s1-secops-skills/README.md index 21f3bd7..5cf6052 100644 --- a/plugins/s1-secops-skills/README.md +++ b/plugins/s1-secops-skills/README.md @@ -374,7 +374,7 @@ Prerequisite: Docker Desktop (macOS/Windows) or Docker Engine (Linux), running. docker pull ghcr.io/pmoses-s1/s1-mcps:1.3.1 ``` -`:1.2.3` is the current pinned release (bundles s1-secops-mcp 1.2.2, purple-mcp v0.7.0, virustotal-mcp 1.0.21). `:latest` also works; pin an explicit version for reproducible, forensically consistent installs. About 250 MB compressed. +`:1.3.1` is the current pinned release (bundles s1-secops-mcp 1.3.1, purple-mcp v0.7.0, virustotal-mcp 1.0.21). `:latest` also works; pin an explicit version for reproducible, forensically consistent installs. About 250 MB compressed. **Step 2: Configure credentials** @@ -403,14 +403,14 @@ Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) o "command": "docker", "args": [ "run", "-i", "--rm", "--pull=missing", - "-e", "PURPLEMCP_CONSOLE_TOKEN", - "-e", "PURPLEMCP_CONSOLE_BASE_URL", + "-e", "S1_CONSOLE_URL", + "-e", "S1_CONSOLE_API_TOKEN", "ghcr.io/pmoses-s1/s1-mcps:1.3.1", "purple-mcp" ], "env": { - "PURPLEMCP_CONSOLE_TOKEN": "eyJ...your-api-token...", - "PURPLEMCP_CONSOLE_BASE_URL": "https://usea1-yourorg.sentinelone.net" + "S1_CONSOLE_URL": "https://usea1-yourorg.sentinelone.net", + "S1_CONSOLE_API_TOKEN": "eyJ...your-api-token..." } }, "virustotal": { @@ -437,8 +437,8 @@ Where to get each value: | Placeholder | What it is | Where to get it | |---|---|---| -| `S1_CONSOLE_URL`, `PURPLEMCP_CONSOLE_BASE_URL` | Your console URL | e.g. `https://usea1-yourorg.sentinelone.net` | -| `S1_CONSOLE_API_TOKEN`, `PURPLEMCP_CONSOLE_TOKEN` | Mgmt Console API token (the **same** token for both) | Settings → Users → Service Users → Create New Service User ([guide](https://community.sentinelone.com/s/article/000005291)) | +| `S1_CONSOLE_URL` | Your console URL | e.g. `https://usea1-yourorg.sentinelone.net` | +| `S1_CONSOLE_API_TOKEN` | Mgmt Console API token | Settings → Users → Service Users → Create New Service User ([guide](https://community.sentinelone.com/s/article/000005291)) | | `S1_HEC_INGEST_URL` | HEC ingest host for your region | [Endpoint URLs by Region](https://community.sentinelone.com/s/article/000004961) | | `VIRUSTOTAL_API_KEY` | VirusTotal API key (free tier is fine) | [virustotal.com/gui/my-apikey](https://www.virustotal.com/gui/my-apikey) | @@ -475,7 +475,7 @@ The second command returns one JSON line with `serverInfo.name = "s1-secops-mcp- | MCP shows red in Cowork → MCP Servers | Confirm Docker is running: `docker info \| head -3`. Start Docker Desktop, then restart Claude Desktop. | | `Cannot connect to the Docker daemon` in the logs | Docker Desktop is not running. | | `denied: permission_denied` from ghcr.io | Image is private or your network blocks ghcr.io: `docker login ghcr.io`, or check VPN/proxy. | -| `VIRUSTOTAL_API_KEY ... required`, or a `PURPLEMCP_*` validation error | The env value did not propagate; re-check the `env` block and that each `-e VAR` name matches a key. | +| `VIRUSTOTAL_API_KEY ... required`, or a `PURPLEMCP_*` validation error | The value did not reach the container. Check each `-e VAR` name has a matching key in the same block's `env`. | | `S1 Mgmt API: NOT configured` | No console token reached the container; check `S1_CONSOLE_URL` + `S1_CONSOLE_API_TOKEN`. | Per-MCP logs are at `~/Library/Logs/Claude/mcp-server-.log`. Upgrading from 1.2.x? See **[docs/upgrading.md](./docs/upgrading.md)**. diff --git a/plugins/s1-secops-skills/dist/hyperautomation.skill b/plugins/s1-secops-skills/dist/hyperautomation.skill index 38fd62c..11d1b5c 100644 Binary files a/plugins/s1-secops-skills/dist/hyperautomation.skill and b/plugins/s1-secops-skills/dist/hyperautomation.skill differ diff --git a/plugins/s1-secops-skills/dist/mgmt-console-api.skill b/plugins/s1-secops-skills/dist/mgmt-console-api.skill index c481ce2..6010d3a 100644 Binary files a/plugins/s1-secops-skills/dist/mgmt-console-api.skill and b/plugins/s1-secops-skills/dist/mgmt-console-api.skill differ diff --git a/plugins/s1-secops-skills/dist/powerquery.skill b/plugins/s1-secops-skills/dist/powerquery.skill index ca86da1..cc9b076 100644 Binary files a/plugins/s1-secops-skills/dist/powerquery.skill and b/plugins/s1-secops-skills/dist/powerquery.skill differ diff --git a/plugins/s1-secops-skills/dist/s1-secops-skills-v1.3.0.plugin b/plugins/s1-secops-skills/dist/s1-secops-skills-v1.3.0.plugin index 4ab2e5f..4c8cfde 100644 Binary files a/plugins/s1-secops-skills/dist/s1-secops-skills-v1.3.0.plugin and b/plugins/s1-secops-skills/dist/s1-secops-skills-v1.3.0.plugin differ diff --git a/plugins/s1-secops-skills/dist/sdl-api.skill b/plugins/s1-secops-skills/dist/sdl-api.skill index b0a3aa6..83acbcd 100644 Binary files a/plugins/s1-secops-skills/dist/sdl-api.skill and b/plugins/s1-secops-skills/dist/sdl-api.skill differ diff --git a/plugins/s1-secops-skills/dist/sdl-dashboard.skill b/plugins/s1-secops-skills/dist/sdl-dashboard.skill index 6d7ab35..3b3d012 100644 Binary files a/plugins/s1-secops-skills/dist/sdl-dashboard.skill and b/plugins/s1-secops-skills/dist/sdl-dashboard.skill differ diff --git a/plugins/s1-secops-skills/dist/sdl-log-parser.skill b/plugins/s1-secops-skills/dist/sdl-log-parser.skill index 760230e..aae8046 100644 Binary files a/plugins/s1-secops-skills/dist/sdl-log-parser.skill and b/plugins/s1-secops-skills/dist/sdl-log-parser.skill differ diff --git a/plugins/s1-secops-skills/dist/sdl-solutions.skill b/plugins/s1-secops-skills/dist/sdl-solutions.skill index 163f860..fafaf5d 100644 Binary files a/plugins/s1-secops-skills/dist/sdl-solutions.skill and b/plugins/s1-secops-skills/dist/sdl-solutions.skill differ diff --git a/plugins/s1-secops-skills/dist/soc-investigator.skill b/plugins/s1-secops-skills/dist/soc-investigator.skill index 05771e0..e6b41be 100644 Binary files a/plugins/s1-secops-skills/dist/soc-investigator.skill and b/plugins/s1-secops-skills/dist/soc-investigator.skill differ diff --git a/plugins/s1-secops-skills/docs/installation.md b/plugins/s1-secops-skills/docs/installation.md index eca3964..c7e51e0 100644 --- a/plugins/s1-secops-skills/docs/installation.md +++ b/plugins/s1-secops-skills/docs/installation.md @@ -64,8 +64,8 @@ All three servers run from public package registries: `s1-secops-mcp` and `@burt "stdio" ], "env": { - "PURPLEMCP_CONSOLE_TOKEN": "eyJ...your-api-token...", - "PURPLEMCP_CONSOLE_BASE_URL": "https://usea1-yourorg.sentinelone.net" + "S1_CONSOLE_URL": "https://usea1-yourorg.sentinelone.net", + "S1_CONSOLE_API_TOKEN": "eyJ...your-api-token..." } }, "virustotal": { diff --git a/plugins/s1-secops-skills/docs/vm-deployment.md b/plugins/s1-secops-skills/docs/vm-deployment.md index 6daebe4..2c374cf 100644 --- a/plugins/s1-secops-skills/docs/vm-deployment.md +++ b/plugins/s1-secops-skills/docs/vm-deployment.md @@ -162,8 +162,8 @@ Paste this into the config file. Replace `` with the beare "command": "uvx", "args": ["--from", "git+https://github.com/Sentinel-One/purple-mcp.git", "purple-mcp", "--mode", "stdio"], "env": { - "PURPLEMCP_CONSOLE_TOKEN": "...", - "PURPLEMCP_CONSOLE_BASE_URL": "..." + "S1_CONSOLE_URL": "...", + "S1_CONSOLE_API_TOKEN": "..." } }, "virustotal": { @@ -220,8 +220,8 @@ Open `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) o "command": "uvx", "args": ["--from", "git+https://github.com/Sentinel-One/purple-mcp.git", "purple-mcp", "--mode", "stdio"], "env": { - "PURPLEMCP_CONSOLE_TOKEN": "...", - "PURPLEMCP_CONSOLE_BASE_URL": "..." + "S1_CONSOLE_URL": "...", + "S1_CONSOLE_API_TOKEN": "..." } }, "virustotal": { diff --git a/plugins/s1-secops-skills/skills/sdl-api/SKILL.md b/plugins/s1-secops-skills/skills/sdl-api/SKILL.md index 4073cd8..1a5e84e 100644 --- a/plugins/s1-secops-skills/skills/sdl-api/SKILL.md +++ b/plugins/s1-secops-skills/skills/sdl-api/SKILL.md @@ -1,7 +1,7 @@ --- name: sdl-api author: Prithvi Moses -description: Use whenever the user wants to read data and manage configuration through the SentinelOne Singularity Data Lake (SDL) API: run queries or manage configuration files (parsers, dashboards, alerts, lookups, datatables) on a Scalyr/SDL/XDR tenant. Trigger on "SDL", "SDL API", "Singularity Data Lake", "Scalyr", "DataSet", "xdr.us1.sentinelone.net" or any "*.sentinelone.net/api/*" URL, and on the method names "query", "powerQuery", "facetQuery", "timeseriesQuery", "numericQuery", "getFile", "putFile", "listFiles". Also trigger on tasks like "run a powerQuery", "list configuration files", "edit my parser via API", "deploy a dashboard JSON", "compute the rate of failures over time", or anything involving SDL Bearer-token auth or the S1-Scope header. Wraps every SDL method with a Python client and CLI. +description: Use whenever the user wants to read data and manage configuration through the SentinelOne Singularity Data Lake (SDL) API: run queries or manage configuration files (parsers, dashboards, alerts, lookups, datatables) on a Scalyr/SDL/XDR tenant. Trigger on "SDL", "SDL API", "Singularity Data Lake", "Scalyr", "DataSet", or any "*.sentinelone.net/sdl/api/*" URL, and on the method names "query", "powerQuery", "facetQuery", "timeseriesQuery", "numericQuery", "getFile", "putFile", "listFiles". Also trigger on tasks like "run a powerQuery", "list configuration files", "edit my parser via API", "deploy a dashboard JSON", "compute the rate of failures over time", or anything involving SDL Bearer-token auth or the S1-Scope header. Wraps every SDL method with a Python client and CLI. --- # SentinelOne SDL API @@ -107,7 +107,7 @@ json.dump(schemas, open(out, "w"), indent=2) **Direct MCP tools bypass sandbox proxy entirely.** -The Cowork sandboxed shell blocks all outbound HTTPS to `xdr.us1.sentinelone.net`. Use the +The Cowork sandboxed shell blocks all outbound HTTPS to `*.sentinelone.net`. Use the s1-secops-mcp MCP tools instead, which run locally and bypass the proxy: | Operation | s1-secops-mcp tool | @@ -115,7 +115,7 @@ s1-secops-mcp MCP tools instead, which run locally and bypass the proxy: | PowerQuery | `mcp__s1-secops-mcp__powerquery_run` or `mcp__s1-secops-mcp__powerquery_schema_discover` | | `put_file` / `get_file` / `list_files` | `mcp__s1-secops-mcp__sdl_put_file`, `mcp__s1-secops-mcp__sdl_get_file`, `mcp__s1-secops-mcp__sdl_list_files` | -All of these tools run on your local machine and make direct HTTPS calls to `xdr.us1.sentinelone.net` +All of these tools run on your local machine and make direct HTTPS calls to the console host without sandbox proxy interference. No fallback or workaround needed. ```python diff --git a/plugins/s1-secops-skills/skills/sdl-dashboard/references/lessons-learned.md b/plugins/s1-secops-skills/skills/sdl-dashboard/references/lessons-learned.md index 21d2fb9..f89885b 100644 --- a/plugins/s1-secops-skills/skills/sdl-dashboard/references/lessons-learned.md +++ b/plugins/s1-secops-skills/skills/sdl-dashboard/references/lessons-learned.md @@ -363,7 +363,7 @@ End of document. Treat this file as a living artefact: append new gotchas as the These tools run locally and bypass the sandbox proxy entirely. Do not fall back to any other approach. -An earlier attempt at schema discovery in the same session ran inside the sandboxed Bash shell, which blocks all outbound HTTPS to `xdr.us1.sentinelone.net`. The V1 query calls returned a proxy error. Because the error was not recognized as a sandbox-specific block, the empty output was interpreted as the source having no useful fields, and a plausible-looking but entirely fabricated field list was deployed into the GRC dashboard panels. +An earlier attempt at schema discovery in the same session ran inside the sandboxed Bash shell, which blocks all outbound HTTPS to `*.sentinelone.net`. The V1 query calls returned a proxy error. Because the error was not recognized as a sandbox-specific block, the empty output was interpreted as the source having no useful fields, and a plausible-looking but entirely fabricated field list was deployed into the GRC dashboard panels. The fabrication was only caught when the user asked to re-verify the schemas, at which point the operation was re-run using the s1-secops-mcp tools and returned the real data: 126 fields for `asset`, 41 fields for `ActivityFeed`. diff --git a/plugins/s1-secops-skills/skills/sdl-solutions/assets/rba_collector.workflow.template.json b/plugins/s1-secops-skills/skills/sdl-solutions/assets/rba_collector.workflow.template.json index 5d801c1..d624bf4 100644 --- a/plugins/s1-secops-skills/skills/sdl-solutions/assets/rba_collector.workflow.template.json +++ b/plugins/s1-secops-skills/skills/sdl-solutions/assets/rba_collector.workflow.template.json @@ -1,5 +1,5 @@ { - "_comment": "RBA RISK COLLECTOR (tenant-validated 2026-06-25). Scheduled HA flow: runs RBA contributor(s) via the SYNCHRONOUS SDL PowerQuery endpoint ({{S1_CONSOLE_URL}}/sdl/api/powerQuery on the xdr/SDL host, e.g. https://xdr.us1.sentinelone.net/api/powerQuery; NOT {{Connection.url}}/sdl/api/powerQuery, which returns an error and was the collector's original bug, tenant-confirmed 2026-07-06) which returns body.columns + body.values in one call, no async poll, maps rows to named objects (MAP_TABLE), shapes them to NDJSON risk events (JQ tojson, which safely escapes command-line quotes/backslashes), and publishes them into dataSource.name='risk'. DEPLOY ORDER (mandatory, the SDL connection CANNOT be bound via API): (1) import via POST /web/api/v2.1/hyper-automate/api/public/workflow-import-export/import?accountIds={{ACCOUNT_ID}} body {data:}; (2) publish to Shared Draft: POST /web/api/v2.1/hyper-automate/api/v1/workflows/{id}/publish?accountIds={{ACCOUNT_ID}} (bodyless, 204); (3) PROMPT the user to bind the 'SentinelOne SDL' (Bearer) connection on BOTH http_request actions in the console; (4) after confirmation, activate: POST /web/api/v2.1/hyper-automate/api/v1/workflows/{id}/{version_id}/activation?accountIds={{ACCOUNT_ID}} (204); (5) run-now to test: POST /web/api/v2.1/hyper-automate/api/public/workflow-execution/manual/{id}/{version_id}?accountIds={{ACCOUNT_ID}}, then poll GET .../workflow-execution/{execution_id} until state=Completed (validated: 6/6 actions, ~2.9s, no error_actions). The example query below is the suspicious_powershell_flags contributor; production unions all contributors from rba_contributors.json. Schedule is daily 02:00 UTC for safe import; set hourly in the console for production RBA and match the query startTime to the interval. Both HTTP actions: use_authentication_data=true, bound to 'SentinelOne SDL'.", + "_comment": "RBA RISK COLLECTOR (tenant-validated 2026-06-25). Scheduled HA flow: runs RBA contributor(s) via the SYNCHRONOUS SDL PowerQuery endpoint ({{S1_CONSOLE_URL}}/sdl/api/powerQuery on the console host; NOT {{Connection.url}}/sdl/api/powerQuery, which returns an error and was the collector's original bug, tenant-confirmed 2026-07-06) which returns body.columns + body.values in one call, no async poll, maps rows to named objects (MAP_TABLE), shapes them to NDJSON risk events (JQ tojson, which safely escapes command-line quotes/backslashes), and publishes them into dataSource.name='risk'. DEPLOY ORDER (mandatory, the SDL connection CANNOT be bound via API): (1) import via POST /web/api/v2.1/hyper-automate/api/public/workflow-import-export/import?accountIds={{ACCOUNT_ID}} body {data:}; (2) publish to Shared Draft: POST /web/api/v2.1/hyper-automate/api/v1/workflows/{id}/publish?accountIds={{ACCOUNT_ID}} (bodyless, 204); (3) PROMPT the user to bind the 'SentinelOne SDL' (Bearer) connection on BOTH http_request actions in the console; (4) after confirmation, activate: POST /web/api/v2.1/hyper-automate/api/v1/workflows/{id}/{version_id}/activation?accountIds={{ACCOUNT_ID}} (204); (5) run-now to test: POST /web/api/v2.1/hyper-automate/api/public/workflow-execution/manual/{id}/{version_id}?accountIds={{ACCOUNT_ID}}, then poll GET .../workflow-execution/{execution_id} until state=Completed (validated: 6/6 actions, ~2.9s, no error_actions). The example query below is the suspicious_powershell_flags contributor; production unions all contributors from rba_contributors.json. Schedule is daily 02:00 UTC for safe import; set hourly in the console for production RBA and match the query startTime to the interval. Both HTTP actions: use_authentication_data=true, bound to 'SentinelOne SDL'.", "name": "{{PREFIX}} - RBA Risk Collector", "description": "RBA collector: runs contributors via sync SDL PowerQuery, applies risk-factor multipliers, and publishes risk events into dataSource.name='risk'. Bind 'SentinelOne SDL' (Bearer) on both HTTP actions, then activate.", "actions": [