dbtest

package
v0.112.0 Latest Latest
Warning

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

Go to latest
Published: May 1, 2026 License: Apache-2.0 Imports: 45 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()

// use SkipCompleteness() when you only care about specific matches
db.Match(t, &matcher, pkg).SkipCompleteness().
    ContainsVulnerabilities("CVE-2024-1234")  // other matches OK
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
HasCount(n) Assert exactly n matches
IsEmpty() Assert no matches
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
HasMatchType(type) Assert at least one detail has this match type
HasOnlyMatchTypes(types...) Assert all details have one of these types
SkipCompleteness() Disable completeness checking
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", "")

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

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. Drops the IgnoreFilter return value for convenience.

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 (*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) HasCount added in v0.112.0

func (f *FindingsAssertion) HasCount(n int) *FindingsAssertion

HasCount asserts that there are exactly n findings.

func (*FindingsAssertion) IsEmpty added in v0.112.0

func (f *FindingsAssertion) IsEmpty() *FindingsAssertion

IsEmpty asserts that there are no findings.

func (*FindingsAssertion) Matches added in v0.112.0

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

Matches returns the underlying matches for direct assertions if needed, but using this is not recommended as it bypasses the completeness checking and makes tests more fragile to internal API changes.

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) SkipCompleteness added in v0.112.0

func (f *FindingsAssertion) SkipCompleteness() *FindingsAssertion

SkipCompleteness disables the completeness check for this assertion chain. Use this when you only want to assert on a subset of matches/details.

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 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 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) 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.

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) 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) 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 to validate (0 = no assertion, 1 = assert, 2+ = error).

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL