You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
With several Poetry envs for one project (poetry env use on two Python minors), agent mode patches the alphabetically first env instead of the one Poetry activated, and VEX attests not_affected #526
[agent] Found by the scheduled Poetry bug-hunt routine (ledger #311).
Summary
Poetry keeps one out-of-tree virtualenv per Python minor you've used with a project (<name>-<hash>-py3.11, <name>-<hash>-py3.12, …). It runs and installs into the activated one, which is recorded in <virtualenvs.path>/envs.toml by poetry env use ([<name>-<hash>] minor = "3.12").
Since #330 (5678b76), poetry_virtualenv_site_packages returns every matching -py* env, sorted by directory name (crates/socket-patch-core/src/crawlers/python_crawler.rs:881, venvs.sort()). It never reads envs.toml. Agent mode then patches only one copy: the first in lexicographic order. When that isn't the activated env, the results are:
scan --mode agent reports added (exit 0) and patches the inactive env. The env that poetry run / poetry shell use stays unpatched.
A follow-up apply reports already_patched and does nothing.
vex attests not_affected / inline_mitigations_already_exist for the project.
Because the sort is lexicographic, the pick isn't even "lowest version": py3.10 sorts before py3.13, and py3.10 would sort before py3.9.
Impact
This is a common setup: anyone who has moved a project to a newer Python with poetry env use 3.12 keeps the old env around. Patches land in a dead env, and the VEX document says the live one is fixed. The run looks fully successful, with nothing printed to stderr.
Repro (real Poetry, Linux, main 61cfb9b)
Any agent patch for six@1.16.0 works. I used a local mock of the patch API (batch + view, the same shapes as crates/socket-patch-cli/tests/in_process_pypi_multi_release.rs).
Expected: the patch goes to the env Poetry uses for the project, or to every env that holds the package. Fix Poetry venv discovery to match Poetry (#327, #329) #330's stated goal is venv discovery that matches Poetry. For that, the activated env (envs.toml's minor, else the env matching the interpreter Poetry would pick) has to come first. vex should only attest copies that are actually patched.
Actual: the alphabetically first <name>-<hash>-py* env is patched. The activated env keeps upstream bytes, apply calls it already_patched, and vex attests not_affected.
OS × version matrix (Linux, main 61cfb9b)
There were 9 independent fresh-project runs. The first row ran twice. Every interpreter here is a real separate CPython (Ubuntu 3.10, 3.11, 3.12 and 3.13), with Poetry pip-installed into its own venv.
Poetry
envs (first created → activated)
virtualenvs.path
Patched env
Activated env patched?
VEX
2.5.1
3.11 → 3.12
custom (POETRY_VIRTUALENVS_PATH)
py3.11
no
not_affected ✗
2.5.1
3.11 → 3.12
default cache dir, package-mode = false
py3.11
no
not_affected ✗
2.5.1
3.11 → 3.12
default cache dir, package mode
py3.11
no
not_affected ✗
2.5.1
3.10 → 3.13
custom
py3.10
no
not_affected ✗
1.8.5
3.11 → 3.12
custom
py3.11
no
not_affected ✗
2.5.1
3.12 → 3.11
custom
py3.11
yes (by luck)
ok
2.5.1
3.13 → 3.10
custom
py3.10
yes (by luck)
ok
1.8.5
3.12 → 3.11
custom
py3.11
yes (by luck)
ok
macOS and Windows aren't tested (this routine's probe branches are blocked), but the selection logic is platform-independent.
First bad version
This isn't a regression in a release. v4.0.0 and v3.3.0 don't discover these out-of-tree envs at all in this layout: package_not_installed, exit 0 (the #327 family). The wrong-env pick arrived with #330 (5678b76), which is unreleased.
Suspect code
crates/socket-patch-core/src/crawlers/python_crawler.rs:881: venvs.sort() orders the per-minor envs by name. Poetry's EnvManager.get() reads envs.toml (minor) for the active env, and falls back to the current interpreter's minor.
[agent] Found by the scheduled Poetry bug-hunt routine (ledger #311).
Summary
Poetry keeps one out-of-tree virtualenv per Python minor you've used with a project (
<name>-<hash>-py3.11,<name>-<hash>-py3.12, …). It runs and installs into the activated one, which is recorded in<virtualenvs.path>/envs.tomlbypoetry env use([<name>-<hash>] minor = "3.12").Since #330 (
5678b76),poetry_virtualenv_site_packagesreturns every matching-py*env, sorted by directory name (crates/socket-patch-core/src/crawlers/python_crawler.rs:881,venvs.sort()). It never readsenvs.toml. Agent mode then patches only one copy: the first in lexicographic order. When that isn't the activated env, the results are:scan --mode agentreportsadded(exit 0) and patches the inactive env. The env thatpoetry run/poetry shelluse stays unpatched.applyreportsalready_patchedand does nothing.vexattestsnot_affected/inline_mitigations_already_existfor the project.Because the sort is lexicographic, the pick isn't even "lowest version":
py3.10sorts beforepy3.13, andpy3.10would sort beforepy3.9.Impact
This is a common setup: anyone who has moved a project to a newer Python with
poetry env use 3.12keeps the old env around. Patches land in a dead env, and the VEX document says the live one is fixed. The run looks fully successful, with nothing printed to stderr.Repro (real Poetry, Linux, main
61cfb9b)Any agent patch for
six@1.16.0works. I used a local mock of the patch API (batch+view, the same shapes ascrates/socket-patch-cli/tests/in_process_pypi_multi_release.rs).Expected vs actual
envs.toml'sminor, else the env matching the interpreter Poetry would pick) has to come first.vexshould only attest copies that are actually patched.<name>-<hash>-py*env is patched. The activated env keeps upstream bytes,applycalls italready_patched, andvexattestsnot_affected.OS × version matrix (Linux, main
61cfb9b)There were 9 independent fresh-project runs. The first row ran twice. Every interpreter here is a real separate CPython (Ubuntu 3.10, 3.11, 3.12 and 3.13), with Poetry pip-installed into its own venv.
virtualenvs.pathPOETRY_VIRTUALENVS_PATH)package-mode = falsemacOS and Windows aren't tested (this routine's probe branches are blocked), but the selection logic is platform-independent.
First bad version
This isn't a regression in a release. v4.0.0 and v3.3.0 don't discover these out-of-tree envs at all in this layout:
package_not_installed, exit 0 (the #327 family). The wrong-env pick arrived with #330 (5678b76), which is unreleased.Suspect code
crates/socket-patch-core/src/crawlers/python_crawler.rs:881:venvs.sort()orders the per-minor envs by name. Poetry'sEnvManager.get()readsenvs.toml(minor) for the active env, and falls back to the current interpreter's minor.crates/socket-patch-cli/src/commands/vex.rs:556:collapse_to_first. Agent-mode npmvexhashes only the first installed copy of a package, so it attests not_affected while another nested copy of the same name@version is unpatched #516 / PR Fix agent vex checking only one installed copy (#516) #517 cover the "VEX checks only the first copy" half for npm. That alone wouldn't fix this, becauseapplyhere also leaves the activated copy alone and reportsalready_patched.