Add owner-mediated bwrap execution boundary

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a06def-6490-7033-8448-2eab2d12ed44
This commit is contained in:
tegwick 2026-09-04 22:12:19 +02:00
parent 877676d1f1
commit d79e3fe358
23 changed files with 1321 additions and 86 deletions

View file

@ -2,6 +2,10 @@
from __future__ import annotations
import re
from pathlib import Path
from threading import Lock
from sandboxer.extensions.registry import load_extension, resolve_backend
from sandboxer.lifecycle.expire import (
ExpireCandidate,
@ -17,6 +21,8 @@ from sandboxer.models import (
MeterRecord,
Reachability,
SandboxCreateRequest,
SandboxExecRequest,
SandboxExecResult,
SandboxState,
SandboxStatus,
SnapshotRecord,
@ -39,6 +45,8 @@ from sandboxer.telemetry.introspection import (
class SandboxManager:
_CREDENTIAL_ROUTE_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$")
def __init__(
self,
store: SandboxStore | None = None,
@ -48,6 +56,7 @@ class SandboxManager:
self.store = store or SandboxStore()
self.credits = credits or CreditsStore()
self.snapshots = snapshots or SnapshotStore()
self._exec_locks: dict[str, Lock] = {}
@staticmethod
def _handle_from_status(status: SandboxStatus) -> dict[str, str]:
@ -207,6 +216,138 @@ class SandboxManager:
return build_reachability_report(status)
@staticmethod
def _validate_exec_consumer(status: SandboxStatus, request: SandboxExecRequest) -> None:
if request.consumer != status.consumer:
raise PermissionError(
"execution consumer does not exactly match sandbox "
"actor/project/session/run identity"
)
@classmethod
def _validate_exec_request(cls, request: SandboxExecRequest) -> None:
if not request.command[0] or any("\x00" in arg for arg in request.command):
raise ValueError("command arguments must be non-empty and contain no NUL bytes")
command_size = sum(len(arg.encode("utf-8")) for arg in request.command)
if command_size > 65_536:
raise ValueError("command argument vector exceeds 65536 bytes")
invalid_refs = [
ref
for ref in request.credential_route_refs
if not cls._CREDENTIAL_ROUTE_RE.fullmatch(ref)
]
if invalid_refs:
raise ValueError("credential route references must be value-free catalog identifiers")
if len(set(request.credential_route_refs)) != len(request.credential_route_refs):
raise ValueError("credential route references must be unique")
def execute(self, sandbox_id: str, request: SandboxExecRequest) -> SandboxExecResult:
"""Run a command through the owning extension without a host fallback."""
lock = self._exec_locks.setdefault(sandbox_id, Lock())
if not lock.acquire(blocking=False):
raise RuntimeError("Sandbox already has an active owner-mediated command")
try:
return self._execute_locked(sandbox_id, request)
finally:
lock.release()
def _execute_locked(
self, sandbox_id: str, request: SandboxExecRequest
) -> SandboxExecResult:
status = self.store.get(sandbox_id)
if not status:
raise KeyError(f"Sandbox not found: {sandbox_id}")
self._validate_exec_request(request)
self._validate_exec_consumer(status, request)
if status.state != SandboxState.READY:
raise RuntimeError(
f"Sandbox must be ready for execution (state={status.state.value})"
)
now = utcnow()
if status.expires_at and now >= status.expires_at:
raise RuntimeError("Sandbox TTL has expired")
profile = load_profile(status.profile_id)
extension = load_extension(status.extension_id)
backend = resolve_backend(extension)
if not backend.supports_execution():
raise RuntimeError(
f"Extension {status.extension_id} has no owner-mediated execution boundary"
)
command_name = Path(request.command[0]).name
status.state = SandboxState.ACTIVE
status.updated_at = now
self.store.save(status)
emit_lifecycle_event(
status,
summary=f"Owner-mediated command started ({command_name})",
event_type=event_type_for_state(status.state),
)
context = {
"sandbox_id": status.sandbox_id,
"profile_id": status.profile_id,
"actor": status.consumer.actor.value,
"project": status.consumer.project,
}
if status.consumer.session_id:
context["session_id"] = status.consumer.session_id
if status.consumer.run_id:
context["run_id"] = status.consumer.run_id
try:
execution = backend.execute(
self._handle_from_status(status),
request.command,
credential_route_refs=request.credential_route_refs,
execution_context=context,
timeout_seconds=request.timeout_seconds,
max_output_bytes=request.max_output_bytes,
)
except Exception as exc:
status.state = SandboxState.READY
status.updated_at = utcnow()
self.store.save(status)
emit_lifecycle_event(
status,
summary=f"Owner-mediated command boundary failed ({command_name}): {exc}",
event_type="note",
)
raise
completed_at = utcnow()
status.state = SandboxState.READY
status.updated_at = completed_at
self.store.save(status)
emit_lifecycle_event(
status,
summary=(
f"Owner-mediated command completed ({command_name}, "
f"exit={execution['exit_code']}, timed_out={execution['timed_out']})"
),
event_type=event_type_for_state(status.state),
)
return SandboxExecResult(
sandbox_id=status.sandbox_id,
profile_id=status.profile_id,
extension_id=status.extension_id,
consumer=status.consumer,
command_name=command_name,
exit_code=int(execution["exit_code"]),
timed_out=bool(execution["timed_out"]),
stdout=str(execution["stdout"]),
stderr=str(execution["stderr"]),
output_truncated=bool(execution["output_truncated"]),
duration_seconds=max(0.0, (completed_at - now).total_seconds()),
workspace_dir=str(execution["workspace_dir"]),
network_default=profile.network.default,
network_egress=profile.network.egress,
credential_route_refs=request.credential_route_refs,
started_at=now,
completed_at=completed_at,
)
def list(self) -> list[SandboxStatus]:
return sorted(self.store.list_all(), key=lambda s: s.created_at, reverse=True)
@ -510,4 +651,4 @@ class SandboxManager:
summary=f"Snapshot restore failed: {exc}",
event_type=event_type_for_state(status.state),
)
raise
raise