summaryrefslogtreecommitdiffstats
path: root/src/ansiblelint/rules/only_builtins.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:06:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:06:49 +0000
commit2fe34b6444502079dc0b84365ce82dbc92de308e (patch)
tree8fedcab52bbbc3db6c5aa909a88a7a7b81685018 /src/ansiblelint/rules/only_builtins.py
parentInitial commit. (diff)
downloadansible-lint-2fe34b6444502079dc0b84365ce82dbc92de308e.tar.xz
ansible-lint-2fe34b6444502079dc0b84365ce82dbc92de308e.zip
Adding upstream version 6.17.2.upstream/6.17.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/ansiblelint/rules/only_builtins.py')
-rw-r--r--src/ansiblelint/rules/only_builtins.py106
1 files changed, 106 insertions, 0 deletions
diff --git a/src/ansiblelint/rules/only_builtins.py b/src/ansiblelint/rules/only_builtins.py
new file mode 100644
index 0000000..78ad93a
--- /dev/null
+++ b/src/ansiblelint/rules/only_builtins.py
@@ -0,0 +1,106 @@
+"""Rule definition for usage of builtin actions only."""
+from __future__ import annotations
+
+import os
+import sys
+from typing import TYPE_CHECKING
+
+from ansiblelint.config import options
+from ansiblelint.rules import AnsibleLintRule
+from ansiblelint.rules.fqcn import builtins
+from ansiblelint.skip_utils import is_nested_task
+
+if TYPE_CHECKING:
+ from ansiblelint.file_utils import Lintable
+ from ansiblelint.utils import Task
+
+
+class OnlyBuiltinsRule(AnsibleLintRule):
+ """Use only builtin actions."""
+
+ id = "only-builtins"
+ severity = "MEDIUM"
+ description = "Check whether the playbook uses anything but ``ansible.builtin``"
+ tags = ["opt-in", "experimental"]
+
+ def matchtask(
+ self,
+ task: Task,
+ file: Lintable | None = None,
+ ) -> bool | str:
+ module = task["action"]["__ansible_module_original__"]
+
+ allowed_collections = [
+ "ansible.builtin",
+ "ansible.legacy",
+ *options.only_builtins_allow_collections,
+ ]
+ allowed_modules = builtins + options.only_builtins_allow_modules
+
+ is_allowed = (
+ any(module.startswith(f"{prefix}.") for prefix in allowed_collections)
+ or module in allowed_modules
+ )
+
+ return not is_allowed and not is_nested_task(task)
+
+
+# testing code to be loaded only with pytest or when executed the rule file
+if "pytest" in sys.modules:
+ # pylint: disable=ungrouped-imports
+ import pytest
+
+ from ansiblelint.constants import RC
+ from ansiblelint.testing import RunFromText, run_ansible_lint
+
+ SUCCESS_PLAY = """
+- hosts: localhost
+ tasks:
+ - name: A block
+ block:
+ - name: Shell (fqcn)
+ ansible.builtin.shell: echo This rule should not get matched by the only-builtins rule
+ - name: Command with legacy FQCN
+ ansible.legacy.command: echo This rule should not get matched by the only-builtins rule
+ """
+
+ def test_only_builtins_fail() -> None:
+ """Test rule matches."""
+ env = os.environ.copy()
+ env["NO_COLOR"] = "1"
+ result = run_ansible_lint(
+ "--strict",
+ "--warn-list=",
+ "--enable-list",
+ "only-builtins",
+ "examples/playbooks/rule-only-builtins.yml",
+ env=env,
+ )
+ assert result.returncode == RC.VIOLATIONS_FOUND
+ assert "Failed" in result.stderr
+ assert "warning(s)" in result.stderr
+ assert "only-builtins: Use only builtin actions" in result.stdout
+
+ def test_only_builtins_allow() -> None:
+ """Test rule doesn't match."""
+ conf_path = "examples/playbooks/.ansible-lint-only-builtins-allow"
+ result = run_ansible_lint(
+ f"--config-file={conf_path}",
+ "--strict",
+ "--warn-list=",
+ "--enable-list",
+ "only-builtins",
+ "examples/playbooks/rule-only-builtins.yml",
+ )
+ assert "only-builtins" not in result.stdout
+ assert result.returncode == RC.SUCCESS
+
+ @pytest.mark.parametrize(
+ "rule_runner",
+ (OnlyBuiltinsRule,),
+ indirect=["rule_runner"],
+ )
+ def test_only_builtin_pass(rule_runner: RunFromText) -> None:
+ """Test rule does not match."""
+ results = rule_runner.run_playbook(SUCCESS_PLAY)
+ assert len(results) == 0, results