Documentation
¶
Overview ¶
Package osv resolves vulnerability advisories for a package version from the OSV database (https://osv.dev).
An advisory is keyed by every identifier it is known by (its own OSV id plus every alias, such as CVE- and GHSA- ids), and the record that actually carries package-level detail wins when the same key is contributed by more than one source record.
The Go database is the only one that publishes vulnerable import paths, so Advisory.Pkgs is populated for Go refs and left empty for everything else -- see advisoryFor.
Index ¶
Constants ¶
const DefaultBaseURL = "https://api.osv.dev/v1"
DefaultBaseURL is the OSV v1 API root. Endpoints are derived from it.
const GoEcosystem = "Go"
GoEcosystem is the OSV ecosystem name for Go modules and the standard library.
Variables ¶
var ErrUnknownDistro = errors.New("no OSV ecosystem is known for this distribution")
ErrUnknownDistro is returned by Release.Ecosystem when the distribution has no entry in the mapping table. It is deliberately an error and never an empty string: a missing ecosystem must stop the scan, because an OSV query with no ecosystem finds nothing and reads exactly like a clean image.
Functions ¶
func Families ¶
func Families() []string
Families lists the OSV ecosystem families Ecosystem can produce, without their version suffixes. It is what --ecosystem accepts for OS packages, and it lives beside the mapping so the two cannot drift apart.
func KnownDistroIDs ¶
func KnownDistroIDs() []string
KnownDistroIDs lists the os-release ID values Ecosystem can map, for error messages.
func MatchesProductRelease ¶
MatchesProductRelease reports whether an OSV affected-entry ecosystem string names a product of the given release.
eco is the full affected-entry spelling ("SUSE:Linux Enterprise Module for Basesystem 15 SP7"); release is a ProductRelease token ("15 SP7"). The support-phase suffix is dropped before comparing, because it distinguishes subscriptions rather than releases: an image running 15 SP4 is described by the "15 SP4-LTSS" records whether or not its owner holds that subscription.
Types ¶
type Advisory ¶
type Advisory struct {
// ID is the canonical OSV identifier (e.g. GO-2024-1234, DSA-5678-1).
ID string
// Aliases are all other identifiers this advisory is known by.
Aliases []string
// Summary and Details are the advisory prose. They are the input to
// advisory-text mining for ecosystems that publish no package-level data.
Summary string
Details string
// Pkgs is the set of vulnerable import paths declared for a Go module.
// Empty when OSV publishes no import paths (e.g. GitHub-only GHSA
// records), in which case callers should fall back to module granularity,
// and always empty for non-Go ecosystems.
Pkgs []string
}
Advisory is the resolved information for a single vulnerability id.
type Client ¶
type Client struct {
HTTP *http.Client
// BaseURL is the API root; DefaultBaseURL when empty.
BaseURL string
// Concurrency bounds the parallel per-id fetches QueryBatch makes;
// defaultConcurrency when zero.
Concurrency int
}
Client queries the OSV API.
func (*Client) Query ¶
Query returns the map of advisory-id -> Advisory for ref. Every alias identifier is a key in the returned map, so a caller may look up a CVE, GHSA or GO id interchangeably.
func (*Client) QueryBatch ¶
QueryBatch resolves many refs at once. result[i] is what Query(refs[i]) would have returned, so the answer is always the same length as refs.
A whole-image scan is thousands of lookups; one /v1/query round trip each is not viable. /v1/querybatch takes 1000 refs per request but answers with ids only, so every distinct id is then fetched once through /v1/vulns/{id} -- distinct being the point, since an OS advisory typically covers many of the packages in one image.
type Ref ¶
type Ref struct {
// Ecosystem is an OSV ecosystem string, e.g. "Go", "Debian:12",
// "Alpine:v3.19". See Release.Ecosystem for how these are derived for OS
// distributions.
Ecosystem string
Name string
Version string
// Release narrows a bare-family ecosystem to a single product release. It
// is empty for every ecosystem whose query already names its release, and
// when set an advisory survives only if one of its affected entries names
// a product of that release. See Release.ProductRelease for why SUSE
// cannot be handled in the query itself.
Release string
}
Ref is an OSV package coordinate: an ecosystem name, a package name as that ecosystem's database spells it, and a version. Version may be empty to ask for every advisory against the package regardless of version.
type Release ¶
type Release struct {
ID string // ID=
IDLike []string // ID_LIKE=
Version string // VERSION=
VersionID string // VERSION_ID=
VersionCodename string // VERSION_CODENAME=
PrettyName string // PRETTY_NAME=
CPEName string // CPE_NAME=
}
Release is the subset of /etc/os-release needed to name an OSV ecosystem.
func ParseOSRelease ¶
ParseOSRelease reads the os-release(5) key=value format.
func (Release) Ecosystem ¶
Ecosystem returns the OSV ecosystem string for this release.
The strings below were verified against the live api.osv.dev rather than read off the schema, because the API validates them asymmetrically: the family name is checked -- a misspelled "Debain:12" is rejected with HTTP 400 and {"code":3,"message":"invalid ecosystem"} -- but the version suffix is not. "Debian:99" answers HTTP 200 with an empty result, indistinguishable from a clean image. That asymmetry is why this is a table with tests rather than a format string, and why an unrecognized distribution is an error.
The suffix rules are not uniform and none of them are guessable:
Debian major only Debian:12 (bare "Debian" over-matches every release)
Ubuntu ":LTS" only when LTS Ubuntu:24.04:LTS ("Ubuntu:24.10" for a non-LTS release)
Alpine "v" prefix, no patch Alpine:v3.19 ("Alpine:3.19" finds nothing)
Azure Linux major only Azure Linux:3 ("Azure Linux:3.0" finds nothing)
openEuler "-LTS" when LTS openEuler:24.03-LTS
openSUSE product name from PRETTY_NAME
Red Hat bare -- see below
SLE bare + ProductRelease narrowing -- see below
func (Release) ProductRelease ¶
ProductRelease is the release token an affected entry must carry for this image, or "" when no narrowing applies.
It exists for the bare-family ecosystems, where a query matches records from every product the vendor ships. That over-matching is not benign for SUSE: gzip is fixed at 1.10-150200.13.1 on SLE 15 and at 1.13-160000.3.1 on SLE 16, so a *fully patched* SLES 15 SP7 image still matches the SLE 16 record, and no amount of patching will ever clear it. Version comparison cannot sort this out, because the two products' version lines never converge.
The token is the trailing version part of the product name -- "15 SP7" for SLES 15 SP7, "5.5" for SLE Micro 5.5 -- which is the one component every spelling of a product shares, module and support-phase suffix included.
type StatusError ¶
StatusError is a non-200 answer from the OSV API.
func (*StatusError) Error ¶
func (e *StatusError) Error() string
func (*StatusError) Retryable ¶
func (e *StatusError) Retryable() bool
Retryable reports whether repeating the request could plausibly succeed.
A 4xx other than 429 is a defect in the request, not a transient fault. The one that matters here is an unrecognized ecosystem name: OSV answers {"code":3,"message":"invalid ecosystem"} with HTTP 400. Retrying that three times and then reporting "unexpected status 400" buries the one message that says what is wrong.