Metadata-Version: 2.4
Name: podsandbox
Version: 0.1.0
Summary: A tiny, host-agnostic sandbox for running commands, moving files, and serving a live preview URL from an isolated, disposable Kubernetes Pod.
Project-URL: Homepage, https://github.com/opxyc/podsandbox
Project-URL: Source, https://github.com/opxyc/podsandbox
Author: BE
License: MIT
License-File: LICENSE
Keywords: coding-agent,exec,ingress,isolation,kubernetes,pod,preview,sandbox
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Build Tools
Classifier: Topic :: System :: Emulators
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: kubernetes>=27.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Provides-Extra: examples
Requires-Dist: anthropic>=0.116; extra == 'examples'
Description-Content-Type: text/markdown

# podsandbox

A small async Python library for running commands, moving files, and serving a live preview URL inside an **isolated, disposable Kubernetes Pod**.

You write your code against one interface — `SandboxProtocol` — and hand it a real `Sandbox` (a hardened pod) in production or a `FakeSandbox` in tests. It knows nothing about your workload: if the image has a tool installed, `exec(["that-tool", …])` runs it.

## Features

- **Run anything** in an isolated pod — `exec`, plus `read_file` / `write_file` / `list_files` / `put_file`.
- **Live preview URL** — `start_service()` boots a long-lived server in the pod and exposes it via a per-pod Service + Ingress.
- **Hardened by default** — non-root, read-only root FS, dropped capabilities, seccomp, no API-token automount; optional gVisor (`runtime_class="gvisor"`).
- **Secret-safe** — register secrets and they're scrubbed from all output/errors; credential files stream in over stdin, never via argv.

## Install

```bash
pip install podsandbox
```

To actually run sandboxes you need a reachable cluster (a local [kind](deploy/kind/) cluster works) and a sandbox image loaded into it. The unit tests need neither.

## Quick start

```python
import asyncio
from podsandbox import Sandbox

async def main():
    box = Sandbox(sandbox_id="run-1234")
    try:
        await box.start(image="podsandbox-example:latest")
        await box.write_file("index.html", "<h1>hello</h1>\n")
        print(await box.exec(["ls", "-la"]))           # ExecResult(exit_code=0, stdout='…')

        preview = await box.start_service(["python3", "-m", "http.server", "8000"], port=8000)
        print(preview.url)                              # http://run-1234.127.0.0.1.nip.io
    finally:
        await box.stop()                                # always tear down (pod + preview)

asyncio.run(main())
```

More runnable examples in [`examples/`](examples/): `hello_exec.py` (generic exec), `preview.py` (the `start_service` flow), and `git_repo.py` (the git recipe). The flagship is **[`coding_agent.py`](examples/coding_agent.py)** — see below.

## The coding agent

[`examples/coding_agent.py`](examples/coding_agent.py) is the showcase: a real Claude agent whose `write_file` / `edit_file` / `run_command` tools each wrap a `Sandbox` method. Give it a task and it writes code, runs it, iterates on the output, and serves the result at a **live preview URL** — every action executing inside the disposable, hardened pod.

```bash
pip install "podsandbox[examples]"     # adds the Anthropic SDK
export ANTHROPIC_API_KEY=sk-ant-...
python examples/coding_agent.py                                    # builds + serves a small web app
python examples/coding_agent.py "build a snake game in one HTML file and serve it"
```

Needs a reachable cluster (see [Local development](#local-development)). This is the whole point of the library: an LLM does arbitrary, untrusted work somewhere it can't touch your machine, and you watch the result come to life at a URL.

## Concepts

- **`SandboxProtocol`** — the interface you depend on and type-hint against.
- **`Sandbox`** — the real implementation, one hardened Kubernetes Pod per instance.
- **`FakeSandbox`** — an in-memory drop-in for tests (dict filesystem, programmable `exec`), no cluster required.

`SandboxConfig` tunes namespace, workdir, preview domain, resource limits, and `runtime_class`.

## Testing

```bash
pip install -e ".[dev]"
pytest              # unit tests — no cluster
pytest -m kind      # integration tests — needs a running kind cluster (see deploy/kind/)
```

## Local development

[`deploy/kind/`](deploy/kind/) has a one-command script to stand up a local cluster (kind + ingress-nginx + a `sandboxes` namespace) that mirrors production shape, so previews resolve at `http://<id>.127.0.0.1.nip.io`.

## Security

Every pod is hardened by default (see the list under [Features](#features)). For stronger kernel isolation, run under gVisor with `SandboxConfig(runtime_class="gvisor")` — this needs cluster-side setup; see [`deploy/gvisor/`](deploy/gvisor/). Network egress restrictions (allowlisting the registry/git host, blocking internal/metadata IPs) are left to a cluster NetworkPolicy.

## License

MIT — see [LICENSE](LICENSE).
