scan

package
v0.23.3 Latest Latest
Warning

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

Go to latest
Published: Aug 30, 2024 License: Apache-2.0 Imports: 43 Imported by: 1

README

Vulnerability scanning

Wolfictl can scan APKs for known vulnerabilities. To do this, it relies on Grype to do 99% of the work. Wolfictl's own code is responsible for managing the handling of SBOM data provided to the scan, as well as vulnerability matching configuration settings, tuned to help account for vulnerabilities discovered downstream in image scans.

Testing

There are integration tests in wolfictl to guard against unexpected behaviors this Grype-based vulnerability scanning process. This section describes how to work with these tests.

How the tests work

The tests retrieve a selected set of Wolfi APK files to scan for vulnerabilities. APKs are saved to "git-ignored" locations in the repository so that they can be reused in subsequent test executions without needing to fetch them again.

Each test uses a "golden file" as the ground truth, and then compare the output of wolfictl's (*Scanner).ScanAPKs method to that golden file. If there is no diff, the test passes! If there is a diff, the test is failed, and the diff is reported to the user. JSON representations of the scan results are used to make diffing easier to reason about.

The Grype DB

Unlike SBOM generation, vulnerability scanning actually takes two inputs: the target artifact to scan, and a dataset of vulnerabilities, to which the target artifact's components will be matched. Wolfictl's vulnerability scanning uses the Grype DB as its vulnerability dataset. The Grype project updates this database every day, but we want our tests to return consistent results on every run, so we've pinned to a specific build of the Grype database. Similar to the APKs used in these tests, the Grype DB used by the tests is fetched only once and stored in the repo tree, as "git-ignored" data.

Running integration tests

Since these tests are long-running, they are not run by default by go test. Instead, you can include them in the executed test suite by using the build tag flag -tags=integration.

What to do when a test fails

When a test fails, a diff is rendered to explain how the ScanAPK method's output differed from what was expected (as codified in that test's golden file).

If a test is failing, it's failing for a notable reason. The ScanAPK method's output should never change (given unchanging APK content and an unchanging vulnerability database) under normal circumstances. So when the test fails, it means that something material changed in Grype, Syft, or in wolfictl's wrapping of these libraries. It's important to determine the root cause of the diff.

The diff either indicates a bug, or it shows an intended change (e.g. by the Syft/Grype maintainers) that wolfictl maintainers should have a heads-up about, since it may have a nontrivial impact on wolfictl's supported use cases.

If the new output coming from ScanAPK seems acceptable, then it's time to update the golden files to reflect the new ground truth.

Updating the golden files

Important! Only update the golden files after you've thoroughly examined the changes to wolfictl's vulnerability scanning behavior and determined they are acceptable.

When running these vulnerability scanning tests, you can pass the test flag -update-golden-files. Doing so will cause the tests not to check for diffs, instead saving the current output of the ScanAPK method to the golden files. It's important to check these changes into the git repository, so that everyone else starts using this data as the ground truth for their test executions.

Updating the list of APKs used for testing

The set of APK packages used during testing should be diverse, in order to give us a fair chance at identifying inbound impactful changes from Grype or Syft. One dimension that warrants diversity in particular is "language ecosystem".

The set of packages used in testing has been intentionally chosen to provide this diversity without being excessively large (costing more test execution time and storage).

But as time goes on, it's natural for the set to need to grow or change. Changing this list should be as simple as:

  1. Modifying the testTargets string slice as desired.
  2. Running the tests with -update-golden-files in order to generate golden files for any new APKs.
  3. Committing in the repo the changes to both of the above.

Documentation

Index

Constants

View Source
const (
	AdvisoriesSetResolved  = "resolved"
	AdvisoriesSetAll       = "all"
	AdvisoriesSetConcluded = "concluded"
)
View Source
const TriageSourceGovulncheck = "govulncheck"

Variables

View Source
var DefaultGrypeDBDir = path.Join(xdg.CacheHome, "wolfictl", "grype", "db")
View Source
var DefaultOptions = Options{}

DefaultOptions is the recommended default configuration for a new Scanner. These options are suitable for most use scanning cases.

Functions

func NewGrypeVulnerabilityMatcher added in v0.15.1

func NewGrypeVulnerabilityMatcher(datastore store.Store, useCPEs bool) *grype.VulnerabilityMatcher

Types

type Finding

type Finding struct {
	Package           Package
	Vulnerability     Vulnerability
	TriageAssessments []TriageAssessment
}

Finding represents a vulnerability finding for a single package.

func FilterWithAdvisories added in v0.1.0

