3 ms·
This project looks very cool - I've been trying to build something similar in a few different ways (https://github.com/simonw/denobox https://github.com/simonw/
by simonw 9mo ago
This project looks very cool - I've been trying to build something similar in a few different ways (https://github.com/simonw/denobox https://github.com/simonw/denobox is my most recent attempt) but this is way ahead of where I've got, especially given its support for shell scripting.
I'm sad about this bit though:
> Python code is MIT. The WASM binary is proprietary—you can use it with this package but can't extract or redistribute it separately.
- sd2k 9mo agoI posted this elsewhere in the thread, and don't want to spam it everywhere (or take away from Amla!), but you might be interested in eryx [1] - the Python bindings [2] get you a similar Python-in-Python sandbox based on a WASI build of CPython (props to the componentize-py [3] people)! [1]: https://github.com/sd2k/eryx/ https://github.com/sd2k/eryx/ [2]: https://pypi.org/project/pyeryx/ https://pypi.org/project/pyeryx/ [3]: https://github.com/bytecodealliance/componentize-py/ https://github.com/bytecodealliance/componentize-py/
- simonw 9mo agoThat's really cool. Any chance you could add SQLite? % uv run --with pyeryx python Installed 1 package in 1ms Python 3.14.0 (main, Oct 7 2025, 16:07:00) [Clang 20.1.4 ] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import eryx >>> sandbox = eryx.Sandbox() >>> result = sandbox.execute(''' ... print("Hello from the sandbox!") ... x = 2 + 2 ... print(f"2 + 2 = {x}") ... ''') >>> result ExecuteResult(stdout="Hello from the sandbox!\n2 + 2 = 4", duration_ms=6.83, callback_invocations=0, peak_memory_bytes=Some(16384000)) >>> sandbox.execute(''' ... import sqlite3 ... print(sqlite3.connect(":memory:").execute("select sqlite_version()").fetchall()) ... ''').stdout Traceback (most recent call last): File "<python-input-6>", line 1, in <module> sandbox.execute(''' ~~~~~~~~~~~~~~~^^^^ import sqlite3 ^^^^^^^^^^^^^^ print(sqlite3.connect(":memory:").execute("select sqlite_version()").fetchall()) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ''').stdout ^^^^ eryx.ExecutionError: Traceback (most recent call last): File "<string>", line 1, in <module> File "<string>", line 125, in _eryx_exec File "<user>", line 2, in <module> File "/python-stdlib/sqlite3/__init__.py", line 57, in <module> from sqlite3.dbapi2 import * File "/python-stdlib/sqlite3/dbapi2.py", line 27, in <module> from _sqlite3 import * ModuleNotFoundError: No module named '_sqlite3' Filed a feature request here: https://github.com/eryx-org/eryx/issues/28 https://github.com/eryx-org/eryx/issues/28
- simonw 9mo agoIt looks like there's not mechanism yet in the Python bindings for exposing callback functions to the sandboxed code - it exists in the Rust library and Python has a ExecuteRusult.callback_invocations counter so presumably this is coming soon?
- sd2k 9mo agoGood call, yes, I'll get that added soon!
- manojlds 9mo agoHow does this all compare to using pyodide?
- simonw 9mo agoA lot of it IS using Pyodide, but wrapping it in a way that's convenient to use not-in-a-browser.
- sd2k 9mo agoI'm not super familiar with how pyodide works but I think it uses CPython compiled with Emscripten then needs to be run from a Javascript environment, and uses the browser's (or Node's) Wasm engine. This uses CPython compiled to WASI and can (in theory) be run from any WASI-compatible Wasm runtime, in this case wasmtime, which has bindings in lots of languages. WASI uses capability based security rather than browser sandboxing and lets the host intercept any syscalls which is pretty cool. Wasmtime also lets you do things like epoch-based interruption, 'gas' for limiting instruction count, memory limits, and a bunch of other things that give you tons of control over the sandbox. Pyodide/Emscripten might offer something similar but I'm not sure!
- manojlds 9mo agoThanks for the explanation, need to dive in deeper into wasm / wasi - I didn't realize there was a difference.
- souvik1997 9mo agoThanks Simon! Denobox looks very cool: Deno's permissions model is a natural fit for this. On the licensing: totally fair point. Our intention is to open source the WASM too. The binary is closed for now only because we need to clean up the source code before releasing it as open-source. The Python SDK and capability layer are MIT. We wanted to ship something usable now rather than wait. Since the wasm binary runs in wasmtime within an open source harness, it is possible to audit everything going in and out of the wasm blob for security. Genuinely open to feedback on this. If the split license is a blocker for your use cases, that's useful signal for us.
- simonw 9mo agoThat's great to hear. The split license is a blocker for me because I build open source tools for other people to use, so I need to be sure that all of my dependencies are things I can freely redistribute to others.
- souvik1997 9mo agoMakes total sense. We'll prioritize getting the WASM source out. This is good signal that it matters. Will ping you when it's up!
- simonw 9mo agoSmall suggestion: push an alpha to PyPI ASAP mainly to preserve your name there but also to make it more convenient for people to try out with `uv`.
- souvik1997 9mo agoYep, we got that sorted. Thanks for the suggestion! https://pypi.org/project/amla-sandbox/ https://pypi.org/project/amla-sandbox/
- phickey 9mo agohttps://github.com/bytecodealliance/ComponentizeJS https://github.com/bytecodealliance/ComponentizeJS is a Bytecode Alliance project which can run JS in a SpiderMonkey-based runtime as a Wasm component
- vimota 9mo agoSimon - would love if you could take a look at Localsandbox (https://github.com/coplane/localsandbox https://github.com/coplane/localsandbox) - it was partly inspired by your Pyodide post!
- simonw 9mo agoI tried it (really like the API design) but ran into a blocker: uv run --with localsandbox python -c ' from localsandbox import LocalSandbox with LocalSandbox() as sandbox: result = sandbox.bash("echo hi") print(result.stdout) ' Gave me: Traceback (most recent call last): File "<string>", line 5, in <module> result = sandbox.bash("echo hi") File "/Users/simon/.cache/uv/archive-v0/spFCEHagkq3VTpTyStT-Z/lib/python3.14/site-packages/localsandbox/core.py", line 492, in bash raise SubprocessCrashed( ...<2 lines>... ) localsandbox.exceptions.SubprocessCrashed: Node subprocess crashed: error: Failed reading lockfile at '/Users/simon/.cache/uv/archive-v0/spFCEHagkq3VTpTyStT-Z/lib/python3.14/site-packages/localsandbox/shim/deno.lock' Caused by: Unsupported lockfile version '5'. Try upgrading Deno or recreating the lockfile Actually that was with Deno 2.2.10 - I ran "brew upgrade deno" and got Deno 2.6.7 and now it works!
- simonw 9mo agoIt looks like it currently defaults to allowing networking so it can load Pyodide from npm. My preference is a sandbox with no network access at all and access only to specific files that I can configure.
- vimota 9mo agoThanks for taking a look and the feedback! We run the shim with internet access (https://github.com/coplane/localsandbox/blob/main/localsandbox/shim/deno.json#L7 https://github.com/coplane/localsandbox/blob/main/localsandb...) but the pyodide sandbox itself doesn't run with internet access : https://github.com/coplane/localsandbox/blob/main/localsandbox/shim/src/python.ts#L139 https://github.com/coplane/localsandbox/blob/main/localsandb...