anchore/grype
Architecture
Grype is structured as a small CLI that orchestrates three independent subsystems: a package provider (powered by Syft), a vulnerability provider (the local database), and a set of matchers that join the two. Output is then handed to a presenter for rendering.
End-to-end scan flow
graph TD
User[grype <input>] --> Root[cmd/grype/cli/commands.Root]
Root --> Parallel{parallel}
Parallel -->|load DB| LoadDB[grype.LoadVulnerabilityDB]
Parallel -->|catalog| Provide[pkg.Provide]
LoadDB --> Provider[v6.NewVulnerabilityProvider]
Provide --> Packages[pkg.Package + pkg.Context]
Provider --> VM[VulnerabilityMatcher.FindMatches]
Packages --> VM
VM --> Matchers[matcher.NewDefaultMatchers]
Matchers -->|apk, dpkg, rpm, java, ...| DB[(vulnerability.db)]
VM --> Filter[Apply ignore rules + VEX]
Filter --> Decorate[EPSS / KEV decoration]
Decorate --> Presenter[presenter.GetPresenter]
Presenter --> Output[stdout / file]The orchestration lives in cmd/grype/cli/commands/root.go's runGrype function. DB loading and package cataloging are launched in parallel via parallel(...) so the slow steps overlap.
Package cataloging
pkg.Provide (in grype/pkg/provider.go) inspects the user input string and dispatches to the right provider:
| Input form | Provider |
|---|---|
image:tag, dir:, file:, docker-archive:, oci-dir:, singularity:, registry: |
syft_provider.go (delegates to Syft for cataloging). |
sbom:path/to/file, stdin |
syft_sbom_provider.go (decodes Syft JSON / SPDX / CycloneDX). |
purl:path or pkg:... |
purl_provider.go (one or many PURLs). |
cpes:path or cpe:2.3:... |
cpe_provider.go (raw CPE matching). |
The providers all converge on []pkg.Package plus a pkg.Context that carries distro identification (grype/distro/distro.go) and detection signals.
Vulnerability database
The DB is a SQLite file (vulnerability.db) downloaded by the curator and read through GORM-backed stores:
graph LR
Listing[listing.json on CDN] --> Client[v6/distribution.Client]
Client --> Curator[v6/installation.Curator]
Curator --> Reader[v6.Reader]
Reader -->|VulnerabilityStoreReader| VulnTable[(vulnerability)]
Reader -->|AffectedPackageStoreReader| PkgTable[(affected_package)]
Reader -->|AffectedCPEStoreReader| CPETable[(affected_cpe)]
Reader -->|VulnerabilityDecoratorStoreReader| Decorators[(EPSS, KEV)]
Reader --> VP[v6.VulnerabilityProvider]
VP -->|FindVulnerabilities| MatchersSchema, models, and version constants live in grype/db/v6/db.go. The schema follows SchemaVer (ModelVersion=6, Revision, Addition); breaking schema bumps require a binary that supports the new ModelVersion. Older v5 code is still present under grype/db/v5/ for build-time compatibility but is deprecated for runtime use.
Matchers
Each ecosystem has its own match.Matcher implementation under grype/matcher/<ecosystem>/. The default set is assembled in grype/matcher/matchers.go:
func NewDefaultMatchers(mc Config) []match.Matcher {
return []match.Matcher{
dpkg.NewDpkgMatcher(mc.Dpkg),
ruby.NewRubyMatcher(mc.Ruby),
// ... python, dotnet, rpm, java, javascript, apk, golang,
// msrc, portage, rust, hex, stock, bitnami, pacman
}
}grype.VulnerabilityMatcher (grype/vulnerability_matcher.go) builds an index from syftPkg.Type to []match.Matcher, falls back to the stock matcher for unknown types, and runs each package through its assigned matchers. Unknown panics in a matcher are converted to fatal errors via callMatcherSafely.
Each matcher returns []match.Match plus a list of match.IgnoreFilters; matches are deduplicated by Fingerprint (see grype/match/match.go) and merged when only the match-type differs (direct vs indirect).
Filtering pipeline
After matchers run, the matcher pipeline applies, in order:
- Hard-coded explicit ignores (
grype/match/explicit_ignores.go) — known false positives (e.g. linux-kernel-headers indirect matches). - CVE normalization — when
--by-cveis set, advisory IDs are rewritten to their CVE identifier vianormalizeByCVE. - User ignore rules —
match.IgnoreRuleentries from CLI flags (--ignore-states,--only-fixed,--only-not-fixed) and config files. - VEX processing — OpenVEX and CSAF documents from
grype/vex/. Statusesnot_affectedandfixedmove matches to the ignored set;affectedcan be augmented in. - Severity gating — if
--fail-onis set, exit code2is returned when any match meets/exceeds the threshold (grype/grypeerr/).
Output
internal/format/ (and grype/presenter/) wire format names to presenters. The models.PresenterConfig carries everything a presenter needs: matches, ignored matches, packages, context, DB status, applied VEX rules, and provenance. Built-ins:
| Format | Path |
|---|---|
table (default) |
grype/presenter/table/ |
json |
grype/presenter/json/ |
cyclonedx-json, cyclonedx-xml |
grype/presenter/cyclonedx/ |
sarif |
grype/presenter/sarif/ |
template |
grype/presenter/template/ |
embedded-cyclonedx-vex-json/xml |
grype/presenter/cyclonedx/ |
The explain subcommand (cmd/grype/cli/commands/explain.go + grype/presenter/explain/) is a separate post-scan analyzer that takes a JSON report and produces a human-readable rationale per match.
Cross-cutting infrastructure
- Event bus (
internal/bus/,wagoodman/go-partybus) — emitsevent.VulnerabilityScanningStartedand progress events consumed by the bubbletea UI incmd/grype/cli/ui/. - Logging (
internal/log/) — wrapsanchore/go-logger; matchers log at trace/debug levels. - Redaction (
internal/redact/) — rewrites configured secret values out of logs. - Config —
clio+fangsprovide a layered config (CLI flags, env vars, YAML file at~/.grype.yamlor--config).
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.