Skip to content

feat(parser): extract CVSS scores and derive severity from numeric score#18

Open
dmchaledev wants to merge 1 commit into
mainfrom
claude/magical-ptolemy-j0caxu
Open

feat(parser): extract CVSS scores and derive severity from numeric score#18
dmchaledev wants to merge 1 commit into
mainfrom
claude/magical-ptolemy-j0caxu

Conversation

@dmchaledev

Copy link
Copy Markdown
Contributor

Problem

CVEEntry.cvssScore?: number is declared in src/types.ts (types.ts:37) but nothing ever populates itparseCycloneDX discards the numeric score on every CycloneDX rating and only reads the severity string (parser.ts). For a tool whose keywords are supply-chain-security / vulnerability-management, that's two gaps:

  1. The CVSS score — the precise prioritization signal — is silently dropped. Reports and the JSON output never carry it, so consumers can't sort or gate on score.
  2. Score-only ratings report severity: undefined. CycloneDX ratings from common scanners (Grype, Trivy, cdxgen) frequently include a numeric score with no severity string. Today such a CVE renders as [unknown] and would slip straight past any severity threshold / CI gate.

Reproduction (before)

// new.json — a real-world score-only rating
{ "id": "CVE-2024-9999", "affects": [{ "ref": "pkg:npm/foo@1.0.0" }],
  "ratings": [{ "source": { "name": "nvd" }, "score": 9.8 }] }
⚠ New CVEs:
  ! CVE-2024-9999 [unknown] — pkg:npm/foo@1.0.0     ❌ a 9.8 critical shown as "unknown"

Fix

  • Capture the highest numeric CVSS score across a vulnerability's ratings and populate CVEEntry.cvssScore.
  • When a rating omits a usable severity string, derive its qualitative severity from the score using the CVSS v3 rating scale (0 none, <4 low, <7 medium, <9 high, ≥9 critical), so score-only ratings still feed into the most-severe selection.
  • Surface the score in the text report ([critical, CVSS 9.8]) and add a CVSS column to the markdown New CVEs table. JSON output is automatic.

After:

⚠ New CVEs:
  ! CVE-2024-9999 [critical, CVSS 9.8] — pkg:npm/foo@1.0.0     ✅

This builds directly on the highest-severity selection merged in #16 — it extends the same single pass over ratings and keeps that behavior unchanged for the common severity-string case.

Tests

Added three regression tests to src/__tests__/parser.test.ts:

  • highest score selected across multiple ratings (7.5 + 9.89.8, critical)
  • severity derived from a score-only rating (9.8critical)
  • neither score nor valid severity present → both undefined

Verification

  • npm run typecheck, npm run lint, npm run build — all clean
  • npm test32 passed
  • End-to-end CLI smoke-tested (text + markdown) with a score-only rating, shown above.

Purely additive: no API changes, no change to default output beyond the added score, and behavior is identical for ratings that already carry a severity string.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WJ7wakyvGuKdzSXpVBPkSN


Generated by Claude Code

CVEEntry.cvssScore was declared in the type but never populated, and the
parser ignored the numeric `score` on CycloneDX vulnerability ratings
entirely. As a result a rating that carries only a score (common output
from scanners such as Grype and Trivy) reported severity `undefined`,
which silently slips past any severity threshold or CI gate.

- Capture the highest numeric CVSS score across a vulnerability's ratings
  and populate CVEEntry.cvssScore.
- When a rating omits a usable `severity` string, derive its qualitative
  severity from the score using the CVSS v3 rating scale, so score-only
  ratings still contribute to the most-severe selection.
- Surface the score in the text and markdown reports (new CVSS column).
- Add regression tests covering highest-score selection, score-derived
  severity, and the neither-present case.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WJ7wakyvGuKdzSXpVBPkSN
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants