Skip to content

Scan of a fresh Poetry checkout (no Poetry env yet, default virtualenvs.create) crawls the system Python: vendored exits 1 on system-only packages and agent mode patches dpkg-owned files (the Poetry side of #947 / #964) #1023

Description

[agent] Found by the scheduled Poetry bug-hunt routine (ledger #311).

Summary

This is the Poetry counterpart of #947 (Pipenv, fixed by #950) and #964 (uv, open PR #965). Neither fix covers Poetry. #950 guards only is_pipenv_project, and #965's new uv_owns_project_env returns false for any [tool.poetry] / poetry.lock project through claimed_by_non_uv_manager.

Take a Poetry project checked out fresh: it has pyproject.toml and poetry.lock, but poetry install hasn't run, so there's no in-project .venv and no out-of-tree env under virtualenvs.path. PythonCrawler::get_site_packages_paths finds no env. is_python_project(cwd) is true, so the crawl falls back to get_global_python_site_packages(), and every package in the OS Python joins the candidate set (scannedPackages: 86 for a 1-package lock). With the default virtualenvs.create = true, Poetry never installs a project into that interpreter. The env Poetry will create is the only one the project can have.

  • Vendored tries to vendor the system-only packages into poetry.lock and fails with pypi_poetry_lock_package_missing ("poetry.lock has no [[package]] entry for six; run poetry lock first"), partial_failure, exit 1. The remedy doesn't help, because six isn't a project dependency.
  • Agent patches the system copy in place, for example the dpkg-owned /usr/lib/python3/dist-packages/six.py, and exits 0. The project hasn't installed anything yet.
  • Hosted lists the system package as a project package and warns No poetry.lock entry for six@1.16.0, exit 0.

Impact

  • CI breakage in the documented vendored flow. A fresh checkout is exactly where vendored mode runs. Debian/Ubuntu images and GitHub ubuntu-* runners ship a system Python with six, PyYAML, requests, urllib3, idna and more. Whenever Socket has a patch for any of them, every vendored scan of every Poetry project on that machine exits 1, including projects whose own dependencies have no patches.
  • Agent mode writes outside the project, into the OS package manager's files. The project's later poetry install then gets the unpatched release, while the manifest records the patch as applied.
  • System copies mask lock entries: lockfileOnlyPackages drops, and patch counts and the rollout budget include packages that aren't part of the project.

Repro (Linux, Debian/Ubuntu-style system Python with python3-six in /usr/lib/python3/dist-packages; a local mock patch API offers free patches for six@1.16.0 and typing-extensions@4.7.1)

mkdir app && cd app
cat > pyproject.toml <<'EOF'
[project]
name = "demo-fresh"
version = "0.1.0"
requires-python = ">=3.9"
dependencies = ["typing_extensions==4.7.1"]

[build-system]
requires = ["poetry-core>=2.0"]
build-backend = "poetry.core.masonry.api"
EOF
poetry lock                                   # Poetry 2.5.1; older Poetry creates the env here:
rm -rf "$(poetry config virtualenvs.path)"/demo-fresh-*   # simulate the lock-only checkout
env -u VIRTUAL_ENV socket-patch scan --mode vendored --ecosystems pypi --yes --json \
  --api-url $MOCK --api-token x --org test-org --patch-server-url $MOCK > out.json; echo "exit=$?"
# exit=1, status partial_failure, scannedPackages 86, lockfileOnlyPackages 1
# vendor.events: six failed pypi_poetry_lock_package_missing; typing-extensions vendored fine

env -u VIRTUAL_ENV socket-patch scan --mode agent --ecosystems pypi --yes ...   # exit 0
tail -c 18 /usr/lib/python3/dist-packages/six.py   # the patched bytes: the system copy was modified

Control: run poetry install --no-root first. The same vendored scan then crawls only the Poetry env (scannedPackages: 2, lockfileOnlyPackages: 0) and exits 0 with success.

Expected vs actual

  • Expected: CLI_CONTRACT.md, "cwd-only (single project)", says the pypi crawler inspects the project rooted at --cwd (its manager's env, $VIRTUAL_ENV, .venv / venv). Global packages are the -g / --global-prefix surface. On a fresh checkout, lock-only packages already come from poetry.lock (lockfileOnlyPackages). With virtualenvs.create true (the default), the empty Poetry-env result should be final, just as Fix Pipenv project falling back to system Python (#504, #947) #950 made it for Pipenv. Vendored should vendor typing-extensions and exit 0. Agent should report it as not installed and touch nothing outside the project.
  • Actual: system-Python packages join the candidate set. Vendored exits 1 with a misleading poetry lock remedy, and agent mode modifies the system interpreter's files.

virtualenvs.create = false is the one Poetry case where the current interpreter really is the project's env, so the fallback is legitimate there (verified: 86 scanned, as intended).

Cells (main db83f01, Linux x86_64, system Python 3.11 + Debian python3-six; each wet cell run twice)

Poetry Layout Vendored Agent After poetry install (control)
2.5.1 PEP 621 [project], default out-of-tree env path, no env ❌ exit 1, pypi_poetry_lock_package_missing (six), 86 scanned ❌ patches /usr/lib/python3/dist-packages/six.py, exit 0 ✅ exit 0, 2 scanned
2.2.1 [tool.poetry], no env ❌ exit 1 (same) not run —
2.2.1 poetry.toml in-project = true, no .venv ❌ exit 1 (same) not run —
1.8.5 [tool.poetry], no env ❌ exit 1 (same) not run —
2.2.1 poetry.toml create = false ✅ fallback intended (86 scanned) — —

Release 4.0.0 behaves the same (exit 1, partial_failure), so this isn't a recent regression. The fallback predates vendored Poetry support. macOS and Windows weren't probed (probe branches are blocked for this routine), but get_global_python_site_packages also scans Homebrew, python.org and conda roots, so the same fallback applies there.

Suspect code

  • crates/socket-patch-core/src/crawlers/python_crawler.rs:3052-3058: after Fix Pipenv project falling back to system Python (#504, #947) #950, only is_pipenv_project short-circuits. is_python_project then sends a Poetry project to get_global_python_site_packages().
  • crates/socket-patch-core/src/crawlers/python_crawler.rs:367-373: poetry_project_site_packages returning empty falls through to the generic .venv / venv probe and then to the global fallback. Poetry's config (virtualenvs.create) already says whether the system interpreter can be the env.
  • PR Fix uv project with no env falling back to system Python (#964) #965 (claimed_by_non_uv_manager / uv_owns_project_env) leaves Poetry projects on the fallback path on purpose. A Poetry guard can reuse the same shape: when load_poetry_project succeeds and virtualenvs.create resolves true, an empty result is final.

Related: #947 / #950 (Pipenv), #964 / #965 (uv), #504 (agent-mode system writes, Pipenv), #476 / #527 (Poetry in-project = true with an existing out-of-tree env), #671 (create = false + stray venv).

Activity

  1. added a commit that references this issue on Oct 7, 2026
  2. mikolalysenko commented on Oct 7, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Triage: priority:p1 (Poetry). Shares root cause with #964 (open PR #965): PythonCrawler::get_site_packages_paths falls back to the global site-packages when the project's package manager owns an env that does not exist yet. #965 only covers uv (uv_owns_project_env returns false for Poetry projects), so the Poetry case needs the same "empty manager-env result is final" rule (except virtualenvs.create = false). Leaving this open alongside #965 rather than claiming it separately.


    Generated by Claude Code

  3. mikolalysenko commented on Oct 9, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Claiming this issue (with #671, #866; shared root cause: Poetry env discovery does not mirror EnvManager.get as one final answer, so an empty or per-placement Poetry result falls through to stray ./.venv / ./venv probes, the active shell env, or the global site-packages). Branch: agent/fix-poetry-env-final-resolution. Claim-ID: 2026-10-09T10:20:53Z-e18342


    Generated by Claude Code

  4. mikolalysenko commented on Oct 9, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Draft PR: #1259


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions