Skip to content

Fix fleetctl vulnerability-data-stream to download OSV data#44260

Merged
mostlikelee merged 4 commits intomainfrom
44242-fleetctl-vuln-data-stream-osv
Apr 30, 2026
Merged

Fix fleetctl vulnerability-data-stream to download OSV data#44260
mostlikelee merged 4 commits intomainfrom
44242-fleetctl-vuln-data-stream-osv

Conversation

@mostlikelee
Copy link
Copy Markdown
Contributor

@mostlikelee mostlikelee commented Apr 27, 2026

Related issue: Resolves #44242

Summary

fleetctl vulnerability-data-stream is documented as the way to pre-seed a Fleet server's vulnerability directory (common in air-gapped or restricted-egress deployments). It already downloads CPE, NVD, EPSS, CISA, OVAL, MSRC, and MacOffice feeds, but it never downloaded OSV (Ubuntu / RHEL) artifacts even though the server's vulnerability cron uses them. Operators ended up with a directory that was missing the artifacts powering Ubuntu (and, with RHELOSVForVulnerabilities, RHEL) vulnerability scanning.

Checklist for submitter

  • Changes file added for user-visible changes in changes/.
  • Input data is properly validated, SELECT * is avoided, SQL injection is prevented, JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters.
  • Timeouts are implemented and retries are limited to avoid infinite loops — reuses fleethttp.NewClient and the existing SyncOSV flow which already handles per-asset failure isolation.
  • If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes — N/A, no API surface changed; the CLI command flag set is unchanged.

Testing

  • Added/updated automated tests — unit tests in server/vulnerabilities/osv/sync_test.go cover the new helpers across happy-path, empty, and malformed-input cases.
  • Where appropriate, automated tests simulate multiple hosts and test for host isolation — N/A, the command is host-agnostic and runs without DB access.
  • QA'd all new/changed functionality manually — TODO before flipping out of draft: run fleetctl vulnerability-data-stream --dir /tmp/fleet-vuln against a clean dir and confirm osv-ubuntu-*.json.gz and osv-rhel-*.json.gz files appear alongside the existing CPE/NVD/OVAL/MSRC/MacOffice artifacts.

For unreleased bug fixes in a release candidate, one of:

  • Confirmed that the fix is not expected to adversely impact load test results — change is to a one-shot CLI download path, not the request hot path.

Summary by CodeRabbit

  • New Features

    • Enhanced fleetctl vulnerability-data-stream to download OSV vulnerability artifacts for Ubuntu and RHEL, and show a dedicated OSV download step.
  • Tests

    • Added and expanded tests covering OSV sync, version/date parsing, and integration checks to ensure OSV artifacts are written to disk.

Adds OSV (Ubuntu and RHEL) artifact downloads to the
`fleetctl vulnerability-data-stream` command. Previously the command
downloaded CPE, NVD, EPSS, CISA, OVAL, MSRC, and MacOffice feeds but
silently skipped OSV, leaving operators who pre-seed the vuln directory
without DB access (e.g. air-gapped) missing the artifacts that drive
Ubuntu and RHEL vulnerability scanning.

Adds an `osv.RefreshAll` entry point that downloads every Ubuntu and
RHEL artifact in the latest osv-processor release (no host-inventory
filtering), and wires it into `vulnerabilityDataStreamCommand`.
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 27, 2026

Codecov Report

❌ Patch coverage is 77.04918% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.83%. Comparing base (b471e24) to head (4aa583e).
⚠️ Report is 115 commits behind head on main.

Files with missing lines Patch % Lines
server/vulnerabilities/osv/sync.go 78.57% 6 Missing and 6 partials ⚠️
cmd/fleetctl/fleetctl/vulnerability_data_stream.go 60.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #44260      +/-   ##
==========================================
+ Coverage   66.73%   66.83%   +0.09%     
==========================================
  Files        2627     2631       +4     
  Lines      211192   211509     +317     
  Branches     9505     9505              
