CycloneDX / CycloneDX/cyclonedx-gomod

cyclonedx-gomod creates circular dependency when package depends on older version of itself

Open
#720 0 comments 1 reaction 0 assignees View on GitHub
Dominant language
Go
Stars
187
Forks
40
Avg merge
1d 7h
Merged PRs (30d)
14

Description

## Description

When a Go module depends on two different versions of the same package (e.g., a newer version depends on an older version), `cyclonedx-gomod` incorrectly merges them into a single component and creates a circular dependency reference instead of creating separate component entries for each version.

## Environment

- **cyclonedx-gomod version**: v1.9.0
- **Go version**: 1.25.0
- **OS**: macOS (also likely affects other platforms)
- **Command used**:
```bash
cyclonedx-gomod mod -licenses -test -output sbom.yml -output-version "1.4" -verbose=true
cyclonedx-gomod mod -licenses -test -output sbom.yml -output-version "1.5" -verbose=true
cyclonedx-gomod mod -licenses -test -output sbom.yml -output-version "1.6" -verbose=true
```

## Steps to Reproduce

1. Use a Go project that depends on `github.com/tedsuo/ifrit@v0.0.0-20230516164442-7862c310ad26`
2. Note that this version itself depends on `github.com/tedsuo/ifrit@v0.0.0-20230330192023-5cba443a66c4` (older version)
3. Verify with `go mod graph`:
```bash
go mod graph | grep -E "tedsuo/ifrit.*tedsuo/ifrit"
```
Output:
```
github.com/tedsuo/ifrit@v0.0.0-20230516164442-7862c310ad26 github.com/tedsuo/ifrit@v0.0.0-20230330192023-5cba443a66c4
```
4. Run cyclonedx-gomod with various output versions (1.4, 1.5, 1.6) - all produce the same issue
5. Examine the generated SBOM

## Expected Behavior

The SBOM should contain:

1. **Two separate component entries**:
- Component for `pkg:golang/github.com/tedsuo/ifrit@v0.0.0-20230516164442-7862c310ad26`
- Component for `pkg:golang/github.com/tedsuo/ifrit@v0.0.0-20230330192023-5cba443a66c4`

2. **Correct dependency relationship**:
```xml




```

## Actual Behavior

The SBOM only contains:

1. **One component entry** (only the newer version):
- Component for `pkg:golang/github.com/tedsuo/ifrit@v0.0.0-20230516164442-7862c310ad26`
- Missing component for the older version

2. **Circular dependency** (self-reference):
```xml








```

## Root Cause

The tool appears to be deduplicating packages by name only, without considering version differences. When building the dependency graph, it then creates a reference to the deduplicated component, resulting in a self-reference rather than a reference to the distinct older version.

## Impact

1. **SBOM validation failures**: SBOMs with circular dependencies may fail validation in some tools
2. **Inaccurate dependency graphs**: Downstream tools cannot accurately analyze the true dependency tree
3. **Security scanning issues**: Vulnerability scanners may miss issues in the older version since it's not represented as a separate component

## Additional Context

This is valid Go module behavior - a package can legitimately depend on an older version of itself. Go's module system handles this correctly via [Minimal Version Selection (MVS)](https://go.dev/ref/mod#minimal-version-selection), and `go mod graph` correctly shows both versions as distinct nodes in the dependency graph.

The SBOM generator should preserve this version-specific dependency information rather than collapsing it into a single component.

## Workaround

Currently, the only workaround is to manually edit the generated SBOM to:
1. Add the missing component entry for the older version
2. Update the dependency reference to point to the correct version

However, this must be redone every time the SBOM is regenerated.

## Related Issues
I do not know of any related issues at this time, but this may be a common scenario for Go projects that use older versions of dependencies.

Contributor guide

Open the contributing guide

Research direction

Reproduce the issue with the listed cyclonedx-gomod command and the github.com/tedsuo/ifrit dependency graph from go mod graph. Trace the component deduplication and dependency-reference generation, then verify that both versions appear as separate components and that the newer version points to the older one without a circular reference.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
devtools
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.