Open-Source Wikis

/

Grype

/

How to contribute

/

Patterns and conventions

anchore/grype

Patterns and conventions

The recurring shapes you will see across the Grype codebase.

File and package layout

  • One concept per package. Most packages export 5–20 symbols and live in a single directory.
  • Tests sit next to the code. Snapshot files (__snapshots__/) are committed.
  • Mocks live in a sibling mock/ package (e.g. grype/vulnerability/mock/).
  • Test data lives in testdata/ directories within the package.
  • Internal helpers go under internal/ directories — not exported across the module boundary.

Configuration with clio + fangs

CLI options follow the anchore/clio + anchore/fangs pattern:

  • Each subcommand defines a *Options struct (e.g. cmd/grype/cli/options/grype.go::Grype).
  • Struct tags drive both YAML config keys and CLI flags.
  • DefaultGrype(id) returns a fully-populated default options struct.
  • The option struct exposes converters like ToClientConfig() and ToCuratorConfig() to translate to internal types.

Add a new flag by extending the relevant options struct, wiring its mapstructure:"..." tag, and adding a default in the Default* constructor.

Error handling

  • Wrap with fmt.Errorf("...: %w", err). Sentinel errors live in grype/grypeerr/ (ErrAboveSeverityThreshold, ErrDBUpgradeAvailable).
  • The CLI translates sentinels to numeric exit codes in cmd/grype/cli/cli.go::SetupConfig::WithMapExitCode.
  • Matchers must never panic. vulnerability_matcher.go::callMatcherSafely recovers panics into match.NewFatalError.
  • Use errors.Join(...) to aggregate per-matcher errors so the user sees them all.

Matcher contract

Implement match.Matcher:

type Matcher interface {
    PackageTypes() []syftPkg.Type
    Type() MatcherType
    Match(vp vulnerability.Provider, p pkg.Package) ([]Match, []IgnoreFilter, error)
}

Conventions:

  • One matcher per ecosystem under grype/matcher/<ecosystem>/.
  • Expose a MatcherConfig struct and a New<Name>Matcher(cfg) constructor; embed in matcher.Config.
  • Use the shared search helpers in grype/matcher/internal/ (CPE search, distro search, language search).
  • Return IgnoreFilters for matches that should be downgraded by other matchers (e.g. indirect matches that should be replaced by direct ones).

Vulnerability provider abstraction

Always go through vulnerability.Provider (grype/vulnerability/provider.go):

type Provider interface {
    PackageSearchNames(grypePkg.Package) []string
    FindVulnerabilities(criteria ...Criteria) ([]Vulnerability, error)
    MetadataProvider
    io.Closer
}

Build queries with grype/search/criteria.go builders rather than poking the GORM DB directly. Optional capabilities (EOLChecker, StoreMetadataProvider) are detected via type assertion.

Bus events for progress

Long-running operations publish to the partybus.Bus (set by internal/bus/):

bus.Publish(partybus.Event{
    Type:  event.VulnerabilityScanningStarted,
    Value: reader,
})

Event types are declared in grype/event/. The TUI subscribes and renders progress; the CI handler swallows them.

Logging

log.WithFields("package", displayPackage(p)).Trace("...")

Conventions:

  • WithFields builds a structured logger; prefer it over log.Printf.
  • Use log.Tracef/Debugf for hot paths; log.Info for once-per-scan messages.
  • Sensitive values must be added to the redact.Store (internal/redact/) before they touch a log.

JSON output

The JSON presenter is the source of truth for the public schema. Schema generation happens in cmd/grype/cli/commands/internal/jsonschema/ and is checked by task check-json-schema-drift. Bumps require updating both the model and the schema.

Naming

  • Packages: lowercase, no underscores (vulnmatcher, presenter, matcher).
  • Files: lowercase with underscores when separating words (vulnerability_matcher.go, db_search_vuln.go).
  • Type names: PascalCase. Exported only when used across packages.
  • Test functions: Test_<Subject>_<Behavior> for unit tests; integration tests follow the same pattern with it_* files.

Linting

.golangci.yaml configures golangci-lint. Notable enabled linters:

  • funlen — long-function check (with nolint:funlen overrides where intentional).
  • staticcheck — including for deprecated APIs (MetadataProvider is the most-overridden case).
  • gosimports — replaces goimports with anchore-local sorting.

The task lint target runs both gofmt -l -s and golangci-lint. PRs must pass.

Deprecation policy

Deprecated symbols are marked with the // Deprecated: ... comment so staticcheck flags them. A few notable still-used-internally deprecations:

  • vulnerability.MetadataProvider
  • presenter.GetPresenter
  • grype/db/v5/ (entire schema) for runtime use

These will be removed in v1.0.

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

Patterns and conventions – Grype wiki | Factory