dbtest

package
v0.115.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 26, 2026 License: Apache-2.0 Imports: 48 Imported by: 0

README

dbtest - Database Testing Utilities

This package provides utilities for building and testing grype vulnerability databases from fixture data, along with fluent assertion helpers that decouple test code from internal API shapes.

Quick Start

Using Fixtures in Tests
func TestVulnerabilityMatching(t *testing.T) {
    // use a fixture from your package's testdata directory
    dbtest.DBs(t, "my-fixture").Run(func(t *testing.T, db *dbtest.DB) {
        // db implements vulnerability.Provider
        vulns, err := db.FindVulnerabilities(...)
    })
}

func TestWithSharedFixture(t *testing.T) {
    // use a fixture from internal/dbtest/testdata/shared/
    dbtest.SharedDBs(t, "all").Run(func(t *testing.T, db *dbtest.DB) {
        // db.Match returns a FindingsAssertion for fluent assertions
        db.Match(t, matcher, pkg).
            SelectMatch("CVE-2024-1234").
            SelectDetailByType(match.ExactDirectMatch).
            AsDistroSearch()
    })
}
Filtering Fixtures at Test Time
// only include specific CVEs from a larger fixture
dbtest.SharedDBs(t, "all").
    SelectOnly("CVE-2024-1234", "CVE-2024-5678").
    Run(func(t *testing.T, db *dbtest.DB) {
        // db only contains the selected CVEs
    })

Motivation

Testing grype's vulnerability matching requires realistic database fixtures. However, real vunnel caches can contain millions of records, making them impractical for test fixtures. This package solves several problems:

  1. Focused fixtures: Extract only the specific CVEs or namespaces needed for a test scenario
  2. Deterministic tests: Create reproducible fixtures from real vunnel data
  3. Easy maintenance: Append new records to existing fixtures as test cases evolve
  4. Cross-package sharing: Share fixtures between test packages via SharedDBs()
  5. Fixture provenance: Track how fixtures were created and regenerate them when needed
  6. API-agnostic assertions: Decouple test assertions from internal data structures to survive refactors

Go API

Building Test Databases

The Builder type provides a fluent API for building test databases from fixtures:

// DBs looks for testdata/<name> relative to the calling test file
func DBs(t *testing.T, fixtureName string) *Builder

// SharedDBs looks for fixtures in internal/dbtest/testdata/shared/<name>
func SharedDBs(t *testing.T, fixtureName string) *Builder

// SelectOnly filters which records are included (patterns combined with OR)
func (b *Builder) SelectOnly(patterns ...string) *Builder

// Run executes a test function for each schema version
func (b *Builder) Run(fn func(t *testing.T, db *DB))

// Build returns databases without running them through t.Run
func (b *Builder) Build(schemas ...int) []*DB
The DB Type

DB wraps a vulnerability.Provider with test metadata:

type DB struct {
    Name          string  // e.g., "v6"
    SchemaVersion int
    Path          string
}

// implements vulnerability.Provider
func (db *DB) FindVulnerabilities(criteria ...vulnerability.Criteria) ([]vulnerability.Vulnerability, error)
func (db *DB) VulnerabilityMetadata(ref vulnerability.Reference) (*vulnerability.Metadata, error)
func (db *DB) PackageSearchNames(p grypePkg.Package) []string

// runs matcher and returns fluent assertion chain
func (db *DB) Match(t *testing.T, matcher Matcher, p grypePkg.Package) *FindingsAssertion
Fluent Assertions

The assertion helpers provide a string-based, API-agnostic way to validate match results. This design has several benefits:

  • Survives refactors: Tests don't break when internal struct shapes change (e.g., grype v1 API changes)
  • Removes boilerplate: No need to manually iterate matches/details or check types
  • Completeness checking: By default, tests fail if any matches or details are not asserted
  • Readable tests: Fluent chains clearly express what's being validated

This approach is similar to syft's pkgtest helpers - abstracting test assertions from implementation details.

Basic Usage
// match and assert in one fluent chain
db.Match(t, &matcher, pkg).
    SelectMatch("CVE-2024-1234").
    SelectDetailByType(match.ExactDirectMatch).
    AsDistroSearch("< 1.0.0")  // validates constraint

// or use AssertFindings directly with pre-existing matches
dbtest.AssertFindings(t, matches, pkg).
    HasCount(2).
    OnlyHasVulnerabilities("CVE-2024-1234", "CVE-2024-5678")
Completeness Checking

By default, assertions require that all matches and details are asserted. This catches cases where a matcher returns unexpected results:

// this will fail if there are matches other than CVE-2024-1234
db.Match(t, &matcher, pkg).
    SelectMatch("CVE-2024-1234").
    SelectDetailByType().
    AsDistroSearch()

SkipCompleteness() inverts the contract: it asserts the chain is intentionally partial, and fails if every match and detail ended up being asserted on anyway. This keeps SkipCompleteness calls from rotting in tests that have grown into being exhaustive — drop the call once your chain covers everything:

// passes: only CVE-2024-1234 was asserted, others left alone
db.Match(t, &matcher, pkg).SkipCompleteness().
    ContainsVulnerabilities("CVE-2024-1234")

// fails: SkipCompleteness was called but the chain ended up exhaustive,
// so the SkipCompleteness call is dead weight and should be removed
db.Match(t, &matcher, pkg).SkipCompleteness().
    SelectMatch("CVE-2024-1234").
    SelectDetailByType().
    AsDistroSearch()

The same inversion applies to Ignores().SkipCompleteness().

Detail Assertions

After selecting a match, drill into details by type or search parameters:

// select by match type
findings.SelectMatch("CVE-2024-1234").
    SelectDetailByType(match.ExactDirectMatch).
    AsDistroSearch()

// select by distro (when multiple distro details exist)
findings.SelectMatch("CVE-2024-1234").
    SelectDetailByDistro("debian", "11", "< 1.0.0")

// select by CPE
findings.SelectMatch("CVE-2024-1234").
    SelectDetailByCPE("cpe:2.3:a:vendor:product:1.0:*:*:*:*:*:*:*").
    FoundCPEs("cpe:2.3:a:vendor:product:*:*:*:*:*:*:*:*")

// select by ecosystem/language
findings.SelectMatch("CVE-2024-1234").
    SelectDetailByEcosystem("python", "< 2.0.0")
Available Assertions
Method Description
IsEmpty() Assert the matcher produced nothing — no matches AND no ignore filters
ContainsVulnerabilities(ids...) Assert these CVEs are present (others may exist)
OnlyHasVulnerabilities(ids...) Assert exactly these CVEs and no others
DoesNotHaveAnyVulnerabilities(ids...) Assert these CVEs are not present
SelectMatch(id) Select a specific match for detail assertions; fails if multiple matches share the ID
SelectMatches(id) Select the subset of matches with a vulnerability ID; chain WithDetailType to disambiguate
HasMatchType(type) Assert at least one detail has this match type
HasOnlyMatchTypes(types...) Assert all details have one of these types
SkipCompleteness() Assert this chain is intentionally partial; fails if the chain is actually exhaustive

IsEmpty() covers the whole result — both matches and ignore filters. For tests that expect zero matches but ≥1 ignore filter, just skip IsEmpty() and assert on the ignores via Ignores(); matches-side completeness checking will still enforce that no matches were produced.

For ignore filters, Ignores().SelectRelatedPackageIgnore(reason, vulnID) selects one ignore for fine-grained assertions; Ignores().SelectRelatedPackageIgnores(reason, vulnIDs...) selects a batch sharing a reason and fans ForPackage/WithRelationshipType over all of them — useful for AlmaLinux alias unwinding where one ALSA emits ignores for itself plus each aliased CVE.

Ignore-completeness is on by default — every matcher-emitted ignore must be asserted on, even by tests that never call Ignores() explicitly. Tests that produce zero ignores don't need Ignores().IsEmpty() boilerplate; the completeness check fails if any unasserted ignore is emitted.

Extending the API (no escape hatches)

The assertion API is a façade over match.Match and vulnerability.Vulnerability. The whole point is to let grype refactor those internal types without touching tests. Two consequences:

  • There is no Match() accessor on SingleFindingAssertion and there should never be one. FindingsAssertion.Matches() exists as a deprecated escape hatch and is not used anywhere — leave it that way.
  • When a test needs a new assertion, add a focused helper. That is the documented extension story. HasFix, HasAdvisories, InNamespace, SelectMatches.WithDetailType, SelectDetailBy{Distro,CPE,Ecosystem}, SelectRelatedPackageIgnores were all added this way. Hypothetical future helpers: HasSeverity, HasCVSSScore, HasRelatedVulnerabilities, HasFixAvailableDate.

If you find yourself reaching for raw struct fields, stop and add the helper. A 5-line addition to assertions.go is cheaper than a 50-test sweep next time the underlying struct moves.

Universe-level vs. element-level assertions

When the chain ends in one or more SelectMatch / SelectMatches calls that fully cover the universe, universe-level assertions (ContainsVulnerabilities, OnlyHasVulnerabilities) are dead weight — completeness checking already proves them. Drop them:

// dead weight - ContainsVulnerabilities is subsumed by SelectMatch + completeness
findings := db.Match(t, &matcher, p).
    ContainsVulnerabilities("CVE-2024-0340")
findings.SelectMatch("CVE-2024-0340")...

// preferred
findings := db.Match(t, &matcher, p)
findings.SelectMatch("CVE-2024-0340")...

The same logic applies to Ignores(): with ignore-completeness on by default, any explicit ignore-side count assertion is subsumed by the exhaustive SelectRelatedPackageIgnore/SelectRelatedPackageIgnores chain. There is intentionally no HasCount method on any of these assertion types — if the count matters, prove it by asserting on each entry.

Extracting Fixtures from Vunnel Cache

Use FixtureExtractor to create fixtures from a vunnel data directory:

extractor := dbtest.NewFixtureExtractor("/path/to/vunnel/data")

// extract to new fixture
err := extractor.
    From("debian").
    Select("CVE-2024-1234", "debian:10").
    WriteTo("internal/dbtest/testdata/shared/my-fixture")

// append to existing fixture
err := extractor.
    From("rhel").
    Select("RHSA-2024:").
    AppendTo("internal/dbtest/testdata/shared/my-fixture")

// multi-provider extraction
err := extractor.
    FromMultiple().
    Provider("debian", "CVE-2024-1234").
    Provider("nvd", "CVE-2024-1234").
    WriteTo("internal/dbtest/testdata/shared/multi-provider")

CLI Tool

The manager CLI provides commands for creating and maintaining fixtures.

Extract Command

Create fixtures from vunnel SQLite caches:

# extract specific CVEs
go run ./internal/dbtest/cmd/manager extract \
    --vunnel-data ~/vunnel/data \
    --provider debian \
    --select "CVE-2024-1234" \
    --output internal/dbtest/testdata/shared/my-fixture

# extract by namespace (all CVEs in debian:11)
go run ./internal/dbtest/cmd/manager extract \
    --vunnel-data ~/vunnel/data \
    --provider debian \
    --select "debian:11" \
    --output internal/dbtest/testdata/shared/debian11-vulns

# extract with multiple patterns (OR logic)
go run ./internal/dbtest/cmd/manager extract \
    --vunnel-data ~/vunnel/data \
    --provider debian \
    --select "CVE-2024-1234" --select "CVE-2024-5678" \
    --output internal/dbtest/testdata/shared/specific-cves

# append to existing fixture
go run ./internal/dbtest/cmd/manager extract \
    --vunnel-data ~/vunnel/data \
    --provider rhel \
    --select "RHSA-2024:" \
    --append internal/dbtest/testdata/shared/my-fixture

# extract from multiple providers
go run ./internal/dbtest/cmd/manager extract \
    --vunnel-data ~/vunnel/data \
    --provider debian --provider nvd \
    --select "CVE-2024-1234" \
    --output internal/dbtest/testdata/shared/multi-provider
Flag Description
--vunnel-data Path to vunnel data directory (required)
--provider Provider name to extract from (repeatable)
--select Pattern for record selection (repeatable)
--output Path for new fixture directory
--append Path to existing fixture to append to
Status Command

Check the status of all fixtures:

# show status of all fixtures
go run ./internal/dbtest/cmd/manager status

# show status of a specific fixture
go run ./internal/dbtest/cmd/manager status --fixture internal/dbtest/testdata/shared/my-fixture

Example output:

internal/dbtest/testdata/shared/all             OK (automatic, synced)
grype/matcher/dpkg/testdata/eol-debian8         OK (automatic, synced)
internal/dbtest/testdata/shared/manual-vuln     OK (manual)
internal/dbtest/testdata/shared/modified-one    CONTENT DRIFT (lock: a1b2c3d4, actual: e5f6g7h8)
Regenerate Command

Regenerate fixtures from their db.yaml configs:

# dry run to see what would be regenerated
go run ./internal/dbtest/cmd/manager regenerate --vunnel-data ~/vunnel/data --dry-run

# regenerate all fixtures
go run ./internal/dbtest/cmd/manager regenerate --vunnel-data ~/vunnel/data

# regenerate a specific fixture
go run ./internal/dbtest/cmd/manager regenerate --vunnel-data ~/vunnel/data --fixture path/to/fixture

# force regeneration even if fixture has been modified
go run ./internal/dbtest/cmd/manager regenerate --vunnel-data ~/vunnel/data --force
Flag Description
--vunnel-data Path to vunnel data directory (required)
--fixture Path to a specific fixture to regenerate
--search-root Root directory to search for fixtures (repeatable)
--force Regenerate even if fixture has been modified
--dry-run Show what would be regenerated without making changes

Pattern Matching

Patterns use SQL LIKE matching with automatic wildcards. All patterns are wrapped with % for partial matching.

Pattern Matches Description
CVE-2024-1234 debian:10/CVE-2024-1234, ubuntu:20.04/CVE-2024-1234 Matches CVE in any namespace
debian:10 debian:10/CVE-2024-1234, debian:10/CVE-2024-5678 Matches all CVEs in namespace
debian debian:10/..., debian:11/... Matches all debian namespaces
RHSA-2024: rhel:8/RHSA-2024:0001, rhel:9/RHSA-2024:0002 Matches all 2024 RHSAs
debian:11/CVE-2024-1234 debian:11/CVE-2024-1234 Exact match

Multiple --select patterns are combined with OR logic.

Fixture Structure

Extracted fixtures follow the vunnel workspace format:

fixture/
├── db.yaml               # extraction config (auto-generate flag, patterns)
├── db-lock.json          # state tracking (content hash, timestamps)
├── provider-name/
│   ├── metadata.json     # provider state (store: "flat-file")
│   └── results/
│       ├── debian@11_CVE-2024-1234.json
│       ├── debian@11_CVE-2024-5678.json
│       └── listing.xxh64
└── another-provider/
    ├── metadata.json
    └── results/
        └── ...

Note: : in identifiers is replaced with @ and / with _ in filenames.

Tracking and Regenerating Fixtures

When you extract a fixture, the manager creates two metadata files:

  • db.yaml - Intent: What extractions to perform (human-editable)
  • db-lock.json - State: What was done (machine-generated)
db.yaml
auto-generate: true
extractions:
  debian:
    - CVE-2024-1234
    - debian:10
  nvd:
    - CVE-2024-1234
Field Description
auto-generate If true, fixture can be regenerated from vunnel cache
extractions Map of provider name to list of patterns
db-lock.json
{
  "content_hash": "a1b2c3d4e5f6g7h8",
  "created_at": "2024-01-15T12:00:00Z",
  "regenerated_at": "2024-03-12T10:30:00Z",
  "providers": {
    "debian": {
      "vunnel_version": "vunnel@0.55.2",
      "timestamp": "2024-03-11T16:25:19Z"
    }
  }
}
Field Description
content_hash xxh64 hash of fixture content (excludes db.yaml and db-lock.json)
created_at When fixture was first created
regenerated_at When last regenerated (omitted if never regenerated)
providers.<name>.vunnel_version Vunnel version from provider's metadata
providers.<name>.timestamp Provider's data timestamp
Fixture Status
Status Description
OK (automatic) auto-generate: true and content hash matches lock
OK (manual) auto-generate: false - manually created, never auto-regenerated
content_drift auto-generate: true but files have changed since last generation
config_ahead auto-generate: true but config has providers not in lock
no_lock auto-generate: true but db-lock.json is missing
no_config No db.yaml file present

Workflows

Creating a New Fixture
# 1. extract (db.yaml and db-lock.json created automatically)
go run ./internal/dbtest/cmd/manager extract \
    --vunnel-data ~/vunnel/data \
    --provider debian --select "CVE-2024-1234" \
    --output internal/dbtest/testdata/shared/my-fixture

# 2. optionally append more providers/CVEs
go run ./internal/dbtest/cmd/manager extract \
    --vunnel-data ~/vunnel/data \
    --provider nvd --select "CVE-2024-1234" \
    --append internal/dbtest/testdata/shared/my-fixture

# 3. commit
git add internal/dbtest/testdata/shared/my-fixture/
git commit -m "add my-fixture test fixture"
Creating a Manual Fixture

Manual fixtures are never automatically regenerated, useful when you need custom modifications:

# 1. extract base
go run ./internal/dbtest/cmd/manager extract \
    --vunnel-data ~/vunnel/data \
    --provider debian --select "CVE-2024-1234" \
    --output internal/dbtest/testdata/shared/manual-fixture

# 2. manually modify files as needed
vim internal/dbtest/testdata/shared/manual-fixture/debian/results/...

# 3. edit db.yaml to set auto-generate: false
# (prevents automatic regeneration)

# 4. commit
git add internal/dbtest/testdata/shared/manual-fixture/
git commit -m "add manual-fixture with custom modifications"
Regenerating Fixtures

When vunnel data is updated, regenerate fixtures to get fresh vulnerability data:

# 1. check current status
go run ./internal/dbtest/cmd/manager status

# 2. dry run to see what would happen
go run ./internal/dbtest/cmd/manager regenerate --vunnel-data ~/vunnel/data --dry-run

# 3. regenerate (skips manual and modified fixtures)
go run ./internal/dbtest/cmd/manager regenerate --vunnel-data ~/vunnel/data

# 4. run tests to verify
go test ./...

Documentation

Index

Constants

View Source
const (
	// ConfigFilename is the name of the fixture config file (intent)
	ConfigFilename = "db.yaml"
	// LockFilename is the name of the fixture lock file (state)
	LockFilename = "db-lock.json"
)

Variables

View Source
var (
	Debian8  = distro.New(distro.Debian, "8", "")
	Debian9  = distro.New(distro.Debian, "9", "")
	Debian10 = distro.New(distro.Debian, "10", "")
	Debian11 = distro.New(distro.Debian, "11", "")
	Debian12 = distro.New(distro.Debian, "12", "")

	Ubuntu1804 = distro.New(distro.Ubuntu, "18.04", "")
	Ubuntu2004 = distro.New(distro.Ubuntu, "20.04", "")
	Ubuntu2204 = distro.New(distro.Ubuntu, "22.04", "")
	Ubuntu2404 = distro.New(distro.Ubuntu, "24.04", "")

	Alpine316 = distro.New(distro.Alpine, "3.16", "")
	Alpine317 = distro.New(distro.Alpine, "3.17", "")
	Alpine318 = distro.New(distro.Alpine, "3.18", "")
	Alpine319 = distro.New(distro.Alpine, "3.19", "")

	// Wolfi is rolling; version is unused for matching but preserved here for
	// readability at call sites.
	WolfiRolling = distro.New(distro.Wolfi, "", "")

	RHEL7  = distro.New(distro.RedHat, "7", "")
	RHEL8  = distro.New(distro.RedHat, "8", "")
	RHEL9  = distro.New(distro.RedHat, "9", "")
	RHEL10 = distro.New(distro.RedHat, "10", "")

	AlmaLinux8 = distro.New(distro.AlmaLinux, "8", "")
	AlmaLinux9 = distro.New(distro.AlmaLinux, "9", "")

	SLES156      = distro.New(distro.SLES, "15.6", "")
	SLES157      = distro.New(distro.SLES, "15.7", "")
	Hummingbird1 = distro.New(distro.Hummingbird, "1", "")
)

common distro constants for tests

View Source
var DefaultSchemaVersions = []int{v6.ModelVersion}

DefaultSchemaVersions controls which schema versions Build() generates by default. Currently only v6; v7 can be added here when ready.

Functions

func ComputeFixtureContentHash added in v0.112.0

func ComputeFixtureContentHash(fixtureDir string) (string, error)

ComputeFixtureContentHash computes an xxh64 hash of all fixture content, excluding db.yaml and db.lock files. The hash is deterministic based on file paths and contents, sorted alphabetically.

func DefaultVulnerabilities

func DefaultVulnerabilities() []vulnerability.Vulnerability

func DiscoverFixtures added in v0.112.0

func DiscoverFixtures(searchRoots ...string) ([]string, error)

DiscoverFixtures finds all fixture directories containing a db.yaml file under the given search roots.

Types

type Builder added in v0.112.0

type Builder struct {
	// contains filtered or unexported fields
}

Builder provides a fluent API for building test databases from fixture directories.

func DBs added in v0.112.0

func DBs(t *testing.T, fixtureName string) *Builder

