Skip to content

fix(diff): detect upgrades when purls embed the version#42

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

fix(diff): detect upgrades when purls embed the version#42
dmchaledev wants to merge 1 commit into
mainfrom
claude/magical-ptolemy-00uicb

Conversation

@dmchaledev

Copy link
Copy Markdown
Contributor

Problem

Detecting upgraded dependencies is the tool's marquee feature (report.upgraded, isMajorBump), but it never fires for real-world SBOMs.

Component identity is keyed on the raw purl in buildComponentMap. Real CycloneDX/SPDX SBOMs embed the version in the purl (e.g. pkg:npm/lodash@4.17.21), so a version bump yields two distinct keys — the old version becomes a "removed" component and the new one an "added" component, and the upgraded bucket stays empty.

Before this change, a routine lodash 4.17.20 → 4.17.21 bump reported:

Added:    1
Removed:  1
Upgraded: 0

Upgrades were only detected for components with no purl (matched by name) — the uncommon case. The existing detects version upgrades test even codified the add/remove behavior as "correct."

Fix

Key components by a version-independent identity: the purl with the @version segment stripped (pkg:npm/lodash), falling back to name:<name> when no purl is present.

stripPurlVersion drops qualifiers (?…) and subpath (#…) first, then removes the segment after the first literal @ following the type/name. An @ inside an npm scope is percent-encoded as %40, so a literal @ unambiguously begins the version.

After the fix the same bump reports:

Added:    0
Removed:  0
Upgraded: 1
  ~ lodash: 4.17.20 → 4.17.21

Tests

  • New regression tests: version bump with versioned purls, scoped-package (%40angular/core) upgrade including major-bump detection, and two distinct packages that must not be collapsed into an upgrade.
  • Updated the test that had asserted the old add/remove behavior.

All 31 tests pass; lint and typecheck clean. No public API or type changes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01G3ef36saEoGYf6ZhTiDDYc


Generated by Claude Code

Component identity was keyed on the raw purl, but real CycloneDX/SPDX
SBOMs embed the version in the purl (e.g. "pkg:npm/lodash@4.17.21").
A version bump therefore produced two distinct keys, so it was reported
as one added + one removed component and the "upgraded" bucket (and its
isMajorBump logic) stayed empty for virtually every real SBOM.

Key components by a version-independent identity: the purl with the
"@Version" segment stripped (qualifiers/subpath removed first, and only a
literal "@" — not a "%40"-encoded npm scope — treated as the delimiter),
falling back to name when no purl is present. Add regression tests for
plain, scoped, and distinct-package cases; update the test that had
codified the old add/remove behavior as expected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G3ef36saEoGYf6ZhTiDDYc
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