ecosystem

package
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: Aug 6, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package ecosystem defines the contract every language or OS package ecosystem implements so vexscan can triage it.

The governing rule is that a plugin brings a *deterministic presence test* and nothing else. Plugins never query OSV and never call the LLM: the orchestrator resolves advisories and applies the optional LLM overlay itself. That makes "the LLM is advisory, never the primary signal" a structural property of the code rather than a convention someone has to remember.

Index

Constants

View Source
const (
	OriginSBOM               = "sbom-metadata"
	ReasonNoReachabilityTest = "no_reachability_test_possible"
)

OriginSBOM is the evidence origin on every finding produced from a bill of materials, and ReasonNoReachabilityTest is the reason those findings carry.

They live here rather than in one plugin because five plugins write them and the report reads them: --sbom hands an inventory to all of os, golang, npm, pypi and maven at once, and the report's caveat sizes itself by counting the reason. A per-plugin spelling would make that count silently short by whichever plugins spelled it differently, and a caveat that undercounts the rows it explains is worse than no caveat.

OriginSBOM is an evidence origin rather than a method. It names the absence of a test and not a test: a bill of materials says a package is there, which no plugin here can turn into a statement about whether its code would run.

Variables

This section is empty.

Functions

func MatchEcosystem

func MatchEcosystem(p Plugin, selector string) bool

MatchEcosystem reports whether selector names a plugin, by its ID or by one of the OSV ecosystems it produces. Matching is case-insensitive and matches an unversioned family against a versioned ecosystem ("debian" vs "Debian:12").

func UsesHints

func UsesHints(p Plugin) bool

UsesHints reports whether a plugin opted into advisory mining.

Types

type Component

type Component struct {
	// Ecosystem is the OSV ecosystem string ("Go", "Debian:12", "PyPI").
	Ecosystem string

	// Release narrows a bare-family Ecosystem to one product release, and is
	// empty unless the ecosystem needs it. Only SUSE does today: its query has
	// to be the bare family to match anything, so the product an advisory
	// applies to can only be checked after the fact. See osv.Ref.Release.
	Release string

	// Name is the package name *as OSV keys it*. For deb and rpm that is the
	// source package, not the binary package the database lists — getting this
	// backwards produces both false negatives and false positives, so plugins
	// map it during inventory rather than leaving it to the orchestrator.
	Name string

	// AltNames are further names to query OSV under, beyond Name.
	//
	// This exists because "which name does the advisory database key this
	// package on" has no consistent answer, even within one package format.
	// Debian and Alpine file against the source package, Red Hat and AlmaLinux
	// against the binary package, and Rocky Linux -- a rebuild of Red Hat --
	// against the source package like its upstream does not. Querying both
	// costs one extra entry in a batch request; picking the wrong single name
	// reports a vulnerable package as clean.
	//
	// The advisories from every name are merged into one set, so an advisory
	// filed under both names produces one finding, not two.
	AltNames []string

	// Version is the version string OSV can compare.
	Version string

	// PURL is the package URL. It is the stable identity in output and the key
	// a future vendor-VEX layer will match statements on.
	PURL string

	// Locations are the paths inside the target this component occupies or is
	// linked into. In Go image mode these are the binaries linking the module,
	// which is what lets the Go plugin keep its existing per-binary output
	// shape without a special case: one component per (module, version), one
	// finding per (binary, advisory).
	Locations []string

	// Extra is plugin-private state carried from inventory to analysis — a
	// loaded symbol table, the file list a package owns. The orchestrator never
	// inspects it.
	Extra any
}

Component is one installed thing a plugin found: a Go module, an OS package, a Python distribution.

func (Component) Key

func (c Component) Key() string

Key identifies a component for advisory resolution. Components sharing a key need only one OSV lookup between them.

type EcosystemResult

