feat: SSH tunnel + browser auto-open for OpenClaw web dashboard#2418
feat: SSH tunnel + browser auto-open for OpenClaw web dashboard#2418AhmedTMM wants to merge 9 commits intoOpenRouterTeam:mainfrom
Conversation
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
left a comment
There was a problem hiding this comment.
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
|
Security review complete — code approved! However, this PR has merge conflicts and needs to be rebased on current Please run: git fetch origin
git rebase origin/main
git push --force-with-leaseOnce conflicts are resolved, this will be ready to merge. -- security/pr-reviewer |
…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>
|
Merge conflicts resolved and rebased onto current main (e396a61). Changes:
Verification:
Note: The force-push dismissed the original approval. This PR needs re-approval before merging. -- refactor/pr-maintainer |
louisgv
left a comment
There was a problem hiding this comment.
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
asassertions, norequire()) - Test preload ensures filesystem isolation
- Centralized path helpers improve maintainability
- Version bumped correctly (0.15.33 → 0.15.36)
-- security/pr-reviewer
The merge-base changed after approval.
louisgv
left a comment
There was a problem hiding this comment.
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
The merge-base changed after approval.
louisgv
left a comment
There was a problem hiding this comment.
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
asassertions, norequire()) - 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
The merge-base changed after approval.
louisgv
left a comment
There was a problem hiding this comment.
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
- Consider moving dashboard token from URL query string to POST body or WebSocket upgrade in future iterations
- Token in URL is acceptable for localhost-only OAuth flows (common pattern)
-- security/pr-reviewer
The merge-base changed after approval.
|
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:
To continue this work: rebase onto current main, resolve conflicts, and re-open. -- security/pr-reviewer |
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>
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>
Summary
?token=parametergetConnectionInfo()to theCloudOrchestratorinterface, implemented by all SSH-based clouds (DigitalOcean, Hetzner, AWS, GCP)Test plan
bunx @biomejs/biome check src/— 0 errorsbun test— 1415 tests pass, 0 failuresspawn run digitalocean openclaw— browser should open to web dashboardspawn run local openclaw— browser opens to localhost:18791 directly🤖 Generated with Claude Code