diff --git a/src/ansiblelint/runner.py b/src/ansiblelint/runner.py index 86e8372da2..ac5cacf5de 100644 --- a/src/ansiblelint/runner.py +++ b/src/ansiblelint/runner.py @@ -213,11 +213,26 @@ def _run(self) -> list[MatchError]: # remove exclusions for lintable in self.lintables.copy(): + # 1. Standard exclusion check if self.is_excluded(lintable): _logger.debug("Excluded %s", lintable) self.lintables.remove(lintable) continue + + # 2. Handle load errors (This is where SOPS/Broken YAML crashes) if isinstance(lintable.data, States) and lintable.exc: + # --- NEW LOGIC FOR #4745 --- + # Even if it's 'explicit', if it's broken, we check the exclude_paths + # one last time before reporting a 'load-failure'. + abs_path = str(lintable.abspath) + if any( + abs_path.startswith(p) or fnmatch(abs_path, p) + for p in self.exclude_paths + ): + self.lintables.remove(lintable) + continue + # --- END NEW LOGIC --- + line = 1 column = None detail = "" diff --git a/test/test_runner.py b/test/test_runner.py index 5e2a79ad56..53ccbc0078 100644 --- a/test/test_runner.py +++ b/test/test_runner.py @@ -87,6 +87,25 @@ def test_runner_exclude_paths(default_rules_collection: RulesCollection) -> None assert len(matches) == 0 +def test_exclude_paths_ignores_broken_yaml( + default_rules_collection: RulesCollection, + tmp_path: Path, +) -> None: + """Ensure exclude_paths prevents parsing of invalid YAML files (#4745).""" + broken_yaml = tmp_path / "secrets.yml" + broken_yaml.write_text("---\ninvalid: : : : yaml\n", encoding="utf-8") + + runner = Runner( + broken_yaml, + rules=default_rules_collection, + exclude_paths=[str(broken_yaml)], + ) + + results = runner.run() + + assert len(results) == 0 + + @pytest.mark.parametrize( ("exclude_path"), (pytest.param("**/playbooks_globs/*b.yml", id="1"),),