type EcosystemResult struct {
	ID string `json:"id"`
	// Ecosystems are the concrete OSV ecosystem strings that were detected
	// ("Debian:12"), not the families the plugin supports.
	Ecosystems []string `json:"ecosystems,omitempty"`
	// Components is how many the inventory phase found.
	Components int `json:"components"`
	// Error is set when the plugin could not complete. Findings for this
	// ecosystem are then absent, not empty.
	Error string `json:"error,omitempty"`
}

EcosystemResult records how one plugin fared, independently of its findings.

It exists so a failure is never indistinguishable from a clean result. A plugin that found a package database and could not read it reports the error here and contributes no findings, rather than contributing an empty inventory that renders as "nothing vulnerable".

type Evidence

type Evidence struct {
	// Origin names what produced the observation: "pclntab", "govulncheck",
	// "pkgdb-inventory", "elf-needed-closure", "llm-mined", "vendor-vex".
	Origin string `json:"origin"`

	// Detail is a short statement of what was observed.
	Detail string `json:"detail"`

	// Blocking marks a taint: something that prevents concluding the component
	// is unaffected. A taint never sets a status by itself — it stops the
	// analysis from reaching a not_affected one, and says why in the output.
	Blocking bool `json:"blocking,omitempty"`
}

Evidence is one recorded observation behind a finding.

Findings carry evidence rather than just a status so that a reader can tell a deterministic result from an advisory one, and so a future vendor-VEX layer can merge claims of different origin under a single policy instead of each source inventing its own way to overrule the others.

type Finding

