Documentation
¶
Overview ¶
Package analysis is the supply-chain vulnerability analysis layer. It takes raw per-source advisory observations (the OSV-API correlation already attached to a dependency, plus a per-file osv-scanner run) and reduces them to ONE canonical vulnerability per advisory with ONE verdict, so a given advisory is reported exactly once regardless of how many sources observed it.
The pipeline is observe → canonicalize → evaluate:
- ObserveDependencies / ObserveScanner gather AdvisoryObservations from each source (policy-free).
- canonicalize groups observations that describe the SAME advisory (one observation's primary id is contained in another's id-set) into a single Vulnerability — pure, deterministic, policy-free.
- evaluate assigns exactly one Verdict per Vulnerability from its severity.
Reduce composes canonicalize → evaluate. Rendering to lint findings lives OUTSIDE this package (src/lint/modules/vulnerabilities) so analysis carries no dependency on the lint layer.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IsScannableLockfile ¶
IsScannableLockfile reports whether osv-scanner should run over the file at absPath (base is its filename): it must be a supported lockfile and not a nested/dominated one (a vendored crate's lock, a sub-project). Mirrors the former osv lint module's per-file gate.
func MarshalSourceAssessment ¶
func MarshalSourceAssessment(vulns []Vulnerability) ([]byte, error)
MarshalSourceAssessment renders the vulnerabilities as the indented JSON catalogue artifact (2-space indent).
Types ¶
type AdvisoryObservation ¶
type AdvisoryObservation struct {
Source string // "osv-api" | "osv-scanner"
VulnID string
Aliases []string
Package string
Version string // affected package version, for triage in the rendered message
Ecosystem string
Severity string // normalized OSV severity label
FixedIn string
Summary string
File string // repo-relative manifest/lockfile, for finding attribution
Line int
Surface Surface // which surface this observation came from (source vs image)
}
AdvisoryObservation is one raw per-source report that a package version is affected by an advisory. Several observations (from different sources, or the same advisory under different IDs) may describe one real vulnerability; canonicalize collapses them. Severity is normalized to the OSV label vocabulary ("CRITICAL"|"HIGH"|"MODERATE"|"LOW"|"UNKNOWN") at collection time so heterogeneous sources (a CVSS label vs. a numeric score) compare on one scale.
func ObserveDependencies ¶
func ObserveDependencies(deps []supplychain.Dependency) []AdvisoryObservation
ObserveDependencies turns the OSV-API vulnerabilities already correlated onto deps (during discovery) into advisory observations (Source "osv-api"). Per-file callers pass the dependency subset for one manifest; deps with no correlated vulnerability contribute nothing. Policy-free: the caller applies any ignore / source-toggle filtering before handing deps in.
func ObserveScanner ¶
func ObserveScanner(ctx context.Context, binPath string, env []string, absPath, relPath string) ([]AdvisoryObservation, error)
ObserveScanner runs the resolved osv-scanner binary over one lockfile at absPath and returns its advisory observations (Source "osv-scanner"), attributing each to relPath. Callers gate the file with IsScannableLockfile first. Per-file counterpart used by the vulnerabilities lint module.
type ReachabilityRecord ¶
type ReachabilityRecord struct {
State string `json:"state"` // ReachabilityState.String(): "reachable"|"unreachable"|"unknown"
Analyzer string `json:"analyzer,omitempty"` //
Confidence string `json:"confidence,omitempty"` // Confidence.String()
Facts []string `json:"facts,omitempty"` //
}
ReachabilityRecord is the flattened form of an evidence.ReachabilityEvidence, carrying its enum states as their String() forms so it round-trips cleanly.
type SourceAssessment ¶
type SourceAssessment struct {
Vulnerabilities []VulnRecord `json:"vulnerabilities"`
}
SourceAssessment is the cross-phase catalogue artifact: the source-side Assessment the audition persists so the review phase can read it back and reconcile image-scan observations against it.
func UnmarshalSourceAssessment ¶
func UnmarshalSourceAssessment(data []byte) (*SourceAssessment, error)
UnmarshalSourceAssessment parses the catalogue artifact back into a SourceAssessment.
type Surface ¶
type Surface string
Surface is the artifact an advisory was observed on: the project's SOURCE (manifests/lockfiles scanned before build) or the built IMAGE (a container scan in the review phase). One canonical advisory may be seen on either or both; recording the surface lets review reconcile image-scan observations against the source Assessment persisted by the audition.
type Verdict ¶
type Verdict int
Verdict is the analysis-layer severity classification for a canonical vulnerability — the single verdict rendered per advisory. Its tiers mirror the lint severity tiers (info / warning / critical) WITHOUT importing lint; the render layer maps a Verdict to a lint.Severity one-to-one.
type VulnRecord ¶
type VulnRecord struct {
ID string `json:"id"`
Aliases []string `json:"aliases,omitempty"`
Severity string `json:"severity,omitempty"`
Verdict string `json:"verdict"` // v.Verdict.String()
Packages []string `json:"packages,omitempty"`
File string `json:"file,omitempty"`
Line int `json:"line,omitempty"`
Ecosystem string `json:"ecosystem,omitempty"`
Surfaces []string `json:"surfaces,omitempty"` // Surface values as strings
Reachability *ReachabilityRecord `json:"reachability,omitempty"`
}
VulnRecord is the serialization-clean form of a canonical Vulnerability for the cross-phase catalogue artifact. Flat, JSON-stable — no Go interfaces.
func ToRecord ¶
func ToRecord(v Vulnerability) VulnRecord
ToRecord converts a canonical Vulnerability to its serialization-clean form, flattening any attached reachability evidence.
type Vulnerability ¶
type Vulnerability struct {
ID string
Aliases []string
Severity string
FixedIn string
Summary string
Packages []string
File string
Line int
Verdict Verdict
// Ecosystem is the representative ecosystem for this advisory, used to route
// evidence contributors (e.g. "gomod" → the Go reachability analyzer). Chosen
// deterministically by mergeComponent.
Ecosystem string
// Surfaces is the DISTINCT surfaces this advisory was observed on, sorted and
// deduped — [source], [image], or [image source]. Aggregated by mergeComponent
// from the component's observations; an observation with an empty Surface
// contributes nothing.
Surfaces []Surface
// Evidence holds enrichment facts (reachability today; KEV/EPSS/fix later)
// attached by Assess. Reduce attaches none, so it stays nil there.
Evidence []evidence.Evidence
}
Vulnerability is one canonical advisory: the union of every observation that describes it. It carries the highest severity seen, a representative summary/fixed-in, and the set of affected packages (each "name@version" when a version is known). Verdict is assigned by evaluate. File/Line attribute the single rendered finding to a representative source location.
func Assess ¶
func Assess(ctx context.Context, obs []AdvisoryObservation, target evidence.Target, reg *evidence.Registry) []Vulnerability
Assess is Reduce plus evidence enrichment: canonicalize (pure) -> enrich via contributors (I/O) -> evaluate (pure, now evidence-aware). Callers with no registry use Reduce; Assess is for the audition path that runs govulncheck.
func Reduce ¶
func Reduce(obs []AdvisoryObservation) []Vulnerability
Reduce composes canonicalize → evaluate: it groups observations into one Vulnerability per advisory and assigns each a Verdict. Pure and deterministic — the same observations always produce the same vulnerabilities in the same order.