Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions components/execd/pkg/runtime/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions server/opensandbox_server/services/docker_port_allocator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
8 changes: 4 additions & 4 deletions server/opensandbox_server/startup_guard.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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"
)
12 changes: 10 additions & 2 deletions server/tests/test_docker_port_allocator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)}
22 changes: 11 additions & 11 deletions server/tests/test_main_api_key_guard.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)

Expand All @@ -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")
Expand All @@ -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(
Expand All @@ -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,
Expand All @@ -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:
Expand All @@ -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(
Expand All @@ -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,
Expand All @@ -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,
Expand Down
Loading