Skip to content

server 0.2.3

Latest

Choose a tag to compare

@Pangjiping Pangjiping released this 26 Aug 09:39
· 6 commits to main since this release

What's New

⚠️ Breaking Changes

  • OPENSANDBOX_EGRESS_SANDBOX_ID is now server-injected and rejected in request env — the server unconditionally sets the egress sidecar's sandbox-id attribution variable in both Docker and Kubernetes runtimes, and removed it from the env allowlist. Requests that pass it in env now get a 400 instead of a user-spoofable value. #1381

✨ Features

  • Sandbox lifecycle hooks (preStart / periodic), OSEP-0020CreateSandboxRequest.lifecycle is accepted, validated (reserved transports, duplicate periodic names, pool-allocation combinations), and transported to Kubernetes workloads via the reserved OPEN_SANDBOX_LIFECYCLE env for execd to execute. Docker explicitly rejects lifecycle requests; PATCH and other hook types are out of scope. Ships with aligned Java/Kotlin, Python, and TypeScript SDK models. #1588 #1589

  • preStart.timeoutSeconds limit raised from 300s to 3 hours — server and OpenAPI limits now allow up to 10800s for pre-start hooks; the periodic limit stays at 300s. The execd-side product policy bound is removed, keeping policy changes server-only. #1637

  • QEMU VMState pause/resume for runc-based sandboxes — opt-in capture of guest memory/vCPU/device state via QMP migration; rootfs and compressed VMState are stored as separate OCI images keyed by immutable SHA-256 digests. Supports pooled BatchSandbox pause, detachment, and standalone restoration while preserving guest memory, writable disk, boot ID, and counter continuity. Rootfs-only snapshots remain backward compatible. #1584

  • Pool capacity exhaustion is now machine-identifiable — the controller publishes a PoolAllocationPending/PoolCapacityExhausted condition; the server waits a bounded acquisition window (new kubernetes.pool_acquisition_timeout_seconds, default 30s) and then returns HTTP 429 with KUBERNETES::POOL_CAPACITY_EXHAUSTED and Retry-After: 5 instead of the generic 504 readiness timeout. Older controllers safely fall back to the existing behavior. #1581

  • Pool allocation summary in lifecycle responsesgetSandbox now surfaces an optional Sandbox.allocation block (mode: pool, poolRef, state: allocated) for confirmed Kubernetes pool allocations, emitted only for concrete non-wildcard pool references with matching allocation evidence. No pod/namespace/IP data is exposed. #1481

  • Generic HTTP request metrics via OTLP — a thin ASGI middleware exports server.http.request.duration (ms) with http_method, matched http_route (or unknown for unrouted/auth-failed requests), and http_status_code attributes, complementing the existing create-duration histogram. Raw paths, IDs, keys, and bodies are never attributes; no-op when [otel] is disabled. #1561

  • Stable diagnostics API with scopes — diagnostics now honor the public inline descriptor contract: logs: container|all and events: runtime|lifecycle|all, with 400 DIAGNOSTICS_SCOPE_UNSUPPORTED for unknown scopes and explicit warnings for incomplete best-effort scopes. Deprecated no-scope plain-text responses still work with a Deprecation header. #1553

  • fast-sandbox fleets backend groundwork (OSEP-0007) — a FastPath v2 gRPC client wraps all FastPathService RPCs with typed error mapping (FastPathNotFound → 404, etc.), and a create/status mapping layer converts the public contract to fast-sandbox semantics, rejecting unsupported fields (volumes, platform, resourceRequests, credentialProxy, snapshotId, etc.) with clear errors. Not yet wired as an active runtime. #1558 #1559

  • Secure-access signing keys can come from a Kubernetes Secret — the server accepts OPENSANDBOX_SECURE_ACCESS_KEYS / OPENSANDBOX_SECURE_ACCESS_ACTIVE_KEY env overrides (mirroring the API-key override, gateway mode required), and the Helm chart adds server.gateway.secureAccess.existingSecret (mutually exclusive with plaintext keys, enforced at render time) so GitOps flows never commit key material. #1445

  • Docker runtime sandbox_env / sandbox_binds — new [docker] fields apply fleet-wide environment variables and host bind mounts to every sandbox container (request env wins over sandbox_env; config binds precede request-derived binds), giving the Docker runtime the operator-side hook the K8s pod template has. #1303

  • Egress sidecar readiness timeout configurable — new [egress] timeout_seconds (default 30s, non-positive values rejected) lets Docker deployments tune how long the server waits for the sidecar health endpoint. #1522

  • Tenant namespaces validated at startup (OSEP-0014) — the server fail-fast verifies every tenant namespace exists and is accessible before serving traffic, aggregating all missing/inaccessible namespaces into a single fatal error instead of failing only at request time. OSEP-0004/0005/0014 marked implemented. #1389

🔒 Security

  • CVE-remediating dependency bumpsgoogle.golang.org/grpc → v1.82.1 across kubernetes/ingress/execd/egress/internal (xDS RBAC and HTTP/2 fixes), postcss → 8.5.11 (arbitrary file read via sourceMappingURL). #1385

