github opensandbox-group/OpenSandbox server/v0.2.2
server 0.2.2

one day ago

What's New

⚠️ Breaking Changes

  • Credential Vault requires dns+nft enforcement — DNS-only egress can no longer carry credential-bound traffic. Migrate to [egress] mode = "dns+nft"; defaultAction: allow still works but is deprecated and warns. #1136

  • X-Forwarded-Proto no longer trusted by default — the server proxy strips client-supplied forwarded headers and rebuilds them from the connection. Deployments that terminate TLS in front of the egress sidecar must list their proxy addresses in the new OPENSANDBOX_EGRESS_CREDENTIAL_VAULT_TRUSTED_PROXY_CIDRS. #1138

  • OPENSANDBOX_EGRESS_MITMPROXY_SCRIPT removed from the env allowlist — the variable let a sandbox point the egress sidecar's mitmdump -s at any file under the shared /opt/opensandbox emptyDir, enabling code execution in the sidecar and Credential Vault plaintext access. Requests carrying it are now rejected. Ship custom addons in a purpose-built egress image via ENV. #1194

🔒 Security

  • Secure-access token now enforced on the server proxy — the lifecycle proxy at /sandboxes/{id}/proxy/{port}/... previously skipped API-key checks and never validated the OpenSandbox-Secure-Access header (CVSSv3.1 ~7.5). Both HTTP and WebSocket paths now require a matching header (constant-time compare) and strip the token before forwarding. #1191

  • Sandbox pods no longer mount a service-account token — the kubernetes.service_account config is removed and automountServiceAccountToken: false is set on both providers. Nothing in the sandbox consumed the token. Operators depending on the SA's imagePullSecrets should move serviceAccountName into their agent-sandbox template. #1227

  • 21 CVE-remediating dependency bumpspydantic-settings, python-multipart, starlette, cryptography, pyjwt, undici, js-yaml. Direct deps pinned in pyproject.toml, transitives via [tool.uv] constraint-dependencies and pnpm.overrides. #1145

✨ Features

  • Multi-tenancy provider with file and HTTP backends — sandboxes and snapshots can be isolated per tenant via K8s namespaces. Ships a file provider (TOML with mtime hot-reload) and an HTTP provider (per-key TTL cache + singleflight). Tenant context is propagated per request through auth middleware; unavailable providers return 503. Closes #972 #497. #1184

  • sandbox.create latency reported via metrics events — new POST /v1/metrics/events accepts fire-and-forget MetricsEvent payloads and optionally records them as an OTEL histogram (opensandbox.sandbox.create.duration). Python/Go/JS SDKs already hook this on every create. Configure via [otel]. #1307

  • Sandbox extensions returned in lifecycle responsesCreateSandboxResponse, getSandbox, and listSandboxes now surface opensandbox.extensions.* back to callers, matching the values set at create time. K8s reads from pod annotations; Docker persists them as container labels. Closes #1060. #1112 #1167

  • Snapshot list supports exact-name filteringGET /snapshots accepts an optional name query parameter, honored through the API, service, and SQLite repository while preserving pagination. Exposed in the Python, JavaScript, Go, C#, and Kotlin SDKs. Closes #1205. #1301

  • Configurable Docker port range for bridge-mode sandboxes — new [docker] port_range_min / port_range_max fields (default 40000-60000) narrow host-port allocation so multiple bridge-mode sandboxes can expose distinct execd ports (host mode always binds 44772). #1182

  • OPENSANDBOX_EGRESS_POLICY_FILE and OPENSANDBOX_EGRESS_SANDBOX_ID now allowlisted — sandbox creates can opt into egress policy-file persistence and per-sandbox OTLP attribution (OSEP-0010) via the standard env field. #1190 #1335

  • JDK trust store hardened for MITM CAbootstrap.sh now discovers every JDK on the system and imports the egress MITM CA into each cacerts via keytool. Fixes PKIX failures on tarball / Alpine / distroless JDKs when using the credential proxy. Idempotent and best-effort. Closes #1201. #1229

