Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,12 @@ def _extract_packages_from_requirements(content: str) -> list[tuple[str, str | N
m = re.match(r"^([a-zA-Z][a-zA-Z0-9._-]*)(?:\[.*?\])?\s*(?:([=<>!~]=?)\s*([\d.*]+))?", line)
if m:
name = m.group(1)
version = m.group(3) if m.group(2) else None
# Only "==" / "<=" bound the version to a concrete, CVE-checkable release.
# ">=", ">", "!=", "~=" are floors/ranges, not pins: treating them as an exact
# version makes a floor like "pillow>=10.0.0" report as "pillow==10.0.0" and
# attributes that release's CVEs to an unpinned dependency. Mirrors the guard
# already used by _extract_packages_from_setup_py.
version = m.group(3) if m.group(2) in ("==", "<=") else None

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<= is still a range, not a concrete release: pkg<=8.1.0 can install any earlier version, so keeping 8.1.0 here continues the same false CVE attribution. The regex also accepts wildcard equality such as pkg==1.*, which is not exact either. Please retain only a non-wildcard exact equality (or model ranges explicitly), and update both extractors consistently.

results.append((name, version, i))
return results

Expand Down
20 changes: 20 additions & 0 deletions tests/unit/test_patterns_new.py
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,26 @@ def test_extract_packages_requirements(self) -> None:
assert "numpy" in names
assert "flask" in names

def test_extract_packages_requirements_specifier_is_not_a_pin(self) -> None:
# Only "==" / "<=" resolve to a concrete version; floors and ranges must not be
# reported as pins (regression: ">=" was treated as "==", so "pillow>=10.0.0" was
# scanned as the exact release "10.0.0" and flagged with that version's CVEs).
content = (
"requests==2.31.0\n" # exact pin -> version kept
"pillow>=10.0.0\n" # floor -> version None
"click<=8.1.0\n" # upper cap -> version kept
"urllib3~=1.26.0\n" # compatible -> version None
"jinja2!=3.0.0\n" # exclusion -> version None
"flask\n" # unpinned -> version None
)
versions = {p[0]: p[1] for p in sc_mod._extract_packages_from_requirements(content)}
assert versions["requests"] == "2.31.0"
assert versions["click"] == "8.1.0"
assert versions["pillow"] is None
assert versions["urllib3"] is None
assert versions["jinja2"] is None
assert versions["flask"] is None

def test_extract_packages_package_json(self) -> None:
content = (
'{\n "dependencies": {\n "express": "^4.18.0",\n "lodash": "4.17.21"\n }\n}'
Expand Down