Open-Source Wikis

/

Grype

/

Grype

/

Architecture

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| Matchers

Schema, 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:

  1. Hard-coded explicit ignores (grype/match/explicit_ignores.go) — known false positives (e.g. linux-kernel-headers indirect matches).
  2. CVE normalization — when --by-cve is set, advisory IDs are rewritten to their CVE identifier via normalizeByCVE.
  3. User ignore rulesmatch.IgnoreRule entries from CLI flags (--ignore-states, --only-fixed, --only-not-fixed) and config files.
  4. VEX processing — OpenVEX and CSAF documents from grype/vex/. Statuses not_affected and fixed move matches to the ignored set; affected can be augmented in.
  5. Severity gating — if --fail-on is set, exit code 2 is 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) — emits event.VulnerabilityScanningStarted and progress events consumed by the bubbletea UI in cmd/grype/cli/ui/.
  • Logging (internal/log/) — wraps anchore/go-logger; matchers log at trace/debug levels.
  • Redaction (internal/redact/) — rewrites configured secret values out of logs.
  • Configclio + fangs provide a layered config (CLI flags, env vars, YAML file at ~/.grype.yaml or --config).

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Architecture – Grype wiki | Factory