Skip to content

fix(deps): bump pygments lower bound to >=2.20.0 for CVE-2026-4539 [PYSDK-106]#594

Merged
helmut-hoffer-von-ankershoffen merged 2 commits intomainfrom
fix/PYSDK-106-audit-pygments-cve-2026-4539
Apr 25, 2026
Merged

fix(deps): bump pygments lower bound to >=2.20.0 for CVE-2026-4539 [PYSDK-106]#594
helmut-hoffer-von-ankershoffen merged 2 commits intomainfrom
fix/PYSDK-106-audit-pygments-cve-2026-4539

Conversation

@helmut-hoffer-von-ankershoffen
Copy link
Copy Markdown
Contributor

@helmut-hoffer-von-ankershoffen helmut-hoffer-von-ankershoffen commented Apr 25, 2026

🛡️ Resolves PYSDK-106 following PR-SOP-01 Problem Resolution and Non-Conforming Products, part of our ISO 13485-certified QMS | Ketryx Project.

Summary

Re-adds the pygments>=2.20.0 lower bound to [project].dependencies transitive overrides in pyproject.toml. The bound was deliberately removed in PYSDK-104 (#592) to give the daily audit-vulnerabilities routine a real downstream gap to detect and remediate; this PR closes that gap.

CVE addressed

  • CVE-2026-4539pygments ReDoS in regex-based lexers, fixed in 2.20.0. Severity: Medium (CVSS 5.3).
  • Reaches every consumer of the published package (transitive via rich).

Why this matters for downstream consumers

pip-audit scans uv.lock (our dev/CI scope). Downstream consumers (uvx aignostics, pip install aignostics, uv add aignostics) resolve against the [project] metadata we publish to PyPI — they never see our uv.lock. Without the lower bound in pyproject.toml, a fresh consumer install could resolve pygments<2.20.0 and pull a vulnerable version even though our own uv.lock is clean.

Diff

 "marshmallow>=3.26.2",              # CVE-2025-68480
+"pygments>=2.20.0",                 # CVE-2026-4539 (>=2.20.0); transitive via rich
 "cryptography>=46.0.7",             # CVE-2026-39892 (>=46.0.7); transitive via pyjwt[crypto]

uv.lock regenerated — no version changes (pygments stays at 2.20.0, which already satisfies the new bound).

Validation

  • make audit ✅ — exits 0, no new findings; existing --ignore-vuln CVE-2026-3219 (pip 26.0, no fix released) re-verified still firing.
  • make lint ✅ — ruff format + check + pyright + mypy all green.
  • make test_unit ✅ — 2 passed, 788 deselected (no behavioural change; this is metadata-only).
  • All 49 prior pyproject.toml lower bounds re-verified against their advisories (locked ≥ bound).

Routine context

This PR was opened by the pysdk-audit-daily cloud routine via the qms:audit-vulnerabilities skill. The routine is configured to auto-merge for all severities once CI is green — for supply-chain CVEs, higher severity = higher urgency to ship. Human review happens on the linked Jira ticket post-merge if needed.

Test plan

  • make audit passes with re-added bound
  • make lint passes
  • make test_unit passes
  • uv.lock shows no version changes
  • Locked pygments version (2.20.0) satisfies new bound (>=2.20.0)

🤖 Generated with Claude Code

…eview [PYSDK-105]

Adds a machine-readable verdict from the automated Claude PR review so
branch-protection rules can gate `auto-merge` on the review outcome
without human intervention.

Changes:
* `.github/labels.yml`: two new mutually-exclusive labels
  - `claude:review:passed` (green) — no blocking findings on current head
  - `claude:review:failed` (red)   — blocking findings on current head
* `.github/workflows/claude-code-automation-pr-review.yml`: extend prompt
  with a mandatory "Machine-Readable Verdict" final step. Claude must
  emit PASS or FAIL based on the existing CRITICAL CHECKS criteria
  (test markers, coverage ≥85%, lint clean, conventional commits,
  architecture/security) and apply the corresponding label via
  `gh pr edit --add-label ... --remove-label ...`. The opposite label
  is always removed, so the labels stay mutually exclusive across
  re-reviews on subsequent pushes.

Re-emission: every push to a PR re-runs the review (existing
`synchronize` trigger), so the verdict is always tied to the current
head commit — stale verdicts cannot persist.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…YSDK-106]

