Describe the subinterpreter backend as what it actually is - #289
Merged
Conversation
README, SECURITY.md and docs/threat-model.md all stated that guest code under backend="subinterpreter" "runs in a sub-interpreter in the supervisor's own process". It does not. pyisolate/runtime/thread.py runs each guest in a threading.Thread and execs guest source against a restricted __builtins__ mapping -- its own module docstring called itself "a greatly simplified placeholder that executes code in a dedicated thread using the standard interpreter". No security claim changes: that backend is documented throughout as an execution cell and not a boundary against hostile Python, which is equally true of a thread and of a real sub-interpreter. What changes is the mechanism a reader should assume. The difference is observable -- a thread shares sys.modules and the GIL with the supervisor, a sub-interpreter does not -- so anyone reasoning about isolation, or about the no-GIL parallel- cell axis, was working from the wrong model. Add a "Sub-interpreter status" section to the README stating the current mechanism, comparing it with the intended one, and pointing untrusted workloads at backend="process". Reference it from the three documents that made the claim and from docs/execution-model.md. Record landing the real implementation (concurrent.interpreters on 3.14, _interpreters on 3.12+), or renaming the backend, as a Now/next roadmap item. Also fix thread.py's docstring, which pointed readers at an AGENTS.md that does not exist anywhere in the repository. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ebvMQ3vLxdK3joymz6Feg
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
README, SECURITY.md, and
docs/threat-model.mdall state that guest code underbackend="subinterpreter""runs in a sub-interpreter in the supervisor's own process."It does not.
pyisolate/runtime/thread.pyruns each guest in athreading.Threadandexecs guest source against a restricted__builtins__mapping. There is nointerpreters/_interpreters/Py_NewInterpreteranywhere in the codebase. The module's own docstring said so:So the most-read documents disagreed with the implementation, in the feature the project is named after.
Why it matters (and what it doesn't change)
No security claim changes. That backend is documented throughout as an execution cell and explicitly not a boundary against hostile Python — equally true of a thread and of a real sub-interpreter. The threat model's answers are unaffected, and I've said so inline rather than leaving a reader to wonder.
The mechanism does change, and it's observable:
sys.modulesAnyone reasoning about isolation between cells, or about the no-GIL "parallel cells vs scheduled compartments" axis, was working from the wrong model.
The change
Docs only — no behavior.
backend="process"for untrusted code.docs/execution-model.mdgets the same note.thread.py's docstring rewritten to describe the runtime accurately — and to drop its pointer to anAGENTS.mdthat does not exist anywhere in the repo.concurrent.interpreters(3.14) /_interpreters(3.12+), or rename the backend tothread. I deliberately did not pick — renaming is a breaking API change and that's your call.Suite unchanged at 505 passed / 6 skipped; flake8 clean.
Generated by Claude Code