Skip to main content

eval_workspace

A local HTTP service for running untrusted code in Python, JavaScript, Java, and Rust, with resource limits (CPU time, memory, wall-clock timeout, process count) and automatic toolchain provisioning — no root required.

What it does

  • Multi-language execution: POST /run with {"language": "python", "code": "..."}, get back stdout/stderr/exit code
  • Local sandboxing: each execution runs in its own process group with:
    • CPU time limit (RLIMIT_CPU)
    • Memory limit (RLIMIT_AS for Python/Java/Rust; Node uses --max-old-space-size instead — V8 reserves large virtual address space upfront, so RLIMIT_AS kills it before user code even runs)
    • Process count limit (fork-bomb protection, RLIMIT_NPROC)
    • Wall-clock timeout (catches processes waiting on I/O rather than burning CPU)
    • No inherited environment variables
    • Fresh temp directory per execution, deleted after
  • Auto-provisioning toolchains: if a language runtime isn't found on PATH, it's downloaded as an official prebuilt binary into ~/.eval_workspace/toolchains/ — no system package manager, no root:
    • Node.js — official prebuilt tarball from nodejs.org
    • Java — Temurin JDK prebuilt tarball from Adoptium
    • Rust — via rustup, which already installs to user-space by design
    • Python — detected only; not auto-installed (no good universal static build to fetch)

Honest limitations — read this before relying on it

This is local (rlimit-based) sandboxing, not container/VM isolation. It reliably stops:

  • Infinite loops (CPU limit + wall-clock timeout)
  • Memory bombs (memory limit)
  • Fork bombs (process count limit)
  • Runaway processes waiting on stdin/network (wall-clock timeout)

It does not provide the same guarantees as Docker, gVisor, or Firecracker against a genuinely adversarial payload. There's no filesystem or namespace isolation beyond a scratch temp directory, and no syscall filtering. If your threat model includes deliberately hostile code trying to escape the sandbox (not just buggy/runaway code), you need real container/VM isolation — this tool does not provide that, and no amount of rlimit tuning makes it equivalent.

Java requires a specific class name. Submitted Java code must define public class Main — same convention most online judges use, since the filename must match the public class name to compile.

Network access is required to auto-install missing toolchains. If the machine running this has no outbound internet access, toolchain auto-install will fail cleanly (returns a clear error) rather than hang — but it can't conjure a compiler out of nowhere either. Pre-install what you need if you're running somewhere network-restricted.

What's actually been tested vs. what hasn't

To be direct about verification status:

Tested end-to-end, with real cross-checks:

  • Python execution (basic output, errors)
  • JavaScript execution via real Node.js (basic output, thrown errors)
  • CPU-limit enforcement (infinite loop correctly killed)
  • Wall-clock timeout enforcement (sleeping process correctly killed)
  • Memory-limit enforcement (large allocation correctly triggers MemoryError)
  • Clean error handling when a toolchain is missing (no crash, structured error returned)
  • Clean error handling when network is unavailable during auto-install (no crash, structured error returned)
  • Limit-clamping logic (abuse-scale requests get capped to sane maximums)

Not testable in the environment this was built in, and not yet verified on a real machine:

  • Java compilation + execution (the build environment had a JRE but no JDK)
  • Rust compilation + execution (Rust wasn't installed, and the sandbox had no network to fetch it)
  • The actual toolchain download/extract logic for Node, JDK, and Rust (needs real network access to confirm the URLs and archive layouts are exactly right)
  • The aiohttp HTTP server itself running live (aiohttp wasn't installable in the build sandbox — the route handlers are thin, tested wrappers around the executor, but the actual server process hasn't been smoke-tested)

If you're the first to run this somewhere with real network and a full toolchain set, treat the untested parts above as "should work, please verify" rather than "confirmed working."

Install

pip install eval-workspace

Usage

Check what's already available:

python -m eval_workspace.cli check

Pre-install any missing toolchains:

python -m eval_workspace.cli install

Start the server:

eval-workspace

Starts on http://127.0.0.1:8765 by default.

Run some code:

curl -X POST http://127.0.0.1:8765/run \
  -H "Content-Type: application/json" \
  -d '{"language": "python", "code": "print(2 + 2)"}'
{"ok": true, "stdout": "4\n", "stderr": "", "exit_code": 0, "timed_out": false, "duration_seconds": 0.05, "error": ""}

Custom limits per request:

curl -X POST http://127.0.0.1:8765/run \
  -H "Content-Type: application/json" \
  -d '{"language": "rust", "code": "fn main() { println!(\"hi\"); }", "limits": {"cpu_seconds": 10, "memory_mb": 512}}'

Check server + toolchain health:

curl http://127.0.0.1:8765/health

API reference

POST /run

Field Type Required Notes
language string yes python, javascript/js, java, or rust
code string yes max 100,000 characters
stdin string no piped to the program's stdin
limits object no see below, all optional

limits fields (all clamped server-side to the max shown):

Field Default Max
cpu_seconds 5 30
memory_mb 256 1024
wall_clock_seconds 10 60
max_processes 16 32
max_output_bytes 200000 1000000

GET /languages

Returns the list of supported language identifiers.

GET /health

Returns toolchain availability for each language.

License

MIT

Release files for eval-workspace 1.5.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 eval-workspace 1.5.1
File Size Uploaded
eval_workspace-1.5.1.tar.gz 14.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for eval-workspace 1.5.1
File Interpreter ABI Platform
eval_workspace-1.5.1-py3-none-any.whl Python 3 none any Details

Total release size: 28.7 kB

Release files / eval_workspace-1.5.1.tar.gz

Download URL eval_workspace-1.5.1.tar.gz
Size 14.4 kB
Tags Source
SHA-256 checksum
How to use checksums
0e84b2c0d4febe39fa41d0863f1d18a8d62c5a4498c985edd415cd7ac60d2a5e
BLAKE2b-256 checksum
How to use checksums
b28a0fc156e44fed0b2db2f7ebd5cbb1f1dc7373fbaabee1fabcd6dbc01025cd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.14

Release files / eval_workspace-1.5.1-py3-none-any.whl

Download URL eval_workspace-1.5.1-py3-none-any.whl
Size 14.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c5fca25c8576a4b112f8de5e7c1051133cceab2fa1aa8040aeef61df30418057
BLAKE2b-256 checksum
How to use checksums
b8d8797f75ec9df2b9f0e887f16ea8498c1335d429877690fe709686ee73c0e8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.14

Release history Release notifications | RSS feed

This release

1.5.1 This release

2 release files

1.5.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