google / google/osv-scanner

Mixed versioned ecosystems duplicate packages in formatted output

Closed
#3,086 0 comments 0 reactions 1 assignee Claimed by @Muszic View on GitHub
Dominant language
Go
Stars
11k
Forks
792
Avg merge
1d 20h
Merged PRs (30d)
48

Description

## Summary

`output.BuildResults` duplicates and misattributes packages when one source contains ecosystem names where one is a prefix of another, such as `Alpine` and `Alpine:v3.18`.

This affects the table, vertical, Markdown, and HTML formatters, all of which consume `BuildResults`. The raw JSON formatter is unaffected.

Reproduced on current `main` at `1f87b5cb9781a03a9b8b50dfc1eac1b2056c79d5`.

## Minimal reproduction

Using one `PackageSource` with these two packages:

```go
Packages: []models.PackageVulns{
packageWithVuln("base-package", "Alpine", "OSV-BASE"),
packageWithVuln("versioned-package", "Alpine:v3.18", "OSV-VERSIONED"),
}
```

and printing the ecosystem/package pairs returned by `output.BuildResults` produces:

```text
Alpine -> base-package
Alpine -> versioned-package
Alpine:v3.18 -> versioned-package
```

The versioned package and its vulnerability count appear in both ecosystem sections. The expected result is:

```text
Alpine -> base-package
Alpine:v3.18 -> versioned-package
```

## Root cause

`processSource` supports multiple ecosystems in one source and stores packages under a composite string key:

```go
key := vulnPkg.Package.Ecosystem + ":" + vulnPkg.Package.Name + ":" + vulnPkg.Package.Version
```

It later assigns packages to ecosystem sections using the ecosystem name as a raw prefix:

```go
if !strings.HasPrefix(key, ecosystem) {
continue
}
```

For the `Alpine` section, both `Alpine:base-package:...` and `Alpine:v3.18:versioned-package:...` match.

Mixed base and versioned OS ecosystems are valid inputs, for example when an SBOM contains some OS package PURLs with distro metadata and others without it.

## Suggested fix

Use a structured package key containing separate ecosystem, name, and version fields, then compare the ecosystem field for exact equality. This also avoids relying on delimiters inside package identities.

Add a focused `BuildResults` regression test with `Alpine` and `Alpine:v3.18` packages and assert that each package appears only in its exact ecosystem section.

I searched existing issues and pull requests and did not find this behavior reported. If this approach looks appropriate, please assign the issue to `@Muszic` and I can submit the fix with regression coverage.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.