func FilterWithAdvisories(_ context.Context, result Result, advisoryDocIndex *configs.Index[v2.Document], advisoryFilterSet string) ([]Finding, error)

FilterWithAdvisories filters the findings in the result based on the advisories for the target APK.

func Triage added in v0.8.0

func Triage(ctx context.Context, result Result, apkFile io.ReadSeeker) ([]Finding, error)

Triage inspects an existing scan Result and attempts to triage each finding, returning a copy of the Result's list of findings, modified to include TriageAssessments where applicable.

type GoVulnDBIndex added in v0.8.0

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

func BuildIndexForGoVulnDB added in v0.8.0

func BuildIndexForGoVulnDB(ctx context.Context) (*GoVulnDBIndex, error)

BuildIndexForGoVulnDB builds an index of GoVulnDB entries, keyed by aliases (like CVE IDs and GHSA IDs).

func (*GoVulnDBIndex) Get added in v0.8.0

Get returns the GoVulnDB index entry for the given ID, or false if it doesn't exist.

type GoVulnDBIndexEntry added in v0.8.0

type GoVulnDBIndexEntry struct {
	ID       string    `json:"id"`
	Modified time.Time `json:"modified"`
	Aliases  []string  `json:"aliases,omitempty"`
}

type Options added in v0.18.0

type Options struct {
	// PathOfDatabaseArchiveToImport, if set, is the path to a Grype vulnerability
	// database archive (.tar.gz file) from which a database will be loaded by
	// Grype.
	//
	// If empty, the default Grype database loading behavior will be used (e.g.
	// downloading the database from the Internet).
	PathOfDatabaseArchiveToImport string

	// PathOfDatabaseDestinationDirectory is the directory to which the Grype
	// database will be extracted, and where the database will be loaded from at
	// runtime. If empty, the value of DefaultGrypeDBDir will be used.
	PathOfDatabaseDestinationDirectory string

	// UseCPEs controls whether the scanner will use CPEs to match vulnerabilities
	// for matcher types that default to not using CPE matching. Most consumers will
	// probably want this set to false in order to avoid excessive noise from
	// matching.
	UseCPEs bool

	// DisableDatabaseAgeValidation controls whether the scanner will validate the
	// age of the vulnerability database before using it. If true, the scanner will
	// not validate the age of the database. This bool should always be set to false
	// except for testing purposes.
	DisableDatabaseAgeValidation bool

	// DisableSBOMCache controls whether the scanner will cache SBOMs generated from
	// APKs. If true, the scanner will not cache SBOMs or use existing cached SBOMs.
	DisableSBOMCache bool
}

Options determine the configuration for a new Scanner. The zero-value of this struct is a valid configuration.

type Package

type Package struct {
	ID       string
	Name     string
	Version  string
	Type     string
	Location string
	PURL     string
}

type Result added in v0.1.0

type Result struct {
	TargetAPK     TargetAPK
	Findings      []Finding
	GrypeDBStatus *db.Status
}

type Scanner added in v0.11.0

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

func NewScanner added in v0.11.0

func NewScanner(opts Options) (*Scanner, error)

NewScanner initializes the grype DB for reuse across multiple scans.

func (*Scanner) APKSBOM added in v0.11.0

func (s *Scanner) APKSBOM(ctx context.Context, ssbom *sbomSyft.SBOM) (*Result, error)

APKSBOM scans an SBOM of an APK for vulnerabilities.

func (*Scanner) ScanAPK added in v0.15.0

func (s *Scanner) ScanAPK(ctx context.Context, apk fs.File, distroID string) (*Result, error)

ScanAPK scans an APK file for vulnerabilities.

type TargetAPK added in v0.1.0

type TargetAPK struct {
	Name              string
	Version           string
	OriginPackageName string
}

func (TargetAPK) Origin added in v0.4.2

func (t TargetAPK) Origin() string

Origin returns the name of the origin package, if the package's metadata indicates an origin package. Otherwise, it returns the package name.

type TriageAssessment added in v0.8.0

type TriageAssessment struct {
	// Source is the name of the source of the triage assessment, e.g.
	// "govulncheck".
	Source string

	// TruePositive indicates whether the vulnerability is a true positive. A value
	// of false indicates that the vulnerability has been assessed to be a false
	// positive.
	TruePositive bool

	// Reason is the explanation of the triage assessment.
	Reason string
}

type Vulnerability

type Vulnerability struct {
	ID           string
	Severity     string
	Aliases      []string
	FixedVersion string
}

Jump to

Keyboard shortcuts

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