Add CORS origins support to Docker sandbox service for remote browser access (#12489)

Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
Tim O'Farrell
2026-01-18 08:02:29 -07:00
committed by GitHub
parent 0176cd9669
commit 9fd4e42438
4 changed files with 143 additions and 4 deletions

View File

@@ -27,6 +27,9 @@ from openhands.app_server.sandbox.sandbox_models import (
SandboxStatus,
)
from openhands.app_server.sandbox.sandbox_service import (
ALLOW_CORS_ORIGINS_VARIABLE,
SESSION_API_KEY_VARIABLE,
WEBHOOK_CALLBACK_VARIABLE,
SandboxService,
SandboxServiceInjector,
)
@@ -37,8 +40,6 @@ from openhands.app_server.utils.docker_utils import (
)
_logger = logging.getLogger(__name__)
SESSION_API_KEY_VARIABLE = 'OH_SESSION_API_KEYS_0'
WEBHOOK_CALLBACK_VARIABLE = 'OH_WEBHOOKS_0_BASE_URL'
STARTUP_GRACE_SECONDS = 15
@@ -79,6 +80,7 @@ class DockerSandboxService(SandboxService):
health_check_path: str | None
httpx_client: httpx.AsyncClient
max_num_sandboxes: int
web_url: str | None = None
extra_hosts: dict[str, str] = field(default_factory=dict)
docker_client: docker.DockerClient = field(default_factory=get_docker_client)
startup_grace_seconds: int = STARTUP_GRACE_SECONDS
@@ -326,6 +328,12 @@ class DockerSandboxService(SandboxService):
f'http://host.docker.internal:{self.host_port}/api/v1/webhooks'
)
# Set CORS origins for remote browser access when web_url is configured.
# This allows the agent-server container to accept requests from the
# frontend when running OpenHands on a remote machine.
if self.web_url:
env_vars[ALLOW_CORS_ORIGINS_VARIABLE] = self.web_url
# Prepare port mappings and add port environment variables
port_mappings = {}
for exposed_port in self.exposed_ports:
@@ -524,10 +532,15 @@ class DockerSandboxServiceInjector(SandboxServiceInjector):
) -> AsyncGenerator[SandboxService, None]:
# Define inline to prevent circular lookup
from openhands.app_server.config import (
get_global_config,
get_httpx_client,
get_sandbox_spec_service,
)
# Get web_url from global config for CORS support
config = get_global_config()
web_url = config.web_url
async with (
get_httpx_client(state) as httpx_client,
get_sandbox_spec_service(state) as sandbox_spec_service,
@@ -542,6 +555,7 @@ class DockerSandboxServiceInjector(SandboxServiceInjector):
health_check_path=self.health_check_path,
httpx_client=httpx_client,
max_num_sandboxes=self.max_num_sandboxes,
web_url=web_url,
extra_hosts=self.extra_hosts,
startup_grace_seconds=self.startup_grace_seconds,
)

View File

@@ -36,6 +36,8 @@ from openhands.app_server.sandbox.sandbox_models import (
SandboxStatus,
)
from openhands.app_server.sandbox.sandbox_service import (
ALLOW_CORS_ORIGINS_VARIABLE,
WEBHOOK_CALLBACK_VARIABLE,
SandboxService,
SandboxServiceInjector,
)
@@ -48,8 +50,6 @@ from openhands.app_server.utils.sql_utils import Base, UtcDateTime
from openhands.sdk.utils.paging import page_iterator
_logger = logging.getLogger(__name__)
WEBHOOK_CALLBACK_VARIABLE = 'OH_WEBHOOKS_0_BASE_URL'
ALLOW_CORS_ORIGINS_VARIABLE = 'OH_ALLOW_CORS_ORIGINS_0'
polling_task: asyncio.Task | None = None
POD_STATUS_MAPPING = {
'ready': SandboxStatus.RUNNING,

View File

@@ -18,6 +18,10 @@ from openhands.app_server.utils.docker_utils import (
from openhands.sdk.utils.models import DiscriminatedUnionMixin
from openhands.sdk.utils.paging import page_iterator
SESSION_API_KEY_VARIABLE = 'OH_SESSION_API_KEYS_0'
WEBHOOK_CALLBACK_VARIABLE = 'OH_WEBHOOKS_0_BASE_URL'
ALLOW_CORS_ORIGINS_VARIABLE = 'OH_ALLOW_CORS_ORIGINS_0'
class SandboxService(ABC):
"""Service for accessing sandboxes in which conversations may be run."""