diff --git a/components/execd/pkg/runtime/sql.go b/components/execd/pkg/runtime/sql.go index 4eea60438..c8174e062 100644 --- a/components/execd/pkg/runtime/sql.go +++ b/components/execd/pkg/runtime/sql.go @@ -69,8 +69,7 @@ func (c *Controller) executeSelectSQLQuery(ctx context.Context, request *Execute // The SQL runtime intentionally executes the user's submitted SQL program // against the sandbox-local database; no trusted query template is composed here. - // codeql[go/sql-injection] - rows, err := c.db.QueryContext(ctx, request.Code) + rows, err := c.db.QueryContext(ctx, request.Code) // lgtm[go/sql-injection] if err != nil { request.Hooks.OnExecuteError(&execute.ErrorOutput{EName: "DBQueryError", EValue: err.Error()}) return nil @@ -136,8 +135,7 @@ func (c *Controller) executeUpdateSQLQuery(ctx context.Context, request *Execute // The SQL runtime intentionally executes the user's submitted SQL program // against the sandbox-local database; no trusted query template is composed here. - // codeql[go/sql-injection] - result, err := c.db.ExecContext(ctx, request.Code) + result, err := c.db.ExecContext(ctx, request.Code) // lgtm[go/sql-injection] if err != nil { request.Hooks.OnExecuteError(&execute.ErrorOutput{EName: "DBExecError", EValue: err.Error()}) return err diff --git a/server/opensandbox_server/services/docker_port_allocator.py b/server/opensandbox_server/services/docker_port_allocator.py index 37625bf97..87302e43e 100644 --- a/server/opensandbox_server/services/docker_port_allocator.py +++ b/server/opensandbox_server/services/docker_port_allocator.py @@ -62,6 +62,8 @@ def allocate_host_port( with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: + # This does not listen for or accept connections; it mirrors the + # later Docker publish binding to catch host-wide port conflicts. # codeql[py/bind-socket-all-network-interfaces] sock.bind((PORT_PROBE_HOST, port)) except OSError: diff --git a/server/opensandbox_server/startup_guard.py b/server/opensandbox_server/startup_guard.py index c5333d5cd..8bc0c7dd2 100644 --- a/server/opensandbox_server/startup_guard.py +++ b/server/opensandbox_server/startup_guard.py @@ -19,7 +19,7 @@ logger = logging.getLogger(__name__) -ALLOW_NO_API_KEY_ENV = "OPENSANDBOX_INSECURE_SERVER" +INSECURE_SERVER_ENV_VAR = "OPENSANDBOX_INSECURE_SERVER" ALLOW_NO_API_KEY_CONFIRMATION = "YES" ANSI_RED = "\033[31m" ANSI_RESET = "\033[0m" @@ -71,11 +71,11 @@ def api_key_confirm( env = environ if environ is not None else os.environ - if env.get(ALLOW_NO_API_KEY_ENV) == ALLOW_NO_API_KEY_CONFIRMATION: + if env.get(INSECURE_SERVER_ENV_VAR) == ALLOW_NO_API_KEY_CONFIRMATION: logger.warning( "server.api_key is not configured. Proceeding because %s explicitly acknowledges " "the insecure server mode.", - ALLOW_NO_API_KEY_ENV, + INSECURE_SERVER_ENV_VAR, ) return @@ -112,7 +112,7 @@ def api_key_confirm( raise RuntimeError( "Startup blocked: server.api_key is empty in non-interactive mode. " - f"Set {ALLOW_NO_API_KEY_ENV}={ALLOW_NO_API_KEY_CONFIRMATION} to acknowledge the risk. " + f"Set {INSECURE_SERVER_ENV_VAR}={ALLOW_NO_API_KEY_CONFIRMATION} to acknowledge the risk. " "Strongly recommend setting server.api_key. " "See: https://github.com/alibaba/OpenSandbox/issues/750" ) diff --git a/server/tests/test_docker_port_allocator.py b/server/tests/test_docker_port_allocator.py index 9ee2b5caa..f0801bffa 100644 --- a/server/tests/test_docker_port_allocator.py +++ b/server/tests/test_docker_port_allocator.py @@ -32,7 +32,7 @@ def bind(self, address): self._bound_addresses.append(address) -def test_allocate_host_port_probes_docker_publish_scope(monkeypatch) -> None: +def test_allocate_host_port_probes_docker_publish_address(monkeypatch) -> None: bound_addresses: list[tuple[str, int]] = [] monkeypatch.setattr(docker_port_allocator.random, "randint", lambda min_port, max_port: 45678) @@ -45,4 +45,12 @@ def test_allocate_host_port_probes_docker_publish_scope(monkeypatch) -> None: port = docker_port_allocator.allocate_host_port(min_port=45678, max_port=45678, attempts=1) assert port == 45678 - assert bound_addresses == [(docker_port_allocator.DOCKER_PUBLISH_HOST, 45678)] + assert bound_addresses == [(docker_port_allocator.PORT_PROBE_HOST, 45678)] + + +def test_allocate_port_bindings_keep_docker_publish_host(monkeypatch) -> None: + monkeypatch.setattr(docker_port_allocator, "allocate_host_port", lambda: 45678) + + bindings = docker_port_allocator.allocate_port_bindings(["8080"]) + + assert bindings == {"8080": (docker_port_allocator.DOCKER_PUBLISH_HOST, 45678)} diff --git a/server/tests/test_main_api_key_guard.py b/server/tests/test_main_api_key_guard.py index 02086350f..c7879becd 100644 --- a/server/tests/test_main_api_key_guard.py +++ b/server/tests/test_main_api_key_guard.py @@ -18,7 +18,7 @@ from opensandbox_server.startup_guard import ( ALLOW_NO_API_KEY_CONFIRMATION, - ALLOW_NO_API_KEY_ENV, + INSECURE_SERVER_ENV_VAR, api_key_confirm, ) @@ -34,7 +34,7 @@ def isatty(self) -> bool: def test_api_key_configured_skips_confirmation(monkeypatch): - monkeypatch.delenv(ALLOW_NO_API_KEY_ENV, raising=False) + monkeypatch.delenv(INSECURE_SERVER_ENV_VAR, raising=False) def _fail_prompt(_: str) -> str: raise AssertionError("prompt should not be called when api_key is configured") @@ -47,7 +47,7 @@ def _fail_prompt(_: str) -> str: def test_non_interactive_requires_env_ack(monkeypatch): - monkeypatch.delenv(ALLOW_NO_API_KEY_ENV, raising=False) + monkeypatch.delenv(INSECURE_SERVER_ENV_VAR, raising=False) with pytest.raises(RuntimeError) as exc_info: api_key_confirm( @@ -56,11 +56,11 @@ def test_non_interactive_requires_env_ack(monkeypatch): ) assert "Startup blocked" in str(exc_info.value) - assert ALLOW_NO_API_KEY_ENV in str(exc_info.value) + assert INSECURE_SERVER_ENV_VAR in str(exc_info.value) def test_env_ack_allows_non_interactive_start(monkeypatch): - monkeypatch.setenv(ALLOW_NO_API_KEY_ENV, ALLOW_NO_API_KEY_CONFIRMATION) + monkeypatch.setenv(INSECURE_SERVER_ENV_VAR, ALLOW_NO_API_KEY_CONFIRMATION) api_key_confirm( configured_api_key=None, @@ -69,7 +69,7 @@ def test_env_ack_allows_non_interactive_start(monkeypatch): def test_env_ack_warning_does_not_log_confirmation_value(monkeypatch): - monkeypatch.setenv(ALLOW_NO_API_KEY_ENV, ALLOW_NO_API_KEY_CONFIRMATION) + monkeypatch.setenv(INSECURE_SERVER_ENV_VAR, ALLOW_NO_API_KEY_CONFIRMATION) calls = [] def _capture_warning(message: str, *args) -> None: @@ -86,12 +86,12 @@ def _capture_warning(message: str, *args) -> None: ) assert len(calls) == 1 - assert ALLOW_NO_API_KEY_ENV in calls[0] - assert f"{ALLOW_NO_API_KEY_ENV}={ALLOW_NO_API_KEY_CONFIRMATION}" not in calls[0] + assert INSECURE_SERVER_ENV_VAR in calls[0] + assert f"{INSECURE_SERVER_ENV_VAR}={ALLOW_NO_API_KEY_CONFIRMATION}" not in calls[0] def test_tty_requires_exact_yes(monkeypatch): - monkeypatch.delenv(ALLOW_NO_API_KEY_ENV, raising=False) + monkeypatch.delenv(INSECURE_SERVER_ENV_VAR, raising=False) with pytest.raises(RuntimeError) as exc_info: api_key_confirm( @@ -104,7 +104,7 @@ def test_tty_requires_exact_yes(monkeypatch): def test_tty_yes_allows_start(monkeypatch): - monkeypatch.delenv(ALLOW_NO_API_KEY_ENV, raising=False) + monkeypatch.delenv(INSECURE_SERVER_ENV_VAR, raising=False) api_key_confirm( configured_api_key=None, @@ -114,7 +114,7 @@ def test_tty_yes_allows_start(monkeypatch): def test_tty_confirmation_timeout(monkeypatch): - monkeypatch.delenv(ALLOW_NO_API_KEY_ENV, raising=False) + monkeypatch.delenv(INSECURE_SERVER_ENV_VAR, raising=False) monkeypatch.setattr( "opensandbox_server.startup_guard.API_KEY_CONFIRM_TIMEOUT_SECONDS", 1,