🐛 Bug Fixes

  • Docker listSandboxes no longer flakes on concurrent deletion — docker-py's high-level containers.list() does a follow-up inspect per match, so a sibling cleanup mid-listing failed the whole call with 500. The service now uses the low-level docker_client.api.containers(...) summary endpoint and maps NotFound from single-container lookups to 404. List view drops entrypoint, exit code, and FinishedAt fidelity (callers needing those must use getSandbox). #1342

  • K8s informer honors informer_resync_seconds — periodic full resync was silently disabled while watch mode was active. Watch streams are now capped by the remaining resync interval. Fixes #1322. #1323

  • networkPolicy rejected in pool mode — combining extensions.poolRef with a networkPolicy is unsupported; requests are now rejected at schema validation with a defense-in-depth guard in BatchSandboxProvider. Closes #1315. #1319

  • Diagnostics scoped to the tenant namespace — K8s pod/log/event lookups use the request-scoped tenant namespace instead of the server default. Non-tenant requests unchanged. Closes #1304. #1305

  • use_server_proxy preserves the API mount prefix — the API is mounted both bare and under /v1, but proxied endpoints were derived from request.base_url and dropped the prefix, breaking ingress deployments that path-split /v1/*. The rewritten endpoint now keeps the prefix; server.eip is still respected verbatim. #1297

  • Renewed Docker sandbox expirations survive restart — timers were rebuilt from immutable container labels, so a renewed sandbox reverted to its original TTL. Renewals now write an override into the file-backed metadata store; old callbacks that observe a renewal rearm cleanly. Closes #1200. #1267

  • PVC readOnly propagated to the volume source — the flag was only applied to the mount, not to persistentVolumeClaim.readOnly on the pod spec. Both are now aligned. Closes #545. #1246

  • Fail fast for missing poolRef poolsextensions.poolRef is validated against the Pool CRD before creating a BatchSandbox, returning KUBERNETES::POOL_NOT_FOUND instead of failing downstream. Fixes #1175. #1176

  • Docker egress no longer crashes on hosts without IPv6 procfs entriesegress.disable_ipv6=true unconditionally injected net.ipv6.conf.*.disable_ipv6 sysctls. The injection is now skipped when the required procfs knobs are missing. Fixes #1168. #1172

  • Event loop no longer blocked during Docker image pull — provisioning runs on a daemon thread with an asyncio.Future so health checks stay responsive. New timeout_graceful_shutdown config (default 5s) makes SIGINT actually exit. #1171

  • K8s diagnostics logs endpoint works on multi-container podsread_namespaced_pod_log was called without a container argument, so every standard sandbox (with egress sidecar + execd-installer init) returned 500. The endpoint now defaults to the sandbox container, accepts ?container= for sidecar/init logs, and maps K8s errors to structured 400/403/404/502. Fixes #1150. #1151

📦 Misc

  • renew_intent marked stable — OSEP-0009 is out of experimental; drops [EXPERIMENTAL] / 🧪 markers from config docstrings, example TOML, startup logs, and configuration.md. No behavior change. #1350

  • Removed unused PendingSandbox machinery and fixed the spec — Docker and K8s both provision synchronously; the async worker, related helpers, and their tests were dead code (−357 lines). The POST /sandboxes 202 response description in specs/sandbox-lifecycle.yml also described a Pending → Running polling flow that was never implemented — now corrected. #1178

  • GHCR image publishing — component images (server, k8s, execd, egress, ingress) are now published to GitHub Container Registry alongside Docker Hub and Aliyun. Refs #1160. #1161

  • Package metadata and docs point at opensandbox-group/OpenSandbox — user-facing links across README, docs, Helm chart, examples, and server/cli pyproject.toml updated. No package rename. #1197 #1140

  • Auto-bumpsexecd v1.0.20 → v1.0.21 (#1144 #1279); egress v1.1.3 → v1.1.4 (#1142 #1278).

👥 Contributors

Thanks to these contributors ❤️


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

Don't miss a new OpenSandbox release

NewReleases is sending notifications on new releases.