acceptance

package
v1.5.54 Latest Latest
Warning

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

Go to latest
Published: Jul 20, 2026 License: Apache-2.0 Imports: 46 Imported by: 0

README

Acceptance Testing

This package provides a testing framework for validating vulnerability analyzers.

See the full documentation for details on:

  • Creating fixtures
  • Running tests
  • Implementing an auditor

Quick Start

go test -tags=integration -v ./test/acceptance/...

Documentation

Overview

Package acceptance provides a testing framework for vulnerability auditors. It loads test fixtures from OCI registries using the Referrers API, runs auditors against them, and compares results with the expected fixture

Example
package main

import (
	"context"
	"io"
	"iter"
	"testing"

	"github.com/quay/claircore/test/acceptance"
)

// ExampleAuditor demonstrates how to implement a custom Auditor.
// This file exists to ensure the example in the documentation compiles.
type ExampleAuditor struct{}

func (a *ExampleAuditor) Audit(ctx context.Context, t testing.TB, ref string, csafDocs iter.Seq[io.Reader]) ([]acceptance.Result, error) {

	for r := range csafDocs {
		_ = r
	}

	return nil, nil
}

func main() {
	ctx := context.Background()
	t := &testing.T{}
	auditor := &ExampleAuditor{}

	acceptance.Run(ctx, t, auditor, []string{
		"quay.io/projectquay/clair-fixtures:python-test",
	})
}

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrNotAFixture = errors.New("image is not a test fixture")

ErrNotAFixture is returned when an image lacks the required referrer artifacts (vulnerability manifest and/or CSAF documents) to be treated as a test fixture. This is acceptable as existing repos can contain non-fixture images.

Functions

func FetchVEXDocs

func FetchVEXDocs(ctx context.Context, client *http.Client, urls []string) ([][]byte, error)

FetchVEXDocs fetches CSAF/VEX documents from the given URLs using client. The returned slice can be assigned directly to Fixture.VEXDocuments.

func Run

func Run(ctx context.Context, t *testing.T, a Auditor, refs []string, opts ...LoaderOption)

Run loads fixtures from the given OCI references and runs them against the auditor. Each fixture is run as a subtest named after its reference. It calls t.Error for any mismatches or missing results.

Types

type Auditor

type Auditor interface {
	// Audit analyses the image at ref using the provided CSAF documents
	// and returns vulnerability findings.
	Audit(ctx context.Context, t testing.TB, ref string, csafDocs iter.Seq[io.Reader]) ([]Result, error)
}

Auditor is the interface that vulnerability auditors must implement.

type ClaircoreAuditor

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

ClaircoreAuditor implements Auditor using claircore's libraries directly.

func NewClaircoreAuditor

func NewClaircoreAuditor(ctx context.Context, t testing.TB, cfg *ClaircoreConfig, client *http.Client) (*ClaircoreAuditor, error)

NewClaircoreAuditor creates a new auditor backed by claircore libraries. The testing.TB is used for layer caching - layers are cached in the global test cache directory and persist across test runs.

func (*ClaircoreAuditor) Audit

func (a *ClaircoreAuditor) Audit(ctx context.Context, t testing.TB, reference string, csafDocs iter.Seq[io.Reader]) ([]Result, error)

Audit implements Auditor.

func (*ClaircoreAuditor) Close

func (a *ClaircoreAuditor) Close(ctx context.Context) error

Close releases resources held by the auditor.

type ClaircoreConfig

type ClaircoreConfig struct {
	IndexerDSN string
	MatcherDSN string
	Platform   string // Default: "linux/amd64"

	// IndexerPool and MatcherPool allow passing pre-existing pools (e.g., from test helpers).
	// If set, the corresponding DSN field is ignored.
	IndexerPool *pgxpool.Pool
	MatcherPool *pgxpool.Pool
}

ClaircoreConfig holds configuration for creating a ClaircoreAuditor.

type Comparison

type Comparison struct {
	// Fixture is the reference that was tested.
	Fixture string
	// Matches are results that matched expectations.
	Matches []Match
	// Mismatches are results with the wrong status.
	Mismatches []Mismatch
	// Misses are expected results that the scanner did not report.
	Misses []fixtures.ManifestRecord
	// Extras are results reported by the scanner but not in the fixture.
	// These do not cause test failure (scanner may find more than fixture defines).
	// TODO (crozzy): Maybe a strict mode that fails the test if there are any extras?
	Extras []Result
}

Comparison is the result of comparing expected vs actual scanner results.

func Compare

func Compare(expected []fixtures.ManifestRecord, actual []Result) *Comparison

Compare checks auditor results against expected results from a fixture.

