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:
parent
877676d1f1
commit
d79e3fe358
23 changed files with 1321 additions and 86 deletions
|
|
@ -2,13 +2,18 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import FastAPI, HTTPException
|
||||
import hmac
|
||||
import os
|
||||
|
||||
from fastapi import FastAPI, Header, HTTPException
|
||||
|
||||
from sandboxer.core.manager import SandboxManager
|
||||
from sandboxer.models import (
|
||||
ExpireActionResult,
|
||||
ExtendTtlRequest,
|
||||
SandboxCreateRequest,
|
||||
SandboxExecRequest,
|
||||
SandboxExecResult,
|
||||
SandboxStatus,
|
||||
SnapshotRecord,
|
||||
SnapshotRestoreRequest,
|
||||
|
|
@ -18,6 +23,16 @@ app = FastAPI(title="sand-boxer", version="0.0.0")
|
|||
_manager = SandboxManager()
|
||||
|
||||
|
||||
def _authorize_exec(authorization: str | None) -> None:
|
||||
"""Require an explicit owner-service capability on the high-risk exec route."""
|
||||
expected = os.environ.get("SANDBOXER_EXEC_TOKEN")
|
||||
if not expected:
|
||||
raise HTTPException(status_code=503, detail="owner execution API is not configured")
|
||||
scheme, _, supplied = (authorization or "").partition(" ")
|
||||
if scheme.lower() != "bearer" or not hmac.compare_digest(supplied, expected):
|
||||
raise HTTPException(status_code=401, detail="invalid owner execution credential")
|
||||
|
||||
|
||||
@app.post("/v1/sandboxes", response_model=SandboxStatus)
|
||||
def create_sandbox(request: SandboxCreateRequest, host: str | None = None) -> SandboxStatus:
|
||||
try:
|
||||
|
|
@ -42,6 +57,25 @@ def get_sandbox_reachability(sandbox_id: str) -> dict:
|
|||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.post("/v1/sandboxes/{sandbox_id}/exec", response_model=SandboxExecResult)
|
||||
def execute_in_sandbox(
|
||||
sandbox_id: str,
|
||||
request: SandboxExecRequest,
|
||||
authorization: str | None = Header(default=None),
|
||||
) -> SandboxExecResult:
|
||||
_authorize_exec(authorization)
|
||||
try:
|
||||
return _manager.execute(sandbox_id, request)
|
||||
except KeyError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
except PermissionError as exc:
|
||||
raise HTTPException(status_code=403, detail=str(exc)) from exc
|
||||
except RuntimeError as exc:
|
||||
raise HTTPException(status_code=409, detail=str(exc)) from exc
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get("/v1/sandboxes", response_model=list[SandboxStatus])
|
||||
def list_sandboxes() -> list[SandboxStatus]:
|
||||
return _manager.list()
|
||||
|
|
@ -117,4 +151,4 @@ def extend_sandbox_ttl(sandbox_id: str, request: ExtendTtlRequest) -> SandboxSta
|
|||
|
||||
@app.post("/v1/sandboxes/expire", response_model=list[ExpireActionResult])
|
||||
def expire_sandboxes(apply: bool = False) -> list[ExpireActionResult]:
|
||||
return _manager.expire(apply=apply)
|
||||
return _manager.expire(apply=apply)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue