@codacy/tools-trivy-0
v0.21.0
Published
Trivy adapter — CLI-mode security scanner
Readme
@codacy/tools-trivy-0
Table of Contents
- Overview
- Umbrella patterns
- Issue parity with
codacy-trivy - DB update management
- Malicious package detection
- Updating patterns
- Updating the Trivy version
- Development
- Notes for maintainers
Overview
Security scanner using the Trivy binary. Scans for vulnerabilities in dependencies and hardcoded secrets. Uses the CLI execution strategy with two separate scan modes (vulnerability + secret).
| Property | Value |
| ------------- | ------------------------------------------- |
| Tool ID | Trivy |
| Codacy UUID | 2fd7fbe0-33f9-4ab3-ab73-e9b62404e2cb |
| Strategy | CLI |
| Languages | Multi-language (scans dependency manifests) |
| Binary | trivy |
| File patterns | * (auto-detects dependency manifests) |
| Pattern count | 6 (umbrella patterns) |
Umbrella patterns
Trivy uses umbrella patterns rather than individual CVE patterns:
| Pattern ID | Severity | Description |
| ------------------------------ | -------- | ------------------------------------ |
| Trivy_vulnerability_critical | Error | Critical vulnerabilities |
| Trivy_vulnerability_high | High | High-severity vulnerabilities |
| Trivy_vulnerability_medium | Warning | Medium-severity vulnerabilities |
| Trivy_vulnerability_minor | Info | Low-severity vulnerabilities |
| Trivy_secret | Error | Hardcoded secrets |
| Trivy_malicious_packages | Error | Malicious packages (via OSV.dev API) |
Issue parity with codacy-trivy
Codacy Cloud analyses repositories with the codacy-trivy Docker engine, so a
repository scanned locally and uploaded must produce the same results as the same
repository scanned on the cloud. Three pieces of this adapter exist only to hold
that line; the reference implementation is codacy-trivy
internal/tool/tool.go, and the ports live in src/vuln-mapping.ts
(fallbackSearchForLineNumber, findLeastDisruptiveFixedVersion,
purlPrettyPrint). Change them only alongside that file.
sourceId — why every issue carries its CVE
Codacy derives a result's deterministic UUID from an MD5 over four keys: filename,
pattern id, the line's text with whitespace stripped, and sourceId
(codacy-worker shared/rules/…/rules/components/ResultUUIDRules.scala).
Trivy reports many CVEs under one of four severity umbrella patterns, so two CVEs
on the same lockfile line share three of those four keys. Without sourceId
they collapse into a single Codacy result. Every issue this adapter produces
therefore sets it:
| Finding | sourceId |
| ----------------- | ----------------------------- |
| Vulnerability | VulnerabilityID (the CVE) |
| Secret | Trivy's RuleID |
| Malicious package | The OSV advisory id (MAL-…) |
src/metadata.ts sets needsSourceIdUpload: true, which is what makes
upload include the field in the v2 payload (mirroring
needs_source_id_upload in the Go CLI's Trivy plugin manifest). Adapters without
the flag omit the field entirely — sending it where the cloud engine does not
would give the same finding a different UUID.
Scan flags that affect what is found
The vulnerability scan passes --detection-priority comprehensive, matching
codacy-trivy's DetectionPriority: PriorityComprehensive. It reports more
vulnerabilities — some of which may be false positives — and it is required for Go
standard-library findings: verified against trivy 0.70, a go.mod scan without it
reports zero stdlib vulnerabilities (6 issues instead of 26 on a small
go 1.20 module). Removing the flag would silently drop every stdlib finding and
make the go.mod handling below dead code.
Line-number resolution
Trivy reports no line for a vulnerable dependency, so the line is reconstructed:
- Look up the package's
Locations[0].StartLine, keyed by PURL — the key the cloud engine uses.PkgIDis a secondary key for the rare package Trivy reports without a PURL. - On a miss or a zero, scan the manifest top to bottom for the first line whose trimmed text contains the package name.
- Still nothing ⇒ emit a file-level error (
Line numbers not supported, deduplicated to one per file), not an issue on line 1. A confidently wrong location is worse than an honest "unknown";codacy-trivymakes the same call viamapIssuesWithoutLineNumber.
go.mod standard library. Trivy reports standard-library vulnerabilities against
a package named stdlib, which never literally appears in go.mod. Trivy
documents
using the minimum of the toolchain and go directives, but in practice always
uses toolchain when it exists. So the scan returns the toolchain line as soon
as it sees one, and only falls back to the go directive line after reading the
whole file. This is not derivable from Trivy's docs — do not "simplify" it.
Fix version
Trivy's FixedVersion is a comma-separated list of every fixing version
("1.9.0, 1.10.0, 2.0.1"). The message reports only the least disruptive one: the
smallest candidate strictly greater than the installed version, by semantic
version. When no candidate is greater (or the scheme isn't semver — Ruby's ~>,
Maven qualifiers), Trivy's raw value is passed through; when FixedVersion is
empty the message reads (no fix available).
Message format, matching the cloud engine verbatim:
Insecure dependency {pretty-printed PURL} ({CVE}: {title}) (update to {version})
Insecure dependency {pretty-printed PURL} ({CVE}: {title}) (no fix available)Comparison uses a port of Go's golang.org/x/mod/semver (compareSemver), not
npm semver: it accepts two-component versions like v1.2, and treats an
unparseable version as lower than any valid one, which is what makes non-semver
schemes fall through instead of being ranked.
Known divergences
Both are deliberate; see docs/tech-debt.md.
- Fix-version ordering.
codacy-trivysorts the candidate strings before adding thevprefix, sox/mod/semversees them all as invalid, compares them equal, and falls back to a lexicographic tiebreak — picking1.10.0over1.9.0. We sort on the prefixed values and return the genuinely smallest. - Packages without a PURL.
codacy-trivyskips those vulnerabilities entirely. We keep them, resolving the line by name and rendering the package asname@version, because silently dropping a real vulnerability is worse than a message that differs from the cloud's. - Secret message text. Ours appends the secret's category
(
Possible hardcoded secret: {title} ({category})); the cloud engine stops at the title. - Offline scan.
codacy-trivysetsOfflineScan: true(its container is air-gapped); we don't, so Trivy may resolve some Java/Maven dependencies over the network and report slightly more accurate results for those ecosystems. Not changed here: making local scans less accurate to match an air-gap constraint we don't have would be the wrong trade.
DB update management
The adapter reads Trivy's metadata.json (at {cacheDir}/db/metadata.json) to
determine if the vulnerability database is still fresh. The NextUpdate field
tells us when Trivy expects the next DB update.
| Scenario | Behavior |
| ------------------------------ | ------------------------------------------------------------------ |
| DB fresh (now < NextUpdate) | --skip-db-update --skip-java-db-update passed — no network check |
| DB stale (now >= NextUpdate) | Trivy checks for updates normally |
| First run (no metadata) | Trivy downloads the DB (~40MB) |
| Container mode | Always skips DB updates (DBs are pre-baked) |
Malicious package detection
Detects known malicious packages by querying the OSV.dev batch API.
This piggybacks on the vulnerability scan output — the package list from --list-all-pkgs
is extracted and cross-referenced against the OpenSSF malicious packages index (MAL-* IDs).
- Covers 14 ecosystems: npm, PyPI, Go, RubyGems, crates.io, NuGet, Maven, Packagist, Pub, Hex, ConanCenter, CocoaPods, SwiftURL, conda
- Uses a 10-second timeout per API call
- On API failure (network error, timeout), logs a warning and skips — never blocks the core scan
- Message format:
Malicious package detected: {name}@{version} ({MAL-ID}). {summary}
Updating patterns
# Re-fetch pattern metadata from the Codacy API
pnpm prefetch
# Commit the result
git add src/patterns.jsonUpdating the Trivy version
- Update
preferredVersioninsrc/adapter.ts - Update the download URL template if the release format changed
- Run
pnpm testto verify compatibility
Development
pnpm build # Build with tsup
pnpm test # Run tests (requires trivy in PATH or auto-install)Notes for maintainers
- Trivy runs two separate scan invocations: one for vulnerabilities (
--scanners vuln --detection-priority comprehensive) and one for secrets (--scanners secret). Malicious package detection piggybacks on the vuln scan output (no extra invocation). Which scans run depends on which umbrella patterns are enabled. - The vulnerability database is downloaded lazily on first run to
--cache-dir ~/.codacy/cache/trivy/. Internet access is required on first use. DB staleness is managed viametadata.json→NextUpdate. - Trivy scans whole directories, not individual files. Results are filtered to
ctx.targetFilesafter scanning. - The binary is downloaded from GitHub releases as a
.tar.gzarchive. - Vulnerability severity (CRITICAL/HIGH/MEDIUM/LOW) maps to the corresponding umbrella pattern.
- Message format, line resolution and
sourceIdare all parity-critical — see Issue parity withcodacy-trivybefore touching them. - A vulnerability whose line cannot be resolved becomes a file-level
AnalysisError(kind: "LineNumbersNotSupported"), one per file, rather than an issue on line 1. - Malicious package detection uses the OSV.dev batch API. On failure, it degrades gracefully (warning only).
- Config file: checks for
trivy.yamlin the repo root.
