Skip to content

Commit

Permalink
add no-prompting rule
Browse files Browse the repository at this point in the history
Adds a new experimental rule to disallow the use of `vars_prompt` or
`ansible.builtin.pause` to better accommodate unattended playbook
runs and use in CI pipelines.

This rule is opt-in for now and needs to be explicitly enabled to be
used.

Fixes: #2036

Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
  • Loading branch information
ziegenberg committed May 3, 2022
1 parent 6ffd7a8 commit f41e000
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 2 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/tox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,7 @@ jobs:
WSLENV: FORCE_COLOR:PYTEST_REQPASS:TOXENV:TOX_PARALLEL_NO_SPINNER
# Number of expected test passes, safety measure for accidental skip of
# tests. Update value if you add/remove tests.
PYTEST_REQPASS: 609

PYTEST_REQPASS: 610
steps:
- name: Activate WSL1
if: "contains(matrix.shell, 'wsl')"
Expand Down
56 changes: 56 additions & 0 deletions src/ansiblelint/rules/no_prompting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"""Implementation of no-prompting rule."""

from typing import TYPE_CHECKING, Any, Dict, List, Union

from ansiblelint.rules import AnsibleLintRule
from ansiblelint.utils import LINE_NUMBER_KEY

if TYPE_CHECKING:
from typing import Optional

from ansiblelint.constants import odict
from ansiblelint.errors import MatchError
from ansiblelint.file_utils import Lintable


class NoPromptingRule(AnsibleLintRule):
"""Disallow prompting."""

id = "no-prompting"
description = (
"Disallow the use of vars_prompt or ansible.builtin.pause to better"
"accommodate unattended playbook runs and use in CI pipelines."
)
tags = ["opt-in", "experimental"]
severity = "VERY_LOW"
version_added = "v6.0.3"

def matchplay(
self, file: "Lintable", data: "odict[str, Any]"
) -> List["MatchError"]:
"""Return matches found for a specific playbook."""
# If the Play uses the 'vars_prompt' section to set variables

if file.kind != "playbook":
return []

vars_prompt = data.get("vars_prompt", None)
if not vars_prompt:
return []

return [
self.create_matcherror(
message="Play uses vars_prompt",
linenumber=vars_prompt[LINE_NUMBER_KEY],
filename=file,
)
]

def matchtask(
self, task: Dict[str, Any], file: "Optional[Lintable]" = None
) -> Union[bool, str]:
"""Return matches for ansible.builtin.pause tasks."""
return task["action"]["__ansible_module_original__"] in [
"pause",
"ansible.builtin.pause",
]
39 changes: 39 additions & 0 deletions test/rules/test_no_prompting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""Tests for no-prompting rule."""
from ansiblelint.config import options
from ansiblelint.rules import RulesCollection
from ansiblelint.rules.no_prompting import NoPromptingRule
from ansiblelint.testing import RunFromText

FAIL_TASKS = """
---
- hosts: all
vars_prompt:
- name: username
prompt: What is your username?
private: no
- name: password
prompt: What is your password?
tasks:
- name: Pause for 5 minutes to build app cache
pause:
minutes: 5
- name: A helpful reminder of what to look out for post-update
ansible.builtin.pause:
prompt: "Make sure org.foo.FooOverload exception is not present"
"""


def test_no_prompting_fail() -> None:
"""Negative test for no-prompting."""
# For testing we want to manually enable opt-in rules
options.enable_list = ["no-prompting"]
collection = RulesCollection(options=options)
collection.register(NoPromptingRule())
runner = RunFromText(collection)
results = runner.run_playbook(FAIL_TASKS)
assert len(results) == 3
assert "Play uses vars_prompt" in str(results)

0 comments on commit f41e000

Please sign in to comment.