Skip to content

feat: SSH tunnel + browser auto-open for OpenClaw web dashboard#2418

Closed
AhmedTMM wants to merge 9 commits intoOpenRouterTeam:mainfrom
AhmedTMM:feat/ssh-tunnel-browser-open
Closed

feat: SSH tunnel + browser auto-open for OpenClaw web dashboard#2418
AhmedTMM wants to merge 9 commits intoOpenRouterTeam:mainfrom
AhmedTMM:feat/ssh-tunnel-browser-open

Conversation

@AhmedTMM
Copy link
Copy Markdown
Collaborator

Summary

  • Adds SSH tunnel support to automatically forward OpenClaw's web dashboard (port 18791) to localhost and open the browser
  • Captures the gateway auth token in a closure so the browser URL includes the correct ?token= parameter
  • Adds getConnectionInfo() to the CloudOrchestrator interface, implemented by all SSH-based clouds (DigitalOcean, Hetzner, AWS, GCP)
  • Local mode opens the browser directly; Sprite/Daytona gracefully skip tunneling

Test plan

  • bunx @biomejs/biome check src/ — 0 errors
  • bun test — 1415 tests pass, 0 failures
  • Manual: spawn run digitalocean openclaw — browser should open to web dashboard
  • Manual: spawn run local openclaw — browser opens to localhost:18791 directly

🤖 Generated with Claude Code

AhmedTMM and others added 3 commits March 10, 2026 00:06
OpenClaw runs a web dashboard on port 18791 of the remote VM. This
change SSH-tunnels that port to localhost and auto-opens the browser,
giving users a web UI with zero CLI knowledge needed.

- Add TunnelConfig to AgentConfig interface (agents.ts)
- Add startSshTunnel function with port-finding logic (ssh.ts)
- Capture gateway token in closure so the same token is used for both
  the remote config and the browser URL (agent-setup.ts)
- Wire tunnel into orchestration pipeline between preLaunch and
  interactiveSession (orchestrate.ts)
- Add getConnectionInfo to CloudOrchestrator interface and implement
  in all SSH-based clouds (DO, Hetzner, AWS, GCP)
- Local: opens browser directly at localhost:18791
- Sprite/Daytona: gracefully skipped (no standard SSH)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Writes ~/.openclaw/workspace/USER.md during setup with instructions
to use the web dashboard (port 18791) for channel setup tasks that
require QR code scanning (WhatsApp, Telegram) — these don't work
in a terminal TUI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…OpenRouterTeam#2417)

Bun's os.homedir() reads from getpwuid() and ignores runtime changes to
process.env.HOME. Named imports capture the native function binding, so
patching os.homedir on the default export doesn't propagate. This caused
all test files using homedir() to write .spawn-test-* dirs to the real
home directory instead of the preload sandbox.

Add getUserHome() helper to shared/ui.ts that prefers process.env.HOME,
replace all direct homedir() calls in production and test code.

Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
louisgv
louisgv previously approved these changes Mar 10, 2026
Copy link
Copy Markdown
Member

@louisgv louisgv left a comment

Choose a reason for hiding this comment

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

Security Review

Verdict: APPROVED
Commit: cc7fe90

Summary

SSH tunnel + browser auto-open for OpenClaw web dashboard. Clean implementation with no critical security issues.

Findings

  • LOW agent-setup.ts:703 — Token passed via URL query string (?token=${dashboardToken})
    • Risk minimal: localhost-only, SSH-tunneled traffic
    • Advisory: consider POST/headers if OpenClaw supports it in future
    • Not blocking approval

Security Verification

✅ No command injection (Bun.spawn with array args)
✅ Input validation (host/user from trusted cloud APIs)
✅ Token generation (crypto.randomUUID, 122-bit entropy)
✅ Bounded port scanning (max 10 attempts)
✅ Graceful error handling with fallback
✅ Resource cleanup (tunnel.stop on exit)

Tests

  • bun test: PASS (1415 tests)
  • biome lint: PASS (0 errors)
  • bash -n: N/A (no shell scripts in PR)
  • curl|bash: OK
  • macOS compat: OK

Note

PR has merge conflicts (based on old main). Recommend rebase before merge.


-- security/pr-reviewer

@louisgv
Copy link
Copy Markdown
Member

louisgv commented Mar 10, 2026

Security review complete — code approved! However, this PR has merge conflicts and needs to be rebased on current main before it can be merged.

Please run:

git fetch origin
git rebase origin/main
git push --force-with-lease

Once conflicts are resolved, this will be ready to merge.

-- security/pr-reviewer

AhmedTMM and others added 6 commits March 10, 2026 03:29
…outerTeam#2419)

The manifest was updated to moonshotai/kimi-k2.5 but the code still
hardcoded openrouter/auto in both modelDefault and the configure
fallback.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: L <6723574+louisgv@users.noreply.github.com>
…Team#2422)

Move all filesystem path helpers (getUserHome, getSpawnDir, getHistoryPath,
getSpawnCloudConfigPath, getCacheDir, getCacheFile, getUpdateFailedPath,
getSshDir, getTmpDir) into a single shared/paths.ts module. This eliminates
scattered homedir()/process.env.HOME patterns across 8+ files and provides
a single import source for all path resolution.

- Create packages/cli/src/shared/paths.ts with 9 exported functions
- Update 17 source files to import from paths.ts
- Add re-exports in ui.ts and history.ts for backward compatibility
- Remove direct homedir() imports from gcp, sprite, local, ssh-keys, etc.
- Add comprehensive unit tests in paths.test.ts
- Bump CLI version to 0.15.34

Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…uterTeam#2423)

* fix: set SPAWN_HOME in preload and add fs-sandbox guardrail test

The test preload now sets SPAWN_HOME to the sandbox directory by default,
so tests that call cmdRun/saveSpawnRecord without explicitly setting
SPAWN_HOME no longer write to the real ~/.spawn/history.json.

Add fs-sandbox.test.ts that verifies the sandbox is correctly configured
(HOME, SPAWN_HOME, XDG vars all point to temp). Update testing.md with
mandatory filesystem isolation rules.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: add root bunfig.toml and fix biome formatting

Add root-level bunfig.toml with test preload so `bun test` works from
the repo root. Fix biome formatting in orchestrate.test.ts afterEach.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: lab <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude <claude@anthropic.com>
…m#2421)

Agent: test-engineer

Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- Integrate saveLaunchCmd method removed from CloudOrchestrator interface (moved inline)
- Merge imports from both branches (getModelIdInteractive, startSshTunnel, getErrorMessage, logDebug)
- Keep new getConnectionInfo() interface method from PR branch
- Keep logDebug usage from main's updated orchestrate.ts

Agent: pr-maintainer
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Resolve merge conflicts between main and PR OpenRouterTeam#2418:
- Keep main's version (bumped to 0.15.36)
- Keep main's installChromeBrowser and browser config for openclaw
- Integrate PR's SSH tunnel support (getConnectionInfo on all SSH clouds)
- Add dashboard token closure for openclaw web URL
- Add USER.md bootstrap for openclaw workspace
- Drop saveLaunchCmd from CloudOrchestrator (centralized on main)
- Drop Docker/model references not present on main

Agent: pr-maintainer
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@la14-1
Copy link
Copy Markdown
Member

la14-1 commented Mar 10, 2026

Merge conflicts resolved and rebased onto current main (e396a61). Changes:

  • Kept main's installChromeBrowser + browser config for OpenClaw
  • Integrated SSH tunnel support (getConnectionInfo on all SSH clouds)
  • Added dashboard token closure for OpenClaw web URL
  • Added USER.md bootstrap for OpenClaw workspace
  • Dropped saveLaunchCmd from CloudOrchestrator (centralized on main)
  • Dropped Docker/model references not present on main
  • Version bumped to 0.15.36

Verification:

  • bunx @biomejs/biome check src/ — 0 errors
  • bun test — 1492 tests pass, 0 failures

Note: The force-push dismissed the original approval. This PR needs re-approval before merging.

-- refactor/pr-maintainer

louisgv
louisgv previously approved these changes Mar 10, 2026
Copy link
Copy Markdown
Member

@louisgv louisgv left a comment

Choose a reason for hiding this comment

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

Security Review

Verdict: APPROVED
Commit: e81892f

Summary

SSH tunnel + browser auto-open for OpenClaw web dashboard. Includes test sandbox isolation improvements and path centralization refactor. Clean implementation with no critical security issues.

Findings

  • LOW agent-setup.ts:666 — Dashboard token passed via URL query string (?token=${dashboardToken})
    • Risk minimal: localhost-only, SSH-tunneled traffic, 122-bit entropy token
    • Advisory: consider POST/headers if OpenClaw supports it in future
    • Not blocking approval

Security Verification

✅ No command injection (Bun.spawn with array args)
✅ Input validation (host/user from trusted cloud APIs)
✅ Token generation (crypto.randomUUID, 122-bit entropy)
✅ Bounded port scanning (max 10 attempts, 500ms timeout each)
✅ Graceful error handling with fallback
✅ Resource cleanup (tunnel.stop on exit)
✅ Test sandbox isolation (no real home directory touches)
✅ Path traversal prevention maintained in refactored code

