Forward nested excluded directories to project mode linters - #8811
Open
nvuillam wants to merge 2 commits into
Open
Forward nested excluded directories to project mode linters#8811nvuillam wants to merge 2 commits into
nvuillam wants to merge 2 commits into
Conversation
nvuillam
requested review from
Kurt-von-Laven,
bdovaz and
echoix
as code owners
August 26, 2026 22:25
Contributor
✅
|
EXCLUDED_DIRECTORIES and ADDITIONAL_EXCLUDED_DIRECTORIES were forwarded to
project lint mode linters only when the directory existed at the workspace
root, while MegaLinter's own file filtering excludes them by basename at any
nesting level. A directory such as infrastructure/cdk.out was therefore
skipped by MegaLinter but still scanned by project mode linters, and missing
from the betterleaks config generated in megalinter-reports.
The workspace lookup now walks the tree (never descending into an already
matched directory) and matches excluded entries by basename at any level,
through utils.match_excluded_dir which becomes the single source of truth
shared with the file listing code. {{WORKSPACE}} anchored exclusion argument
templates receive the concrete workspace relative paths found instead of a
bare directory name. Betterleaks allowlist path regexes are anchored with
(^|/) so they match the directory at any level and not a directory merely
ending with the excluded name.
Fixes #8806
nvuillam
force-pushed
the
fix/forward-nested-excluded-directories
branch
from
August 27, 2026 08:28
0b250dd to
f31d188
Compare
- find_workspace_excluded_directories() prunes the default excluded
directories even when EXCLUDED_DIRECTORIES replaces them, so a custom
exclusion list no longer turns the lookup into a full walk of every
node_modules, .venv and .terraform tree
- New {{DIR_PATH}} value template placeholder sending the workspace
relative path of each located directory, for linters anchoring their
exclusions on the repository root: PYTHON_BANDIT, YAML_V8R and the
shared dotnet-format definition, which kept missing nested directories
- REPOSITORY_LS_LINT generates its ignore list from the located paths,
as ls-lint resolves ignore entries from the root
- config.delete() clears the per request excluded directories caches
through a registered cleaner, so server mode does not leak them
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.

Root cause
Linter.get_project_exclude_directories()kept an excluded entry only whenos.path.isdir(workspace/<entry>)was true, i.e. only when the directory existed at the workspace root.MegaLinter's own file filtering (
Megalinter._is_excluded_dir) matches excluded entries by basename at any nesting level. The two were inconsistent, so a directory likeinfrastructure/cdk.outwas:projectlint mode lintersFor
REPOSITORY_BETTERLEAKSthe generatedmegalinter-reports/betterleaks-config.tomltherefore contained only the root level directories:and betterleaks reported findings in
infrastructure/cdk.out/*.template.json.ADDITIONAL_EXCLUDED_DIRECTORIESitself was fine:utils.get_excluded_directories()already merges it. The root only existence check was the whole problem, and it affects every linter using the project mode exclusions forwarding, not just betterleaks.Fix
utils.normalize_excluded_directories()/match_excluded_dir()/is_excluded_dir(), moved out ofMegaLinter.py, so directory exclusion matching has a single source of truth shared by the file listing and the forwarding.utils.find_workspace_excluded_directories()locates every excluded entry anywhere in the workspace with oneos.walk. It never descends into a matched directory (nor into.git), so it stays cheap on repositories carrying hugenode_modules,.venvor.terraformtrees, and the result is cached for the whole run.get_project_exclude_directories()keeps its contract (directory names, nothing forwarded when none exists in the workspace) but now finds nested ones.get_project_exclude_directory_paths()returns the concrete workspace relative paths.build_project_exclude_arguments()uses them when the descriptor value template contains{{WORKSPACE}}(onlyJAVA_PMDtoday): an absolute path argument cannot be built from a bare directory name, and this also avoids passing a path that does not exist.BetterleaksLinterallowlist path regexes are now anchored with(^|/), so they match the directory at any nesting level and do not match a directory merely ending with the excluded name.Descriptor templates that are already nesting aware (
**/{{DIR}}/**,(^|/){{DIR}}/,*/{{DIR}}/*, …) benefit immediately. Root anchored templates (./{{DIR}}for bandit,{{DIR}}/**for v8r,./{{DIR}}/for dotnet-format) simply keep behaving as before for nested directories, which is not a regression; the rule doc now flags them.Verification
megalinter/tests/test_megalinter/linter_test.py: nested directory forwarded, nested paths collected, no descent into an already excluded directory. Existing root level and report folder tests still pass..automation/test/betterleaks/good/infrastructure/.wireit/poison_creds_nested.txt:.wireitis a default excluded directory, sotest_success_project_lint_modefor betterleaks fails if nested forwarding regresses (it fails on the currentmain).ADDITIONAL_EXCLUDED_DIRECTORIES: cdk.out+infrastructure/cdk.out/) now generates:Fixes #8806