Skip to content

Commit cc1a278

Browse files
authored
fix(integrations): close defects found by an independent cold audit (#6767)
* fix(integrations): repair Update SLO and advanced OData filters An independent audit — eight cold readers, one per integration, given no prior findings — checked the eight integrations merged to staging today. Two defects broke an operation outright; both are fixed here. datadog: Update SLO rewrote every non-metric SLO to `metric`. The SLO Type dropdown carried a `metric` default and its condition covered both create and update, so an untouched control reached mergeSloUpdatePayload as an edit. A metric SLO requires `query`, and the merged body carries monitor_ids or sli_specification instead, so Datadog rejected it — Update SLO was unusable on monitor-based and time-slice SLOs, with no way to express "keep the current type". Update now has its own control defaulting to "Keep current". microsoft_ad: list_users, list_groups and list_service_principals emitted $count=true only alongside $search, so any $filter using an advanced operator (ne, not, endsWith, startsWith on non-indexed properties) returned 400. Graph requires $count=true with ConsistencyLevel: eventual for those. list_devices already did this correctly; the other three now match it. Also from the same audit: Datadog path IDs are trimmed before encoding in all 20 URL builders rather than 2, matching the existing get_monitor test. * fix(integrations): cloudflare, crowdstrike, and mssql audit findings From the independent cold audit. Cloudflare: DNS analytics no longer emits fabricated min/max telemetry (Cloudflare documents both as always empty); purge_everything defaults to specific-purge and errors when combined with target lists; three unsourced description claims corrected; Array.isArray guards on four older list transforms. CrowdStrike: IOC sort placeholder corrected to the dot form (created_on.desc, not the nonexistent created_timestamp); the 500-indicator cap relabelled as a Sim bound rather than a CrowdStrike one; credential failures return 401 rather than 500; prevent_no_ui noted as unenumerated. MSSQL: introspect no longer lets the model choose the database; row and byte caps on reads; introspection collapsed from 4N+2 to 6 fixed queries; WHERE and identifier guards run before the connection opens so rejections are 400 not 500; SAVE TRANSACTION, OPEN/CLOSE key, DEALLOCATE and ADD SIGNATURE added to the statement screen as two-token phrases; encrypt wording corrected to say TDS 7.4 encryption is negotiated, not guaranteed. * fix(splunk): publish the real output tables and read the errors Splunk sends The docs generator parses tool source text and resolves a shared `outputs` const only from the family's `types.ts`, so Splunk's helpers in `utils.ts` were invisible to it: seven operations published the block's union of every output instead of their own. Run Search and Get Search Results each shipped a ~50-row table naming savedSearches, alerts, indexes, and apps they never return, Cancel Search Job lost `messages`, and the four list tools lost `total`/`offset`. Inline the four helpers into each consuming tool and delete them, since relocating a shared const only moves the trap. Also: - Add a `splunk-errors` extractor for the documented `{messages: [{type, text}]}` envelope and set it on all twelve tools. A rejected SPL string, the most common failure, previously fell through to the status text and reported "Bad Request". - Read `searchEarliestTime`/`searchLatestTime` with `asNumber`. The job entry documents them as bare epoch numbers, so `asString` returned null for every `output_mode=json` response. - Project the `<messages>` block of the XML job-control response. It is the only payload that endpoint returns, so `cancel_search_job.messages` was always empty. - Mark the nullable job outputs optional, matching the transform. - Default `run_search` to `max_count=1000`. A oneshot search has no paging escape hatch and Splunk's own default is 10000 rows in one buffered response. - Add suggested skills to `SplunkBlockMeta`, grounded in `tools.access`. The regenerated tool metadata also picks up the Cloudflare and MSSQL output changes from the previous commit, which were never synced. * fix(okta,servicenow): apply integration audit findings Cherry-picked from fix/okta-servicenow-audit-followups (6db0f54), whose base predated the earlier audit round; the duplicate isOktaFlagEnabled that produced is resolved in favour of the existing richer helper, which already accepts 'yes'/1/'on' as well as true/'true'. okta: get_logs no longer advertises hasMore forever. A System Log query with no 'until' is a polling query, and Okta always returns a next link for one, even on an empty page — so any loop driven by hasMore never terminated, including the one our own shipped skill instructs the agent to run. errorCauses is now surfaced, so a failed write reports the real reason instead of the useless 'Api validation failed: profile'. sendEmail routes through one coercion helper across all four lifecycle tools. update_group's declarative fallback throws rather than silently truncating an extensible group profile. servicenow: attachmentLimit and limit no longer overwrite each other. Neither assignment was scoped to an operation, so all 12 paginated operations could silently return a row count the user never asked for — defeating the block's own design, which gave attachmentLimit a unique id precisely to avoid this. All seven approval states are published by ServiceNow and are now reachable from the filter, with the space-vs-underscore punctuation documented. The five legacy generic tools route through the shared response helpers, and the folder's only 'any' is gone. Block skills now name the semantic operations. * chore(integrations): regenerate catalog and docs artifacts * fix(integrations): disclose MSSQL truncation and keep Okta's poll cursor Three defects the review round found in the audit fixes themselves. MSSQL capped a recordset and then reported it as complete: `executeQuery` computed `truncated`/`truncationReason` but all five statement routes returned only `message`, `rows`, and `rowCount`, so a caller could not tell paging was required. A shared `toRowsResponseBody` now folds the reason into `message` for an agent reading the status line and exposes the two fields for a caller that branches on them. The byte ceiling also admitted a single oversized row as a lone exception, so one `nvarchar(max)` value serialized an unbounded body — the ceiling bounded everything except the case it exists for. A row is now admitted only when it still fits, and the drop is disclosed rather than read as an empty table. Okta's `get_logs` nulled `nextCursor` alongside `hasMore` on an empty polling page. Terminating the loop is right, but the cursor is the resume handle Okta tells callers to persist, so a scheduled workflow that hit one quiet interval restarted from `since` and re-delivered events it had already processed. The two answer different questions and now diverge. Cloudflare's purge block no longer lets the invalid combination be built: the four target fields are hidden once Purge Everything is selected, so the tool's guard is a backstop rather than a reachable hard error. * fix(okta,servicenow): stop sending requests the APIs reject Okta documents `since` and `after` on the System Log as mutually exclusive, so `get_logs` lets the cursor win rather than sending both — the shape a scheduled poll that persists the cursor would otherwise send. Seven boolean query params reached Okta interpolated raw, so an agent tool call supplying `yes` was rejected. Each now routes through `isOktaFlagEnabled`, keeping its existing send-or-omit behavior. A cleared ServiceNow limit/offset/quantity stayed `''` through the block mapper and was appended as a valueless `sysparm_limit=`. The mapper now resolves a blank to undefined, and the tools skip a blank as well. * fix(integrations): mssql guard gaps and Entra query, scope, and output findings MSSQL read-only screen - Screen RENAME, documented T-SQL DDL for Azure Synapse dedicated SQL pools and Analytics Platform System, which are reachable over TDS with exactly the connection fields this block exposes. `SELECT 1 RENAME OBJECT dbo.t TO t2` was a schema change passing an operation advertised as read-only. - Screen the Service Broker family: RECEIVE as a word, and END/MOVE/GET CONVERSATION and SEND ON CONVERSATION as two-token phrases, since END closes every CASE. RECEIVE is a destructive read and END CONVERSATION WITH CLEANUP drops a conversation's messages. MSSQL routes and block - Build the insert statement before connecting, matching update and delete, so a bad identifier answers 400 instead of burning a TLS+login and returning 500. - Declare `truncated`/`truncationReason` on the block, which the tools declare and the routes emit but the block left unreferenceable. Microsoft Entra ID - Pair `$count=true` with `ConsistencyLevel: eventual` conditionally. Graph documents `hasMembersWithLicenseErrors`, `isLicenseReconciliationNeeded`, and `identities/any(i:i/issuer)` as filterable only *without* advanced query parameters, and documents advanced queries as unsupported in Azure AD B2C tenants, so the unconditional pair broke filters that previously worked. When continuing from a nextLink the pairing is read off the link itself. - Request `LicenseAssignment.Read.All` instead of `Directory.Read.All`. The latter was needed by `GET /subscribedSkus` alone, whose permission table names the former as least privileged and does not list the ReadWrite scope we hold. - Enumerate the block's real output keys instead of a single `response` object no tool emits. * fix(splunk,datadog): stop truncating searches and send mute/unmute as query params Splunk run_search: revert the `max_count=1000` default added last pass. It was wrong on both halves. Splunk documents the parameter as "the number of events that can be accessible in any given status bucket. Also, in transforming mode, the maximum number of results to store" — so for a non-transforming oneshot it bounds status buckets, not the response, and for a transforming search (`| stats`, `| timechart`, which is what the block's own skills generate) it capped results at 1000 where Splunk would have stored 10000, silently. The block's `maxCount` placeholder already read `10000`, contradicting the code. Send `max_count` only when the caller sets it and restate the description in Splunk's own terms, matching create_search_job. The real guidance — a oneshot buffers the whole result set, so use Create Search Job + Get Search Results for anything large — moves into the tool description and the search-splunk-logs skill. Datadog mute/unmute: send `scope`, `end`, and `all_scopes` as query parameters. `MuteMonitor` and `UnmuteMonitor` declare no `requestBody` in the authoritative spec (docs.datadoghq.com/resources/json/full_spec_v1.json — the generated datadog-api-client-go v1 schema omits both operations and is a subset, not the authority); all three parameters are `in: query`. Sent as a JSON body they are dropped, so a scoped, time-boxed mute becomes an indefinite mute across every scope and unmute's "all scopes" never applies — answered with a 200 and the full monitor object, so nothing surfaces. Datadog list_monitors: imply `page=0` when a page size is set without a page. Datadog "returns all monitors without a `page_size` limit" when `page` is absent, so Page Size was inert from a control that reads as a bound. `page` is not defaulted when neither is set — that would silently truncate a caller relying on the documented return-everything behavior. Also: - Note in get_fired_alerts that `name=-` returns every saved search's fired alerts and the endpoint documents "Request parameters: None", so there is no count/offset to bound it. - Fix the Splunk block's `messages` output blurb: `[{type, text}]` holds for the search and job-control operations, but get_search_job returns an object. - Generalize the Datadog block's numeric coercion (`datadogPageNumber` → `datadogNumber`) over all 32 bare `Number()` mappings, so a typo or unresolved reference is omitted rather than sent as `NaN`/`null`, and an explicit `0` survives the old truthiness guard. - Disclose create_event's documented 18-hour `date_happened` ceiling, and that send_logs' `ddsource: "custom"` is a Sim default rather than a Datadog one. * chore(integrations): regenerate tool metadata and docs * fix(integrations): resolve confirmed findings from cold block audit Cloudflare: clear purge_cache advanced targets across operations; send action_parameters/ref/logging on rate-limit rule updates; migrate off the deprecated batch zone-settings endpoint; correct MX/URI priority wording; stop coercing blank numerics to 0. CrowdStrike: seed includeHidden to match Falcon's documented default. Microsoft Entra ID: resolve a UPN to an object ID for app role assignment; wrap 21 array outputs in items.properties so nested paths resolve. Okta: route assign_user_role's notification flag through isOktaFlagEnabled. ServiceNow: drop the triage skill's claim of a default limit that does not exist. Splunk: always assign coerced numerics so raw values cannot leak through the executor's raw-input merge. * fix(editor,credential-group): mask secrets outside short-input and stop a per-option abort from failing a shared query config.password only reached the short-input renderer, so eight credential fields rendered in plaintext: private keys on ssh/sftp/pi/kalshi, the Secrets Manager payload, the STS web-identity and SAML assertions, and the Browser Use variables table. long-input, code, and table now honor the flag. Code fields mask through the highlighter because react-simple-code-editor paints its textarea transparent; the table masks every column but the first so key/value rows stay distinguishable. A registry-walking audit test fails both on a password flag sitting on a type that cannot honor it and on any of the eight fields losing its flag. credential-group threaded a per-option AbortSignal into the fetch registered under the workspace-wide credential group list key, so closing one option panel rejected every co-observer with an AbortError that is not a React Query cancellation. The shared fetch now runs on its own lifecycle signal. * fix(mssql,editor): measure the response cap in UTF-8 and stop search from unmasking secrets capRecordset sized rows with JSON.stringify(row).length, which counts UTF-16 code units while the emitted body carries raw UTF-8. CJK is the worst case at 3 bytes per unit, so a recordset admitted as 10 MB serialized to 28 MB. Rows are now measured with Buffer.byteLength, serialized once each, with array punctuation charged exactly and a reserve held back for the response envelope. Workflow search revealed masked credentials without the user touching the field: the search panel keeps focus in its own input and only scrolls the match into view, so typing a guess painted a private key on screen. The index is built client-side from values already in page memory, so this was never a privilege boundary, but masking exists to prevent incidental display and a screenshare-visible reveal defeats it. Focus is now the only reveal, applied through one shared policy across all four renderers. * test(editor): drop PEM-shaped fixtures from the masking tests The masking fixtures carried a literal OPENSSH private key header, which GitGuardian flags as a committed secret even though the body was only the base64 of "openssh-key-v1". The fixtures now use an obvious marker string, and the assertions derive their match text and dot counts from the fixture instead of restating its bytes. * refactor(editor): drop the dead isSearchHighlighted prop No renderer consumed it. The editor computed it at two call sites and sub-block passed a hardcoded false into renderLabel's slot for it, so even the one function that declared a parameter never saw the real value. Its only live effect was in the memo comparator, where an unconsumed value changing forced a re-render for nothing. The name stays in the masking audit's forbidden-inputs list, which guards against a search signal being wired back into a masking decision.
1 parent fd828f8 commit cc1a278

