Files
2026-07-13 13:12:33 +08:00

875 lines
26 KiB
Python

from __future__ import annotations
import json
import sys
from types import SimpleNamespace
import pytest
from opensquilla.sandbox.backend import linux_helper
from opensquilla.sandbox.backend.linux_filesystem import run_filesystem_payload
from opensquilla.sandbox.backend.linux_helper import build_outer_bwrap_command
from opensquilla.sandbox.backend.linux_payload import (
FilesystemHelperPayload,
HelperPayload,
ProcessHelperPayload,
encode_payload,
)
from opensquilla.sandbox.backend.linux_process import run_process_payload
from opensquilla.sandbox.backend.linux_protected_create import (
SyntheticMountCleanupTarget,
cleanup_protected_create_registrations,
cleanup_synthetic_mount_registrations,
cleanup_synthetic_mount_targets,
register_protected_create_targets,
register_synthetic_mount_targets,
)
pytestmark = pytest.mark.skipif(
not sys.platform.startswith("linux"),
reason="Linux helper tests require POSIX process-group and seccomp semantics",
)
@pytest.mark.asyncio
async def test_run_process_payload_captures_stdout_and_stderr(tmp_path) -> None:
payload = HelperPayload(
operation_type="process",
action_kind="shell.exec",
run_mode="trusted",
session_id="s1",
cwd=str(tmp_path),
env={},
policy={"wallTimeoutS": 5.0},
process=ProcessHelperPayload(
argv=[
sys.executable,
"-c",
"import sys; print('out'); print('err', file=sys.stderr)",
]
),
filesystem=None,
)
result = await run_process_payload(payload)
assert result["returncode"] == 0
assert result["stdout"] == "out\n"
assert result["stderr"] == "err\n"
assert result["timedOut"] is False
@pytest.mark.asyncio
async def test_run_process_payload_passes_resource_preexec_to_child(
monkeypatch: pytest.MonkeyPatch,
tmp_path,
) -> None:
captured: dict[str, object] = {}
class _Proc:
returncode = 0
async def communicate(self, input=None):
return b"", b""
async def fake_create_subprocess_exec(*argv, **kwargs):
captured["argv"] = argv
captured["kwargs"] = kwargs
return _Proc()
monkeypatch.setattr(
"opensquilla.sandbox.backend.linux_process.asyncio.create_subprocess_exec",
fake_create_subprocess_exec,
)
payload = HelperPayload(
operation_type="process",
action_kind="shell.exec",
run_mode="trusted",
session_id="s1",
cwd=str(tmp_path),
env={},
policy={
"cpuSeconds": 7,
"memoryMb": 64,
"pids": 23,
"wallTimeoutS": 5.0,
},
process=ProcessHelperPayload(argv=[sys.executable, "-c", "print('ok')"]),
filesystem=None,
)
result = await run_process_payload(payload)
assert result["returncode"] == 0
kwargs = captured["kwargs"]
assert callable(kwargs["preexec_fn"])
@pytest.mark.asyncio
async def test_run_process_payload_passes_network_seccomp_to_child(
monkeypatch: pytest.MonkeyPatch,
tmp_path,
) -> None:
captured: dict[str, object] = {}
class _Proc:
returncode = 0
async def communicate(self, input=None):
return b"", b""
async def fake_create_subprocess_exec(*argv, **kwargs):
captured["kwargs"] = kwargs
return _Proc()
def fake_process_preexec_from_policy(policy):
captured["policy"] = policy
return lambda: None
monkeypatch.setattr(
"opensquilla.sandbox.backend.linux_process.asyncio.create_subprocess_exec",
fake_create_subprocess_exec,
)
monkeypatch.setattr(
"opensquilla.sandbox.backend.linux_process.process_preexec_from_policy",
fake_process_preexec_from_policy,
raising=False,
)
payload = HelperPayload(
operation_type="process",
action_kind="shell.exec",
run_mode="trusted",
session_id="s1",
cwd=str(tmp_path),
env={},
policy={
"network": "proxy_allowlist",
"cpuSeconds": 7,
"memoryMb": 64,
"pids": 23,
"wallTimeoutS": 5.0,
},
process=ProcessHelperPayload(argv=[sys.executable, "-c", "print('ok')"]),
filesystem=None,
)
await run_process_payload(payload)
assert captured["policy"] == payload.policy
assert callable(captured["kwargs"]["preexec_fn"])
@pytest.mark.asyncio
async def test_run_process_payload_times_out(tmp_path) -> None:
payload = HelperPayload(
operation_type="process",
action_kind="shell.exec",
run_mode="trusted",
session_id="s1",
cwd=str(tmp_path),
env={},
policy={"wallTimeoutS": 0.01},
process=ProcessHelperPayload(
argv=[sys.executable, "-c", "import time; time.sleep(5)"]
),
filesystem=None,
)
result = await run_process_payload(payload)
assert result["returncode"] == 124
assert result["timedOut"] is True
assert "timed out" in result["stderr"]
@pytest.mark.asyncio
async def test_run_process_payload_proxy_mode_denies_af_unix_socket(tmp_path) -> None:
payload = HelperPayload(
operation_type="process",
action_kind="shell.exec",
run_mode="trusted",
session_id="s1",
cwd=str(tmp_path),
env={},
policy={"network": "proxy_allowlist", "wallTimeoutS": 5.0},
process=ProcessHelperPayload(
argv=[
sys.executable,
"-c",
(
"import socket, sys\n"
"try:\n"
" socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)\n"
"except PermissionError:\n"
" print('af_unix_denied')\n"
" raise SystemExit(0)\n"
"except OSError as exc:\n"
" print(type(exc).__name__)\n"
" raise SystemExit(2)\n"
"print('unexpected_af_unix')\n"
"raise SystemExit(1)\n"
),
]
),
filesystem=None,
)
result = await run_process_payload(payload)
assert result["returncode"] == 0
assert result["stdout"] == "af_unix_denied\n"
@pytest.mark.asyncio
async def test_run_process_payload_restricted_mode_allows_af_unix_only(tmp_path) -> None:
payload = HelperPayload(
operation_type="process",
action_kind="shell.exec",
run_mode="trusted",
session_id="s1",
cwd=str(tmp_path),
env={},
policy={"network": "none", "wallTimeoutS": 5.0},
process=ProcessHelperPayload(
argv=[
sys.executable,
"-c",
(
"import socket\n"
"socket.socket(socket.AF_UNIX, socket.SOCK_STREAM).close()\n"
"try:\n"
" socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n"
"except PermissionError:\n"
" print('ip_denied')\n"
" raise SystemExit(0)\n"
"print('unexpected_ip')\n"
"raise SystemExit(1)\n"
),
]
),
filesystem=None,
)
result = await run_process_payload(payload)
assert result["returncode"] == 0
assert result["stdout"] == "ip_denied\n"
@pytest.mark.asyncio
async def test_run_filesystem_payload_writes_worker_payload_and_parses_result(
tmp_path,
) -> None:
target = tmp_path / "out.txt"
worker_payload_path = tmp_path / "payload.json"
payload = HelperPayload(
operation_type="filesystem",
action_kind="fs.worker.write_text",
run_mode="trusted",
session_id="s1",
cwd=str(tmp_path),
env={},
policy={"wallTimeoutS": 5.0},
process=None,
filesystem=FilesystemHelperPayload(
kind="write_text",
worker_payload_path=str(worker_payload_path),
worker_payload={
"kind": "write_text",
"path": str(target),
"content": "hello",
},
),
)
result = await run_filesystem_payload(payload)
assert result["message"] == f"Written 5 bytes to {target}"
assert result["created"] is True
assert target.read_text(encoding="utf-8") == "hello"
def test_linux_helper_inner_process_prints_json_result(tmp_path, capsys) -> None:
payload = HelperPayload(
operation_type="process",
action_kind="shell.exec",
run_mode="trusted",
session_id="s1",
cwd=str(tmp_path),
env={},
policy={"wallTimeoutS": 5.0},
process=ProcessHelperPayload(argv=[sys.executable, "-c", "print('ok')"]),
filesystem=None,
)
payload_path = tmp_path / "payload.json"
payload_path.write_text(encode_payload(payload), encoding="utf-8")
exit_code = linux_helper.main(["--inner", "--payload", str(payload_path)])
assert exit_code == 0
result = json.loads(capsys.readouterr().out)
assert result["returncode"] == 0
assert result["stdout"] == "ok\n"
def test_build_outer_bwrap_command_reenters_helper_inner_mode(tmp_path) -> None:
payload = HelperPayload(
operation_type="process",
action_kind="shell.exec",
run_mode="trusted",
session_id="s1",
cwd=str(tmp_path),
env={},
policy={
"network": "none",
"mounts": [
{"host": str(tmp_path), "sandbox": "/workspace", "mode": "rw", "required": True}
],
"envAllowlist": ["PATH"],
"tmpWritable": True,
"wallTimeoutS": 5.0,
},
process=ProcessHelperPayload(argv=["/bin/echo", "ok"]),
filesystem=None,
)
payload_path = tmp_path / "payload.json"
payload_path.write_text(encode_payload(payload), encoding="utf-8")
argv = build_outer_bwrap_command(
payload=payload,
payload_path=payload_path,
bwrap_path="bwrap",
mount_proc=True,
)
assert argv[0] == "bwrap"
assert "--unshare-user" in argv
assert "--unshare-pid" in argv
assert "--unshare-net" in argv
separator = argv.index("--")
inner = argv[separator + 1 :]
assert inner[:3] == [sys.executable, "-m", "opensquilla.sandbox.backend.linux_helper"]
assert "--inner" in inner
assert str(payload_path) in inner
def test_build_outer_bwrap_command_wraps_proxy_allowlist_with_bridge(tmp_path) -> None:
bridge_dir = tmp_path / "bridge"
payload = HelperPayload(
operation_type="process",
action_kind="network.http",
run_mode="trusted",
session_id="s1",
cwd=str(tmp_path),
env={},
policy={
"network": "proxy_allowlist",
"mounts": [
{"host": str(tmp_path), "sandbox": "/workspace", "mode": "rw", "required": True}
],
"envAllowlist": ["PATH"],
"tmpWritable": True,
"wallTimeoutS": 5.0,
"linuxProxyBridge": {
"udsPath": str(bridge_dir / "proxy.sock"),
"scriptPath": str(bridge_dir / "inner_bridge.py"),
"port": 18080,
},
},
process=ProcessHelperPayload(argv=["/bin/echo", "ok"]),
filesystem=None,
)
payload_path = tmp_path / "payload.json"
payload_path.write_text(encode_payload(payload), encoding="utf-8")
argv = build_outer_bwrap_command(
payload=payload,
payload_path=payload_path,
bwrap_path="bwrap",
mount_proc=True,
)
separator = argv.index("--")
inner = argv[separator + 1 :]
assert "--unshare-net" in argv
assert str(bridge_dir) in argv
assert "OPENSQUILLA_SANDBOX_PROXY_UDS" in argv
assert str(bridge_dir / "proxy.sock") in argv
assert "OPENSQUILLA_SANDBOX_PROXY_PORT" in argv
assert "18080" in argv
assert "OPENSQUILLA_SANDBOX_EXEC_WRAPPER" not in argv
assert "OPENSQUILLA_SANDBOX_POLICY_B64" not in argv
assert inner[:3] == [sys.executable, str(bridge_dir / "inner_bridge.py"), "--"]
assert inner[3:6] == [sys.executable, "-m", "opensquilla.sandbox.backend.linux_helper"]
assert "--inner" in inner
def test_linux_helper_outer_mode_runs_bwrap_and_prints_inner_json(
tmp_path,
monkeypatch: pytest.MonkeyPatch,
capsys,
) -> None:
payload = HelperPayload(
operation_type="process",
action_kind="shell.exec",
run_mode="trusted",
session_id="s1",
cwd=str(tmp_path),
env={},
policy={
"network": "none",
"mounts": [
{"host": str(tmp_path), "sandbox": "/workspace", "mode": "rw", "required": True}
],
"envAllowlist": ["PATH"],
"tmpWritable": True,
"wallTimeoutS": 5.0,
},
process=ProcessHelperPayload(argv=["/bin/echo", "ok"]),
filesystem=None,
)
payload_path = tmp_path / "payload.json"
payload_path.write_text(encode_payload(payload), encoding="utf-8")
class _Proc:
returncode = 0
async def communicate(self):
payload = {
"returncode": 0,
"stdout": "ok\n",
"stderr": "",
"wallTimeS": 0.01,
"timedOut": False,
"truncatedStdout": False,
"truncatedStderr": False,
}
return (
json.dumps(payload).encode(),
b"",
)
async def fake_create_subprocess_exec(*argv, **kwargs):
assert argv[0] == "bwrap"
assert "--unshare-user" in argv
assert "--" in argv
return _Proc()
monkeypatch.setattr(
linux_helper,
"probe_bwrap",
lambda: SimpleNamespace(
available=True,
message="ready",
path="bwrap",
),
)
monkeypatch.setattr(
linux_helper.asyncio,
"create_subprocess_exec",
fake_create_subprocess_exec,
)
exit_code = linux_helper.main(["--payload", str(payload_path)])
assert exit_code == 0
result = json.loads(capsys.readouterr().out)
assert result["returncode"] == 0
def test_linux_helper_outer_mode_retries_without_proc_when_proc_mount_fails(
tmp_path,
monkeypatch: pytest.MonkeyPatch,
capsys,
) -> None:
payload = HelperPayload(
operation_type="process",
action_kind="shell.exec",
run_mode="trusted",
session_id="s1",
cwd=str(tmp_path),
env={},
policy={
"network": "none",
"mounts": [
{"host": str(tmp_path), "sandbox": "/workspace", "mode": "rw", "required": True}
],
"envAllowlist": ["PATH"],
"tmpWritable": True,
"wallTimeoutS": 5.0,
},
process=ProcessHelperPayload(argv=["/bin/echo", "ok"]),
filesystem=None,
)
payload_path = tmp_path / "payload.json"
payload_path.write_text(encode_payload(payload), encoding="utf-8")
calls: list[tuple[str, ...]] = []
class _Proc:
def __init__(self, returncode: int, stdout: bytes, stderr: bytes) -> None:
self.returncode = returncode
self._stdout = stdout
self._stderr = stderr
async def communicate(self):
return self._stdout, self._stderr
async def fake_create_subprocess_exec(*argv, **kwargs):
calls.append(tuple(argv))
if len(calls) == 1:
assert "--proc" in argv
return _Proc(
1,
b"",
b"bwrap: setting up /proc: Operation not permitted\n",
)
assert "--proc" not in argv
return _Proc(
0,
json.dumps(
{
"returncode": 0,
"stdout": "ok\n",
"stderr": "",
"wallTimeS": 0.01,
"timedOut": False,
"truncatedStdout": False,
"truncatedStderr": False,
}
).encode(),
b"",
)
monkeypatch.setattr(
linux_helper,
"probe_bwrap",
lambda: SimpleNamespace(
available=True,
message="ready",
path="bwrap",
),
)
monkeypatch.setattr(
linux_helper.asyncio,
"create_subprocess_exec",
fake_create_subprocess_exec,
)
exit_code = linux_helper.main(["--payload", str(payload_path)])
assert exit_code == 0
assert len(calls) == 2
result = json.loads(capsys.readouterr().out)
assert result["returncode"] == 0
assert result["stdout"] == "ok\n"
assert result["stdout"] == "ok\n"
def test_linux_helper_outer_mode_passes_preserved_fds_for_denied_globs(
tmp_path,
monkeypatch: pytest.MonkeyPatch,
capsys,
) -> None:
secret = tmp_path / ".env"
secret.write_text("secret", encoding="utf-8")
captured: dict[str, object] = {}
payload = HelperPayload(
operation_type="process",
action_kind="shell.exec",
run_mode="trusted",
session_id="s1",
cwd=str(tmp_path),
env={},
policy={
"network": "none",
"mounts": [
{"host": str(tmp_path), "sandbox": "/workspace", "mode": "ro", "required": True}
],
"unreadableGlobs": [str(tmp_path / "**" / ".env")],
"envAllowlist": ["PATH"],
"tmpWritable": True,
"wallTimeoutS": 5.0,
},
process=ProcessHelperPayload(argv=["/bin/echo", "ok"]),
filesystem=None,
)
payload_path = tmp_path / "payload.json"
payload_path.write_text(encode_payload(payload), encoding="utf-8")
class _Proc:
returncode = 0
async def communicate(self):
payload = {
"returncode": 0,
"stdout": "ok\n",
"stderr": "",
"wallTimeS": 0.01,
"timedOut": False,
"truncatedStdout": False,
"truncatedStderr": False,
}
return (
json.dumps(payload).encode(),
b"",
)
async def fake_create_subprocess_exec(*argv, **kwargs):
captured["argv"] = argv
captured["kwargs"] = kwargs
return _Proc()
monkeypatch.setattr(
linux_helper,
"probe_bwrap",
lambda: SimpleNamespace(
available=True,
message="ready",
path="bwrap",
),
)
monkeypatch.setattr(
linux_helper.asyncio,
"create_subprocess_exec",
fake_create_subprocess_exec,
)
exit_code = linux_helper.main(["--payload", str(payload_path)])
assert exit_code == 0
result = json.loads(capsys.readouterr().out)
assert result["returncode"] == 0
kwargs = captured["kwargs"]
assert kwargs["pass_fds"]
argv = captured["argv"]
assert "--ro-bind" in argv
assert str(secret) in argv
def test_linux_helper_outer_mode_reports_protected_metadata_creation(
tmp_path,
monkeypatch: pytest.MonkeyPatch,
capsys,
) -> None:
parent_git = tmp_path / ".git"
parent_git.mkdir()
(parent_git / "HEAD").write_text("ref: refs/heads/main\n", encoding="utf-8")
workspace = tmp_path / "child"
workspace.mkdir()
protected = workspace / ".git"
payload = HelperPayload(
operation_type="process",
action_kind="shell.exec",
run_mode="trusted",
session_id="s1",
cwd=str(workspace),
env={},
policy={
"network": "none",
"mounts": [
{
"host": str(workspace),
"sandbox": "/workspace",
"mode": "rw",
"required": True,
}
],
"envAllowlist": ["PATH"],
"tmpWritable": True,
"wallTimeoutS": 5.0,
},
process=ProcessHelperPayload(argv=["/bin/true"]),
filesystem=None,
)
payload_path = tmp_path / "payload.json"
payload_path.write_text(encode_payload(payload), encoding="utf-8")
class _Proc:
returncode = 0
async def communicate(self):
protected.mkdir()
payload = {
"returncode": 0,
"stdout": "",
"stderr": "",
"wallTimeS": 0.01,
"timedOut": False,
"truncatedStdout": False,
"truncatedStderr": False,
}
return (
json.dumps(payload).encode(),
b"",
)
async def fake_create_subprocess_exec(*argv, **kwargs):
return _Proc()
monkeypatch.setattr(
linux_helper,
"probe_bwrap",
lambda: SimpleNamespace(
available=True,
message="ready",
path="bwrap",
),
)
monkeypatch.setattr(
linux_helper.asyncio,
"create_subprocess_exec",
fake_create_subprocess_exec,
)
exit_code = linux_helper.main(["--payload", str(payload_path)])
assert exit_code == 0
result = json.loads(capsys.readouterr().out)
assert result["returncode"] == 1
assert "sandbox blocked creation of protected workspace metadata path" in result["stderr"]
assert str(protected) in result["stderr"]
assert not protected.exists()
def test_linux_helper_outer_mode_cleans_synthetic_metadata_mount_target(
tmp_path,
monkeypatch: pytest.MonkeyPatch,
capsys,
) -> None:
protected = tmp_path / ".codex"
payload = HelperPayload(
operation_type="process",
action_kind="shell.exec",
run_mode="trusted",
session_id="s1",
cwd=str(tmp_path),
env={},
policy={
"network": "none",
"mounts": [
{"host": str(tmp_path), "sandbox": "/workspace", "mode": "rw", "required": True}
],
"envAllowlist": ["PATH"],
"tmpWritable": True,
"wallTimeoutS": 5.0,
},
process=ProcessHelperPayload(argv=["/bin/true"]),
filesystem=None,
)
payload_path = tmp_path / "payload.json"
payload_path.write_text(encode_payload(payload), encoding="utf-8")
class _Proc:
returncode = 0
async def communicate(self):
protected.mkdir()
payload = {
"returncode": 0,
"stdout": "",
"stderr": "",
"wallTimeS": 0.01,
"timedOut": False,
"truncatedStdout": False,
"truncatedStderr": False,
}
return (
json.dumps(payload).encode(),
b"",
)
async def fake_create_subprocess_exec(*argv, **kwargs):
return _Proc()
monkeypatch.setattr(
linux_helper,
"probe_bwrap",
lambda: SimpleNamespace(
available=True,
message="ready",
path="bwrap",
),
)
monkeypatch.setattr(
linux_helper.asyncio,
"create_subprocess_exec",
fake_create_subprocess_exec,
)
exit_code = linux_helper.main(["--payload", str(payload_path)])
assert exit_code == 0
result = json.loads(capsys.readouterr().out)
assert result["returncode"] == 0
assert result["stderr"] == ""
assert not protected.exists()
def test_synthetic_mount_cleanup_preserves_non_empty_directory(tmp_path) -> None:
protected = tmp_path / ".codex"
protected.mkdir()
(protected / "config.json").write_text("{}", encoding="utf-8")
cleanup_synthetic_mount_targets(
(SyntheticMountCleanupTarget(path=protected, kind="empty_directory"),)
)
assert protected.exists()
assert (protected / "config.json").read_text(encoding="utf-8") == "{}"
def test_synthetic_mount_cleanup_preserves_pre_existing_empty_file(tmp_path) -> None:
protected = tmp_path / ".git"
protected.write_text("", encoding="utf-8")
identity = SyntheticMountCleanupTarget.identity_for_path(protected)
assert identity is not None
cleanup_synthetic_mount_targets(
(
SyntheticMountCleanupTarget(
path=protected,
kind="empty_file",
pre_existing_identity=identity,
),
)
)
assert protected.exists()
def test_synthetic_mount_registry_waits_for_other_active_registration(tmp_path) -> None:
protected = tmp_path / ".codex"
protected.mkdir()
target = SyntheticMountCleanupTarget(path=protected, kind="empty_directory")
first = register_synthetic_mount_targets((target,))
second = register_synthetic_mount_targets((target,))
cleanup_synthetic_mount_registrations(first)
assert protected.exists()
cleanup_synthetic_mount_registrations(second)
assert not protected.exists()
def test_protected_create_registry_waits_before_removing_created_path(tmp_path) -> None:
protected = tmp_path / ".git"
first = register_protected_create_targets((protected,))
second = register_protected_create_targets((protected,))
protected.mkdir()
first_messages = cleanup_protected_create_registrations(first)
assert first_messages == [
f"sandbox blocked creation of protected workspace metadata path {protected}"
]
assert protected.exists()
second_messages = cleanup_protected_create_registrations(second)
assert second_messages == [
f"sandbox blocked creation of protected workspace metadata path {protected}"
]
assert not protected.exists()