Publish administrator termination to session readers and reject new input before rebuilding compute. Preserve normal recovery after sandbox reclamation, explicit manual recovery, and completed history. Cover both lifecycle paths with live tests and give deployments a stable hook for styling the recovery control. Co-Authored-By: Claude <noreply@anthropic.com>
18 KiB
Changelog
All notable changes to AstraBox are documented in this file.
The format is based on Keep a Changelog, and this project follows Semantic Versioning.
[Unreleased]
Fixed
- Administrator-terminated sessions publish their terminal state and reject new messages before automatic runtime recovery. Active sessions still recover after sandbox reclamation, and explicit manual recovery remains available.
[0.1.1]
Upgrading is strongly recommended for every 0.1.0 installation: it fixes sandbox isolation and access-control vulnerabilities, and engines that could not complete a first turn on the one-command install. Re-run the installer to upgrade; settings, secrets and data are kept.
Sandboxes that 0.1.0 started keep their old port bindings until they are replaced. To close that exposure right away, remove them on the AstraBox host after upgrading:
docker ps -aq --filter label=opensandbox.io/id | xargs -r docker rm -f
docker ps -aq --filter label=opensandbox.io/egress-sidecar-for | xargs -r docker rm -f
Each conversation continues on a new sandbox with its history. Files in a removed sandbox's workspace are kept only with the optional persistent workspace volume.
Security
- Sandbox services were reachable from the network. Each sandbox's command and file services were published on every host interface without authentication. They are now bound to the Docker bridge gateway only.
- A sandbox could reach the management API. With Unrestricted networking, code in a sandbox could call the platform API, which in no-login mode acts as an administrator. The server no longer publishes its API on the Docker bridge; the scoped sandbox edges reach it over a private network.
- A sandbox could reach another sandbox. Every sandbox now denies the Docker bridge subnet, apart from the scoped edges, in every networking mode.
- Cloud metadata and raw sockets.
169.254.0.0/16is denied in every networking mode, and sandbox containers no longer haveNET_RAW(Docker). - Agent fields could widen a sandbox's access. Plugin, Skill and MCP hosts
written by an Agent author are now checked against the Environment's policy.
Private, loopback, link-local and Docker bridge hosts are refused unless an
administrator has explicitly admitted them in that Environment.
deploy_key_secret_nameresolves only names listed inASTRABOX_DEPLOY_KEY_SECRET_NAMES, an author's MCP definition cannot select the platform's gateway credential, and the Git HTTPS token is sent only toASTRABOX_GIT_HTTPS_TOKEN_HOST. Refusals are403with registered codes. - Team login: members could become administrators. A member could request
astrabox:adminin their own token. API scopes now count only on tokens issued to the configured API client; a user's token carries the user's role. - Team login: bundled Casdoor defaults. The built-in Casdoor administrator's
default password is replaced with a generated secret at first start, and
AstraBox accepts only accounts of the configured organization
(
ASTRABOX_CASDOOR_ORGANIZATION, defaultastrabox). - The name-only egress mode is refused.
ASTRABOX_SANDBOX_EGRESS_MODE=dnsenforces no address rule, so the cloud metadata deny, the Docker bridge deny and address entries in Limited allow lists would not apply. The server now refuses to start with it instead of warning. - IPv6 stays off in every sandbox. AstraBox now sets OpenSandbox's
egress.disable_ipv6itself instead of relying on its default, so sandboxes have no IPv6 route even where the Docker daemon enables IPv6. - The server never offers sandboxes its own address. With
ASTRABOX_MCP_PROXY_BASE_URLunset, the server used its own container address as the sandbox callback base, and the protected embedded gateway used it as the private gateway address; either let a sandbox reach every port the server listens on. Neither is derived any more: an unset callback base fails the first sandbox, and the embedded gateway refuses to start without a gateway address. The maintained Compose stack sets both to the sandbox edge. - Kubernetes sandboxes lose
NET_RAW. Sandbox containers on Kubernetes could open raw sockets, which Docker sandboxes lost in 0.1.1. The bundled lifecycle server now creates every sandbox withNET_RAWdropped, through the OpenSandbox BatchSandbox template. WithASTRABOX_SANDBOX_SERVER_KUBE_WORKLOAD_PROVIDER=agent-sandboxthe server logs a warning instead, because that provider reads a template AstraBox does not write. - Hermes' session token no longer reaches proxy logs. AstraBox sent the
token that opens an Assistant's Hermes backend in the connection URL, and the
OpenSandbox ingress gateway and the sandbox's command service log every
request URL. It now travels in a request header, and the Hermes image moves
it to where Hermes reads it inside the sandbox. Rebuild or pull the
sandbox-hermesimage together with the server. - The Hermes backend credential is no longer computable from a box's
identity. The token that opens an Assistant's Hermes backend was a hash of
the box's account and home directory, with no deployment secret, so anyone
who could reach the backend port and knew those identifiers could present it.
On Kubernetes the sandbox Pod has no ingress firewall, so that port is
reachable from elsewhere in the cluster. The token is now derived from the
deployment's own secret and cannot be reproduced from the identity alone.
Rebuild or pull the
sandbox-hermesimage together with the server. - Claude Code and Codex sandboxes admit only the platform on their engine
ports. A Claude Code sandbox's runner handed its live conversation to any
connection that named the conversation's id, which the API shows and which
the runner's own refusal revealed to a peer that named a wrong one. A Codex
sandbox's app-server port relayed every connection to the server. On
Kubernetes a sandbox Pod has no ingress firewall of OpenSandbox's making, so
any pod in the cluster could reach both, and in an Agent-shared sandbox every
other conversation could. Both now require a credential derived from the
deployment's own secret and the sandbox's identity, and refuse a connection
without it before naming or relaying anything. A new Claude Code sandbox's
runner also refuses to be prepared until AstraBox has written that
credential into the sandbox, so the first connection to reach it cannot
claim it. Rebuild or pull the
sandbox-claude-codeandsandbox-codeximages together with the server; sandboxes started before the upgrade keep the old behaviour until they are replaced. - The sandbox's :8080 services were open to any caller that reached the
port. The agent-infra base image serves a file and shell API, a terminal,
JupyterLab, a VNC desktop, code-server and an MCP hub on :8080 and left them
unauthenticated, so an unauthenticated request ran arbitrary commands in the
box. On Kubernetes every Pod in the cluster can reach that port, and on Docker
every container on the default bridge can, including through the address the
egress sidecar publishes on the bridge gateway — cross-tenant code execution.
AstraBox now sets the base image's own
SANDBOX_API_KEYper box, derived from the deployment secret and the box's identity, so the port refuses a caller without it. Exposed-port links never carry that credential: port 8080 cannot be exposed, and previews use the agent's own web server port. The services AstraBox does not use — JupyterLab, code-server, the VNC desktop, the browser and the Node REPLs — no longer run at all. Rebuild or pull thesandbox-*images together with the server.
Added
- Team login from the installer.
ASTRABOX_INSTALL_TEAM_LOGIN=casdoorturns on the bundled Casdoor login; setASTRABOX_CONSOLE_ORIGINandASTRABOX_OIDC_ISSUERfor a deployment behind a reverse proxy. The release bundle now contains the login overlay. - Langfuse tracing through OpenTelemetry. The bundled gateway sends traces
with LiteLLM's OTel integration when
LANGFUSE_PUBLIC_KEYandLANGFUSE_SECRET_KEYare set, and sends nothing otherwise. - Single-container deployment.
ghcr.io/colton-z/astrabox:0.1.1runs the platform withdocker run; it keeps its data in a Docker volume and creates separate sandbox containers from the matchingsandbox-*images. See the all-in-one guide.
Fixed
-
Assistant workspaces on persistent volumes prepare their private directory ownership before startup checks. Replacement sandboxes reuse the same numeric account so the existing workspace and Hermes profile remain writable.
-
A conversation replacing a lost sandbox could fail its next message because background cleanup deleted the replacement during startup. Cleanup now preserves the replacement while the conversation's accepted turn is active.
-
Prepared-runtime status keeps the existing pool identity while an Agent configuration change prepares a replacement.
-
The first model request of the bundled gateway failed with
400 Invalid request formatfor Pi, Hermes, DeepSeek Harness and Codex. -
DeepSeek Harness and Hermes could not start on the one-command install; the server now connects to sandboxes directly instead of through the lifecycle server's relay.
-
Sandboxes could not be created on hosts with fewer than four CPUs.
-
The server restarted once during a fresh install while the model gateway finished its first boot.
-
docker stopnow stops AstraBox before the services it depends on. -
Claude Code ran without its own system prompt when an Agent had no instructions (including the seeded Agent) and its sandbox started cold. It now always runs on Claude Code's preset, with Agent instructions appended.
-
DeepSeek Harness failed every turn on models other than DeepSeek's (it asked for a 256,000-token output). Other models now use the harness's generic gateway route with its standard limits.
-
Conversation titles and process summaries were never generated on the one-command install. Every turn logged
session title generation failedand the conversation kept the Agent's name, because the server sent these requests to the sandbox-only gateway namegateway.astrabox.test. The server now uses the gateway's server-side address and its own gateway credential, as model discovery does. TheASTRABOX_TITLE_MODEL_*settings still override both. -
A lost sandbox now produces the registered, non-retryable
SANDBOX_GONEresult; input that was never delivered produces the registered, non-retryableINPUT_NOT_DELIVEREDresult instead of looking like a failed agent turn. -
Codex child command cards recover an empty command result from the same call's recorded native output after the child finishes.
-
Conversations stopped answering after a restart. On the one-host Docker stack, the two sandbox edges can come back at different Docker bridge addresses after
docker compose stopandstart, or after an edge restarts. A conversation whose sandbox was created before then could not reach the model: each message retried for about six minutes and failed. Sandboxes now record the addresses they were created with; the server removes those created with other addresses, and the next message takes a new sandbox, as after any other sandbox loss. A server that sees an edge move while it runs exits so that Docker restarts it. Sandboxes started by 0.1.0 carry no such record; after upgrading, remove them with the commands at the start of these notes if a conversation stops answering after an edge restart. -
docker stopreported a failure. A stop that completes now exits with status 0 instead of 241. A process killed by a signal reports 128 plus the signal number. -
Hermes Assistants could not start behind the OpenSandbox ingress gateway. The gateway that Secure Access requires on Kubernetes replaces the
Hostheader, and Hermes refuses aHostother than its loopback address, so the workspace never became ready. The Hermes image now presents the address Hermes expects, and the server connects to the sandbox address it was given, which wildcard gateway routes also need. Rebuild or pull thesandbox-hermesimage together with the server. -
The Kubernetes Compose stack ignored the ingress settings.
ASTRABOX_SANDBOX_SECURE_ACCESS,ASTRABOX_SANDBOX_ENDPOINT_SCHEMEand theASTRABOX_SANDBOX_SERVER_INGRESS_*settings never reached the server, so sandboxes were served without Secure Access even when it was set. They are now passed through, and on Docker the server refuses to start with Secure Access set instead of ignoring it.
Changed
- A user's own OAuth token no longer needs
astrabox:*scopes; it can call every route the user can reach in the console. Tokens issued to OAuth clients other than the console and the API client are refused. - Existing Agents that reference a deploy key name not listed in
ASTRABOX_DEPLOY_KEY_SECRET_NAMESare refused when a Session starts. ASTRABOX_SERVER_SANDBOX_PORT,ASTRABOX_MODEL_GATEWAY_HOST_PORTandASTRABOX_GATEWAY_DNS_HOST_PORTare no longer used; remove them fromcontainers/.env.- Docker deployments now require Docker Engine 26.0 or later and the Compose plugin 2.17.0 or later. The installer checks both before starting.
- New Agents keep a sandbox ready. An Agent created without a prewarm
choice, from the API, the console, the CLI or the seed of a fresh
installation, now has prewarming on wherever the deployment can prewarm
(
ASTRABOX_AGENT_PREWARM_REDIS_URLis set, as in every bundled Compose deployment), so its first conversation claims a prepared sandbox instead of starting one. Each such Agent holds one idle sandbox. Existing Agents keep their setting. The cost per deployment and how to turn it off are in Plan capacity for prepared sandboxes.
Documentation
- A reverse-proxy guide for team login: public URLs, and keeping Casdoor's administration pages private.
- A sandbox network boundary section in the deployment guide.
- The AstraBox CLI and the plugin interfaces are introduced on the site and in the README.
[0.1.0]
First public release: a self-hosted runtime that turns the Agent programs you already use into managed cloud Agents, on your own infrastructure and with your own models.
Added
- Five Agent programs behind one platform. Claude Code, Codex, Hermes, DeepSeek Harness and Pi each run through their own engine adapter. The vendor program owns its agent loop and its native session; AstraBox owns placement, sandbox lifecycle, transport, streaming, credentials and orchestration state. Adapters are entry points, so a deployment can install its own.
- Sandboxes through the OpenSandbox lifecycle API. One Docker host or a Kubernetes cluster runs the sandboxes; a deployment can also point at an OpenSandbox service it already operates. Conversations get their own sandbox, or share an Agent-owned one through isolated Linux accounts.
- Prepared capacity. An Agent keeps warm sandboxes ready, so a conversation starts in seconds instead of waiting for a cold container, and resumes the same way after its box is gone. Idle boxes pause or terminate by the Environment's own rule.
- Recovery that keeps the conversation. Every engine's native session store is kept in the platform database and restored for the supplier's own resume, so a lost sandbox, a restarted server or a replaced box does not cost the conversation its history. Persistent workspace volumes stay optional.
- Web console and HTTP API over the same resources. Agents, Environments, Sessions, Events, Assistants, Deployments, Vaults and channels are one set of records; the console and the API operate them the same way. Events stream over SSE with tool approval, interruption, reconnect and durable history. The console ships in English and Simplified Chinese.
- Any model through the bundled gateway. Model requests go through LiteLLM, so Anthropic, OpenAI-compatible and local providers all work; an Environment names the route, never a vendor key.
- Credentials the sandbox never holds. Vault credentials are injected outside the sandbox at its egress boundary — model keys, MCP server credentials and HTTP Basic repository access. The Agent sees a placeholder; a backend that cannot inject reports it instead of degrading.
- Tools: MCP servers, Plugins and Skills. Anonymous direct MCP servers, managed MCP servers with administrator-held secrets through the gateway, and each program's native Plugin and Skill formats.
- Deployments. Schedules, webhooks and manual runs start Agents without a person present, and messaging channels connect them to chat platforms through official Satori adapters.
- Assistants. A long-lived Agent with one durable shared workspace across its conversations.
- Identity. Single-user with no auth out of the box;
trusted_header, verifiedjwt, and OIDC (a bundled Casdoor deployment) add team login, ownership and an administrator surface by configuration. - One-command install.
curl -fsSL .../install.sh | bashpulls published images and starts the Compose deployment: API and console, PostgreSQL, Redis, the model gateway, the messaging gateway and the local sandbox service. Building from source stays documented. - Observability. Prometheus metrics, and OpenTelemetry tracing to a collector of your choice (Langfuse included) when you switch it on.
- Extension seams. Sandbox backend, storage, model access, secret store, repository, identity resolver and engine adapter are all entry points with versioned contracts and conformance suites, so a deployment can replace one without forking the platform.