The comparison logic:

  • StatusAffected: MUST appear in results as affected. Missing or wrong status is failure.
  • StatusNotAffected: MUST appear in results as not-affected. Missing or wrong status is failure.
  • StatusAbsent: MUST NOT appear in results. If present, it's a failure.
  • Results not in expected are Extras (reported but not a failure).

func (*Comparison) Passed

func (c *Comparison) Passed() bool

Passed returns true if there were no mismatches or missing results.

type Fixture

type Fixture struct {
	// Reference is the OCI reference (e.g., "registry.io/repo:tag").
	Reference string
	// Manifest is the digest of the OCI manifest.
	Manifest string
	// VEXDocuments contains the CSAF/VEX documents for vulnerability matching.
	VEXDocuments [][]byte
	// Expected is the parsed vulnerability manifest (expected output).
	Expected []fixtures.ManifestRecord
}

Fixture is a loaded test fixture from an OCI registry.

func LoadFixture

func LoadFixture(ctx context.Context, reference string, opts ...LoaderOption) (*Fixture, error)

LoadFixture fetches a fixture from an OCI registry using the Referrers API.

The reference can be:

  • A registry reference: "registry.io/repo:tag" or "registry.io/repo@sha256:..."
  • An OCI Layout directory: "ocidir:///path/to/layout"

If WithFixture is provided, that fixture is returned directly without fetching.

type LoaderOption

type LoaderOption func(*loaderConfig)

LoaderOption configures the fixture loader.

func WithDockerCerts

func WithDockerCerts() LoaderOption

WithDockerCerts uses TLS certificates from local cert directories.

func WithDockerCreds

func WithDockerCreds() LoaderOption

WithDockerCreds uses credentials from local machine.

func WithFixture

func WithFixture(f *Fixture) LoaderOption

WithFixture provides a pre-loaded fixture, bypassing registry fetching. This is primarily useful for testing.

Note: When using WithFixture with Run, only a single reference should be provided. The same fixture is returned for all references, ignoring which reference was requested. For testing multiple fixtures, use real registry fixtures with OCI referrers or call Run multiple times.

To build a fixture from live VEX URLs rather than OCI referrers, use FetchVEXDocs to populate Fixture.VEXDocuments and set Fixture.Expected inline, then pass the result to Run.

Example

ExampleWithFixture demonstrates building a fixture from live VEX URLs using acceptance.FetchVEXDocs and acceptance.WithFixture, without storing VEX documents as OCI referrers.

package main

import (
	"context"
	"io"
	"iter"
	"net/http"
	"testing"

	"github.com/quay/claircore/test/acceptance"
	"github.com/quay/claircore/toolkit/fixtures"
)

// ExampleAuditor demonstrates how to implement a custom Auditor.
// This file exists to ensure the example in the documentation compiles.
type ExampleAuditor struct{}

func (a *ExampleAuditor) Audit(ctx context.Context, t testing.TB, ref string, csafDocs iter.Seq[io.Reader]) ([]acceptance.Result, error) {

	for r := range csafDocs {
		_ = r
	}

	return nil, nil
}

func main() {
	ctx := context.Background()
	t := &testing.T{}
	auditor := &ExampleAuditor{}

	docs, err := acceptance.FetchVEXDocs(ctx, http.DefaultClient, []string{
		"https://security.example.com/advisories/CVE-2024-1234.json",
	})
	if err != nil {
		t.Fatal(err)
	}

	fix := &acceptance.Fixture{
		Reference:    "registry.example.com/namespace/image@sha256:abc123...",
		VEXDocuments: docs,
		Expected: []fixtures.ManifestRecord{
			{ID: "CVE-2024-1234", Product: "mypackage-1.2.3", Status: fixtures.StatusAffected},
		},
	}

	acceptance.Run(ctx, t, auditor, nil, acceptance.WithFixture(fix))
}

type Match

type Match struct {
	TrackingID string
	ProductID  string
	Status     fixtures.VulnerabilityStatus
}

Match is a result that matched expectations.

type Mismatch

type Mismatch struct {
	TrackingID string
	ProductID  string
	Expected   fixtures.VulnerabilityStatus
	Actual     fixtures.VulnerabilityStatus
}

Mismatch is a result with a status different from expected.

type Result

type Result struct {
	// TrackingID is the CSAF trackingID.
	TrackingID string
	// ProductID is the CSAF productID from the product tree.
	ProductID string
	// Status is the scanner's determination.
	Status fixtures.VulnerabilityStatus
	// Package is the matched package name@version for debugging.
	Package string
}

Result is a single vulnerability finding from a scanner.

Directories

Path Synopsis
cmd
fixture command
Command fixture manages acceptance test fixtures in OCI registries.
Command fixture manages acceptance test fixtures in OCI registries.

Jump to

Keyboard shortcuts

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