type Finding struct {
	// Ecosystem is the plugin that produced this finding ("golang", "os").
	// Plugins do not set it -- the orchestrator stamps every finding with the
	// analyzer it came from, so no plugin can forget to and no plugin can
	// claim to be another.
	Ecosystem string `json:"ecosystem,omitempty"`

	// ID is the advisory, under the id the caller asked about. Same value as
	// CVE.
	ID string `json:"id"`
	// Package is the component's name in its ecosystem's terms: a Go module
	// path, an OS source package. Same value as Module.
	Package string `json:"package"`
	// Location is the path inside the target the finding is about, empty when
	// the finding is about the whole target. Same value as Binary.
	Location string `json:"location,omitempty"`
	// PURL is the component's package URL, and the key the vendor-VEX layer
	// matches statements on. Plugins set this one; nothing else can.
	PURL string `json:"purl,omitempty"`

	// Product is the purl of the shipped artifact this finding was found in --
	// the scanned image, or a Go binary's main module. It is the other half of
	// a VEX lookup: a hub keys its documents by product and names components
	// like PURL inside them.
	//
	// Plugins do not set it. The orchestrator stamps the image product on every
	// finding, and a plugin that knows a narrower artifact overrides it.
	Product string `json:"product,omitempty"`

	Binary      string   `json:"binary,omitempty"`
	Module      string   `json:"module"`
	Version     string   `json:"version"`
	CVE         string   `json:"cve"`
	GoID        string   `json:"go_id,omitempty"`
	Packages    []string `json:"packages,omitempty"`
	Granularity string   `json:"granularity,omitempty"` // package | module

	// Upstream is the CVEs this advisory says its patch fixes, when it is a
	// bundle of more than one. Distro advisories routinely are: SUSE-SU-2026
	// :0312-1 addresses eight, RHSA-2024:2447 seven, and neither id names a
	// CVE anywhere.
	//
	// Plugins do not set it; the orchestrator fills it from the OSV record.
	// Empty is the ordinary case and means the advisory is about one thing,
	// which the row already names.
	Upstream []string `json:"upstream,omitempty"`

	// FixedVersion is the version the advisory's patch lands in for this
	// finding's package, when the OSV record publishes one. It is the
	// report's one actionable field: what to upgrade to.
	//
	// Plugins do not set it; the orchestrator fills it from the OSV record's
	// affected ranges, joined on Package. Empty means no fix was published --
	// a real and common state that the renderer shows as "no fix", not as a
	// blank cell, because the two mean opposite things.
	//
	// Emitted even when empty, and that is the whole point. "" is the "no fix"
	// answer, so omitting it would drop the fact a JSON consumer most needs --
	// the flaw is acknowledged and no patch has shipped -- and leave it
	// indistinguishable from a scan run before this field existed. The text
	// report goes to the trouble of printing "no fix" rather than a blank for
	// exactly this reason; omitempty would have undone that for every
	// non-human reader. Same rule as known_exploited.
	FixedVersion string `json:"fixed_version"`

	// FixedVersions is every version the advisory published a fix in, set only
	// when there is more than one and FixedVersion is therefore a choice rather
	// than the only answer.
	//
	// A vendor maintaining several branches fixes them all: GO-2022-0623 names
	// Vault 1.5.9, 1.6.5 and 1.7.2. Those are alternatives, and the one to
	// install depends on the branch you are on, so the report shows the target
	// it picked and the ones it did not. Omitted in the ordinary single-fix
	// case, where it would only repeat FixedVersion -- unlike that field, an
	// absence here has no second meaning to lose.
	FixedVersions []string `json:"fixed_versions,omitempty"`

	// Stripped is a pointer because it is a Go-only fact with three states: a
	// binary with symbols, a binary without, and an OS package that is not a
	// binary at all. A plain bool would report every deb in the image as
	// unstripped.
	Stripped *bool `json:"stripped,omitempty"`

	// Severity is the advisory's rating, in the vocabulary of internal/cvss,
	// and CVSS is the v3 base vector it was computed from when the record
	// published one. Plugins do not set these: the orchestrator fills them
	// from advisories it has already fetched, for the same reason it stamps
	// Ecosystem, so no plugin can forget to.
	//
	// Empty means no advisory data was resolved for the finding at all, which
	// is not the same as UNKNOWN -- that is a record which was read and
	// published no rating.
	Severity string `json:"severity,omitempty"`
	CVSS     string `json:"cvss,omitempty"`

	Status        Status       `json:"status"`
	Method        string       `json:"method,omitempty"`
	Justification string       `json:"justification,omitempty"`
	Reason        string       `json:"reason,omitempty"` // for undetermined
	LLM           *llm.Verdict `json:"llm,omitempty"`
	Evidence      []Evidence   `json:"evidence,omitempty"`

	// VEX is a published vendor statement covering this finding, when a
	// --vexhub was given and one matched. It never changes Status: the verdict
	// above is what local evidence concluded, and stays comparable between a
	// run with a hub and a run without one.
	VEX *VEXStatement `json:"vex,omitempty"`

	// Priority is exploitation evidence -- an EPSS score, a KEV listing --
	// attached by --triage. Like VEX it never changes Status: whether anyone is
	// exploiting a vulnerability elsewhere says nothing about whether the code
	// is present here, which is the only question this tool answers.
	//
	// Nil means --triage was off. Non-nil with Scored false means the flag was
	// on and this finding could not be looked up, which is a different fact and
	// must not be allowed to look like a low score.
	Priority *triage.Priority `json:"priority,omitempty"`

	// Reachability is how the plugin's deterministic layer characterized a
	// genuinely-affected component, in its own words ("linked (symbols
	// retained; reachability not asserted)"). It exists so the orchestrator can
	// build an LLM prompt without knowing anything ecosystem-specific, and is
	// not serialized.
	Reachability string `json:"-"`
}

Finding is the per-location, per-advisory result.

The JSON shape is the tool's published output. Fields are added, never renamed or removed, so the Go-only spellings below stay even though every other ecosystem leaves them empty.

Identity is therefore written twice. ID/Package/Location are the ecosystem-neutral names new consumers should read; CVE/Module/Binary are the same values under the names gomod-vex published, kept so existing `jq` pipelines keep working. The orchestrator copies one onto the other rather than asking plugins to fill in both, so they cannot drift.

func SBOMAbsent added in v0.7.0

func SBOMAbsent(f Finding, name, method string) Finding

SBOMAbsent is the verdict for a package the user named that the bill of materials does not list.

