Skip to content

fix(ssh): make execution timeout configurable and remove internal 300s cutoff#3394

Open
Danigm-dev wants to merge 7 commits intosimstudioai:stagingfrom
Danigm-dev:fix/ssh-timeout-configurable-staging
Open

fix(ssh): make execution timeout configurable and remove internal 300s cutoff#3394
Danigm-dev wants to merge 7 commits intosimstudioai:stagingfrom
Danigm-dev:fix/ssh-timeout-configurable-staging

Conversation

@Danigm-dev
Copy link

Summary

Makes SSH/tool internal execution timeout configurable by forwarding the effective timeout to internal
secure fetch calls, removing the hard internal 300s cutoff. Also documents how to configure
EXECUTION_TIMEOUT_FREE for local Docker and Helm/cloud deployments.

Fixes #(issue)

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Other: tests

Testing

  • Ran targeted suite:
    • cd apps/sim && bunx vitest run tools/index.test.ts
  • Result:
    • 1 passed, 52 passed

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)

Screenshots/Videos

N/A

@vercel
Copy link

vercel bot commented Mar 2, 2026

@Danigm-dev is attempting to deploy a commit to the Sim Team on Vercel.

A member of the Team first needs to authorize it.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 2, 2026

Greptile Summary

This PR removes the hardcoded 300s (5 minute) internal timeout for SSH/tool execution by forwarding the configurable EXECUTION_TIMEOUT_FREE value to the underlying secureFetchWithPinnedIP calls. The implementation replaces the local AbortController pattern with direct timeout forwarding, allowing SSH blocks to run up to 10 minutes when configured.

  • Refactored internal route handling in apps/sim/tools/index.ts to use secureFetchWithPinnedIP with configurable timeout
  • Added comprehensive test coverage for timeout forwarding behavior with two dedicated test cases
  • Updated documentation for both Docker Compose and Helm deployments with clear configuration examples
  • Test expectations aligned with current error parser behavior (HTTP status text fallback when response body parsing fails)

Confidence Score: 5/5

  • This PR is safe to merge with no identified risks
  • The implementation is clean and focused, with comprehensive test coverage verifying both explicit and default timeout forwarding. The refactoring properly handles DNS resolution for internal routes, constructs Response objects correctly for different status codes, and maintains clear error messages. Documentation is thorough for both local and cloud deployments.
  • No files require special attention

Important Files Changed

Filename Overview
apps/sim/tools/index.ts Replaced hardcoded 300s timeout with configurable timeout forwarding to secureFetchWithPinnedIP, enabling SSH blocks to run beyond 5 minutes when configured
apps/sim/tools/index.test.ts Added comprehensive test coverage for timeout forwarding behavior and updated error message expectations to match current parser behavior
README.md Documented SSH block timeout configuration for local deployments, explaining how to set EXECUTION_TIMEOUT_FREE environment variable
docker-compose.prod.yml Added EXECUTION_TIMEOUT_FREE environment variable with default value of 300 seconds to enable timeout configuration
helm/sim/README.md Documented Helm deployment steps for configuring SSH 10-minute timeout in cloud environments with verification commands

Last reviewed commit: a624850

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@Danigm-dev Danigm-dev force-pushed the fix/ssh-timeout-configurable-staging branch from 3d83b39 to f70f154 Compare March 18, 2026 13:47
@cursor
Copy link

cursor bot commented Mar 18, 2026

PR Summary

Medium Risk
Changes internal tool execution to use SSRF-protected secureFetchWithPinnedIP with DNS/IP resolution and forwarded timeout values, which could affect all internal /api/* tool calls if response/body handling differs. Adds coverage and deployment knobs, reducing risk of regressions but still touching core execution plumbing.

Overview
Removes the hard internal ~300s cutoff for internal /api/* tool calls by forwarding the effective per-tool timeout (defaulting to DEFAULT_EXECUTION_TIMEOUT_MS) into secureFetchWithPinnedIP, enabling longer-running SSH/tool executions.

Internal routes now resolve and pin an IP (including localhost -> 127.0.0.1) and wrap the secure-fetch response back into a standard Response, with updated timeout error detection.

Adds unit tests asserting timeout propagation/defaulting and updates expected error-message fallbacks, plus docs and deployment config to make EXECUTION_TIMEOUT_FREE configurable in Docker Compose and Helm/cloud rollouts.

Written by Cursor Bugbot for commit f70f154. This will update automatically on new commits. Configure here.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

statusText: secureResponse.statusText,
headers: responseHeaders,
})
}
Copy link

Choose a reason for hiding this comment

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

Error text lost when converting secureFetch to Response

Medium Severity

For internal routes, the body is eagerly consumed via secureResponse.arrayBuffer() and wrapped in a new Response(bodyBuffer). Later, the error-handling path tries response.json() first, then falls back to response.text(). Since a standard Response body can only be consumed once, the .text() fallback always fails after .json() consumes the body. Bun's native fetch allows multiple body reads, so the old code could extract meaningful error text (e.g., "Invalid access token"). Now errorData is always null for non-JSON error responses, and users see only the HTTP status text like "Unauthorized" instead of the actual error message.

Additional Locations (1)
Fix in Cursor Fix in Web

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