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
1 change: 1 addition & 0 deletions aish.spec
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ a_sandbox = Analysis(
datas=[],
hiddenimports=[
'aish.security.sandbox_daemon',
'aish.security.sandbox_worker',
],
hookspath=[],
hooksconfig={},
Expand Down
10 changes: 10 additions & 0 deletions src/aish/sandboxd.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(
prog="aish-sandboxd", description="Privileged sandbox daemon for aish"
)
parser.add_argument(
"--sandbox-worker",
action="store_true",
help=argparse.SUPPRESS,
)
parser.add_argument(
"--socket-path",
default=str(DEFAULT_SANDBOX_SOCKET_PATH),
Expand All @@ -21,6 +26,11 @@ def main(argv: list[str] | None = None) -> int:

args = parser.parse_args(argv)

if args.sandbox_worker:
from aish.security import sandbox_worker

return sandbox_worker.main()

if os.geteuid() != 0:
print("aish-sandboxd must run as root", file=sys.stderr)
return 2
Expand Down
28 changes: 18 additions & 10 deletions src/aish/security/sandbox_daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,23 @@
_LOG_DETAIL_MAX_CHARS = 4096


def _build_worker_command() -> list[str]:
worker_cmd = [
"unshare",
"--mount",
"--propagation",
"private",
"--",
sys.executable,
]
if getattr(sys, "frozen", False):
worker_cmd.append("--sandbox-worker")
return worker_cmd

worker_cmd.extend(["-m", "aish.security.sandbox_worker"])
return worker_cmd


def _elapsed_ms(start_ts: float) -> int:
return int((time.monotonic() - start_ts) * 1000)

Expand Down Expand Up @@ -743,16 +760,7 @@ def _simulate_for_user(
"timeout_s": timeout_s,
}

worker_cmd = [
"unshare",
"--mount",
"--propagation",
"private",
"--",
sys.executable,
"-m",
"aish.security.sandbox_worker",
]
worker_cmd = _build_worker_command()
exec_timeout: Optional[float] = None
if timeout_s is not None:
exec_timeout = float(timeout_s) + 10.0
Expand Down
37 changes: 37 additions & 0 deletions tests/security/sandbox/test_daemon_isolation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,55 @@

import json
import subprocess
import sys
from pathlib import Path

import pytest

from aish.security.sandbox import SandboxUnavailableError
from aish.security import sandbox_daemon
from aish.security.sandbox_daemon import SandboxDaemon, SandboxDaemonConfig


def _make_daemon() -> SandboxDaemon:
return SandboxDaemon(SandboxDaemonConfig(socket_path=Path("/tmp/aish-test.sock")))


def test_build_worker_command_uses_module_entrypoint(monkeypatch):
monkeypatch.delattr(sys, "frozen", raising=False)
monkeypatch.setattr(sys, "executable", "/usr/bin/python3")

cmd = sandbox_daemon._build_worker_command()

assert cmd == [
"unshare",
"--mount",
"--propagation",
"private",
"--",
"/usr/bin/python3",
"-m",
"aish.security.sandbox_worker",
]


def test_build_worker_command_uses_internal_entrypoint_when_frozen(monkeypatch):
monkeypatch.setattr(sys, "frozen", True, raising=False)
monkeypatch.setattr(sys, "executable", "/usr/bin/aish-sandbox")

cmd = sandbox_daemon._build_worker_command()

assert cmd == [
"unshare",
"--mount",
"--propagation",
"private",
"--",
"/usr/bin/aish-sandbox",
"--sandbox-worker",
]


def test_simulate_for_user_uses_unshare_worker(monkeypatch):
daemon = _make_daemon()

Expand Down
10 changes: 10 additions & 0 deletions tests/security/sandbox/test_sandboxd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from __future__ import annotations

from aish import sandboxd
from aish.security import sandbox_worker


def test_sandboxd_main_dispatches_internal_worker(monkeypatch):
monkeypatch.setattr(sandbox_worker, "main", lambda: 17)

assert sandboxd.main(["--sandbox-worker"]) == 17
Loading