Skip to content

fix(frontend): stop frontend bash probes on cloud runtimes#761

Merged
hieptl merged 2 commits into
mainfrom
hieptl/app-1926
May 26, 2026
Merged

fix(frontend): stop frontend bash probes on cloud runtimes#761
hieptl merged 2 commits into
mainfrom
hieptl/app-1926

Conversation

@hieptl
Copy link
Copy Markdown
Contributor

@hieptl hieptl commented May 26, 2026

  • A human has tested these changes.

Why

Description

When a user is connected to a Cloud backend (e.g. OpenHands Cloud production) and creates a new conversation, the frontend immediately fires /api/bash/execute_bash_command on the cloud runtime to probe git metadata. The cwd in that request is a local filesystem path read from localStorage (e.g. /Users/<user>/.openhands/agent-canvas/workspaces), which leaks the host filesystem layout to the cloud runtime and resolves to nothing meaningful there.

Steps to reproduce

  1. npm run dev in agent-canvas.
  2. Open the <BackendSelector /> and click Add Backend.
  3. Configure a Cloud backend pointing at OpenHands Cloud production with a Personal Workspace API key.
  4. Switch to the cloud backend, create a new conversation, send a message.
  5. In the Network panel, observe:
POST http://<runtime-host>.staging-runtime.all-hands.dev/api/bash/execute_bash_command
{
  "command": "git remote get-url origin",
  "cwd": "/Users/<user>/.openhands/agent-canvas/workspaces",
  "timeout": 10
}

Expected behavior

/api/bash/execute_bash_command is not driven by the frontend on cloud backends. Cloud uses conversation metadata (selected_repository, git_provider, selected_branch) as the source of truth for the chat's git control bar.

Root cause

useLocalGitInfo (src/hooks/query/use-local-git-info.ts) and useHasGitCommits (src/hooks/query/use-has-git-commits.ts) had no backend-kind gate on their enabled predicate. On cloud, AgentServerRuntimeService.executeCommand routes through callCloudProxy to /api/bash/execute_bash_command. useLocalGitInfo additionally falls back to getAgentServerWorkingDir() (local config) when the conversation's workspace.working_dir is missing — that's the leak path.

Fix

