Skip to content

fix(go): remove directDepPaths filtering that drops direct dependencies#497

Open
ruromero wants to merge 2 commits intoguacsec:mainfrom
ruromero:TC-4275
Open

fix(go): remove directDepPaths filtering that drops direct dependencies#497
ruromero wants to merge 2 commits intoguacsec:mainfrom
ruromero:TC-4275

Conversation

@ruromero
Copy link
Copy Markdown
Collaborator

@ruromero ruromero commented Apr 28, 2026

Summary

  • Removes the directDepPaths filtering introduced in de12f6a that used go mod edit -json Indirect flags to exclude root-level edges from go mod graph, causing an 84% drop in reported direct dependencies (45→7 for go_mod_no_ignore)
  • Adds a reproducer test verifying go_mod_no_ignore component analysis reports all 45 root-level deps from go mod graph
  • Regenerates 9 expected SBOM fixtures to match corrected dependency counts

Fixes TC-4275
Part of TC-3818

Root Cause

Commit de12f6a built a directDepPaths Set from go mod edit -json entries where Indirect === false, then filtered root-level edges from go mod graph against it. Since go mod graph reports edges after MVS resolution while go mod edit -json reflects go.mod's // indirect markers, valid direct dependencies were incorrectly excluded.

The Java client treats ALL root-level edges from go mod graph as direct dependencies and never performs this filtering — restoring that behavior here aligns cross-client parity.

Test plan

  • Reproducer test: go_mod_no_ignore component analysis asserts 45 root-level deps (failed with 7 before fix)
  • All 7 Go module test scenarios pass (stack + component analysis): 16 passing
  • ESLint: 0 errors, 0 warnings
  • Cross-client parity: go_mod_no_ignore stack=138 components, go_mod_mvs_versions stack=138 components (matching Java client)

🤖 Generated with Claude Code

Summary by Sourcery

Restore reporting of all root-level Go module dependencies in SBOM generation and update tests/fixtures accordingly.

Bug Fixes:

  • Stop filtering out direct Go module dependencies based on go mod edit Indirect flags so all root-level edges from go mod graph are treated as direct dependencies.

Tests:

  • Add a regression test to ensure go_mod_no_ignore component analysis reports all root-level dependencies from go mod graph.
  • Regenerate Go module SBOM fixture files to reflect the corrected dependency counts for component and stack analysis.

Commit de12f6a introduced filtering in getSBOM() that uses go mod edit
-json's Indirect flag to exclude root-level edges from go mod graph.
This caused go_mod_no_ignore direct dependency count to drop from 45
to 7 (84% reduction).

The Java client treats all root-level edges from go mod graph as direct
dependencies. The go mod graph output is the authoritative dependency
tree after MVS resolution — filtering based on go.mod's indirect
markers removes real edges from the graph.

Remove the directDepPaths set construction and its filtering guards
from both the stack analysis and component analysis paths. Add a
reproducer test asserting 45 direct deps for go_mod_no_ignore.
Regenerate all affected expected SBOM fixtures.

Implements TC-4275

Assisted-by: Claude Code
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Apr 28, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

This PR removes previously introduced filtering of Go module root-level dependencies based on go mod edit -json Indirect flags, restores treating all go mod graph root edges as direct dependencies, adds a targeted regression test, and updates SBOM fixture expectations accordingly.

Sequence diagram for Go module SBOM generation without directDepPaths filtering

