Description
pin_pep508_entry in pyproject_preparer.rb does not handle PEP 508 direct references (@ git+https://...). Prior to #14706, it produced an invalid specifier causing Poetry to crash. After #14706 (merged today), it silently drops the @ git+ URL and replaces the dep with ==version from PyPI — changing the resolved package from a private fork to the public one.
Reproduction
pyproject.toml using PEP 621 format with a Poetry backend:
[project]
dependencies = [
"pillow>=12.1.1,<13.0.0",
"ffmpeg-python @ git+https://github.com/example/ffmpeg-python",
]
When dependabot tries to resolve pillow, freeze_pep621_dep_array! iterates all entries and calls pin_pep508_entry on ffmpeg-python. The lock file has version = "0.2.0", so:
Before #14706: output is ffmpeg-python==0.2.0 @ git+https://... — Poetry crashes with The requirement is invalid: Unexpected character at column 22
After #14706: output is ffmpeg-python==0.2.0 — silently replaces the git fork with the PyPI version, which may have different dependencies (in our case, the fork removes an unmaintained transitive dep)
Root cause
The new pin_pep508_entry extracts the name prefix via PEP508_PREFIX, then unconditionally rebuilds the entry as "#{prefix}==#{version}#{marker}", discarding everything between the name and the marker — including @ git+ URLs.
Suggested fix
pin_pep508_entry should detect direct references and return the entry unchanged:
def self.pin_pep508_entry(entry, version)
prefix_match = entry.match(PEP508_PREFIX)
return entry unless prefix_match
prefix = T.must(prefix_match[:prefix])
rest = T.must(entry[prefix.length..])
# Skip direct references — already pinned to a URL
return entry if rest.match?(/\A\s*@\s/)
marker_match = rest.match(/(\s*;.*)/)
marker = marker_match ? marker_match[1] : ""
"#{prefix}==#{version}#{marker}"
end
Environment
- Package manager: pip (Poetry backend with
poetry.lock)
pyproject.toml format: PEP 621 [project].dependencies
- Dependabot Updates workflow (GitHub-hosted, security updates)
Description
pin_pep508_entryinpyproject_preparer.rbdoes not handle PEP 508 direct references (@ git+https://...). Prior to #14706, it produced an invalid specifier causing Poetry to crash. After #14706 (merged today), it silently drops the@ git+URL and replaces the dep with==versionfrom PyPI — changing the resolved package from a private fork to the public one.Reproduction
pyproject.tomlusing PEP 621 format with a Poetry backend:When dependabot tries to resolve
pillow,freeze_pep621_dep_array!iterates all entries and callspin_pep508_entryonffmpeg-python. The lock file hasversion = "0.2.0", so:Before #14706: output is
ffmpeg-python==0.2.0 @ git+https://...— Poetry crashes withThe requirement is invalid: Unexpected character at column 22After #14706: output is
ffmpeg-python==0.2.0— silently replaces the git fork with the PyPI version, which may have different dependencies (in our case, the fork removes an unmaintained transitive dep)Root cause
The new
pin_pep508_entryextracts the name prefix viaPEP508_PREFIX, then unconditionally rebuilds the entry as"#{prefix}==#{version}#{marker}", discarding everything between the name and the marker — including@ git+URLs.Suggested fix
pin_pep508_entryshould detect direct references and return the entry unchanged:Environment
poetry.lock)pyproject.tomlformat: PEP 621[project].dependencies