Skip to content

feat(rootio): migrate source to per-advisory OSV v1.6.0 format#657

Open
chait-slim wants to merge 6 commits into
aquasecurity:mainfrom
chait-slim:rootio-osv
Open

feat(rootio): migrate source to per-advisory OSV v1.6.0 format#657
chait-slim wants to merge 6 commits into
aquasecurity:mainfrom
chait-slim:rootio-osv

Conversation

@chait-slim

@chait-slim chait-slim commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Migrates the Root.io vulnerability source from the legacy monolithic
cve_feed.json to per-advisory OSV v1.6.0 files under rootio/**/*.json,
using the shared pkg/vulnsrc/osv parser.

Each advisory's bucket is resolved by a single "Root:" bucket resolver
driven by the OSV ecosystem string (e.g. Root:Alpine:3.18) plus
database_specific.distro / distro_version. Only OS ecosystems are
supported.

Trivy resolution is unchanged: VulnSrcGetter.Get pulls every base-OS
advisory (Debian/Ubuntu/Alpine), then overlays Root.io's patched
versions on top, with Root.io winning only on vulnerability-ID
collision. Unfixed CVEs continue to surface from the upstream source.

Comment thread pkg/vulnsrc/rootio/types.go Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i think you can use osv packages.

You can see seal as example

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed

@chait-slim

Copy link
Copy Markdown
Contributor Author

@DmitriyLewen can you please review again the two PRs?

Comment thread pkg/vulnsrc/rootio/rootio.go Outdated
Comment on lines +48 to +50
ecosystem.Npm: source,
ecosystem.Pip: source,
ecosystem.RubyGems: source,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We migrate to OSV in this PR.

We don't need to add language ecosystems here.

Comment thread pkg/vulnsrc/rootio/rootio.go Outdated
o := osv.New(vulnsDir, source.ID, dataSources,
osv.WithBucketResolver("alpine", resolveAlpineBucket),
osv.WithBucketResolver("debian", resolveDebianBucket),
osv.WithBucketResolver("ubuntu", resolveUbuntuBucket),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

IIUC we can create a single function to resolve the Bucket based on the ecosystem.

It also makes sense to move this function into bucket.go.

Comment thread pkg/vulnsrc/rootio/rootio.go Outdated
Comment on lines +90 to +93
var dbSpec struct {
Distro string `json:"distro"`
DistroVersion string `json:"distro_version"`
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would move this structure outside of the function — it's more readable that way.

Comment thread pkg/vulnsrc/rootio/rootio.go Outdated

func (vs VulnSrc) put(tx *bolt.Tx, platform string, feed Feed) error {
eb := oops.With("platform", platform).With("package", feed.PkgName).With("cve", feed.VulnerabilityID)
if dbSpec.Distro != "" {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Since we currently only support OS ecosystems — I think we should return an error if Distro is empty.

Comment thread pkg/vulnsrc/rootio/rootio.go Outdated
return nil
type config struct {
dbc db.Operation
logger *log.Logger

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

unused now.

Comment thread pkg/vulnsrc/rootio/rootio.go Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can we use bucket now?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can you update test files with severity?

chait-slim added a commit to chait-slim/trivy-db that referenced this pull request May 6, 2026
…stems

                                                                          Addresses PR aquasecurity#657 review (DmitriyLewen, 2026-05-04) and aligns the
  parser with the actual root.io OSV feed (https://api.root.io/external/osv/all.zip).
  The feed emits ecosystem strings of the form "Root:<os>:<version>"                                                                                 (e.g. "Root:Alpine:3.18", "Root:Debian:11", "Root:Ubuntu:20.04").
  The OSV parser splits on the first ":" and looks up the resolver under                                                                             "root", passing "<os>:<version>" as the suffix — the previous Alpine/
  Debian/Ubuntu resolvers would never have matched.
  - Replace the three per-OS resolvers with a single resolveBucket(suffix)                                                                             in bucket.go that parses suffix into <os>+<version> and builds the
    Root.io bucket directly.                                                                                                                         - Reject suffixes without a version (Root:npm, Root:PyPI, Root:Maven,
    Root:Go) so the OSV parser skips language-ecosystem entries; this                                                                                  source is OS-only.
  - Drop the dataSources map (not needed without language ecosystems) and
    the database_specific JSON parse + per-entry bucket rewrite (the                                                                                   ecosystem string already carries the version).
  - Flatten VulnSrcGetter: drop the unused config/logger wrapper.                                                                                    - In Get(), derive the platform key from newOSBucket(...).Name() instead
    of the hand-rolled platformFormat constant.
  - Test fixtures use the real feed shape; add CVSSv3 severity coverage.

Signed-off-by: Chai Tadmor <chai.tadmor@root.io>
chait-slim added 3 commits May 6, 2026 10:02
  Or if you want to be more explicit about what changed:

  refactor(rootio): replace cve_feed.json parser with OSV v1.6.0 walker

  I'd lean toward the first — it's a new capability (supporting the new vuln-list
  layout) rather than purely internal refactoring. The body could be:

  feat(rootio): migrate source to per-advisory OSV v1.6.0 format

  Replaces the monolithic cve_feed.json reader with a recursive
  fs.WalkDir over rootio/**/*.json. Each file is an OSV v1.6.0
  advisory. OS advisories are keyed by "root.io {distro} {version}";
  app advisories (npm, PyPI, etc.) are keyed by ecosystem name.
  Entries with empty affected[] or no fixed version are silently skipped.

Signed-off-by: Chai Tadmor <chai.tadmor@root.io>
  review feedback). A custom Transformer reads distro/distro_version
  from entry.DatabaseSpecific to build root.io OS buckets and drops
  advisories without a fixed version

Signed-off-by: Chai Tadmor <chai.tadmor@root.io>
…stems

                                                                          Addresses PR aquasecurity#657 review (DmitriyLewen, 2026-05-04) and aligns the
  parser with the actual root.io OSV feed (https://api.root.io/external/osv/all.zip).
  The feed emits ecosystem strings of the form "Root:<os>:<version>"                                                                                 (e.g. "Root:Alpine:3.18", "Root:Debian:11", "Root:Ubuntu:20.04").
  The OSV parser splits on the first ":" and looks up the resolver under                                                                             "root", passing "<os>:<version>" as the suffix — the previous Alpine/
  Debian/Ubuntu resolvers would never have matched.
  - Replace the three per-OS resolvers with a single resolveBucket(suffix)                                                                             in bucket.go that parses suffix into <os>+<version> and builds the
    Root.io bucket directly.                                                                                                                         - Reject suffixes without a version (Root:npm, Root:PyPI, Root:Maven,
    Root:Go) so the OSV parser skips language-ecosystem entries; this                                                                                  source is OS-only.
  - Drop the dataSources map (not needed without language ecosystems) and
    the database_specific JSON parse + per-entry bucket rewrite (the                                                                                   ecosystem string already carries the version).
  - Flatten VulnSrcGetter: drop the unused config/logger wrapper.                                                                                    - In Get(), derive the platform key from newOSBucket(...).Name() instead
    of the hand-rolled platformFormat constant.
  - Test fixtures use the real feed shape; add CVSSv3 severity coverage.

Signed-off-by: Chai Tadmor <chai.tadmor@root.io>
@chait-slim

Copy link
Copy Markdown
Contributor Author

@DmitriyLewen addressed all comments

@DmitriyLewen DmitriyLewen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you update PR description?

Also i left one question.

Comment thread pkg/vulnsrc/rootio/rootio_test.go Outdated
{
name: "happy path with unsupported OS",
dir: filepath.Join("testdata", "unsupported-os"),
// Skipped entries (empty affected, no fixed) must not create buckets

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could you elaborate on why you are skipping these CVEs (both with an empty affected and without a fixed version)?
Is this an internal root.io decision?
I assume that an empty affected means it is not yet known whether the package is vulnerable (correct me if I'm wrong), but I think we should still show vulnerabilities that don't have a fix yet, even if it's a potential vulnerability — users should be aware.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You're right that filtering these is questionable. The Root.io feed only publishes advisories where Root.io has shipped a patch: a "no fix" or "empty affected" entry shouldn't occur in real feed data, so the filter was just defensive code against malformed entries.
Removed it (and the test fixtures that only existed to exercise it).

chait-slim and others added 3 commits May 6, 2026 17:57
a patch, so a no-fix or empty-affected entry shouldn't occur in real
feed data. Filtering them silently was just defensive code; removing
it lets malformed entries surface instead of being swallowed.

Unfixed CVEs continue to reach users via the upstream OS source:
VulnSrcGetter.Get merges base-OS advisories first, then overlays
Root.io's patches on top.

Signed-off-by: Chai Tadmor <chai.tadmor@root.io>
Replace types.SourceID with ecosystem.Type for the baseOS parameter:
removes the awkward ecosystem.Type(strings.ToLower(string(...))) cast in
Get() and aligns with seal.NewVulnSrcGetter, which already takes
ecosystem.Type.
@DmitriyLewen

Copy link
Copy Markdown
Contributor

Hi @chait-slim
I updated the PR a bit:

Could you take a quick look?
Also, please review and fix the comments in aquasecurity/vuln-list-update#438.

Thanks in advance!

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.

2 participants