Still not_present, and for the same reason a package database's silence is: the document is put forward as the complete inventory of what is there, so a name missing from it is a name that is not there. What changes is only the prose -- every plugin's own wording says "in this image", and there is no image, which in a report whose whole subject is what was and was not examined is not a detail to leave wrong.

method is the caller's own inventory method, because that is what was consulted; only the document behind it differs.

func SBOMFinding added in v0.7.0

func SBOMFinding(f Finding, name string) Finding

SBOMFinding is the verdict for a component that a bill of materials named.

There is only one, and it is undetermined. Every plugin here decides a status in two steps -- does the package ship code, and would that code be loaded -- and a CycloneDX component takes both away at once: it lists no files, so nothing rules the code out, and it comes with no tree, so nothing rules the reachability out. Anything more confident than this would be a conclusion drawn from an input that does not contain it.

A function rather than the same literal written into each plugin, because the report's caveat sizes itself by counting these rows and five spellings would make the count short.

func (Finding) Affected

func (f Finding) Affected() bool

Affected reports whether a finding is a real one — something the LLM overlay should be asked about and a reader should act on.

func (Finding) Component added in v0.2.0

func (f Finding) Component() string

Component is the installed artifact's own name: the binary package, not the source package the advisory is filed against.

For an OS package these differ, and printing Package instead makes the report appear to contradict itself. One Debian source package fans out into several binary packages with genuinely different answers -- gcc-12 ships gcc-12-base, which contains no ELF object and is not_present, alongside libgcc-s1 and libstdc++6, which are linked -- and all three are filed under the same advisory. Rendered as "gcc-12" they are three identical-looking rows with two different verdicts. The binary name is the thing that tells them apart, and it survives only in the purl.

For every other ecosystem this returns exactly what Package does, so the distinction stays confined to the case where it is real. Anything unparseable falls back to Package: a name that is merely coarse beats no name at all.

type HintConsumer

type HintConsumer interface {
	WantsHints() bool
}

HintConsumer is implemented by a plugin that can do something with hints mined from an advisory's prose.

It exists so the orchestrator does not pay for mining nobody will read. The Go plugin has pclntab, which answers presence outright; asking a model to guess at symbol names for it would be a round trip per advisory spent on an answer the plugin discards. A plugin that says yes here is also promising to validate what it receives — an unvalidated hint is indistinguishable from a hallucination, and must never reach a status.

type ImageAnalyzer

type ImageAnalyzer interface {
	Plugin

	// DetectImage reports whether this plugin applies to img at all. A plugin
	// that does not apply is skipped silently; an error means detection itself
	// failed and must be surfaced, never treated as "does not apply".
	DetectImage(ctx context.Context, img *target.Image) (bool, error)

	// InventoryImage lists the components present, restricted to subjects when
	// any are given.
	//
	// Returning an empty inventory means "nothing is installed". A plugin that
	// found a package database it could not read must return an error instead:
	// an empty inventory renders as "no vulnerable packages", which is the
	// worst possible failure mode for a tool whose output becomes an
	// attestation.
	InventoryImage(ctx context.Context, img *target.Image, subjects []Subject) ([]Component, error)

	// AnalyzeImage decides each work item. Findings must carry no LLM verdict;
	// the orchestrator adds that.
	AnalyzeImage(ctx context.Context, img *target.Image, items []WorkItem) ([]Finding, error)
}

ImageAnalyzer analyzes a container image in three phases, because the orchestrator has to sit between them: it is the one that turns an inventory into advisories, and the one that decides which advisories were asked for.

func ImageAnalyzers

func ImageAnalyzers(plugins []Plugin) []ImageAnalyzer

ImageAnalyzers filters plugins to those that can analyze an image.

type InventorySourceAnalyzer

