OpenHands / OpenHands/enterprise

Kubernetes runtimes need separate public, control, and callback URLs

Open
#285 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
Python
Stars
4
Forks
2
Avg merge
1d 22h
Merged PRs (30d)
101

Description

Summary

Self-hosted Kubernetes deployments need separate URLs for:

  1. browser-facing access to a sandbox through ingress/Gateway API; and
  2. trusted server-side control traffic from OpenHands and runtime-api directly to the runtime's cluster-local Service.

The current remote-runtime contract exposes only runtime["url"]. OpenHands uses that same URL both as a browser-facing exposed URL and for server-side agent-server health/control calls. This forces trusted control traffic through public ingress, where the originating workload identity may be replaced by the ingress proxy identity and the full agent-server API must be reachable on the browser data plane.

The callback side has a related coupling: sandbox webhook, provider-secret lookup, and default MCP URLs are constructed from the public web_url. An isolated sandbox may need a distinct internal-only callback hostname while the browser continues using the public application hostname.

Affected versions

  • OpenHands Enterprise 1.56.0
  • Current main at 338d41ee584ea4f7db27ac425cc0d75364d2c5ef

Current behavior

Why this matters

A secure Kubernetes deployment may intentionally enforce all of the following:

  • browser traffic reaches a runtime only through authenticated ingress;
  • OpenHands core and runtime-api reach agent-server directly through a cluster-local Service;
  • workload identity is preserved for server-side network policy;
  • sandbox RFC1918 access is denied by default;
  • sandbox callbacks can reach one narrow internal Gateway without gaining broad private-network access;
  • callback, secret-lookup, and MCP requests retain their existing application-layer authentication.

The single URL/public-host coupling makes those requirements conflict.

Requested contract

One possible backward-compatible shape would be:

  • public_url: returned to browser-facing consumers and used to derive VS Code/worker URLs;
  • control_url: used only by runtime-api and OpenHands for /alive and the full server-side agent API;
  • a separately configurable sandbox callback base URL used for OH_WEBHOOKS_0_BASE_URL, provider-secret lookup, and default MCP construction;
  • existing url/web_url behavior retained as fallback when the new values are absent.

The runtime-api should perform readiness checks against the control URL when configured. OpenHands should retain the public URL in exposed browser metadata while all server-side agent calls prefer the control URL.

Acceptance criteria

  • A Kubernetes runtime can advertise both a public ingress URL and a cluster-local control URL.
  • runtime-api readiness and OpenHands server-side agent calls use the control URL.
  • browser-facing sandbox/worker links continue to use the public URL.
  • sandbox webhook, provider-secret lookup, and default MCP URLs can use a callback base distinct from the public application URL.
  • existing deployments that provide only the current URL fields remain compatible.
  • tests prove the public and control paths cannot be accidentally interchanged.

No private IPs, credentials, tokens, or deployment-specific hostnames are included in this report.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in openhands/app_server/sandbox/remote_sandbox_service.py at _to_sandbox_info() and the webhook URL construction, then trace the /alive checks in sandbox_service.py. Review the provider-secret and default MCP URL callers in live_status_app_conversation_service.py, along with the runtime-api readiness path. Done means public, control, and callback URLs remain distinct, legacy fields still fall back correctly, and tests prevent path interchange.

Written by the indexing model from the issue text.

Assessment

Tech stack
kubernetes, python
Domain
backend-api-design, cloud, infrastructure
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.