From 91c0e320355c649fa7901d4a61cbbf2333916d24 Mon Sep 17 00:00:00 2001 From: Junghwan <70629228+shaun0927@users.noreply.github.com> Date: Fri, 17 Apr 2026 19:55:25 +0900 Subject: [PATCH] fix(sandbox): fail closed for unsupported Docker domain policies (#152) The Docker backend currently turns any non-empty allowed_domains list into unrestricted bridge networking even though no per-domain enforcement exists. Keep Docker networking disabled and emit a warning until the backend can actually honor domain policies. Constraint: Preserve a small, reviewable fix instead of designing a full Docker egress filter Rejected: Keep bridge networking with docs-only clarification | leaves silently overbroad behavior in place Confidence: high Scope-risk: narrow Reversibility: clean Directive: If Docker domain policies are re-enabled later, add true enforcement before widening network access Tested: PYTHONPATH=src pytest -q tests/test_sandbox/test_docker_backend.py tests/test_sandbox/test_adapter.py Tested: PYTHONPATH=src ruff check src tests Not-tested: Full pytest suite in this environment (collection fails because optional pyperclip dependency is missing) Related: #150 --- src/openharness/sandbox/docker_backend.py | 15 ++++++++++----- tests/test_sandbox/test_docker_backend.py | 10 +++++++--- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/openharness/sandbox/docker_backend.py b/src/openharness/sandbox/docker_backend.py index 41053c1..956cc62 100644 --- a/src/openharness/sandbox/docker_backend.py +++ b/src/openharness/sandbox/docker_backend.py @@ -95,11 +95,16 @@ class DockerSandboxSession: self._container_name, ] - # Network isolation - if sandbox.network.allowed_domains: - argv.extend(["--network", "bridge"]) - else: - argv.extend(["--network", "none"]) + # Docker backend currently supports only fully disabled networking. + # Domain-level allow/deny policies exist for the srt backend, but Docker + # does not enforce them yet. Fail closed instead of silently widening + # egress to unrestricted bridge networking. + if sandbox.network.allowed_domains or sandbox.network.denied_domains: + logger.warning( + "Docker sandbox does not enforce allowed_domains/denied_domains yet; " + "keeping network disabled" + ) + argv.extend(["--network", "none"]) # Resource limits if docker_cfg.cpu_limit > 0: diff --git a/tests/test_sandbox/test_docker_backend.py b/tests/test_sandbox/test_docker_backend.py index add36b7..33b042d 100644 --- a/tests/test_sandbox/test_docker_backend.py +++ b/tests/test_sandbox/test_docker_backend.py @@ -134,7 +134,7 @@ def test_network_none_by_default(monkeypatch): assert argv[net_idx + 1] == "none" -def test_network_bridge_when_domains_allowed(monkeypatch): +def test_network_none_and_warning_when_domain_policy_is_configured(monkeypatch, caplog): monkeypatch.setattr( "openharness.sandbox.docker_backend.shutil.which", lambda name: "/usr/bin/docker", @@ -143,7 +143,10 @@ def test_network_bridge_when_domains_allowed(monkeypatch): sandbox=SandboxSettings( enabled=True, backend="docker", - network=SandboxNetworkSettings(allowed_domains=["github.com"]), + network=SandboxNetworkSettings( + allowed_domains=["github.com"], + denied_domains=["example.com"], + ), ) ) session = DockerSandboxSession(settings=settings, session_id="abc", cwd=Path("/repo")) @@ -151,7 +154,8 @@ def test_network_bridge_when_domains_allowed(monkeypatch): argv = session._build_run_argv() net_idx = argv.index("--network") - assert argv[net_idx + 1] == "bridge" + assert argv[net_idx + 1] == "none" + assert "does not enforce allowed_domains/denied_domains yet" in caplog.text def test_resource_limits_applied(monkeypatch):