Skip to main content

maf-sandbox-docker

PyPI Python License

Experimental. Releases before 1.0 may change or remove APIs. Importing this package emits MafSandboxDockerExperimentalWarning.

Run sandbox workloads in Linux containers through the Docker CLI. This backend provides commands, file transfer and guest-to-host tool calls. Its Python dependency is maf-sandbox.

This is an independent package, not a Docker Inc. or Microsoft product.

Quickstart

pip install maf-sandbox-docker
from maf_sandbox import Isolation, SandboxRouter
from maf_sandbox_docker import DockerSandboxBackend, DockerSandboxConfig

backend = await DockerSandboxBackend.create(DockerSandboxConfig())
router = SandboxRouter([backend], min_isolation=Isolation.CONTAINER)

The async factory reads the daemon's OS and declares POSIX for Linux. The plain constructor also works, but declares no OS family. A kind requiring POSIX therefore needs the async factory.

Container isolation shares a kernel and is below the router's default microVM minimum. The explicit minimum above allows it. Docker Desktop's shared VM does not change this declaration.

See the Docker CodeAct sample or file-output sample for a complete application.

Requirements

Use Docker Desktop or Docker Engine with a reachable Docker CLI. Both rootful and rootless Linux engines are supported. Windows requires an event loop that can start subprocesses, such as the default Proactor loop.

DockerSandboxConfig.docker_path selects the CLI binary. The client must support Docker context inspection; the Podman CLI does not. Other compatible engines reached through Docker's CLI are not verified here.

The backend captures the client environment and binds its context, endpoint and TLS settings. Later context changes cannot redirect it. A missing context refuses instead of falling back. The async factory binds immediately; the constructor binds on first use.

Supported operations

Setting Behavior
Isolation CONTAINER
Capabilities EXEC, FILES_IN, FILES_OUT, FILES_DELETE, HOST_TOOLS, RECLAIM
Network CLOSED; ALLOWLIST with a configured proxy
Lifetime Conversation or separate sandbox per call
Transfer ceiling 64 MiB per file, 256 MiB total, 256 files in each direction
Cleanup Disposal by default; reclaim requires explicit host opt-in

Directory listing, runtime run_code, snapshots, method-level network rules and core attached identity are unavailable.

Acquisition checks the guest commands needed by the requested capabilities. EXEC needs sh, even for an argv-only workload. Deletion needs rm; host tools also need mkdir, mv and nohup. File transfer itself needs no guest command.

The backend adds no host bind mount or Docker socket. Every container uses no-new-privileges and a PID limit. Dropping all capabilities, memory limits and CPU limits are optional configuration.

File transfer

Acquisition prepares the storage base for workloads using commands or files. work_dir=None selects /maf-sandbox/work; an explicit path requests that exact base. Use working_directory="." to address it.

Files move through Docker's tar-based copy API. Input files and newly created directories use the resolved image UID/GID. Existing directories keep their contents, ownership and modes.

Output reads check every ancestor from the filesystem root and reject links or non-directory parents. The final entry must be a regular file. Reads over the caller's cap fail without returning a prefix.

The container stays paused across each path check and transfer. This prevents guest code from replacing a checked parent before the copy. It also stops all guest execution during the transfer and adds overhead, especially when host tools poll for files.

The engine must support pause, including for ordinary command acquisition that prepares a work directory. There is no unpaused fallback.

Transfers observe the ordinary container filesystem. Keep outputs out of tmpfs, /proc, /sys, /dev and other guest mounts the copy API does not expose. A guest-visible mounted file can appear absent to the collector.

FILES_LIST is unavailable because Docker's directory archive transfers the whole subtree to discover its names. Kinds must name outputs explicitly.

Image users

The backend resolves Config.User using container account files and, when needed, id. An unset user means root. A numeric uid:gid is the clearest image setting.

Unresolved users refuse workloads requiring FILES_OUT or HOST_TOOLS. Root-owned inputs cannot promise the guest can create adjacent outputs or transport files. Other workloads may proceed with a warning and root-owned inputs. Failed resolution is retried on later acquisition.

Network access

Without a proxy, only Egress.CLOSED is supported and containers use --network none. An allowlist request is refused.

Build the packaged proxy once and select it in configuration:

from maf_sandbox_docker import DockerSandboxConfig, proxy_build_context

print(f"docker build -t maf-egress-proxy:local {proxy_build_context()}")
config = DockerSandboxConfig(egress_proxy_image="maf-egress-proxy:local")

A nonempty allowlist needs Docker Engine 28.0.0 or newer. The workload joins an isolated internal network with no bridge address. Its only route out is a filtering proxy that permits the spec's hosts. Proxy environment variables help clients find it; the network topology enforces the restriction.

TLS is not decrypted. Unrestricted access and method-scoped rules are refused. An empty allowlist uses --network none.

Proxy decisions can be reported through the router's observer after confirmed proxy removal. Failed removal can leave a window unreported; missing events do not prove no traffic occurred. See egress observation.

Cleanup and retention

Acquisition reuses a matching running container, restarts a stopped one or creates a missing one. Router-managed tools dispose after each call unless the host explicitly permits reclaim. Reclaim can leave state outside the call directory; a kind's confinement declaration is advisory.

dispose(key, kind=...) removes a selected kind. dispose_scope(scope, thread_id) finds conversation resources through engine labels, including resources created by another host process.

An operator can remove old workloads and orphaned proxy infrastructure:

from datetime import timedelta

result = await backend.reap(timedelta(hours=24), scope="my-app")
print(result.disposed, result.proxies_removed, result.networks_removed)
for failure in result.failures:
    print(failure)

This is a maximum creation age, not an idle timeout. It can terminate active sandboxes. Omitting scope covers all backend-owned scopes on the engine. The backend starts no scheduler.

Inventory and revalidation failures prevent deletion. Removals target inspected resource IDs, and attached networks are not forcibly disconnected. Individual failures remain in the result for operator handling. See cleanup ownership.

Verification

The repository's Docker live suite runs shared conformance probes against a real engine. To test a kind's confinement claim, use DockerFingerprintSubject with assert_nothing_left_behind and require every result to pass.

from maf_sandbox.conformance import assert_nothing_left_behind
from maf_sandbox_docker.conformance import DockerFingerprintSubject

subject = DockerFingerprintSubject(sandbox, observer_image="trusted-python-observer:local")
results = await assert_nothing_left_behind(subject, call_and_cleanup)
assert all(result.passed for result in results)

call_and_cleanup runs the kind and awaits its cleanup on a fresh sandbox. Set MAF_SANDBOX_DOCKER_E2E_IMAGE and MAF_SANDBOX_DOCKER_OBSERVER_IMAGE to run the repository's live observer tests with your images.

The subject needs a trusted local observer image with Python 3.12 or newer. It measures final filesystem and process state, including mounted storage such as /dev/shm. A restored temporary change can leave no measured residue, and the probe does not prove all kernel state is clean.

See the backend guide for measurement limits and the complete transfer, network and cleanup contract.

Maintained by SOKOLAI BV.

Release files for maf-sandbox-docker 0.22.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for maf-sandbox-docker 0.22.1
File Size Uploaded
maf_sandbox_docker-0.22.1.tar.gz 69.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for maf-sandbox-docker 0.22.1
File Interpreter ABI Platform
maf_sandbox_docker-0.22.1-py3-none-any.whl Python 3 none any Details

Total release size: 144.2 kB

Release files / maf_sandbox_docker-0.22.1.tar.gz

Download URL maf_sandbox_docker-0.22.1.tar.gz
Size 69.9 kB
Tags Source
SHA-256 checksum
How to use checksums
cbd4354d1eafae8baba07541a24308c917a1217da4d56c8e811e3f0d9e1a6db1
BLAKE2b-256 checksum
How to use checksums
194da2b7755ba4d168d0e6e5c91da2f26a90d12cc06cc4812081c80193fce6ae
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release files / maf_sandbox_docker-0.22.1-py3-none-any.whl

Download URL maf_sandbox_docker-0.22.1-py3-none-any.whl
Size 74.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8fe62b307f8b37e088c7413b1baaac457e4318f59fd364f35beae82007e282cb
BLAKE2b-256 checksum
How to use checksums
9beebfc4f6e6f9cc11912adbd53de5dc0c066f203f42ab7254217054c1c1f645
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release history Release notifications | RSS feed

0.23.1

2 release files

0.23.0

2 release files

This release

0.22.1 This release

2 release files

0.22.0

2 release files

0.21.0

2 release files

0.20.1

2 release files

0.19.0

2 release files

0.18.1

2 release files

0.18.0

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.2

2 release files

0.8.1

2 release files

0.7.3

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page