Repository navigation
feat(supervisor): add an independent sandbox application listener #4666
Description
- Parent: Sandbox Service Exposure #4310
- Dependencies: current main only.
User Story
I run OpenShell sandboxes that include an addressable service. I need HTTP and WebSocket traffic to reach the owning supervisor without carrying application payloads through the gateway, while keeping sandbox isolation and application authentication effective.
Problem Statement
Application requests currently use the gateway relay path. A supervisor needs an application-only listener that can serve declared sandbox services independently of the gateway management connection.
Impact / Why This Matters
Application traffic competes with control-plane traffic, and operators cannot validate a direct supervisor ingress path independently of a discovery router.
Proposed Design
Add an opt-in supervisor TLS listener supporting HTTP/1.1 and WebSockets, separate from gateway ingress. The supervisor app-listener enabled flag defaults to false and controls actual listener availability. Enabling the app listener does not disable gateway ingress or reuse gateway user authentication. Applications or a trusted ingress edge provide the new listener's client authentication. Use existing service declarations, delivered through sandbox settings, as the ingress allowlist. Reach only their declared loopback ports through the backend RPC client. Preserve the validated public Host and browser Origin. Retain existing bearer stripping/passthrough and removal of gateway/edge identity headers and cookies.
Provide the Kubernetes listener configuration, TLS Secret mount, and a supervisor-only headless Service owned by the sandbox. Operators provide TLS, reachability, and ingress network rules. Service configuration changes refresh the listener without restarting the workload. Removal, replacement, rejected configuration, or lease expiry revokes affected streams.
This issue excludes route advertisements, discovery RPCs/storage, the reference proxy, and new CLI/SDK URL/status modes. Existing gateway service behavior stays available. Direct requests to an explicitly configured supervisor endpoint are sufficient to demonstrate this stage.
Suggested UX
Proposed configuration for this feature: Omitting the section or setting enabled = false leaves the listener disabled. Base configuration and Helm defaults use false; only explicit development/test profiles opt in. Setting port/domain or driver TLS/Service options alone must not enable the listener.
An explicitly enabled test configuration:
[openshell.supervisor.app_listener]
enabled = true
port = 8443
domain = "services.example.com"
[openshell.drivers.kubernetes.sandbox_runtime.app_listener]
tls_secret_name = "openshell-app-tls"
create_service = trueThe common port configures the supervisor listener and the matching container/headless Service endpoint. Discovery later advertises this same port; it is independent of any public load-balancer port. Do not require a second driver port setting.
Continue using openshell service expose app-sandbox 8080. For the direct smoke test, connect to the supervisor endpoint with SNI/Host default--app-sandbox.services.example.com. Automatic public URL publication is handled in #4670.
Acceptance Criteria
- Omitted configuration and explicit
enabled = falseboth disable the listener, including when port/domain and driver options are present. - Disabled configuration creates no app-listener socket, app-specific TLS mount, or app headless Service; existing supervisor/control and gateway ingress remain available.
- Base configuration and Helm defaults disable the listener; development/test profiles must explicitly enable it.
- Common enabled/port/domain configuration is under the supervisor app-listener table; driver deployment details remain driver-owned.
- Listener startup and Kubernetes container/Service ports derive from the common app-listener port; no duplicate driver port is required.
- Nondefault ports work; invalid ports, bind conflicts, and inconsistent endpoint/TLS configuration fail clearly.
- Authentication of supervisor service-ingress requests remains independent from gateway user authentication, with separate tests for each path.
- Declared named and unnamed HTTP services and WebSockets work through the real backend RPC path.
- Unknown SNI, Host/SNI mismatch, undeclared ports, and expired configuration cannot dial a sandbox service.
- Public Host/Origin and application session cookies survive forwarding; browser login, CSRF checks, and WebSocket origin checks remain effective.
- Removing/editing one service closes its streams without dropping unrelated services; stale routes cannot revive after recreation.
- Listener lifetime follows the workload, and connection/parser/connect work is bounded.
- Kubernetes endpoints select only the paired supervisor, enforce ownership, follow stop/start, and disappear with the sandbox.
- Direct in-cluster Service reachability and the browser-facing path are tested; port-forward-only evidence is insufficient.
- This stage builds and passes without a proxy binary or service discovery RPCs.
Verification Plan
- Configuration and rendering tests cover omitted configuration, explicit false, and explicit true. Include false with otherwise complete listener/driver settings to catch accidental enablement. Assert the parsed default and rendered supervisor environment, container ports, TLS mounts, and Service resources.
- Supervisor integration tests use a real TLS client and backend RPC connector. With the listener disabled, assert no listener task/socket is created. With it enabled, send HTTP and WebSocket traffic to declared services. Assert unknown SNI, mismatched Host, and undeclared ports are rejected before any backend dial. Verify public Host/Origin, application cookies, CSRF checks, and selective stream revocation using a controlled application fixture.
- Kubernetes integration tests exercise omitted, false, and true configurations, including a nondefault listener port. Verify direct traffic from another pod through the headless Service, TLS/SNI, supervisor-only selection, ownership, and cleanup after sandbox deletion. Verify disabling the feature and recreating a sandbox removes its owned app endpoints without affecting unrelated resources.
- Exercise the existing gateway ingress path in both disabled and enabled runs. Its HTTP/WebSocket behavior must remain available independently of the new listener. Gateway user authorization requires its own tests and scope.
- Run these checks on the branch implementing this issue against main, without discovery RPCs or the proxy. Record commands and results in the PR. Verify this issue independently of later discovery and proxy work. Browser smoke tests supplement automated checks.
Alternatives Considered
A separate gateway listener still carries application payloads through the gateway. Shipping the proxy first couples the listener to discovery deployment. Middleware, interceptors, and providers do not provision the independent listener or the sandbox loopback transport.
Agent Investigation
Use service configuration snapshots to supply the declared-service allowlist. Listener startup and test fixtures must work without route advertisements or discovery. The backend connector is openshell_sandbox_backend::BoundaryLoopbackConnector.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsIn progress
Activity