summaryrefslogtreecommitdiffstats
path: root/src/ansiblelint/rules/sanity.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/ansiblelint/rules/sanity.py')
-rw-r--r--src/ansiblelint/rules/sanity.py148
1 files changed, 148 insertions, 0 deletions
diff --git a/src/ansiblelint/rules/sanity.py b/src/ansiblelint/rules/sanity.py
new file mode 100644
index 0000000..09fe7cc
--- /dev/null
+++ b/src/ansiblelint/rules/sanity.py
@@ -0,0 +1,148 @@
+"""Implementation of sanity rule."""
+from __future__ import annotations
+
+import sys
+from typing import TYPE_CHECKING
+
+from ansiblelint.rules import AnsibleLintRule
+
+# Copyright (c) 2018, Ansible Project
+
+
+if TYPE_CHECKING:
+ from ansiblelint.errors import MatchError
+ from ansiblelint.file_utils import Lintable
+
+
+class CheckSanityIgnoreFiles(AnsibleLintRule):
+ """Ignore entries in sanity ignore files must match an allow list."""
+
+ id = "sanity"
+ description = (
+ "Identifies non-allowed entries in the `tests/sanity/ignore*.txt files."
+ )
+ severity = "MEDIUM"
+ tags = ["idiom"]
+ version_added = "v6.14.0"
+
+ # Partner Engineering defines this list. Please contact PE for changes.
+
+ allowed_ignores_v2_9 = [
+ "validate-modules:deprecation-mismatch", # Note: 2.9 expects a deprecated key in the METADATA. It was removed in later versions.
+ "validate-modules:invalid-documentation", # Note: The removed_at_date key in the deprecated section is invalid for 2.9.
+ ]
+
+ allowed_ignores_all = [
+ "validate-modules:missing-gplv3-license",
+ "action-plugin-docs", # Added for Networking Collections
+ "import-2.6",
+ "import-2.6!skip",
+ "import-2.7",
+ "import-2.7!skip",
+ "import-3.5",
+ "import-3.5!skip",
+ "compile-2.6",
+ "compile-2.6!skip",
+ "compile-2.7",
+ "compile-2.7!skip",
+ "compile-3.5",
+ "compile-3.5!skip",
+ ]
+ _ids = {
+ "sanity[cannot-ignore]": "Ignore file contains ... at line ..., which is not a permitted ignore.",
+ "sanity[bad-ignore]": "Ignore file entry at ... is formatted incorrectly. Please review.",
+ }
+
+ def matchyaml(self, file: Lintable) -> list[MatchError]:
+ """Evaluate sanity ignore lists for disallowed ignores.
+
+ :param file: Input lintable file that is a match for `sanity-ignore-file`
+ :returns: List of errors matched to the input file
+ """
+ results: list[MatchError] = []
+ test = ""
+
+ if file.kind != "sanity-ignore-file":
+ return []
+
+ with file.path.open(encoding="utf-8") as ignore_file:
+ entries = ignore_file.read().splitlines()
+
+ ignores = self.allowed_ignores_all
+
+ # If there is a ignore-2.9.txt file, add the v2_9 list of allowed ignores
+ if "ignore-2.9.txt" in str(file.abspath):
+ ignores = self.allowed_ignores_all + self.allowed_ignores_v2_9
+
+ for line_num, entry in enumerate(entries, 1):
+ if entry and entry[0] != "#":
+ try:
+ if "#" in entry:
+ entry, _ = entry.split("#")
+ (_, test) = entry.split()
+ if test not in ignores:
+ results.append(
+ self.create_matcherror(
+ message=f"Ignore file contains {test} at line {line_num}, which is not a permitted ignore.",
+ tag="sanity[cannot-ignore]",
+ lineno=line_num,
+ filename=file,
+ ),
+ )
+
+ except ValueError:
+ results.append(
+ self.create_matcherror(
+ message=f"Ignore file entry at {line_num} is formatted incorrectly. Please review.",
+ tag="sanity[bad-ignore]",
+ lineno=line_num,
+ filename=file,
+ ),
+ )
+
+ return results
+
+
+# testing code to be loaded only with pytest or when executed the rule file
+if "pytest" in sys.modules:
+ import pytest
+
+ from ansiblelint.rules import RulesCollection # pylint: disable=ungrouped-imports
+ from ansiblelint.runner import Runner # pylint: disable=ungrouped-imports
+
+ @pytest.mark.parametrize(
+ ("test_file", "failures", "tags"),
+ (
+ pytest.param(
+ "examples/sanity_ignores/tests/sanity/ignore-2.9.txt",
+ 0,
+ "sanity[cannot-ignore]",
+ id="pass",
+ ),
+ pytest.param(
+ "examples/sanity_ignores/tests/sanity/ignore-2.15.txt",
+ 1,
+ "sanity[bad-ignore]",
+ id="fail0",
+ ),
+ pytest.param(
+ "examples/sanity_ignores/tests/sanity/ignore-2.13.txt",
+ 1,
+ "sanity[cannot-ignore]",
+ id="fail1",
+ ),
+ ),
+ )
+ def test_sanity_ignore_files(
+ default_rules_collection: RulesCollection,
+ test_file: str,
+ failures: int,
+ tags: str,
+ ) -> None:
+ """Test rule matches."""
+ default_rules_collection.register(CheckSanityIgnoreFiles())
+ results = Runner(test_file, rules=default_rules_collection).run()
+ for result in results:
+ assert result.rule.id == CheckSanityIgnoreFiles().id
+ assert result.tag == tags
+ assert len(results) == failures