Skip to content

fix(elasticsearch): resolve Cloud IDs to the real host and correct the integration's output, timeout, and redirect defects - #7276

Open
waleedlatif1 wants to merge 4 commits into
stagingfrom
fix/elasticsearch-cloud-id-host
Open

fix(elasticsearch): resolve Cloud IDs to the real host and correct the integration's output, timeout, and redirect defects#7276
waleedlatif1 wants to merge 4 commits into
stagingfrom
fix/elasticsearch-cloud-id-host

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes the Elastic Cloud endpoint bug, plus every defect a full /validate-integration pass 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 is https://<esUuid>.<parentDomain>. Every tool built https://<label>.<parentDomain> — the human-readable label, not the Elasticsearch UUID — so Elastic Cloud was unusable in every operation.

Replaced with parseCloudId in a new apps/sim/tools/elasticsearch/utils.ts, following Beats' libbeat/cloudid/cloudid.go decodeCloudID(): 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, so https://<uuid>@evil.example.com would send Authorization: ApiKey … to an attacker-controlled origin. Two checks beyond Beats. First, both ports must be all digits — Beats validates neither, and uuid:80@evil.example.com survives its reject set by landing the @ in the port half. Second, : is rejected in a component name: extractPortFromName has already split at the last colon, so a colon surviving in the name half means the component carried two, and found.io:9243:5 would otherwise assemble https://<uuid>.found.io:9243:5 and fail as a bare TypeError: Invalid URL inside 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.

buildBaseUrl and buildAuthHeaders were duplicated across all 13 tool files, byte-identical apart from _bulk's NDJSON media type. Now shared, with _bulk passing its content type as an argument.

2. elasticsearch_get_index declared a phantom output

Declared index, but GET /{index} returns a map keyed by index name{"logs-2024": {aliases, mappings, settings}}. There is no index key at any level, so the whole payload was unreferenceable from downstream blocks.

Now returns { indices: data, ...data } and declares indices. The raw per-index keys are spread alongside so references saved before indices existed keep resolving; an index legitimately named indices is spread last and wins. The error branch returns { indices: {} } so both branches satisfy the declared shape.

3. elasticsearch_cluster_health declared a param literally named timeout

tools/request-transport.ts reads params.timeout as the outbound HTTP deadline in milliseconds. On the block path this was inert — the mapper always suffixed s, and Number('30s') is NaN, which the transport discards. On the agent tool-calling path it was live: a model emitting timeout: 30 as a number skips the mapper's typeof === '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 in tools.config.params (not tools.config.tool, which runs at serialization before variable resolution). The mapper also clears timeout explicitly, because the handler merges { ...inputs, ...transformedParams } and the raw input would otherwise still reach the transport. The subBlock id stays timeout, so saved workflow state is not orphaned — check-block-registry.ts subblock-ID stability passes.

Same mapper had a unit bug: it appended s to anything not already ending in s, so 1m became 1ms — a 1-millisecond server-side wait. It now only appends s to 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. prepareToolRequest only populates redirectPolicy from the tool, and the stripping branch in lib/core/security/input-validation.server.ts is 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 }. stripAuthOnRedirect is deliberately not used: it drops Authorization on 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, _count and _bulk.

5. list_indices dropped indices silently and could throw

item.index.startsWith('.') threw outright on a _cat row with no index column, 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 advanced includeSystemIndices dropdown. Default behavior is unchanged.

6. Nullable outputs missing optional: true

get_document._version and ._source (both absent on the 404 branch; _source also whenever _source_excludes strips it), delete_document._version, create_index.shards_acknowledged and .index, cluster_stats.status.

7. Block outputs did not cover every tool

list_indices.message and count._shards were returned but undeclared, so they were missing from the reference picker.

Backwards compatibility

Zero subBlock ids removed or renamed, zero required flips (one addition, a new optional param), zero visibility changes. check-block-registry.ts origin/staging passes 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_index keeps its raw keys. list_indices keeps its default filter. The timeout subBlock keeps its id and its saved values.

Type of Change

  • Bug fix

Testing

86 tests across utils.test.ts, cluster_health.test.ts, responses.test.ts and the existing search.test.ts.

Covers label-vs-UUID host resolution, colon-in-label, per-service and inherited ports, the #@?/\ reject set, both port-smuggle variants, <3 components, self-hosted trailing-slash and missing-host, a sweep asserting all 13 tools resolve the same cloud host, _bulk media type, prepareToolRequest leaving no client deadline while emitting timeout=30s, the 1m/500ms/2h unit cases, get_index declared-vs-actual output parity on both branches, list_indices filtering/opt-in/malformed rows, the redirect policy on all 13 tools, and the optional flags.

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.

