-
Notifications
You must be signed in to change notification settings - Fork 88
Add vulnerabilities to the PyPI JSON API #1357
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Added a `vulnerabilities` field to the PyPI JSON API, populated from OSV scan reports. Remotes can opt in to scan the new repository version after sync. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| from django.db import migrations, models | ||
|
|
||
|
|
||
| class Migration(migrations.Migration): | ||
|
|
||
| dependencies = [ | ||
| ("python", "0024_pythonrepository_error_on_reject"), | ||
| ] | ||
|
|
||
| operations = [ | ||
| migrations.AddField( | ||
| model_name="pythonremote", | ||
| name="vulnerabilities", | ||
| field=models.BooleanField(default=False), | ||
| ), | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| from packaging.version import InvalidVersion, Version | ||
|
|
||
|
|
||
| def _osv_fixed_in(vuln): | ||
| """Extract PEP 440 fixed versions from an OSV vulnerability record.""" | ||
| fixed = [] | ||
| seen = set() | ||
| for affected in vuln.get("affected") or []: | ||
| for range_ in affected.get("ranges") or []: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- target file ---'
cat -n pulp_python/app/osv.py | sed -n '1,180p'
printf '%s\n' '--- bound symbols and callers ---'
rg -n -A12 -B8 'def _osv_fixed_in|_osv_fixed_in|Version\(' pulp_python tests 2>/dev/null | head -n 260
printf '%s\n' '--- OSV range handling ---'
rg -n -A10 -B6 'ranges|fixed_in|range_' pulp_python tests 2>/dev/null | head -n 260Repository: pulp/pulp_python Length of output: 17457 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from packaging.version import Version
value = "1" * 40
print(value)
print(Version(value))
PYRepository: pulp/pulp_python Length of output: 276 🌐 Web query:
💡 Result: A 40-character hexadecimal string—commonly representing a Git commit hash—is not a valid PEP 440 version string and will cause Citations:
🌐 Web query:
💡 Result: The version string "1111111111111111111111111111111111111111" is not a valid version according to the packaging.version.Version class [1][2]. The packaging.version.Version class validates version strings against the PEP 440 specification [1][3]. A valid PEP 440 version must generally follow a structure of release segments separated by dots (e.g., "1.0", "2026.8.31"), optionally followed by pre-release, post-release, or development release identifiers [1]. Because "1111111111111111111111111111111111111111" consists only of a single, very long integer without any version separators (dots), it does not conform to the expected format and will raise an InvalidVersion exception when passed to the Version constructor [1][2]. Citations:
🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- packaging dependency declarations ---'
rg -n -i -A3 -B3 '(^|[\[" ])packaging([<>=!~]|[" ,]|$)' pyproject.toml setup.cfg setup.py requirements*.txt poetry.lock uv.lock tox.ini 2>/dev/null || true
printf '%s\n' '--- repository tests and OSV fixtures ---'
cat -n pulp_python/tests/unit/test_vulnerabilities.py | sed -n '1,110p'Repository: pulp/pulp_python Length of output: 3416 🌐 Web query:
💡 Result: Under PEP 440, the release segment is defined as N(.N), where N represents a non-negative integer [1][2]. The release segment consists of one or more non-negative integer values separated by dots [1][3]. While the notation N(.N) implies an arbitrary number of segments (or "dots" followed by integers), each individual component N must be a valid, non-negative integer [1]. There is no restriction on the number of digits an individual integer component may have, provided it remains a non-negative integer [1][4]. For example, 1, 1.2, 1.2.3, and 1.1000000000.5 are all valid release segments because each component is a non-negative integer [1][4]. Leading zeros are generally normalized away during parsing (e.g., 1.01 is treated as 1.1) [4]. In summary, the release segment is not a single integer, but a sequence of one or more non-negative integers separated by dots, where each integer can have an arbitrary number of digits [1][2]. Citations:
Ignore
🤖 Prompt for AI Agents |
||
| for event in range_.get("events") or []: | ||
| if "fixed" not in event: | ||
| continue | ||
| version = event["fixed"] | ||
| if version in seen: | ||
| continue | ||
| try: | ||
| Version(version) | ||
| except InvalidVersion: | ||
| continue | ||
| seen.add(version) | ||
| fixed.append(version) | ||
| return fixed | ||
|
|
||
|
|
||
| def osv_to_pypi_vulnerabilities(vulns): | ||
| """Trim OSV vulnerability records to the Warehouse JSON API shape.""" | ||
| seen = {} | ||
| for vuln in vulns or []: | ||
| vuln_id = vuln.get("id") | ||
| if not vuln_id or vuln_id in seen: | ||
| continue | ||
| seen[vuln_id] = { | ||
| "id": vuln_id, | ||
| "source": "osv", | ||
| "link": f"https://osv.dev/vulnerability/{vuln_id}", | ||
| "aliases": vuln.get("aliases") or [], | ||
| "details": vuln.get("details"), | ||
| "summary": vuln.get("summary"), | ||
| "fixed_in": _osv_fixed_in(vuln), | ||
| "withdrawn": vuln.get("withdrawn"), | ||
| } | ||
| return list(seen.values()) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Fix the markdown code-block style violation.
markdownlint reports MD046 for this fenced block. Use the configured indented block style, or update the documented lint configuration if fenced blocks are intended.
🧰 Tools
🪛 markdownlint-cli2 (0.23.2)
[warning] 159-159: Code block style
Expected: indented; Actual: fenced
(MD046, code-block-style)
🤖 Prompt for AI Agents
Source: Linters/SAST tools