sequenceDiagram
    actor User
    participant GolangProvider as Golang_gomodules
    participant GoToolchain as Go_commands
    participant SBOM as SbomBuilder

    User->>GolangProvider: getSBOM(manifest, opts, includeTransitive)
    GolangProvider->>GoToolchain: run go mod edit -json
    GoToolchain-->>GolangProvider: goModEditOutput
    GolangProvider->>GoToolchain: run go mod graph
    GoToolchain-->>GolangProvider: goGraphOutput

    GolangProvider->>GolangProvider: parse goGraphOutput into rows
    GolangProvider->>GolangProvider: determine root module path

    loop for each row in rows
        GolangProvider->>GolangProvider: parent = getParentVertexFromEdge(row)
        GolangProvider->>GolangProvider: child = getChildVertexFromEdge(row)
        GolangProvider->>GolangProvider: source = toPurl(parent, "@")
        GolangProvider->>GolangProvider: target = toPurl(child, "@")

        alt dependencyNotIgnored
            GolangProvider->>SBOM: addDependency(source, target)
        else ignored
            GolangProvider->>SBOM: skip dependency
        end
    end

    par component analysis root dependencies
        loop for each root level pair
            GolangProvider->>GolangProvider: child = getChildVertexFromEdge(pair)
            GolangProvider->>GolangProvider: target = toPurl(child, "@")
            alt dependencyNotIgnored
                GolangProvider->>SBOM: addDependency(mainModule, target)
            else ignored
                GolangProvider->>SBOM: skip dependency
            end
        end
    and cleanup
        GolangProvider->>SBOM: enforceRemovingIgnoredDepsInCaseOfAutomaticVersionUpdate
    end

    SBOM-->>User: final SBOM
Loading

File-Level Changes

Change Details Files
Restore inclusion of all root-level go mod graph edges as direct dependencies in SBOM generation.
  • Remove construction of a directDepPaths set derived from non-indirect go.mod requirements.
  • Stop skipping root-level edges when the parent is the main module but the child is not in the directDepPaths set.
  • Always add dependencies from the main module to children reported by go mod graph when they are not ignored, regardless of go.mod Indirect markers.
src/providers/golang_gomodules.js
Add regression test to ensure go_mod_no_ignore component analysis includes all root-level dependencies from go mod graph.
  • Create a new test that runs provideComponent on the go_mod_no_ignore manifest and parses the resulting SBOM.
  • Assert that the first dependency entry with dependsOn is of length 45, matching the full set of root-level edges from go mod graph.
  • Use a descriptive failure message to indicate when directDepPaths-style filtering would incorrectly exclude dependencies.
test/providers/golang_gomodules.test.js
Update expected SBOM fixtures to match corrected dependency counts and dependency graphs.
  • Regenerate expected component analysis SBOMs for various go_mod_* scenarios to reflect restored direct dependency reporting.
  • Regenerate expected stack analysis SBOMs for the same scenarios, ensuring parity with the Java client behavior.
test/providers/tst_manifests/golang/go_mod_light_no_ignore/expected_sbom_component_analysis.json
test/providers/tst_manifests/golang/go_mod_light_no_ignore/expected_sbom_stack_analysis.json
test/providers/tst_manifests/golang/go_mod_mvs_versions/expected_sbom_stack_analysis.json
test/providers/tst_manifests/golang/go_mod_no_ignore/expected_sbom_component_analysis.json
test/providers/tst_manifests/golang/go_mod_no_ignore/expected_sbom_stack_analysis.json
test/providers/tst_manifests/golang/go_mod_test_ignore/expected_sbom_component_analysis.json
test/providers/tst_manifests/golang/go_mod_test_ignore/expected_sbom_stack_analysis.json
test/providers/tst_manifests/golang/go_mod_with_ignore/expected_sbom_component_analysis.json
test/providers/tst_manifests/golang/go_mod_with_ignore/expected_sbom_stack_analysis.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • In the new test, rootDeps is derived by taking the first dependency entry with a non-empty dependsOn array; consider explicitly identifying the root module (e.g., by matching ref/purl/module path) so the assertion doesn't depend on fixture ordering.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the new test, `rootDeps` is derived by taking the first dependency entry with a non-empty `dependsOn` array; consider explicitly identifying the root module (e.g., by matching `ref`/purl/module path) so the assertion doesn't depend on fixture ordering.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@ruromero
Copy link
Copy Markdown
Collaborator Author

Verification Report for TC-4275 (commit 6a43c91)

