Skip to content
Open
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
18 changes: 10 additions & 8 deletions hud/environment/egress.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,14 +526,16 @@ def handle(self) -> None:
_relay(self.request, upstream)


class _UnixServer(socketserver.ThreadingUnixStreamServer):
daemon_threads = True
request_queue_size = socket.SOMAXCONN

def get_request(self) -> tuple[socket.socket, tuple[str, int]]:
# A unix peer has no address; the handler wants one to log.
request, _ = super().get_request()
return request, ("workspace", 0)
if sys.platform != "win32": # the sockets this serves on have no Windows analogue

class _UnixServer(socketserver.ThreadingUnixStreamServer):
daemon_threads = True
request_queue_size = socket.SOMAXCONN

def get_request(self) -> tuple[socket.socket, tuple[str, int]]:
# A unix peer has no address; the handler wants one to log.
request, _ = super().get_request()
return request, ("workspace", 0)
Comment thread
cursor[bot] marked this conversation as resolved.


class Egress:
Expand Down
4 changes: 3 additions & 1 deletion hud/environment/namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import json
import logging
import os
import pty
import shutil
import signal
import socket
Expand All @@ -22,6 +21,9 @@
from hud.environment.utils import splice
from hud.utils.process import ProcessGroup, ProcessResult, create_process_group_exec

if sys.platform != "win32": # the pty a session runs on has no Windows analogue
import pty

_AF_NETLINK = getattr(socket, "AF_NETLINK", 16)
_NETLINK_ROUTE = getattr(socket, "NETLINK_ROUTE", 0)
LOGGER = logging.getLogger("hud.environment.namespace")
Expand Down
52 changes: 52 additions & 0 deletions hud/environment/tests/test_platform.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""Regression test for importing the package where unix sockets do not exist.

Both routes out of a workspace are served on unix sockets and a session runs on a pty,
and each reached for its platform at module scope: a
``socketserver.ThreadingUnixStreamServer`` subclass in :mod:`hud.environment.egress`,
and a top-level ``import pty`` in :mod:`hud.environment.namespace`. Neither exists on
Windows, so ``import hud`` raised there before any of it was used, taking down the
commands that never go near a workspace with it. Both now sit behind the platform
guard the rest of the package already applies.

The breakage is at import time, so the check runs in a fresh interpreter. That
interpreter imports the package once as the platform it really is, because the
standard library and the dependencies settle their own platform at their first import
and will not be told otherwise afterwards, and then imports it again with only the
package's own modules dropped, the platform reported as Windows, and the unix pieces
taken away.
"""

from __future__ import annotations

import subprocess
import sys

_IMPORT_AS_WINDOWS = """
import socketserver
import sys

import hud

for name in [n for n in sys.modules if n == "hud" or n.startswith("hud.")]:
del sys.modules[name]

sys.platform = "win32"
sys.modules["pty"] = None # a Windows interpreter has no pty module to import
socketserver.__dict__.pop("ThreadingUnixStreamServer", None) # nor this server

import hud

print("IMPORTED")
"""


def test_the_package_imports_where_unix_sockets_do_not_exist() -> None:
result = subprocess.run(
[sys.executable, "-c", _IMPORT_AS_WINDOWS],
capture_output=True,
text=True,
timeout=120,
)

assert result.returncode == 0, f"stdout={result.stdout!r}\nstderr={result.stderr!r}"
assert "IMPORTED" in result.stdout
4 changes: 3 additions & 1 deletion hud/environment/tests/test_workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from hud.capabilities import SSHClient
from hud.environment import namespace as namespace_mod
from hud.environment import workspace as workspace_mod
from hud.environment.egress import Peer, _field, _UnixServer, _Unrelayable
from hud.environment.egress import Peer, _field, _Unrelayable
from hud.environment.workspace import Bubblewrap, Mount, Workspace
from hud.utils.process import ProcessGroup, ProcessResult

Expand Down Expand Up @@ -657,6 +657,8 @@ async def spawn(argv: list[str], **kwargs: Any) -> Any:


def test_peer_forwarders_use_the_substrate_listen_backlog() -> None:
from hud.environment.egress import _UnixServer # unix-only, as this module is

assert _UnixServer.request_queue_size == socket.SOMAXCONN


Expand Down