640 lines
20 KiB
Python
640 lines
20 KiB
Python
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from opensquilla.sandbox.backend.linux_bwrap import (
|
|
HOST_RUNTIME_READONLY_PATHS,
|
|
BwrapOptions,
|
|
build_bwrap_argv,
|
|
build_bwrap_plan,
|
|
)
|
|
from opensquilla.sandbox.backend.linux_permissions import LinuxPermissions, LinuxRoot
|
|
from opensquilla.sandbox.types import NetworkMode, SandboxBackendError
|
|
|
|
pytestmark = pytest.mark.skipif(
|
|
sys.platform.startswith("win"),
|
|
reason="Linux bubblewrap backend tests require POSIX path and process semantics",
|
|
)
|
|
|
|
|
|
def _permissions(tmp_path: Path, *, network: NetworkMode = NetworkMode.NONE) -> LinuxPermissions:
|
|
return LinuxPermissions(
|
|
read_roots=(LinuxRoot(tmp_path / "docs", Path("/workspace/docs"), required=False),),
|
|
write_roots=(LinuxRoot(tmp_path, Path("/workspace"), required=True),),
|
|
denied_roots=(),
|
|
protected_subpaths=(tmp_path / ".git",),
|
|
env_allowlist=("PATH",),
|
|
network=network,
|
|
tmp_writable=True,
|
|
wall_timeout_s=30,
|
|
)
|
|
|
|
|
|
def test_bwrap_argv_uses_readonly_baseline_and_write_layers(tmp_path: Path) -> None:
|
|
argv = build_bwrap_argv(
|
|
command=["/bin/echo", "ok"],
|
|
command_cwd=tmp_path,
|
|
permissions=_permissions(tmp_path),
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
assert argv[:2] == ["bwrap", "--new-session"]
|
|
assert "--ro-bind" in argv
|
|
assert "/" in argv
|
|
assert "--bind" in argv
|
|
assert str(tmp_path) in argv
|
|
assert "/workspace" in argv
|
|
assert "--unshare-user" in argv
|
|
assert "--unshare-pid" in argv
|
|
assert "--unshare-net" in argv
|
|
assert "--proc" in argv
|
|
assert argv[-2:] == ["/bin/echo", "ok"]
|
|
|
|
|
|
def test_linux_runtime_readonly_paths_match_codex_platform_defaults() -> None:
|
|
paths = {path.as_posix() for path in HOST_RUNTIME_READONLY_PATHS}
|
|
|
|
assert {
|
|
"/bin",
|
|
"/sbin",
|
|
"/usr",
|
|
"/etc",
|
|
"/lib",
|
|
"/lib64",
|
|
"/nix/store",
|
|
"/run/current-system/sw",
|
|
}.issubset(paths)
|
|
|
|
|
|
def test_bwrap_argv_uses_readonly_root_when_root_is_readable(tmp_path: Path) -> None:
|
|
permissions = LinuxPermissions(
|
|
read_roots=(LinuxRoot(Path("/"), Path("/"), required=True),),
|
|
write_roots=(LinuxRoot(tmp_path, tmp_path, required=True),),
|
|
denied_roots=(),
|
|
protected_subpaths=(),
|
|
env_allowlist=("PATH",),
|
|
network=NetworkMode.NONE,
|
|
tmp_writable=True,
|
|
wall_timeout_s=30,
|
|
)
|
|
|
|
argv = build_bwrap_argv(
|
|
command=["/bin/true"],
|
|
command_cwd=tmp_path,
|
|
permissions=permissions,
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
assert argv[argv.index("--ro-bind") : argv.index("--ro-bind") + 3] == [
|
|
"--ro-bind",
|
|
"/",
|
|
"/",
|
|
]
|
|
assert ["--tmpfs", "/"] not in [argv[index : index + 2] for index in range(len(argv) - 1)]
|
|
|
|
|
|
def test_bwrap_argv_keeps_host_network_when_network_mode_host(tmp_path: Path) -> None:
|
|
argv = build_bwrap_argv(
|
|
command=["/bin/echo", "ok"],
|
|
command_cwd=tmp_path,
|
|
permissions=_permissions(tmp_path, network=NetworkMode.HOST),
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
assert "--unshare-net" not in argv
|
|
|
|
|
|
def test_bwrap_argv_can_skip_proc(tmp_path: Path) -> None:
|
|
argv = build_bwrap_argv(
|
|
command=["/bin/echo", "ok"],
|
|
command_cwd=tmp_path,
|
|
permissions=_permissions(tmp_path),
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=False),
|
|
)
|
|
|
|
assert "--proc" not in argv
|
|
|
|
|
|
def test_bwrap_argv_creates_parent_dirs_for_file_read_roots(tmp_path: Path) -> None:
|
|
target = tmp_path / "pyproject.toml"
|
|
target.write_text("[project]\n", encoding="utf-8")
|
|
permissions = LinuxPermissions(
|
|
read_roots=(LinuxRoot(target, target, required=True),),
|
|
write_roots=(),
|
|
denied_roots=(),
|
|
protected_subpaths=(),
|
|
env_allowlist=("PATH",),
|
|
network=NetworkMode.NONE,
|
|
tmp_writable=True,
|
|
wall_timeout_s=30,
|
|
)
|
|
|
|
argv = build_bwrap_argv(
|
|
command=["/bin/cat", str(target)],
|
|
command_cwd=tmp_path,
|
|
permissions=permissions,
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
dir_targets = [argv[index + 1] for index, item in enumerate(argv) if item == "--dir"]
|
|
assert str(target) not in dir_targets
|
|
assert str(target.parent) in dir_targets
|
|
bind_index = argv.index(str(target))
|
|
assert argv[bind_index - 1] == "--ro-bind"
|
|
assert argv[bind_index + 1] == str(target)
|
|
|
|
|
|
def test_bwrap_argv_masks_missing_protected_metadata_paths(tmp_path: Path) -> None:
|
|
protected = tmp_path / ".codex"
|
|
permissions = LinuxPermissions(
|
|
read_roots=(),
|
|
write_roots=(LinuxRoot(tmp_path, Path("/workspace"), required=True),),
|
|
denied_roots=(),
|
|
protected_subpaths=(protected,),
|
|
env_allowlist=("PATH",),
|
|
network=NetworkMode.NONE,
|
|
tmp_writable=True,
|
|
wall_timeout_s=30,
|
|
)
|
|
|
|
argv = build_bwrap_argv(
|
|
command=["/bin/true"],
|
|
command_cwd=tmp_path,
|
|
permissions=permissions,
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
protected_target = str(protected)
|
|
assert protected_target in argv
|
|
protected_index = argv.index(protected_target)
|
|
assert argv[protected_index - 1] == "--tmpfs"
|
|
assert "--remount-ro" in argv
|
|
|
|
|
|
def test_bwrap_plan_tracks_missing_protected_metadata_synthetic_mount(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
protected = tmp_path / ".codex"
|
|
permissions = LinuxPermissions(
|
|
read_roots=(),
|
|
write_roots=(LinuxRoot(tmp_path, tmp_path, required=True),),
|
|
denied_roots=(),
|
|
protected_subpaths=(protected,),
|
|
env_allowlist=("PATH",),
|
|
network=NetworkMode.NONE,
|
|
tmp_writable=True,
|
|
wall_timeout_s=30,
|
|
)
|
|
|
|
plan = build_bwrap_plan(
|
|
command=["/bin/true"],
|
|
command_cwd=tmp_path,
|
|
permissions=permissions,
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
assert [(target.path, target.kind) for target in plan.synthetic_mount_targets] == [
|
|
(protected, "empty_directory")
|
|
]
|
|
|
|
|
|
def test_bwrap_plan_treats_existing_empty_protected_file_as_synthetic_mount(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
protected = tmp_path / ".git"
|
|
protected.write_text("", encoding="utf-8")
|
|
permissions = LinuxPermissions(
|
|
read_roots=(),
|
|
write_roots=(LinuxRoot(tmp_path, tmp_path, required=True),),
|
|
denied_roots=(),
|
|
protected_subpaths=(protected,),
|
|
env_allowlist=("PATH",),
|
|
network=NetworkMode.NONE,
|
|
tmp_writable=True,
|
|
wall_timeout_s=30,
|
|
)
|
|
|
|
plan = build_bwrap_plan(
|
|
command=["/bin/true"],
|
|
command_cwd=tmp_path,
|
|
permissions=permissions,
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
protected_target = str(protected)
|
|
assert any(
|
|
window[0] == "--ro-bind" and window[2] == protected_target
|
|
for window in (plan.argv[index : index + 3] for index in range(len(plan.argv) - 2))
|
|
)
|
|
assert ["--ro-bind", protected_target, protected_target] not in [
|
|
plan.argv[index : index + 3] for index in range(len(plan.argv) - 2)
|
|
]
|
|
assert [(target.path, target.kind) for target in plan.synthetic_mount_targets] == [
|
|
(protected, "empty_file")
|
|
]
|
|
assert plan.synthetic_mount_targets[0].pre_existing_identity is not None
|
|
|
|
|
|
def test_bwrap_argv_rejects_symlinked_protected_metadata_paths(tmp_path: Path) -> None:
|
|
protected_target = tmp_path / "agents-target"
|
|
protected_target.mkdir()
|
|
protected = tmp_path / ".agents"
|
|
protected.symlink_to(protected_target, target_is_directory=True)
|
|
permissions = LinuxPermissions(
|
|
read_roots=(),
|
|
write_roots=(LinuxRoot(tmp_path, tmp_path, required=True),),
|
|
denied_roots=(),
|
|
protected_subpaths=(protected,),
|
|
env_allowlist=("PATH",),
|
|
network=NetworkMode.NONE,
|
|
tmp_writable=True,
|
|
wall_timeout_s=30,
|
|
)
|
|
|
|
with pytest.raises(SandboxBackendError, match="cannot enforce sandbox read-only path"):
|
|
build_bwrap_argv(
|
|
command=["/bin/true"],
|
|
command_cwd=tmp_path,
|
|
permissions=permissions,
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
|
|
def test_bwrap_plan_leaves_missing_child_git_for_parent_repo_discovery(
|
|
tmp_path: Path,
|
|
) -> 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"
|
|
permissions = LinuxPermissions(
|
|
read_roots=(),
|
|
write_roots=(LinuxRoot(workspace, workspace, required=True),),
|
|
denied_roots=(),
|
|
protected_subpaths=(protected,),
|
|
env_allowlist=("PATH",),
|
|
network=NetworkMode.NONE,
|
|
tmp_writable=True,
|
|
wall_timeout_s=30,
|
|
)
|
|
|
|
plan = build_bwrap_plan(
|
|
command=["/bin/true"],
|
|
command_cwd=workspace,
|
|
permissions=permissions,
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
protected_target = str(protected)
|
|
assert ["--perms", "555", "--tmpfs", protected_target] not in [
|
|
plan.argv[index : index + 4]
|
|
for index in range(len(plan.argv) - 3)
|
|
]
|
|
assert plan.protected_create_targets == (protected,)
|
|
|
|
|
|
def test_bwrap_argv_does_not_recreate_protected_parent_after_bind(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
protected = tmp_path / ".git"
|
|
permissions = LinuxPermissions(
|
|
read_roots=(),
|
|
write_roots=(LinuxRoot(tmp_path, tmp_path, required=True),),
|
|
denied_roots=(),
|
|
protected_subpaths=(protected,),
|
|
env_allowlist=("PATH",),
|
|
network=NetworkMode.NONE,
|
|
tmp_writable=True,
|
|
wall_timeout_s=30,
|
|
)
|
|
|
|
argv = build_bwrap_argv(
|
|
command=["/bin/true"],
|
|
command_cwd=tmp_path,
|
|
permissions=permissions,
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
bind_index = argv.index(str(tmp_path))
|
|
protected_index = argv.index(str(protected))
|
|
parent_dirs_after_bind = [
|
|
argv[index + 1]
|
|
for index, item in enumerate(argv[bind_index + 1 : protected_index], start=bind_index + 1)
|
|
if item == "--dir"
|
|
]
|
|
assert str(tmp_path) not in parent_dirs_after_bind
|
|
|
|
|
|
def test_bwrap_argv_masks_denied_roots(tmp_path: Path) -> None:
|
|
denied = tmp_path / "private"
|
|
denied.mkdir()
|
|
permissions = LinuxPermissions(
|
|
read_roots=(),
|
|
write_roots=(LinuxRoot(tmp_path, tmp_path, required=True),),
|
|
denied_roots=(denied,),
|
|
protected_subpaths=(),
|
|
env_allowlist=("PATH",),
|
|
network=NetworkMode.NONE,
|
|
tmp_writable=True,
|
|
wall_timeout_s=30,
|
|
)
|
|
|
|
argv = build_bwrap_argv(
|
|
command=["/bin/true"],
|
|
command_cwd=tmp_path,
|
|
permissions=permissions,
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
denied_target = str(denied)
|
|
assert denied_target in argv
|
|
denied_index = argv.index(denied_target)
|
|
assert argv[denied_index - 1] == "--tmpfs"
|
|
assert ["--perms", "000", "--tmpfs", denied_target] == argv[
|
|
denied_index - 3 : denied_index + 1
|
|
]
|
|
|
|
|
|
def test_bwrap_plan_masks_missing_denied_root_with_empty_file_bind(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
denied = tmp_path / "missing" / "secret.txt"
|
|
permissions = LinuxPermissions(
|
|
read_roots=(),
|
|
write_roots=(LinuxRoot(tmp_path, tmp_path, required=True),),
|
|
denied_roots=(denied,),
|
|
protected_subpaths=(),
|
|
env_allowlist=("PATH",),
|
|
network=NetworkMode.NONE,
|
|
tmp_writable=True,
|
|
wall_timeout_s=30,
|
|
)
|
|
|
|
plan = build_bwrap_plan(
|
|
command=["/bin/true"],
|
|
command_cwd=tmp_path,
|
|
permissions=permissions,
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
missing_component = tmp_path / "missing"
|
|
assert plan.preserved_files
|
|
assert any(
|
|
window[0] == "--ro-bind" and window[2] == str(missing_component)
|
|
for window in (plan.argv[index : index + 3] for index in range(len(plan.argv) - 2))
|
|
)
|
|
assert ["--perms", "000", "--ro-bind"] not in [
|
|
plan.argv[index : index + 3] for index in range(len(plan.argv) - 2)
|
|
]
|
|
assert ["--tmpfs", str(denied)] not in [
|
|
plan.argv[index : index + 2] for index in range(len(plan.argv) - 1)
|
|
]
|
|
assert [(target.path, target.kind) for target in plan.synthetic_mount_targets] == [
|
|
(missing_component, "empty_file")
|
|
]
|
|
|
|
|
|
def test_bwrap_plan_expands_denied_globs_to_file_masks(tmp_path: Path) -> None:
|
|
secret = tmp_path / ".env"
|
|
secret.write_text("secret", encoding="utf-8")
|
|
permissions = LinuxPermissions(
|
|
read_roots=(LinuxRoot(tmp_path, tmp_path, required=True),),
|
|
write_roots=(),
|
|
denied_roots=(),
|
|
denied_globs=(str(tmp_path / "**" / ".env"),),
|
|
protected_subpaths=(),
|
|
env_allowlist=("PATH",),
|
|
network=NetworkMode.NONE,
|
|
tmp_writable=True,
|
|
wall_timeout_s=30,
|
|
)
|
|
|
|
plan = build_bwrap_plan(
|
|
command=["/bin/true"],
|
|
command_cwd=tmp_path,
|
|
permissions=permissions,
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
secret_target = str(secret)
|
|
assert plan.preserved_files
|
|
assert any(
|
|
window[0] == "--ro-bind"
|
|
and window[2] == secret_target
|
|
for window in (plan.argv[index : index + 3] for index in range(len(plan.argv) - 2))
|
|
)
|
|
|
|
|
|
def test_bwrap_plan_denied_globs_mask_symlink_targets(tmp_path: Path) -> None:
|
|
real_root = tmp_path / "real"
|
|
link_root = tmp_path / "link"
|
|
real_root.mkdir()
|
|
secret = real_root / "secret.env"
|
|
secret.write_text("secret", encoding="utf-8")
|
|
link_root.symlink_to(real_root, target_is_directory=True)
|
|
permissions = LinuxPermissions(
|
|
read_roots=(LinuxRoot(tmp_path, tmp_path, required=True),),
|
|
write_roots=(),
|
|
denied_roots=(),
|
|
denied_globs=(str(link_root / "**" / "*.env"),),
|
|
protected_subpaths=(),
|
|
env_allowlist=("PATH",),
|
|
network=NetworkMode.NONE,
|
|
tmp_writable=True,
|
|
wall_timeout_s=30,
|
|
)
|
|
|
|
plan = build_bwrap_plan(
|
|
command=["/bin/true"],
|
|
command_cwd=tmp_path,
|
|
permissions=permissions,
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
assert str(secret) in plan.argv
|
|
|
|
|
|
def test_bwrap_argv_binds_symlinked_writable_root_real_target_and_remaps_denied_child(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
real_root = tmp_path / "real"
|
|
link_root = tmp_path / "link"
|
|
blocked = real_root / "blocked"
|
|
blocked.mkdir(parents=True)
|
|
link_root.symlink_to(real_root, target_is_directory=True)
|
|
permissions = LinuxPermissions(
|
|
read_roots=(),
|
|
write_roots=(LinuxRoot(link_root, link_root, required=True),),
|
|
denied_roots=(link_root / "blocked",),
|
|
protected_subpaths=(),
|
|
env_allowlist=("PATH",),
|
|
network=NetworkMode.NONE,
|
|
tmp_writable=True,
|
|
wall_timeout_s=30,
|
|
)
|
|
|
|
argv = build_bwrap_argv(
|
|
command=["/bin/true"],
|
|
command_cwd=link_root,
|
|
permissions=permissions,
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
assert ["--bind", str(real_root), str(real_root)] in [
|
|
argv[index : index + 3] for index in range(len(argv) - 2)
|
|
]
|
|
assert ["--bind", str(link_root), str(link_root)] not in [
|
|
argv[index : index + 3] for index in range(len(argv) - 2)
|
|
]
|
|
assert ["--chdir", str(real_root)] in [
|
|
argv[index : index + 2] for index in range(len(argv) - 1)
|
|
]
|
|
assert ["--perms", "000", "--tmpfs", str(blocked)] in [
|
|
argv[index : index + 4] for index in range(len(argv) - 3)
|
|
]
|
|
|
|
|
|
def test_bwrap_argv_reopens_writable_directory_under_denied_parent(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
blocked = tmp_path / "blocked"
|
|
allowed = blocked / "allowed"
|
|
allowed.mkdir(parents=True)
|
|
permissions = LinuxPermissions(
|
|
read_roots=(LinuxRoot(Path("/"), Path("/"), required=True),),
|
|
write_roots=(LinuxRoot(allowed, allowed, required=True),),
|
|
denied_roots=(blocked,),
|
|
protected_subpaths=(),
|
|
env_allowlist=("PATH",),
|
|
network=NetworkMode.NONE,
|
|
tmp_writable=True,
|
|
wall_timeout_s=30,
|
|
)
|
|
|
|
argv = build_bwrap_argv(
|
|
command=["/bin/true"],
|
|
command_cwd=allowed,
|
|
permissions=permissions,
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
blocked_mask_index = next(
|
|
index
|
|
for index in range(len(argv) - 3)
|
|
if argv[index : index + 4] == ["--perms", "111", "--tmpfs", str(blocked)]
|
|
)
|
|
allowed_dir_index = next(
|
|
index
|
|
for index in range(len(argv) - 1)
|
|
if argv[index : index + 2] == ["--dir", str(allowed)]
|
|
)
|
|
blocked_remount_index = next(
|
|
index
|
|
for index in range(len(argv) - 1)
|
|
if argv[index : index + 2] == ["--remount-ro", str(blocked)]
|
|
)
|
|
allowed_bind_index = next(
|
|
index
|
|
for index in range(len(argv) - 2)
|
|
if argv[index : index + 3] == ["--bind", str(allowed), str(allowed)]
|
|
)
|
|
|
|
assert blocked_mask_index < allowed_dir_index < blocked_remount_index < allowed_bind_index
|
|
|
|
|
|
def test_bwrap_argv_reopens_writable_file_under_denied_parent(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
blocked = tmp_path / "blocked"
|
|
allowed_dir = blocked / "allowed"
|
|
allowed_file = allowed_dir / "note.txt"
|
|
allowed_dir.mkdir(parents=True)
|
|
allowed_file.write_text("ok", encoding="utf-8")
|
|
permissions = LinuxPermissions(
|
|
read_roots=(LinuxRoot(Path("/"), Path("/"), required=True),),
|
|
write_roots=(LinuxRoot(allowed_file, allowed_file, required=True),),
|
|
denied_roots=(blocked,),
|
|
protected_subpaths=(),
|
|
env_allowlist=("PATH",),
|
|
network=NetworkMode.NONE,
|
|
tmp_writable=True,
|
|
wall_timeout_s=30,
|
|
)
|
|
|
|
argv = build_bwrap_argv(
|
|
command=["/bin/true"],
|
|
command_cwd=allowed_dir,
|
|
permissions=permissions,
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
assert ["--perms", "111", "--tmpfs", str(blocked)] in [
|
|
argv[index : index + 4] for index in range(len(argv) - 3)
|
|
]
|
|
assert ["--dir", str(allowed_dir)] in [
|
|
argv[index : index + 2] for index in range(len(argv) - 1)
|
|
]
|
|
assert ["--dir", str(allowed_file)] not in [
|
|
argv[index : index + 2] for index in range(len(argv) - 1)
|
|
]
|
|
assert ["--bind", str(allowed_file), str(allowed_file)] in [
|
|
argv[index : index + 3] for index in range(len(argv) - 2)
|
|
]
|
|
|
|
|
|
def test_bwrap_argv_rejects_relative_mount_paths(tmp_path: Path) -> None:
|
|
permissions = LinuxPermissions(
|
|
read_roots=(),
|
|
write_roots=(LinuxRoot(Path("relative"), tmp_path, required=True),),
|
|
denied_roots=(),
|
|
protected_subpaths=(),
|
|
env_allowlist=("PATH",),
|
|
network=NetworkMode.NONE,
|
|
tmp_writable=True,
|
|
wall_timeout_s=30,
|
|
)
|
|
|
|
with pytest.raises(SandboxBackendError, match="host mount path must be absolute"):
|
|
build_bwrap_argv(
|
|
command=["/bin/true"],
|
|
command_cwd=tmp_path,
|
|
permissions=permissions,
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
|
|
def test_bwrap_argv_rejects_traversal_mount_paths(tmp_path: Path) -> None:
|
|
permissions = LinuxPermissions(
|
|
read_roots=(),
|
|
write_roots=(LinuxRoot(tmp_path / ".." / "workspace", tmp_path, required=True),),
|
|
denied_roots=(),
|
|
protected_subpaths=(),
|
|
env_allowlist=("PATH",),
|
|
network=NetworkMode.NONE,
|
|
tmp_writable=True,
|
|
wall_timeout_s=30,
|
|
)
|
|
|
|
with pytest.raises(SandboxBackendError, match="host mount path contains '..'"):
|
|
build_bwrap_argv(
|
|
command=["/bin/true"],
|
|
command_cwd=tmp_path,
|
|
permissions=permissions,
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|
|
|
|
|
|
def test_bwrap_argv_rejects_relative_command_cwd(tmp_path: Path) -> None:
|
|
with pytest.raises(SandboxBackendError, match="command cwd must be absolute"):
|
|
build_bwrap_argv(
|
|
command=["/bin/true"],
|
|
command_cwd=Path("relative"),
|
|
permissions=_permissions(tmp_path),
|
|
options=BwrapOptions(bwrap_path="bwrap", mount_proc=True),
|
|
)
|