🐛 Bug Fixes

  • Docker endpoint lookups ~108x faster — container lookup now goes through the deterministic sandbox-<id> name with opensandbox.io/id label validation, falling back to the label scan only when needed. Local benchmark: 6.07s → 56ms for execd+egress endpoint resolution. #1400

  • Informer cache expires when the watch stallshas_synced now means "cache is currently live", not "an initial list finished once"; a stalled or half-open watch (e.g. after a control-plane upgrade) degrades to direct API reads instead of serving frozen status forever, which previously caused every create to 504 with POD_READY_TIMEOUT. Bound derived from existing knobs (resync_period + watch_timeout); no new config. #1534

  • Proxy connection leak on aborted responses — when a downstream client disconnected before response-body streaming started, the backend httpx response was never released, gradually exhausting the shared pool until httpcore.PoolTimeout. The proxy now owns the backend response for the full ASGI lifecycle, shields aclose() from cancellation, and releases on setup failure. Stress test: 1000/1000 disconnects cleaned up. #1488

  • Unique, stable proxy operation IDs — the 20 proxied HTTP operations previously emitted 4 process-dependent duplicate operation IDs (16 OpenAPI warnings); each method now gets its own deterministic ID with identical runtime dispatch, auth, and 405 behavior. Generated clients should be regenerated. #1634

  • PVC auto-create no longer crashes with a malformed 500 — the PVC owner-reference patch went through an unsupported _content_type path that raised ApiTypeError (leaving PVCs without owner refs) and SandboxErrorCodes.INTERNAL_ERROR was undefined, masking the real error. Both fixed: patch uses the supported strategic-merge call_api path; error code defined. #1538 #1447

  • Template container securityContext now reaches pods — the deep-merge previously replaced the template's containers wholesale, silently dropping container-level securityContext. Template keys now supplement (never override) runtime values, matching the existing volumeMounts philosophy. #1564

  • Root-relative backend redirects stay under the proxy routeLocation: /login from a sandbox backend is rebased to /v1/sandboxes/{id}/proxy/{port}/login; absolute, network-path, and query-only references are left untouched. #1516

  • Server-proxy endpoints drop the ingress routing headerOpenSandbox-Ingress-To (case-insensitive) is removed from use_server_proxy=true responses while secure-access and other endpoint headers are preserved. #1503

  • No duplicate Date/Server headers on proxied responses — the proxy preserves an origin Date while suppressing Uvicorn's default (and the backend Server header), emitting exactly one Date. #1471

  • Invalid-resume error no longer leaks controller internals — the 409 message for a Running (internally Succeed) sandbox now says "state Running" instead of "phase Succeed"; HTTP status and error code unchanged. #1586

  • Non-finite CPU limits rejectednan, infinite, and overflowed values are rejected before Docker NanoCpus conversion instead of being silently accepted. #1568

  • Mixed read-only PVC subPath mounts allowed — the PVC source is set read-only only when every mount of the claim is read-only; the service-level rejection that blocked legitimate mixed-policy PVC creation is removed. #1440

  • Agent-sandbox server-proxy endpoints resolve — internal endpoint resolution now delegates to the workload provider and reads agent-sandbox pod addresses from status.podIPs instead of the BatchSandbox-only annotation, and brackets IPv6 literals before appending the port. #1424

  • Version reporting fixed everywhere/openapi.json, installed package metadata, and the chart appVersion all reported stale 0.1.0; the server now reads its version from package metadata at runtime, builds inject SETUPTOOLS_SCM_PRETEND_VERSION, and the release script bumps Chart.yaml appVersion. #1439

📦 Misc

  • execd v1.0.22 ships OSEP-0018 init-mode hardening — execd as sandbox init (PID 1) with pre-exec hardening floor (env strip, bounding set, no_new_privs, identity drop, ambient caps, seccomp) and Kubernetes hardening e2e + PTY/bwrap coverage. #1474 #1555

  • Isolated-session fail-closed workload lifecycle gate — the server distributes a native Bubblewrap lifecycle gate to /opt/opensandbox for both runtimes; workloads stay blocked until execd marks them ready. First phase only — capability admission and session networking remain disabled. #1388

  • Egress transparent MITM can intercept extra TCP ports — experimental OPENSANDBOX_EGRESS_MITMPROXY_EXTRA_PORTS appends ports to the always-on 80/443 with fail-closed validation (multiport cap 15); credential binding still applies to canonical ports only. #1379

  • Auto-bumpsegress v1.1.5 → v1.1.7 (#1391 #1498 #1600); execd v1.0.22 (#1501).

👥 Contributors

Thanks to these contributors ❤️


  • PyPI: opensandbox-server==0.2.3
  • Docker Hub: opensandbox/server:v0.2.3
  • Aliyun Registry: sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/server:v0.2.3
  • GHCR: ghcr.io/opensandbox-group/server:v0.2.3