-
Notifications
You must be signed in to change notification settings - Fork 824
Draft: add BellSoft family of OS #3264
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
i-bs
wants to merge
8
commits into
anchore:main
Choose a base branch
from
i-bs:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+1,441
−80
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
90d027e
add BellSoft family of OS
i-bs f289de3
fix: db: conjunction-ed constraints must be comma-delimetered
i-bs e55bb38
feat: db: add transform_bellsoft
i-bs 353d7ee
Merge branch 'main' of github.com:anchore/grype
willmurphyscode 09e6883
move bellsoft to modern pattern and add dbtests
willmurphyscode b17e6fd
Merge branch 'main' of github.com:anchore/grype
willmurphyscode 76aa9f2
normalize constraints in cgr tests
willmurphyscode 2cddf53
additional bellsoft tests
willmurphyscode File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
147 changes: 147 additions & 0 deletions
147
grype/db/v6/build/transformers/osv/testdata/BELL-CVE-2025-59375.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,147 @@ | ||
| { | ||
| "affected": [ | ||
| { | ||
| "package": { | ||
| "ecosystem": "Alpaquita:23", | ||
| "name": "expat", | ||
| "purl": "pkg:apk/alpaquita/expat?arch=source&distro=23" | ||
| }, | ||
| "ranges": [ | ||
| { | ||
| "events": [ | ||
| { | ||
| "introduced": "2.5.0-r0" | ||
| }, | ||
| { | ||
| "fixed": "2.7.2-r0" | ||
| } | ||
| ], | ||
| "type": "ECOSYSTEM" | ||
| } | ||
| ] | ||
| }, | ||
| { | ||
| "package": { | ||
| "ecosystem": "Alpaquita:25", | ||
| "name": "expat", | ||
| "purl": "pkg:apk/alpaquita/expat?arch=source&distro=25" | ||
| }, | ||
| "ranges": [ | ||
| { | ||
| "events": [ | ||
| { | ||
| "introduced": "2.7.1-r0" | ||
| }, | ||
| { | ||
| "fixed": "2.7.2-r0" | ||
| } | ||
| ], | ||
| "type": "ECOSYSTEM" | ||
| } | ||
| ] | ||
| }, | ||
| { | ||
| "package": { | ||
| "ecosystem": "Alpaquita:stream", | ||
| "name": "expat", | ||
| "purl": "pkg:apk/alpaquita/expat?arch=source&distro=stream" | ||
| }, | ||
| "ranges": [ | ||
| { | ||
| "events": [ | ||
| { | ||
| "introduced": "2.4.9-r0" | ||
| }, | ||
| { | ||
| "fixed": "2.7.2-r0" | ||
| } | ||
| ], | ||
| "type": "ECOSYSTEM" | ||
| } | ||
| ] | ||
| }, | ||
| { | ||
| "package": { | ||
| "ecosystem": "BellSoft Hardened Containers:23", | ||
| "name": "expat", | ||
| "purl": "pkg:apk/bellsoft-hardened-containers/expat?arch=source&distro=23" | ||
| }, | ||
| "ranges": [ | ||
| { | ||
| "events": [ | ||
| { | ||
| "introduced": "2.5.0-r0" | ||
| }, | ||
| { | ||
| "fixed": "2.7.2-r0" | ||
| } | ||
| ], | ||
| "type": "ECOSYSTEM" | ||
| } | ||
| ] | ||
| }, | ||
| { | ||
| "package": { | ||
| "ecosystem": "BellSoft Hardened Containers:25", | ||
| "name": "expat", | ||
| "purl": "pkg:apk/bellsoft-hardened-containers/expat?arch=source&distro=25" | ||
| }, | ||
| "ranges": [ | ||
| { | ||
| "events": [ | ||
| { | ||
| "introduced": "2.7.1-r0" | ||
| }, | ||
| { | ||
| "fixed": "2.7.2-r0" | ||
| } | ||
| ], | ||
| "type": "ECOSYSTEM" | ||
| } | ||
| ] | ||
| }, | ||
| { | ||
| "package": { | ||
| "ecosystem": "BellSoft Hardened Containers:stream", | ||
| "name": "expat", | ||
| "purl": "pkg:apk/bellsoft-hardened-containers/expat?arch=source&distro=stream" | ||
| }, | ||
| "ranges": [ | ||
| { | ||
| "events": [ | ||
| { | ||
| "introduced": "2.4.9-r0" | ||
| }, | ||
| { | ||
| "fixed": "2.7.2-r0" | ||
| } | ||
| ], | ||
| "type": "ECOSYSTEM" | ||
| } | ||
| ] | ||
| } | ||
| ], | ||
| "id": "BELL-CVE-2025-59375", | ||
| "modified": "2025-12-23T13:05:51.859654Z", | ||
| "published": "2025-09-15T11:56:23.866967Z", | ||
| "references": [ | ||
| { | ||
| "type": "ADVISORY", | ||
| "url": "https://docs.bell-sw.com/security/cves/CVE-2025-59375" | ||
| }, | ||
| { | ||
| "type": "ADVISORY", | ||
| "url": "https://docs.bell-sw.com/security/advisories/BELL-SA-2025-13" | ||
| } | ||
| ], | ||
| "schema_version": "1.7.4", | ||
| "severity": [ | ||
| { | ||
| "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", | ||
| "type": "CVSS_V3" | ||
| } | ||
| ], | ||
| "upstream": [ | ||
| "CVE-2025-59375" | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
175 changes: 175 additions & 0 deletions
175
grype/db/v6/build/transformers/osv/transform_bellsoft.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,175 @@ | ||
| package osv | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "sort" | ||
| "strconv" | ||
| "strings" | ||
|
|
||
| "github.com/anchore/grype/grype/db/data" | ||
| "github.com/anchore/grype/grype/db/internal/provider/unmarshal" | ||
| "github.com/anchore/grype/grype/db/internal/provider/unmarshal/osvmodel" | ||
| "github.com/anchore/grype/grype/db/provider" | ||
| db "github.com/anchore/grype/grype/db/v6" | ||
| "github.com/anchore/grype/grype/db/v6/build/transformers" | ||
| "github.com/anchore/grype/grype/db/v6/build/transformers/internal" | ||
| "github.com/anchore/grype/grype/db/v6/name" | ||
| "github.com/anchore/grype/internal/log" | ||
| "github.com/anchore/syft/syft/pkg" | ||
| ) | ||
|
|
||
| // bellsoftStrategy handles BELL-* records from BellSoft's vulnerability database. | ||
| // BellSoft records describe *affected* apk version ranges for packages shipped | ||
| // in BellSoft's distros: Alpaquita Linux and BellSoft Hardened Containers. | ||
| // | ||
| // BellSoft-specific decisions: | ||
| // - CVE refs live in the `upstream` field (aliases/related are empty); it | ||
| // feeds both the vulnerability blob's Aliases and each package blob's CVEs. | ||
| // - These are distro packages (like alpine secdb), not application packages | ||
| // (like bitnami). Every affected entry carries an OperatingSystem derived | ||
| // from the OSV ecosystem string ("Alpaquita:23", "BellSoft Hardened | ||
| // Containers:stream", ...) so the apk matcher's distro search can find them. | ||
| // Package.Ecosystem is the apk package-type string, taken from the PURL. | ||
| // - apk-flavored versions (e.g. 2.7.2-r0) compare with the apk comparator. | ||
| // - No qualifiers or CPEs are emitted; the apk matcher finds these records by | ||
| // distro + package name, never by CPE. | ||
| type bellsoftStrategy struct{} | ||
|
|
||
| func (bellsoftStrategy) Matches(id string) bool { | ||
| return strings.HasPrefix(id, "BELL-") | ||
| } | ||
|
|
||
| func (bellsoftStrategy) Transform(vuln unmarshal.OSVVulnerability, state provider.State) ([]data.Entry, error) { | ||
| severities, err := getSeverities(vuln) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("unable to obtain severities: %w", err) | ||
| } | ||
|
|
||
| in := []any{ | ||
| db.VulnerabilityHandle{ | ||
| Name: vuln.ID, | ||
| ProviderID: state.Provider, | ||
| Provider: provider.Model(state), | ||
| Status: db.VulnerabilityActive, | ||
| ModifiedDate: &vuln.Modified, | ||
| PublishedDate: &vuln.Published, | ||
| BlobValue: &db.VulnerabilityBlob{ | ||
| ID: vuln.ID, | ||
| Description: vuln.Details, | ||
| References: bellsoftReferences(vuln), | ||
| Aliases: vuln.Upstream, | ||
| Severities: severities, | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| for _, aph := range bellsoftAffectedPackages(vuln) { | ||
| in = append(in, aph) | ||
| } | ||
| return transformers.NewEntries(in...), nil | ||
| } | ||
|
|
||
| func bellsoftReferences(vuln unmarshal.OSVVulnerability) []db.Reference { | ||
| var refs []db.Reference | ||
| for _, ref := range vuln.References { | ||
| refs = append(refs, db.Reference{ | ||
| URL: ref.URL, | ||
| Tags: []string{string(ref.Type)}, | ||
| }) | ||
| } | ||
| return refs | ||
| } | ||
|
|
||
| func bellsoftAffectedPackages(vuln unmarshal.OSVVulnerability) []db.AffectedPackageHandle { | ||
| if len(vuln.Affected) == 0 { | ||
| return nil | ||
| } | ||
| var aphs []db.AffectedPackageHandle | ||
| for _, affected := range vuln.Affected { | ||
| os := bellsoftOSFromEcosystem(affected.Package.Ecosystem) | ||
| if os == nil { | ||
| // A BellSoft record keyed to an ecosystem we don't recognize would | ||
| // produce a DB entry with no OS — unreachable by the apk matcher's | ||
| // distro search. Skip with a warning so the drift is visible rather | ||
| // than silently emitting dead records. | ||
| log.WithFields("id", vuln.ID, "ecosystem", affected.Package.Ecosystem, "package", affected.Package.Name). | ||
| Warn("bellsoft record uses an unrecognized ecosystem; skipping (add a case to bellsoftOSFromEcosystem to enable)") | ||
| continue | ||
| } | ||
|
|
||
| var ranges []db.Range | ||
| for _, r := range affected.Ranges { | ||
| ranges = append(ranges, getGrypeRangesFromRange(r, bellsoftRangeType(r.Type))...) | ||
| } | ||
| aphs = append(aphs, db.AffectedPackageHandle{ | ||
| Package: bellsoftPackage(affected.Package), | ||
| OperatingSystem: os, | ||
| BlobValue: &db.PackageBlob{ | ||
| CVEs: vuln.Upstream, | ||
| Ranges: ranges, | ||
| }, | ||
| }) | ||
| } | ||
| // stable: entries for the same package+constraint on different distros | ||
| // (alpaquita vs BHC) compare equal, so keep the record's affected order | ||
| sort.Stable(internal.ByAffectedPackage(aphs)) | ||
| return aphs | ||
| } | ||
|
|
||
| func bellsoftPackage(p osvmodel.Package) *db.Package { | ||
| pkgType := pkg.TypeFromPURL(p.Purl) | ||
| return &db.Package{ | ||
| Ecosystem: pkgType.String(), | ||
| Name: name.Normalize(p.Name, pkgType), | ||
| } | ||
| } | ||
|
|
||
| // bellsoftOSFromEcosystem derives operating-system metadata from a BellSoft OSV | ||
| // ecosystem string. BellSoft records are keyed by distro (like alpine secdb), | ||
| // so every affected package needs an OperatingSystem for the apk matcher's | ||
| // distro search to reach it. | ||
| // | ||
| // The ecosystem shape is "<distro>:<version>", mapped to the grype distro type | ||
| // string so it matches a scanned distro's ID: | ||
| // | ||
| // - "Alpaquita:23" → alpaquita, major version 23 | ||
| // - "Alpaquita:stream" → alpaquita, rolling label "stream" | ||
| // - "BellSoft Hardened Containers:stream" → bellsoft-hardened-containers, label "stream" | ||
| // | ||
| // A numeric version is a release major; a non-numeric one (e.g. "stream") is a | ||
| // rolling label. Unrecognized ecosystems return nil so the caller can skip them. | ||
| func bellsoftOSFromEcosystem(ecosystem string) *db.OperatingSystem { | ||
| base, ver, ok := strings.Cut(ecosystem, ":") | ||
| if !ok || ver == "" { | ||
| return nil | ||
| } | ||
|
|
||
| var osName string | ||
| switch base { | ||
| case "Alpaquita": | ||
| osName = "alpaquita" | ||
| case "BellSoft Hardened Containers": | ||
| osName = "bellsoft-hardened-containers" | ||
| default: | ||
| return nil | ||
| } | ||
|
|
||
| if _, err := strconv.Atoi(ver); err == nil { | ||
| return &db.OperatingSystem{Name: osName, MajorVersion: ver} | ||
| } | ||
| return &db.OperatingSystem{Name: osName, LabelVersion: ver} | ||
| } | ||
|
|
||
| // bellsoftRangeType maps an OSV range type to the grype version-format string | ||
| // for BellSoft records. BellSoft packages are Alpaquita/BHC apk packages, so | ||
| // both SEMVER and ECOSYSTEM ranges carry apk-formatted versions (e.g. 2.7.2-r0) | ||
| // and must be compared with the apk comparator. Other OSV types fall through to | ||
| // the default mapping. | ||
| func bellsoftRangeType(t osvmodel.RangeType) string { | ||
| switch t { | ||
| case osvmodel.RangeSemVer, osvmodel.RangeEcosystem: | ||
| return "apk" | ||
| default: | ||
| return defaultRangeType(t) | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.