Check Result Details
Review Feedback PASS Sourcery bot suggestion about fragile root dep lookup was addressed by commit 2. No unresolved code change requests.
Root-Cause Investigation N/A No sub-tasks created — nothing to investigate.
Scope Containment PASS All 11 changed files match task spec: 1 source file, 1 test file, 9 expected SBOM fixtures.
Diff Size PASS +3951 / -2517 across 11 files. Bulk is regenerated SBOM fixtures (expected per task). Actual logic change is small.
Commit Traceability WARN Commit 1 references "Implements TC-4275". Commit 2 ("chore: improve test fragile root dep lookup") does not reference the issue.
Sensitive Patterns PASS Only match: process.env.GITHUB_ACTIONS (false positive — standard Node.js env check).
CI Status PASS All 5 checks pass: Lint/test (Node 22 + 24), Sourcery review, PR title validation, commit message validation.
Acceptance Criteria PASS All 4 criteria met (details below).
Test Quality WARN 1 parameterization candidate; 5 test functions lack doc comments (pre-existing gap).
Test Change Classification ADDITIVE 1 new test function added, 0 removed, 0 weakened. Fixture changes expand expected output (stricter assertions).
Verification Commands N/A No verification commands in task description.

Acceptance Criteria Details

# Criterion Result Evidence
1 Reproducer test fails before fix (gets 7), passes after (gets 45) PASS Test at lines 61-69 asserts expect(rootDeps.dependsOn).to.have.lengthOf(45, ...) with descriptive failure message
2 All 16 Go module tests pass PASS 16 tests confirmed: 2 isSupported + 12 forEach (6 scenarios × 2 analysis types) + 1 reproducer + 1 MVS
3 go_mod_no_ignore component analysis direct deps = 45 PASS Expected SBOM fixture verified: root component has exactly 45 dependsOn entries
4 ESLint passes with no new errors PASS CI passes; directDepPaths fully removed from source; no lint issues detected

Overall: WARN

One commit lacks a Jira issue reference. Test quality has advisory findings (parameterization opportunity, missing doc comments) that don't affect correctness.


This comment was AI-generated by sdlc-workflow/verify-pr v0.7.2.

@ruromero
Copy link
Copy Markdown
Collaborator Author

Why test fixture expectations changed

For reviewers unfamiliar with the Go provider internals, here's context on why the expected SBOM fixtures changed significantly:

Root cause

Commit de12f6a introduced directDepPaths filtering that used go mod edit -json's Indirect flag to classify which root-level edges from go mod graph are "direct." This was incorrect — Go's go.mod file marks dependencies as // indirect based on whether they appear in import statements of the root module, not based on whether they're direct graph edges after MVS (Minimum Version Selection) resolution.

The result was that go mod graph correctly showed 45 direct dependencies for go_mod_no_ignore, but the filtering reduced this to just 7 — an 84% drop.

What changed in fixtures

Category What happened Why
Component analysis fixtures (4 files) dependsOn arrays expanded significantly (e.g., 7→45 deps for go_mod_no_ignore) The fix removes the incorrect filter, so all root-level edges from go mod graph are now correctly treated as direct dependencies — matching the Java client's behavior
Stack analysis fixtures (5 files) Same component/dependency counts, only entry ordering changed Stack analysis uses go mod graph for the full tree (not filtered by directDepPaths), so only non-deterministic ordering differences appear

How to verify

The new reproducer test at line 61 of golang_gomodules.test.js asserts exactly 45 direct deps for go_mod_no_ignore, which matches both the pre-regression count and the Java client's output. If the directDepPaths filtering were reintroduced, this test would fail with 7.

Collapse the stack analysis and component analysis test bodies into a
single parameterized forEach over analysis type, provider method,
fixture file, and CI timeout. This removes duplication while preserving
identical test coverage and names.

Implements TC-4275
Signed-off-by: Ruben Romero Montes <rromerom@redhat.com>
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.

1 participant