Gate both hooks on backend.kind === "local". useWorkspaceFiles is intentionally left untouched (it powers the Files tab's file-list sub-view; needs a cloud-native replacement endpoint as a follow-up).

Acceptance criteria

  • No /api/bash/execute_bash_command requests are issued from the frontend when the active backend is cloud.
  • The git control bar on cloud still renders repo/branch/provider from conversation metadata.
  • Local-backend conversations continue to probe git remote get-url origin / git rev-parse --abbrev-ref HEAD / git rev-parse --verify HEAD as before.
  • Tests cover both the cloud-disabled and local-enabled paths for each hook.

Summary

  • Gate useLocalGitInfo and useHasGitCommits on backend.kind === "local" so the frontend no longer drives /api/bash/execute_bash_command on cloud runtimes.
  • Eliminates a privacy/leak bug where the user's local FS path (from getAgentServerWorkingDir() localStorage) was sent as cwd to a cloud sandbox.
  • Cloud git metadata continues to come from the conversation payload (selected_repository, git_provider, selected_branch) — no UX regression in the chat's git control bar.
  • useWorkspaceFiles is intentionally not gated; it powers the Files tab's file-list sub-view and there is no cloud-native replacement endpoint yet. Tracked as a follow-up.

Root cause

AgentServerRuntimeService.executeCommand is cloud-aware: on cloud it routes through callCloudProxy to /api/bash/execute_bash_command. The two probe hooks called this service with no backend gate, so they fired on cloud immediately after a new conversation was created. useLocalGitInfo made it worse by falling back to getAgentServerWorkingDir() (a local-machine path read from localStorage) when the cloud conversation hadn't yet populated workspace.working_dir, leaking that host path to the remote runtime.

Changes

  • src/hooks/query/use-local-git-info.ts
    • Import useActiveBackend, derive isLocalBackend, and AND it into the enabled predicate.
    • Tighten the docblock: explicit "local-only" intent, and rationale (leak + invariant).
  • src/hooks/query/use-has-git-commits.ts
    • Same gate pattern + docblock note. On cloud, hasCommits stays null and the Files tab keeps its optimistic diff-view default — fine in practice since cloud conversations almost always have an attached repo with commits.
  • __tests__/hooks/query/use-local-git-info.test.tsx (new)
    • Cloud backend + incomplete metadata → executeCommand not called (regression test).
    • Local backend + incomplete metadata → executeCommand called with the expected git probe and parsed result.
  • __tests__/hooks/query/use-has-git-commits.test.tsx (new)
    • Cloud backend → executeCommand not called; hasCommits is null.
    • Local backend → executeCommand called for git rev-parse --verify HEAD; hasCommits resolves to true.

Issue Number

Resolves #760

How to Test

  1. npm run dev in agent-canvas.
  2. Open the <BackendSelector /> and click Add Backend.
  3. Configure a Cloud backend pointing at OpenHands Cloud production with a Personal Workspace API key.
  4. Switch to the cloud backend, create a new conversation, send a message.
  5. In the Network panel, observe:
POST http://<runtime-host>.staging-runtime.all-hands.dev/api/bash/execute_bash_command
{
  "command": "git remote get-url origin",
  "cwd": "/Users/<user>/.openhands/agent-canvas/workspaces",
  "timeout": 10
}

Type

  • Bug fix
  • Feature
  • Refactor
  • Breaking change
  • Docs / chore

🐳 Docker images for this PR

GHCR package: https://github.com/OpenHands/agent-canvas/pkgs/container/agent-canvas

Component Value
Image ghcr.io/openhands/agent-canvas
Architectures amd64, arm64
Agent Server ghcr.io/openhands/agent-server:1.23.0-python
Automation openhands-automation==1.0.0a3
Commit 6a8534cade7c585de432bfff711ad02ef038ddac

Pull (multi-arch manifest)

# Multi-arch manifest — Docker automatically pulls the correct architecture
docker pull ghcr.io/openhands/agent-canvas:sha-6a8534c

Run

docker run -it --rm \
  -p 8000:8000 \
  ghcr.io/openhands/agent-canvas:sha-6a8534c

All tags pushed for this build

ghcr.io/openhands/agent-canvas:sha-6a8534c-amd64
ghcr.io/openhands/agent-canvas:hieptl-app-1926-amd64
ghcr.io/openhands/agent-canvas:pr-761-amd64
ghcr.io/openhands/agent-canvas:sha-6a8534c-arm64
ghcr.io/openhands/agent-canvas:hieptl-app-1926-arm64
ghcr.io/openhands/agent-canvas:pr-761-arm64
ghcr.io/openhands/agent-canvas:sha-6a8534c
ghcr.io/openhands/agent-canvas:hieptl-app-1926
ghcr.io/openhands/agent-canvas:pr-761

About Multi-Architecture Support

  • Each tag (e.g., sha-6a8534c) is a multi-arch manifest supporting both amd64 and arm64
  • Docker automatically pulls the correct architecture for your platform
  • Individual architecture tags (e.g., sha-6a8534c-amd64) are also available if needed

@hieptl hieptl self-assigned this May 26, 2026
@vercel
Copy link
Copy Markdown

vercel Bot commented May 26, 2026

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

Project Deployment Actions Updated (UTC)
agent-canvas Ready Ready Preview, Comment May 26, 2026 7:37am

Request Review

Copy link
Copy Markdown
Contributor

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

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

Taste Rating: 🟢 Good taste — Clean, targeted fix for a real privacy/security issue.

VERDICT: ✅ Worth merging

KEY INSIGHT: The fix correctly gates local filesystem probes to prevent leaking host paths to cloud runtimes while preserving the existing fallback chain in consumers (conversation metadata → local git info → undefined).


[RISK ASSESSMENT]

  • [Overall PR] Risk Assessment: 🟢 LOW

This is a surgical bug fix that prevents leaking local filesystem paths to cloud runtimes. Changes are minimal (just adding backend kind gates), well-tested, and cause no breaking changes. Cloud backends already rely on conversation metadata as the source of truth; local behavior is unchanged. Consumer code (git-control-bar.tsx) already handles the fallback chain correctly.


Was this automated review useful? React with 👍 or 👎 to this review to help us measure review quality.
Workflow run: https://github.com/OpenHands/agent-canvas/actions/runs/26438260977

@github-actions
Copy link
Copy Markdown
Contributor

📸 Snapshot Test Report

✅ All snapshots match the main branch baselines.

Category Count
🔴 Changed 0
🆕 New 0
✅ Unchanged 73
Total 73
✅ Unchanged snapshots (73)

archived-conversation

  • conversation-panel-with-archived-badges
  • conversation-view-archived
  • conversation-view-sandbox-error

automations

  • automations-delete-modal
  • automations-list-active-inactive
  • automations-no-automations
  • automations-search-no-results

backends-extended

  • backend-add-blank-disabled
  • backend-add-cloud-advanced-open
  • backend-add-cloud-no-key-disabled
  • backend-add-cloud-with-key-enabled
  • backend-add-form-partially-filled
  • backend-add-invalid-url-disabled
  • backend-add-local-ready
  • backend-add-name-only-disabled
  • backend-add-two-column-layout
  • backend-add-whitespace-host-disabled
  • backend-after-switch
  • backend-cancel-nothing-saved
  • backend-dropdown-two-backends
  • backend-edit-prefilled
  • backend-manage-after-removal
  • backend-manage-two-listed
  • backend-remove-cancelled
  • backend-remove-confirmation
  • backend-switch-overlay

backends

  • backend-add-modal
  • backend-manage-modal
  • backend-selector-open

changes-tab

  • changes-deleted-file
  • changes-diff-viewer
  • changes-empty

collapsible-thinking

  • reasoning-content-collapsed
  • reasoning-content-expanded
  • think-action-collapsed
  • think-action-expanded

mcp-page

  • mcp-custom-server-1-editor-open
  • mcp-custom-server-2-url-filled
  • mcp-custom-server-3-all-filled
  • mcp-custom-server-4-installed
  • mcp-custom-server-editor
  • mcp-empty-installed
  • mcp-search-filtered
  • mcp-slack-install-1-marketplace
  • mcp-slack-install-2-modal
  • mcp-slack-install-3-filled
  • mcp-slack-install-4-installed

onboarding

  • onboarding-step-0-choose-agent
  • onboarding-step-1-check-backend
  • onboarding-step-2-setup-llm
  • onboarding-step-3-say-hello

projects-workspace-browser

  • projects-workspace-browser

settings-page

  • add-backend-modal
  • analytics-consent-modal
  • home-screen
  • settings-app-page
  • settings-page

settings-secrets

  • secrets-add-form-filled
  • secrets-add-form
  • secrets-after-save
  • secrets-delete-confirm
  • secrets-list

settings-verification

  • condenser-settings
  • verification-settings-off
  • verification-settings-on

sidebar

  • sidebar-collapsed
  • sidebar-conversation-panel
  • sidebar-filter-menu

skills-page

  • skills-empty
  • skills-loaded
  • skills-no-match
  • skills-search-filtered
  • skills-type-filter

Generated by the Snapshot Tests workflow. This comment was created by an AI agent (OpenHands) on behalf of the repo maintainers.

@hieptl hieptl merged commit 9d652d7 into main May 26, 2026
14 checks passed
@hieptl hieptl deleted the hieptl/app-1926 branch May 26, 2026 08:18
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.

Cloud conversations leak local FS path through /api/bash/execute_bash_command git probe

2 participants