One Java API for synchronous command execution and workspace file operations across
multiple backends. The shared command/file contract is tested by the
AbstractSandboxTCK; backend-specific or unsupported capabilities, such as interactive
execution, are not interchangeable. An agent, evaluation harness, or build runner can
choose a local process, a Docker container, or a remote Firecracker microVM at
construction time.
Documentation: lab.pollack.ai/projects/agent-sandbox — backends, the core API, file operations and customizers. Release notes: What's New.
Sandbox— the backend-neutral surface:exec,files(),workDir(), andclose(). Everything a backend cannot offer everywhere stays off this interface.ExecSpec/ExecResult— an immutable command specification (argument vector, environment overrides, timeout) and its outcome (exit code, stdout, stderr, duration). AnExecSpecis an argument vector on every backend: arguments are never split or expanded by a shell.SandboxFiles— fluent file operations against the sandbox workspace, chained back into the sandbox withand().ExecSpecCustomizer— construction-time interception of each spec before it runs.AbstractSandboxTCK— the compatibility kit every backend passes, published in theagent-sandbox-coretest-jar so an out-of-tree backend can run it too.
| Module | Backend | Isolation | Notable dependencies |
|---|---|---|---|
agent-sandbox-core |
LocalSandbox |
none — runs on the host | zt-exec, slf4j |
agent-sandbox-docker |
DockerSandbox |
container | Testcontainers |
agent-sandbox-e2b |
E2BSandbox |
remote microVM | jackson, awaitility |
LocalSandbox provides process and workspace convenience but no security isolation; it
is for trusted code and development. DockerSandbox is the convenient local Docker
backend. It is not presented as a hardened multi-tenant execution service, and a
container alone is not a complete hostile-workload security boundary.
This project publishes Maven artifacts. It does not build, publish, own, or maintain any container image.
agent-sandbox-docker runs an image you select. There is no default: every constructor
and DockerSandbox.builder().image(...) requires an explicit reference, and build()
fails before it contacts Docker if you did not supply one.
try (Sandbox sandbox = DockerSandbox.builder()
.image("your-registry/your-runtime@sha256:...") // required
.build()) {
...
}What that means for you:
- You own the image — its provenance, contents, patching cadence, and vulnerability policy. Nothing about it is asserted or vouched for here.
- Prefer an immutable digest (
repo@sha256:...) over a mutable tag for reproducible operation, and scan and attest whatever you pick. A:latesttag can change under you without any release of this library. - The image needs a POSIX userland:
bash, GNU coreutils, and GNU findutils. File listing usesfind -printf, which BusyBox does not implement, so minimal BusyBox images will not work.
Reaching a Docker daemon is not a sandbox in itself. A caller who can start containers can generally obtain root-equivalent control of the host, and container isolation alone is not a security guarantee against hostile code. Treat this backend as workload separation, and add the kernel-, user-, and network-level controls your threat model actually requires before running code you do not trust.
<dependency>
<groupId>io.github.markpollack</groupId>
<artifactId>agent-sandbox-core</artifactId>
<version>0.9.3</version>
</dependency>Add agent-sandbox-docker or agent-sandbox-e2b for those backends; each brings
agent-sandbox-core transitively.
try (Sandbox sandbox = LocalSandbox.builder()
.tempDirectory("build-")
.build()) {
ExecResult result = sandbox.files()
.create("pom.xml", pomContent)
.create("src/main/java/App.java", code)
.and()
.exec(ExecSpec.of("mvn", "-q", "compile"));
if (result.success()) {
System.out.println(result.stdout());
}
}./mvnw clean verifyThat runs the unit tests and the LocalSandbox TCK. The other two backends need
infrastructure and gate themselves off when it is absent:
./mvnw -B -pl agent-sandbox-core,agent-sandbox-docker -am clean verify \
-Dsandbox.infrastructure.test=true # needs a Docker daemon
./mvnw -pl agent-sandbox-e2b verify # needs E2B_API_KEYThe Docker suite runs against a minimal ubuntu fixture pinned by digest. That fixture is
a test dependency only — it is not shipped, not endorsed as an application runtime, and
carries no recommendation for your own image choice.
A local dependency CVE scan is available and is deliberately not part of ordinary CI:
./mvnw -Powasp verify # OWASP dependency-check, fails on CVSS >= 7.0
./scripts/security-scan.sh # Trivy, HIGH/CRITICALPre-1.0 and versioned accordingly: the API may change between minor versions.
LocalSandbox and DockerSandbox are exercised by the full TCK; E2BSandbox passes
the same TCK against the live E2B service. agent-sandbox-docker requires Docker
Engine with API version 1.44 or newer.
The 0.10.0 dependency closure has three disclosed upstream findings in Apache HttpComponents classes embedded and relocated inside the Java Docker transport. The HTTP/2/HPACK condition is not reachable on the Docker HTTP/1.1 path examined; the other two require a malicious response from the trusted, root-equivalent local Docker daemon. No path from untrusted code inside a selected container to those advisory conditions was identified under this trust model. Published Testcontainers/docker-java combinations examined do not yet embed the fixed versions, and ordinary dependency overrides cannot replace relocated classes inside the zerodep JAR. The findings remain visible and are accepted for the trusted-local-daemon use case; changing the caller-selected image cannot remove them.
Breaking change in 0.10.0. DockerSandbox no longer has a default image. The
no-argument DockerSandbox() constructor is removed, and builder() now requires
.image(...). Previously it silently pulled ghcr.io/spring-ai-community/agents-runtime:latest
— a mutable tag in a namespace this project does not control or maintain. Pass the image
you want; constructors taking an explicit image are unchanged.
This project originated from earlier Apache-licensed work in the Spring AI Community.
Its last Apache License 2.0 release was org.springaicommunity:agent-sandbox-* 0.9.1.
Beginning with 0.9.2 — the first release under the io.github.markpollack coordinates —
new development is licensed under the Business Source License 1.1.
The 0.9.0 and 0.9.1 artifacts published under Apache 2.0 remain available under their original terms; nothing already released has been relicensed. See Business Source License 1.1 and LICENSE-APACHE.txt.