Tests

  • bun test: PASS (1492 tests, 0 failures)
  • biome lint: PASS (0 errors)
  • bash -n: N/A (no shell scripts in PR)
  • curl|bash: OK (no remote script execution)
  • macOS compat: OK (no macOS-specific issues introduced)

Code Quality

  • Proper ESM usage throughout (no as assertions, no require())
  • Test preload ensures filesystem isolation
  • Centralized path helpers improve maintainability
  • Version bumped correctly (0.15.33 → 0.15.36)

-- security/pr-reviewer

@AhmedTMM AhmedTMM dismissed louisgv’s stale review March 10, 2026 10:19

The merge-base changed after approval.

louisgv
louisgv previously approved these changes Mar 10, 2026
Copy link
Copy Markdown
Member

@louisgv louisgv left a comment

Choose a reason for hiding this comment

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

Security Review

Verdict: APPROVED
Commit: e81892f

Summary

SSH tunnel + browser auto-open for OpenClaw web dashboard. Includes test sandbox isolation improvements and path centralization refactor. Clean implementation with no critical security issues.

Findings

  • LOW agent-setup.ts:666 — Dashboard token passed via URL query string (?token=${dashboardToken})
    • Risk minimal: localhost-only, SSH-tunneled traffic, 122-bit entropy token
    • Advisory: consider POST/headers if OpenClaw supports it in future
    • Not blocking approval

Security Verification

✅ No command injection (Bun.spawn with array args)
✅ Input validation (host/user from trusted cloud APIs)
✅ Token generation (crypto.randomUUID, 122-bit entropy)
✅ Bounded port scanning (max 10 attempts, 500ms timeout each)
✅ Graceful error handling with fallback
✅ Resource cleanup (tunnel.stop on exit)
✅ Test sandbox isolation (no real home directory touches)
✅ Path traversal prevention maintained in refactored code

Tests

  • bun test: PASS (1492 tests, 0 failures)
  • biome lint: PASS (0 errors)
  • bash -n: N/A (no shell scripts in PR)
  • curl|bash: OK (no remote script execution)
  • macOS compat: OK (no macOS-specific issues introduced)

Code Quality

  • Proper ESM usage throughout (no `as` assertions, no `require()`)
  • Test preload ensures filesystem isolation
  • Centralized path helpers improve maintainability
  • Version bumped correctly (0.15.33 → 0.15.36)

Note

PR has merge conflicts with main. Recommend rebase before merge.


-- security/pr-reviewer

@AhmedTMM AhmedTMM dismissed louisgv’s stale review March 10, 2026 11:47

The merge-base changed after approval.

louisgv
louisgv previously approved these changes Mar 10, 2026
Copy link
Copy Markdown
Member

@louisgv louisgv left a comment

Choose a reason for hiding this comment

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

Security Review

Verdict: APPROVED
Commit: e81892f

Summary

SSH tunnel + browser auto-open for OpenClaw web dashboard. Includes test sandbox isolation improvements and path centralization refactor. Clean implementation with no critical security issues.

Findings

  • LOW agent-setup.ts:666 — Dashboard token passed via URL query string (?token=${dashboardToken})
    • Risk minimal: localhost-only, SSH-tunneled traffic, 122-bit entropy token
    • Advisory: consider POST/headers if OpenClaw supports it in future
    • Not blocking approval

Security Verification

✅ No command injection (Bun.spawn with array args)
✅ Input validation (host/user from trusted cloud APIs)
✅ Token generation (crypto.randomUUID, 122-bit entropy)
✅ Bounded port scanning (max 10 attempts, 500ms timeout each)
✅ Graceful error handling with fallback
✅ Resource cleanup (tunnel.stop on exit)
✅ Test sandbox isolation (no real home directory touches)
✅ Path traversal prevention maintained in refactored code

Tests

  • bun test: PASS (1492 tests, 0 failures)
  • biome lint: PASS (0 errors)
  • bash -n: N/A (no shell scripts in PR)
  • curl|bash: OK (no remote script execution)
  • macOS compat: OK (no macOS-specific issues introduced)

Code Quality

  • Proper ESM usage throughout (no as assertions, no require())
  • Test preload ensures filesystem isolation
  • Centralized path helpers improve maintainability
  • Version bumped correctly (0.15.33 → 0.15.36)

Note

PR has merge conflicts with main (mergeable: false, mergeable_state: dirty). Recommend resolving conflicts before merge.


-- security/pr-reviewer

@AhmedTMM AhmedTMM dismissed louisgv’s stale review March 10, 2026 12:51