==========================================
+ Hits       140938   141355     +417     
+ Misses      57466    57305     -161     
- Partials    12788    12849      +61     
Flag Coverage Δ
backend 68.61% <77.04%> (+0.10%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mostlikelee
Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 28, 2026

✅ Actions performed

Full review triggered.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 28, 2026

Walkthrough

This PR adds OSV (Open Source Vulnerability) artifact downloading to fleetctl vulnerability-data-stream. It introduces an exported RefreshAll(ctx, vulnPath) in the OSV sync package that inspects the latest release assets, parses Ubuntu and RHEL version/date suffixes from asset filenames, and downloads matching osv-ubuntu-*.json.gz and osv-rhel-*.json.gz artifacts. The fleetctl command now calls this function and the integration test and unit tests were updated to verify OSV artifacts are downloaded and parsed.

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 43.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely captures the main change: adding OSV data downloads to the fleetctl vulnerability-data-stream command.
Description check ✅ Passed The PR description comprehensively addresses the template with a clear summary, issue reference, completed checklist items, testing details, and load test considerations.
Linked Issues check ✅ Passed The PR implementation meets all coding objectives from #44242: adds OSV downloads to fleetctl, introduces RefreshAll as a DB-less entry point, downloads all supported Ubuntu/RHEL versions, includes unit tests, and considers timeouts/retries.
Out of Scope Changes check ✅ Passed All changes are directly scoped to adding OSV download functionality to fleetctl and supporting infrastructure; no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 44242-fleetctl-vuln-data-stream-osv

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
cmd/fleetctl/integrationtest/vuln/vulnerability_data_stream_test.go (1)

21-31: Assert the OSV artifacts on disk, not just the new log line.

This update only proves the CLI printed Downloading OSV artifacts... Done. The test still passes if osv.RefreshAll becomes a no-op after logging success, which would miss the main regression this PR is fixing. Please add at least one filesystem assertion for both osv-ubuntu-*.json.gz and osv-rhel-*.json.gz.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/fleetctl/integrationtest/vuln/vulnerability_data_stream_test.go` around
lines 21 - 31, The test currently only asserts the CLI log line but not that
osv.RefreshAll actually wrote files; after invoking the code that triggers
downloads in vulnerability_data_stream_test.go (the test's command run), add
filesystem assertions that at least one file matching "osv-ubuntu-*.json.gz" and
one matching "osv-rhel-*.json.gz" exist in the directory used for OSV artifacts
(use the same test directory or dataDir variable the test uses), e.g. use
filepath.Glob to find matches and require that len(matches) > 0 or os.Stat to
verify a file exists; this guarantees osv.RefreshAll produced the expected
artifacts rather than just logging success.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@server/vulnerabilities/osv/sync.go`:
- Around line 163-178: The current calls to SyncOSV and syncRHELOSV only check
the returned error but ignore partial failures reported in result.Failed; update
the RefreshAll call site to treat any per-version failures as a hard error:
after calling SyncOSV or syncRHELOSV, if result.Failed is non-empty return the
accumulated downloaded list and an error describing which versions failed
(include result.Failed contents and contextual text like "failed to download OSV
for versions"). Keep references to SyncOSV, syncRHELOSV, and the
result.Downloaded/result.Failed fields so the change is applied to both Ubuntu
and RHEL branches.

---

Nitpick comments:
In `@cmd/fleetctl/integrationtest/vuln/vulnerability_data_stream_test.go`:
- Around line 21-31: The test currently only asserts the CLI log line but not
that osv.RefreshAll actually wrote files; after invoking the code that triggers
downloads in vulnerability_data_stream_test.go (the test's command run), add
filesystem assertions that at least one file matching "osv-ubuntu-*.json.gz" and
one matching "osv-rhel-*.json.gz" exist in the directory used for OSV artifacts
(use the same test directory or dataDir variable the test uses), e.g. use
filepath.Glob to find matches and require that len(matches) > 0 or os.Stat to
verify a file exists; this guarantees osv.RefreshAll produced the expected
artifacts rather than just logging success.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d4a61014-ac0b-4b88-8068-784e3dac2159

📥 Commits

Reviewing files that changed from the base of the PR and between 1c89b79 and da8c805.

📒 Files selected for processing (5)
  • changes/44242-fleetctl-vuln-data-stream-osv
  • cmd/fleetctl/fleetctl/vulnerability_data_stream.go
  • cmd/fleetctl/integrationtest/vuln/vulnerability_data_stream_test.go
  • server/vulnerabilities/osv/sync.go
  • server/vulnerabilities/osv/sync_test.go

Comment thread server/vulnerabilities/osv/sync.go
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes fleetctl vulnerability-data-stream so it also pre-seeds OSV (Ubuntu + RHEL) vulnerability artifacts, aligning the CLI’s “air-gapped preseed” behavior with what the server-side vulnerability cron expects.

Changes:

  • Add osv.RefreshAll to download all OSV artifacts from the latest release without relying on host inventory/DB access.
  • Extend OSV sync helpers to derive versions + release date from release asset names.
  • Update fleetctl integration test expected output and add unit tests covering the new OSV helper behavior.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
server/vulnerabilities/osv/sync.go Adds RefreshAll and helpers to download all OSV artifacts from the latest release.
server/vulnerabilities/osv/sync_test.go Adds tests for partial-failure behavior and new release parsing helpers.
cmd/fleetctl/fleetctl/vulnerability_data_stream.go Invokes osv.RefreshAll as part of vulnerability-data-stream.
cmd/fleetctl/integrationtest/vuln/vulnerability_data_stream_test.go Updates expected CLI output to include OSV download step.
changes/44242-fleetctl-vuln-data-stream-osv Adds changelog entry for the user-visible fix.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cmd/fleetctl/integrationtest/vuln/vulnerability_data_stream_test.go
@mostlikelee mostlikelee marked this pull request as ready for review April 29, 2026 12:12
@mostlikelee mostlikelee requested a review from a team as a code owner April 29, 2026 12:12
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@qodo-code-review
Copy link
Copy Markdown

ⓘ You've reached your Qodo monthly free-tier limit. Reviews pause until next month — upgrade your plan to continue now, or link your paid account if you already have one.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
server/vulnerabilities/osv/sync.go (2)

163-184: Prefer aggregating Ubuntu/RHEL failures instead of early-returning after Ubuntu.

Line 170 currently exits before attempting RHEL sync when Ubuntu has partial failures. Continuing both syncs and returning a combined error would maximize artifacts written in a single run while still failing the command.

Proposed refactor
 	var downloaded []string
+	var failures []string
 	if len(ubuntuVers) > 0 {
 		result, err := SyncOSV(ctx, vulnPath, ubuntuVers, releaseDate, release)
 		if err != nil {
 			return downloaded, fmt.Errorf("syncing Ubuntu OSV artifacts: %w", err)
 		}
 		downloaded = append(downloaded, result.Downloaded...)
 		if len(result.Failed) > 0 {
-			return downloaded, fmt.Errorf("failed to download OSV for Ubuntu versions: %v", result.Failed)
+			failures = append(failures, fmt.Sprintf("Ubuntu: %v", result.Failed))
 		}
 	}
 
 	if len(rhelVers) > 0 {
 		result, err := syncRHELOSV(ctx, vulnPath, rhelVers, releaseDate, release)
 		if err != nil {
 			return downloaded, fmt.Errorf("syncing RHEL OSV artifacts: %w", err)
 		}
 		downloaded = append(downloaded, result.Downloaded...)
 		if len(result.Failed) > 0 {
-			return downloaded, fmt.Errorf("failed to download OSV for RHEL versions: %v", result.Failed)
+			failures = append(failures, fmt.Sprintf("RHEL: %v", result.Failed))
 		}
 	}
 
+	if len(failures) > 0 {
+		return downloaded, fmt.Errorf("failed to download OSV artifacts for %s", strings.Join(failures, "; "))
+	}
+
 	return downloaded, nil
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/vulnerabilities/osv/sync.go` around lines 163 - 184, The current flow
in SyncOSV/syncRHELOSV handling returns early when Ubuntu downloads have
failures, preventing RHEL sync from running; change the logic in the block that
calls SyncOSV and syncRHELOSV (symbols: SyncOSV, syncRHELOSV, downloaded,
result.Downloaded, result.Failed) to always attempt both syncs, append each
result.Downloaded to downloaded, collect any result.Failed entries from both
calls into a single failures slice, and after both calls complete, if failures
is non-empty return downloaded with a combined error listing all failed
versions; preserve existing error wrapping for fatal call errors but do not
early-return on partial failures.

192-206: Consider dedup + stable sort of extracted versions for deterministic behavior.

versionsFromRelease iterates a map, so output order is non-deterministic and may include duplicates if release assets evolve. Deduping and sorting makes logs/errors/tests more stable.

Proposed refactor
 import (
 	"context"
 	"fmt"
 	"os"
 	"path/filepath"
+	"sort"
 	"strings"
 	"time"
@@
 func versionsFromRelease(release *ReleaseInfo) (ubuntu []string, rhel []string) {
+	ubuntuSet := make(map[string]struct{})
+	rhelSet := make(map[string]struct{})
+
 	for assetName := range release.Assets {
 		switch {
 		case strings.HasPrefix(assetName, OSVFilePrefix):
 			if v := versionFromAssetName(assetName, OSVFilePrefix); v != "" {
-				ubuntu = append(ubuntu, v)
+				ubuntuSet[v] = struct{}{}
 			}
 		case strings.HasPrefix(assetName, OSVRHELFilePrefix):
 			if v := versionFromAssetName(assetName, OSVRHELFilePrefix); v != "" {
-				rhel = append(rhel, v)
+				rhelSet[v] = struct{}{}
 			}
 		}
 	}
+
+	for v := range ubuntuSet {
+		ubuntu = append(ubuntu, v)
+	}
+	for v := range rhelSet {
+		rhel = append(rhel, v)
+	}
+	sort.Strings(ubuntu)
+	sort.Strings(rhel)
+
 	return ubuntu, rhel
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/vulnerabilities/osv/sync.go` around lines 192 - 206,
versionsFromRelease currently collects versions by iterating ReleaseInfo.Assets
(a map) which yields non-deterministic ordering and may produce duplicates;
change it to deduplicate and deterministically sort the ubuntu and rhel slices
before returning: use a small set (map[string]struct{}) when calling
versionFromAssetName for OSVFilePrefix and OSVRHELFilePrefix to collect unique
versions, then convert each set to a slice and apply a stable sort (e.g.,
sort.Strings) before returning; keep the existing function names
(versionsFromRelease, versionFromAssetName) and asset prefix checks
(OSVFilePrefix, OSVRHELFilePrefix) to locate where to implement this.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@server/vulnerabilities/osv/sync.go`:
- Around line 163-184: The current flow in SyncOSV/syncRHELOSV handling returns
early when Ubuntu downloads have failures, preventing RHEL sync from running;
change the logic in the block that calls SyncOSV and syncRHELOSV (symbols:
SyncOSV, syncRHELOSV, downloaded, result.Downloaded, result.Failed) to always
attempt both syncs, append each result.Downloaded to downloaded, collect any
result.Failed entries from both calls into a single failures slice, and after
both calls complete, if failures is non-empty return downloaded with a combined
error listing all failed versions; preserve existing error wrapping for fatal
call errors but do not early-return on partial failures.
- Around line 192-206: versionsFromRelease currently collects versions by
iterating ReleaseInfo.Assets (a map) which yields non-deterministic ordering and
may produce duplicates; change it to deduplicate and deterministically sort the
ubuntu and rhel slices before returning: use a small set (map[string]struct{})
when calling versionFromAssetName for OSVFilePrefix and OSVRHELFilePrefix to
collect unique versions, then convert each set to a slice and apply a stable
sort (e.g., sort.Strings) before returning; keep the existing function names
(versionsFromRelease, versionFromAssetName) and asset prefix checks
(OSVFilePrefix, OSVRHELFilePrefix) to locate where to implement this.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a50c347c-5c61-41cc-9e6c-37419c4f4ec5

📥 Commits

Reviewing files that changed from the base of the PR and between da8c805 and 4aa583e.

📒 Files selected for processing (3)
  • cmd/fleetctl/integrationtest/vuln/vulnerability_data_stream_test.go
  • server/vulnerabilities/osv/sync.go
  • server/vulnerabilities/osv/sync_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • cmd/fleetctl/integrationtest/vuln/vulnerability_data_stream_test.go

Copy link
Copy Markdown
Member

@dantecatalfamo dantecatalfamo left a comment

Choose a reason for hiding this comment

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

⬇️ 🐛

@mostlikelee mostlikelee merged commit 2d586cb into main Apr 30, 2026
54 checks passed
@mostlikelee mostlikelee deleted the 44242-fleetctl-vuln-data-stream-osv branch April 30, 2026 16:46
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.

Bug: fleetctl vulnerability-data-stream does not download OSV data (Ubuntu/RHEL)

3 participants