DBs creates a new Builder for the named fixture. The fixture is expected to be in a "testdata" directory relative to the calling test file.

Example:

for _, db := range dbtest.DBs(t, "my-fixture").Build() {
    t.Run(db.Name, func(t *testing.T) {
        // use db as vulnerability.Provider
    })
}

func SharedDBs added in v0.112.0

func SharedDBs(t *testing.T, fixtureName string) *Builder

SharedDBs creates a Builder for a fixture in the shared fixture directory. Shared fixtures live in internal/dbtest/testdata/shared/{fixtureName} and can be used by tests in any package, enabling cross-package fixture sharing.

Example:

// from any test file in any package:
dbtest.SharedDBs(t, "common-debian").Run(func(t *testing.T, db *dbtest.DB) {
    // use the shared fixture
})

func (*Builder) Build added in v0.112.0

func (b *Builder) Build(schemas ...int) []*DB

Build builds databases for the specified schema versions (or DefaultSchemaVersions if none specified). Returns a slice of DB pointers that implement vulnerability.Provider.

func (*Builder) Run added in v0.112.0

func (b *Builder) Run(fn func(t *testing.T, db *DB))

Run executes a test function for each database built from the fixture. This is a convenience method that wraps Build() with the common for-loop and t.Run pattern.

func (*Builder) SelectOnly added in v0.112.0

func (b *Builder) SelectOnly(patterns ...string) *Builder

SelectOnly specifies patterns to filter which vulnerability records are included in the built database. This enables creating focused test databases from larger fixtures.

Pattern types:

  • CVE ID only: "CVE-2024-1234" (matches any namespace containing this CVE)
  • Namespace only: "debian:10" (matches all CVEs in that namespace)
  • Full identifier: "debian:10/CVE-2024-1234" (exact match)

Multiple patterns are combined with OR logic (union). If no selections are specified, all records are included.

Example:

// select specific CVEs across all namespaces
dbtest.SharedDBs(t, "large-fixture").SelectOnly("CVE-2024-1234", "CVE-2024-5678").Build()

// select all CVEs in a namespace
dbtest.DBs(t, "fixture").SelectOnly("debian:10").Build()

// combine namespace and CVE selections
dbtest.SharedDBs(t, "fixture").SelectOnly("debian:10", "CVE-2024-9999").Build()

type CPEDetailAssertion added in v0.112.0

type CPEDetailAssertion struct {
	// contains filtered or unexported fields
}

CPEDetailAssertion provides assertions for CPE-based matches. SearchedBy is CPEParameters, Found is CPEResult.

func (*CPEDetailAssertion) FoundCPEs added in v0.112.0

func (c *CPEDetailAssertion) FoundCPEs(cpes ...string) *CPEDetailAssertion

FoundCPEs asserts that the found CPEs contain all the given CPEs.

func (*CPEDetailAssertion) HasMatchType added in v0.112.0

func (c *CPEDetailAssertion) HasMatchType(matchType match.Type) *CPEDetailAssertion

HasMatchType asserts that the detail has the expected match type.

type DB added in v0.112.0

type DB struct {
	// Name is a human-readable name for this database (e.g., "v6")
	Name string

	// SchemaVersion is the database schema version
	SchemaVersion int

	// Path is the path to the database directory
	Path string
	// contains filtered or unexported fields
}

DB wraps a vulnerability.Provider with metadata about the database. It implements the vulnerability.Provider interface by delegating to the internal provider.

func (*DB) Close added in v0.112.0

func (db *DB) Close() error

Close closes the database connection and releases resources.

func (*DB) FindVulnerabilities added in v0.112.0

func (db *DB) FindVulnerabilities(criteria ...vulnerability.Criteria) ([]vulnerability.Vulnerability, error)

FindVulnerabilities returns vulnerabilities matching all the provided criteria.

func (*DB) GetOperatingSystemEOL added in v0.112.0

func (db *DB) GetOperatingSystemEOL(d *distro.Distro) (eolDate, eoasDate *time.Time, err error)

GetOperatingSystemEOL returns the EOL and EOAS dates for the given distro. Implements vulnerability.EOLChecker by delegating to the underlying provider if it supports the interface.

func (*DB) Match added in v0.112.0

func (db *DB) Match(t *testing.T, matcher Matcher, p grypePkg.Package) *FindingsAssertion

Match calls matcher.Match using this DB as the provider and returns a FindingsAssertion for fluent assertions. Fails the test on error. The returned assertion captures both the matches and the ignore filters; use FindingsAssertion.Ignores() to assert on the latter. Ignore-filter completeness is only enforced once Ignores() is called.

func (*DB) PackageSearchNames added in v0.112.0

func (db *DB) PackageSearchNames(p grypePkg.Package) []string

PackageSearchNames returns the package names to search for in the database.

func (*DB) String added in v0.112.0

func (db *DB) String() string

String returns a string representation of the database.

func (*DB) VulnerabilityMetadata added in v0.112.0

func (db *DB) VulnerabilityMetadata(ref vulnerability.Reference) (*vulnerability.Metadata, error)

VulnerabilityMetadata returns the metadata associated with a vulnerability.

type DistroDetailAssertion added in v0.112.0

type DistroDetailAssertion struct {
	// contains filtered or unexported fields
}

DistroDetailAssertion provides assertions for distro/OS package matches. SearchedBy is DistroParameters, Found is DistroResult.

func (*DistroDetailAssertion) HasMatchType added in v0.112.0

func (d *DistroDetailAssertion) HasMatchType(matchType match.Type) *DistroDetailAssertion

HasMatchType asserts that the detail has the expected match type.

type EcosystemDetailAssertion added in v0.112.0

type EcosystemDetailAssertion struct {
	// contains filtered or unexported fields
}

EcosystemDetailAssertion provides assertions for language/ecosystem package matches. SearchedBy is EcosystemParameters, Found is EcosystemResult.

func (*EcosystemDetailAssertion) HasMatchType added in v0.112.0

func (e *EcosystemDetailAssertion) HasMatchType(matchType match.Type) *EcosystemDetailAssertion

HasMatchType asserts that the detail has the expected match type.

type ExtractionBuilder added in v0.112.0

type ExtractionBuilder struct {
	// contains filtered or unexported fields
}

ExtractionBuilder provides a fluent API for extraction operations.

func (*ExtractionBuilder) AppendTo added in v0.112.0

func (b *ExtractionBuilder) AppendTo(fixtureDir string) error

AppendTo extracts matching records and appends them to an existing fixture. Existing records with the same ID are overwritten. This also updates the db.yaml and db.lock files to track the additional extraction.

func (*ExtractionBuilder) Select added in v0.112.0

func (b *ExtractionBuilder) Select(patterns ...string) *ExtractionBuilder

Select adds patterns for record selection (LIKE matching). Patterns are wrapped with % for partial matching:

  • "CVE-2024-1234" matches any record containing this CVE ID
  • "debian:10" matches records in the debian:10 namespace
  • "RHSA-2024:%" matches all 2024 RHSAs

func (*ExtractionBuilder) WriteTo added in v0.112.0

func (b *ExtractionBuilder) WriteTo(fixtureDir string) error

