Skip to content

feat(server): WebSocket proxy for bash sessions through opensandbox-server #537

@ctlaltlaltc

Description

@ctlaltlaltc

Summary

Ref #455 the execd component already exposes a full interactive bash session API over WebSocket (GET /ws/session/:sessionId), but the opensandbox-server currently rejects WebSocket upgrades with a 400 error. This means clients that route through the server (K8s, NAT, cloud deployments) cannot reach bash sessions.

This issue tracks adding a transparent WebSocket proxy route to the server.

User Cases

UC-1 — Interactive terminal in cloud / Kubernetes

A developer uses the Python SDK with use_server_proxy=True (the default in K8s).
They want to open an interactive bash terminal inside the sandbox.
Today this fails. After this change they connect via:

WS /sandboxes/{id}/proxy/8080/ws/session/{sessionId}?pty=1

and get a fully functional PTY-backed terminal.

UC-2 — Agent scripting with stateful sessions

An AI agent creates a bash session, runs multiple commands in sequence (state preserved between commands), and reads streaming output — all through the server proxy.

UC-3 — Reconnect / replay after network blip

A client disconnects briefly. On reconnect it passes ?since=<offset> and the server transparently forwards it to execd's replay buffer, so no output is lost.

Implementation Scope

File Change
server/pyproject.toml Add websockets>=13.0 dependency
server/src/api/lifecycle.py New @router.websocket("/sandboxes/{id}/proxy/{port}/{path}") handler with bidirectional frame relay
server/tests/test_routes_proxy.py 7 new unit tests covering text/binary relay, query forwarding, header filtering, error codes

Key design decisions:

  • Resolve sandbox endpoint before accept() so a 1008 close can be sent without accepting
  • Filter Authorization, Cookie, and WS handshake headers; forward custom headers and endpoint egress-auth token
  • Python 3.10-compatible (asyncio.wait instead of TaskGroup)
  • Existing HTTP proxy 400-guard for non-WS-upgrade probes is preserved

Out of Scope

  • SDK-level bash_session() helper method (follow-up issue)
  • Authentication on the WebSocket proxy path (proxy paths are already auth-exempt, consistent with HTTP proxy)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions