Skip to content

fix(registry-check): require corroboration for round-version confusion signal - #9

Merged
lachaib merged 1 commit into
mainfrom
fix/round-version-confusion-false-positive
Aug 17, 2026
Merged

fix(registry-check): require corroboration for round-version confusion signal#9
lachaib merged 1 commit into
mainfrom
fix/round-version-confusion-false-positive

Conversation

@lachaib

@lachaib lachaib commented Aug 17, 2026

Copy link
Copy Markdown
Owner

Fixes #8

Problem

The dependency-confusion heuristic in src/ecosystems/shared/registry-check.ts flagged any "round and high" (major > 9, minor/patch = 0) or "comically high" (major >= 100) version number as a confusion signal, and packageMaxSeverity() escalated that straight to critical on its own — with no requirement that anything else about the package actually looked anomalous (registry change, publisher change, missing source tag, ...).

In practice this fires on ordinary big-round major releases (e.g. a package jumping from 4x.y.z to 50.0.0) even when the registry origin, publisher, and matching source repo tag are all unchanged — a false positive.

This heuristic is shared across all supported ecosystems (npm, PyPI, Packagist, deno/JSR) via one module, so the fix applies uniformly to all of them.

Fix

  • registry-check.ts: split the heuristic's output into a strong signal (private → public registry move — real provenance change, stays critical standalone) and a weak versionShapeSuspicious signal (round/high version number alone).
  • Added reconcileConfusionSignal(registryCheck, repoCheck): promotes the weak signal to potentialConfusion only when corroborated by an actual registry change or a dropped release tag in the source repo (repoCheck.releaseDropped). Wired into core/analyzer.ts once, right after each ecosystem's analyzeChange() returns — so it applies identically to every ecosystem without touching their individual index.ts files.
  • severity.ts: an uncorroborated round-version signal now surfaces at low severity (visible, non-blocking) instead of critical; corroborated it still escalates to critical as before.
  • types.ts: added RegistryCheck.versionShapeSuspicious.
  • report.ts / markdown.ts / annotations.ts / sarif.ts: uncorroborated round-version notes are now shown as an informational note ("unusual version number" / SARIF lockscan/version-shape-note at note level) rather than a "DEPENDENCY CONFUSION" alarm.
  • README.md: documented the corroboration requirement in the "Registry change and dependency confusion" section.

Tests

Added tests/ecosystems/shared/registry-check.test.ts (11 new cases, previously zero direct coverage of this heuristic):

  • round/high version alone, same registry origin → no standalone confusion, visible as low severity
  • same signal + registry change, or + dropped release tag → escalates to critical
  • private → public registry move still stands alone as critical, regardless of version shape
  • ordinary versions produce no finding at all

All 69 existing + new tests pass; tsc --noEmit and biome check are clean.

🤖 Generated with Claude Code

@lachaib
lachaib merged commit b9f11ce into main Aug 17, 2026
1 check passed
@lachaib
lachaib deleted the fix/round-version-confusion-false-positive branch August 17, 2026 12:01
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.

False positive: round major version bump (e.g. x.0.0) treated as standalone critical dependency-confusion signal

1 participant