bun run lint, bun run type-check (no Elasticsearch diagnostics), bun run check:audits (39 audits), and check-block-registry.ts origin/staging all pass. tool-metadata:generate and generate-docs artifacts regenerated and committed.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercel Bot commented Aug 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Aug 29, 2026 4:17pm

Request Review

@greptile-apps

greptile-apps Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR centralizes Elasticsearch endpoint and authentication handling while correcting Cloud ID resolution, redirect credentials, timeout mapping, and output contracts.

  • Adds shared Cloud ID parsing and request-header utilities across all Elasticsearch tools.
  • Aligns workflow inputs and generated outputs with the tools’ runtime behavior.
  • Adds coverage for endpoint parsing, redirects, response shapes, timeout units, and system-index filtering.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
apps/sim/tools/elasticsearch/utils.ts Centralizes Cloud ID endpoint resolution and authentication-header construction with hostname and port validation.
apps/sim/blocks/blocks/elasticsearch.ts Preserves the saved timeout sub-block ID while mapping it away from the transport-reserved parameter and adds system-index configuration.
apps/sim/tools/elasticsearch/get_index.ts Declares an aggregate indices output while retaining raw index-name keys for compatibility.
apps/sim/tools/elasticsearch/list_indices.ts Makes response handling tolerant of malformed rows and adds an opt-in for system indices.
apps/sim/tools/elasticsearch/cluster_health.ts Separates the Elasticsearch server-side wait from the transport timeout and applies redirect credential protection.
apps/sim/tools/elasticsearch/responses.test.ts Verifies response contracts, optional outputs, and redirect policies across the integration.

Reviews (4): Last reviewed commit: "fix(elasticsearch): reject a surviving c..." | Re-trigger Greptile

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 16 files

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread apps/sim/tools/elasticsearch/utils.ts Outdated
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 29, 2026

Copy link
Copy Markdown

@cubic review

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 16 files

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread apps/sim/tools/elasticsearch/utils.ts
Comment thread apps/sim/tools/elasticsearch/utils.test.ts Outdated
@waleedlatif1 waleedlatif1 changed the title fix(elasticsearch): resolve a Cloud ID to the real Elasticsearch host fix(elasticsearch): resolve Cloud IDs to the real host and correct the integration's output, timeout, and redirect defects Aug 29, 2026
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 29, 2026

Copy link
Copy Markdown

@cubic review

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 29, 2026

Copy link
Copy Markdown

@cubic review

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 22 files

Confidence score: 3/5

  • In apps/sim/tools/elasticsearch/utils.ts, a cloud deployment without cloudId can fall through to a stale self-hosted host and send operations to the wrong cluster; branch explicitly on deployment type and handle the missing cloud ID before selecting a host.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/sim/tools/elasticsearch/utils.ts">

<violation number="1" location="apps/sim/tools/elasticsearch/utils.ts:88">
P1: When `deploymentType` is `cloud` but `cloudId` is missing, this condition falls through to the self-hosted host. A stale host can therefore send a cloud-configured operation to the wrong cluster; branch on deployment type first and reject a missing Cloud ID.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment on lines +88 to +90
if (params.deploymentType === 'cloud' && params.cloudId) {
return parseCloudId(params.cloudId)
}

@cubic-dev-ai cubic-dev-ai Bot Aug 29, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: When deploymentType is cloud but cloudId is missing, this condition falls through to the self-hosted host. A stale host can therefore send a cloud-configured operation to the wrong cluster; branch on deployment type first and reject a missing Cloud ID.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/sim/tools/elasticsearch/utils.ts, line 88:

<comment>When `deploymentType` is `cloud` but `cloudId` is missing, this condition falls through to the self-hosted host. A stale host can therefore send a cloud-configured operation to the wrong cluster; branch on deployment type first and reject a missing Cloud ID.</comment>

<file context>
@@ -0,0 +1,125 @@
+ * Elastic Cloud ID or a self-hosted host URL.
+ */
+export function buildBaseUrl(params: ElasticsearchBaseParams): string {
+  if (params.deploymentType === 'cloud' && params.cloudId) {
+    return parseCloudId(params.cloudId)
+  }
</file context>
Suggested change
if (params.deploymentType === 'cloud' && params.cloudId) {
return parseCloudId(params.cloudId)
}
if (params.deploymentType === 'cloud') {
if (!params.cloudId) {
throw new Error('Cloud ID is required for cloud deployments')
}
return parseCloudId(params.cloudId)
}
Fix with cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant