Skill v1.0.0
currentLLM-judged scan90/100version: "1.0.0" name: sdl-solutions author: Prithvi Moses <prithvi.moses@sentinelone.com> description: "Deploy packaged, repeatable SentinelOne Singularity Data Lake (SDL) solutions into a site from one prompt. Catalog: (1) data source onboarding (raw to OCSF, enrichment, dashboard, MITRE detections, threat response); (2) asset enrichment; (3) UEBA anomaly detection; (4) per-device ingest health; (5) detection exclusions; (6) Risk-Based Alerting; (7) Detection as Code (rules as TOML in Git, synced by CI); (8) alert noise reduction; (9) custom detections with MITRE mapping (watchdog alert carrying ATT&CK, since STAR rules cannot); (10) query slicing (long-window PowerQuery as parallel time slices, merged). Triggers: 'onboard a source', 'deploy UEBA/ingest health', 'add a detection exclusion', 'deploy RBA', 'detection as code', 'reduce alert noise', 'map my custom detection to MITRE', 'custom alerts have no MITRE', 'this query is slow', 'run this over 30 days'. NOT for one-off queries or standalone parser authoring."
SentinelOne SDL Solutions
<!-- CONFIG-FILE-ADDRESSING v1 -->
SDL config files: address by `udoId`, and do not trust a REST listing.RESTlistFiles/getFilecannot see udoId-addressed/dashboards/files, sogetFilereturns404on a dashboard the console is displaying and the listing under-reports (measured onone tenant: REST 8, GraphQL 17, console 48 files). **If a listing disagrees with what the UIshows, the listing is wrong until proven otherwise**, change read path before concluding theobject is missing or the token lacks scope. Use the GraphQLconfigFiles/configFilesurface.A name-addressedaddConfigFileto/dashboards/creates a duplicate instead of updating;address dashboards byudoIdwithexpectedVersion.contentis HJSON, not JSON.S1-Scopechanges which files exist as far as the caller can tell.Full detail: `sdl-api/references/config-file-graphql.md`
This skill packages repeatable SDL solutions and deploys them into a specific customer environment from a short set of prompts. It is an orchestration layer: it does not reimplement PowerQuery, parser, SDL API, or Hyperautomation mechanics. Instead it collects the customer parameters, renders the solution's templates, previews the result, deploys through the primitive skills, and validates.
Use this skill when the user wants to deploy or tailor a whole solution. For a single query, parser, dashboard, or workflow, use the matching primitive skill directly.
Solution catalog
| Solution | What it does | Playbook | |||
|---|---|---|---|---|---|
| Data source onboarding | Take a raw log stream already reaching the tenant and operationalise it end to end from one short prompt: locate the source, normalise it to OCSF, enrich it with device/user context, then build a dashboard, MITRE-mapped detections, and a Hyperautomation flow | references/data-source-onboarding.md | |||
| Asset enrichment | Enrich ingested raw logs with device and user context (OS, IP, agent UUID, AD groups, SID, criticality, risk factors) from the Asset Inventory, at ingest or at query time | references/asset-enrichment.md | |||
| UEBA behavioural anomaly detection | Baseline ANY security or non-security signal per (action, principal) over a chosen window and detect deviations. Ten behavioural detections: core SPIKE, DROP, SILENT, NEW-BEHAVIOR plus advanced OFF-HOURS, FAN-OUT, RATIO, VELOCITY, PEER-GROUP, DORMANT; plus two location detections GEO-NEW and IMPOSSIBLE-TRAVEL when a Location field is set; plus Risk-Based Alerting (RBA) that consolidates alerts into one cumulative per-entity risk score. The source is matched by dataSource.name or serverHost, and the action can be a composite of 2-3 fields. A Sensitivity knob switches volume scoring between Standard (z-score) and Robust (percentile p95/p05, default); a use-case selector (account takeover, account takeover geo, brute force, insider / data exfil, lateral movement, privilege abuse, service/feed health, all, custom) presets detections and method. One-click production deploy: baseline lookups + scheduled PowerQuery rules + Hyperautomation watchdogs + staggered per-baseline nightly refresh + a daily failure-notifier + a review dashboard. The s1-ueba-deployer is the source of truth | references/ueba-anomaly-detection.md | |||
| Ingest health monitoring (per device) | Per-device ingest health: anomaly detection on a 7-day hour-of-day seasonal baseline refreshed daily, detecting when a specific firewall, endpoint, or server spikes, drops, lags (p95), or goes silent, plus parser drift. Deploys per-device baseline lookups, scheduled PowerQuery detections, an ingest-loss watchdog flow, a 5-tab dashboard, an email-notification flow for every failure, and an editable source-exclusions lookup and a device-level config lookup (source level by default, per-device opt-in), with unified Spike/Drop/Lag rules that tag each alert source or device; Parser Drift is optional and tuned per environment | references/ingest-health-monitoring.md | |||
| Detection exclusions (single-event, correlation, or scheduled) | Suppress known-good noise in a STAR Custom Detection rule over a third-party or EDR SDL source. Ask the user the rule type first (Step 0): a single-event rule (queryType: events) or a correlation rule (queryType: correlation) hardcodes the exclusion as an inline AND NOT (<field> in:anycase (...)) negative list in a boolean S1QL body (correlation appends it to each sub-query in correlationParams), fires per event / on multi-event thresholds, and supports mitigation; or a scheduled PowerQuery detection (queryType: scheduled) loads a CSV exclusion list as an SDL lookup table and omits matching rows via an anti-join (`\ | lookup ... \ | filter <col> = null`), aggregates, and ships an effectiveness dashboard. Single-event and correlation deploy just the rule; scheduled deploys the lookup table, the rule, an optional source-of-truth refresh flow, and the dashboard | references/custom-detection-exclusions.md | |
| Risk-Based Alerting (RBA) | Noisy-but-interesting observations are published as low-noise risk events into a risk index instead of alerting individually; risk accumulates per object (user / host), amplified by asset-derived risk factors; one high-fidelity alert fires only when a 24h cumulative score or 7d distinct-MITRE-tactic threshold is crossed, giving a contextualised story instead of disconnected alerts. Deploys contributors, a risk-factor table, a scheduled collector flow (publish as Shared Draft, then prompt the user to bind the "SentinelOne SDL" connection, then activate, the connection cannot be bound via API), four incident rules (user/host x score/tactics), and a dashboard. This is the heavyweight risk-index model (a dedicated risk index + collector + contributors + risk factors). For a lightweight alternative that scores the existing SentinelOne alert stream in place against an editable RiskWeights + AssetWatchlist table and fires one watchdog per entity, use the RBA built into the UEBA solution (the s1-ueba-deployer), see references/ueba-anomaly-detection.md | references/risk-based-alerting.md | |||
| Detection as Code (DaC) | Stand up a Git + CI pipeline where detection engineers author rules as TOML files, a pull request triggers validation and four-eyes review, and a merge syncs the changed rules to the SentinelOne Custom Detection Rule API. Scaffolds a starter repo (per-target-system folders, CODEOWNERS, branch-protection guidance), seeds working examples of all three rule types (single-event events, correlation, scheduled PowerQuery), and ships a zero-dependency TOML-to-API sync engine with idempotent create-or-update plus lint-on-PR and sync-on-merge CI for GitHub Actions, GitLab CI, and Azure Pipelines. Unlike the other solutions, DaC sets up a workflow OUTSIDE the tenant that pushes rules in | references/detection-as-code.md | |||
| Custom detections with MITRE mapping | Solution for custom detections to carry MITRE mapping. A Custom Detection (STAR) rule has no MITRE field (the API rejects mitre with 400 Unknown field) and its alerts reach UAM with mitreTactics empty. This solution renders a small JSON rule spec (name, severity, PowerQuery, lookback, interval, MITRE tactic/technique list) into a scheduled Hyperautomation watchdog that runs the query through the LRQ API and posts the UAM alert with attacks[] on each finding_info.related_events[] entry, so the alert carries mitreTactics / mitreTechniques like a library-rule alert. Converts an existing scheduled STAR rule with --from-rule. Ships a renderer with validation and example specs | references/custom-detection-mitre-mapping.md | |||
| Query slicing | Run a long-window PowerQuery fast: split the time range into slices, run them in parallel through the LRQ API (25 calls/s per token, 15 in flight, launch-429 backoff, every query cancelled, slow slices split in two) and merge the results client-side with explicit sum / min / max rules that refuse non-additive columns. Measured: a 30-day aggregate in about 5 s as 15 two-day slices versus 21 to 40 s as one query, identical totals. Primary path: the powerquery_run MCP tool with slices and merge; scripts/lrq_sliced.py is the zero-dependency host-only runner that deployers and scripts vendor as is | references/query-slicing.md | |||
| Alert noise reduction | Find the (source, signature) pairs flooding the alert queue, separate ingested and already-actioned noise (block/drop/sinkhole/reset) from real S1 detections, then recommend an ingestion-severity filter (a console setting on the connector), deploy an auto-resolve Hyperautomation flow that closes already-mitigated alerts with a note, optionally preserve signal-worthy categories (e.g. C2/DGA) as one correlation rule, and ship a noise-vs-signal dashboard. All product/source/signature/action values are discovered live; nothing is hardcoded | references/alert-noise-reduction.md |
More solutions are added under references/<solution>.md plus templates under assets/. See "Adding a new solution" below.
How a deployment runs (always follow this loop)
- Pick the solution. If the user named it, use it. Otherwise show the catalog and ask which one.
- Collect parameters with simple prompts. Ask only what the playbook needs, one compact question set, with sensible defaults pre-filled. Never start deploying before parameters are confirmed. Each playbook lists its parameters and defaults.
- Confirm the environment. Resolve the target site name to a siteId (fuzzy match, console site names can contain spaces). Confirm the console/tenant. Read existing config versions before any overwrite.
- Render and preview. Fill the templates in
assets/with the parameters and show the user the final config (queries, parser, workflow) and the projected enriched record BEFORE deploying. This is a dry run. - Deploy in dependency order through the primitive skills (see each playbook for the exact order). Typical order: build lookup tables, then parser or lookup guidance, then refresh flow.
- Validate with a real ingest and query, and report what populated. Use
metadata.versionas the propagation canary for parser changes. - Test end to end with run-now, then prompt the user. For any solution with HA flows, trigger each flow immediately with
POST /web/api/v2.1/hyper-automate/api/public/workflow-execution/manual/{id}/{version}?accountIds=<acct>(works on scheduled-trigger flows once active), pollGET .../workflow-execution/{exec_id}untilstateisCompletedwitherror_actions: []andexecuted_actions== the action count, and confirm the downstream effect (tables written, dashboard renders, a detection alert present). An import is NOT complete until the flow is published to a Shared Draft: treatha_import_workflowand publish as ONE atomic step, publish in the SAME step as the import, never as a follow-up. Imported flows land as PRIVATE DRAFTS owned by the API token's user (invisible in the console to the person who asked), so IMMEDIATELY after eachha_import_workflowpublish it to a Shared Draft:POST /web/api/v2.1/hyper-automate/api/v1/workflows/{id}/publish?siteIds=<id>(bodyless{}, returns 204; useaccountIds=<acct>for account-scoped flows). A published flow stays inactive until its connection is bound and it is activated, so always end a deployment by prompting the user to bind/activate and run this E2E check (offer to run it for them once active). - Summarize the deployed artifacts (paths, IDs, site) and hand off the rendered config files.
Prove a detection by its alert, not by a query match. Ingest a positive and a negative case per detection with principals unique to the run, add the run tag to the rule's initial filter, and assert the positive appears and the negative does not. Then deploy and wait for the UAM alert: it lands about 8 minutes after detectedAt, and scheduled rules evaluate on staggered offsets within their interval. Read UAM unfiltered and narrow client-side (a server-side filter the API accepts and ignores reads as zero alerts). A rule created but left as Draft never alerts while the create call still succeeds, so read each rule's status (and statusReason) after deploy and report any that are not Active. In the NZISM deployer this caught one rule missing its key command at query level and 21 of 26 rules left as Draft at alert level, both invisible to a query-only test (reference implementation: tools/nzism_detection_harness.py in the s1-nzism-deployer repo, not shipped with this plugin).
Read-only mode. From 1.5.5, s1-secops-mcp is read-only by default (S1_READ_ONLY unset or true), and step 5 writes through sdl_put_file, sdl_create_dashboard, ha_import_workflow, hec_ingest, powerquery_run with | savelookup, and s1_api_post (rules, publish, run-now). Check the mode at step 3, before you render or deploy anything: read mode.readOnly from the sentinelone://credentials-status resource, or the server's initialize instructions. A half-built deployment is worse than none.
- If a write tool returns "s1-secops-mcp is in read-only mode (S1_READ_ONLY).", stop. Do not retry, and do not route around it with another tool (
s1_api_postto a different endpoint, purple-mcppowerquerywith| savelookup, a hand-built GraphQL mutation). - Tell the user which action was refused and how to enable write: Docker launcher
s1-secops-mcp-launch.sh install --read-write(Windows-ReadWrite), then restart Claude Desktop;.mcpbextension: turn off "Read-only mode (recommended)"; Node install:"S1_READ_ONLY": "false"in the server'senvblock. Detail:docs/read-only.mdin the source repo (not shipped). - Offer every rendered artifact (parser, lookup CSV, dashboard JSON, workflow JSON, rule body) as a local file via
outputFileor the Write tool so nothing is lost. - Never enable write on the user's behalf by editing their MCP client config.
Keep prompts simple and few. Prefer defaults the user can accept with one word over long forms.
Dependencies (load as needed)
This skill orchestrates the SentinelOne primitive skills. Load the ones a playbook calls for. Every tenant call goes through the s1-secops-mcp MCP tools, which run on the user's machine and read credentials from environment variables or the OS keychain; the Cowork sandbox cannot reach *.sentinelone.net, so Python scripts that call the tenant are host-only (Claude Code or a terminal). If a tool reports a missing credential, ask the user to run s1-secops-mcp setup.
powerqueryfordatasource+savelookupqueries, run withpowerquery_run. Thereferences/datasource-command.mdthere is the source of truth for the assets datasource.sdl-api(or thes1-secops-mcptoolssdl_put_file,sdl_get_file,hec_ingest) to deploy config files and ingest test data. Config-file writes use the console API token;hec_ingestneeds an SDL Log Write Key inS1_HEC_TOKENinstead, and because that key is minted for one account or site it also fixes where test data lands, which no scope argument overrides.sdl-log-parserfor parser authoring and the computeFields lookup pattern.hyperautomationfor the scheduled refresh workflow.mgmt-console-api(ors1-secops-mcps1_api_*) for site lookup and scoped workflow import / activate / deactivate.
Conventions
- Naming prefix. Every artifact a deployment creates is prefixed with a customer or solution code so multiple deployments coexist cleanly: tables
<prefix>IdentityLookup/<prefix>EndpointLookup, parser<prefix>_enrich, workflow<prefix> Asset Lookups. - Scope by site. Deploy to the customer's site. Resolve the name to a siteId and pass it on every scoped call. The HA import, activation, and deactivation all require the scope parameter.
- Empty suppression. Inventory empties (for example
riskFactorsas the string"[]") are converted to null in the savelookup so enrichment never writes an empty field. - Preview before deploy. Always show rendered config and an example enriched record first.
- Idempotence. Read the current version of any SDL config file before overwriting, and pass it as the expected version. Hyperautomation import always creates a new workflow, so to update one, replace it rather than re-import blindly.
- Dashboards: create by name once, update by udoId. Only
/dashboards/files carry audoId; everything else (/lookups/,/datatables/,/logParsers/,/automaticLookups) is name-addressed. A name-addressed write to an existing dashboard creates a duplicate instead of updating it, so record theudoIdreturned by the initial create and address the dashboard byudoIdon every later write. Solutions are re-runnable, so a name-addressed re-deploy silently doubles the dashboard on each run. - Asset mapping is built in. Any parser or detection a solution creates must carry the minimum attributes that let an alert bind its Target Asset, so alerts are not "Unknown Device". The endpoint lookup captures
device_agentid(the numeric console agent id); the parser stampsdevice.uid=device_agentidplus an endpointclass_uid; and scheduled detections setentityMappingson the device identity columns (device_host/device_agentid/device_agentuuid). Binding reconcilesdevice.uidagainst the live Asset Inventory, so a real enrolled agent id is required (a fabricated id stays Unknown Device). The tested binding matrix and the minimum set live inpowerquery/references/detection-rules.md.
Reference files
references/data-source-onboarding.md- the onboarding playbook: the one-line-prompt UX, the parser-attribute editability rule for locating a source, parser create/update to OCSF plus asset enrichment, the 5-minute propagation wait, the parallel dashboard and MITRE-mapped detection build with asset-context columns, and the Hyperautomation SOC threat-response playbook (alert-triggered, VirusTotal-gated containment) with the single deploy-location question. Read this when onboarding a new data source.references/asset-enrichment.md- the asset enrichment playbook: parameters and defaults, the deployment-mode prompt (ingest-time parser vs query-time lookup vs automatic lookup; ingest-time requires the parser deployed in AI SIEM), the savelookup table builders, the parser, the validation steps, the Hyperautomation refresh flow, and the gotchas. Read this when deploying or tailoring asset enrichment.references/custom-detection-mitre-mapping.md- the custom-detection MITRE playbook: the rule-spec format, rendering withscripts/render_mitre_watchdog.py(or--from-ruleto convert a scheduled STAR rule), the import / publish / activate / run-now order, validation queries, and gotchas (finding_info.attacksis ignored, tactic ids not names, one alert per run, no suppression). Read this when a custom detection needs a queryable MITRE ATT&CK mapping.references/query-slicing.md- the query slicing playbook: measured LRQ limits and slicing timings, defaults per window, which aggregates merge (count / sum / min / max) and which do not (estimate_distinct, avg, percentiles, top K), running it withpowerquery_run(slices+merge) or the host-onlyscripts/lrq_sliced.py, validation and gotchas. Read this before writing any multi-day query loop, report collector or baseline builder.references/detection-as-code.md- the Detection-as-Code playbook: the one-line-prompt UX, prerequisites (Git repo, CI engine, API-token secret), scaffolding the starter repo, the manual repo controls (branch protection, RBAC, CODEOWNERS), wiring lint-on-PR and sync-on-merge CI for GitHub/GitLab/Azure, the TOML rule format for all three rule types (events, correlation, scheduled), the dry-run-then-deploy flow with idempotent create-or-update, the monitor-and-refine loop, and the confirmed Custom Detection API gotchas. Read this when setting up detection as code or automating detection-rule sync from Git.
Templates
assets/ holds the parameterized templates a playbook renders. Tokens use {{NAME}}:
assets/savelookup_identity.pq- identity lookup table builderassets/savelookup_endpoint.pq- endpoint lookup table builderassets/parser.template.json- the enrichment parserassets/refresh_workflow.template.json- the Hyperautomation refresh workflowassets/onboarding_detection.template.json- STAR scheduled PowerQuery detection-rule envelope (onboarding)assets/threat_response_workflow.template.json- Hyperautomation SOC threat-response playbook (alert trigger to VirusTotal enrich to VT-gated containment: IOC block + endpoint quarantine, then note + notify) for an onboarded source's detectionsassets/onboarding_dashboard.template.json- starter tabbed dashboard skeleton for an onboarded sourceassets/exclusion_list_assets.csv.template- asset exclusion list (IP / CIDR, keyedcidr =:cidr <ip field>)assets/exclusion_list_custom.csv.template- custom-value exclusion list (domain / user / value, keyedvalue =:anycase <field>)assets/exclusion_detection_single_event.template.json- STAR single-event rule (queryType: events) with the exclusion as an inline hardcodedAND NOT (<field> in:anycase (...))negative list indata.s1ql(no lookup, no dashboard; double backslashes in the JSON so the engine receives one)assets/exclusion_detection_correlation.template.json- STAR correlation rule (queryType: correlation,queryLang: 2.0,s1qlempty) with the exclusion as an inline hardcodedAND NOT (<field> in:anycase (...))negative list appended to each sub-query indata.correlationParams(no lookup, no dashboard; same backslash doubling; tenant-validated 2026-07-01)assets/exclusion_detection.template.json- STAR scheduled PowerQuery rule wrapping a base detection with the lookup anti-join (chain multiple lists with distinctexcl_*join vars)assets/exclusion_dashboard.template.json- exclusion-effectiveness dashboard (excluded vs kept, over time, by list / reason / value, plus a post-exclusion threat tab)assets/exclusion_refresh_workflow.template.json- optional nightly rebuild of a source-of-truth (savelookup) exclusion listassets/rba_contributors.json- RBA risk model: contributor definitions (noisy observations to score, each with base score + MITRE tag + risk-object/threat-object fields)assets/rba_risk_factors.csv.template- RBA per-object risk-factor multipliers (the Risk Factor Editor), built from the Asset Inventory plus hand-edited overridesassets/rba_collector.workflow.template.json- RBA scheduled HA collector: sync SDL PowerQuery to MAP_TABLE to JQ NDJSON to publish into theriskindex (deploy as Shared Draft, prompt to bind 'SentinelOne SDL', then activate)assets/rba_incident_cumulative_score.template.json- RBA STAR scheduled incident rule: 24h cumulative risk score per object >= threshold (render per user / host)assets/rba_incident_multitactic.template.json- RBA STAR scheduled incident rule: 7d distinct MITRE tactics per object >= threshold (render per user / host)assets/rba_dashboard.template.json- RBA dashboard (risk leaderboard, score over time, MITRE / contributor / threat-object breakdowns, contributing-events timeline)assets/rba_risk_register.savelookup.pq- OPTIONAL persisted decayed risk register (daily savelookup; complements, does not replace, the windowed incident rules; tokens{{PREFIX}},{{DECAY}})assets/rba_console/- OPTIONAL local demo console: a zero-dependency Python proxy (server.py) + a 4-tab HTML UI (index.html) for live demos (talk track, deployed artefacts, live leaderboard, read/write risk-factor editor). ReadsS1_CONSOLE_URL/S1_CONSOLE_API_TOKENfrom the environment or the OS keychain on the presenter's laptop; render{{ACCOUNT_NAME}}/{{ACCOUNT_ID}}/{{PREFIX}}/{{RULE_*_ID}}tokens. Seeassets/rba_console/README.mdassets/mitre_watchdog.workflow.template.json- custom detection with MITRE mapping: scheduled HA watchdog (LRQ launch, poll, summarise, POST one S1 Security Alert withattacks[]on the inline indicator). Render it withscripts/render_mitre_watchdog.py, never by hand: the PowerQuery is escaped twice. Tokens{{PREFIX}},{{RULE_NAME}},{{RULE_DESCRIPTION}},{{PRODUCT_NAME}},{{PQ_QUERY}},{{LOOKBACK_HOURS}},{{INTERVAL_MINUTES}},{{SEVERITY_ID}},{{MITRE_ATTACKS_JSON}},{{HEC_URL}},{{ACCOUNT_ID}},{{SITE_ID}},{{SDL_INTEGRATION_ID}}assets/mitre_rule_specs/- example rule specs for the MITRE solution:encoded_powershell.json,windows_bruteforce.json,e2e_probe.json(synthetic end-to-end test)assets/ha_watchdog.workflow.template.json- the generic HA watchdog (no MITRE); seepowerquery/references/detection-rules.mdassets/detection-as-code-starter/- the whole Detection-as-Code repo scaffold (rendered into the user's Git repo, not a single tokenized file):scripts/dac_sync.py(zero-dependency TOML-to-API validate + convert + idempotent create-or-update engine),scripts/dac_lint.py(local lint / pre-commit),rule.schema.json(editor validation),detections/{endpoint,identity,cloud}/*.toml(working examples of the single-event, correlation, and scheduled rule types),.github/workflows/{lint,sync}.yml+.github/CODEOWNERS, andci/gitlab/.gitlab-ci.yml+ci/azure/azure-pipelines.yml. Render the[scope] siteand CODEOWNERS handles per customer. Seereferences/detection-as-code.md.
Common tokens: {{PREFIX}}, {{IDENTITY_TABLE}}, {{ENDPOINT_TABLE}}, {{PARSER_NAME}}, {{DATASOURCE_NAME}}, {{VENDOR}}, {{HOSTNAME_FIELD}}, {{USERNAME_FIELD}}, {{USERNAME_KEY}} (samAccountName or principalName), {{SCHEDULE_HOUR}}, {{SITE_ID}}, {{CONSOLE_HOST}}, {{ENDPOINT_CLASS_UID}} (OCSF class for the parser's class_uid; default 1007, must be an endpoint class 1xxx for events-rule asset auto-binding). Onboarding tokens: {{DETECTION_NAME}}, {{DETECTION_DESCRIPTION}}, {{MITRE_TACTIC}}, {{MITRE_TECHNIQUE}}, {{SEVERITY}}, {{PQ_BODY_ENDING_WITH_COLUMNS_PROJECTION}}, {{RENOTIFY_MINUTES}}, {{ENTITY_COL_1}}, {{ENTITY_COL_2}}, {{ENTITY_COL_3}} (entityMappings is capped at 3), {{SCOPE_KEY}} (accountIds/siteIds; MUST be accountIds for any detection rule whose PQ body reads a lookup table or datatable, because lookups/datatables are account-level objects and site-scoped creation of lookup-reading rules is invalid), {{SCOPE_ID}}, {{IP_SRC_FIELD}}, {{IP_DST_FIELD}}, {{PORT_FIELD}}, {{ACTION_FIELD}}, {{USER_FIELD}}, {{SOURCE_LABEL}}, {{ACCOUNT_ID}}, {{NOTIFY_WEBHOOK_URL}}, {{IOC_TTL_HOURS_NEG}}. The VirusTotal step uses the packaged VirusTotal integration action, so the API key lives in a Hyperautomation VirusTotal connection, never in the workflow JSON.
Adding a new solution
- Write
references/<solution>.mdas a self-contained playbook: parameters with defaults, render steps, deploy order through the primitives, validation, gotchas. - Add the rendered templates to
assets/. - Add a row to the Solution catalog table above and name the new solution in this skill's frontmatter description so it triggers.
- Keep each solution self-contained so the router can branch cleanly.