Re-adds the `pygments>=2.20.0` lower bound to `[project].dependencies`
transitive overrides in pyproject.toml. The bound was deliberately
removed in PYSDK-104 (PR #592) to give the daily audit-vulnerabilities
routine a real gap to remediate; this PR closes that gap.

The locked version in uv.lock (pygments 2.20.0) already protects our
dev/CI env from CVE-2026-4539 (Pygments AdlLexer ReDoS, CVSS 4.8 Medium).
This PR closes the remaining downstream-consumer gap so a fresh
`pip install aignostics` / `uv add aignostics` / `uvx aignostics` cannot
resolve `pygments<2.20.0` transitively via rich.

The new lower bound (>=2.20.0) is <= the currently-locked version
(2.20.0), so no dependency is upgraded — uv.lock diff is metadata-only
(adds the new specifier and the dependency edge); no [[package]]
version block changed.

Resolves PYSDK-106.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@helmut-hoffer-von-ankershoffen helmut-hoffer-von-ankershoffen added dependencies Pull requests that update a dependency file python Pull requests that update python code skip:test:long_running Skip long-running tests (≥5min) sop:pr-sop-01 PR-SOP-01 Problem Resolution (bug / anomaly fix) type:fix Bug fix (conventional fix) security Addresses a security advisory, CVE, or hardens security posture security:supply-chain Supply-chain (dependency) vulnerability remediation scope:sdk-consumers Affects downstream SDK consumers (uvx aignostics / uv add aignostics) auto-merge Eligible for auto-merge once CI is green labels Apr 25, 2026
Copilot AI review requested due to automatic review settings April 25, 2026 09:28
@helmut-hoffer-von-ankershoffen helmut-hoffer-von-ankershoffen requested a review from a team as a code owner April 25, 2026 09:28
@helmut-hoffer-von-ankershoffen helmut-hoffer-von-ankershoffen added dependencies Pull requests that update a dependency file python Pull requests that update python code skip:test:long_running Skip long-running tests (≥5min) sop:pr-sop-01 PR-SOP-01 Problem Resolution (bug / anomaly fix) type:fix Bug fix (conventional fix) security Addresses a security advisory, CVE, or hardens security posture security:supply-chain Supply-chain (dependency) vulnerability remediation scope:sdk-consumers Affects downstream SDK consumers (uvx aignostics / uv add aignostics) auto-merge Eligible for auto-merge once CI is green labels Apr 25, 2026
@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Reintroduces a published dependency lower bound to protect downstream SDK consumers from a pygments ReDoS CVE, and updates Claude PR review automation instructions/labels to support machine-readable PASS/FAIL gating.

Changes:

  • Re-adds pygments>=2.20.0 to pyproject.toml transitive override dependencies (CVE-2026-4539).
  • Regenerates uv.lock so pygments appears as a direct requirement with >=2.20.0.
  • Extends the Claude PR review workflow prompt and introduces new claude:review:{passed,failed} labels.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.

File Description
pyproject.toml Restores pygments>=2.20.0 lower bound for downstream consumer safety.
uv.lock Reflects the new direct requirement entry for pygments / >=2.20.0.
.github/workflows/claude-code-automation-pr-review.yml Adds “machine-readable verdict” instructions to the Claude automation prompt.
.github/labels.yml Defines claude:review:passed and claude:review:failed labels referenced by the new prompt.

Comment on lines 214 to +220

Use `gh pr comment` with your Bash tool to leave your comprehensive review as a comment on the PR.

## Machine-Readable Verdict (MANDATORY)

After posting your review comment, you MUST emit a single-label verdict on the PR. This label is consumed by branch-protection rules to gate auto-merge — it is the only deterministic signal of your review outcome.

Comment on lines +230 to +242
**Apply the label** (the two labels are mutually exclusive — always remove the opposite one):

```bash
# PASS:
gh pr edit ${{ github.event.pull_request.number }} \
--add-label "claude:review:passed" \
--remove-label "claude:review:failed"

# FAIL:
gh pr edit ${{ github.event.pull_request.number }} \
--add-label "claude:review:failed" \
--remove-label "claude:review:passed"
```
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 25, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

❌ Your project status has failed because the head coverage (63.80%) is below the target coverage (70.00%). You can increase the head coverage or adjust the target coverage.
see 20 files with indirect coverage changes

@helmut-hoffer-von-ankershoffen helmut-hoffer-von-ankershoffen merged commit 43e91b2 into main Apr 25, 2026
65 of 67 checks passed
@helmut-hoffer-von-ankershoffen helmut-hoffer-von-ankershoffen deleted the fix/PYSDK-106-audit-pygments-cve-2026-4539 branch April 25, 2026 10:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auto-merge Eligible for auto-merge once CI is green dependencies Pull requests that update a dependency file python Pull requests that update python code scope:sdk-consumers Affects downstream SDK consumers (uvx aignostics / uv add aignostics) security:supply-chain Supply-chain (dependency) vulnerability remediation security Addresses a security advisory, CVE, or hardens security posture skip:test:long_running Skip long-running tests (≥5min) sop:pr-sop-01 PR-SOP-01 Problem Resolution (bug / anomaly fix) type:fix Bug fix (conventional fix)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants