Skip to main content

Restricted Python execution runner with subprocess isolation, timeout, memory caps, and import/global controls

Project description

safe-py-runner

A lightweight, secure-by-default Python code runner designed for LLM agents.

PyPI version License: MIT

The Missing Middleware for AI Agents: When building agents that write code, you often face a dilemma:

  1. Run Blindly: Use exec() in your main process (Dangerous, fragile).
  2. Full Sandbox: Spin up Docker containers for every execution (Heavy, slow, complex).
  3. SaaS: Pay for external sandbox APIs (Expensive, latency).

safe-py-runner offers a middle path: It runs code in a subprocess with timeout, memory limits, and input/output marshalling. It's perfect for internal tools, data analysis agents, and POCs where full Docker isolation is overkill.

Features

  • 🛡️ Process Isolation: User code runs in a separate subprocess, protecting your main app from crashes.
  • ⏱️ Timeouts: Automatically kill scripts that run too long (default 5s).
  • 💾 Memory Limits: Enforce RAM usage caps (default 256MB) on POSIX systems.
  • 🚫 Import Blocklist: Prevent access to dangerous modules (os, subprocess, socket).
  • 📦 Magic I/O: Automatically injects input variables and captures results as JSON.

Installation

pip install safe-py-runner

Quick Start

from safe_py_runner import RunnerPolicy, run_code

# Define a policy (optional, defaults are safe)
policy = RunnerPolicy(
    timeout_seconds=5,
    memory_limit_mb=128,
    blocked_imports=["os", "subprocess", "socket"],
)

# Run code
result = run_code(
    code="import math\nresult = math.sqrt(input_data['x'])",
    input_data={"x": 81},
    policy=policy,
    # Optional: Path to a specific Python executable (e.g., in a venv)
    # python_executable="/path/to/venv/bin/python",
)

if result.ok:
    print(f"Result: {result.result}")  # 9.0
else:
    print(f"Error: {result.error}")

## Advanced Configuration

### Using a Custom Python Environment
By default, `safe-py-runner` uses `sys.executable` (the same Python running your app).
To improve isolation or provide specific libraries to the runner, creating a dedicated virtual environment is recommended:

1. Create a venv: `python -m venv runner_env`
2. Install allowed packages: `runner_env/bin/pip install pandas numpy`
3. Pass the path to `run_code`:

```python
run_code(
    code="...",
    python_executable="/path/to/runner_env/bin/python"
)

## Security Note

**This is not an OS-level sandbox.**
It uses Python runtime hooks and resource limits to prevent accidents and basic misuse. For hosting code from anonymous/hostile users, you MUST pair this with Docker or similar isolation.

## Contributing

Contributions are welcome! Please open an issue or PR on GitHub.

## CI and Release Automation

- Push to `main`: runs CI tests automatically via GitHub Actions.
- Push a tag like `v0.1.1`: builds `sdist` + wheel, creates a GitHub Release, and publishes to PyPI via Trusted Publishing.

Release title/description are read from:

- `.github/release/metadata.json`

Trusted Publishing configuration expected by this repo:

- workflow name: `release`
- workflow file: `.github/workflows/release.yml`
- GitHub environment: `pypi`

Example `release_metadata.md`:

```md
# safe-py-runner {{tag}}

Release notes for {{tag}}.

- Summarize key changes here.
- Add migration notes if any.

{{tag}} is replaced automatically with the pushed tag name by the release workflow.

Commit Workflow (Step-by-Step)

Assuming commit_message.txt is already updated:

  1. Run tests:
make test
  1. Stage files:
make git-add
  1. Commit:
make git-commit

make git-commit validates:

  • commit_message.txt exists and is non-empty
  • commit_message.txt is different from the latest git commit message
  1. Push to main:
make git-push

Optional shortcut:

make push

Note: if you already ran atomic steps (make git-add + make git-commit), you can run either make git-push or make push. make push is smart now: when there are no local file changes, it skips commit/test steps and only pushes.

Release Workflow (Step-by-Step)

Assuming commit_message.txt and release_metadata.md are updated:

  1. Bump version:
make set-version 0.1.2
  1. Regenerate release metadata JSON:
make metadata
  1. Run tests:
make test
  1. Stage files:
make git-add
  1. Commit:
make git-commit
  1. Push to main:
make git-push
  1. Create and push release tag:
make git-tag

make git-tag reads version from pyproject.toml and will fail if:

  • a version argument is provided
  • version in pyproject.toml is missing or invalid
  • current tag from pyproject.toml is already the latest tag

Optional shortcut:

make release

Note: if you run release as atomic steps and already executed make git-commit, continue with make git-push and make git-tag (or run make push first; it will detect no local file changes and only push).

Additional Recommended Steps

  1. Run make help to see available commands.
  2. Verify GitHub Actions CI passed on main before tagging.
  3. After tagging, verify the release workflow succeeded and wheel artifact is attached.

Project details


Download files

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

Source Distribution

safe_py_runner-0.1.4.tar.gz (30.3 kB view details)

Uploaded Source

Built Distribution

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

safe_py_runner-0.1.4-py3-none-any.whl (8.8 kB view details)

Uploaded Python 3

File details

Details for the file safe_py_runner-0.1.4.tar.gz.

File metadata

  • Download URL: safe_py_runner-0.1.4.tar.gz
  • Upload date:
  • Size: 30.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for safe_py_runner-0.1.4.tar.gz
Algorithm Hash digest
SHA256 7ed8a9a3e6ff18ac60cfe6f1eac169eb230d1a62be885317cb4d7d76b749e2e1
MD5 fc293288b4198970998e575695631a02
BLAKE2b-256 42422e7184b2d41e3e4fed8be5024aa6f0a3c53070fa5cc904e311d760376e07

See more details on using hashes here.

Provenance

The following attestation bundles were made for safe_py_runner-0.1.4.tar.gz:

Publisher: release.yml on adarsh9780/safe-py-runner

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

File details

Details for the file safe_py_runner-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: safe_py_runner-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 8.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for safe_py_runner-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 5064f97de3dc941c3eca31054917ba9483149e48fa4f4a0c77b4d3dd23cab899
MD5 49e0da5a8a14e14f04e67b3aeafde944
BLAKE2b-256 ea3ff33669629c339e945f99477e521086cf8a0b7b29b7a62c603080add3c0dd

See more details on using hashes here.

Provenance

The following attestation bundles were made for safe_py_runner-0.1.4-py3-none-any.whl:

Publisher: release.yml on adarsh9780/safe-py-runner

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