WriteTo extracts matching records and writes them to a new fixture directory. The fixtureDir should be the path to the fixture root directory (provider subdirectory will be created inside). This also creates db.yaml and db.lock files to track the fixture's provenance.

type FindingsAssertion added in v0.112.0

type FindingsAssertion struct {
	// contains filtered or unexported fields
}

FindingsAssertion provides a string-based, API-agnostic fluent assertion chain for match results. This approach abstracts away internal struct shapes so that tests don't need to change when the high-level API is refactored (e.g., in grype v1).

Example:

dbtest.AssertFindings(t, matches, p).
    HasCount(2).
    OnlyHasVulnerabilities("CVE-2024-1234", "CVE-2024-5678").
    DoesNotHaveAnyVulnerabilities("CVE-2024-9999")

func AssertFindings added in v0.112.0

func AssertFindings(t TestingT, matches []match.Match, p pkg.Package) *FindingsAssertion

AssertFindings creates a new FindingsAssertion for API-agnostic assertions. The package parameter is the package that was matched against. If the package is zero-value (empty name), asserts that there are no matches. Otherwise, asserts that all matches are for the given package.

Use complete() to enable completeness checking, which verifies that all matches and details were asserted.

func AssertFindingsAndIgnores added in v0.113.0

func AssertFindingsAndIgnores(t TestingT, matches []match.Match, ignores []match.IgnoreFilter, p pkg.Package) *FindingsAssertion

AssertFindingsAndIgnores is the same as AssertFindings but also captures the ignore filters returned by the matcher so they can be asserted on via FindingsAssertion.Ignores().

func (*FindingsAssertion) ContainsVulnerabilities added in v0.112.0

func (f *FindingsAssertion) ContainsVulnerabilities(vulnIDs ...string) *FindingsAssertion

ContainsVulnerabilities asserts that findings with all the given vulnerability IDs exist. Other vulnerabilities may also be present.

func (*FindingsAssertion) DoesNotHaveAnyVulnerabilities added in v0.112.0

func (f *FindingsAssertion) DoesNotHaveAnyVulnerabilities(vulnIDs ...string) *FindingsAssertion

DoesNotHaveAnyVulnerabilities asserts that no finding with the given vulnerability ID exists.

func (*FindingsAssertion) Ignores added in v0.113.0

Ignores returns an IgnoreFiltersAssertion for asserting on the ignore filters returned alongside the matches. Ignore-side completeness is always on (set up at construction time), so a test that produces zero ignores does not need to call this at all - completeness fails the test if any unasserted ignore is emitted by the matcher. Tests that expect ≥1 ignore must use this to assert on each one. Use SkipCompleteness on the returned assertion to scope to a subset.

func (*FindingsAssertion) IsEmpty added in v0.112.0

func (f *FindingsAssertion) IsEmpty() *FindingsAssertion

IsEmpty asserts that the matcher returned nothing - no matches AND no ignores. Use this when the matcher is expected to be a complete no-op for the input. For "no matches but some ignores expected", just skip IsEmpty and assert on the ignores via Ignores(); the matches-side completeness check will enforce that no matches were produced.

func (*FindingsAssertion) Matches added in v0.112.0

func (f *FindingsAssertion) Matches() []match.Match

Matches returns the underlying []match.Match. It is an intentional escape hatch and should be avoided.

The point of this assertion API is to be a façade over match.Match and vulnerability.Vulnerability so that the internal struct layout can be refactored (e.g., the v1 API rewrite) without touching tests. Every caller of Matches() is one more test that locks itself to today's struct shape.

If you find yourself wanting raw matches, the right move is almost always to add a focused helper instead - HasFix, HasAdvisories, InNamespace, SelectMatches+WithDetailType, SelectDetailBy* and friends were all added this way. There is intentionally no equivalent on SingleFindingAssertion.

Bypasses completeness checking, which is the other reason it makes tests fragile.

func (*FindingsAssertion) OnlyHasVulnerabilities added in v0.112.0

func (f *FindingsAssertion) OnlyHasVulnerabilities(vulnIDs ...string) *FindingsAssertion

OnlyHasVulnerabilities asserts that findings contain exactly the given vulnerability IDs and no others. Order does not matter.

func (*FindingsAssertion) SelectMatch added in v0.112.0

func (f *FindingsAssertion) SelectMatch(vulnIDs ...string) *SingleFindingAssertion

SelectMatch returns a SingleFindingAssertion for detailed assertions on a specific finding. With no arguments, selects the single match (fails if not exactly one). With one argument, selects the match with the given vulnerability ID.

func (*FindingsAssertion) SelectMatches added in v0.113.0

func (f *FindingsAssertion) SelectMatches(vulnID string) *MultipleFindingAssertion

SelectMatches returns the subset of matches with the given vulnerability ID. Unlike SelectMatch, which fatals when multiple matches share an ID, SelectMatches accepts any non-zero count and lets callers narrow further via WithDetailType. The returned MultipleFindingAssertion participates in completeness tracking; selecting a sub-match here is what marks the underlying match as asserted.

func (*FindingsAssertion) SkipCompleteness added in v0.112.0

func (f *FindingsAssertion) SkipCompleteness() *FindingsAssertion

SkipCompleteness asserts that this chain is intentionally checking only a subset of matches/details. The default mode requires every match and detail to be asserted; calling SkipCompleteness inverts that contract: the chain fails if everything happened to be asserted anyway. The inversion exists so that SkipCompleteness calls don't rot in tests that have grown into being exhaustive - if the chain is fully asserting, drop the SkipCompleteness call.

type FixtureConfig added in v0.112.0

type FixtureConfig struct {
	AutoGenerate bool                `yaml:"auto-generate"`
	Extractions  map[string][]string `yaml:"extractions"` // provider name -> patterns
}

FixtureConfig represents the intent of what a fixture should contain (db.yaml). This file is human-edited and defines how the fixture was created.

func ReadConfig added in v0.112.0

func ReadConfig(fixtureDir string) (*FixtureConfig, error)

ReadConfig reads a FixtureConfig from the given fixture directory.

func (*FixtureConfig) Write added in v0.112.0

func (c *FixtureConfig) Write(fixtureDir string) error

Write writes the FixtureConfig to the given fixture directory.

type FixtureExtractor added in v0.112.0

type FixtureExtractor struct {
	// contains filtered or unexported fields
}

FixtureExtractor extracts records from vunnel SQLite caches and writes them as fixtures.

func NewFixtureExtractor added in v0.112.0

func NewFixtureExtractor(vunnelRoot string) *FixtureExtractor

NewFixtureExtractor creates an extractor for the given vunnel cache root. The vunnelRoot should be the path to the vunnel data directory containing provider subdirectories (e.g., "debian", "rhel", "nvd").

func (*FixtureExtractor) From added in v0.112.0

func (e *FixtureExtractor) From(providerName string) *ExtractionBuilder

From specifies which provider's results.db to read from. The provider name should match a subdirectory in the vunnel data directory.

func (*FixtureExtractor) FromMultiple added in v0.112.0

func (e *FixtureExtractor) FromMultiple() *MultiProviderExtractor

FromMultiple starts a multi-provider extraction, returning a builder that allows adding multiple provider extractions.

type FixtureLock added in v0.112.0

type FixtureLock struct {
	ContentHash   string                   `json:"content_hash"`
	CreatedAt     time.Time                `json:"created_at"`
	RegeneratedAt *time.Time               `json:"regenerated_at,omitempty"`
	Providers     map[string]ProviderState `json:"providers"`
}

FixtureLock represents the state of a fixture (db.lock). This file is machine-generated and should never be manually edited.

func ReadLock added in v0.112.0

func ReadLock(fixtureDir string) (*FixtureLock, error)

ReadLock reads a FixtureLock from the given fixture directory.

func (*FixtureLock) Write added in v0.112.0

func (l *FixtureLock) Write(fixtureDir string) error

Write writes the FixtureLock to the given fixture directory.

type FixtureStatus added in v0.112.0

type FixtureStatus string

FixtureStatus represents the high-level state of a fixture.

const (
	StatusOK           FixtureStatus = "ok"            // auto-generate=true, config/lock in sync, hash matches
	StatusContentDrift FixtureStatus = "content_drift" // auto-generate=true, files on disk don't match lock hash
	StatusConfigAhead  FixtureStatus = "config_ahead"  // auto-generate=true, config has extractions not in lock
	StatusManual       FixtureStatus = "manual"        // auto-generate=false
	StatusNoConfig     FixtureStatus = "no_config"     // no db.yaml
	StatusNoLock       FixtureStatus = "no_lock"       // db.yaml exists but no db.lock
)

func GetFixtureStatus added in v0.112.0

func GetFixtureStatus(fixtureDir string) (FixtureStatus, error)

GetFixtureStatus determines the current status of a fixture.

type FixtureStatusDetail added in v0.112.0

type FixtureStatusDetail struct {
	Status        FixtureStatus
	ConfigExists  bool
	LockExists    bool
	AutoGenerate  bool
	ContentHash   string   // current hash of files on disk
	LockHash      string   // hash recorded in db.lock
	HashMatches   bool     // ContentHash == LockHash
	ConfigInSync  bool     // all config extractions have corresponding lock entries
	MissingInLock []string // providers in config but not in lock
}

FixtureStatusDetail provides detailed information about a fixture's state.

func GetFixtureStatusDetail added in v0.112.0

func GetFixtureStatusDetail(fixtureDir string) (*FixtureStatusDetail, error)

GetFixtureStatusDetail determines the detailed status of a fixture, including information about config/lock synchronization and content hashes.

type IgnoreFiltersAssertion added in v0.113.0

type IgnoreFiltersAssertion struct {
	// contains filtered or unexported fields
}

IgnoreFiltersAssertion provides assertions on the ignore filters returned by a matcher. Like FindingsAssertion, it tracks which ignores were asserted and fails the test if any were missed (unless SkipCompleteness is called).

func (*IgnoreFiltersAssertion) IsEmpty added in v0.113.0

IsEmpty asserts there are no ignore filters.

func (*IgnoreFiltersAssertion) SelectIgnoreRule added in v0.113.0

func (i *IgnoreFiltersAssertion) SelectIgnoreRule(reason, vulnID string) *IgnoreRuleAssertion

SelectIgnoreRule finds an IgnoreRule with the given reason and vulnerability ID. Fails if not exactly one matches. The returned assertion can be further qualified with ForPackage. Use this for matchers that emit match.IgnoreRule (e.g., the language ecosystem path's UnaffectedPackageEntry rules); use SelectRelatedPackageIgnore for matchers that emit match.IgnoreRelatedPackage.

func (*IgnoreFiltersAssertion) SelectRelatedPackageIgnore added in v0.113.0

func (i *IgnoreFiltersAssertion) SelectRelatedPackageIgnore(reason, vulnID string) *IgnoreRelatedPackageAssertion

SelectRelatedPackageIgnore finds an IgnoreRelatedPackage with the given reason and vulnerability ID. Fails if not exactly one matches. The returned assertion can be further qualified with ForPackage and WithRelationshipType.

func (*IgnoreFiltersAssertion) SelectRelatedPackageIgnores added in v0.113.0

func (i *IgnoreFiltersAssertion) SelectRelatedPackageIgnores(reason string, vulnIDs ...string) *IgnoreRelatedPackagesAssertion

SelectRelatedPackageIgnores selects a batch of IgnoreRelatedPackage filters that share a reason and lets the caller assert on the whole batch with one chain. This is the right shape for cases like AlmaLinux alias unwinding, where one ALSA emits an ignore for the ALSA itself plus one per aliased CVE - all with the same reason, same package, and the same relationship type. Fails fatally if any of the requested vulnerability IDs is missing or duplicated under that reason. Each selected ignore is registered for completeness tracking. Pass at least one vulnerability ID; for a single ID, the singular SelectRelatedPackageIgnore reads cleaner.

func (*IgnoreFiltersAssertion) SkipCompleteness added in v0.113.0

func (i *IgnoreFiltersAssertion) SkipCompleteness() *IgnoreFiltersAssertion

SkipCompleteness asserts that this ignore-filter chain is intentionally partial. Mirrors the inverted semantics of FindingsAssertion.SkipCompleteness: the default requires every ignore filter to be asserted, and calling this flips the contract so the chain fails if everything happened to be asserted anyway. Drop the call once you are exhaustively asserting on ignores.

type IgnoreRelatedPackageAssertion added in v0.113.0

type IgnoreRelatedPackageAssertion struct {
	// contains filtered or unexported fields
}

IgnoreRelatedPackageAssertion provides assertions on a single match.IgnoreRelatedPackage that has already been selected by reason+vuln.

func (*IgnoreRelatedPackageAssertion) ForPackage added in v0.113.0

ForPackage asserts the related package ID matches the given pkg.ID. This is the most common follow-up assertion: tests typically capture the package ID when constructing the test package and then assert that the ignore points back at it.

func (*IgnoreRelatedPackageAssertion) WithRelationshipType added in v0.113.0

WithRelationshipType asserts the ignore filter's relationship type. The vast majority of cases use OwnershipByFileOverlapRelationship so this is only needed for the rare cases that use a different relationship.

type IgnoreRelatedPackagesAssertion added in v0.113.0

type IgnoreRelatedPackagesAssertion struct {
	// contains filtered or unexported fields
}

IgnoreRelatedPackagesAssertion fans assertions out over a batch of IgnoreRelatedPackage filters that were selected together via SelectRelatedPackageIgnores. Each method applies to every filter in the batch.

func (*IgnoreRelatedPackagesAssertion) ForPackage added in v0.113.0

ForPackage asserts that every filter in the batch has the given related package ID.

func (*IgnoreRelatedPackagesAssertion) WithRelationshipType added in v0.113.0

WithRelationshipType asserts that every filter in the batch has the given relationship type.

type IgnoreRuleAssertion added in v0.113.0

type IgnoreRuleAssertion struct {
	// contains filtered or unexported fields
}

IgnoreRuleAssertion provides assertions on a single match.IgnoreRule that has already been selected by reason+vulnerability.

func (*IgnoreRuleAssertion) ForPackage added in v0.113.0

func (a *IgnoreRuleAssertion) ForPackage(name, version string) *IgnoreRuleAssertion

ForPackage asserts the rule's package identification matches the given name and version. This is the most common follow-up assertion for VEX/unaffected ignore rules, where the package coordinates pin the rule to the specific scanned artifact.

func (*IgnoreRuleAssertion) IncludesAliases added in v0.113.0

func (a *IgnoreRuleAssertion) IncludesAliases() *IgnoreRuleAssertion

IncludesAliases asserts the rule will fan out to aliased vulnerability IDs (the common case for VEX/unaffected entries that suppress a primary advisory along with all its aliases).

type Matcher added in v0.112.0

type Matcher interface {
	Match(vulnerability.Provider, grypePkg.Package) ([]match.Match, []match.IgnoreFilter, error)
}

Matcher is the interface for vulnerability matchers.

type MultiProviderExtractor added in v0.112.0

type MultiProviderExtractor struct {
	// contains filtered or unexported fields
}

MultiProviderExtractor extends FixtureExtractor to support extracting from multiple providers.

func (*MultiProviderExtractor) AppendTo added in v0.112.0

func (m *MultiProviderExtractor) AppendTo(fixtureDir string) error

AppendTo extracts matching records from all providers and appends them to an existing fixture.

func (*MultiProviderExtractor) Provider added in v0.112.0

func (m *MultiProviderExtractor) Provider(providerName string, patterns ...string) *MultiProviderExtractor

Provider adds a provider extraction to the multi-provider builder.

func (*MultiProviderExtractor) WriteTo added in v0.112.0

func (m *MultiProviderExtractor) WriteTo(fixtureDir string) error

WriteTo extracts matching records from all providers and writes them to a new fixture directory.

type MultipleFindingAssertion added in v0.113.0

type MultipleFindingAssertion struct {
	// contains filtered or unexported fields
}

MultipleFindingAssertion is a subset of a FindingsAssertion's matches that share a vulnerability ID. Used to disambiguate the otherwise-ambiguous case where one matcher emits multiple findings for the same CVE (e.g., a distro disclosure plus a CPE-fallback NVD finding for an EOL distro).

func (*MultipleFindingAssertion) WithDetailType added in v0.113.0

func (m *MultipleFindingAssertion) WithDetailType(detailType match.Type) *SingleFindingAssertion

WithDetailType narrows the subset to the single match that has at least one detail of the given type. Fatals if zero or more than one match in the subset has a detail of that type. The selected match (and the detail used to pick it) become tracked for completeness purposes.

type PackageBuilder added in v0.112.0

type PackageBuilder struct {
	// contains filtered or unexported fields
}

PackageBuilder provides a fluent API for building test packages.

func NewPackage added in v0.112.0

func NewPackage(name, version string, t syftPkg.Type) *PackageBuilder

NewPackage creates a new PackageBuilder with the given name, version, and type. An ID is auto-generated.

func (*PackageBuilder) Build added in v0.112.0

func (b *PackageBuilder) Build() pkg.Package

Build returns the constructed package.

func (*PackageBuilder) WithCPE added in v0.112.0

func (b *PackageBuilder) WithCPE(cpeStr string) *PackageBuilder

WithCPE adds a CPE to the package. The cpeStr should be in CPE 2.3 format (e.g., "cpe:2.3:a:vendor:product:version:*:*:*:*:*:*:*").

func (*PackageBuilder) WithCPEs added in v0.112.0

func (b *PackageBuilder) WithCPEs(cpeStrs ...string) *PackageBuilder

WithCPEs adds multiple CPEs to the package.

func (*PackageBuilder) WithDistro added in v0.112.0

func (b *PackageBuilder) WithDistro(d *distro.Distro) *PackageBuilder

WithDistro sets the package's distro.

func (*PackageBuilder) WithID added in v0.113.0

func (b *PackageBuilder) WithID(id pkg.ID) *PackageBuilder

WithID overrides the auto-generated package ID. Use this when a test needs a stable, comparable ID (e.g., to assert against an IgnoreFilter that references the package by ID).

func (*PackageBuilder) WithLanguage added in v0.112.0

func (b *PackageBuilder) WithLanguage(lang syftPkg.Language) *PackageBuilder

WithLanguage sets the package's language ecosystem.

func (*PackageBuilder) WithLicenses added in v0.112.0

func (b *PackageBuilder) WithLicenses(licenses ...string) *PackageBuilder

WithLicenses sets the package licenses.

func (*PackageBuilder) WithLocation added in v0.112.0

func (b *PackageBuilder) WithLocation(path string) *PackageBuilder

WithLocation adds a file location to the package.

func (*PackageBuilder) WithMetadata added in v0.112.0

func (b *PackageBuilder) WithMetadata(metadata interface{}) *PackageBuilder

WithMetadata sets package-specific metadata.

func (*PackageBuilder) WithPURL added in v0.112.0

func (b *PackageBuilder) WithPURL(purl string) *PackageBuilder

WithPURL sets the Package URL.

func (*PackageBuilder) WithRelatedPackage added in v0.112.0

func (b *PackageBuilder) WithRelatedPackage(relationshipType artifact.RelationshipType, related *pkg.Package) *PackageBuilder

WithRelatedPackage adds a related package via the given relationship type.

func (*PackageBuilder) WithType added in v0.112.0

func (b *PackageBuilder) WithType(t syftPkg.Type) *PackageBuilder

WithType sets the package type (e.g., syftPkg.ApkPkg, syftPkg.RpmPkg).

func (*PackageBuilder) WithUpstream added in v0.112.0

func (b *PackageBuilder) WithUpstream(name, version string) *PackageBuilder

WithUpstream adds an upstream package.

type ProviderState added in v0.112.0

type ProviderState struct {
	VunnelVersion string    `json:"vunnel_version"` // from metadata.json processor field
	Timestamp     time.Time `json:"timestamp"`      // from metadata.json timestamp field
}

ProviderState captures metadata from a vunnel provider at extraction time.

type RegenerateOptions added in v0.112.0

type RegenerateOptions struct {
	VunnelRoot string // path to vunnel data directory
	Force      bool   // regenerate even if modified
	DryRun     bool   // only report what would be done
}

RegenerateOptions configures the regeneration behavior.

type RegenerateResult added in v0.112.0

type RegenerateResult struct {
	FixtureDir string
	Status     FixtureStatus
	Skipped    bool
	SkipReason string
	Error      error
}

RegenerateResult describes the outcome of a regeneration attempt.

func RegenerateAll added in v0.112.0

func RegenerateAll(searchRoots []string, opts RegenerateOptions) ([]RegenerateResult, error)

RegenerateAll regenerates all fixtures found under the given search roots.

func RegenerateFixture added in v0.112.0

func RegenerateFixture(fixtureDir string, opts RegenerateOptions) (*RegenerateResult, error)

RegenerateFixture regenerates a single fixture from its config. The process is: check status -> delete fixture content -> replay extractions -> update lock.

type ServerBuilder

type ServerBuilder struct {
	DBFormat        string
	DBBuildTime     time.Time
	DBVersion       schemaver.SchemaVer
	Vulnerabilities []vulnerability.Vulnerability
	LatestDoc       *distribution.LatestDocument
	ServerSubdir    string
	LatestDocFile   string
	RequestHandler  http.HandlerFunc
	// contains filtered or unexported fields
}

func NewServer

func NewServer(t *testing.T) *ServerBuilder

NewServer creates a new test db server building a single database from the provided vulnerabilities, along with a latest.json pointing to it, optionally with any properties specified in the provided latest parameter

func (*ServerBuilder) SetDBBuilt

func (s *ServerBuilder) SetDBBuilt(t time.Time) *ServerBuilder

func (*ServerBuilder) SetDBVersion

func (s *ServerBuilder) SetDBVersion(major, minor, patch int) *ServerBuilder

func (*ServerBuilder) Start

func (s *ServerBuilder) Start() (url string)

Start starts builds a database and starts a server with the current settings if you need to rebuild a DB or modify the behavior, you can either set a custom RequestHandler func or modify the settings and call Start() again. Returns a URL to the latest.json file, e.g. http://127.0.0.1:5678/v6/latest.json

func (*ServerBuilder) WithHandler

func (s *ServerBuilder) WithHandler(handler http.HandlerFunc) *ServerBuilder

type SingleDetailAssertion added in v0.112.0

type SingleDetailAssertion struct {
	// contains filtered or unexported fields
}

SingleDetailAssertion provides assertions on a single match detail. Use AsDistroSearch(), AsCPESearch(), or AsEcosystemSearch() for type-specific assertions.

func (*SingleDetailAssertion) AsCPESearch added in v0.112.0

func (d *SingleDetailAssertion) AsCPESearch(constraint ...string) *CPEDetailAssertion

AsCPESearch validates that SearchedBy is CPEParameters and Found is CPEResult, and validates the found vulnerability. Takes an optional version constraint to validate (0 = no assertion, 1 = assert, 2+ = error).

func (*SingleDetailAssertion) AsDistroSearch added in v0.112.0

func (d *SingleDetailAssertion) AsDistroSearch(constraint ...string) *DistroDetailAssertion

AsDistroSearch validates that SearchedBy is DistroParameters and Found is DistroResult, asserts the searched distro matches the package's distro, and validates the found vulnerability. Takes an optional version constraint to validate (0 = no assertion, 1 = assert, 2+ = error).

func (*SingleDetailAssertion) AsEcosystemSearch added in v0.112.0

func (d *SingleDetailAssertion) AsEcosystemSearch(constraint ...string) *EcosystemDetailAssertion

AsEcosystemSearch validates that SearchedBy is EcosystemParameters and Found is EcosystemResult, asserts the searched language matches the package's language, and validates the found vulnerability. Takes an optional version constraint to validate (0 = no assertion, 1 = assert, 2+ = error).

type SingleFindingAssertion added in v0.112.0

type SingleFindingAssertion struct {
	// contains filtered or unexported fields
}

SingleFindingAssertion provides detailed string-based assertions on a single finding. There is intentionally no Match() accessor returning the underlying match.Match: the assertion API is a façade so that the internal struct layout can be refactored without touching tests. When a new assertion is needed (e.g., severity, CVSS, alias IDs), the right move is to add a focused method here rather than reach into the struct.

func (*SingleFindingAssertion) HasAdvisories added in v0.113.0

func (s *SingleFindingAssertion) HasAdvisories(ids ...string) *SingleFindingAssertion

HasAdvisories asserts the match's vulnerability has exactly the given advisory IDs (order doesn't matter, but the count must match).

func (*SingleFindingAssertion) HasDetailCount added in v0.112.0

func (s *SingleFindingAssertion) HasDetailCount(count int) *SingleFindingAssertion

HasDetailCount asserts the match has the expected number of details.

func (*SingleFindingAssertion) HasFix added in v0.113.0

HasFix asserts the match's vulnerability has the expected fix state and (if any are passed) the exact set of fix versions in order.

func (*SingleFindingAssertion) HasMatchType added in v0.112.0

func (s *SingleFindingAssertion) HasMatchType(matchType match.Type) *SingleFindingAssertion

HasMatchType asserts that at least one match detail has the expected match type.

func (*SingleFindingAssertion) HasOnlyMatchTypes added in v0.112.0

func (s *SingleFindingAssertion) HasOnlyMatchTypes(matchTypes ...match.Type) *SingleFindingAssertion

HasOnlyMatchTypes asserts that all match details have one of the expected types.

func (*SingleFindingAssertion) InNamespace added in v0.113.0

func (s *SingleFindingAssertion) InNamespace(namespace string) *SingleFindingAssertion

InNamespace asserts the match's vulnerability lives in the expected namespace - useful when one matcher's results are scoped to a different namespace than the package's distro (e.g., AlmaLinux disclosures live in the rhel namespace).

func (*SingleFindingAssertion) SelectDetailByCPE added in v0.112.0

func (s *SingleFindingAssertion) SelectDetailByCPE(cpe string, constraint ...string) *CPEDetailAssertion

SelectDetailByCPE finds a detail where SearchedBy is CPEParameters containing the given CPE, and validates the found vulnerability. Fails if not exactly one detail matches. Takes an optional version constraint to validate (0 = no assertion, 1 = assert, 2+ = error).

func (*SingleFindingAssertion) SelectDetailByDistro added in v0.112.0

func (s *SingleFindingAssertion) SelectDetailByDistro(distroType, distroVersion string, constraint ...string) *DistroDetailAssertion

SelectDetailByDistro finds a detail where SearchedBy is DistroParameters matching the given distro type and version, and validates the found vulnerability. Fails if not exactly one detail matches.

Takes an optional version constraint. When provided, the constraint serves as BOTH a selection filter (the matched detail must have this exact Found.VersionConstraint) AND a validation - so callers can disambiguate findings that produce multiple details with the same (distro, version) but different version constraints, like RHEL EUS findings whose details cover the EUS-overlay fix and the mainline fix paths in the same match.

At most one constraint may be passed.

func (*SingleFindingAssertion) SelectDetailByEcosystem added in v0.112.0

func (s *SingleFindingAssertion) SelectDetailByEcosystem(language string, constraint ...string) *EcosystemDetailAssertion

SelectDetailByEcosystem finds a detail where SearchedBy is EcosystemParameters matching the given language, and validates the found vulnerability. Fails if not exactly one detail matches. Takes an optional version constraint to validate (0 = no assertion, 1 = assert, 2+ = error).

func (*SingleFindingAssertion) SelectDetailByType added in v0.112.0

func (s *SingleFindingAssertion) SelectDetailByType(matchType ...match.Type) *SingleDetailAssertion

SelectDetailByType returns a SingleDetailAssertion for assertions on a specific detail. With no arguments, requires exactly one detail (fails if not exactly one). With one argument, selects the detail matching the given type (fails if not exactly one match). More than one argument is an error.

type TestingT added in v0.112.0

type TestingT interface {
	Helper()
	Errorf(format string, args ...any)
	Fatalf(format string, args ...any)
	FailNow()
	Cleanup(f func())
	Name() string
}

TestingT is the interface required for assertions, satisfied by *testing.T and mock implementations.

Directories

Path Synopsis
cmd
manager command
manager is a CLI tool for creating and maintaining test fixtures from vunnel SQLite caches.
manager is a CLI tool for creating and maintaining test fixtures from vunnel SQLite caches.