Fix trivy failures when the vulnerability database registry rate-limits the run - #8813
Open
nvuillam wants to merge 1 commit into
Open
Fix trivy failures when the vulnerability database registry rate-limits the run#8813nvuillam wants to merge 1 commit into
nvuillam wants to merge 1 commit into
Conversation
nvuillam
requested review from
Kurt-von-Laven,
bdovaz and
echoix
as code owners
August 26, 2026 22:46
Contributor
❌MegaLinter analysis: Error❌ SPELL / cspell - 9 errors❌ COPYPASTE / jscpd - 1 error
|
…ts the run Fixes #8807 trivy could end a MegaLinter run with the confusing fatal error "--skip-db-update cannot be specified on the first run": after 5 immediate retries, TrivyLinter always fell back to --skip-db-update, which trivy refuses when no database has ever been downloaded. - Point trivy at all official database mirrors (mirror.gcr.io, ghcr.io and public.ecr.aws) through --db-repository / --java-db-repository, unless the user configured TRIVY_DB_REPOSITORY, --db-repository or db.repository - Space the download retries with an exponential backoff (10s, 20s, 40s, 60s) so they no longer all land within the same rate limit minute - Only run the last-chance --skip-db-update attempt when a database is actually cached (db/trivy.db + db/metadata.json), looking at --cache-dir, cache.dir, TRIVY_CACHE_DIR, XDG_CACHE_HOME, HOME and the database shipped within the docker image; log an actionable error otherwise - Only retry when trivy aborted (FATAL): a rate limit while fetching the optional checks bundle no longer triggers useless retries - Report the resolution guidance once instead of once per attempt - TrivySbomLinter inherits the same behaviour - New configuration variables: <LINTER>_DB_REPOSITORIES, <LINTER>_JAVA_DB_REPOSITORIES, <LINTER>_DB_RETRY_ATTEMPTS, <LINTER>_DB_RETRY_INITIAL_DELAY, <LINTER>_DB_RETRY_MAX_DELAY
nvuillam
force-pushed
the
fix/trivy-db-rate-limit-fallback
branch
from
August 27, 2026 08:28
d2b9555 to
7ee3d99
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Fixes #8807
Root cause
REPOSITORY_TRIVYended runs with a confusing fatal error:Three problems combined:
TrivyLinterunconditionally appended--skip-db-update --skip-check-update. trivy refuses this when no database has ever been downloaded (pkg/db/db.go:noRequiredFileswhendb/trivy.dbordb/metadata.jsonis missing), turning a rate limit into a fatal error nobody can act on./root/.cache/trivy(HOME=/root), but the GitHub Actions runner forcesHOME=/github/homein container actions, so trivy resolves its cache to an empty/github/home/.cache/trivy. Every GitHub Actions run is therefore a "first run".Fix
--db-repository/--java-db-repositoryare set tomirror.gcr.io,ghcr.ioandpublic.ecr.aws, and trivy falls back to the next one on 429/5xx/BLOB_UNKNOWN. trivy's own defaults are only the first two, and setting the flag replaces the defaults, so all three are listed. Skipped when the user setTRIVY_DB_REPOSITORY, passed--db-repository, or defineddb.repositoryin a trivy config file.--skip-db-updateonly when a database exists. The cache directory is resolved from--cache-dir,cache.dir,TRIVY_CACHE_DIR,XDG_CACHE_HOME,HOME, and finally/root/.cache/trivy(the one baked in the image), anddb/trivy.db+db/metadata.jsonmust both be present. When the database is found outside the directory trivy would use,--cache-diris passed so the image database is actually used. When no database exists at all, the run ends with an actionable error instead of the fatal above.FATALabort.TrivySbomLinterinherits fromTrivyLinter, soREPOSITORY_TRIVY_SBOMgets the same behaviour.New configuration variables, for both
REPOSITORY_TRIVYandREPOSITORY_TRIVY_SBOM:<LINTER>_DB_REPOSITORIESmirror.gcr.io/aquasec/trivy-db:2,ghcr.io/aquasecurity/trivy-db:2,public.ecr.aws/aquasecurity/trivy-db:2<LINTER>_JAVA_DB_REPOSITORIESmirror.gcr.io/aquasec/trivy-java-db:1,ghcr.io/aquasecurity/trivy-java-db:1,public.ecr.aws/aquasecurity/trivy-java-db:1<LINTER>_DB_RETRY_ATTEMPTS5<LINTER>_DB_RETRY_INITIAL_DELAY10<LINTER>_DB_RETRY_MAX_DELAY60The
common_linter_errorsguidance was refreshed accordingly (authenticating withGITHUB_TOKENwas removed: per trivy's own troubleshooting page it does not help with the database rate limit, and a stale token returnsDENIED, which disables mirror fallback entirely). A newREPOSITORY_TRIVY_ERROR_FIRST_RUN_NO_DBentry covers users who set--skip-db-updatethemselves.Verification
megalinter/tests/test_megalinter/trivy_linter_test.pycover the mirrors (defaults, user overrides through arguments / env var / config file, disabling), the backoff sequence, cache detection, the offline command, the "no retry on a completed scan" case, and the single guidance message. All pass.--db-repositoryand--java-db-repositoryexist ontrivy fs, arestrings(comma-separated values accepted), and are accepted after the positional target. A run with a 3-mirror list was confirmed to attempt the first repository of the list.Not verified here
repository_trivy_test,repository_trivy_sbom_test) were not run locally; CI covers them.build.py, which only writes them during a documentation build, so they will land with the next auto-update run.