Skip to main content

maf-sandbox

Experimental. This package is early-stage (0.1.0, Development Status :: 4 - Beta) — its API may change or be removed in a future release without notice. Importing it emits a one-time MafSandboxExperimentalWarning; suppress it with warnings.filterwarnings("ignore", category=maf_sandbox.MafSandboxExperimentalWarning) once you've read the notice.

This package is not affiliated with, endorsed by, or a product of Microsoft — it is a third-party reference implementation of microsoft/agent-framework#7568, written for use with Microsoft Agent Framework but with no dependency on it in its protocol layer.

Quickstart

pip install maf-sandbox
from maf_sandbox import Isolation, SandboxKey, SandboxRouter, SandboxSpec, WorkspaceContext

# Implement SandboxBackend against your own provider — or install maf-sandbox-aca for a
# ready-made Azure Container Apps Sandboxes backend — then wire it into a router:
router = SandboxRouter([my_backend], deployed=False)
sandbox = await router.acquire(SandboxKey(scope="tenant-1", thread_id="t-1", agent_dir="devops"), SandboxSpec(kind="bicep", image="bicep-sandbox:0.46.1", egress_allow=("mcr.microsoft.com",), work_dir="/workspace"))

Threat model

This package draws no isolation boundary itself — it is protocol and policy over whatever a SandboxBackend implementation actually provides. Isolation states three tiers a backend can declare, from strongest to weakest: vm (a VM boundary — the whole guest, not just a process, is untrusted), container (a shared-kernel boundary), and process (no boundary beyond the OS's own process isolation). SandboxRouter enforces the one rule below on top of that declaration; the package's job is to make an unsafe backend selection fail loudly at construction, not silently at first use. Beyond backend selection, this layer has nothing else to get wrong: it holds no credentials, executes nothing, and reaches no network — everything security-relevant about a specific sandbox lives in the backend that implements it.

The vocabulary

SandboxKey (scope, thread_id, agent_dir) — the one sandbox a caller may reach
SandboxSpec what a sandbox of a given kind needs: image, egress allowlist, work dir
Sandbox write_file + exec — all a workload gets
SandboxBackend acquire / dispose / dispose_scope
SandboxRouter picks the backend, enforces the deployed rule
SandboxPurger duck-typed purge_scoped_thread(scope, thread_id) for a host's delete path

SandboxKey's scope and thread come from the host's request context through WorkspaceContext, whose fields are callables read at call time rather than values. That is deliberate: a key a caller can supply is a key a model can supply, and that would let one conversation address another's sandbox.

SandboxSpec.egress_allow is an allowlist — everything not named is denied, so an empty tuple means no network. Stating it positively means a spec that forgets to mention egress gets the closed configuration rather than the open one.

The one rule that is not a convenience

DEPLOYED_ISOLATION = frozenset({Isolation.VM})

A backend declares its own isolation (vm / container / process). When the host reports it is running deployed, the router refuses to select anything weaker than a VM boundary — raising SandboxBackendNotPermitted at construction, not at first use, so a misconfigured deployment cannot start with the feature apparently enabled and quietly unsafe.

It refuses rather than degrades. Falling back to a stronger backend would hide a misconfiguration; proceeding with the weaker one would break claims the host's security posture makes about every execution surface. Neither is better than an error.

A hardened container runtime (gVisor, Kata, Firecracker) is deliberately not in the permitted set. Admitting one is a decision for whoever owns those posture claims, taken there first.

Writing a backend

Implement name, isolation, acquire, dispose, dispose_scope. Two things worth knowing before you start:

acquire is get-or-create. A workload's fix-round loop calls it every iteration; returning a cold sandbox each time turns a seconds-long loop into a minutes-long one.

dispose_scope must not consult only your process's memory. A multi-replica host serves a conversation delete wherever it lands, so the replica that created the sandbox is usually not the one deleting it. Derive the set from the service — labels, a listing, whatever your provider offers. A backend that skips this leaves billable compute running and the bug is invisible on a single-replica dev box.

Both dispose methods are best-effort by contract: purge must never fail a delete.

Provenance

Extracted from a production agent application, where this seam was written for its first execution surface: a tool that compiles agent-authored infrastructure code in a sandbox. The deployed-isolation rule above is not a preference — it is what a security review concluded when it worked through what a shared-kernel boundary does not close for code an agent wrote.


Maintained by SOKOLAI BV.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

maf_sandbox-0.1.0.tar.gz (20.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

maf_sandbox-0.1.0-py3-none-any.whl (24.4 kB view details)

Uploaded Python 3

File details

Details for the file maf_sandbox-0.1.0.tar.gz.

File metadata

  • Download URL: maf_sandbox-0.1.0.tar.gz
  • Upload date:
  • Size: 20.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for maf_sandbox-0.1.0.tar.gz
Algorithm Hash digest
SHA256 4c730a74538821a9bcbf62c4a5f04f0d4d75665afb58daa8c3852a6da82cfc3f
MD5 c866280d4a65e93c85e023c97592609d
BLAKE2b-256 5d0f87dad5c99b2d500820539c8be7d636b06ab0e0ea5a26903e61a58ed73021

See more details on using hashes here.

Provenance

The following attestation bundles were made for maf_sandbox-0.1.0.tar.gz:

Publisher: publish-packages.yml on sokolaidev/maf-extensions

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file maf_sandbox-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: maf_sandbox-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 24.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for maf_sandbox-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f400841c951b17bf1e883750141aa9fbbf053b86bbffc849da2785f8503fb79e
MD5 bd4413eaaa88a43cdd31178b72dbf451
BLAKE2b-256 882abfb22620effdf116a6d8ccab5410ec78ba1ffa5deff3d676959d6d856ea7

See more details on using hashes here.

Provenance

The following attestation bundles were made for maf_sandbox-0.1.0-py3-none-any.whl:

Publisher: publish-packages.yml on sokolaidev/maf-extensions

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page