Repository navigation
Fix Poetry 1.3 source-pin guard (#1447) - #1451
Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
Poetry 1.3 writes its lock header without a version, so the guard from #1413 never recognized a 1.3 lock. Hosted and vendored scans then rewired a `source = "pypi"` dependency into a lock that `poetry install` 1.3 can't solve, exited 0, and the advisory said 1.3 installs it. A 1.3 lock is recognized by the versionless header over `lock-version = "2.0"`, which no other Poetry writes. The refusal now covers 1.3 - 2.2 in hosted, vendored and the vendored-to-hosted takeover, and the advisory, docs and CLI contract name the right range. Fixes #1447 Assisted-by: Claude Code:claude-opus-5-5
Only Poetry 1.3 - 1.8 write lock-version 2.0, and every one of them refuses a source-pinned package once the lock sources it from a URL or file. Key the 1.3 case on the lock format alone, so a 1.3 lock whose header was edited away is still refused, and the writer reads the same way the stale-install advisory already reads it. Tighten the tests: a stamped 1.3.0 case, explicit headers in the takeover test, and a sibling-lock filter that drops only its stale warning. Refs #1447 Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit e161737. Configure here.
|
Ready for review (burn-down agent)
Generated by Claude Code |
Final review briefWhat it does. The guard refuses Risk: low. The change only widens a refusal guard by one Poetry minor version. When unsure it refuses: an unstamped 2.0 lock that Poetry 2.3+ would install, or one some other tool wrote, gets refused with remedy text and is never left in a broken install. Look here
Verified
Changes I made: none. Non-blocking nits (fine as follow-ups)
Auto-merge is armed, so approving sends this straight to the merge queue. Generated by Claude Code |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #1447
Summary
Hosted and vendored scans now refuse a
source = "pypi"-pinned Poetry dependency when Poetry 1.3 wrote the lock, the same way they already refuse 1.4 – 2.2 locks. Before this, a 1.3 project got a rewired lock thatpoetry install1.3 can't solve ("version solving failed"). The scan still exited 0, and its advisory said 1.3 installs it.Root cause
source_constraint_breaks_writer(utils/poetry_lock.rs) judged the writer only by the version in the@generated by Poetry X.Ystamp. Poetry 1.3 writes that sentence without a version, sogenerated_by_versionreturnedNoneand the guard never fired. The hosted rewriter, the vendored guard and the vendored → hosted takeover preflight all go through this one function, so a single fix covers all three.Fix
lock_writer_version: it reads the stamped version when there is one. Otherwise it reports 1.3 forlock-version = "2.0", because only 1.3 – 1.8 write that format and 1.4 – 1.8 always stamp their version. This is the same rulepre_1_4_writeralready uses for the stale-install advisories, so the two can no longer disagree about an unstamped 2.0 lock. It also still refuses a 1.3 lock whose header was edited away, which is a case/code-reviewraised.docs/testing/poetry-compatibility.mdandCLI_CONTRACT.mdnow name the corrected range.e2e_vex_buildPoetry matrix. The issue points out that the matrix had no 1.3 leg.Test evidence
utils::poetry_lock::tests::source_constraint_breaks_only_poetry_1_3_to_2_2_writers(1.3.2 fixture, stamped 1.3.0, versionless and unstamped 2.0, CRLF, 1.1/2.1 controls)vendor::pypi_poetry::tests::source_constrained_dependency_is_refused_for_poetry_1_3_to_2_2(vendored, 1.3.2 fixture)patch::redirect::poetry::equivalence_tests::source_constrained_dependency_is_refused_for_poetry_1_3_to_2_2(hosted, 6 pyproject shapes, fresh and already-redirected)patch::redirect::pypi_takeover::tests::poetry_source_pinned_package_follows_the_writer(takeover, 1.3 lock)poetry::poetry_source_pypi_constraint_never_breaks_installon real Poetry 1.3.2The whole
poetry::e2e suite (4 tests) passes on real Poetry 1.3.2 locally:SOCKET_PATCH_POETRY_BIN=… SOCKET_PATCH_POETRY_E2E_REQUIRED=1 SOCKET_PATCH_POETRY_E2E_VERSION=1.3.2 cargo test -p socket-patch-cli --all-features --test e2e_vex_build -- poetry:: --ignoredLocal gate:
cargo fmt --all -- --checkandcargo clippy --workspace --all-features -- -D warningsare clean.cargo test --workspace --all-features --no-fail-fastpasses except 13 tests that fail only because this sandbox runs as root (chmod-0555 / unremovable-file write-failure tests, which root bypasses) or has no network to patches-api (binary_shared_bundled_record_hosted_pin_is_managed). None of them touch the Poetry source-pin path. CI runs them as non-root.Per-issue checklist
source = "pypi"dependency andpoetry install1.3 fails with a solver error #1447: hosted refusal (redirect_poetry_lock_unsupported), vendored refusal (pypi_poetry_source_constraint), takeover keeps the package vendored, and the advisory/docs no longer claim 1.3 installs it. Covered by the four unit tests above and by the real-Poetry 1.3.2 e2e.Review notes
/code-review highalso suggested merging the twopre_1_4_writercopies (redirect/poetry.rs,vendor/pypi_poetry.rs) intolock_writer_version, and not re-parsing the lock to read its format. I left both out of this PR. They are pre-existing duplication, they now agree with the new helper, and the extra parse happens once per lock per run. The wrappers (npm/,pypi/,gem/) only dispatch to the binary, so they need no change.🤖 Generated with Claude Code
https://claude.ai/code/session_01G22ffRqhurh7MjZ7GZA2HM
Generated by Claude Code