Skip to content

Update MegaLinter from v9 to v10 - #1071

Merged
berendt merged 1 commit into
mainfrom
update-megalinter-v10
Aug 14, 2026
Merged

Update MegaLinter from v9 to v10#1071
berendt merged 1 commit into
mainfrom
update-megalinter-v10

Conversation

@jklare

@jklare jklare commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Updates the MegaLinter GitHub Action from v9 to v10, together with the two configuration changes the new major version requires.

What would have broken

I ran v9.6.0 and v10.0.0 side by side against identical clean clones of main (documentation flavor, VALIDATE_ALL_CODEBASE=true) to separate new failures from pre-existing ones.

REPOSITORY_BETTERLEAKS failed the build on v10. Both documented example secrets were reported as leaks — the VNC console token in migration-vmware-esxi.md and the Ceph keyring key in ceph/index.mdx — even though .betterleaks.toml allowlists them. Green on v9.6.0, red on v10.

The cause is v10's new forwarding of EXCLUDED_DIRECTORIES to linters that scan the workspace themselves. For betterleaks it stops passing our config directly and instead generates a wrapper that pulls ours in:

[extend]
path = '/tmp/lint/.betterleaks.toml'

[allowlist]
paths = ['\.git/', 'megalinter\-reports/']

Our allowlist regexes do survive that merge — but the targetRules binding to generic-api-key does not. I confirmed this by testing three shapes of the allowlist against a child config mimicking the generated one:

Parent allowlist shape Direct Via generated wrapper
[[allowlists]] + targetRules (previous) pass 2 leaks
[allowlist] singular, no targetRules pass pass
[[allowlists]] plural, no targetRules pass pass

The last two differ from the first by exactly one line, so targetRules is the culprit — not the plural/singular form and not allowlist merging in general. Dropping it fixes the failure and lets the forwarding stay enabled as v10 intends, rather than switching it off with REPOSITORY_BETTERLEAKS_FORWARD_EXCLUDED_DIRECTORIES: false.

REPOSITORY_GITLEAKS no longer exists. v10 removed it in favour of betterleaks and prints a notice on every run for configurations still referencing it. The migration itself was already done — .betterleaks.toml exists and betterleaks was already running under v9.6 — so only the stale DISABLE_LINTERS entry needed removing.

On widening the allowlist scope

The two entries are exact literal strings, so restricting them to one rule added no real protection. To be sure detection is intact, I took the real Ceph key, mutated its last two payload characters, and betterleaks still reports it. Only the two exact documented literals are exempt.

The alternative was a .gitleaksignore with fingerprints, which does work under v10's defaults, but each entry pins a line number: inserting two lines above the example in ceph/index.mdx brought the leak straight back. In a docs repo that would fail on unrelated PRs, so I did not go that way.

Verification

Full v10 documentation-flavor run over the whole codebase with these changes: exit 0, all 16 linters pass, forwarding confirmed active for betterleaks, checkov and secretlint. The only remaining finding is the pre-existing, non-blocking lychee 404 on the GitLab no_proxy link in proxy.md, which is unrelated to this change.

Two notes, no action needed here

  • MegaLinter publishes images to ghcr.io only since v9.5.0. Local runs should pull ghcr.io/oxsecurity/megalinter-documentation:v10; Docker Hub has no v10 tag and its v9 tag is frozen at 9.4.0. The Action reference used by the workflow is unaffected.
  • v10 adds a default LINTER_TIMEOUT_SECONDS: 300. The slowest linter here is checkov at ~19s, so there is plenty of headroom; SPELL_LYCHEE_TIMEOUT_SECONDS is the knob if lychee ever gets slow in CI.

targetRules being silently ignored under [extend] looks like a betterleaks/gitleaks bug that MegaLinter's wrapping merely exposes. Happy to report it upstream if you think it is worth filing.

🤖 Generated with Claude Code

MegaLinter v10 removes REPOSITORY_GITLEAKS in favour of betterleaks,
which this repository already uses, so the DISABLE_LINTERS entry for it
is dropped. Left in place, v10 reports it as a removed item on every
run.

v10 also forwards EXCLUDED_DIRECTORIES to linters that scan the
workspace themselves. For betterleaks it does so by wrapping
.betterleaks.toml in a generated config that pulls ours in through
"[extend] path". A rule-scoped allowlist does not survive that merge:
the regexes are kept, but the targetRules binding to generic-api-key is
lost, so both documented example secrets (the VNC console token and the
Ceph keyring key) were reported as leaks and the job failed. Dropping
targetRules keeps the allowlist effective through the generated config,
so the forwarding can stay enabled as v10 intends.

The two entries are exact literal strings, so restricting them to a
single rule added no protection. A near-identical Ceph key differing in
its last two payload characters is still reported, which confirms
detection is unchanged.

Verified with a full documentation-flavor v10 run over the whole
codebase: all 16 linters pass. The only finding left is the
pre-existing, non-blocking lychee 404 on the GitLab no_proxy link.

Unrelated to CI, but worth knowing for local runs: MegaLinter publishes
images to ghcr.io only since v9.5.0, so pull
ghcr.io/oxsecurity/megalinter-documentation:v10. Docker Hub has no v10
tag and its v9 tag is frozen at 9.4.0. The GitHub Action reference used
by the workflow is unaffected.

SecurityImpact
Assisted-by: Claude:claude-opus-5[1m]
Signed-off-by: Jan Klare <klare@osism.tech>
@github-actions

Copy link
Copy Markdown

MegaLinter analysis: Success

Descriptor Linter Files Fixed Errors Max errors Warnings Elapsed time
✅ ACTION actionlint 5 0 0 0.03s
✅ JSON jsonlint 4 0 0 0.06s
✅ JSON prettier 4 0 0 0.24s
✅ JSON v8r 4 0 0 4.65s
✅ MARKDOWN markdownlint 168 0 0 1.41s
✅ MARKDOWN markdown-table-formatter 168 0 0 0.18s
✅ REPOSITORY betterleaks yes no no 0.46s
✅ REPOSITORY checkov yes no no 11.83s
✅ REPOSITORY git_diff yes no no 0.04s
✅ REPOSITORY secretlint yes no no 1.56s
✅ REPOSITORY trufflehog yes no no 2.39s
✅ SPELL codespell 178 0 0 0.35s
✅ SPELL lychee 178 0 0 12.01s
✅ YAML prettier 6 0 0 0.26s
✅ YAML v8r 6 0 0 4.2s
✅ YAML yamllint 6 0 0 0.32s

See detailed reports in MegaLinter artifacts

Your project could benefit from a custom flavor, which would allow you to run only the linters you need, and thus improve runtime performances. (Skip this info by defining FLAVOR_SUGGESTIONS: false)

  • Documentation: Custom Flavors
  • Command: npx mega-linter-runner@10.0.0 --custom-flavor-setup --custom-flavor-linters ACTION_ACTIONLINT,JSON_JSONLINT,JSON_V8R,JSON_PRETTIER,MARKDOWN_MARKDOWNLINT,MARKDOWN_MARKDOWN_TABLE_FORMATTER,REPOSITORY_CHECKOV,REPOSITORY_GIT_DIFF,REPOSITORY_BETTERLEAKS,REPOSITORY_SECRETLINT,REPOSITORY_TRUFFLEHOG,SPELL_LYCHEE,SPELL_CODESPELL,YAML_PRETTIER,YAML_YAMLLINT,YAML_V8R

MegaLinter is provided by OX Security
Show us your support by starring ⭐ the repository

@berendt
berendt merged commit 6b43c38 into main Aug 14, 2026
4 checks passed
@berendt
berendt deleted the update-megalinter-v10 branch August 14, 2026 15:20
@github-project-automation github-project-automation Bot moved this from New to Done in Human Board Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants