Skip to content

Releases: opensandbox-group/OpenSandbox

OpenSandbox 1.2.0-rc.2

Pre-release

Choose a tag to compare

@github-actions github-actions released this 21 Oct 12:39
5659365

Second release candidate on the 1.2.0 line, carrying everything merged since release-1.2.0-rc.1 — the headline is the Credential Vault (OSEP-0022) landing end to end for fast sandboxes: an egress-held vault with durable per-subject persistence and pause/resume transfer, the user-reachable server-routed vault API, and a pool-pinned MITM CA. Network policy follows the same egress-held pattern, and NetworkRule gains port-scoped rules in the classic profile — fast sandboxes reject them fail-closed until the fastlet nft path enforces them. Images publish now; SDK/CLI packages ship at the 1.2.0 stable bump. Please test and report issues.

Highlights

  • Credential Vault (OSEP-0022) lands end to end for fast sandboxes: the egress sidecar holds the vault with durable per-subject files, sealed snapshot transfer for pause/resume, and stale-subject takeover on slot reuse (#2249 #2252 #2255 #2250); the server exposes the user-reachable POST|GET|PATCH|DELETE /v1/sandboxes/{id}/credential-vault API over the FastPath handler relay with credential values never appearing on any public read (#2263), and the MITM CA is pinned per pool so an egress restart no longer rotates the trust anchor under live sandboxes (#2251)
  • Network policy mirrors the vault: the recorded fast-sandbox policy becomes egress-held state with relay CRUD, durable persistence, and pause/resume snapshot transfer (#2309), and NetworkRule gains port-scoped rules end to end in the classic profile — spec, sidecar nftables, server validation, and all five SDKs, while fast sandboxes reject ports fail-closed for now — plus an operator-side TCP port floor that no user policy can open (#2212)
  • Lifecycle and diagnostics polish: lifecycle.renewalPolicy replaces the opaque renew extensions key (OSEP-0009) (#2296); the diagnostics context API reaches server, all five SDKs, and the CLI (#2292); execd fixes make start failures distinguishable, preserve session output byte-for-byte, and stop silent disk growth (#2303 #2318 #2295)

Server

  • Implement the server side of the Credential Vault (OSEP-0022, fast-sandbox profile): the user-reachable POST|GET|PATCH|DELETE /v1/sandboxes/{id}/credential-vault API pushes complete vault revisions over the FastPath InvokeHandlerAction handler relay and treats the relay response as the synchronous egress-validated ack — the CRD never carries vault material, and every public read is sanitized server-side; PATCH composes in memory (delete → replace → add, each name resolving at most once) with expectedRevision as the cross-replica backstop, non-fsb backends proxy the sidecar's /credential-vault surface, and the fsb credentialProxy create-time rejection is lifted (#2263)
  • Bake the pinned MITM CA into server-created SandboxTemplates (OSEP-0022): new [kubernetes] template_mitm_ca_secret / template_mitm_ca_secret_key config (default off) emits spec.egressMitmCertificate — the certificate entry only, never the private key — on every server-created template; the Secret must exist in each template namespace (ops-runbook distribution), and a missed copy fails the build observably (#2288)
  • Add lifecycle.renewalPolicy (OSEP-0009): the renew-on-access opt-in moves from the opaque extensions["access.renew.extend.seconds"] create key to a structured renewalPolicy.extendSeconds (300–86400), mirroring the idlePolicy pattern; the legacy key is deprecated (supported throughout 1.x, removed in 2.0), setting both is accepted only when the parsed values match, the value normalizes into the existing Docker label / Kubernetes annotation so pre-upgrade sandboxes keep renewing, and fast sandbox rejects it with 400 rather than silently accepting a no-op (#2296)
  • Implement the diagnostics context endpoint (OSEP contract from rc.1): GET /v1/sandboxes/{sandboxId}/diagnostics/context returns the sandbox ID, lifecycle state, backend type, and backend-defined identifiers for Docker, Kubernetes, and Fast Sandbox without connecting to execd — Kubernetes context stays available before a Pod is allocated, and extension backends that don't implement it return 501 (#2292)
  • Forward the still-encoded path through the sandbox proxy: Starlette bound the {full_path:path} route from the percent-decoded path and the proxy pasted that value back into the upstream URL, so a decoded ? started a query, # a fragment, %2F became a separator, %25 and non-UTF-8 escapes were rewritten, and %2E%2E segments were resolved — the proxy now takes the client's still-encoded tail from the raw path (validating it decodes to the routed path, with a re-encode fallback) and reads the query from the raw query string; backends receive request targets byte-for-byte, matching the ingress gateway, and the %2E%2E prefix-escape on Docker host-mapped endpoints is closed (#2228)
  • Report BatchSandbox expiry while the pod is still Running: a past spec.expireTime was still reported as Running (Ready pod with IP), so wall-clock billing kept growing after the configured timeout; expiry now checks before the ready states and returns Terminated / SANDBOX_EXPIRED with last_transition_at set to the expireTime itself (#2238)
  • Reject gVisor snapshots that would silently drop writes: docker commit under gVisor's default --overlay2=root:self can report READY while restoring none of the sandbox's writes (only the opaque /.gvisor.filestore.* entry is visible); snapshot preflight now resolves the container's runtime and refuses gVisor unless the effective args include --overlay2=none, and create fails closed when the filesystem diff is filestore-only (#2241)
  • Apply [docker] security profiles and secure_runtime to the execd cache container: it ignored apparmor_profile / seccomp_profile / docker_runtime, so on a host whose default seccomp profile blocks the execd image, every POST /sandboxes failed 503 with no configuration escape (#2254)
  • Make concurrent Docker metadata patches safe: the store's read-modify-write was unlocked and every write shared one temporary name, so two concurrent PATCH /metadata requests for a sandbox raced into a 500 (FileNotFoundError on rename) or silently dropped the other's key; a store-wide lock plus per-write temp names serialize patches (last write wins per key), a failed write no longer leaves its temp file behind, and the endpoint contract is now documented per runtime — Kubernetes patches write back the whole label set it read, fsb patches send only their own keys fenced by UID and generation (#2267 #2281)
  • Resolve proxy endpoints off the event loop: HTTP/WebSocket proxy handlers called the synchronous get_endpoint directly — a Docker socket call per proxied request on Docker, an apiserver read on Kubernetes cache misses — blocking the loop for every other request and stream; a slow Docker daemon (e.g. during an image pull) was enough to freeze the server; the lookup now runs via asyncio.to_thread with tenant context preserved (#2268)
  • Apply the renew cooldown when the Redis consumer is enabled: proxy renews skipped min_interval_seconds entirely (every proxied request ran a get_sandbox + expiration renew) and queue intents were only throttled per ingress replica, so N replicas renewed up to N times per interval; the cooldown now applies to every renew source and starts only after a successful renew (#2276 #2279)

SDKs

Code changes below ride the 1.2.0 stable release — rc ships no SDK packages.

  • Add the Credential Vault client contract to all five SDKs (OSEP-0022): template-backed sandboxes route vault calls through the server on the same template-origin signal as network policy (OPEN-SANDBOX-ORIGIN: template or the local createFromTemplate flag), while sidecar-direct adapters stay untouched; Python's Sandbox.credential_vault now returns the vault service for both profiles, and Go gains Sandbox-level vault methods branching on the same signal (#2263)
  • Add lifecycle.renewalPolicy to all five SDKs (OSEP-0009): a typed create field with client-side fail-fast validation (extendSeconds 300–86400) wired through the create converters, replacing the opaque extensions key (#2296)
  • Implement diagnostics across the SDK surface (with [#2292](https://github.com/op...
Read more

OpenSandbox 1.2.0-rc.1

Choose a tag to compare

@github-actions github-actions released this 15 Oct 09:20
cf61f3d

First release candidate on the 1.2.0 line, carrying everything merged since release-1.1.1 — the headline is OSEP-0024: auto-pause and wake-on-access for fast sandboxes, landing end to end. Images publish now; SDK/CLI packages ship at the 1.2.0 stable bump. Please test and report issues.

Highlights

  • Auto-pause and wake-on-access for fast sandboxes (OSEP-0024) lands end to end: ingress activity tracking and the wake path, the server-side idle sweeper, the opt-in lifecycle.idlePolicy create field, and the wake-retry contract in all five SDKs — off by default, additive only (#2156 #2180 #2192 #2198 #2218)
  • Egress sidecar (experimental, opt-in): live credential-bound Vault admission, HTTP/2 support with bounded drain, atomic policy-file persistence, and runtime fault containment (#2176 #2201 #2182 #2162 #2172)
  • SDK reliability: file uploads and downloads are no longer aborted at the 30-second request timeout in any of the five SDKs; execd now reports sandbox-scoped CPU/memory and OOM kills (#2165 #2186 #2196 #2206 #2191 #2200)

Server

  • Implement the server side of OSEP-0024 auto-pause for fast sandboxes: the lifecycle create field lifecycle.idlePolicy (idleTimeoutSeconds 30–86400, onIdle: pause, wakeOnAccess, optional activeProbe) validates with pydantic bounds and persists as the reserved sandbox.opensandbox.io/idle-policy Sandbox CR annotation (annotation-write failure stays fail-safe — the sandbox is created unpolicied); an idle sweeper enumerates opted-in fsb sandboxes from the informer cache, checks activity in Redis (monotonic-max writes, missing-key tombstones can only delay a pause), takes a per-sandbox pause lock with re-verify under lock, and issues an idempotent FastPath PauseSandbox; a declared activeProbe executes through the ingress gateway and a busy answer records ordinary activity; an OpenSandbox-Skip-Activity: skip sentinel suppresses the observation for one request and is stripped on both gateway and server-proxy hops (#2192 #2181)
  • Configure idle-pause under the new lifecycle-automation umbrella: [idle_pause] becomes [automation.idle_pause] and the redundant redis.enabled gate is removed — redis.dsn is required (validated at load) when enabled = true, failing loudly instead of silently not starting the sweeper; configuration.md is rewritten for conciseness and now documents ingress.secure_access and the missing env-var overrides (#2215)
  • Default BatchSandbox pods to restartPolicy: Never: a kubelet in-place container restart recreated the main container from its image — wiping the writable layer and in-memory state — while the sandbox kept reporting Succeed; restarting is never a meaningful recovery for a sandbox, so the honest default is no restart, which also makes the controller's terminal-failure path reachable. An explicit restartPolicy in the template still wins, the Windows profile keeps forcing Always (multi-phase installation relies on it), and pool mode is unchanged (#2128)
  • Treat pasta/slirp4netns/none as container-runtime network modes and pass them straight through, making podman's kernel-level networking selectable — on Windows 11 + WSL2 where netavark breaks bridge mode, pasta was the only working network and previously failed create with a 400 asking for a user-defined Docker network; networkPolicy is now rejected for these modes since there is no bridge for the egress sidecar to attach to (previously silently accepted for none) (#2203)
  • Parse Docker timestamps whose fractional second is not 3 or 6 digits: Docker writes RFC3339Nano (trailing zeros dropped), Python 3.10's fromisoformat rejects 5-digit fractions, and the helper fell back to datetime.now() — so createdAt and status.lastTransitionAt silently reported the current time; the fraction is now zero-padded to 6 digits (#2220)

SDKs

Code changes below ride the 1.2.0 stable release — rc ships no SDK packages.

  • Add the OSEP-0024 SDK contract to all five languages: a typed lifecycle.idlePolicy create field (IdlePolicy/ActivityProbe models with client-side fail-fast validation mirroring the server: timeout 30–86400 s, onIdle: "pause" pairing, probe path/timeout bounds; wired through both standard and template create) and the wake-retry contract — on a 503 carrying the gateway-owned OpenSandbox-Wake: expired marker (its presence proves the request was parked and never forwarded, making any-method retry safe), the SDK resends after Retry-After under a bounded budget (default 5 attempts / 60 s, per-client knobs), exhaustion raises a typed wake-timeout exception carrying attempts and waited time, the server-side resume is never canceled, bare 503 handling is unchanged, and SSE/streaming transports bypass wake retry (#2198 #2218)
  • Stop capping file uploads and downloads at the request timeout (30 s default) in all four remaining SDKs — the whole-call timeout (http.Client.Timeout, OkHttp callTimeout, AbortController, HttpClient.Timeout) covered sending the request body and reading the response, so any large or slow transfer failed mid-flight even while healthy; transfers now run on a dedicated client with no whole-call deadline that still bounds the wait for response headers, so a stalled transfer still fails instead of hanging (#2165 #2186 #2196 #2206)
  • Suppress sandbox.create client metrics for client-pool warmup creates in Go, Python, and JavaScript, aligning with Kotlin: warmup traffic (hardcoded skipHealthCheck, hundreds of ms) previously mixed into user-facing create-latency metrics and dragged p50/p99 down; direct-create from pool acquire and user-facing creates keep reporting (#2199)

Python

  • Clean up cancelled async pool startup: cancelling SandboxPoolAsync.start() mid-await left the instance stuck in STARTING, where a subsequent start() silently returned and startup-owned resources skipped cleanup; cancellation now reuses the reconciliation cleanup path, moves to STOPPED, and re-raises so the caller can retry (#2209)
  • Stop reporting failed file replacements as successful: the ordinary filesystem adapters caught and discarded the generated client's JSONDecodeError, so an empty or non-JSON HTTP 400/500 from replace_contents() returned success and an agent could keep building on an unapplied edit; the catch is removed and the documented SandboxException failure contract is restored (isolated-session adapters keep their empty-body compatibility catch) (#2222)

Go

  • Strip all OPEN-SANDBOX-*/OPENSANDBOX-* headers and every configured authentication header (including X-EXECD-ACCESS-TOKEN, X-API-Key, and custom WithAuthHeader names) on cross-origin redirects, comparing each destination against the initial request's scheme, host, and effective port so credentials cannot reappear on later foreign-origin hops; applied across lifecycle, execd, egress, file transfers, SSE, and creation metrics while preserving custom CheckRedirect policies (#2178)

Controller

  • Retain a BatchSandbox until cleanup completes: a deleted sandbox could disappear from the lifecycle API (GET 404) while its owned pod still ran, letting a replacement sandbox write the same persistent directory before the old writer exited; deletion now uses foreground cascading deletion alongside the existing task-cleanup and pool-release finalizers, and TTL reconciliation stops once deletion is accepted — DELETE still returns 204 when accepted, queries report Stopping during managed cleanup, and 404 arrives only after the runtime is gone; all five SDKs' kill docs and logs describe the accepted-deletion semantics (#2154)

Execd

  • Report OOM kills via cgroupfs polling: kernel-side evidence was out of reach from inside a sandbox (no CAP_SYSLOG, no /dev/kmsg), so OOM events were unobservable; execd now polls the sandbox cgroup every 5 s and diffs the kernel OO...
Read more

OpenSandbox 1.1.1

Choose a tag to compare

@github-actions github-actions released this 09 Oct 15:09

Stable cut of the 1.1.1 patch line: fixes the broken 1.1.0 server wheel — hatchling's VCS-exclude filtering silently dropped the committed FastPath gRPC stubs from the PyPI package, so every 1.1.0 install of opensandbox-server failed at import time; PyPI is immutable, so the fix ships on this line (#1959). SDK/CLI/server packages publish at 1.1.1 (1.1.1-rc.1 shipped images only). Everyone on 1.1.0 should upgrade. Baseline for every section below: release-1.1.0.

Highlights

  • Fixes the 1.1.0 server wheel: FastPath stubs now ship in the package and installs import cleanly; SDK/CLI/server packages publish at 1.1.1 (#1959)
  • Identity-bound filesystem operations: execd executes file APIs as an explicit Linux UID/GID, with FilesWithIdentity/files_with_identity in all five SDKs; isolated sessions gain multiple independent overlay mounts (#2070 #2093 #2094 #2095 #2096 #2097 #2032)
  • Server hardening: snapshot creation submits the runtime object before persisting so early reads can't map to Failed, proxied backend failures map to 502/504 instead of a generic 500, and diagnostics work for pooled sandboxes (#2098 #2077 #2084 #2104)

Server

  • Implement pause/resume for the agent-sandbox provider by bridging to spec.operatingMode (Running/Suspended) on agents.x-k8s.io/v1beta1, with state derivation (Paused/Pausing/Resuming/Terminated) and 409 on invalid transitions; both endpoints previously returned "not supported" (#1975)
  • Isolate tenants that share one Kubernetes namespace: creates stamp opensandbox.io/tenant, and list/get/delete/pause/resume/proxy hide other tenants' labeled sandboxes as 404 while unlabeled legacy sandboxes stay visible until expiry; also adds kubernetes.insecure_skip_tls_verify for ServiceAccount CA mismatches (#1973)
  • Heal the silent renew-intent drop after a server restart in multi-tenant mode: the resolver now falls back to a cluster-wide label lookup with a 403 circuit breaker and structured warnings, trusts an ingress-observed namespace from the intent payload when verifiable, and single-tenant deployments never resolve beyond the configured namespace (#1819)
  • Add [docker] publish_host to publish bridge-mode sandbox ports on one host address (default 0.0.0.0 unchanged) — with 127.0.0.1 or the Docker bridge gateway, the tokenless execd port no longer lands on public interfaces (#1954)
  • Add a typed, admin-only [egress.upstream_proxy] config section (URL + optional authorization, validated at load) that injects the sidecar's chained upstream CONNECT proxy on both Docker and Kubernetes, with fail-closed 400s when the requested networkPolicy is incompatible; secret values are no longer echoed in config-validation errors (#1999), plus ca_cert_path (Docker) and ca_secret_name (Kubernetes) so https:// proxies signed by a private CA are trusted without replacing the system trust store — the PEM augments /etc/ssl/certs in the sidecar (#2030)
  • Make snapshot creation race-free for early readers on k8s/fsb: POST /sandboxes/{id}/snapshots now creates the runtime object (SandboxSnapshot CR / fsb submit) before persisting the Creating row and returns without queueing a worker, so read-time sync can no longer map a not-yet-created object to Failed — including on other HA replicas; recovery resubmits stuck rows inline (#2098), fixing the window where a client polling right after create flipped the row to a permanent Failed (#2077)
  • Map proxied backend failures to meaningful statuses: read/write timeouts return 504 BACKEND_TIMEOUT, mid-response resets and protocol errors return 502 BACKEND_RESPONSE_FAILED, keeping 502 BACKEND_CONNECTION_FAILED for connect failures — a sandbox that dies mid-request no longer looks like a server bug (#2084)
  • Find pool-allocated pods for k8s diagnostics: pooled BatchSandboxes don't carry the opensandbox.io/id pod label, so every logs/events/inspect call returned 404; the lookup now falls back to the pods listed in the workload's alloc-status annotation (#2104)
  • Remove auto-created Docker volumes when create fails before the provisioning block runs (image pull, credential/upstream-proxy checks, Windows prerequisites, OSSFS prep) — a mistyped image name no longer leaks the PVC it triggered (#2103)
  • Report deleting pooled/task-mode BatchSandboxes as Stopping/DELETING: metadata.deletionTimestamp now wins over runtime status publication, so a sandbox whose pods go not-ready during finalization no longer flips back to Pending/CREATING (#2122)
  • Stop Docker metadata PATCHes from resurrecting deleted keys: patch() now starts from the override file (as get() does) instead of re-merging container labels, so {"env": null} stays deleted and an emptied override file doesn't restore the original labels (#2065)
  • Accept env on template create and bake it into the fast-sandbox golden image (/etc/sandbox-init.env, inheriting the source image's OCI Config.Env), closing the gap where SandboxTemplate.spec.envs existed but the lifecycle API rejected it; supported across all SDKs (#1984)
  • Wake Kubernetes creation waits on informer watch events instead of fixed 1-second polling, cutting prewarmed-pool create latency from ~1 s to tens of milliseconds while keeping the polling fallback (#1996)
  • Ship the committed FastPath gRPC stubs in the server wheel by force-including them past hatchling's VCS excludes, and smoke-import the built wheel in the release workflow before publishing — this is the 1.1.0 install-time breakage fix (#1959)
  • Fix the Fast Sandbox snapshot CR plural (sandboxsnapshots) in Helm RBAC and the fsb snapshot runtime, where sandboxesnapshots could fail list/watch with missing RBAC (#1972)
  • Propagate the underlying FastPath error message through the 429 capacity mapping (keeping status and Retry-After, adding a cause field) so admission/runtime failures like a broken KVM device are no longer masked as pool exhaustion, and warn-log the raw error before mapping (#2001)
  • Clarify the renewal contract: renew-expiration may shorten, preserve, or extend expiration (any future target is valid) and max_sandbox_timeout_seconds caps only creation, not renewal or total lifetime — documentation and SDK references aligned, with regression coverage across Docker, Kubernetes, and FastSandbox (#2087)
  • Fix Docker edges: reject a repeated pause of an already-paused sandbox with the documented 409 instead of surfacing Docker's "already paused" as 500 (#2023), and clear Docker masked/read-only system paths only for sandboxes that opt into the isolation extension so nested Bubblewrap can mount a private procfs (#1982)

SDKs

  • Add identity-bound filesystem operations end to end: execd gains additive /v1/filesystem/{uid}/{gid} routes backed by a per-request worker process running with explicit credentials and account-derived supplementary groups (fail-closed, existing routes unchanged), and every sandbox SDK exposes it — Python files_with_identity, JavaScript filesWithIdentity, Kotlin filesWithIdentity, C# FilesWithIdentity, Go FilesWithIdentity — so Linux checks the selected user's permissions during actual access; identity selection belongs in the trusted backend, this enforces filesystem permissions and is not a tenant boundary (#2070 #2093 #2094 #2095 #2096 #2097)
  • Expose multiple independent overlay mounts per isolated session across the API and all five SDKs: `CreateIsolatedSessionRequest...
Read more

OpenSandbox 1.1.1-rc.1

Choose a tag to compare

@github-actions github-actions released this 28 Sep 08:21

First release candidate on the 1.1.1 patch line, cut to fix the broken 1.1.0 server wheel: hatchling's VCS-exclude filtering silently dropped the committed FastPath gRPC stubs from the PyPI package, so every 1.1.0 install of opensandbox-server failed at import time — PyPI is immutable, so the patched line is 1.1.1 (#1959). Beyond that fix, this rc carries everything merged since release-1.1.0: agent-sandbox pause/resume, shared-namespace tenant isolation, watch-driven create latency, commands.setEnv and a systematic audit cleanup across all five SDKs, upstream-proxy chaining for egress, and two fast-sandbox pin bumps. Baseline for every section is release-1.1.0. rc releases publish images but hold packages — SDK/CLI artifacts ship at the 1.1.1 stable bump. Please test and report issues.

Highlights

  • Fixes the 1.1.0 server wheel: FastPath stubs now ship in the package and installs import cleanly (#1959)
  • Server: pause/resume on the agent-sandbox provider, tenant isolation for sandboxes sharing a Kubernetes namespace, and pool creates woken by watch events instead of 1-second polling (#1975 #1973 #1996)
  • SDKs: commands.setEnv runtime env injection in all five languages, plus a systematic cross-language audit cleanup fixing dozens of correctness bugs (#2013 #2020)

Server

  • Implement pause/resume for the agent-sandbox provider by bridging to spec.operatingMode (Running/Suspended) on agents.x-k8s.io/v1beta1, with state derivation (Paused/Pausing/Resuming/Terminated), resourceVersion preconditions, and 409 on invalid transitions; both endpoints previously returned "not supported" (#1975)
  • Isolate tenants that share one Kubernetes namespace: creates stamp opensandbox.io/tenant, and list/get/delete/pause/resume/proxy hide other tenants' labeled sandboxes as 404 while unlabeled legacy sandboxes stay visible until expiry; also adds kubernetes.insecure_skip_tls_verify for ServiceAccount CA mismatches (#1973)
  • Heal the silent renew-intent drop after a server restart in multi-tenant mode: the resolver now falls back to a cluster-wide label lookup with a 403 circuit breaker and structured warnings, trusts an ingress-observed namespace from the intent payload when verifiable, and single-tenant deployments never resolve beyond the configured namespace (#1819)
  • Add [docker] publish_host to publish bridge-mode sandbox ports on one host address (default 0.0.0.0 unchanged) — with 127.0.0.1 or the Docker bridge gateway, the tokenless execd port no longer lands on public interfaces (#1954)
  • Add a typed, admin-only [egress.upstream_proxy] config section (URL + optional authorization, validated at load) that injects the sidecar's chained upstream CONNECT proxy on both Docker and Kubernetes, with fail-closed 400s when the requested networkPolicy is incompatible; secret values are no longer echoed in config-validation errors (#1999)
  • Accept env on template create and bake it into the fast-sandbox golden image (/etc/sandbox-init.env, inheriting the source image's OCI Config.Env), closing the gap where SandboxTemplate.spec.envs existed but the lifecycle API rejected it; supported across all SDKs (#1984)
  • Wake Kubernetes creation waits on informer watch events instead of fixed 1-second polling, cutting prewarmed-pool create latency from ~1 s to tens of milliseconds while keeping the polling fallback (#1996)
  • Ship the committed FastPath gRPC stubs in the server wheel by force-including them past hatchling's VCS excludes, and smoke-import the built wheel in the release workflow before publishing — this is the 1.1.0 install-time breakage fix (#1959)
  • Fix the Fast Sandbox snapshot CR plural (sandboxsnapshots) in Helm RBAC and the fsb snapshot runtime, where sandboxesnapshots could fail list/watch with missing RBAC (#1972)
  • Propagate the underlying FastPath error message through the 429 capacity mapping (keeping status and Retry-After, adding a cause field) so admission/runtime failures like a broken KVM device are no longer masked as pool exhaustion, and warn-log the raw error before mapping (#2001)
  • Fix Docker edges: reject a repeated pause of an already-paused sandbox with the documented 409 instead of surfacing Docker's "already paused" as 500 (#2023), and clear Docker masked/read-only system paths only for sandboxes that opt into the isolation extension so nested Bubblewrap can mount a private procfs (#1982)

SDKs

Code changes below ride the 1.1.1 stable release — rc ships no SDK packages.

  • Add commands.setEnv for persistent runtime env injection in all five sandbox SDKs (Python async/sync, JavaScript, Kotlin/Java, Go, C#): appends KEY=VALUE to the sandbox env file with runtime-exact serialization, local key/NUL validation, and a loud failure when EXECD_ENVS is unset (#2013)
  • Systematic cross-language audit cleanup across sandbox, code-interpreter, and MCP SDKs: Go retry backoff collapsing to zero delay and dropped session cwd, Python isolated-session ignoring encoding and readiness budgets reporting stale errors, JS resume sharing and killing the source sandbox's transport, Kotlin codes runs dropping every SSE-framed event and never setting exitCode, C# create failing on fresh-sandbox 404 and NREs on empty bodies, and MCP per-call closes tearing down the server-wide shared transport — each fixed with regression tests (#2020)
  • Support env on template create across all five SDKs, matching the server-side golden-image baking (#1984)
  • Align background command stream completion across languages: with execd's fixed completion delay removed, background result collection in Go, Kotlin, and C# now returns on startup acknowledgement like Python and JavaScript instead of waiting for EOF and inferring exit code 0 — query command status for the eventual outcome; foreground calls still read to EOF for older servers (#1825)

Controller

  • Fix an image-committer deadlock where pausing the QEMU container via cgroup v2 freeze never completes (KVM worker kernel threads never reach frozen), by skipping the redundant freeze for the QEMU container already paused over QMP and committing with --pause=false (#1986)

Execd

  • Remove the fixed one-second delay after command completion, cutting median terminal-event-to-return latency from ~1000 ms to sub-millisecond while retaining output flushing and heartbeat cleanup (#1825)
  • Support multiple independent overlay mounts per session in the bwrap isolation layer (separate uppers for workspace vs system paths, nested shadowing, ephemeral tmpfs uppers); internal foundation with no public API change — the request-level overlays field follows (#2021)
  • Stop logging every stdout/stderr chunk at info level, which accounted for 99.8% of execd log volume on output-heavy workloads (#1906)

Networking

egress

  • Add an opt-in chained upstream CONNECT proxy to the transparent mitmproxy path (OPENSANDBOX_EGRESS_UPSTREAM_PROXY/_AUTH), routing sandbox egress through corporate forward proxies with SNI/Host-consistent CONNECT authority, fail-closed startup validation, and no behavior change when unset (#1816)
  • Continue the credential-bound TLS interception foundation (OSEP-0023) [EXPERIMENTAL]: bootstrap authenticated revision sessions on sidecar launch and restart behind an internal gate (#1948), stage unpublished Credential Vault mutation candidates with acknowledge-before-publish commit semantics (#1980), serialize /policy and Vault writes behind a shared mutation barrier (#1991), stage always-rule reloads before publishing (#1997), retain exact attempt identity across indeterminate coordinator outcomes (#2007), and add post-bootstrap revision updates with exact-attempt reconciliation (#2017) — groundwork only; public Vault writes still 503 under the gate and selective ...
Read more

OpenSandbox 1.1.0

Choose a tag to compare

@github-actions github-actions released this 21 Sep 07:46

First stable release of the unified umbrella release line: one platform version — 1.1.0 — covers server, component images, charts, CLI, and every published SDK, cut from one commit and pinned in a signed BOM (versioning starts at 1.1.0; 1.0.0 was already consumed by legacy releases, so the line skips it by design per the umbrella governance OSEP). Everyone on a legacy per-component version should upgrade; legacy tag namespaces are frozen. Because this is the first umbrella cut, sections carry different baselines — the controller jumps from its May v0.2.0 release, ingress from July, the JavaScript/C#/Go SDKs from their July releases — so those sections list several months of changes at once.

Highlights

  • First unified umbrella release: every artifact ships at 1.1.0 from tag release-1.1.0, with a Sigstore-signed BOM as the digest authority
  • First release of the Fast Sandbox integration: a Firecracker microVM runtime behind the FastPath fleets backend, with pause/resume, ingress FastPath routing, and fsb template management in all five SDKs
  • Snapshot persistence gains an opt-in PostgreSQL store with multi-process HA and a SQLite migration command, and sandboxes gain preStart/periodic lifecycle hooks

Server

  • Add the FastPath fleets lifecycle backend: create, renew, delete, and status mapping served through FastPath v2, plus end-to-end fsb pause/resume with async 202 semantics and UID fencing (#1703 #1844)
  • Converge snapshot status via a per-namespace watch instead of blocking polls, and add fast-sandbox snapshot support (#1846)
  • Add an opt-in PostgreSQL snapshot store with pooled connections and CAS semantics, a one-shot migrate-snapshots command for moving SQLite records, and multi-process HA coordination for snapshot create/recovery/delete on Kubernetes (#1653 #1670 #1724)
  • Transport sandbox lifecycle hooks (OSEP-0020): create requests accept preStart and periodic hooks, validated and serialized into a reserved environment variable for Kubernetes workloads; the Docker provider rejects lifecycle requests for now (#1589 #1542)
  • Implement a stable, scoped diagnostics API over the existing log/event collectors with logs:container|all and events:runtime|lifecycle|all scopes, explicit warnings on partial scopes, 400 DIAGNOSTICS_SCOPE_UNSUPPORTED for unknown scopes, and backward-compatible plain-text responses (#1553)
  • Export generic HTTP request metrics (request rate, error rate, latency) from the server over OTLP, complementing the SDK-reported create-duration histogram (#1561)
  • Reject unsupported gVisor (runsc) snapshots before persistence with 409 SNAPSHOT::UNSUPPORTED_RUNTIME (#1720)
  • Support independent resource requests/limits for the Kubernetes egress sidecar via [egress.resources] (#1620), add [egress] otlp_endpoint so the sidecar exports metrics to an OpenTelemetry collector on both runtimes (#1753), pause and resume the sidecar together with the sandbox (#1441), make the sidecar readiness wait configurable via [egress] timeout_seconds (#1522), and inject OPENSANDBOX_EGRESS_SANDBOX_ID server-side so sidecar telemetry can no longer be spoofed by request env (#1381)
  • Honor image.auth in create requests for the agent-sandbox provider with per-sandbox pull secrets that are garbage-collected with the Sandbox CR (#1789)
  • Source OSEP-0011 secure-access signing keys from the OPENSANDBOX_SECURE_ACCESS_KEYS environment variables or a Kubernetes Secret instead of plaintext chart values (#1445)
  • Make the reverse proxy's internal resolution configurable with [proxy] resolve_internal for deployments that cannot route to Docker bridge IPs (#1631)
  • Raise the preStart.timeoutSeconds limit from 300 to 10800 seconds across the server API, execd, and SDKs (#1637)
  • Add Docker-runtime-wide sandbox_env and sandbox_binds configuration, giving Docker parity with the Kubernetes pod template for fleet-wide CA bundles, proxies, and mounts (#1303)
  • Breaking: migrate the agent-sandbox provider and ingress informer to agents.x-k8s.io/v1beta1 required by agent-sandbox v1.0.0, creating workloads with operatingMode: Running and service: true; see Upgrade & Compatibility (#1763)
  • Support pool-only sandbox creation (poolRef without entrypoint) instead of rejecting it with HTTP 400, scheduling the execd-start task per allocation (#1729), fail fast on exhausted namespace ResourceQuotas by surfacing the Sandbox CR's admission rejection (#1752), and surface pool back-pressure as HTTP 429 KUBERNETES::POOL_CAPACITY_EXHAUSTED with Retry-After instead of a generic readiness timeout (#1581)
  • Propagate template container securityContext into generated pods (#1564), honor the PVC readOnly flag on the volume source and not just the mount (#1246), allow mixed read-only subPath mounts from a shared PVC (#1440), reject networkPolicy combined with extensions.poolRef (#1319), and patch PVC owner references through the supported strategic-merge path (#1538)
  • Make the informer-backed cache the only Kubernetes read path by removing the informer_enabled flag, and expire stale informer entries when a watch stops delivering (#1926 #1534)
  • Reserve Docker host ports in-process between probing and container start, and retry container creation when the probed port conflicts at Docker bind time (#1666 #1715)
  • Map completed agent-sandbox pods to terminal states (#1643), report Failed when a pooled sandbox task fails (#1663), keep direct responses out of the informer cache (#1674), resolve agent-sandbox server-proxy endpoints from status.podIPs with IPv6 bracketing (#1424), and use the public state in invalid-resume errors (#1586)
  • Handle websocket close semantics: map abnormal upstream closures and relay client closes with a legal status code (#1642 #1731)
  • Fix HTTP proxy fidelity: preserve repeated response headers without duplicating Uvicorn's own (#1858 #1471), forward the query string unchanged (#1902), rewrite root-relative redirects to stay on the proxy path (#1516), release backend responses when clients abort mid-stream (#1488), stop leaking the ingress routing header on server-proxied endpoints (#1503), and generate unique OpenAPI operation IDs (#1634)
  • Improve proxy diagnostics: identify backend connection failures (#1675) and describe transparent proxy responses in the spec (#1701)
  • Preserve the egress auth token on internal proxy requests to port 18080 across Docker and Kubernetes (#1880)
  • Route Compose proxying through host port mappings (#1698)
  • Fix Docker runtime edges: skip a missing IPv6 sysctl in Kubernetes init (#1721), use the supported no-new-privileges separator ([#1383](https://...
Read more

python/sandbox/v0.1.17.dev0

Pre-release

Choose a tag to compare

@ninan-nn ninan-nn released this 03 Sep 03:50
4178647
Merge pull request #1707 from jianpingpei/chore/python-sdk-0.1.17-dev…

components/execd 1.1.0

Choose a tag to compare

@Pangjiping Pangjiping released this 26 Aug 09:31
48b0215

What's New

✨ Features

  • execd as sandbox init (OSEP-0018). execd can now run as PID 1: single reaper with a managedProcess abstraction on every launch path, signal forwarding (TERM/HUP/USR1/USR2/WINCH), entrypoint-owned exit-code propagation, and a subreaper fallback for the Pool path. Opt-in via EXECD_INIT=1 (injected by the server's runtime.execd_run_as_init for Docker/K8s Batch/Agent/Pool); classic topology unchanged and default off. (#1474)

  • Pre-exec hardening floor. The new opensandbox-launcher native helper applies env strip → KEEPCAPS → bounding-set trim → no_new_privs → identity drop → seccomp → execve; [landlock] adds a filesystem allowlist (fail-open below ABI/kernel 5.13, reported as unsupported). GET /v1/isolated/capabilities gains a hardening object with per-layer state; every layer degrades fail-open. (#1474)

  • eBPF observation variant. execd-ebpf (CGO + cilium/ebpf) hooks exec/connect/privilege with CO-RE, scoped to the sandbox cgroup, emitting a rotating JSONL audit; needs kernel ≥5.10 with BTF. The default image is unchanged. (#1474 #1562)

  • preStart and periodic lifecycle hooks (OSEP-0020). CreateSandboxRequest.lifecycle is transported to the sandbox via the internal OPEN_SANDBOX_LIFECYCLE env (Kubernetes; the Docker provider rejects lifecycle requests). execd starts HTTP before preStart, runs non-overlapping periodic hooks through the reaper-aware managed-process path, and only releases the user process after preStart succeeds. Config persists at $HOME/.execd/lifecycle.toml, with EXECD_LIFECYCLE_CONFIG as exact override; bootstrap sync and preStart shutdown are fail-closed with TERM/KILL watchdogs, and internal transport vars are stripped from user code. API models aligned across Go/Python/JS/Kotlin/C# SDKs. (#1587 #1588 #1589)

🐛 Bug Fixes

  • In-namespace signals no longer leak into /command in init mode. kill -HUP 1 previously killed whatever /command was running (signal: hangup); signals are now owned by the init forwarder only. (#1546)

  • PTY creation failure emitted a second success body. POST /pty now stops immediately after the error response instead of appending a success body and a nonexistent session id. (#1603)

  • cwd validation now honors request-scoped envs. Foreground/background /command requests can use a cwd variable from their own envs map instead of being rejected with 400. (#1611)

  • Non-root workloads could not start: /bootstrap.sh normalized to 0755. A deployed image carried bootstrap.sh as 0751 root:root, sending images with a non-root default user (e.g. admin) into CrashLoopBackOff before hooks ran. The image build now forces exec bits on execd/execd-ebpf/opensandbox-supervisor/bootstrap.sh regardless of checkout permissions. (#1619 #1606)

  • preStart timeout raised from 300s to 10800s (3h). periodic.timeoutSeconds stays at 300s; product policy bounds are now enforced Server-side only, with execd keeping just a technical overflow guard. (#1637)

📦 Misc

  • OSEP-0018 coverage closed out: server-path and Kubernetes hardening e2e (ConfigMap-carried isolation TOML, no server logic change), PTY-under-hardening, bwrap + init-reaper integration, custom [seccomp]/keep_capabilities policy, EXECD_INIT↔TOML drift pin, K8s Restart recycle against init-mode pods, runtime-initiated stop, and an execd-ebpf bare-container smoke (doubles as kernel-5.10 validation). Test redundancy and dead code trimmed (-359 lines). (#1554 #1555 #1562 #1574)

  • OTLP endpoint auto-allow shipped in the shared components (egress honors OTEL_EXPORTER_OTLP_METRICS_ENDPOINT/OTEL_EXPORTER_OTLP_ENDPOINT; PTY viewer read loop refactored along the way). (#1504)

  • Lifecycle hook guide with timing diagram and per-SDK creation examples; SDK client-side timeout validation aligned with the Server. (#1605)

👥 Contributors

Thanks to these contributors ❤️


  • Docker Hub: opensandbox/execd:v1.1.0
  • Aliyun Registry: sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/execd:v1.1.0
  • GHCR: ghcr.io/opensandbox-group/opensandbox/execd:v1.1.0

server 0.2.3

Choose a tag to compare

@Pangjiping Pangjiping released this 26 Aug 09:39

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-0020 — CreateSandboxRequest.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 responses — getSandbox 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 bumps — google.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 stalls — has_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 route — Location: /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 header — OpenSandbox-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 rejected — nan, 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/...

Read more

Python Sandbox SDK v0.1.16

Choose a tag to compare

@ninan-nn ninan-nn released this 26 Aug 08:01
169adf7

What's New

✨ Features

  • Resilient HTTP transport — Async and sync clients now share a configurable retry transport with backoff, jitter, Retry-After handling, per-attempt timeouts, an overall deadline, and retry callbacks. Retries are enabled by default for idempotent requests on HTTP 429, 502, and 503; callers that require the previous fast-fail behavior can use RetryPolicy.disabled(). User-supplied transports remain untouched, and streaming SSE requests bypass replay. #1372
  • Sandbox lifecycle hooks — Sandbox.create and SandboxSync.create now accept optional preStart and periodic lifecycle hooks, with stable Python models and server-aligned validation. Hook timeout ranges remain server-authoritative. #1588 #1605
  • Background runs in isolated sessions — Isolated sessions can start detached work and poll its status and incremental combined output. Active background runs suspend idle collection; read-only workspaces reject background execution because they cannot persist run logs. #1456
  • Runtime allocation and hardening visibility — Sandbox responses can expose confirmed Pool allocation summaries, while isolated capabilities include execd init mode and hardening-layer state. These fields are additive and remain absent when the server cannot confirm the corresponding state. #1481 #1474
  • Pool capacity back-pressure — Compatible lifecycle servers can now surface exhausted Kubernetes Pool capacity as HTTP 429 with KUBERNETES::POOL_CAPACITY_EXHAUSTED and Retry-After, instead of eventually reporting a generic readiness timeout. Sandbox creation remains non-idempotent and is not automatically replayed on this status. #1581

⚡ Performance

  • Faster sandbox startup — Async sandbox creation, connection, and resume resolve execd and egress endpoints concurrently, reducing the two management API lookups to one parallel wait. Failure propagation and create cleanup semantics remain unchanged. #1531
  • Bounded parallel Pool cleanup — Idle sandbox release uses bounded concurrency while preserving best-effort cleanup and legacy public behavior. The measured 100-sandbox cleanup in the PR dropped from about 8.3 seconds to 0.8 seconds. #1475

🐛 Bug Fixes

  • Standards-compliant SSE parsing — Command and isolated execution streams now use SSE-specific framing, preserving Unicode separators inside JSON strings while remaining compatible with legacy bare-JSON frames. #1444
  • Reliable background command completion — Background command streams stop after execution_complete, preventing false RemoteProtocolError failures when the peer closes before the final HTTP terminator. Foreground streaming behavior is unchanged. #1532
  • Endpoint cache race fix — Completing an older endpoint fetch no longer removes a newer replacement inflight fetch in async or sync clients. #1567
  • More useful API errors — Unstructured 4xx and 5xx response bodies are included in exception messages and remain available as raw response_body bytes. HTTP 429 responses use SandboxRateLimitException and expose parsed retry_after when present. #1496 #1372
  • Cleaner readiness diagnostics — Readiness timeout messages retain timing, connection context, and the last health-check error without suggesting deployment-specific network fixes that may not apply. #1493

📦 Misc

  • Regenerated lifecycle models, bumped the package fallback version to 0.1.16, and aligned async and sync default User-Agent strings with the release. #1622 #1623

👥 Contributors

Java/Kotlin SDKs v1.0.19

Choose a tag to compare

@ninan-nn ninan-nn released this 25 Aug 11:23
22a1ece

What's New

⚠️ Breaking Changes

  • Client-pool reconcile interval is no longer configurable — SandboxPool.Builder.reconcileInterval(...) and the corresponding PoolConfig setting have been removed. Pool reconciliation now runs on a fixed one-second cadence, while new sandbox creation is bounded by warmupCreateQps; callers should delete uses of reconcileInterval with no replacement. #1575

✨ Features

  • Scalable asynchronous client-pool warmup — Pool refill now separates create, readiness, prepare, post-prepare health checking, renewal, and commit into a staged asynchronous pipeline. Create admission is rate-limited per pool, delayed retries no longer occupy worker threads, and staged warmups use a single create transport attempt while direct create and other non-pool paths retain their existing retry behavior. #1575
  • Pool warmup tracing and operational summaries — Applications can opt in with ConnectionConfig.enableTracing(true) to emit OpenTelemetry traces covering queue wait and every warmup phase, using the application's global SDK, exporter, sampler, and propagators. Warmups now also expose bounded terminal outcome attributes, rate-limited failure logs, and active-pool summaries without allowing telemetry failures to affect pool behavior. #1524 #1604
  • Lifecycle hook models — Sandbox creation now accepts additive preStart and periodic lifecycle hook models. Hook timeout validation remains authoritative on the server rather than being duplicated in stable Kotlin models; Docker support, PATCH operations, and additional hook types remain outside this release's scope. #1588 #1605
  • Detached runs in isolated sessions — Kotlin consumers can start background work inside a persistent isolated session, poll its status, and read logs incrementally. Background runs are bounded by the session lifetime, do not support per-run timeouts, and are rejected for read-only workspaces because they require a host-visible writable log location. #1456
  • Richer runtime metadata — The SDK now models execd hardening capability results and exposes an optional Sandbox.allocation summary for confirmed Kubernetes Pool allocations. Allocation metadata is omitted when evidence is incomplete or inconsistent and does not expose Pod, node, namespace, or internal controller details. #1474 #1481
  • Shared HTTP connections for client pools — When callers do not provide an OkHttp connection pool, SandboxPool now creates and owns one sized from warmupConcurrency, reuses it across warmup, acquire, and direct-create paths, and evicts it on shutdown. User-supplied connection pools retain their existing ownership semantics. #1517

🐛 Bug Fixes

  • Stable warmup pacing under failures and throttling — Fast create failures can no longer drive a self-sustaining reconcile loop, and pool warmups now honor Retry-After without counting rate limits as degraded failures. Stale-sandbox cleanup triggers prompt replenishment, while concurrent warmup commits no longer serialize behind a single JVM mutex or starve health-check work. #1494 #1512 #1519 #1621
  • More actionable client errors — Kotlin ClientException messages now retain response bodies for caller-fixable 4xx responses across generated and handwritten paths. Readiness timeout messages no longer suggest Docker bridge, remote-network, or server-proxy settings that may not apply, while preserving timeout and last-error context. #1496 #1493
  • Faster bounded idle cleanup — releaseAllIdle() now deletes idle sandboxes with bounded concurrency instead of serially, preserving best-effort cleanup semantics while substantially reducing drain time for large pools. #1475

📦 Misc

  • Published Kotlin/JVM sandbox, code-interpreter, Redis pool, and BOM artifacts at version 1.0.19 under the existing com.alibaba.opensandbox coordinates.

👥 Contributors