"""Free host rehearsal of an admitted owner runtime (REINAH-WP-0008-T01). The owner check reads only the first line of each launcher. The 2026-09-27 run 6efa9436 passed that and still failed with exit 127, because a launcher re-executed a deleted build-host interpreter. This rehearsal runs the launchers the way the sandbox does: inside bwrap, with the runtime read-only at the mount path, no network, a cleared environment and nothing else writable. It uses no credentials, provider route, queue or ledger. """ from __future__ import annotations import json import shutil import subprocess from dataclasses import dataclass from pathlib import Path from typing import Callable, Sequence RUNTIME_MOUNT = "/opt/sandboxer/runtime" # Same read-only system binds as sand-boxer's bwrap extension. SYSTEM_RO_BINDS = ("/usr", "/bin", "/lib", "/lib64", "/etc/resolv.conf", "/etc/ssl/certs") PYTHON_LAUNCHERS = ("rein-aharness", "glas-harness") TIMEOUT_SECONDS = 60 Runner = Callable[[Sequence[str], int], int] @dataclass(frozen=True) class Step: name: str exit_code: int @property def ok(self) -> bool: return self.exit_code == 0 def bwrap_argv(runtime: Path, command: Sequence[str], *, bwrap_bin: str = "bwrap") -> list[str]: argv = [ bwrap_bin, "--unshare-user", "--unshare-pid", "--unshare-ipc", "--unshare-uts", "--unshare-cgroup", "--unshare-net", "--tmpfs", "/", "--proc", "/proc", "--dev", "/dev", "--clearenv", ] for path in SYSTEM_RO_BINDS: if Path(path).exists(): argv += ["--ro-bind", path, path] argv += [ "--dir", "/opt", "--dir", "/opt/sandboxer", "--ro-bind", str(runtime), RUNTIME_MOUNT, "--dir", "/tmp", "--setenv", "HOME", "/tmp", "--setenv", "PATH", f"{RUNTIME_MOUNT}/bin:/usr/bin:/bin", "--chdir", "/tmp", ] return argv + list(command) def _run(argv: Sequence[str], timeout: int) -> int: try: return subprocess.run( list(argv), stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=timeout, ).returncode except subprocess.TimeoutExpired: return 124 except OSError: return 127 def _expects_claude(runtime: Path) -> bool: try: info = json.loads((runtime / "build-info.json").read_text()) except (OSError, ValueError): return False return isinstance(info, dict) and isinstance(info.get("claude"), dict) def rehearse(runtime: Path, *, run: Runner = _run, bwrap_bin: str | None = None) -> list[Step]: """Run each launcher once inside bwrap; return one step per launcher.""" bwrap = bwrap_bin or shutil.which("bwrap") if bwrap is None: return [Step("bwrap", 127)] commands = [(name, [f"{RUNTIME_MOUNT}/bin/{name}", "--help"]) for name in PYTHON_LAUNCHERS] if _expects_claude(runtime): commands.append(("claude", [f"{RUNTIME_MOUNT}/bin/claude", "--version"])) return [ Step(name, run(bwrap_argv(runtime, command, bwrap_bin=bwrap), TIMEOUT_SECONDS)) for name, command in commands ]