fix(elasticsearch): resolve Cloud IDs to the real host and correct the integration's output, timeout, and redirect defects - #7276
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThe PR centralizes Elasticsearch connection/authentication handling and corrects Cloud ID resolution, redirect credential handling, cluster-health timeout mapping, and several response contracts.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| apps/sim/tools/elasticsearch/utils.ts | Centralizes Cloud ID parsing, deployment URL selection, and authentication-header construction with explicit malformed-input checks. |
| apps/sim/blocks/blocks/elasticsearch.ts | Preserves the saved timeout sub-block ID while mapping it to the renamed tool parameter and adds system-index and output metadata. |
| apps/sim/tools/elasticsearch/cluster_health.ts | Separates Elasticsearch's server-side cluster wait from the transport timeout and applies safe redirect handling. |
| apps/sim/tools/elasticsearch/get_index.ts | Exposes the provider's index-keyed response through the declared indices output while retaining legacy top-level index keys. |
| apps/sim/tools/elasticsearch/list_indices.ts | Handles malformed response bodies and rows safely and adds an explicit option to include system indices. |
| apps/sim/tools/elasticsearch/utils.test.ts | Exercises Cloud ID host resolution, port inheritance, malformed components, authentication headers, and consistent tool behavior. |
| apps/sim/tools/elasticsearch/responses.test.ts | Verifies runtime response shapes and declared output metadata across the corrected Elasticsearch operations. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[Workflow or agent inputs] --> B{Deployment type}
B -->|Cloud| C[Parse and validate Cloud ID]
B -->|Self-hosted| D[Normalize configured host]
C --> E[Build Elasticsearch endpoint]
D --> E
E --> F[Attach API key or Basic auth]
F --> G[Execute request with legacy redirect semantics]
G --> H{Redirect crosses origin?}
H -->|Yes| I[Strip credentials]
H -->|No| J[Retain credentials]
I --> K[Transform structured output]
J --> K
Reviews (6): Last reviewed commit: "Merge remote-tracking branch 'origin/sta..." | Re-trigger Greptile
There was a problem hiding this comment.
All reported issues were addressed across 16 files
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
|
@cubic review |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
All reported issues were addressed across 16 files
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
… and redirect credentials
|
@cubic review |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
All reported issues were addressed across 22 files
Requires human review: Auto-approval blocked because this review re-detected 1 unresolved issue already reported by Cubic.
Re-trigger cubic
|
@cubic review |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
All reported issues were addressed across 22 files
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
|
@cubic review |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
No issues found across 22 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Re-trigger cubic
…cloud-id-host # Conflicts: # apps/sim/tools/generated/tool-metadata.ts # apps/sim/tools/generated/tool-outputs.ts
|
@cubic review |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
No issues found across 22 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Re-trigger cubic
Summary
Fixes the Elastic Cloud endpoint bug, plus every defect a full
/validate-integrationpass turned up in this integration.1. Cloud ID resolved to a host that does not exist (all 13 tools)
A Cloud ID is
<deployment label>:<base64 of "parentDomain$esUuid$kibanaUuid">and the reachable endpoint ishttps://<esUuid>.<parentDomain>. Every tool builthttps://<label>.<parentDomain>— the human-readable label, not the Elasticsearch UUID — so Elastic Cloud was unusable in every operation.Replaced with
parseCloudIdin a newapps/sim/tools/elasticsearch/utils.ts, following Beats'libbeat/cloudid/cloudid.godecodeCloudID(): split at the last colon so a colon in the label cannot corrupt the payload; require ≥3$-separated components; right-partition each component at its last colon for a per-service port, inheriting the parent domain's port and defaulting to 443.Rejects the component characters Beats rejects (
#@?/) plus\. This is the security-relevant part — an@in the UUID component turns everything before it into URL userinfo, sohttps://<uuid>@evil.example.comwould sendAuthorization: ApiKey …to an attacker-controlled origin. Two checks beyond Beats. First, both ports must be all digits — Beats validates neither, anduuid:80@evil.example.comsurvives its reject set by landing the@in the port half. Second,:is rejected in a component name:extractPortFromNamehas already split at the last colon, so a colon surviving in the name half means the component carried two, andfound.io:9243:5would otherwise assemblehttps://<uuid>.found.io:9243:5and fail as a bareTypeError: Invalid URLinside the transport. The port check does not cover that case — it only fires when the trailing half is non-numeric — so the two checks carry separate cases.buildBaseUrlandbuildAuthHeaderswere duplicated across all 13 tool files, byte-identical apart from_bulk's NDJSON media type. Now shared, with_bulkpassing its content type as an argument.2.
elasticsearch_get_indexdeclared a phantom outputDeclared
index, butGET /{index}returns a map keyed by index name —{"logs-2024": {aliases, mappings, settings}}. There is noindexkey at any level, so the whole payload was unreferenceable from downstream blocks.Now returns
{ indices: data, ...data }and declaresindices. The raw per-index keys are spread alongside so references saved beforeindicesexisted keep resolving; an index legitimately namedindicesis spread last and wins. The error branch returns{ indices: {} }so both branches satisfy the declared shape.3.
elasticsearch_cluster_healthdeclared a param literally namedtimeouttools/request-transport.tsreadsparams.timeoutas the outbound HTTP deadline in milliseconds. On the block path this was inert — the mapper always suffixeds, andNumber('30s')isNaN, which the transport discards. On the agent tool-calling path it was live: a model emittingtimeout: 30as a number skips the mapper'stypeof === 'string'guard, and the generic handler merges raw inputs over the transform, so it arrived as a 30 ms client abort.Renamed to
clusterTimeout, mapped intools.config.params(nottools.config.tool, which runs at serialization before variable resolution). The mapper also clearstimeoutexplicitly, because the handler merges{ ...inputs, ...transformedParams }and the raw input would otherwise still reach the transport. The subBlock id staystimeout, so saved workflow state is not orphaned —check-block-registry.tssubblock-ID stability passes.Same mapper had a unit bug: it appended
sto anything not already ending ins, so1mbecame1ms— a 1-millisecond server-side wait. It now only appendssto a bare integer.4. Credentials survived a cross-origin redirect (all 13 tools)
Every tool sends
Authorization, but nothing stripped it on a redirect off the configured origin.prepareToolRequestonly populatesredirectPolicyfrom the tool, and the stripping branch inlib/core/security/input-validation.server.tsis gated on that policy existing — so a redirect carried the API key or Basic credentials to the redirect target.All 13 now declare
{ mode: 'legacy', sendCredentialsOnCrossOriginRedirect: false }.stripAuthOnRedirectis deliberately not used: it dropsAuthorizationon every hop including same-origin, which would 401 a reverse proxy in front of Elasticsearch issuing a legitimate same-origin redirect.mode: 'legacy'preserves method and body replay — under'standard', a 301/302 would rewrite POST to GET and break_search,_countand_bulk.5. A cloud deployment fell back to a stale self-hosted host
buildBaseUrlbranched ondeploymentType === 'cloud' && cloudId, so a cloud invocation with no Cloud ID fell through tohost. The block markscloudIdrequired and does not renderhostwhen cloud is selected, but a user who switches the dropdown keeps their previoushostin saved state — hidden, not cleared. The cloud credential was sent to the cluster they used to point at.Now branches on deployment type first and rejects a missing Cloud ID. An unrecognized deployment type is also rejected rather than falling through:
deploymentTypeisrequired: truewith no explicitvisibility, whichtools/params.tsresolves touser-or-llm, so a model supplies it on the agent path and a near miss likeCloudwould take the self-hosted branch. A nullish value still means self-hosted — the dropdown's own default, and the shape of state saved before the field was touched.6.
list_indicesdropped indices silently and could throwitem.index.startsWith('.')threw outright on a_catrow with noindexcolumn, and every system index was filtered out with no way to opt in. Now guarded, tolerant of a non-array body, and opt-in via an advancedincludeSystemIndicesdropdown. Default behavior is unchanged.7. Nullable outputs missing
optional: trueget_document._versionand._source(both absent on the 404 branch;_sourcealso whenever_source_excludesstrips it),delete_document._version,create_index.shards_acknowledgedand.index,cluster_stats.status.8. Block outputs did not cover every tool
list_indices.messageandcount._shardswere returned but undeclared, so they were missing from the reference picker.Backwards compatibility
Zero subBlock ids removed or renamed, zero
requiredflips (one addition, a new optional param), zerovisibilitychanges.check-block-registry.ts origin/stagingpasses the subblock-ID stability check.Behavior only moves in one direction: a valid Cloud ID that produced an unreachable host now produces the reachable one; a malformed one threw before and throws now.
get_indexkeeps its raw keys.list_indiceskeeps its default filter. ThetimeoutsubBlock keeps its id and its saved values.Type of Change
Testing
94 tests across
utils.test.ts,cluster_health.test.ts,responses.test.tsand the existingsearch.test.ts.Covers label-vs-UUID host resolution, colon-in-label, per-service and inherited ports, the
#@?/\reject set, both port-smuggle variants,<3components, self-hosted trailing-slash and missing-host, a sweep asserting all 13 tools resolve the same cloud host,_bulkmedia type,prepareToolRequestleaving no client deadline while emittingtimeout=30s, the1m/500ms/2hunit cases,get_indexdeclared-vs-actual output parity on both branches,list_indicesfiltering/opt-in/malformed rows, the redirect policy on all 13 tools, and theoptionalflags.Every fix was verified red-first by reverting it and watching its tests fail: get_index 2, list_indices 3, redirect policy 10, optional flags 4, timeout mapper 6, Cloud ID reject set 3, cloud-host fallback 7.
bun run lint,bun run type-check(no Elasticsearch diagnostics),bun run check:audits(39 audits), andcheck-block-registry.ts origin/stagingall pass.tool-metadata:generateandgenerate-docsartifacts regenerated and committed.Checklist