Notable changes per release. Earlier releases (v0.1.x – v0.2.x) carry their notes in the signed tag messages.
-
Mouse controls for
secopsctl config. Click any field to focus it, click Yes/No and Save/Cancel directly, or use the mouse wheel to move through a form taller than the terminal. Arrow and Tab navigation remain available. -
MCP large-output spill. Tool results larger than an inline threshold (64 KiB default,
SECOPS_MCP_SPILL_BYTESto tune) are streamed to a temporary file — bounded memory, no giant inline result for the client to reject — and the tool returns a JSON pointer with the path, size, a 1 KiB head preview, and guidance. Spill files are0600under$TMPDIR/secopsctl-mcp/and swept after 24 hours. -
entities auditcross-references watchlist membership for real. The audit lists every watchlist's entities via the documentedwatchlists/{id}:listEntitiessurface (new SDK methodListWatchlistEntities) and reports as coverage gaps only the high-risk entities on no watchlist. When an instance does not serve entity listing, the result degrades honestly:crossReferenced: falseplus a note, with every high-risk entity listed unchecked.
-
Config editing is safer and SIEM-only setup works. SOAR URL/AppKey now remain optional as documented; form and flag values receive the same whitespace normalization; malformed YAML is refused instead of overwritten; and hand-edited or future YAML keys survive a
secopsctl configrewrite. -
MCP
runrespects--flag=valueoutput flags. The server appended--jsonwhenever aruncommand set its format in equals form (e.g.--output=csv), which collided with the mutually-exclusive--jsonand failed the subprocess. Both--flag valueand--flag=valueforms are now detected. -
Full-code-review sweep. An adversarially-verified review of every package landed ~45 correctness fixes. SDK highlights: coverageDetails uses the project-number path form; ingest's get-or-create forwarder pins the v1beta forwarders version; pipeline IDs are URL-escaped;
ListErrorsapplies its time window (client-side) instead of ignoring it;omitemptyremoved from non-pointer scalars that droppedfalse/0on re-marshal; numeric BLOCK step types recognized end-to-end; a bare HTTP 400 is no longer retried as FAILED_PRECONDITION; save-drift detection no longer false-positives on identifier-only steps. CLI highlights:dashboards deletepreviews offline and honors--json; button/markdown edits restore the original tile when the re-add half of remove+add fails; reserved dashboard variable detection uses one comprehensive keyword set; saved-query--paramno longer corrupts prefix-sharing placeholders; guarded commands gained consistent banners,--jsonenvelopes, and flag exclusivity.
-
Pull redaction matches secret key names case-insensitively. A
Password/APIKeycasing variant now redacts the same as its lowercase form before anything is written to disk. -
Structure and dedup pass. Oversized command files split by topic (dashboards lint helpers,
soar job instance, integration configure/lifecycle/connector-def); wave-named test files renamed by feature; duplicate legacy SDK methods consolidated (GetSystemVersion/ListEnabledPlaybooks/ExportPlaybooktwins removed in favor of their kept counterparts); deadMintTokenandworkflowSummaryBodyremoved; one generic size-bounded batcher backs the data-table importers; all machine-readable output flows through one indented-JSON emitter; the retry/idempotency and request-id helpers both transports duplicated live once in the shared retry package; the tips and guides embed packages share one Markdown-walk implementation. -
One guard envelope for simple mutations.
guardedSIEMMutationand the newsoarGuardedMutationshare one core (LIVE banner naming the plane and action, standard dry-run/refuse/Done lines, a single structured--jsonresult), and 27 hand-rolled guard sites across the dashboards, data-access, and SOAR command families now use it. Commands whose success emits an API payload keep their richer envelopes deliberately. -
MCP subprocess streams split. Tool subprocesses no longer interleave stderr into the result: success returns stdout (falling back to stderr when stdout is empty), failure returns stderr plus the stdout head with the exit cause appended, capped at the inline threshold. Both exec paths (
runand typed tools) share one helper. -
MCP concurrency hardening. The cobra command tree is pre-sorted before concurrent dispatch begins (child slices sort in place on first access), and a failed response write now leaves a trace on stderr instead of being dropped silently.
- Concurrent MCP tool calls. The MCP server now dispatches
tools/callrequests in goroutines, so multiple long-running commands (UDM searches, pulls) execute in parallel as independent subprocesses. Metadata operations (initialize, tools/list, focus/unfocus) remain synchronous to preserve ordering. AnRWMutexguards the focused-tools map; a separate write mutex serializes stdout encoding.
-
Reposition as MCP server for Google SecOps. Docs homepage, SEO metadata, structured data, llms.txt, and OG tags now lead with "MCP server, CLI, and Go SDK" — three interfaces, one tool.
-
Dedicated MCP guide (
docs/guides/mcp.md). Setup instructions for Claude Code, Claude Desktop, and Cursor; discovery workflow; security model. -
Guides served as MCP resources. The 15 user-facing guides now travel inside the binary as
guide://resources alongside the existingtips://resources (32 total). -
Verb-first command descriptions. 23 noun-first
Shortdescriptions rewritten to start with imperative verbs for better MCP tool discovery. -
Server instructions enriched. Structured discovery flow (numbered steps), shell-style quoting guidance for the
runtool, JSON-output note.
-
integrations import --file <zip>. Import a custom integration ZIP (produced byintegrations scaffold+soar ide package-integration) into SecOps SOAR. Creates the integration and all action/job definitions with their Python scripts. Staging by default (--no-stagingfor production). Closes the scaffold → package → import → configure lifecycle with no UI step. -
soar.Client.CreateIntegrationSDK method (v1alpha POST on the SOAR host). Manifest parameter types are mapped to v1alpha enum values automatically (string→STRING, etc.).
- Playbook save: backfill missing step params. The SOAR save endpoint
returns HTTP 500 (errorCode 2000) when ACTION steps lack infrastructure
parameters introduced in a platform update (
AsyncActionTimeout,AsyncPollingInterval, and 7 others). Older playbooks pre-date these fields.coercePlaybookTypesnow detects missing params on each ACTION step and backfills them with their platform defaults before the save call. Existing params are never overwritten.
-
Audit user: UDM field paths. All 6 activity category queries used camelCase
emailAddressesinstead of the snake_caseemail_addressesrequired by the UDM query language, causing HTTP 400 on every query. -
MCP subprocess cwd. The MCP server subprocess inherited the server's cwd (home dir), so relative
--outpaths resolved to the wrong directory.mcp servenow accepts--project-dir(set bymcp install) and passes it ascmd.Dirto every subprocess. -
Parser activation retry.
push parsersnow checks the response body for FAILED_PRECONDITION (not just HTTP 400) and retries up to 6 times (~51s budget), covering SCC log types that need extra server-side processing time after validation passes.
- Doctor: parallel health checks. The SIEM pipeline (auth + reach) and SOAR probe now run concurrently, cutting wall-clock time roughly in half. A 403 on the SIEM reach check now surfaces a clear ADC permission hint instead of a generic connectivity message.
-
MCP: focus-first design. Server instructions and tool descriptions now steer agents toward
focus <group>(typed tools with validated schemas) as the primary interaction pattern;runis described as the escape hatch.usage <command>auto-loads the resolved tool as a callable typed tool (no separatefocuscall needed).runappends a one-line tip when a typed tool exists for the command. -
MCP: tool annotations. Every tool carries
readOnlyHint/destructiveHintannotations derived from the command classification, plus atitlewith the human-readable command path. Lets MCP clients auto-approve read-only tool calls.
- Push dry-run: surface resolved data directory. All push JSON
results now include
dir(the resolved absolute data directory) so an agent can see where the command looked.ensureDataDirreturns a warning on dry-run when the directory doesn't exist — surfaced aswarningin the JSON output instead of a silentcount: 0.
-
Playbook save: detect server-side drift (steps/relations dropped).
soar push playbooknow compares the submitted playbook against the server response by instanceName (stable across saves — identifiers are reassigned). If the server silently drops steps or relations, the command exits non-zero with the affected step names. Previously this was a stderr warning that still printed "Done." -
CreateManualCase: reject emptyassignedUser. The SOAR API requiresassignedUser(a username or@RoleName) but the swagger marks it nullable. An empty value causes a 400 with an unclear validation error. The SDK now rejects it early with a clear message before making the API call.
cases playbook-errors <id>: inspect playbook execution errors. Walks every alert's playbook(s) in a case, fetches the workflow instance summary, and shows faulted steps with full error messages. Recurses into nested BLOCK playbooks. Embedded JSON in error messages is auto-detected and pretty-printed. Handles both legacy integer and modern string status enums.--alertscopes to one alert;--jsonemits structured output.
- MCP: focus output hints the callable tool name prefix. The focused
tool list now shows
(callable as mcp__<server>__<name>)so agents know the full tool name to use.
- Playbook lint: detect step relation cycles.
playbooks lintnow detects cycles in the step relation graph ([error] cycle) — a playbook with a cycle may loop infinitely at runtime.
- Playbook lint: detect dangling step relations and orphan steps.
playbooks lintnow flags orphanedstepsRelationsentries whosefromSteportoStepreferences a step that no longer exists ([error] dangling-relation— causes console 500 on edit), and steps with no incoming relation ([warning] orphan-step— disconnected from the flow). When dangling relations are found, the fix instructions name the affected indices and orphan steps to reconnect.
- MCP:
runrespects quoted arguments. Therunmeta-tool split on whitespace, breaking flag values with spaces (e.g.--name "SOC Agents - Auto-Trigger"). Now uses a shell-style tokenizer that respects single and double quotes.
- MCP: hyphenated tool names now callable. Focused tool names like
playbooks_debug-step-datacontained hyphens that MCP clients normalize to underscores — the server rejected the underscore form. Tool names are now all-underscore (playbooks_debug_step_data); reverse resolution to cobra commands already handled this. - Playbook run/rerun: auto-resolve alertGroupIdentifier from the case.
playbooks runandplaybooks rerunnow fetch the case detail and extract the opaquealertGroupIdentifierwhen--alert-groupis omitted. Previously the API 500'd because the required identifier was missing or callers passed the human-readablealert.identifier(fromcases get) instead of the internal value fromalerts[].additionalProperties.alertGroupIdentifier.
- MCP: progressive discovery replaces flat tool list. Initial
tools/listnow returns 5 meta-tools (run,help,usage,focus,unfocus) instead of ~50+ individual tools. Agents discover commands viahelp, inspect one command's schema viausage, execute viarun, or load a full group's typed tools viafocus/unfocus(dynamiclistChangednotifications). - MCP: grouped command catalog.
helpreturns a compact catalog (~4.5K chars) with group name, description, and command counts. Groups with sub-commands (soar, ingest, playbooks, cases, dashboards, integrations, rules, data-access) auto-show a sub-group catalog; drill deeper with dotted notation (e.g.help group=soar.push). - MCP: server instructions. The
initializeresponse includes instructions guiding agents through the help → usage → run discovery flow.
commandsaccepts a group argument.commands <group>drills into one group;commands(no arg) shows the grouped catalog. Drill-down JSON drops flags (agents useusageinstead) — worst case 21K → 4.7K chars.
- MCP argument schemas. Flag-only commands no longer emit a bogus
argsproperty. ThestripFlagHintspipeline (balanced-bracket scanner + bare-flag regex + residue cleaner) correctly isolates genuine positional args from flag documentation in cobraUsestrings — fixes ~85 commands. - Command descriptions. All
Shortstrings rewritten verb-first for cleaner MCP tool descriptions,commands --jsoncatalog, and auto-generated docs. Normalized 16GUARDED:prefixes toMUTATING (guarded):.
parsers deactivate— revert a custom parser to the prebuilt version (auto-selects the ACTIVE CUSTOM parser).parsers activate— activate a parser by log-type alone (auto-selects the latest INACTIVE CUSTOM version).parsers versions— now shows validation stage, version, and release stage columns.
- Parser create retries activation on
FAILED_PRECONDITIONand handlesVALIDATION_SKIPPED/INTERNAL_ERRORstages. - Dashboard
charts addbinds new charts toGlobalTimeFiltervia dashboard PATCH after creation. - Playbook save coerces integer step types to string enums and warns when SOAR silently drops steps.
- Playbooks
createstrips identity fields to prevent overwriting source. - Search view shows elapsed-time progress during blocking fetch.
- Removed
catalog-siem.md/catalog-soar.mddetail files (duplicated auto-generated command docs); compact status matrix incatalog.mdstays.
playbooks attachalias.playbooks attachis now an alias forplaybooks run, matching the console's "Attach playbooks manually" action.playbooks run/attachname→UUID auto-resolution.--namenow auto-resolves theoriginalWorkflowDefinitionIdentifier(same two-step resolution asrerun), sends bothwfNameand the uuid, and includesinputParameters: []— matching the console's request shape exactly. The--automaticflag is removed (console does not use it).
playbooks rerun500 fix. The rerun command was sendingwfName(display name) but the API requiresoriginalWorkflowDefinitionIdentifier(the immutable original playbook uuid).--namenow auto-resolves via list → get → extractoriginalPlaybookIdentifier. Dropped the unusedshouldRunAutomaticfield and--automaticflag from the rerun body.
Progressive tool disclosure for the MCP server — reduces the initial tool listing from 361 tools / 207K chars to 36 tools / 41K chars.
- MCP progressive disclosure.
mcp servenow declareslistChangedcapability and uses a three-tier tool hierarchy. Tier 0: standalone commands and promoted high-use tools (search_udm, gemini_ask, etc). Tier 1: category routers — one tool per top-level group whose description summarizes available subcommands. Tier 2: sub-tools registered on demand when a category is first called, via MCPnotifications/tools/list_changed. Calling a category withaction="help"returns the full subcommand listing.
MCP-first agent integration. The skill command is removed; agent integration
is now secopsctl mcp install → every Claude Code session gets all 361
secopsctl tools and 17 craft-guide resources automatically.
- MCP server.
mcp serve— Model Context Protocol server over stdio JSON-RPC. Auto-generates tools from the cobra command tree with typed InputSchema (flags → JSON schema properties, positional args, enums). Guarded mutations carry[guarded: dry-run by default]in the description. Zero external dependencies. - MCP resources. All
docs/tips/*.mdfiles embedded in the binary and served astips://{name}resources — recipes, gotchas, the auth model, search surface, parser extensions. mcp install. Registers secopsctl in.claude/settings.json(--globalfor~/.claude/settings.json).- Tips gap-fill.
15-recipes.md(cross-cutting workflows) and16-gotchas.md(operational traps). Tips embed expanded from single-file toembed.FSwithAll()export.
skill/skill installand theskills/secopsctl/package — fully replaced bymcp serve+ MCP resources.
status capabilitiesJSON:skill_command→mcp_command.
Dashboard portability, a quota-aware transport, and a broad operator command
suite that wires SDK surfaces the CLI had not yet exposed. Every mutation stays
behind the standard dry-run/--yes guard with a structured --json result.
- Dashboard portability.
dashboards export <id>/import <file>round-trip a dashboard with its charts and queries as one JSON document.dashboards duplicateuses the server:duplicateverb (the copy gets its own independent charts and queries) with a--deep-copyclient-side fallback.cases overviewsurfaces a case's entities and the overview widget template. - Detection lifecycle.
rules test <file.yaral>dry-runs a rule against historical data (preview detections, no deploy);rules versions(+--show);rule-exclusions list|get;rules retrohunt create --wait;coverage(MITRE ATT&CK). - Investigation.
entities graph <detection-id>(findings-graph pivot) andentities risk-scores. - Triage.
alerts list --sort,cases list --sort+ an SLA column,cases workload|aging|stats, and bulkcases assign|tag|stage --ids. - Case work.
cases run-action(run an integration action on a case),cases task, andcases evidence. - RBAC / data.
data-access labels|scopesCRUD;watchlists create|delete|remove-entity. - SOAR ops.
soar connector stat|run. - Platform / data.
log-types,forwarders(+ collectors),feeds list|get|service-account, andingestion health.
- Quota-aware transport. The chronicle and SOAR clients honor a 429's
Retry-After/RetryInfo, add equal jitter and a total backoff budget, plus an opt-in client-side rate limiter (off by default); the CLI prints a clear hint when retries exhaust. A non-idempotent POST is not retried on a 5xx. alerts enrichreads the collection that backs the per-alert context view (rule, UDM events, entities/indicators, MITRE tags, triage, case bridge).- Chart reads (
dashboards charts,pull --with-charts, the copy path) use onedashboardCharts:batchGetwith a per-chart fallback;dashboards verifytreats a 4xx chart failure as broken and a 429/5xx as transient. - MCP resources serve the domain knowledge formerly in the bundled agent skill.
An operator-experience and agent-enablement milestone (Waves 73–83): the CLI's
own surface becomes machine-discoverable, daily triage scales, deploy previews
get more honest, the last config-as-code fidelity edges close, and dashboard
authoring gains a verify half. Every mutation stays behind the standard
dry-run/--yes guard.
- Agent enablement.
secopsctl capabilities [--json|--offline]— one session-bootstrap call fusing version, per-plane auth health, read-only state, and a surface-status rollup (validated vs blocked).commands --jsonnow carries per-flag{type, default, required, enum, usage}, positional-arg spec, and an example per command. A failed command under--jsonemits a structured{code, message, retryable, status, request_id}envelope on stderr (so stdout stays clean for the payload).push --jsondry-run includes a per-object change plan (items[]). - Agent enablement via MCP.
secopsctl mcp serveauto-generates MCP tools from the command tree;mcp installregisters in Claude Code settings. - Query library.
query run --file <path>|-andquery saved [<name>]run a UDM predicate from a file/stdin or from a trackedsaved_queries/pack. - Alert triage at scale.
alerts update --where <filter>/--stdin-idsapply one update to many alerts in a reviewed, guarded command;alerts listsurfaces a completeness signal (baseline count + a truncation warning — the alerts snapshot has no server cursor). - Bulk case close from a filter.
soar push bulk-close --where <filter>selects cases by a modern cases-list filter with a typed close-reason. - Rule promote.
rules promote <file.yaral>validates, creates, and deploys a new rule in one guarded step. - Curated blast-radius preview.
curated setpreviews the addressed deployment's current → requested state and the set×precision scope before the guard. - Dashboard reconcile completion. A schema-checked dry-run (an API-invalid
body now fails the preview, not just at
--yes); chart layout / filters / reorder / removal reconcile throughpush;pull --with-chartsreports the count of charts that degraded to a reference. - Grouping settings.
soar settings grouping getreads the alert-grouping General/Overflow settings singleton (the legacy max-alerts value plus any modern moduleSettings properties); guardedsetwrites where the instance exposes writable properties (the max-alerts singleton is read-mostly — no API SET). - Query stats.
query stats '<match:/outcome: YARA-L>'runs an aggregation query (whichquery udmrejects) and prints the result table — validate a chart query before authoring it. - Dashboard chart execute & verify.
dashboards run-chart/valuesprints the values a chart renders;dashboards verifyflags empty/errored charts (a headless dashboard health check) — the missing verify half of authoring. - Chart-type authoring.
add-chart/edit-chart --chart-type bar|line|pie|table --x --y [--series-by]generate + validate the visualization (vs hand-writing echarts JSON);edit-chartedits visualization/layout in place;add-charts --filebatch-authors a dashboard (paced, idempotent).
- The blocked Chronicle-host case verbs (
cases list/get/search) are hidden from help (still runnable for when the endpoint stabilizes); the workingcases soar-iduuid→id bridge stays visible.
- Default chart layout for
dashboards add-chart(and the reconcile fallback when an authored chart omits its layout) is now full-width on the native-dashboard 96-column grid (spanX: 96,spanY: 16) instead of the previousspanX: 12, which rendered a chart at one-eighth of the width.chartLayoutstartX/spanXrange over0–96. Explicit--layoutvalues are unaffected.
pull dashboards --with-chartsdereferences each chart into its inline YARA-L query so a dashboard round-trips as code (the dashboard body only references charts; the query lives in separatedashboardCharts→dashboardQueriesresources). The defaultpull dashboardsstays reference-only — a handful of requests and deterministicdrift— while--with-chartsdoes the heavier per-chart deref; a chart that can't be fetched standalone (some 404) or that hits the per-minute quota (429) degrades to a reference rather than losing the dashboard.pushanddriftdetect an inline mirror and dereference the live side to match (so an inline mirror never phantom-diffs a reference-only live).
push dashboardsof an inline mirror reconciles charts: a new chart via:addChart, a changed query / title / visualization / drilldown via:editChart(etag-guarded). Chart layout/filters/datasource edits, reordering, and removal are reported rather than applied — edit layout in the UI and remove charts withdashboards remove-chart. Per-chart server ids are kept out of the diff basis.
-
dashboardschart-authoring CLI verbs surface the Wave 70 SDK ops so a charted dashboard can be built from the command line:dashboards add-chart <id> --title <t> --query <yaral>(or--query-file) adds a chart and its YARA-L query in one:addChartcall;--layout/--datasource/--interval/--tile-typedefault sensibly and JSON flags are validated up front.dashboards edit-chart <id> --chart-id <c> --query <yaral>replaces a chart's query via:editChart, round-tripping the query's etag.dashboards remove-chart <id> --chart-id <c>removes a chart.dashboards charts <id>lists each chart with its resolved query (read-only;--json), the way to recover a--chart-idor review what a dashboard runs.
The mutating verbs are guarded (dry-run by default,
--yesto apply). A lossless deref-on-pull round-trip (capturing chart queries into the mirror) remains a tracked follow-up.
- Native-dashboard chart-query authoring via the dedicated chart ops. A dashboard's
definition.charts[]is reference-only by API design — each entry references adashboardChartsresource by name, and the YARA-L query lives one hop further in adashboardQueriesresource — sopush dashboards(wholesaledefinition.chartsreplace) re-points chart references and layout but cannot author a chart query. The query is authored through the dedicated chart ops the SDK carries:AddChart(:addChart, with an inlinedashboardQuery{query,input}),EditChart(:editChart, etag-guarded),RemoveChart,GetChart,GetQuery. Proven end to end byTestLiveDashboardChartAuthoringWriteSmoke(create → add chart with a YARA-L query → confirm the query round-trips → confirm the dashboard definition stays reference-only → edit the query → remove → delete), with offline tests pinning the request shapes. Surfacing these as a CLI command and dereferencing chart bodies onpull dashboardsare tracked follow-ups.
- Server-managed actor ids (
createUserId/updateUserId) are now stripped GLOBALLY by the reconcile engine (alongside the time fields), instead of as adashboards-only special case, so no config-as-code surface can write a tenant user id into a committed file (andupdateUserIdno longer churns the diff on every edit). Removed the dead, leakyPullDashboardspuller (no caller; it wrote raw CURATED dashboard list items includingcreateUserId);pull dashboardsuses the engine surface. Pulled dashboards carry no actor ids anddrift dashboardsis in sync.
Operator-confidence fixes from dogfooding the config-as-code loop, plus a new alert-grouping reconcile surface.
soar push grouping— alert-grouping rules as config-as-code via the modern v1alphaalertGroupingRulesAPI (siemplify-soar host). Reconciles create/update/delete;--prunedeletes server-only rules but refuses the non-deletable catch-all fallback (category: ALL).- Pull-time value redaction: a committed
.secopsctl-redactpatterns file (one regex per line) at the data root, plus an ad-hoc--redactflag onsoar pull, masks secrets that arrive as plain inline strings (e.g. a webhook URL carrying a token in a playbook step parameter). Drift-safe — pull, drift, and push load the same patterns, so a masked value never produces a phantom diff; a marker guard refuses to push a body still carrying the redaction marker. driftnow names the diverged objects —[+a ~b -c]in the text report andcreated_names/updated_names/deleted_names/untracked_namesin--json— so a bare count is diagnosable.
push rules-deployfield-masks the deployment PATCH to only the fields that differ from live, so an alerting-only flip no longer trips a 409 on an unchangedenabled; a residual "already enabled/disabled" 409 is treated as success-with-note; and the summary reports deployed / already-in-desired-state / failed truthfully, exiting non-zero only on a genuine failure.drift reference_listsno longer phantom-reports an empty reference list as changed immediately after a clean pull (entries canonicalize to[]on both the live and on-disk sides).entity summarizedecodes counters the API renders as JSON strings (proto3 int64), fixing the decode error onalertCounts.countand the sibling prevalence/timeline/widget counters.
soar playbook export(default JSON) now emits the save-compatible definition — the same shapepull playbookswrites — so the export → edit →push playbookloop round-trips and the file is whatsoar playbook mold/build-playbookconsume. The platform bundle is unchanged on--zip. Anything that parsed the previous (save-incompatible) export JSON should adopt the new shape.soar pull groupingwritesgrouping/rules/*.json(full reconcilable config) plus the General/Overflow settings singleton atgrouping/settings.json, replacing the earlier lossyrules/*.yamland emptysettings.yaml. Re-pull existing grouping mirrors.
Network-layer fix: force_ipv4 now applies to every outbound connection.
- One shared
auth.HTTPTransportbuilds all five outbound HTTP clients — the Chronicle SIEM client, the SOAR transport (modern + legacy), in-process OAuth token minting, Secret Managersecret_refreads, and theinfo cronheartbeat checker — withhttp.DefaultTransport-equivalent pooling and timeouts, and the dialer pinned to IPv4 whenforce_ipv4/SECOPS_FORCE_IPV4is on. - The
info cron --heartbeat-statusclient previously ignored the flag. It now reads it validation-free, so a partial config (force_ipv4set but SIEM keys absent) still pins the dialer, andinfo cronkeeps working with no config file at all.
The operational release: the alert → case → rule triage loop, the AI-assist layer, the playbook authoring palette, and agent-safety guardrails.
alerts update— guarded SIEM alert disposition (status / verdict / priority / comment), with id fan-out.- Alert ⇄ case bridges:
alerts getresolves the SOAR case id;cases soar-idbulk-resolves SIEM case UUIDs. soar case listtriage filters (--assignee/--priority/--tag/--since) plus a verbatim server-side--filter; the full modern filter grammar (scalars,any()collections, epoch-ms ranges) is documented and supported end to end — long filters auto-switch to the method-override POST, zero-match queries decode as empty results.soar case counts— per-priority queue numbers via the list'stotalSize.- Per-alert verbs inside a case:
soar case alert close | priority | move | reopen; case verbs gainpriority,reopen,comment add/list. - Rule tuning reads:
rules trends | counts | eventsandcurated detections | trends | events(plus a gated batch rule update in the SDK).
alerts investigate <id> [--latest]— the per-alert Gemini investigation: verdict, confidence, summary, suggested next steps (with the agent's UDM queries under--json);--latestis the read-only variant.soar case summarize— the structured Gemini case summary (poll-first;--refreshto regenerate).query gemini— environment-grounded SecOps Gemini chat.soar playbook generate— AI playbook drafting (returns the draft without persisting; instances may restrict the Playbook Assistant to interactive auth, surfaced plainly).
- The authoring palette:
soar playbook components actions(every action across every integration, with numeric ids),flow(transformers + logical operators),triggers(the trigger vocabulary),blocks;components usageresolves an action by name for impact analysis. - Lifecycle completion:
versions/restore,stats,export/import,step skip, batchdelete, and job-instance schedule management. soar playbook step insert— splice a brand-new action step into a playbook graph offline (fresh identity, rewired relations), reviewable before save.- Custom Python definitions over the API:
soar integration action | job-def template | create | update | delete(the IDE's authoring flow, guarded — create is POST, update is a sparse PATCH by id).
- Hard read-only mode:
--read-only/SECOPS_READONLY=1degrades every guarded mutation to a dry-run and refuses AI generations. secopsctl commands— the offline, machine-readable verb catalog (read vs guarded-mutation), for building automation allowlists. Each row now also reports per-command--jsonsupport (thejsonfield /JSONcolumn), so agents read it from the catalog instead of a hand-maintained doc list.- A local JSONL audit log of confirmed mutations (
$SECOPSCTL_HOME/audit.jsonl).
soar settings api-keys create | revokealongsidelist— the key value is minted locally (crypto/rand), shown exactly once, never logged.
- The root
--helpnow renders titled command groups (Setup & health / Read & query / Config as code / SOAR / Utilities), a getting-started pointer (config→doctor→commands/surfaces), and Example blocks on the high-traffic commands; a mistyped command suggests the nearest match. - Sharper errors: invalid enum flags echo your verbatim input and list the
valid set,
curated --precisionvalidates before the live-deploy banner,--hours <= 0is rejected up front, and missing files name the flag. - Flag spellings aligned (old names kept as hidden aliases):
alerts list --filter(was--query),soar case run-action/context set --id(was--case-id),soar integration uninstall --key(was--name). Flag value placeholders no longer render stray tokens.
- Watchlist entity writes send the UDM Entity envelope (the previous flat
noun was rejected);
RemoveWatchlistEntityremoves by resource name. - AI case summaries no longer restart generation on every read (poll-first).
- int64-bearing SOAR bodies (step skip, job instances, definition authoring) round-trip through raw-JSON overlays, immune to float64 truncation.