diff --git a/src/hqt/sandbox.py b/src/hqt/sandbox.py new file mode 100644 index 0000000..f1d5219 --- /dev/null +++ b/src/hqt/sandbox.py @@ -0,0 +1,33 @@ +import os # noqa: F401 +import shutil +import sys +from dataclasses import dataclass +from pathlib import Path + + +@dataclass(frozen=True) +class Bind: + """A host path to expose inside the sandbox (read-only unless writable).""" + + src: Path + writable: bool = False + + +@dataclass(frozen=True) +class SandboxPolicy: + """Per-session sandbox settings. + + fs: "rw" binds the project dir writable; "ro" binds it read-only. + net: True shares the host network namespace; False = no connectivity. + """ + + fs: str + net: bool + + +def is_available() -> bool: + """True when bubblewrap can be used: Linux with `bwrap` on PATH. + + The single source of truth for both `hqt doctor` and the New Session dialog. + """ + return sys.platform.startswith("linux") and shutil.which("bwrap") is not None diff --git a/tests/test_sandbox.py b/tests/test_sandbox.py new file mode 100644 index 0000000..52884f5 --- /dev/null +++ b/tests/test_sandbox.py @@ -0,0 +1,34 @@ +from pathlib import Path + +from hqt import sandbox +from hqt.sandbox import Bind, SandboxPolicy + + +def test_bind_defaults_readonly(): + b = Bind(Path("/home/u/.claude")) + assert b.src == Path("/home/u/.claude") + assert b.writable is False + + +def test_sandbox_policy_fields(): + p = SandboxPolicy(fs="rw", net=True) + assert p.fs == "rw" + assert p.net is True + + +def test_is_available_true_on_linux_with_bwrap(monkeypatch): + monkeypatch.setattr(sandbox.sys, "platform", "linux") + monkeypatch.setattr(sandbox.shutil, "which", lambda name: "/usr/bin/bwrap") + assert sandbox.is_available() is True + + +def test_is_available_false_without_bwrap(monkeypatch): + monkeypatch.setattr(sandbox.sys, "platform", "linux") + monkeypatch.setattr(sandbox.shutil, "which", lambda name: None) + assert sandbox.is_available() is False + + +def test_is_available_false_off_linux(monkeypatch): + monkeypatch.setattr(sandbox.sys, "platform", "darwin") + monkeypatch.setattr(sandbox.shutil, "which", lambda name: "/usr/bin/bwrap") + assert sandbox.is_available() is False