Skip to content

fix(detectors): union scopes when duplicate nodes fold - #406

Merged
bomly-guy merged 1 commit into
mainfrom
claude/github-issue-400-b7ad68
Aug 26, 2026
Merged

fix(detectors): union scopes when duplicate nodes fold#406
bomly-guy merged 1 commit into
mainfrom
claude/github-issue-400-b7ad68

Conversation

@bomly-guy

Copy link
Copy Markdown
Collaborator

Fixes #400.

What

When one package appears twice in a manifest, the duplicate node folds and its scopes went with it — a Pipfile.lock package listed in both default and develop kept only the scope of whichever group was processed first. Four detectors (node, gomod, gradle, maven) hand-merged scopes at their own fold sites; ten others silently dropped them.

How

  • detectors.EnsureNode (the fold point centralized in feat(sbom): detector-asserted package origin in SBOM export #397, called AddNodeFolding in the issue) now unions the incoming record's scopes onto the survivor. Scopes answer "where is this package reachable?", so a fold takes the union; everything else on the discarded record is still dropped.
  • EnsureOccurrence now decides fold-vs-distinct-occurrence before inserting, so a record that stays a distinct occurrence (conflicting ResolvedURL) never leaks its scope onto the node it collided with. Same identity semantics as before, restated without the double insert.
  • Deleted the per-detector merges the helper now subsumes: gomod's addOrMergeModuleNode scope parameter, maven's and gradle's post-fold AddScope(PrimaryScope()), gradle's hand-rolled lookup-then-AddScope for project references, and the four node-family sites (npm list tree, npm/pnpm/yarn lockfile parsers). Every one of those nodes already carries its scope via sdk.ScopesOf at construction. Edge-time scope propagation (composer/cargo/mix/nuget/etc. marking scopes on lookups driven by manifest sections) is a different mechanism and is untouched.

Behavior change

Duplicate-node scope semantics change for every detector using the helper: a package reachable at more than one scope now carries all of them, not just the first-seen one. The previously hand-merging detectors are unchanged in effect (their nodes carried a single scope, and union ⊇ PrimaryScope merge).

Tests

  • TestEnsureNodeUnionsScopesOnFold — fold unions scopes.
  • TestEnsureOccurrenceScopes — distinct occurrence keeps its own scope and leaks nothing; same-resolution fold unions.
  • TestDepGraphFromPipfileLockPackageInBothGroupsKeepsBothScopes — the issue's reproduction: requests in both groups carries runtime + development, pytest stays development-only.
  • make test passes with no golden drift. Smoke goldens may move where a real-repo package is reachable at more than one scope — if the smoke run flags drift, dispatch Update Smoke Goldens after review.

🤖 Generated with Claude Code

A package listed in two dependency groups is reachable at both scopes,
but folding the duplicate record kept only whichever group was processed
first -- a Pipfile.lock package in both default and develop lost its
development scope. Four detectors (node, gomod, gradle, maven) patched
this at their own call sites; ten others silently dropped the scope.

Move the rule into the shared fold point: detectors.EnsureNode now
unions the incoming record's scopes onto the survivor, and the
per-detector AddScope merges that duplicated it are deleted.
EnsureOccurrence decides distinct-occurrence identity before inserting,
so a record that stays its own occurrence never leaks its scope onto
the node it collided with.

Fixes #400

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 33 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3ffbfef9-f25a-4124-9464-9e0983d01a42

📥 Commits

Reviewing files that changed from the base of the PR and between 22e3ded and dea3757.

📒 Files selected for processing (10)
  • internal/detectors/ensure_node.go
  • internal/detectors/ensure_node_test.go
  • internal/detectors/gomod/detector.go
  • internal/detectors/gradle/detector.go
  • internal/detectors/maven/detector.go
  • internal/detectors/node/common.go
  • internal/detectors/node/npm/npm_lockfile_parser.go
  • internal/detectors/node/pnpm/pnpm_lockfile_parser.go
  • internal/detectors/node/yarn/yarn_lockfile_parser.go
  • internal/detectors/python/detector_test.go

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Bomly Diff Summary

Compared 22e3dedb67ada74eca47974be74928c232af7ddb to dea3757e045b59d5c88820206c551bef3944c34b.

Overview

Status Manifests Dependencies Findings Duration
✅ Pass +0 / ~0 / -0 0 added / 0 version changed / 0 detail changes / 0 removed 0 introduced / 0 persisted / 0 resolved 1m 12s

Dependency Changes

✅ No dependency changes.

Vulnerabilities

✅ No vulnerability changes.

License Changes

✅ No license changes.

Project Posture

✅ No project posture changes (--matchers +scorecard was not selected).

Policy Findings

✅ No policy differences were identified.

@bomly-guy
bomly-guy merged commit 64aa29b into main Aug 26, 2026
16 checks passed
@bomly-guy
bomly-guy deleted the claude/github-issue-400-b7ad68 branch August 26, 2026 05:49
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.

detectors: a package in two dependency groups loses the second group's scope

2 participants