174 files changed

Lines changed: 6927 additions & 1200 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/docs/content/docs/en/integrations/cloudflare.mdx

Lines changed: 29 additions & 36 deletions
Large diffs are not rendered by default.

apps/docs/content/docs/en/integrations/crowdstrike.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Create custom CrowdStrike Falcon indicators of compromise (POST /iocs/entities/i
4949
| `clientId` | string | Yes | CrowdStrike Falcon API client ID |
5050
| `clientSecret` | string | Yes | CrowdStrike Falcon API client secret |
5151
| `cloud` | string | Yes | CrowdStrike Falcon cloud region |
52-
| `indicators` | json | Yes | JSON array of indicators to create. Each entry requires type, value, and applied_globally \(boolean\). type is one of sha256, md5, domain, ipv4, ipv6; action is one of no_action, allow, prevent_no_ui, prevent, detect; severity is one of informational, low, medium, high, critical; platforms entries are windows, mac, or linux. Other documented fields: host_groups \(array\), description, source, tags \(array\), expiration \(ISO 8601\), mobile_action, metadata \(\{ filename \}\). Either applied_globally must be true or host_groups must be supplied. Tenants can extend these value sets, so treat them as the documented defaults rather than a closed list. |
52+
| `indicators` | json | Yes | JSON array of indicators to create. Each entry requires type, value, and applied_globally \(boolean\). type is one of sha256, md5, domain, ipv4, ipv6; action is one of no_action, allow, prevent, detect \(prevent_no_ui is widely reported and appears in the Falcon console, but CrowdStrike does not enumerate it in the IOC API docs - call GET /iocs/queries/actions/v1 to read the actions your tenant actually accepts\); severity is one of informational, low, medium, high, critical; platforms entries are windows, mac, or linux. Other documented fields: host_groups \(array\), description, source, tags \(array\), expiration \(ISO 8601\), mobile_action, metadata \(\{ filename \}\). Either applied_globally must be true or host_groups must be supplied. Tenants can extend these value sets, so treat them as the documented defaults rather than a closed list. |
5353
| `comment` | string | No | Audit comment explaining why these indicators were created |
5454
| `retrodetects` | boolean | No | Whether to generate retroactive detections for the new indicators |
5555
| `ignoreWarnings` | boolean | No | Whether to create the indicators even when CrowdStrike returns warnings |
@@ -774,7 +774,7 @@ Search custom CrowdStrike Falcon indicators of compromise (IOCs) with a Falcon Q
774774
| `clientSecret` | string | Yes | CrowdStrike Falcon API client secret |
775775
| `cloud` | string | Yes | CrowdStrike Falcon cloud region |
776776
| `filter` | string | No | Falcon Query Language filter over IOC fields |
777-
| `limit` | number | No | Maximum number of IOC IDs to return \(1-500, default 100\) |
777+
| `limit` | number | No | Maximum number of IOC IDs to return \(default 100\). CrowdStrike publishes no maximum for this endpoint; Sim caps it at 500 to keep a single request bounded |
778778
| `offset` | number | No | Pagination offset. Mutually exclusive with the after cursor; use after beyond 10,000 IOCs. |
779779
| `after` | string | No | Pagination cursor from a previous response. Mutually exclusive with offset. |
780780
| `sort` | string | No | Sort expression. Supported fields include action, applied_globally, created_by, created_on, expiration, expired, modified_by, modified_on, severity_number, source, type, and value. |

apps/docs/content/docs/en/integrations/datadog.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ Post an event to the Datadog event stream. Use for deployment notifications, ale
9595
| `tags` | string | No | Comma-separated list of tags \(e.g., "env:production,service:api", "team:backend,priority:high"\) |
9696
| `aggregationKey` | string | No | Key to aggregate events together |
9797
| `sourceTypeName` | string | No | Source type name for the event |
98-
| `dateHappened` | number | No | Unix timestamp in seconds when the event occurred \(e.g., 1705320000, defaults to now\) |
98+
| `dateHappened` | number | No | Unix timestamp in seconds when the event occurred \(e.g., 1705320000, defaults to now\). Datadog limits this to events no older than 18 hours. |
9999
| `apiKey` | string | Yes | Datadog API key |
100100
| `site` | string | No | Datadog site/region \(default: datadoghq.com\) |
101101

@@ -197,8 +197,8 @@ List all monitors in Datadog with optional filtering by name, tags, or state.
197197
| `tags` | string | No | Comma-separated list of tags to filter by \(e.g., "env:prod,team:backend"\) |
198198
| `monitorTags` | string | No | Comma-separated list of monitor tags to filter by \(e.g., "service:api,priority:high"\) |
199199
| `withDowntimes` | boolean | No | Include downtime data with monitors |
200-
| `page` | number | No | Page number for pagination \(0-indexed, e.g., 0, 1, 2\) |
201-
| `pageSize` | number | No | Number of monitors per page \(e.g., 50, max: 1000\) |
200+
| `page` | number | No | Page to start paginating from \(0-indexed, e.g., 0, 1, 2\). Datadog returns every monitor in the org without pagination when this is not specified, so set it to bound the response. Setting Page Size alone implies page 0. |
201+
| `pageSize` | number | No | Number of monitors per page \(e.g., 50, max: 1000\). Datadog only applies this when a page is specified — otherwise it returns all monitors with no page size limit — so setting this alone sends page 0. With a page but no page size, Datadog defaults to 100. |
202202
| `apiKey` | string | Yes | Datadog API key |
203203
| `applicationKey` | string | Yes | Datadog Application key |
204204
| `site` | string | No | Datadog site/region \(default: datadoghq.com\) |
@@ -312,7 +312,7 @@ Send log entries to Datadog for centralized logging and analysis.
312312

313313
| Parameter | Type | Required | Description |
314314
| --------- | ---- | -------- | ----------- |
315-
| `logs` | string | Yes | JSON array of log entries. Each entry should have message and optionally ddsource, ddtags, hostname, service. |
315+
| `logs` | string | Yes | JSON array of log entries. Each entry should have message and optionally ddsource, ddtags, hostname, service. Sim fills in ddsource="custom" when an entry omits it — that is a Sim default, not a Datadog one; set ddsource yourself to have Datadog apply the matching integration log pipeline. |
316316
| `apiKey` | string | Yes | Datadog API key |
317317
| `site` | string | No | Datadog site/region \(default: datadoghq.com\) |
318318

0 commit comments

Comments
 (0)