type InventorySourceAnalyzer interface {
	Plugin

	// DetectSource reports whether this plugin applies to src.
	DetectSource(ctx context.Context, src *target.Source) (bool, error)

	// InventorySource lists the components the checkout declares, restricted
	// to subjects when any are given. The same rule as InventoryImage applies:
	// a lock file that was found and could not be parsed is an error, never an
	// empty inventory.
	InventorySource(ctx context.Context, src *target.Source, subjects []Subject) ([]Component, error)

	// AnalyzeSource decides each work item. Findings must carry no LLM verdict.
	AnalyzeSource(ctx context.Context, src *target.Source, items []WorkItem) ([]Finding, error)
}

InventorySourceAnalyzer analyzes a source checkout in the same three phases as an image, for an ecosystem whose source-mode evidence is a lock file rather than a call-graph tool.

It exists because SourceAnalyzer's two-phase shape encodes an assumption that only holds for Go: that the analysis tool supplies the advisories. A lock file supplies coordinates and nothing else, so an ecosystem reading one needs the orchestrator to sit in the middle and resolve them -- which is exactly what ImageAnalyzer's three phases are for. Reusing the phase structure means repo mode gets --cves filtering, the shared advisory cache and the LLM overlay for free, and means a plugin still cannot query OSV itself.

AnalyzeSource deliberately collides with SourceAnalyzer's method of the same name at a different signature, so a type can satisfy one interface or the other but never both. That is the correct constraint: govulncheck and a lock file are two answers to one question, and an ecosystem has to pick.

func InventorySourceAnalyzers

func InventorySourceAnalyzers(plugins []Plugin) []InventorySourceAnalyzer

InventorySourceAnalyzers filters plugins to those that analyze a checkout through an inventory rather than a call-graph tool.

type Plugin

type Plugin interface {
	// ID is the stable selector used by --ecosystem and printed in output
	// ("golang", "os", "pypi").
	ID() string

	// Ecosystems lists the OSV ecosystem strings this plugin can produce
	// components for. Distro ecosystems are versioned at detect time
	// ("Debian:12"), so the OS plugin returns the unversioned families it
	// understands ("Debian", "Alpine") and callers match on prefix.
	Ecosystems() []string
}

Plugin is what every ecosystem implements. Capability is expressed by also implementing ImageAnalyzer, SourceAnalyzer, or both.

type Registry

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

Registry holds the plugins available to a run.

func NewRegistry

func NewRegistry(plugins ...Plugin) *Registry

NewRegistry returns a registry over plugins, in the order given. Order is the order findings are produced in before the orchestrator's final sort, so it is worth keeping stable.

func (*Registry) All

func (r *Registry) All() []Plugin

All returns every registered plugin.

func (*Registry) IDs

func (r *Registry) IDs() []string

IDs returns every registered plugin's selector, sorted, for error messages and --help text.

func (*Registry) Select

func (r *Registry) Select(selectors []string) ([]Plugin, error)

Select resolves --ecosystem selectors to plugins, preserving registration order and deduplicating. An empty selector list selects everything.

An unrecognized selector is an error rather than an empty selection: silently scanning nothing because of a typo produces a clean-looking report, which is the one outcome this tool must never manufacture.

type Request

type Request struct {
	ID       string
	Advisory *osv.Advisory

	// Hints are the mined identifiers for this advisory, or nil. See
	// WorkItem.Hints for what a plugin owes them.
	Hints *llm.Hints
}

Request is one advisory to decide on, paired with the id the caller asked about -- which may be a CVE or GHSA alias rather than the record's own id.

type SourceAnalyzer

type SourceAnalyzer interface {
	Plugin

	// DetectSource reports whether this plugin applies to src.
	DetectSource(ctx context.Context, src *target.Source) (bool, error)

	// AnalyzeSource decides the requested ids against src. An empty requested
	// list means "every advisory that applies".
	AnalyzeSource(ctx context.Context, src *target.Source, subjects []Subject, requested []string) ([]Finding, error)
}

SourceAnalyzer analyzes a source checkout in two phases rather than three.

