Some checks failed
ci / validate (push) Has been cancelled
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0726e-5232-73f2-aaca-2c05ceb62efb
175 lines
6.4 KiB
Python
175 lines
6.4 KiB
Python
import json
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
from glas_harness.contract import SandboxHandle
|
|
from glas_harness.transport import ExecutionTransport, TransportError, transport_from_sandbox
|
|
|
|
|
|
def test_local_namespace_transport_requires_pid_and_workspace(tmp_path: Path) -> None:
|
|
sandbox = SandboxHandle(
|
|
sandbox_id="sbx",
|
|
host="localhost",
|
|
reachability={"pid": "4321", "workspace_dir": str(tmp_path)},
|
|
)
|
|
sandbox._owner_execute = MagicMock(return_value=MagicMock(
|
|
timed_out=False, output_truncated=False, exit_code=0, stdout="ok", stderr=""
|
|
))
|
|
transport = transport_from_sandbox(sandbox)
|
|
assert transport.kind == "local_namespace"
|
|
assert transport.workspace == str(tmp_path)
|
|
with patch("glas_harness.transport.subprocess.run") as run:
|
|
assert transport.run(["git", "status"], timeout=30).stdout == "ok"
|
|
run.assert_not_called()
|
|
sandbox._owner_execute.assert_called_once_with(["git", "status"], None, 30)
|
|
with pytest.raises(TransportError, match="owner execution"):
|
|
transport.command(["git", "status"])
|
|
|
|
|
|
def test_remote_transport_wraps_command_without_local_shell() -> None:
|
|
sandbox = SandboxHandle(
|
|
sandbox_id="sbx",
|
|
host="sandboxer01",
|
|
reachability={"ssh": "agent@sandboxer01", "remote_dir": "/tmp/sbx"},
|
|
)
|
|
transport = transport_from_sandbox(sandbox)
|
|
|
|
assert transport.kind == "ssh"
|
|
assert transport.command(["git", "-C", "/tmp/sbx", "status"]) == [
|
|
"ssh",
|
|
"--",
|
|
"agent@sandboxer01",
|
|
"sh -c 'cd \"$1\" && shift && exec \"$@\"' sh /tmp/sbx git -C /tmp/sbx status",
|
|
]
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"ssh_target",
|
|
["-v", "-oProxyCommand", "agent@-host", "-agent@host", "agent@host extra"],
|
|
)
|
|
def test_remote_transport_rejects_ssh_option_and_invalid_targets(ssh_target) -> None:
|
|
sandbox = SandboxHandle(
|
|
sandbox_id="sbx",
|
|
host="sandboxer01",
|
|
reachability={"ssh": ssh_target, "remote_dir": "/tmp/sbx"},
|
|
)
|
|
|
|
with pytest.raises(TransportError, match="single non-option host"):
|
|
transport_from_sandbox(sandbox)
|
|
|
|
|
|
def test_direct_remote_transport_cannot_bypass_ssh_target_validation() -> None:
|
|
transport = ExecutionTransport(kind="ssh", workspace="/tmp/sbx", ssh_target="-v")
|
|
|
|
with pytest.raises(TransportError, match="single non-option host"):
|
|
transport.command(["true"])
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"reachability",
|
|
[
|
|
{},
|
|
{"workspace_dir": "/tmp/ws"},
|
|
{"pid": "12"},
|
|
{"ssh": "agent@host"},
|
|
{"remote_dir": "/tmp/ws"},
|
|
{
|
|
"pid": "12",
|
|
"workspace_dir": "/tmp/ws",
|
|
"ssh": "agent@host",
|
|
"remote_dir": "/tmp/ws",
|
|
},
|
|
],
|
|
)
|
|
def test_incomplete_or_ambiguous_reachability_fails_closed(reachability) -> None:
|
|
with pytest.raises(TransportError):
|
|
transport_from_sandbox(
|
|
SandboxHandle(sandbox_id="sbx", host="localhost", reachability=reachability)
|
|
)
|
|
|
|
|
|
def test_local_task_file_uses_owner_stdin_and_cleanup(tmp_path: Path) -> None:
|
|
owner = MagicMock(return_value=MagicMock(
|
|
timed_out=False, output_truncated=False, exit_code=0, stdout="", stderr=""
|
|
))
|
|
transport = ExecutionTransport(
|
|
kind="local_namespace", workspace=str(tmp_path), pid=123, owner_execute=owner,
|
|
timeout_seconds=7,
|
|
)
|
|
task_path = transport.write_task_file({"title": "private prompt"})
|
|
command, stdin, timeout = owner.call_args.args
|
|
assert "umask 077; set -C; cat" in command[2]
|
|
assert "private prompt" not in str(command)
|
|
assert json.loads(stdin) == {"title": "private prompt"}
|
|
assert timeout == 7
|
|
assert Path(task_path).parent == tmp_path / ".git"
|
|
assert not Path(task_path).exists() # No host write, even with a fake owner.
|
|
transport.remove_file(task_path)
|
|
owner.assert_called_with(["rm", "-f", "--", task_path], None, 7)
|
|
|
|
|
|
def test_local_descriptor_without_owner_fails_closed():
|
|
with pytest.raises(TransportError, match="owner execution binding"):
|
|
transport_from_sandbox(SandboxHandle(
|
|
sandbox_id="sbx", host="localhost",
|
|
reachability={"pid": "123", "workspace_dir": "/tmp/ws"},
|
|
))
|
|
|
|
|
|
@pytest.mark.parametrize("timed_out,truncated", [(True, False), (False, True)])
|
|
def test_owner_timeout_and_truncation_fail_closed(timed_out, truncated):
|
|
import subprocess
|
|
owner = MagicMock(return_value=MagicMock(
|
|
timed_out=timed_out, output_truncated=truncated
|
|
))
|
|
transport = ExecutionTransport(
|
|
kind="local_namespace", workspace="/tmp/ws", owner_execute=owner,
|
|
timeout_seconds=3,
|
|
)
|
|
with pytest.raises(subprocess.TimeoutExpired if timed_out else TransportError):
|
|
transport.run(["true"], timeout=30)
|
|
owner.assert_called_once_with(["true"], None, 3)
|
|
|
|
|
|
def test_remote_task_file_uses_ssh_stdin_and_cleanup() -> None:
|
|
transport = ExecutionTransport(
|
|
kind="ssh", workspace="/tmp/sbx", ssh_target="agent@sandboxer01"
|
|
)
|
|
completed = MagicMock(returncode=0, stdout="", stderr="")
|
|
with patch("glas_harness.transport.subprocess.run", return_value=completed) as run:
|
|
task_path = transport.write_task_file({"title": "bounded"})
|
|
transport.remove_file(task_path)
|
|
|
|
create = run.call_args_list[0]
|
|
assert create.args[0][:3] == ["ssh", "--", "agent@sandboxer01"]
|
|
assert create.kwargs["input"] == '{"title": "bounded"}'
|
|
assert "cat >" in create.args[0][3]
|
|
assert "rm -f" in run.call_args_list[1].args[0][3]
|
|
|
|
|
|
def test_resolve_executable_fails_inside_transport() -> None:
|
|
transport = ExecutionTransport(
|
|
kind="ssh", workspace="/tmp/sbx", ssh_target="agent@sandboxer01"
|
|
)
|
|
with patch.object(
|
|
ExecutionTransport,
|
|
"run",
|
|
return_value=MagicMock(returncode=127, stdout="", stderr="not found"),
|
|
):
|
|
with pytest.raises(TransportError, match="not installed inside"):
|
|
transport.resolve_executable("rein-aharness")
|
|
|
|
|
|
def test_git_head_fails_closed_on_transport_error() -> None:
|
|
transport = ExecutionTransport(
|
|
kind="ssh", workspace="/tmp/sbx", ssh_target="agent@sandboxer01"
|
|
)
|
|
with patch.object(
|
|
ExecutionTransport,
|
|
"run",
|
|
return_value=MagicMock(returncode=1, stdout="", stderr="permission denied"),
|
|
):
|
|
with pytest.raises(TransportError, match="inside the selected sandbox"):
|
|
transport.git_head()
|