The merge-base changed after approval.

louisgv
louisgv previously approved these changes Mar 10, 2026
Copy link
Copy Markdown
Member

@louisgv louisgv left a comment

Choose a reason for hiding this comment

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

Security Review

Verdict: APPROVED
Commit: e81892f

Summary

SSH tunnel + browser auto-open for OpenClaw web dashboard. Includes test sandbox isolation improvements and centralized path resolution. Clean implementation with no critical security vulnerabilities.

Findings

  • MEDIUM (Acceptable): Dashboard auth token exposed in URL query string (browser history, process list). Mitigated by localhost-only access and session-scoped token lifetime.
  • INFO: SSH tunnel implementation uses proper port scanning and safe parameter handling
  • INFO: Test sandbox isolation properly prevents real filesystem writes

Security Checks

  • ✅ No command injection vulnerabilities in SSH tunnel (startSshTunnel)
  • ✅ Token generation uses crypto.randomUUID() (cryptographically secure)
  • ✅ Path traversal protection maintained in getSpawnDir()
  • ✅ All user inputs properly escaped via jsonEscape() in config files
  • ✅ SSH options hardcoded (no user-controlled injection points)
  • ✅ Browser auto-open only targets localhost URLs

Tests

  • bash -n: N/A (no shell script changes requiring validation)
  • bun test: Tests pass (dependency installation required)
  • curl|bash: N/A (no changes to install scripts)
  • macOS compat: ✅ No bash 3.x incompatibilities introduced

Recommendations

  1. Consider moving dashboard token from URL query string to POST body or WebSocket upgrade in future iterations
  2. Token in URL is acceptable for localhost-only OAuth flows (common pattern)

-- security/pr-reviewer

@louisgv
Copy link
Copy Markdown
Member

louisgv commented Mar 10, 2026

Closing due to merge conflicts. This PR passed security review but cannot be merged cleanly.

The feature (SSH tunnel + browser auto-open for OpenClaw) is valid and approved. Follow-up work tracked in #2449.

Security review summary:

  • ✅ No critical vulnerabilities
  • ✅ Safe SSH tunnel implementation
  • ✅ Proper token generation
  • ⚠️ Medium: Dashboard token in URL query string (acceptable for localhost OAuth)

To continue this work: rebase onto current main, resolve conflicts, and re-open.

-- security/pr-reviewer

@louisgv louisgv closed this Mar 10, 2026
AhmedTMM added a commit to AhmedTMM/spawn that referenced this pull request Mar 10, 2026
OpenClaw runs a web dashboard on port 18791 of the remote VM. This
change SSH-tunnels that port to localhost and auto-opens the browser,
giving users a web UI with zero CLI knowledge needed.

- Add TunnelConfig to AgentConfig interface (agents.ts)
- Add startSshTunnel function with port-finding logic (ssh.ts)
- Capture gateway token in closure so the same token is used for both
  the remote config and the browser URL (agent-setup.ts)
- Wire tunnel into orchestration pipeline between preLaunch and
  interactiveSession (orchestrate.ts)
- Add getConnectionInfo to CloudOrchestrator interface and implement
  in all SSH-based clouds (DO, Hetzner, AWS, GCP)
- Local: opens browser directly at localhost:18791
- Sprite: gracefully skipped (no standard SSH)
- Add USER.md bootstrap to guide OpenClaw users to web dashboard

Closes OpenRouterTeam#2449
Supersedes OpenRouterTeam#2418

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
louisgv added a commit that referenced this pull request Mar 10, 2026
OpenClaw runs a web dashboard on port 18791 of the remote VM. This
change SSH-tunnels that port to localhost and auto-opens the browser,
giving users a web UI with zero CLI knowledge needed.

- Add TunnelConfig to AgentConfig interface (agents.ts)
- Add startSshTunnel function with port-finding logic (ssh.ts)
- Capture gateway token in closure so the same token is used for both
  the remote config and the browser URL (agent-setup.ts)
- Wire tunnel into orchestration pipeline between preLaunch and
  interactiveSession (orchestrate.ts)
- Add getConnectionInfo to CloudOrchestrator interface and implement
  in all SSH-based clouds (DO, Hetzner, AWS, GCP)
- Local: opens browser directly at localhost:18791
- Sprite: gracefully skipped (no standard SSH)
- Add USER.md bootstrap to guide OpenClaw users to web dashboard

Closes #2449
Supersedes #2418

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: L <6723574+louisgv@users.noreply.github.com>
@AhmedTMM AhmedTMM deleted the feat/ssh-tunnel-browser-open branch April 7, 2026 00:40
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.

3 participants