summaryrefslogtreecommitdiffstats
path: root/src/ansiblelint/rules/no_relative_paths.py
blob: de22641cb57a25a3ebc967a67bc2f4d53d8c1145 (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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
"""Implementation of no-relative-paths rule."""

# Copyright (c) 2016, Tsukinowa Inc. <info@tsukinowa.jp>
# Copyright (c) 2018, Ansible Project

from __future__ import annotations

import sys
from typing import TYPE_CHECKING

from ansiblelint.rules import AnsibleLintRule

if TYPE_CHECKING:
    from ansiblelint.file_utils import Lintable
    from ansiblelint.utils import Task


class RoleRelativePath(AnsibleLintRule):
    """The src argument should not use a relative path."""

    id = "no-relative-paths"
    description = "The ``copy`` and ``template`` modules should not use relative path for ``src``."
    severity = "HIGH"
    tags = ["idiom"]
    version_added = "v4.0.0"

    _module_to_path_folder = {
        "copy": "files",
        "win_copy": "files",
        "template": "templates",
        "win_template": "win_templates",
    }

    def matchtask(
        self,
        task: Task,
        file: Lintable | None = None,
    ) -> bool | str:
        module = task["action"]["__ansible_module__"]
        if module not in self._module_to_path_folder:
            return False

        if "src" not in task["action"]:
            return False

        path_to_check = f"../{self._module_to_path_folder[module]}"
        if path_to_check in task["action"]["src"]:
            return True

        return False


# testing code to be loaded only with pytest or when executed the rule file
if "pytest" in sys.modules:
    import pytest

    # pylint: disable=ungrouped-imports
    from ansiblelint.rules import RulesCollection
    from ansiblelint.runner import Runner

    @pytest.mark.parametrize(
        ("test_file", "failures"),
        (
            pytest.param("examples/playbooks/no_relative_paths_fail.yml", 2, id="fail"),
            pytest.param("examples/playbooks/no_relative_paths_pass.yml", 0, id="pass"),
        ),
    )
    def test_no_relative_paths(
        default_rules_collection: RulesCollection,
        test_file: str,
        failures: int,
    ) -> None:
        """Test rule matches."""
        results = Runner(test_file, rules=default_rules_collection).run()
        assert len(results) == failures
        for result in results:
            assert result.tag == "no-relative-paths"