Repository navigation
馃悰 fix(seed): isolate shared cache compilation - #3407
Merged
Merged
Conversation
gaborbernat
force-pushed
the
fix/seed-compile-isolation
branch
from
October 16, 2026 14:22
e19806d to
64ad260
Compare
Reported by Anthropic's OSS Scanner: ANT-2026-9S579FUR.
gaborbernat
force-pushed
the
fix/seed-compile-isolation
branch
from
October 16, 2026 14:25
64ad260 to
e97ae5a
Compare
The test asserted the compileall command line. It now plants a compileall.py in the working directory and a .pth in the destination site-packages, then checks that neither runs while the image still gets its bytecode. Both cases fail with the previous command.
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
app-dataseeder with--symlink-app-databuilds one image of each seed wheel in the app-data cache (the per-user directory where virtualenv keeps wheels and extracted images) and symlinks that image into every environment it creates. Building the image ran the destination interpreter aspython -m compileall <image>with its default startup. That startup puts the working directory first onsys.pathand importssite, which runs the.pthfiles in the destination'ssite-packages. Acompileall.pyin the directory virtualenv was run from replaced the standard library module, and animportline in a.pthfile of an existing destination ran before compilation started. 馃悰 The compile step now runs with-I -S, so neither the working directory nor the destination's site configuration takes part, and the bytecode in the shared image comes from the standard library'scompileallalone.The compile child started with the destination's full startup
SymlinkPipInstall._generate_new_filesranself._creator.exe -m compileall <image>with no interpreter flags. #1480 added the call when the shared image became read-only, so that the.pycfiles exist before an import from a linked environment would try to write them and fail. The-mswitch prepends the working directory tosys.path, soimport compileallfound acompileall.pynext to where virtualenv was invoked before the standard library's. Default startup also importssite, which adds the destination'ssite-packages, executes every line beginning withimportin the.pthfiles there, and then importssitecustomizeandusercustomize. On a re-run over an existing path, or with--system-site-packages, those directories hold whatever was there before.PYTHONPATH,PYTHONHOMEand the otherPYTHON*variables of the calling process applied as well.FromAppData.runkeys the image by installer and wheel and builds it once, and every later environment created from the same cache links to it, so code that ran in the child could change the image beforebuild_imagemade it read-only. A plantedcompileall.pythat exits at once leaves the image with no bytecode, and the build goes on, since the child's exit status and output are discarded.The command now carries
-Iand-S.-Ikeeps the working directory offsys.path, ignores thePYTHON*variables and skips the user site-packages.-Sskips thesiteimport, so no.pthfile,sitecustomizeorusercustomizeruns.sys.pathis then the standard library of the interpreter the destination was created from, which is wherecompileallcomes from. The child is still the destination interpreter, so the bytecode still matches the target Python version. Its exit status and output are still not read, as before. The test plants acompileall.pyin the working directory and a.pthfile in the destination'ssite-packages, each of which would create a marker file, and checks thatpip/__pycache__is populated and no marker exists.sequenceDiagram participant V as virtualenv participant C as destination python participant W as working directory participant S as destination site-packages V->>C: -m compileall image rect rgb(255, 214, 214) C->>W: sys.path[0]: a compileall.py here wins C->>S: import site: .pth import lines run, sitecustomize imported Note over C: PYTHONPATH and the other PYTHON* variables applied end V->>C: -I -S -m compileall image rect rgb(216, 243, 220) Note over C: sys.path is the stdlib only, site never imported C->>C: stdlib compileall writes image/**/__pycache__ endBehavior changes
Symlink seeding compiles its shared image without the destination's
.pthfiles,sitecustomizeandusercustomize, without the user site-packages, without the working directory onsys.pathand withoutPYTHON*environment variables. A.pthfile orsitecustomizethat an existing destination relied on during that step no longer runs there. Startup of the completed environment is unchanged, and so is the copy installer, which has no compile step.Reported by Anthropic's OSS Scanner: ANT-2026-9S579FUR.