Skip to content

Add source-agnostic RHEL vulnerability integration tests - #43185

Merged
mostlikelee merged 9 commits into
mainfrom
tlee/43182-vuln-integration-tests
Apr 11, 2026
Merged

Add source-agnostic RHEL vulnerability integration tests#43185
mostlikelee merged 9 commits into
mainfrom
tlee/43182-vuln-integration-tests

Conversation

@mostlikelee

@mostlikelee mostlikelee commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

Resolves #43182

Summary

  • Adds server/vulnerabilities/vulntest/ package with a Scanner abstraction that decouples integration tests from the vulnerability data source (OVAL/OSV)
  • Expands test coverage from the existing hand-crafted fixtures (~20 packages per RHEL version) to the full OVAL feed: 2722 packages / 2888 CVEs for RHEL 8 and 2594 packages / 2593 CVEs for RHEL 9 — software fixtures are derived directly from the OVAL definitions, not hand-crafted
  • Per-package CVE assertions verify correct attribution (e.g. curl CVEs aren't attributed to openssl)
  • No changes to existing oval/ or goval_dictionary/ packages

Changes

New package: server/vulnerabilities/vulntest/

File Purpose
vulntest.go Scanner type, VulnFixture (software→CVE mapping), RunAndAssert with per-package assertions, legacy helpers for existing oval/analyzer_test.go
scanners.go OVALScanner() and GovalDictionaryScanner() factory functions that wrap the existing analyzers behind the Scanner interface
vulnerability_scanning_test.go Table-driven integration tests parameterized by scanner
gen_fixture_test.go Fixture generator (gated behind GENERATE_FIXTURES=1) that extracts vulnerable packages from OVAL definitions and captures per-package CVE mappings

New test fixtures

File Description
testdata/rhel/2026/rhel_08-oval_def.json.bz2 RHEL 8 OVAL definitions (2026-04-07 snapshot)
testdata/rhel/2026/rhel_09-oval_def.json.bz2 RHEL 9 OVAL definitions (2026-04-07 snapshot)
testdata/rhel/software/0810/rhel_08-vulns.json.bz2 RHEL 8.10: 2722 packages → 2888 CVEs
testdata/rhel/software/0904/rhel_09-vulns.json.bz2 RHEL 9.4: 2594 packages → 2593 CVEs

How OSV plugs in later

When RHEL OSV is implemented, the only changes needed are:

  1. Add OSV artifacts to testdata/rhel/osv/
  2. Add OSVScanner() factory in scanners.go
  3. Uncomment vulntest.OSVScanner() in the test's scanners slice

Same fixtures, same assertions — zero test data changes.

Test plan

  • MYSQL_TEST=1 go test -run TestRHELVulnerabilityScanning ./server/vulnerabilities/vulntest/... — verifies per-package CVE mappings for RHEL 8.10 and 9.4
  • MYSQL_TEST=1 go test -run TestRHELKernelVulnerabilities ./server/vulnerabilities/vulntest/... — verifies goval-dictionary kernel scanning (vulnerable + patched)
  • MYSQL_TEST=1 go test -run TestOvalAnalyzer ./server/vulnerabilities/oval/... — existing tests pass unchanged
  • make lint-go — passes

Summary by CodeRabbit

  • Tests
    • Added comprehensive testing infrastructure for RHEL vulnerability scanning.
    • Enabled testing against multiple vulnerability data sources.
    • Introduced fixture generation and validation utilities for vulnerability testing.
    • Expanded test coverage for RHEL 8.10 and 9.4 systems.

Tim Lee added 2 commits April 7, 2026 15:11
Adds integration tests for RHEL vulnerability scanning that are decoupled
from the data source (OVAL/OSV) via a Scanner abstraction. The same software
fixtures and per-package CVE mappings can verify both OVAL today and OSV
after migration without modifying test data.

- Scanner type abstracts setup + analyze so tests are parameterized by scanner
- OVALScanner and GovalDictionaryScanner wrap existing analyzers
- Software fixtures derived from OVAL feeds (2722 packages for RHEL 8, 2594 for RHEL 9)
- Per-package CVE assertions verify correct attribution (not just total count)
- No changes to existing oval/ or goval_dictionary/ packages
@mostlikelee

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Apr 7, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@coderabbitai

coderabbitai Bot commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Introduces vulnerability scanning integration test infrastructure comprising a test helper package (vulntest), two scanner implementations for OVAL and goval-dictionary sources, a fixture-generation test, and integration tests for RHEL vulnerability scanning. The helper package provides abstractions for defining scanners, loading test fixtures, seeding hosts with software, and asserting vulnerabilities. The fixture-generation test conditionally creates OVAL-derived vulnerability test data by parsing OVAL definitions, computing vulnerable package versions, and storing generated fixtures. Integration tests exercise RHEL 8.10 and 9.4 vulnerability scanning pipelines against MySQL datastore instances.

Possibly related PRs

  • Vulnerabilities cron optimization #39820: Implements datastore APIs for vulnerability management (ListSoftwareVulnerabilitiesByHostIDsSource, batch vulnerability inserts) that are directly called by the new test helpers and scanner implementations.
  • 33990 scan goval #39749: Adds RHEL kernel vulnerability scanning with goval-dictionary support, sharing kernel-specific vulnerability analysis with the newly introduced test infrastructure.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add source-agnostic RHEL vulnerability integration tests' clearly summarizes the main change: introduction of scanner-agnostic integration tests that can work with multiple vulnerability data sources.
Description check ✅ Passed The PR description is comprehensive and complete. It clearly addresses the linked issue, provides detailed summary of changes including the new vulntest package, test fixtures, and explains how OSV will plug in. It includes a test plan confirming validation.
Linked Issues check ✅ Passed The PR fully addresses both objectives from issue #43182: (1) expands test coverage from ~20 hand-crafted packages to full OVAL feeds (2722 packages for RHEL 8, 2594 for RHEL 9), and (2) abstracts integration tests via the Scanner abstraction to support OVAL and upcoming OSV sources.
Out of Scope Changes check ✅ Passed All changes are in-scope: the new vulntest package, scanners, integration tests, fixture generation, and test data are directly aligned with the stated objectives. PR explicitly notes no changes to existing oval/ or goval_dictionary/ packages.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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 tlee/43182-vuln-integration-tests

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

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

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (3)
server/vulnerabilities/vulntest/gen_fixture_test.go (2)

245-248: External bzip2 dependency for compression.

Shelling out to bzip2 requires the binary to be installed. This is reasonable since Go's compress/bzip2 only supports reading, not writing. Consider documenting this dependency in the test comment or adding a check for the binary's existence with a helpful error message.

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

In `@server/vulnerabilities/vulntest/gen_fixture_test.go` around lines 245 - 248,
The test currently shells out to the external bzip2 binary via
exec.Command("bzip2", "-f", jsonPath) and will fail if bzip2 isn't installed;
update the test to check for the binary before invoking it and give a clear
error message (e.g., use exec.LookPath("bzip2") or similar) and/or add a test
comment documenting that bzip2 is required; reference the existing usage of
exec.Command, jsonPath and sys.outPath so the check runs before calling
exec.Command and the error message mentions bzip2 and the affected test artifact
paths.

99-107: Edge case: decrement logic may produce unexpected results for certain release strings.

The decrement logic only handles digits '1'-'9' and skips leading zeros followed by non-dots. If a release string has all zeros or starts with '0' followed by a digit (e.g., "0.1.el9"), the logic may not decrement correctly and could return the original release unchanged.

This is acceptable for fixture generation since OVAL data typically has normal release numbers, but worth documenting or adding a fallback.

server/vulnerabilities/vulntest/vulntest.go (1)

103-153: Consider extracting shared host creation logic to reduce duplication.

LoadSoftwareFromFixture and LoadSoftware share identical host creation and CPE upsert logic. Consider extracting a shared helper for host creation that accepts a software slice.

♻️ Suggested refactor to reduce duplication
// createHostWithSoftware creates a host and populates it with the given software.
func createHostWithSoftware(
	ds *mysql.Datastore,
	platformStr string,
	ver fleet.OSVersion,
	software []fleet.Software,
	t require.TestingT,
) *fleet.Host {
	osqueryHostID, err := server.GenerateRandomText(10)
	require.NoError(t, err)

	ctx := context.Background()

	h, err := ds.NewHost(ctx, &fleet.Host{
		Hostname:        platformStr,
		NodeKey:         ptr.String(platformStr),
		UUID:            platformStr,
		DetailUpdatedAt: time.Now(),
		LabelUpdatedAt:  time.Now(),
		PolicyUpdatedAt: time.Now(),
		SeenTime:        time.Now(),
		OsqueryHostID:   &osqueryHostID,
		Platform:        ver.Platform,
		OSVersion:       ver.Name,
	})
	require.NoError(t, err)

	_, err = ds.UpdateHostSoftware(ctx, h.ID, software)
	require.NoError(t, err)

	err = ds.LoadHostSoftware(ctx, h, false)
	require.NoError(t, err)

	var cpes []fleet.SoftwareCPE
	for _, s := range h.Software {
		cpes = append(cpes, fleet.SoftwareCPE{SoftwareID: s.ID, CPE: fmt.Sprintf("%s-%s", s.Name, s.Version)})
	}
	_, err = ds.UpsertSoftwareCPEs(ctx, cpes)
	require.NoError(t, err)

	return h
}

Then LoadSoftwareFromFixture and LoadSoftware can delegate to this helper.

Also applies to: 231-289

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

In `@server/vulnerabilities/vulntest/vulntest.go` around lines 103 - 153,
LoadSoftwareFromFixture and LoadSoftware duplicate host-creation, software
update, LoadHostSoftware and CPE upsert logic; extract that shared logic into a
helper (e.g., createHostWithSoftware) that takes (ds *mysql.Datastore,
platformStr string, ver fleet.OSVersion, software []fleet.Software, t
require.TestingT) and inside it call server.GenerateRandomText, ds.NewHost,
ds.UpdateHostSoftware, ds.LoadHostSoftware and ds.UpsertSoftwareCPEs to populate
CPEs; then have LoadSoftwareFromFixture and LoadSoftware build their software
slice (or convert fixture output) and delegate to createHostWithSoftware to
remove duplication.
🤖 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/vulntest/gen_fixture_test.go`:
- Around line 38-50: Remove the unused file handle: delete the os.Open(defPath)
call and its associated variable f and defer f.Close() in gen_fixture_test.go,
since ExtractBzip2(defPath, tmpJSON, t) reads the file itself; ensure defPath,
tmpJSON, ovalDef and the subsequent ReadFile/Unmarshal remain unchanged (or if
you intended to assert the file exists, replace the os.Open with
os.Stat(defPath) instead).

---

Nitpick comments:
In `@server/vulnerabilities/vulntest/gen_fixture_test.go`:
- Around line 245-248: The test currently shells out to the external bzip2
binary via exec.Command("bzip2", "-f", jsonPath) and will fail if bzip2 isn't
installed; update the test to check for the binary before invoking it and give a
clear error message (e.g., use exec.LookPath("bzip2") or similar) and/or add a
test comment documenting that bzip2 is required; reference the existing usage of
exec.Command, jsonPath and sys.outPath so the check runs before calling
exec.Command and the error message mentions bzip2 and the affected test artifact
paths.

In `@server/vulnerabilities/vulntest/vulntest.go`:
- Around line 103-153: LoadSoftwareFromFixture and LoadSoftware duplicate
host-creation, software update, LoadHostSoftware and CPE upsert logic; extract
that shared logic into a helper (e.g., createHostWithSoftware) that takes (ds
*mysql.Datastore, platformStr string, ver fleet.OSVersion, software
[]fleet.Software, t require.TestingT) and inside it call
server.GenerateRandomText, ds.NewHost, ds.UpdateHostSoftware,
ds.LoadHostSoftware and ds.UpsertSoftwareCPEs to populate CPEs; then have
LoadSoftwareFromFixture and LoadSoftware build their software slice (or convert
fixture output) and delegate to createHostWithSoftware to remove duplication.
🪄 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: 6fbf6d86-aad0-4299-8b0f-13ee05743f2f

📥 Commits

Reviewing files that changed from the base of the PR and between 6e3648a and e4289b8.

⛔ Files ignored due to path filters (4)
  • server/vulnerabilities/testdata/rhel/2026/rhel_08-oval_def.json.bz2 is excluded by !**/*.bz2
  • server/vulnerabilities/testdata/rhel/2026/rhel_09-oval_def.json.bz2 is excluded by !**/*.bz2
  • server/vulnerabilities/testdata/rhel/software/0810/rhel_08-vulns.json.bz2 is excluded by !**/*.bz2
  • server/vulnerabilities/testdata/rhel/software/0904/rhel_09-vulns.json.bz2 is excluded by !**/*.bz2
📒 Files selected for processing (4)
  • server/vulnerabilities/vulntest/gen_fixture_test.go
  • server/vulnerabilities/vulntest/scanners.go
  • server/vulnerabilities/vulntest/vulnerability_scanning_test.go
  • server/vulnerabilities/vulntest/vulntest.go

Comment thread server/vulnerabilities/vulntest/gen_fixture_test.go Outdated
@@ -0,0 +1,253 @@
package vulntest_test

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.

this is the fixture generator. I expect we'll remove this once we feel confident that the OSV transition is stable. A deep review is probably not needed here.

@codecov

codecov Bot commented Apr 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 71.36150% with 61 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.89%. Comparing base (ef119bd) to head (1a98967).
⚠️ Report is 206 commits behind head on main.

Files with missing lines Patch % Lines
server/vulnerabilities/vulntest/vulntest.go 63.25% 59 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #43185      +/-   ##
==========================================
+ Coverage   66.86%   66.89%   +0.02%     
==========================================
  Files        2578     2588      +10     
  Lines      206869   207518     +649     
  Branches     9283     9283              
==========================================
+ Hits       138328   138824     +496     
- Misses      55978    56071      +93     
- Partials    12563    12623      +60     
Flag Coverage Δ
backend 68.66% <71.36%> (+0.02%) ⬆️

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.

Copilot AI 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.

Pull request overview

This PR introduces a new server/vulnerabilities/vulntest helper package to run source-agnostic RHEL vulnerability scanning integration tests (OVAL now, OSV later) using large, feed-derived fixtures.

Changes:

  • Added a Scanner abstraction plus shared fixture loading + assertion helpers for vulnerability integration tests.
  • Added table-driven RHEL integration tests that run against a scanner implementation (currently OVAL) and verify per-package CVE mappings.
  • Added a gated fixture generator test and new large bzip2-compressed fixtures for RHEL 8.10 and 9.4.

Reviewed changes

Copilot reviewed 4 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
server/vulnerabilities/vulntest/vulntest.go New shared helpers: scanner interface, fixture formats, host/software loading, and assertion logic.
server/vulnerabilities/vulntest/scanners.go Scanner implementations wrapping existing OVAL and goval-dictionary analyzers.
server/vulnerabilities/vulntest/vulnerability_scanning_test.go New integration tests for RHEL package + kernel vulnerability scanning using the scanner abstraction.
server/vulnerabilities/vulntest/gen_fixture_test.go Gated fixture generation test to derive vulnerable package fixtures from OVAL definitions.
server/vulnerabilities/testdata/rhel/software/0810/rhel_08-vulns.json.bz2 New large RHEL 8.10 software→CVE fixture.
server/vulnerabilities/testdata/rhel/software/0904/rhel_09-vulns.json.bz2 New large RHEL 9.4 software→CVE fixture.

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

Comment thread server/vulnerabilities/vulntest/scanners.go
Comment thread server/vulnerabilities/vulntest/gen_fixture_test.go
Comment thread server/vulnerabilities/vulntest/vulntest.go
@mostlikelee
mostlikelee marked this pull request as ready for review April 8, 2026 15:27
@mostlikelee
mostlikelee requested a review from a team as a code owner April 8, 2026 15:27

@claude claude Bot left a comment

Copy link
Copy Markdown

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.

@mostlikelee
mostlikelee merged commit 65d1981 into main Apr 11, 2026
68 of 70 checks passed
@mostlikelee
mostlikelee deleted the tlee/43182-vuln-integration-tests branch April 11, 2026 19:43
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.

Expand and abstract integration tests

3 participants