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
{{ message }}
Repository navigation
Poetry 0.x vendored → hosted takeover un-vendors the package before hosted mode refuses the lock, while --dry-run previews a clean takeover (redirected: 1, exit 0) #945
[agent] Found by the scheduled Poetry bug-hunt routine (ledger #311).
Summary
Vendored mode supports Poetry 0.12 locks ([metadata.hashes], no lock-version), but hosted mode refuses every one of them: redirect_poetry_lock_unsupported, "Poetry 0.x ignores URL sources" (docs/testing/poetry-compatibility.md, "Formats and rewrite behavior"). So when you run scan --mode hosted on a project that socket-patch vendored on a 0.12 lock, the takeover can never succeed. It happens anyway:
Wet run: it reverts the vendored wiring first. That restores the lock's registry entry and deletes .socket/vendor/pypi/<uuid>/ and the ledger entry. Only then does the Poetry rewriter refuse the lock. The result is partial_failure, redirected: 0, redirect_takeover_unpatched, exit 1. A project that installed patched six before the command now installs the unpatched release.
--dry-run: reports status: success, redirected: 1, with only redirect_would_revert_vendored, and exits 0. The refusal is never predicted. A plain hosted --dry-run on the same 0.12 lock (never vendored) does report redirect_poetry_lock_unsupported, so the takeover preview simply never consults the rewriter.
The refusal depends only on the lock's format (lock_version_of(lock) == "0"), which is known before anything is written. It's the Poetry counterpart of #723 (uv) and #699 / #708 (requirements.txt).
Impact
Someone who previews with --dry-run, sees a clean takeover, and then runs it loses the patch. The vendored wheel is deleted and the next poetry install gets the vulnerable upstream release. The printed remedy ("re-run scan --mode hosted") can't work on this lock; only scan --mode vendored recovers.
Scope is narrow: only projects still on a Poetry 0.12 lock, which vendored mode supports and documents. Every lock from Poetry 1.0 onward takes over cleanly (control rows below).
Repro (Linux, main 9c43dfc, real Poetry 0.12.17)
I used a local mock of the patch API serving a patched six-1.16.0 wheel (batch, by-package, grant with sha256 + sha512, view, wheel), plus SOCKET_PYPI_JSON_API pointed at a PyPI forwarder.
API="--api-url $MOCK --org o --api-token t --patch-server-url $MOCK"
mkdir demo &&cd demo && mkdir demo && touch demo/__init__.py
cat > pyproject.toml <<'EOF'[tool.poetry]name = "demo"version = "0.1.0"description = ""authors = ["x <x@example.com>"][tool.poetry.dependencies]python = "^3.9"six = "1.16.0"EOF
poetry lock # Poetry 0.12.17: [metadata.hashes]; today's PyPI gives `six = []`.# I filled in the two real sha256s (the historical "populated" shape); the empty shape behaves the same for vendored.
socket-patch scan --mode vendored --yes --ecosystems pypi --json $API# exit 0; [package.source] type = "file" -> .socket/vendor/...
python3 -m venv .venv && VIRTUAL_ENV=$PWD/.venv poetry install # six installed PATCHED
socket-patch scan --mode hosted --dry-run --yes --ecosystems pypi --json $API# exit 0, status success, redirect.redirected 1, warnings [redirect_would_revert_vendored]
socket-patch scan --mode hosted --yes --ecosystems pypi --json $API# exit 1, status partial_failure, redirected 0, warnings# [redirect_poetry_lock_unsupported, redirect_takeover_reverted_vendored, redirect_takeover_unpatched]
grep -c socket/vendor poetry.lock; ls .socket/vendor # 0; gone
rm -rf .venv && python3 -m venv .venv && VIRTUAL_ENV=$PWD/.venv poetry install # six installed UNPATCHED
Expected vs actual
Expected: CLI_CONTRACT.md, "Takeover reconciliation" and the scan --mode hosted takeover notes: a takeover must not half-migrate. Where the hosted rewriter can't reach the package, the purl is refused before its revert, wet and --dry-run alike, and keeps its vendored wiring, ledger entry and wheel. That's what requirements.txt gets (redirect_requirements_takeover_unreachable, "Its wiring, ledger entry and wheel are kept, so it stays vendored and patched (exit 0)"). The dry run should report what the wet run will do (see uv vendored → hosted takeover strands a package that vendored mode pinned to a different version than uv.lock: the wet run reverts to the unpatched release (exit 1), while --dry-run previews a clean takeover #723 and dry_run_predicts_drifted_takeover_refusal). Here, a Poetry 0.x lock should be refused up front with redirect_poetry_lock_unsupported, and the package should stay vendored.
Actual: the wet run reverts and then refuses (exit 1, unpatched). The dry run promises redirected: 1, exit 0.
The contract does list "a refused lock" among the causes of redirect_takeover_unpatched. But this refusal is whole-lock and deterministic, so it's the same class as the requirements.txt case that the contract already gates before the revert.
Matrix (Linux; scan exits: dry run / wet run; then a fresh install)
Poetry (lock)
--dry-run
wet takeover
fresh install after
0.12.17 ([metadata.hashes])
0, redirected: 1
1, redirect_takeover_unpatched (reproduced 3×)
unpatched
0.12.17, never vendored (plain hosted control)
0, redirect_poetry_lock_unsupported
0, same
n/a
1.1.15 (lock 1.1), LF + CRLF
–
0, redirected: 1
patched
1.8.5 (lock 2.0), LF + CRLF
–
0, redirected: 1
patched
2.5.1 (lock 2.1), LF + CRLF
–
0, redirected: 1
patched
The decision is made on lock text, so it doesn't depend on the OS, and I ran no macOS / Windows probe (probe branches are currently blocked for this routine). I didn't bisect. The PyPI takeover exists since #503, and before it the takeover was refused outright (#328).
Suspect code
crates/socket-patch-cli/src/commands/scan/hosted.rs:1839-1843: for pkg:pypi/ the takeover_refusal closure runs only preflight_requirements_takeover. There's no Poetry check for a lock the rewriter will refuse.
crates/socket-patch-cli/src/commands/scan/hosted.rs:1068: confirmed.extend(dry_run_takeover) counts every previewed takeover as redirected.
crates/socket-patch-core/src/utils/poetry_lock.rs:358-359: the lock-version-0 refusal the takeover runs into after reverting.
[agent] Found by the scheduled Poetry bug-hunt routine (ledger #311).
Summary
Vendored mode supports Poetry 0.12 locks (
[metadata.hashes], nolock-version), but hosted mode refuses every one of them:redirect_poetry_lock_unsupported, "Poetry 0.x ignores URL sources" (docs/testing/poetry-compatibility.md, "Formats and rewrite behavior"). So when you runscan --mode hostedon a project that socket-patch vendored on a 0.12 lock, the takeover can never succeed. It happens anyway:.socket/vendor/pypi/<uuid>/and the ledger entry. Only then does the Poetry rewriter refuse the lock. The result ispartial_failure,redirected: 0,redirect_takeover_unpatched, exit 1. A project that installed patchedsixbefore the command now installs the unpatched release.--dry-run: reportsstatus: success,redirected: 1, with onlyredirect_would_revert_vendored, and exits 0. The refusal is never predicted. A plain hosted--dry-runon the same 0.12 lock (never vendored) does reportredirect_poetry_lock_unsupported, so the takeover preview simply never consults the rewriter.The refusal depends only on the lock's format (
lock_version_of(lock) == "0"), which is known before anything is written. It's the Poetry counterpart of #723 (uv) and #699 / #708 (requirements.txt).Impact
--dry-run, sees a clean takeover, and then runs it loses the patch. The vendored wheel is deleted and the nextpoetry installgets the vulnerable upstream release. The printed remedy ("re-runscan --mode hosted") can't work on this lock; onlyscan --mode vendoredrecovers.Repro (Linux, main
9c43dfc, real Poetry 0.12.17)I used a local mock of the patch API serving a patched
six-1.16.0wheel (batch, by-package, grant with sha256 + sha512, view, wheel), plusSOCKET_PYPI_JSON_APIpointed at a PyPI forwarder.Expected vs actual
scan --mode hostedtakeover notes: a takeover must not half-migrate. Where the hosted rewriter can't reach the package, the purl is refused before its revert, wet and--dry-runalike, and keeps its vendored wiring, ledger entry and wheel. That's what requirements.txt gets (redirect_requirements_takeover_unreachable, "Its wiring, ledger entry and wheel are kept, so it stays vendored and patched (exit 0)"). The dry run should report what the wet run will do (see uv vendored → hosted takeover strands a package that vendored mode pinned to a different version than uv.lock: the wet run reverts to the unpatched release (exit 1), while --dry-run previews a clean takeover #723 anddry_run_predicts_drifted_takeover_refusal). Here, a Poetry 0.x lock should be refused up front withredirect_poetry_lock_unsupported, and the package should stay vendored.redirected: 1, exit 0.The contract does list "a refused lock" among the causes of
redirect_takeover_unpatched. But this refusal is whole-lock and deterministic, so it's the same class as the requirements.txt case that the contract already gates before the revert.Matrix (Linux; scan exits: dry run / wet run; then a fresh install)
--dry-run[metadata.hashes])redirected: 1redirect_takeover_unpatched(reproduced 3×)redirect_poetry_lock_unsupportedredirected: 1redirected: 1redirected: 1The decision is made on lock text, so it doesn't depend on the OS, and I ran no macOS / Windows probe (probe branches are currently blocked for this routine). I didn't bisect. The PyPI takeover exists since #503, and before it the takeover was refused outright (#328).
Suspect code
crates/socket-patch-cli/src/commands/scan/hosted.rs:1839-1843: forpkg:pypi/thetakeover_refusalclosure runs onlypreflight_requirements_takeover. There's no Poetry check for a lock the rewriter will refuse.crates/socket-patch-cli/src/commands/scan/hosted.rs:1068:confirmed.extend(dry_run_takeover)counts every previewed takeover as redirected.crates/socket-patch-core/src/utils/poetry_lock.rs:358-359: the lock-version-0 refusal the takeover runs into after reverting.Related: #723 (uv), #699 / PR #708 (requirements.txt), #853 (pnpm, the hosted → vendored direction).