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
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ RUN useradd --system --no-create-home --uid 1001 appuser

USER appuser

# A deployment can run the image as a uid with no passwd entry. getpass,
# and so asyncssh, reads the login name from LOGNAME first.
ENV LOGNAME=appuser

EXPOSE 8780

HEALTHCHECK --interval=60s --timeout=5s --start-period=30s --retries=3 \
Expand Down
8 changes: 5 additions & 3 deletions src/gateway/tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from core.database import async_session_factory
from gateway import server as gateway_server
from gateway.settings import GatewaySettings
from gateway.tests.localprocess import LocalProcess
from hosts.models import Host, HostStatus
from providers.base import SandboxProcess, TerminalSize
from providers.exceptions import ProviderTransportError
Expand Down Expand Up @@ -169,8 +170,6 @@ async def answer(reader, writer):

@pytest.fixture
def local_provider(monkeypatch):
from gateway.tests.localprocess import LocalProcess

provider = SimpleNamespace(gateway_process_class=LocalProcess)
monkeypatch.setattr(gateway_server, "get_vm_provider", lambda name: provider)
return LocalProcess
Expand Down Expand Up @@ -418,7 +417,9 @@ async def test_gateway_shares_one_tunnel_and_closes_it_with_the_caller(
await asyncio.wait_for(tunnel.wait_closed(), 5)


async def test_gateway_reports_a_tunnel_that_fails_to_open(forwarding_caller, sandbox_provider):
async def test_gateway_fails_only_the_channel_when_the_tunnel_fails_to_open(
forwarding_caller, sandbox_provider
):
async def refuse(name):
raise ProviderTransportError("sandboxd is not running")

Expand All @@ -427,3 +428,4 @@ async def refuse(name):
await forwarding_caller.open_connection("127.0.0.1", 80)

assert refusal.value.code == OPEN_CONNECT_FAILED
assert (await forwarding_caller.run("true", input="\n")).exit_status == 7
5 changes: 3 additions & 2 deletions src/providers/docker_sbx/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ async def delete_vm(self, name: str) -> None:

async def open_gateway_tunnel(self, name: str) -> asyncssh.SSHClientConnection:
# sandboxd authenticates the OS user on its local socket, and sbx itself
# trusts the host key on first use. No key crosses a network.
# trusts the host key on first use. No key crosses a network. asyncssh
# raises ValueError when the local login name is unknown.
try:
return await asyncssh.connect(
f"{name}.sbx",
Expand All @@ -168,7 +169,7 @@ async def open_gateway_tunnel(self, name: str) -> asyncssh.SSHClientConnection:
agent_path=None,
preferred_auth="none",
)
except (OSError, asyncssh.Error) as exc:
except (OSError, ValueError, asyncssh.Error) as exc:
raise ProviderTransportError(f"sbx could not open a tunnel: {exc}") from exc

async def build_template_image(
Expand Down
13 changes: 13 additions & 0 deletions src/providers/docker_sbx/tests/test_provider.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import getpass
from pathlib import Path
from typing import Any
from unittest.mock import AsyncMock, MagicMock
Expand Down Expand Up @@ -278,3 +279,15 @@ async def test_delete_template_image_translates_a_missing_template(tmp_path):

with pytest.raises(ProviderNotFoundError, match="was not found"):
await provider.delete_template_image("drukbox-template:missing")


@pytest.mark.asyncio
async def test_open_gateway_tunnel_translates_an_unknown_local_login_name(tmp_path, monkeypatch):
def unknown_uid():
raise KeyError("getpwuid(): uid not found: 1000")

monkeypatch.setattr(getpass, "getuser", unknown_uid)
provider = _provider(_api_mock(), _settings(tmp_path))

with pytest.raises(ProviderTransportError):
await provider.open_gateway_tunnel("sb-test")
Loading