summaryrefslogtreecommitdiffstats
path: root/src/ansiblelint/rules/avoid_implicit.py
blob: dbd44d6046a805bc6d1dab44b9349fa983ea6207 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
"""Implementation of avoid-implicit rule."""
# https://github.com/ansible/ansible-lint/issues/2501
from __future__ import annotations

import sys
from typing import TYPE_CHECKING, Any

from ansiblelint.rules import AnsibleLintRule

if TYPE_CHECKING:
    from ansiblelint.file_utils import Lintable


class AvoidImplicitRule(AnsibleLintRule):
    """Rule that identifies use of undocumented or discouraged implicit behaviors."""

    id = "avoid-implicit"
    shortdesc = "Avoid implicit behaviors"
    description = (
        "Items which are templated should use ``template`` instead of "
        "``copy`` with ``content`` to ensure correctness."
    )
    severity = "MEDIUM"
    tags = ["unpredictability"]
    version_added = "v6.8.0"

    def matchtask(
        self, task: dict[str, Any], file: Lintable | None = None
    ) -> bool | str:
        """Confirm if current rule is matching a specific task."""
        if task["action"]["__ansible_module__"] == "copy":
            content = task["action"].get("content", "")
            if not isinstance(content, str):
                return True
        return False


# testing code to be loaded only with pytest or when executed the rule file
if "pytest" in sys.modules:
    from ansiblelint.rules import RulesCollection  # pylint: disable=ungrouped-imports
    from ansiblelint.runner import Runner  # pylint: disable=ungrouped-imports

    def test_template_instead_of_copy_positive() -> None:
        """Positive test for avoid-implicit."""
        collection = RulesCollection()
        collection.register(AvoidImplicitRule())
        success = "examples/playbooks/rule-avoid-implicit-pass.yml"
        good_runner = Runner(success, rules=collection)
        assert [] == good_runner.run()

    def test_template_instead_of_copy_negative() -> None:
        """Negative test for avoid-implicit."""
        collection = RulesCollection()
        collection.register(AvoidImplicitRule())
        failure = "examples/playbooks/rule-avoid-implicit-fail.yml"
        bad_runner = Runner(failure, rules=collection)
        errs = bad_runner.run()
        assert len(errs) == 1