anchore/grype
Vulnerability database
Active contributors: Alex Goodman, Christopher Phillips, Keith Zantow
Purpose
The vulnerability database is the on-disk SQLite file that backs every Grype scan. The database layer covers four distinct concerns:
- Distribution — fetching and verifying database archives from a CDN.
- Installation — placing them in the local cache, validating, and exposing a current pointer.
- Reading — typed stores over GORM models for vulnerability, affected/unaffected packages, CPEs, operating systems, and decorators.
- Building — used by the sibling
grype-dbrepo to produce archives. Build code lives here so that the CLI can construct test databases and run schema-drift checks.
Directory layout
grype/db/
├── build.go # top-level Build() driver
├── package.go, package_legacy.go # builder helpers
├── data/ # shared data abstractions used by builders
├── default_schema_version.go
├── generate.go # go:generate hooks
├── internal/ # gormadapter, provider unmarshalling, OS codename data
│ ├── gormadapter/ # GORM + SQLite glue
│ └── provider/ # raw provider payload unmarshallers
├── processors/ # per-schema record processors
├── provider/ # provider state metadata loaded from grype-db output
├── v5/ # legacy schema (build-time only)
└── v6/ # current schema (the runtime path)
├── db.go # ModelVersion, Reader/Writer/Curator interfaces
├── store.go # concrete Reader/Writer
├── distribution/ # CDN client, listing parsing
├── installation/ # Curator
├── name/ # name normalization
├── schema/ # JSON-schema generation for blobs
├── *_store.go # one file per top-level table family
├── blobs.go, blob_store.go # JSON blob storage for compact data
└── vulnerability_provider.go # implements vulnerability.Provider over the storesSchema versioning
grype/db/v6/db.go declares:
const (
ModelVersion = 6 // breaking changes
Revision = 1 // may break some historical data
Addition = 4 // backward-compatible
)This is SchemaVer. The CLI reports the supported ModelVersion via the version subcommand:
func dbVersion() (string, any) {
return "Supported DB Schema", v6.ModelVersion
}The v6 changelog (in the same file) shows the evolution: 6.0.1 added KEV, 6.0.2 added EPSS, 6.0.3 added the channel column to OperatingSystem, 6.1.x added unaffected variants, CWEs, advisory IDs, and EOL dates.
Reader interface
Anyone wanting to read the DB does so through grype/db/v6/db.go::Reader:
type Reader interface {
DBMetadataStoreReader
ProviderStoreReader
VulnerabilityStoreReader
VulnerabilityDecoratorStoreReader
OperatingSystemStoreReader
AffectedPackageStoreReader
UnaffectedPackageStoreReader
AffectedCPEStoreReader
UnaffectedCPEStoreReader
io.Closer
attachBlobValue(...blobable) error
}Each *StoreReader interface is defined in the corresponding *_store.go file. They expose typed query methods like GetVulnerabilities(by Reference, opts ...Option).
Vulnerability provider
grype/db/v6/vulnerability_provider.go adapts the typed stores into the higher-level vulnerability.Provider interface (grype/vulnerability/provider.go):
type Provider interface {
PackageSearchNames(grypePkg.Package) []string
FindVulnerabilities(criteria ...Criteria) ([]Vulnerability, error)
MetadataProvider
io.Closer
}Matchers always use Provider. The implementation translates criteria... into store-specific queries, joins blob data via attachBlobValue, and returns hydrated vulnerability.Vulnerability objects.
The provider also implements optional capabilities detected by the matcher pipeline:
vulnerability.EOLChecker— used byvulnerability_matcher.go::eolTrackerto flag end-of-life distros.vulnerability.StoreMetadataProvider— used by presenters to surface per-provider provenance.
Distribution + Installation
The two halves of fetching:
graph LR
Listing[listing.json on CDN] --> Client
Client[v6/distribution.Client] -->|verify checksum, hash| Archive[.tar.zst]
Archive --> Curator[v6/installation.Curator]
Curator --> Local[~/.cache/grype/db/<schema>/]
Local --> Reader[v6.Reader]installation.Curator exposes:
type Curator interface {
Reader() (Reader, error)
Status() vulnerability.ProviderStatus
Delete() error
Update() (bool, error)
Import(dbArchivePath string) error
}grype.LoadVulnerabilityDB (grype/load_vulnerability_db.go) wires the two together with a single call:
func LoadVulnerabilityDB(distCfg v6dist.Config, installCfg v6inst.Config, update bool) (vulnerability.Provider, *vulnerability.ProviderStatus, error) {
client, err := v6dist.NewClient(distCfg)
c, err := v6inst.NewCurator(installCfg, client)
if update { c.Update() }
s := c.Status()
rdr, err := c.Reader()
return v6.NewVulnerabilityProvider(rdr), &s, nil
}Status() returns a ProviderStatus carrying SchemaVersion, Built time, From URL, and Path. The CLI logs all four when DB load completes.
Building (grype-db side)
grype/db/build.go::Build is the top-level builder used by grype-db. It:
- Selects the right schema processors (
v5.Processorsorv6.Processors). - Constructs a
data.Writerfor the schema. - Streams provider results from
grype/db/provider/and writes records viadata.Processor. - Optionally hydrates the v6 DB (runs migrations and indexes after data import).
The builder is what gets exercised by the schema drift checks (task check-db-schema-drift).
Blob storage
Several v6 tables store JSON blobs rather than fully-normalized rows — large fields like AffectedPackageBlob are marshaled to JSON and pointed to by id. grype/db/v6/blob_store.go handles deduplication via content hash, and blobs.go defines the JSON shapes. Blob schemas are generated under grype/db/v6/schema/ and validated by drift checks.
Decorator store
vulnerability_decorator_store.go joins external prioritization data onto vulnerability records:
- CISA KEV — boolean "known exploited" flag, source URL, date added.
- EPSS — daily exploit-prediction scores + percentiles.
Decorations are loaded via vulnerability_provider.go when callers ask for vulnerabilities through the high-level provider.
Search query construction
grype/db/v6/search_query.go builds the GORM queries used by the stores. It exposes filters like BySeverity, ByID, ByEcosystem, etc. These are largely consumed by cmd/grype/cli/commands/db_search*.go and by the matcher pipeline.
Key source files
| File | Purpose |
|---|---|
grype/db/v6/db.go |
Schema constants, Reader/Writer/Curator interfaces. |
grype/db/v6/store.go |
Concrete *store implementing both interfaces. |
grype/db/v6/vulnerability_provider.go |
Adapts stores to vulnerability.Provider. |
grype/db/v6/models.go |
GORM models for the v6 schema. |
grype/db/v6/distribution/ |
CDN client. |
grype/db/v6/installation/ |
Local cache curator. |
grype/db/v6/blobs.go + blob_store.go |
JSON blob storage. |
grype/db/v6/search_query.go |
Query builder. |
grype/db/build.go |
Top-level builder for grype-db. |
grype/load_vulnerability_db.go |
Convenience wrapper used by the CLI. |
Entry points for modification
- Add a new field to a vulnerability — extend the GORM model in
models.go, bumpAddition, regenerate JSON schemas (task generate-db-schema), update the writer to populate it, and have the reader hydrate it throughattachBlobValueif it's a blob field. - Add a new top-level table — add the model, a sibling
*_store.gowith reader/writer interfaces, register it inModels(), and surface it in theReader/Writeraggregate interfaces. - Change query semantics — modify
search_query.go. Be aware that test coverage for query construction is dense (search_query_test.gohas thousands of lines).
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.