Skip to content

fix(diff): detect version upgrades when purls include the version#44

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

fix(diff): detect version upgrades when purls include the version#44
dmchaledev wants to merge 1 commit into
mainfrom
claude/magical-ptolemy-6u39ez

Conversation

@dmchaledev

Copy link
Copy Markdown
Contributor

Problem

Detecting version upgrades is the tool's flagship feature, but it is broken for real-world SBOMs.

buildComponentMap keyed components on the full purl (comp.purl ?? comp.name). Every mainstream SBOM generator — syft, cdxgen, trivy — embeds the version in the purl, e.g. pkg:npm/lodash@4.17.21. So when a package is upgraded, its old and new entries get two different keys, and the diff reports a spurious removed + added pair instead of an upgrade. In practice the upgraded list is almost always empty for real SBOMs.

The old test acknowledged and rationalized this ("different purls are different packages"), but for a dependency-diffing tool that is exactly the case that must be caught.

Before this fix

A routine lodash 4.17.20 → 4.17.21, react 17 → 18 bump reported:

Added: 2   Removed: 2   Upgraded: 0

After

Summary:
  Added:       0
  Removed:     0
  Upgraded:    2
↑ Upgraded Components:
  ~ lodash: 4.17.20 → 4.17.21
  ~ react: 17.0.2 → 18.2.0 [MAJOR]

Change

  • Key components on a version-independent purl coordinate — the purl with its @version segment stripped, bounded by any ?qualifiers / #subpath suffix. The same package now matches across SBOMs, so genuine version changes flow through the existing upgrade path (including isMajorBump).
  • Correctly handles scoped npm namespaces (pkg:npm/%40angular/core@16.0.0 — the scope's @ is %40-encoded, so only the version @ is unescaped) and purl qualifiers.
  • Falls back to name when no purl is present (unchanged behavior).

Tests

  • Replaced the test that asserted the buggy add/remove behavior with one asserting a single detected upgrade.
  • Added coverage for scoped namespaces and purl qualifiers, including major-bump detection.
  • Full suite passes (30 tests), typecheck and lint clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TbSanSfxx5hSGA6prTYxfs


Generated by Claude Code

Real-world SBOM generators (syft, cdxgen, trivy) embed the version in
the purl, e.g. "pkg:npm/lodash@4.17.21". buildComponentMap keyed
components on the full purl, so an upgraded package received two
different keys and was reported as a spurious removed + added pair
instead of an upgrade — leaving the `upgraded` list effectively always
empty for real SBOMs, which defeats the tool's core purpose.

Key components on a version-independent purl coordinate (purl with the
`@version` segment stripped, bounded by any ?qualifiers/#subpath), so
the same package matches across SBOMs and genuine version changes are
detected. Handles scoped npm namespaces (%40) and purl qualifiers.

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