[agent] Found by the scheduled Poetry bug-hunt routine (ledger #311).
Summary
Poetry lets a dependency name the source it must come from: six = {version = "1.16.0", source = "pypi"}. Poetry's docs recommend this to pin a package to PyPI when a project also declares private or supplemental sources. Poetry records nothing extra in poetry.lock for a PyPI package, so socket-patch sees an ordinary PyPI entry. It rewrites it to [package.source] type = "url" (hosted) or type = "file" (vendored), and the scan exits 0 with no warning.
On Poetry 1.4.0 through 2.2.x, the next poetry install then fails: the installer matches the pyproject constraint source = "pypi" against a locked package whose source is now a URL or file. Poetry 1.6–2.2 print Repository "pypi" does not exist. Poetry 1.4 prints Because demo-app depends on six (1.16.0) which doesn't match any versions, version solving failed. Without the rewrite, the same project installs fine on every version, and Poetry 1.1, 1.2 and 2.3+ install the rewritten lock fine.
Impact
After scan --mode hosted or scan --mode vendored, every poetry install / poetry sync (CI, Docker builds, fresh clones) fails on the affected Poetry releases until the user reverts. socket-patch reports success (redirected: 1 / applied, exit 0) and emits no advisory. Nothing is silently left unpatched, because the install hard-fails, but the build breaks. vendor --revert / rollback restore a working install.
Repro (Linux, main e782c9a, local mock of the patch API serving a patched six-1.16.0 wheel)
mkdir demo && cd demo
cat > pyproject.toml <<'EOF'
[tool.poetry]
name = "demo-app"
version = "0.1.0"
description = ""
authors = ["x <x@example.com>"]
[tool.poetry.dependencies]
python = ">=3.8"
six = {version = "1.16.0", source = "pypi"}
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
EOF
export POETRY_VIRTUALENVS_IN_PROJECT=true
poetry lock --no-update # Poetry 1.8.5
poetry install --no-root # baseline: Installing six (1.16.0), exit 0
rm -rf .venv
socket-patch scan --mode vendored --yes # (or --mode hosted) exit 0, poetry.lock rewired, no warning
poetry install --no-root # exit 1: Repository "pypi" does not exist.
socket-patch vendor --revert --yes && poetry install --no-root # works again
It also reproduces with an extra declared source ([[tool.poetry.source]] name = "mirror", priority = "supplemental") beside source = "pypi" on 1.8.5. On 2.5.1 that shape installs fine.
Expected vs actual
- Expected: docs/testing/poetry-compatibility.md says both modes keep the package's dependencies, groups, markers and extras and that "no pyproject edit is required". It lists the lock shapes that are refused before any write (forked packages, a user-authored
[package.source] on another origin, …). A rewrite that makes the next install fail on a supported Poetry release should be refused before writing, like those shapes (or at least warned about, naming the source = "pypi" constraint and the affected Poetry range). CLI_CONTRACT.md's redirect_poetry_lock_unsupported row is the existing hosted refusal channel. The vendored twin would be a pypi_poetry_* refusal.
- Actual: both modes rewrite, report success, and leave a lock that Poetry 1.4–2.2 can't install.
OS × version
Each cell is a fresh project (poetry lock, then scan, then rm -rf .venv && poetry install --no-root). Baseline = the same project without socket-patch.
| OS |
Poetry |
baseline |
hosted |
vendored |
| Linux |
1.1.15 |
pass |
pass (patched) |
pass (patched) |
| Linux |
1.2.2 |
pass |
pass |
pass |
| Linux |
1.4.2 |
pass |
fail ("doesn't match any versions") |
fail |
| Linux |
1.6.1 |
pass |
fail (Repository "pypi" does not exist.) |
fail |
| Linux |
1.7.1 |
pass |
fail |
fail |
| Linux |
1.8.5 |
pass |
fail (×2, also with a supplemental source) |
fail (×2) |
| Linux |
2.0.1 |
pass |
fail |
fail |
| Linux |
2.1.1 |
pass |
fail |
fail |
| Linux |
2.2.1 |
pass |
fail |
fail |
| Linux |
2.3.3 |
pass |
pass |
pass |
| Linux |
2.4.3 |
pass |
pass |
pass |
| Linux |
2.5.1 |
pass |
pass (also with a supplemental source) |
pass |
| macOS / Windows |
— |
not probed (probe branches are blocked for this routine). The failure is in Poetry's platform-independent installer/solver, so it's expected to match. |
|
|
The line endings of the lock don't matter here (the lock has no source data for six either way).
First bad version
Not a regression in socket-patch: the [package.source] rewrite shape has been the design since Poetry support landed (#241). The boundary is on Poetry's side (1.4.0 → 2.2.x).
Suspect code
socket-patch never reads the pyproject dependency's source key. The only source guard looks at the lock's own [package.source]:
crates/socket-patch-core/src/utils/poetry_lock.rs:531 (shared rewriter: refuses only an existing lock source)
crates/socket-patch-core/src/vendor/pypi_poetry.rs:234 (vendored target guard, same)
crates/socket-patch-core/src/patch/redirect/poetry.rs (hosted lane: the generated_by_version / pre_1_4_writer advisories exist, but nothing for this constraint)
The lock's @generated by Poetry X.Y stamp (utils::poetry_lock::generated_by_version) is already available to gate on the affected range, though the installing Poetry may differ from the writer.
No probe runs: probe branches are blocked for this routine (see ledger #311).
[agent] Found by the scheduled Poetry bug-hunt routine (ledger #311).
Summary
Poetry lets a dependency name the source it must come from:
six = {version = "1.16.0", source = "pypi"}. Poetry's docs recommend this to pin a package to PyPI when a project also declares private or supplemental sources. Poetry records nothing extra inpoetry.lockfor a PyPI package, so socket-patch sees an ordinary PyPI entry. It rewrites it to[package.source] type = "url"(hosted) ortype = "file"(vendored), and the scan exits 0 with no warning.On Poetry 1.4.0 through 2.2.x, the next
poetry installthen fails: the installer matches the pyproject constraintsource = "pypi"against a locked package whose source is now a URL or file. Poetry 1.6–2.2 printRepository "pypi" does not exist.Poetry 1.4 printsBecause demo-app depends on six (1.16.0) which doesn't match any versions, version solving failed.Without the rewrite, the same project installs fine on every version, and Poetry 1.1, 1.2 and 2.3+ install the rewritten lock fine.Impact
After
scan --mode hostedorscan --mode vendored, everypoetry install/poetry sync(CI, Docker builds, fresh clones) fails on the affected Poetry releases until the user reverts. socket-patch reports success (redirected: 1/applied, exit 0) and emits no advisory. Nothing is silently left unpatched, because the install hard-fails, but the build breaks.vendor --revert/rollbackrestore a working install.Repro (Linux, main
e782c9a, local mock of the patch API serving a patchedsix-1.16.0wheel)It also reproduces with an extra declared source (
[[tool.poetry.source]] name = "mirror", priority = "supplemental") besidesource = "pypi"on 1.8.5. On 2.5.1 that shape installs fine.Expected vs actual
[package.source]on another origin, …). A rewrite that makes the next install fail on a supported Poetry release should be refused before writing, like those shapes (or at least warned about, naming thesource = "pypi"constraint and the affected Poetry range). CLI_CONTRACT.md'sredirect_poetry_lock_unsupportedrow is the existing hosted refusal channel. The vendored twin would be apypi_poetry_*refusal.OS × version
Each cell is a fresh project (
poetry lock, then scan, thenrm -rf .venv && poetry install --no-root). Baseline = the same project without socket-patch.Repository "pypi" does not exist.)The line endings of the lock don't matter here (the lock has no
sourcedata for six either way).First bad version
Not a regression in socket-patch: the
[package.source]rewrite shape has been the design since Poetry support landed (#241). The boundary is on Poetry's side (1.4.0 → 2.2.x).Suspect code
socket-patch never reads the pyproject dependency's
sourcekey. The only source guard looks at the lock's own[package.source]:crates/socket-patch-core/src/utils/poetry_lock.rs:531(shared rewriter: refuses only an existing locksource)crates/socket-patch-core/src/vendor/pypi_poetry.rs:234(vendored target guard, same)crates/socket-patch-core/src/patch/redirect/poetry.rs(hosted lane: thegenerated_by_version/pre_1_4_writeradvisories exist, but nothing for this constraint)The lock's
@generated by Poetry X.Ystamp (utils::poetry_lock::generated_by_version) is already available to gate on the affected range, though the installing Poetry may differ from the writer.No probe runs: probe branches are blocked for this routine (see ledger #311).