maf-sandbox-wslc
Experimental. Releases before 1.0 may change or remove APIs. Importing this package emits
MafSandboxWslcExperimentalWarning.
Run sandbox commands in Linux containers managed by wslc, the container CLI included with WSL. This backend transfers input files and returns command output. It has no Azure dependency.
This is an independent package, not a Microsoft product.
Quickstart
pip install maf-sandbox-wslc
from maf_sandbox import Isolation, SandboxRouter
from maf_sandbox_wslc import WslcSandboxBackend, WslcSandboxConfig
backend = WslcSandboxBackend(WslcSandboxConfig())
router = SandboxRouter([backend], min_isolation=Isolation.CONTAINER)
Containers share the WSL kernel. The explicit minimum permits container isolation, below the router's default microVM minimum.
Use Windows with WSL 2.9.3 or later. wsl --version reports the installed version. The backend's CLI contract has been measured on WSLC 2.9.4.0 and 2.9.12.0.
The Python event loop must support subprocesses. Windows' default Proactor loop does; WindowsSelectorEventLoopPolicy does not.
See the Bicep sample or CodeAct sample for complete applications.
Supported operations
| Setting | Behavior |
|---|---|
| Isolation | CONTAINER |
| Capabilities | EXEC, FILES_IN |
| Guest OS | POSIX |
| Network | CLOSED; ALLOWLIST with a configured proxy |
| Lifetime | Conversation or separate sandbox per call |
| Transfer ceiling | 8 MiB per file, 32 MiB total, 64 files per direction |
| Cleanup | Disposal; no reclaim or snapshot reset |
Output reads, directory listing, file deletion, runtime run_code and host-tool calls are unavailable. A kind requiring one is refused before attachment.
Acquisition checks sh for commands. Input transfer also needs the external test command and a resolved image user. Failed prerequisite checks are retryable.
Input files and their limits
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. Existing directories keep their contents, ownership and modes.
Files and missing directories at or below working_directory receive the image user's UID/GID. An unset Config.User means root. Named users or an omitted group need working id commands. Unresolved ownership refuses writes and creation of a missing base.
The copy acts with root authority, and its path check is separate from the write. A guest can replace a checked parent with a symlink before extraction. That can redirect bytes outside the working directory, including into a root-owned directory the guest cannot write itself.
The same race affects creation of missing directories and work-directory repair during acquisition. Setting tar ownership does not reduce placement authority. Cancellation after copy submission can leave partial writes.
Some path classification runs inside the guest. It does not hold the checked filesystem state or provide a trusted freeze. Choose another transfer mechanism or backend if concurrent guest changes must not escape the checked directory.
Path inspection can also copy an existing guest file into a private host temporary directory. Its disk use is not bounded by input limits or stdout limits. Normal exits remove the temporary copy, but a host crash or cleanup failure can leave it behind. Use an enforced temporary-filesystem quota when that consumption is unacceptable.
See the backend guide for the precise file contract and remaining limits.
Network access
Without a proxy, only Egress.CLOSED is supported. Containers use --network none, and an allowlist request is refused.
Build the packaged proxy and select it in configuration:
from maf_sandbox_wslc import WslcSandboxConfig, proxy_build_context
print(f"wslc build -t maf-egress-proxy:local {proxy_build_context()}")
config = WslcSandboxConfig(egress_proxy_image="maf-egress-proxy:local")
Each allowlisted sandbox gets an internal network and a filtering proxy. The proxy is its only route out and permits only the spec's hosts. TLS is not decrypted. Unrestricted access and method-scoped rules are unsupported.
The router's observer can receive proxy decisions after confirmed removal. Failed removal can leave a window unreported. See observability.
Cleanup and retention
Router-managed calls dispose their sandbox even when a kind claims to keep changes inside its call directory. WSLC cannot establish the ancestry needed for privileged reclaim and declares no snapshot reset.
dispose(key, kind=...) removes a selected kind and its infrastructure. dispose_scope(scope, thread_id) discovers conversation resources through engine labels, not only process memory.
An operator can clean up stopped workloads and orphan 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)
Run this under the Windows account that owns the WSLC engine. The backend starts no timer. An external scheduler must select the environment, prevent overlapping sweeps and monitor failures.
Pause and drain acquisition, restarts and other resource changes in the selected scope before sweeping. Engine rechecks cannot make name-based network deletion atomic. Keep Windows and WSL clocks synchronized.
| Resource | Age used for retention |
|---|---|
| Stopped workload | Time since its inspected stop; a restart and stop resets it. |
| Never-started workload | Creation time. |
| Proxy without a workload | Creation time, including for a running orphan proxy. |
| Network alone | Its backend creation-time label; missing labels retain it for manual handling. |
Running or uncertain workload states retain their whole group. Resources exactly at the cutoff are retained. An incomplete inventory prevents deletion; individual failures are reported. Retention does not infer that a host has died or impose a maximum running lifetime.
See operations for scheduling and cleanup ownership. The live suite covers writes, networks and separate-process retention using explicitly configured images.
Maintained by SOKOLAI BV.
Release files for maf-sandbox-wslc 0.23.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| maf_sandbox_wslc-0.23.1.tar.gz | 43.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| maf_sandbox_wslc-0.23.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 91.3 kB
Release files / maf_sandbox_wslc-0.23.1.tar.gz
| Download URL | maf_sandbox_wslc-0.23.1.tar.gz |
|---|---|
| Size | 43.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7b01bf780dcde806b1d7c22ed1161545eb7a709ea451c330f54172d147627892
|
|
BLAKE2b-256 checksum How to use checksums |
58b22b5410051b02edbe053e761e8b7e7f5fab6d4dc8b26d23d74fe804d5220a
|
| 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 logRelease files / maf_sandbox_wslc-0.23.1-py3-none-any.whl
| Download URL | maf_sandbox_wslc-0.23.1-py3-none-any.whl |
|---|---|
| Size | 47.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c72aec36f9aeb01864138a3123ddd4027b11be671357232326855fdb252b186e
|
|
BLAKE2b-256 checksum How to use checksums |
e36bd49c05d1fed03e056a74175ff7fa9e26f1f5cc4fe58450769cab75bea40d
|
| 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