The split differs from ImageAnalyzer on purpose. In image mode the orchestrator resolves advisories, because an inventory of (name, version) pairs is exactly an OSV query. In source mode the analysis tool *is* the advisory source — govulncheck reports the module version along with the verdict — so forcing repo mode through an inventory phase would mean either running govulncheck twice or fabricating an inventory to satisfy the shape.

func SourceAnalyzers

func SourceAnalyzers(plugins []Plugin) []SourceAnalyzer

SourceAnalyzers filters plugins to those that can analyze a source checkout.

type Status

type Status string

Status classifies one (location, advisory) pair.

These five values are the tool's published vocabulary and deliberately do not grow: "the package isn't installed at all" is expressed as StatusNotPresent with a component_not_present justification, which VEX consumers already read, rather than as a sixth status every downstream parser would have to learn.

const (
	StatusNotPresent   Status = "not_present"         // vulnerable code absent
	StatusNotInPath    Status = "not_in_execute_path" // present but not reachable
	StatusLinked       Status = "linked"              // genuinely linked (image mode)
	StatusReachable    Status = "reachable"           // genuinely called (source mode)
	StatusUndetermined Status = "undetermined"        // no mapping could be resolved
)

type Subject

type Subject struct {
	// Ecosystem restricts the subject to one plugin ("golang", "os"). Empty
	// matches any plugin, which is how a bare `--package openssl` resolves
	// against whatever inventory turns out to contain it.
	Ecosystem string
	// Name is the package or module name as given, or "" for "everything".
	Name string
	// PURL is set instead of Name when the user gave a full package URL.
	PURL string
	// Raw is exactly what the user typed, for error messages.
	Raw string
}

Subject is what the user asked to scan, before anything has been resolved against a real target: the --package / --module selection.

func ParseSubject

func ParseSubject(raw string) (Subject, error)

ParseSubject turns one --package value into a Subject.

Three spellings are accepted, in the order they are tried:

pkg:golang/golang.org%2Fx%2Fnet@v0.17.0   a package URL
deb:openssl, golang:golang.org/x/net      ecosystem:name shorthand
openssl                                   a bare name, resolved by inventory

A bare name is deliberately not tied to an ecosystem: it is answered by whichever plugin's inventory turns out to contain it, which is what makes `--package openssl` work without the user knowing whether the image is Debian or Alpine.

A Maven coordinate is a bare name that contains a colon, which is why the shorthand's prefix may not contain a dot. Without that, `--package org.apache.logging.log4j:log4j-core` -- the way every Java tool in the world spells that artifact -- would parse as an unknown ecosystem named "org.apache.logging.log4j" and fail. No ecosystem selector has a dot in it, and a Go module path, the other dotted thing here, has no colon at all.

func Subjects

func Subjects(plugins []Plugin, raws []string) ([]Subject, error)

Subjects parses every --package value and checks each one against plugins, so that a selector nothing can answer is reported rather than scanned past.

The check matters more than it looks. A subject aimed at an ecosystem no selected plugin handles -- a typo, or `--package golang:x --ecosystem os` -- produces an empty inventory, and an empty inventory renders as a clean report. That is the one result this tool must never manufacture from a mistake in the command line.

func (Subject) MatchesAll

func (s Subject) MatchesAll() bool

MatchesAll reports whether s selects everything (no name and no purl).

type VEXHubResult added in v0.3.0

type VEXHubResult struct {
	URL string `json:"url"`
	// Author is whoever signed the documents actually read from this hub.
	Author string `json:"author,omitempty"`
	// Products is how many artifacts the hub indexes, and Matched how many
	// findings it spoke to.
	Products int `json:"products,omitempty"`
	Matched  int `json:"matched"`
	// Error is why the hub contributed nothing. Unlike an ecosystem error it
	// does not make the whole run incomplete: see the comment on vexOverlay.
	Error string `json:"error,omitempty"`
}

VEXHubResult records how one --vexhub fared, for the same reason EcosystemResult does: a hub that could not be reached must not look like a hub that had nothing to say.

type VEXStatement added in v0.3.0

type VEXStatement struct {
	// Status is OpenVEX's, not vexscan's: not_affected, affected, fixed,
	// under_investigation. It is deliberately a different vocabulary from
	// Finding.Status so the two can never be confused in the JSON.
	Status          string `json:"status"`
	Justification   string `json:"justification,omitempty"`
	ImpactStatement string `json:"impact_statement,omitempty"`
	ActionStatement string `json:"action_statement,omitempty"`

	Author    string `json:"author,omitempty"`
	Timestamp string `json:"timestamp,omitempty"`
	// Product is the artifact purl the statement was filed under, and Hub the
	// --vexhub it came from.
	Product string `json:"product,omitempty"`
	Hub     string `json:"hub,omitempty"`
	// Match records how the statement's component purl differed from the
	// finding's, when it did. Empty means they agreed exactly.
	Match string `json:"match,omitempty"`
}

VEXStatement is a vendor's published claim about a finding, copied out of a VEX hub document.

Everything needed to audit the claim without re-fetching the hub is here: which hub, which author, which product it was filed under, and any spelling disagreement the match tolerated to get there.

func (*VEXStatement) Exculpatory added in v0.3.0

func (v *VEXStatement) Exculpatory() bool

Exculpatory reports whether the vendor's statement says the reader has nothing to do here.

Only such a statement moves a row out of AFFECTED. A vendor confirming a finding, or saying they are still looking, must not make it quieter.

type WorkItem

type WorkItem struct {
	Component Component

	// Advisories are what the orchestrator resolved, keyed by every id each
	// advisory is known by, so a plugin can look up a CVE, GHSA or GO id
	// interchangeably.
	Advisories map[string]*osv.Advisory

	// Requested are the ids the user explicitly asked about; empty means "every
	// advisory that applies".
	Requested []string

	// Targeted says the user named this component, rather than it arriving from
	// an enumeration of everything installed.
	//
	// It decides what happens to a requested id this component has no advisory
	// for. Named, the user asked about this package and is owed an answer, so
	// the id reports undetermined; a --cves scan that silently dropped the ids
	// it could not map would read as "not affected". Enumerated, the same
	// answer repeated across four hundred packages is noise that buries the one
	// package the id actually landed on. An id that lands on nothing at all is
	// the orchestrator's to report, because it is the only thing that can see
	// the whole image at once.
	Targeted bool

	// Hints are the identifiers an LLM claimed each advisory's text names,
	// keyed by the advisory's canonical id. Present only under
	// --mine-advisories, and nil the rest of the time.
	//
	// Nothing here is a fact. A plugin must validate a hint against something
	// it can observe in the artifact before letting it support a
	// not_affected-flavored status, and an unvalidatable hint must be inert:
	// it is indistinguishable from an invented one. The validation lives in
	// the plugins because they are what hold the evidence to do it with.
	Hints map[string]*llm.Hints
}

WorkItem pairs a component with the advisories to decide on.

func (WorkItem) Requests

func (w WorkItem) Requests() []Request

Requests turns a WorkItem's requested-id list into concrete lookups.

In filter mode every requested id is returned, with a nil advisory when OSV has no mapping -- as long as the component was named. See Targeted for why an enumerated component drops the ids that do not apply to it. With no ids requested, every distinct advisory is returned under its canonical OSV id.

Directories

Path Synopsis
Package golang is the Go ecosystem plugin.
Package golang is the Go ecosystem plugin.
Package maven is the Java package ecosystem plugin.
Package maven is the Java package ecosystem plugin.
Package npm is the Node package ecosystem plugin.
Package npm is the Node package ecosystem plugin.
Package ospkg is the OS package ecosystem plugin: dpkg, apk and rpm.
Package ospkg is the OS package ecosystem plugin: dpkg, apk and rpm.
Package pypi is the Python distribution ecosystem plugin.
Package pypi is the Python distribution ecosystem plugin.

Jump to

Keyboard shortcuts

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