aquasecurity/trivy
fanal
Active contributors: knqyf263, DmitriyLewen, afdesk, nikpivkin
Purpose
pkg/fanal/ ("file analyzer") is the largest single subsystem in Trivy. It owns artifact inspection — turning a container image, filesystem, repository, VM image, or SBOM into a normalized set of BlobInfo records that downstream scanners consume. fanal is structured as a registry of analyzers, post-analyzers, and handlers, each of which knows about one kind of file or content.
Directory layout
pkg/fanal/
├── analyzer/ # ~80 analyzers, registered via init()
│ ├── analyzer.go # registry, types, AnalyzerGroup
│ ├── const.go # analyzer Type enum
│ ├── all/ # blank-import aggregator
│ ├── buildinfo/ # Red Hat content manifests
│ ├── config/ # configuration files (Terraform, K8s, ...)
│ ├── executable/ # generic binary detection
│ ├── imgconf/ # image config layer (history, secrets)
│ ├── language/ # 16 language ecosystems
│ ├── licensing/
│ ├── os/ # 17 OS distributions
│ ├── pkg/ # OS package managers (apk, dpkg, rpm, rpmqa)
│ ├── repo/ # apk-repo
│ ├── sbom/
│ └── secret/
├── applier/ # merges per-layer blobs into ArtifactDetail
├── artifact/ # artifact handlers (image, fs, repo, vm, sbom)
│ ├── image/
│ ├── local/ # filesystem
│ ├── repo/ # Git repository
│ ├── sbom/
│ └── vm/
├── handler/ # post-handlers (e.g., system-files cleanup)
├── image/ # container image readers (Docker engine, podman, registry, tar)
├── secret/ # built-in secret rules and matcher
├── types/ # public type definitions (BlobInfo, ArtifactInfo, ...)
├── utils/
├── vm/ # VM image readers
└── walker/ # filesystem and image-layer walkersKey abstractions
| Symbol | File | Purpose |
|---|---|---|
analyzer.AnalyzerGroup |
pkg/fanal/analyzer/analyzer.go |
Holds the registered analyzers and runs them for a single file. |
analyzer.RegisterAnalyzer |
pkg/fanal/analyzer/analyzer.go |
Init-time registration. Each analyzer adds itself. |
analyzer.RegisterPostAnalyzer |
pkg/fanal/analyzer/analyzer.go |
Same idea, but for analyzers that need the full file set. |
analyzer.Type |
pkg/fanal/analyzer/const.go |
The enum naming every analyzer (apk, dpkg, gomod, jar, dockerfile, ...). |
analyzer.AnalysisInput / AnalysisResult |
pkg/fanal/analyzer/analyzer.go |
The per-file input and output. |
walker.FS / walker.Image |
pkg/fanal/walker/ |
Walks a filesystem or image layers and feeds the analyzer group. |
artifact.Artifact |
pkg/fanal/artifact/artifact.go |
The user-facing interface (Inspect, Clean). |
artifact.Reference |
pkg/fanal/artifact/artifact.go |
Returned by Inspect; contains artifact ID, blob IDs, and metadata. |
applier.Applier |
pkg/fanal/applier/applier.go |
Combines blobs from multiple layers into one ArtifactDetail. |
image.Image |
pkg/fanal/image/image.go |
Image reader abstraction; backed by Docker engine, containerd, podman, registry, or tar. |
secret.Scanner |
pkg/fanal/secret/scanner.go |
Built-in secret matcher driven by builtin-rules.go. |
How an artifact is inspected
graph TD
Cmd[trivy <command>] -->|builds| Art[artifact.Artifact]
Art -->|Inspect ctx| Walker
subgraph Walker[walker]
FS[walker.FS / walker.Image]
FS --> AG[AnalyzerGroup.AnalyzeFile]
AG --> Analyzers[per-analyzer Analyze]
AG --> PostAnalyzers[PostAnalyze<br/>at end of walk]
end
Walker -->|BlobInfo| Cache[(cache)]
Walker -->|artifact.Reference| CmdThe walker only opens files that an analyzer says it Required(path, info). This is what keeps fanal fast: an Alpine image with thousands of files only opens the small handful that apk cares about.
Analyzer interface
Plain analyzers see one file at a time:
type analyzer interface {
Type() Type
Version() int
Analyze(ctx context.Context, input AnalysisInput) (*AnalysisResult, error)
Required(filePath string, info os.FileInfo) bool
}Post-analyzers see the full file set:
type PostAnalyzer interface {
Type() Type
Version() int
PostAnalyze(ctx context.Context, input PostAnalysisInput) (*AnalysisResult, error)
Required(filePath string, info os.FileInfo) bool
}Required is called twice for filesystem walks (once during the dry run, once during analysis) and is what determines whether the file is opened. Type() returns a analyzer.Type from const.go. Version() is bumped when the analyzer changes its output schema; the cache uses it to invalidate stale blobs.
Artifact handlers
Each artifact type has its own handler in pkg/fanal/artifact/<kind>/:
| Artifact type | File | Notes |
|---|---|---|
| Container image | pkg/fanal/artifact/image/image.go |
Walks each layer separately; supports OCI, Docker, tar. |
| Filesystem | pkg/fanal/artifact/local/fs.go |
Single synthetic layer; honors --skip-files/--skip-dirs. |
| Git repository | pkg/fanal/artifact/repo/repo.go |
Wraps local and adds repository metadata (URL, commit, branch). |
| VM image | pkg/fanal/artifact/vm/vm.go |
Mounts EBS-/QCOW2-/VMDK-style disks via pkg/fanal/vm/. |
| SBOM | pkg/fanal/artifact/sbom/sbom.go |
Reads CycloneDX or SPDX and emits synthetic blobs. |
The image handler is the most complex. It supports five image sources (registry, Docker engine, containerd, podman, tar) and per-layer caching. It uses go-containerregistry for registry/OCI work.
Walker
pkg/fanal/walker/ contains:
walker.FS— for filesystem and repository scans.walker.LayerTar— for image layers (one tar at a time).walker.VM— for VM image filesystems.
Walkers are configured with file/dir skip patterns, custom file patterns, and parallelism limits. They produce []types.AnalyzerType per blob and call the analyzer group for each matching file.
Built-in secret scanning
pkg/fanal/secret/ is special: the secret scanner runs as an analyzer over the same file walk. Built-in rules live in builtin-rules.go (~32k lines including patterns and metadata) and builtin-allow-rules.go filters out common false positives. Custom rules can be supplied via --secret-config.
Image readers
pkg/fanal/image/ is itself a small subsystem. The dispatcher in image.go accepts an image reference plus options and picks a backend:
daemon— Docker engine (/var/run/docker.sock).containerd— containerd via the v2 client.podman— Podman remote.remote— registry pull viago-containerregistry.tar/oci— local archive.
Each backend implements an Image interface that the artifact handler consumes.
Integration points
- Cache — every blob produced by fanal is keyed by content digest and stored here.
- Scan service — consumes the
artifact.Referencereturned by fanal. - Misconfiguration — config-file analyzers feed the IaC engine.
- Module system — WASM modules can register as additional analyzers.
Entry points for modification
- Add a new analyzer — implement the
analyzer(orPostAnalyzer) interface inpkg/fanal/analyzer/<kind>/<name>.go, register it ininit(), add the constant inconst.go, and import it inpkg/fanal/analyzer/all/all.go. - Add an artifact handler — implement
artifact.Artifactinpkg/fanal/artifact/<kind>/, then dispatch to it frompkg/commands/artifact/scanner.gofor the new target type. - Add an image source — implement the
Imageinterface inpkg/fanal/image/<source>/and wire it into the dispatcher. - Tweak walker behavior —
pkg/fanal/walker/fs.goandwalker/layer.go.
Key source files
| File | Purpose |
|---|---|
pkg/fanal/analyzer/analyzer.go |
Analyzer registry and group. |
pkg/fanal/analyzer/const.go |
Analyzer type enum. |
pkg/fanal/applier/applier.go |
Layer merge. |
pkg/fanal/artifact/artifact.go |
Artifact interface and Reference type. |
pkg/fanal/artifact/image/image.go |
Image artifact handler. |
pkg/fanal/artifact/local/fs.go |
Filesystem artifact handler. |
pkg/fanal/artifact/repo/repo.go |
Repository artifact handler. |
pkg/fanal/walker/fs.go |
Filesystem walker. |
pkg/fanal/walker/layer.go |
Image-layer walker. |
pkg/fanal/secret/scanner.go |
Secret analyzer. |
pkg/fanal/secret/builtin-rules.go |
Built-in secret rules. |
pkg/fanal/image/image.go |
Image source dispatcher. |
See also
- Cache system — what fanal writes into.
- Scan service — what consumes fanal's output.
- Vulnerability scanning, Secret scanning, License scanning, Misconfiguration scanning — the user-visible features that fanal feeds.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.