[agent] Found by the scheduled Poetry bug-hunt routine (ledger #311).
Summary
scan --mode agent finds Poetry's out-of-tree virtualenv by rebuilding Poetry's env name (<name>-<hash>-py<X.Y>) and its in-project decision without running Poetry (find_poetry_virtualenv_site_packages). Three common Poetry configurations don't match Poetry's own choice:
- Nameless non-package-mode project (Poetry ≥ 1.8):
[tool.poetry] package-mode = false with no name. Poetry names the env non-package-mode-<hash>-py3.X. poetry_project_names returns no names, so discovery returns nothing.
[project].name and [tool.poetry].name both set (Poetry 2.x): Poetry uses [project].name (poetry check: "[project.name] and [tool.poetry.name] are both set. The latter will be ignored."). The crawler prefers [tool.poetry].name, so it looks for the wrong prefix.
virtualenvs.in-project = false set explicitly, with a ./.venv dir present (any Poetry): Poetry honours the explicit false and installs into its cache venv. find_local_venv_site_packages stops at ./.venv (step 2) before it ever consults Poetry's config.
In every case the scan falls back to the wrong interpreter (the global site-packages, or the stray .venv), reports the patch skipped / package_not_installed, and exits 0 with "status": "success". The venv Poetry actually uses stays unpatched.
Impact
Agent mode silently doesn't patch a normally installed Poetry project, and a CI job gating on the exit code passes. Case 1 is the documented Poetry ≥ 1.8 way to manage an application's dependencies without packaging it. Case 2 is common in projects migrating to PEP 621 on Poetry 2. Case 3 shows up when a .venv created by another tool is left behind. The docs say "a bare socket-patch scan --mode agent / rollback in a default-configured Poetry checkout works" (docs/testing/poetry-compatibility.md, "Mode notes").
Repro (Linux, Poetry 2.4.3, default config)
mkdir nameless && cd nameless
cat > pyproject.toml <<'EOF'
[tool.poetry]
package-mode = false
[tool.poetry.dependencies]
python = ">=3.8"
six = "1.16.0"
EOF
poetry install # -> ~/.cache/pypoetry/virtualenvs/non-package-mode-XXXXXXXX-py3.12
# patch API with one [email protected] patch (wiremock/local mock, same routes as tests/e2e_vex_build/poetry.rs)
SOCKET_API_URL=http://127.0.0.1:18080 SOCKET_API_TOKEN=fake SOCKET_ORG_SLUG=test-org \
socket-patch scan --mode agent --json --yes; echo "exit=$?"
# -> "status": "success", apply.patches[0] = {"action":"skipped","errorCode":"package_not_installed"}, exit=0
grep -c SOCKET_PATCHED "$(poetry env info -p)"/lib/python3.*/site-packages/six.py # 0
Case 2: same, with [project] name = "pep-name" … dependencies = ["six==1.16.0"] plus [tool.poetry] name = "legacy-name" (Poetry places the env at pep-name-…).
Case 3: a named project, poetry.toml containing [virtualenvs]\nin-project = false, plus python -m venv .venv before poetry install.
Control: the same project with [tool.poetry] name = "probe-named" gets "action": "added" and the venv file is patched.
Expected vs actual
- Expected: the crawler resolves the same env as
poetry env info -p (docs/testing/poetry-compatibility.md: "reproducing Poetry's own placement from POETRY_*, the project's poetry.toml, the user config.toml and the platform default cache dir"). Failing that, it should not report success while Poetry's venv holds the package unpatched.
- Actual: wrong interpreter crawled,
package_not_installed, exit 0.
OS × Poetry matrix
Measured with the probe workflow (a real poetry install, then socket-patch scan --mode agent, then reading the installed six.py):
| Case |
Linux 1.8.5 |
Linux 2.0.1 |
Linux 2.3.3 (local) |
Linux 2.4.3 |
macOS 1.8.5 |
Windows 1.8.5 / 2.0.1 / 2.4.3 |
| named project (control) |
✅ patched |
✅ |
✅ |
✅ |
✅ |
❌ (separate Windows issue) |
| 1. nameless non-package-mode |
❌ |
❌ |
❌ |
❌ |
❌ |
❌ |
2. [project].name + [tool.poetry].name |
n/a (1.8 ignores [project]) |
❌ |
❌ |
❌ |
n/a |
❌ |
3. in-project = false + stray .venv |
❌ |
❌ |
❌ |
❌ |
❌ |
❌ |
First bad version
Never worked. Released 4.0.0 has no Poetry out-of-tree discovery at all (the named control also fails on 4.0.0). Discovery arrived in ff6aaae (#241, unreleased), which has these gaps.
Suspect code
crates/socket-patch-core/src/crawlers/python_crawler.rs:503 poetry_project_names: prefers [tool.poetry].name, and returns no names when neither table has one. poetry-core uses [project].name first, then [tool.poetry].name, then "non-package-mode" when package-mode = false.
crates/socket-patch-core/src/crawlers/python_crawler.rs:287 / :297 find_local_venv_site_packages: ./.venv wins unconditionally. Poetry uses .venv only when virtualenvs.in-project is unset or true, not when it's explicitly false.
Probe runs
[agent] Found by the scheduled Poetry bug-hunt routine (ledger #311).
Summary
scan --mode agentfinds Poetry's out-of-tree virtualenv by rebuilding Poetry's env name (<name>-<hash>-py<X.Y>) and its in-project decision without running Poetry (find_poetry_virtualenv_site_packages). Three common Poetry configurations don't match Poetry's own choice:[tool.poetry] package-mode = falsewith noname. Poetry names the envnon-package-mode-<hash>-py3.X.poetry_project_namesreturns no names, so discovery returns nothing.[project].nameand[tool.poetry].nameboth set (Poetry 2.x): Poetry uses[project].name(poetry check: "[project.name] and [tool.poetry.name] are both set. The latter will be ignored."). The crawler prefers[tool.poetry].name, so it looks for the wrong prefix.virtualenvs.in-project = falseset explicitly, with a./.venvdir present (any Poetry): Poetry honours the explicitfalseand installs into its cache venv.find_local_venv_site_packagesstops at./.venv(step 2) before it ever consults Poetry's config.In every case the scan falls back to the wrong interpreter (the global site-packages, or the stray
.venv), reports the patchskipped/package_not_installed, and exits 0 with"status": "success". The venv Poetry actually uses stays unpatched.Impact
Agent mode silently doesn't patch a normally installed Poetry project, and a CI job gating on the exit code passes. Case 1 is the documented Poetry ≥ 1.8 way to manage an application's dependencies without packaging it. Case 2 is common in projects migrating to PEP 621 on Poetry 2. Case 3 shows up when a
.venvcreated by another tool is left behind. The docs say "a baresocket-patch scan --mode agent/rollbackin a default-configured Poetry checkout works" (docs/testing/poetry-compatibility.md, "Mode notes").Repro (Linux, Poetry 2.4.3, default config)
Case 2: same, with
[project] name = "pep-name" … dependencies = ["six==1.16.0"]plus[tool.poetry] name = "legacy-name"(Poetry places the env atpep-name-…).Case 3: a named project,
poetry.tomlcontaining[virtualenvs]\nin-project = false, pluspython -m venv .venvbeforepoetry install.Control: the same project with
[tool.poetry] name = "probe-named"gets"action": "added"and the venv file is patched.Expected vs actual
poetry env info -p(docs/testing/poetry-compatibility.md: "reproducing Poetry's own placement fromPOETRY_*, the project'spoetry.toml, the userconfig.tomland the platform default cache dir"). Failing that, it should not report success while Poetry's venv holds the package unpatched.package_not_installed, exit 0.OS × Poetry matrix
Measured with the probe workflow (a real
poetry install, thensocket-patch scan --mode agent, then reading the installedsix.py):[project].name+[tool.poetry].name[project])in-project = false+ stray.venvFirst bad version
Never worked. Released 4.0.0 has no Poetry out-of-tree discovery at all (the named control also fails on 4.0.0). Discovery arrived in ff6aaae (#241, unreleased), which has these gaps.
Suspect code
crates/socket-patch-core/src/crawlers/python_crawler.rs:503poetry_project_names: prefers[tool.poetry].name, and returns no names when neither table has one. poetry-core uses[project].namefirst, then[tool.poetry].name, then"non-package-mode"whenpackage-mode = false.crates/socket-patch-core/src/crawlers/python_crawler.rs:287/:297find_local_venv_site_packages:./.venvwins unconditionally. Poetry uses.venvonly whenvirtualenvs.in-projectis unset ortrue, not when it's explicitlyfalse.Probe runs