Package sandbox definitions and build a pinned owner runtime
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
This commit is contained in:
tegwick 2026-09-09 22:54:39 +02:00
parent bfe0e4c4c8
commit be42de7caf
9 changed files with 127 additions and 8 deletions

View file

@ -19,6 +19,9 @@ class OwnerMessagesRoute:
run_id: str
private_paths: tuple[Path, ...] = field(default=(), repr=False)
runtime_path: Path | None = None
runtime_sha256: str | None = None
def validate(self, profile, consumer, backend, inputs) -> None:
from sandboxer.extensions.bwrap import BwrapExtension
@ -32,6 +35,15 @@ class OwnerMessagesRoute:
or not self.run_id
):
raise ValueError("metered route consumer mismatch")
if self.runtime_path is not None or self.runtime_sha256 is not None:
if (self.runtime_path is None or not self.runtime_path.is_absolute()
or not isinstance(self.runtime_sha256, str)
or not re.fullmatch(r"[0-9a-f]{64}", self.runtime_sha256)):
raise ValueError("metered runtime requires exact path and digest")
# Trusted, in-memory bootstrap selection; never copied into public status.
backend.config = {**backend.config, "runtime": {
"path": str(self.runtime_path), "sha256": self.runtime_sha256,
}}
if profile.setup.secret_refs:
raise ValueError("metered route refuses setup credential acquisition")
if profile.network.default != "deny" or profile.network.egress:

View file

@ -11,7 +11,8 @@ import yaml
from sandboxer.models import Extension, Profile
_REPO_ROOT = Path(__file__).resolve().parents[3]
_EXTENSIONS_DIR = _REPO_ROOT / "extensions"
_PACKAGED_DIR = Path(__file__).resolve().parents[1] / "data" / "extensions"
_EXTENSIONS_DIR = _PACKAGED_DIR if _PACKAGED_DIR.is_dir() else _REPO_ROOT / "extensions"
_REQUIRED_CAPABILITY_FIELDS = ("isolation_levels", "pricing_model")

View file

@ -9,7 +9,8 @@ import yaml
from sandboxer.models import Profile
_REPO_ROOT = Path(__file__).resolve().parents[3]
_PROFILES_DIR = _REPO_ROOT / "profiles"
_PACKAGED_DIR = Path(__file__).resolve().parents[1] / "data" / "profiles"
_PROFILES_DIR = _PACKAGED_DIR if _PACKAGED_DIR.is_dir() else _REPO_ROOT / "profiles"
def profiles_dir() -> Path: