pax_global_header00006660000000000000000000000064147734735600014532gustar00rootroot0000000000000052 comment=c16f018b1bdfdea6717f4b5b1b141a78b86021cd ansible-ansible-lint-c16f018/000077500000000000000000000000001477347356000160605ustar00rootroot00000000000000ansible-ansible-lint-c16f018/.ansible-lint000066400000000000000000000106011477347356000204400ustar00rootroot00000000000000--- # .ansible-lint profile: null # min, basic, moderate,safety, shared, production # Allows dumping of results in SARIF format # sarif_file: result.sarif # exclude_paths included in this file are parsed relative to this file's location # and not relative to the CWD of execution. CLI arguments passed to the --exclude # option are parsed relative to the CWD of execution. exclude_paths: - .cache/ # implicit unless exclude_paths is defined in config - test/fixtures/formatting-before/ - test/fixtures/formatting-prettier/ # parseable: true # quiet: true # strict: true # verbosity: 1 # Mock modules or roles in order to pass ansible-playbook --syntax-check mock_modules: - zuul_return # note the foo.bar is invalid as being neither a module or a collection - fake_namespace.fake_collection.fake_module - fake_namespace.fake_collection.fake_module.fake_submodule mock_roles: - mocked_role - author.role_name # old standalone galaxy role - fake_namespace.fake_collection.fake_role # role within a collection # Enable checking of loop variable prefixes in roles loop_var_prefix: "^(__|{role}_)" # Enforce variable names to follow pattern below, in addition to Ansible own # requirements, like avoiding python identifiers. To disable add `var-naming` # to skip_list. var_naming_pattern: "^[a-z_][a-z0-9_]*$" use_default_rules: true # Load custom rules from this specific folder # rulesdir: # - ./rule/directory/ # Ansible-lint is able to recognize and load skip rules stored inside # `.ansible-lint-ignore` (or `.config/ansible-lint-ignore.txt`) files. # To skip a rule just enter filename and tag, like "playbook.yml package-latest" # on a new line. # Optionally you can add comments after the tag, prefixed by "#". We discourage # the use of skip_list below because that will hide violations from the output. # When putting ignores inside the ignore file, they are marked as ignored, but # still visible, making it easier to address later. skip_list: - skip_this_tag # Ansible-lint does not automatically load rules that have the 'opt-in' tag. # You must enable opt-in rules by listing each rule 'id' below. enable_list: - args - empty-string-compare # opt-in - no-log-password # opt-in - no-same-owner # opt-in - name[prefix] # opt-in - galaxy-version-incorrect # opt-in # add yaml here if you want to avoid ignoring yaml checks when yamllint # library is missing. Normally its absence just skips using that rule. - yaml # Report only a subset of tags and fully ignore any others # tags: # - jinja[spacing] # Ansible-lint does not fail on warnings from the rules or tags listed below warn_list: - skip_this_tag - experimental # experimental is included in the implicit list # - role-name # - yaml[document-start] # you can also use sub-rule matches # Some rules can transform files to fix (or make it easier to fix) identified # errors. `ansible-lint --fix` will reformat YAML files and run these transforms. # By default it will run all transforms (effectively `write_list: ["all"]`). # You can disable running transforms by setting `write_list: ["none"]`. # Or only enable a subset of rule transforms by listing rules/tags here. # write_list: # - all # Offline mode disables installation of requirements.yml and schema refreshing offline: true # Define required Ansible's variables to satisfy syntax check extra_vars: foo: bar multiline_string_variable: | line1 line2 complex_variable: ":{;\t$()" # Uncomment to enforce action validation with tasks, usually is not # needed as Ansible syntax check also covers it. # skip_action_validation: false # List of additional kind:pattern to be added at the top of the default # match list, first match determines the file kind. kinds: # - playbook: "**/examples/*.{yml,yaml}" # - galaxy: "**/folder/galaxy.yml" # - tasks: "**/tasks/*.yml" # - vars: "**/vars/*.yml" # - meta: "**/meta/main.yml" - yaml: "**/*.yaml-too" # List of additional collections to allow in only-builtins rule. # only_builtins_allow_collections: # - example_ns.example_collection # List of additions modules to allow in only-builtins rule. # only_builtins_allow_modules: # - example_module # Allow setting custom prefix for name[prefix] rule task_name_prefix: "{stem} | " # Complexity related settings # Limit the depth of the nested blocks: # max_block_depth: 20 # Also recognize these versions of Ansible as supported: # supported_ansible_also: # - "2.18" ansible-ansible-lint-c16f018/.ansible-lint-ignore000066400000000000000000000002351477347356000217230ustar00rootroot00000000000000# See https://ansible.readthedocs.io/projects/lint/configuring/#ignoring-rules-for-entire-files playbook2.yml package-latest # comment playbook2.yml foo-bar ansible-ansible-lint-c16f018/.config/000077500000000000000000000000001477347356000174035ustar00rootroot00000000000000ansible-ansible-lint-c16f018/.config/ansible-lint.spec000066400000000000000000000033031477347356000226370ustar00rootroot00000000000000# spell-checker:ignore bcond pkgversion buildrequires autosetup PYTHONPATH noarch buildroot bindir sitelib numprocesses clib # All tests require Internet access # to test in mock use: --enable-network --with check # to test in a privileged environment use: # --with check --with privileged_tests %bcond_with check %bcond_with privileged_tests Name: ansible-lint Version: VERSION_PLACEHOLDER Release: 1%{?dist} Summary: Ansible-lint checks ansible content for common mistakes License: GPL-3.0-or-later AND MIT URL: https://github.com/ansible/ansible-lint Source0: %{pypi_source} BuildArch: noarch BuildRequires: python%{python3_pkgversion}-devel %if %{with check} # These are required for tests: BuildRequires: python%{python3_pkgversion}-pytest BuildRequires: python%{python3_pkgversion}-pytest-xdist BuildRequires: python%{python3_pkgversion}-libselinux BuildRequires: git-core %endif Requires: git-core %description Ansible-lint checks ansible content for practices and behaviors that could potentially be improved. %prep %autosetup %generate_buildrequires %pyproject_buildrequires %build %pyproject_wheel %install %pyproject_install %pyproject_save_files ansiblelint %check # Don't try to import tests that import pytest which isn't available at runtime %pyproject_check_import -e 'ansiblelint.testing*' -e 'ansiblelint.rules.conftest' %if %{with check} %pytest \ -v \ --disable-pytest-warnings \ --numprocesses=auto \ %if %{with privileged_tests} tests %else tests/unit %endif %endif %files -f %{pyproject_files} %{_bindir}/ansible-lint %license COPYING docs/licenses/LICENSE.mit.txt %doc docs/ README.md %changelog ansible-ansible-lint-c16f018/.config/constraints.txt000066400000000000000000000200461477347356000225150ustar00rootroot00000000000000# This file was autogenerated by uv via the following command: # tox run -e deps ansible-compat==25.1.5 # via ansible-lint (pyproject.toml) astroid==3.3.9 # via pylint asttokens==3.0.0 # via stack-data attrs==25.3.0 # via jsonschema, referencing babel==2.17.0 # via mkdocs-material backrefs==5.8 # via mkdocs-material beautifulsoup4==4.13.3 # via linkchecker, mkdocs-htmlproofer-plugin bindep==2.13.0 # via tox-extra black==25.1.0 # via ansible-lint (pyproject.toml) boolean-py==4.0 # via license-expression bracex==2.5.post1 # via wcmatch cachetools==5.5.2 # via tox cairocffi==1.7.1 # via cairosvg cairosvg==2.7.1 # via mkdocs-ansible certifi==2025.1.31 # via requests cffi==1.17.1 # via cairocffi, cryptography chardet==5.2.0 # via tox charset-normalizer==3.4.1 # via requests click==8.1.8 # via black, mkdocs colorama==0.4.6 # via griffe, mkdocs-material, tox coverage==7.7.1 # via coverage-enable-subprocess, ansible-lint (pyproject.toml) coverage-enable-subprocess==1.0 # via ansible-lint (pyproject.toml) cryptography==44.0.2 # via ansible-core csscompressor==0.9.5 # via mkdocs-minify-plugin cssselect2==0.8.0 # via cairosvg decorator==5.2.1 # via ipdb, ipython defusedxml==0.7.1 # via cairosvg dill==0.3.9 # via pylint distlib==0.3.9 # via virtualenv distro==1.9.0 # via bindep dnspython==2.7.0 # via linkchecker execnet==2.1.1 # via pytest-xdist executing==2.2.0 # via stack-data filelock==3.18.0 # via tox, virtualenv, ansible-lint (pyproject.toml) ghp-import==2.1.0 # via mkdocs gitdb==4.0.12 # via gitpython gitpython==3.1.44 # via tox-extra griffe==1.7.1 # via mkdocstrings-python hjson==3.1.0 # via mkdocs-macros-plugin, super-collections htmlmin2==0.1.13 # via mkdocs-minify-plugin idna==3.10 # via requests importlib-metadata==8.6.1 # via ansible-lint (pyproject.toml) iniconfig==2.1.0 # via pytest ipdb==0.13.13 # via ansible-lint (pyproject.toml) ipython==8.34.0 # via ipdb, ansible-lint (pyproject.toml) isort==6.0.1 # via pylint jedi==0.19.2 # via ipython jinja2==3.1.6 # via ansible-core, mkdocs, mkdocs-macros-plugin, mkdocs-material, mkdocstrings jmespath==1.0.1 # via ansible-lint (pyproject.toml) jsmin==3.0.1 # via mkdocs-minify-plugin jsonschema==4.23.0 # via ansible-compat, ansible-lint (pyproject.toml) jsonschema-specifications==2024.10.1 # via jsonschema license-expression==30.4.1 # via ansible-lint (pyproject.toml) linkchecker==10.5.0 # via mkdocs-ansible markdown==3.7 # via markdown-include, mkdocs, mkdocs-autorefs, mkdocs-htmlproofer-plugin, mkdocs-material, mkdocstrings, pymdown-extensions markdown-exec==1.10.3 # via mkdocs-ansible markdown-include==0.8.1 # via mkdocs-ansible markupsafe==3.0.2 # via jinja2, mkdocs, mkdocs-autorefs, mkdocstrings matplotlib-inline==0.1.7 # via ipython mccabe==0.7.0 # via pylint mergedeep==1.3.4 # via mkdocs, mkdocs-get-deps mkdocs==1.6.1 # via mkdocs-ansible, mkdocs-autorefs, mkdocs-gen-files, mkdocs-htmlproofer-plugin, mkdocs-macros-plugin, mkdocs-material, mkdocs-minify-plugin, mkdocs-monorepo-plugin, mkdocstrings mkdocs-ansible==25.2.0 # via ansible-lint (pyproject.toml) mkdocs-autorefs==1.4.1 # via mkdocstrings, mkdocstrings-python mkdocs-gen-files==0.5.0 # via mkdocs-ansible mkdocs-get-deps==0.2.0 # via mkdocs mkdocs-htmlproofer-plugin==1.3.0 # via mkdocs-ansible mkdocs-macros-plugin==1.3.7 # via mkdocs-ansible mkdocs-material==9.6.9 # via mkdocs-ansible mkdocs-material-extensions==1.3.1 # via mkdocs-ansible, mkdocs-material mkdocs-minify-plugin==0.8.0 # via mkdocs-ansible mkdocs-monorepo-plugin==1.1.0 # via mkdocs-ansible mkdocstrings==0.29.0 # via mkdocs-ansible, mkdocstrings-python mkdocstrings-python==1.16.8 # via mkdocs-ansible mypy==1.15.0 # via ansible-lint (pyproject.toml) mypy-extensions==1.0.0 # via black, mypy netaddr==1.3.0 # via ansible-lint (pyproject.toml) packaging==24.2 # via ansible-compat, ansible-core, bindep, black, mkdocs, mkdocs-macros-plugin, pyproject-api, pytest, pytest-sugar, tox, tox-extra, tox-uv, ansible-lint (pyproject.toml) paginate==0.5.7 # via mkdocs-material parsley==1.3 # via bindep parso==0.8.4 # via jedi pathspec==0.12.1 # via black, mkdocs, mkdocs-macros-plugin, yamllint, ansible-lint (pyproject.toml) pbr==6.1.1 # via bindep pexpect==4.9.0 # via ipython pillow==11.1.0 # via cairosvg, mkdocs-ansible platformdirs==4.3.7 # via black, mkdocs-get-deps, pylint, tox, virtualenv pluggy==1.5.0 # via pytest, tox prompt-toolkit==3.0.50 # via ipython psutil==7.0.0 # via pytest-xdist, ansible-lint (pyproject.toml) ptyprocess==0.7.0 # via pexpect pure-eval==0.2.3 # via stack-data pycparser==2.22 # via cffi pygments==2.19.1 # via ipython, mkdocs-material pylint==3.3.6 # via ansible-lint (pyproject.toml) pymdown-extensions==10.14.3 # via markdown-exec, mkdocs-ansible, mkdocs-material, mkdocstrings pyproject-api==1.9.0 # via tox pytest==8.3.5 # via pytest-instafail, pytest-mock, pytest-plus, pytest-sugar, pytest-xdist, ansible-lint (pyproject.toml) pytest-instafail==0.5.0 # via ansible-lint (pyproject.toml) pytest-mock==3.14.0 # via ansible-lint (pyproject.toml) pytest-plus==0.8.1 # via ansible-lint (pyproject.toml) pytest-sugar==1.0.0 # via ansible-lint (pyproject.toml) pytest-xdist==3.6.1 # via ansible-lint (pyproject.toml) python-dateutil==2.9.0.post0 # via ghp-import, mkdocs-macros-plugin python-slugify==8.0.4 # via mkdocs-monorepo-plugin pyyaml==6.0.2 # via ansible-compat, ansible-core, mkdocs, mkdocs-get-deps, mkdocs-macros-plugin, pymdown-extensions, pyyaml-env-tag, yamllint, ansible-lint (pyproject.toml) pyyaml-env-tag==0.1 # via mkdocs referencing==0.36.2 # via jsonschema, jsonschema-specifications, types-jsonschema, ansible-lint (pyproject.toml) requests==2.32.3 # via linkchecker, mkdocs-htmlproofer-plugin, mkdocs-material rpds-py==0.24.0 # via jsonschema, referencing ruamel-yaml==0.18.10 # via ansible-lint (pyproject.toml) setproctitle==1.3.5 # via pytest-xdist setuptools==78.1.0 # via pbr six==1.17.0 # via python-dateutil smmap==5.0.2 # via gitdb soupsieve==2.6 # via beautifulsoup4 stack-data==0.6.3 # via ipython subprocess-tee==0.4.2 # via ansible-compat, ansible-lint (pyproject.toml) super-collections==0.5.3 # via mkdocs-macros-plugin termcolor==2.5.0 # via mkdocs-macros-plugin, pytest-sugar text-unidecode==1.3 # via python-slugify tinycss2==1.4.0 # via cairosvg, cssselect2 tomlkit==0.13.2 # via pylint tox==4.25.0 # via tox-extra, tox-uv, ansible-lint (pyproject.toml) tox-extra==2.1.0 # via ansible-lint (pyproject.toml) tox-uv==1.25.0 # via tox-extra, ansible-lint (pyproject.toml) traitlets==5.14.3 # via ipython, matplotlib-inline types-jsonschema==4.23.0.20241208 # via ansible-lint (pyproject.toml) types-pyyaml==6.0.12.20250326 # via ansible-lint (pyproject.toml) urllib3==2.3.0 # via requests virtualenv==20.29.3 # via tox watchdog==6.0.0 # via mkdocs wcmatch==10.0 # via ansible-lint (pyproject.toml) wcwidth==0.2.13 # via prompt-toolkit webencodings==0.5.1 # via cssselect2, tinycss2 yamllint==1.37.0 # via ansible-lint (pyproject.toml) zipp==3.21.0 # via importlib-metadata # The following packages were excluded from the output: # ansible-core # exceptiongroup # pip # resolvelib # ruamel-yaml-clib # tomli # typing-extensions # uv ansible-ansible-lint-c16f018/.config/dictionary.txt000066400000000000000000000077271477347356000223260ustar00rootroot00000000000000Adrián Autobuild CLICOLOR CODENOTIFY CODEOWNERS CTYPE Cacqueray Chamoulaud DISTRO DOTGLOB ENVVAR EPEL EPIPE # linux Fimport Jython MYTAG PYTHONBREAKPOINT PYTHONIOENCODING PYTHONPYCACHEPREFIX REQPASS RULEDIRS RUNLEVEL Renderable Representer SIGUSR1 SRCROOT Sbarnea Sorin Sshell TOXENV TYPECHECK Taskfiles Tsukinowa Tóth WSLENV aarch64 abspath addoption addopts alertmanager ansiblelint apidoc apport argparsing argspecs arxcruz audgirka auditd autobuild autoclass autodetected autodiscovery autodoc autofix autohide autorefs autoupdate awcrosby backports backticks bdist becomeuserabove bindep blockincludes blockinfile bools boto bracketsmatchtest bracketsmatchtestfile buildinfo buildset builtins cacheable cachier capfd caplog capsys cffi chdir chgrp chkconfig chunksize clib codeclimate codecov codenotify codeql codespell colorama colsystem commandline commitlint commonmark compat conftest coveragerc cpus cpuset createfile darglint dataclasses dbservers deannotate debconf debops decryptable delenv dellemc denormalize deps devel dharmabumstead direnv dirhtml dists distutils doas docstrings doctest doctrees docutils dotconfig dotslash drybjed dunder dzdo ematcher ematchtestfile envrc execnet extlinks facelessuser facter fakerole fastapi fileglob filelock filesspot filetree fips firewalld fontawesome formatstr formetting fqcn fqrn fstring fulltoc fullwidth gecos geerlingguy getent getmatches globbing globmatch gplv3 groupname hostkey hostnames hostvars htmldir htmlproofer htpasswd hwchksum hwcksum idempotency ignorelist importlib indentless iniconfig inlinehilite insertafter ipaddr ipwrap isclass iscsi isdir isdisjoint iskeyword isort isorted jsonfile jsonschema junitxml keepends keypair keyserver konstruktoid kubernetes kubevirt lalo languageservice letsencrypt levelname libbzip libera libyaml licensedb lineinfile linenums linkcheck lintable lintables literalinclude localectl machinectl magiclink markdownlint matchdir matcherror matchlines matchtask matchtasks matchvar matchyaml maxdepth maxsplit minversion mkdir mkdocs mkdocstrings mkdtemp mockings mockreturn modifyitems modindex moduleauthor mypy myrole namedtempfile nestedincludes netcommon netscaler nilashishc nitpicky nocolor nodeps noexist nomatches nomatchestest noqa norole nostderr notest nxos octal octals opensearch openshift outdir outlen pacman pageview panos parseable pathex pathlib pathspec pathspecs pbrun pfexec pickleable pipefail piptools pipx pkgcache # linux pkgs placefolder plainexamples pluggy pluginmanager pmrun podman portchannel posargs preexec prerun prettierignore programoutput psutil pwsh pyargs pycache pycharm pyenv pygments pylint pylintrc pymdown pymdownx pypa pyparsing pypi pyproject pyproject.toml pypy pyright pytest pyupgrade pyyaml redef redirections reexec reformatter regexes releasenotes relpath reportversion representer reqs resolvelib returncode rmtree robertdebock rolepath roundtrip ruamel rulebook rulebooks ruledirs rulesdir rulesdirs ruleset runas sarif scalarint scalarstring scancode schemafile sdist sdists sectionauthor seealso sesu setenv setuptools shortdesc showlocals shutil signoff simpletask simplifiable skippable skiptasks skiputils slackpkg slaveinput sortfunc sourcegraph srcs srpm ssbarnea stylesheet subdir subelements subfolders subresults subschema subschemas substrs subtest sudosu superfences supervisorctl swdepot switchport synchronize sysvinit taskfile taskhandler taskimports taskincludes taskshandlers templatevars templating testcollection testinfra testmon testns testpath testpaths testproject testpypi testrun timesyncd tmpfs toctree toidentifier tomli tomlsort toolset tripleo tuco typehint typehints ulimits uncook ungrouped unignored unimported unindented uninstallation unjinja unlex unloadable unnormalized unskippable unspaced unsubscriptable untemplated userbase uwsgi validable vararg varname varnotset varset varsfile varstring varunset venv viewcode virtnet virtualenv virtualenvs wcmatch webserver webservers willthames workdir workerinput worktree xdist xfail xunit yatesr zuul ansible-ansible-lint-c16f018/.config/requirements-docs.in000066400000000000000000000001331477347356000234010ustar00rootroot00000000000000mkdocs-ansible>=24.12.0 # do not use lock extra because it would break dependabot updates ansible-ansible-lint-c16f018/.config/requirements-lock.txt000066400000000000000000000033531477347356000236210ustar00rootroot00000000000000# This file was autogenerated by uv via the following command: # tox run -e deps ansible-compat==25.1.5 # via ansible-lint (pyproject.toml) attrs==25.3.0 # via jsonschema, referencing black==25.1.0 # via ansible-lint (pyproject.toml) bracex==2.5.post1 # via wcmatch cffi==1.17.1 # via cryptography click==8.1.8 # via black cryptography==44.0.2 # via ansible-core filelock==3.18.0 # via ansible-lint (pyproject.toml) importlib-metadata==8.6.1 # via ansible-lint (pyproject.toml) jinja2==3.1.6 # via ansible-core jsonschema==4.23.0 # via ansible-compat, ansible-lint (pyproject.toml) jsonschema-specifications==2024.10.1 # via jsonschema markupsafe==3.0.2 # via jinja2 mypy-extensions==1.0.0 # via black packaging==24.2 # via ansible-compat, ansible-core, black, ansible-lint (pyproject.toml) pathspec==0.12.1 # via black, yamllint, ansible-lint (pyproject.toml) platformdirs==4.3.7 # via black pycparser==2.22 # via cffi pyyaml==6.0.2 # via ansible-compat, ansible-core, yamllint, ansible-lint (pyproject.toml) referencing==0.36.2 # via jsonschema, jsonschema-specifications, ansible-lint (pyproject.toml) rpds-py==0.24.0 # via jsonschema, referencing ruamel-yaml==0.18.10 # via ansible-lint (pyproject.toml) subprocess-tee==0.4.2 # via ansible-compat, ansible-lint (pyproject.toml) wcmatch==10.0 # via ansible-lint (pyproject.toml) yamllint==1.37.0 # via ansible-lint (pyproject.toml) zipp==3.21.0 # via importlib-metadata # The following packages were excluded from the output: # ansible-core # resolvelib # ruamel-yaml-clib # tomli # typing-extensions ansible-ansible-lint-c16f018/.config/requirements-test.in000066400000000000000000000013701477347356000234340ustar00rootroot00000000000000black # IDE support coverage-enable-subprocess # see https://github.com/nedbat/coveragepy/issues/1341#issuecomment-1228942657 coverage[toml] >= 6.4.4 ipdb ipython jmespath license-expression >= 30.3.0 # Apache 2.0 mypy # IDE support netaddr # needed by ipwrap filter pip # tox command psutil # soft-dep of pytest-xdist pylint # IDE support pytest >= 7.2.2 pytest-instafail >= 0.5.0 # only for local development, via PYTEST_ADDOPTS=-edit pytest-mock pytest-plus >= 0.6 # for PYTEST_REQPASS pytest-sugar # shows failures immediately, even with xdist pytest-xdist[psutil,setproctitle] >= 2.1.0 ruamel-yaml-clib # needed for mypy ruamel.yaml>=0.17.31 tox >= 4.0.0 tox-extra>=2.1 tox-uv>=1.25 tox>=4.24.2 types-jsonschema # IDE support types-pyyaml # IDE support ansible-ansible-lint-c16f018/.config/requirements.in000066400000000000000000000013461477347356000224620ustar00rootroot00000000000000# Special order section for helping pip: ansible-core>=2.16.11 # GPLv3 ansible-compat>=25.1.5 # GPLv3 # alphabetically sorted: black>=24.3.0 # MIT (security) filelock>=3.8.2 # The Unlicense importlib-metadata # Apache jsonschema>=4.10.0 # MIT, version needed for improved errors packaging>=22.0 # Apache-2.0,BSD-2-Clause pathspec>=0.10.3 # Mozilla Public License 2.0 (MPL 2.0) pyyaml>=6.0.2 # MIT (compilation probles with older versions) ruamel.yaml>=0.18.5,!=0.18.7,!=0.18.8 # MIT referencing>=0.36.2 # MIT, https://github.com/python-jsonschema/referencing/issues/216 subprocess-tee>=0.4.1 # MIT, used by ansible-compat yamllint >= 1.34.0 # GPLv3 wcmatch>=8.1.2; python_version < '3.12' # MIT wcmatch>=8.5.0; python_version >= '3.12' # MIT ansible-ansible-lint-c16f018/.config/vulture_whitelist.py000066400000000000000000000035011477347356000235560ustar00rootroot00000000000000# type: ignore _.configured # unused attribute (src/ansiblelint/__main__.py:140) configured # unused variable (src/ansiblelint/config.py:132) _.keep_trailing_newline # unused attribute (src/ansiblelint/rules/jinja.py:280) _.lstrip_blocks # unused attribute (src/ansiblelint/rules/jinja.py:282) _.trim_blocks # unused attribute (src/ansiblelint/rules/jinja.py:283) _.autoescape # unused attribute (src/ansiblelint/rules/jinja.py:284) _.newline_sequence # unused attribute (src/ansiblelint/rules/jinja.py:285) _.allow_duplicate_keys # unused attribute (src/ansiblelint/skip_utils.py:138) _.playbook_paths # unused attribute (src/ansiblelint/utils.py:257) _.explicit_end # unused attribute (src/ansiblelint/yaml_utils.py:915) _.default_flow_style # unused attribute (src/ansiblelint/yaml_utils.py:923) _.compact_seq_seq # unused attribute (src/ansiblelint/yaml_utils.py:924) _.compact_seq_map # unused attribute (src/ansiblelint/yaml_utils.py:925) _.Constructor # unused attribute (src/ansiblelint/yaml_utils.py:946) _.preserve_quotes # unused attribute (src/ansiblelint/yaml_utils.py:956) _.BLACK # unused variable (src/ansiblelint/output.py:172) _.YELLOW # unused variable (src/ansiblelint/output.py:175) _.CYAN # unused variable (src/ansiblelint/output.py:178) _.WHITE # unused variable (src/ansiblelint/output.py:179) _.GREY # unused variable (src/ansiblelint/output.py:180) _.BRIGHT_RED # unused variable (src/ansiblelint/output.py:181) _.BRIGHT_GREEN # unused variable (src/ansiblelint/output.py:182) _.BRIGHT_YELLOW # unused variable (src/ansiblelint/output.py:183) _.BRIGHT_BLUE # unused variable (src/ansiblelint/output.py:184) _.BRIGHT_MAGENTA # unused variable (src/ansiblelint/output.py:185) _.BRIGHT_CYAN # unused variable (src/ansiblelint/output.py:186) _.BRIGHT_WHITE # unused variable (src/ansiblelint/output.py:187) ansible-ansible-lint-c16f018/.darglint000066400000000000000000000001171477347356000176640ustar00rootroot00000000000000[darglint] docstring_style=sphinx ignore=DAR101 enable=DAR104 strictness=long ansible-ansible-lint-c16f018/.git_archival.txt000066400000000000000000000002221477347356000213270ustar00rootroot00000000000000node: c16f018b1bdfdea6717f4b5b1b141a78b86021cd node-date: 2025-04-03T11:56:32Z describe-name: v25 ref-names: HEAD -> main, tag: v25.2.1, tag: v25 ansible-ansible-lint-c16f018/.gitattributes000066400000000000000000000002211477347356000207460ustar00rootroot00000000000000# Force LF line endings for text files * text=auto eol=lf *.png binary # Needed for setuptools-scm-git-archive .git_archival.txt export-subst ansible-ansible-lint-c16f018/.github/000077500000000000000000000000001477347356000174205ustar00rootroot00000000000000ansible-ansible-lint-c16f018/.github/CODEOWNERS000066400000000000000000000000321477347356000210060ustar00rootroot00000000000000* @ansible/devtools ansible-ansible-lint-c16f018/.github/CODE_OF_CONDUCT.md000066400000000000000000000002421477347356000222150ustar00rootroot00000000000000# Community Code of Conduct Please see the official [Ansible Community Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html). ansible-ansible-lint-c16f018/.github/ISSUE_TEMPLATE.md000066400000000000000000000014671477347356000221350ustar00rootroot00000000000000# Issue Type - Bug report - Feature request # Ansible and Ansible Lint details ``` ansible --version ansible-lint --version ``` - ansible installation method: one of source, pip, OS package - ansible-lint installation method: one of source, pip, OS package # Desired Behavior Please give some details of the feature being requested or what should happen if providing a bug report Possible security bugs should be reported via email to `security@ansible.com` # Actual Behavior (Bug report only) Please give some details of what is actually happening. Include a [minimum complete verifiable example] with: - playbook - output of running ansible-lint - if you're getting a stack trace, output of `ansible-playbook --syntax-check playbook` [minimum complete verifiable example]: http://stackoverflow.com/help/mcve ansible-ansible-lint-c16f018/.github/ISSUE_TEMPLATE/000077500000000000000000000000001477347356000216035ustar00rootroot00000000000000ansible-ansible-lint-c16f018/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000035111477347356000242750ustar00rootroot00000000000000--- name: Bug report about: > Create a bug report. Ensure that it does reproduce on the main branch with python >=3.10. For anything else, please use the discussion link below. labels: bug, new --- ##### Summary ##### Issue Type - Bug Report ##### OS / ENVIRONMENT ```console (paste below) ansible-lint --version ``` - ansible installation method: one of source, pip, OS package - ansible-lint installation method: one of source, pip, OS package ##### STEPS TO REPRODUCE ```console (paste below) ``` ##### Desired Behavior Possible security bugs should be reported via email to `security@ansible.com` ##### Actual Behavior Please give some details of what is happening. Include a [minimum complete verifiable example] with: - minimized playbook to reproduce the error - the output of running ansible-lint including the command line used - if you're getting a stack trace, also the output of `ansible-playbook --syntax-check playbook` ```paste below ``` [minimum complete verifiable example]: http://stackoverflow.com/help/mcve ansible-ansible-lint-c16f018/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000021751477347356000236000ustar00rootroot00000000000000--- # Ref: https://help.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser blank_issues_enabled: false # default is true contact_links: - name: Feature requests url: https://github.com/ansible/ansible-lint/discussions/categories/ideas about: Suggest an idea for this project - name: Discussions url: https://github.com/ansible/ansible-lint/discussions/ about: Any kind of questions should go on the forum. - name: Security bug report url: https://docs.ansible.com/ansible/latest/community/reporting_bugs_and_features.html about: | Please learn how to report security vulnerabilities here. For all security related bugs, email security@ansible.com instead of using this issue tracker and you will receive a prompt response. For more information, see https://docs.ansible.com/ansible/latest/community/reporting_bugs_and_features.html - name: Ansible Code of Conduct url: https://docs.ansible.com/ansible/latest/community/code_of_conduct.html about: Be nice to other members of the community. Behave. ansible-ansible-lint-c16f018/.github/SECURITY.md000066400000000000000000000011521477347356000212100ustar00rootroot00000000000000# Security Policy ## Supported Versions Ansible applies security fixes according to the 3-versions-back support policy. Please find more information in [our docs]. ## Reporting a Vulnerability We encourage responsible disclosure practices for security vulnerabilities. Please read our [policies for reporting bugs](https://docs.ansible.com/ansible/devel/community/reporting_bugs_and_features.html#reporting-a-bug) if you want to report a security issue that might affect Ansible. [our docs]: https://docs.ansible.com/ansible-core/devel/reference_appendices/release_and_maintenance.html#ansible-core-release-cycle ansible-ansible-lint-c16f018/.github/dependabot.yml000066400000000000000000000007751477347356000222610ustar00rootroot00000000000000--- version: 2 updates: - package-ecosystem: pip directory: /.config/ schedule: day: sunday interval: weekly labels: - dependabot-deps-updates - skip-changelog groups: dependencies: patterns: - "*" - package-ecosystem: "github-actions" directory: "/" schedule: interval: daily labels: - "dependencies" - "skip-changelog" ignore: - dependency-name: "codecov/codecov-action" versions: ["4.6.0"] ansible-ansible-lint-c16f018/.github/lower-constraints.txt000066400000000000000000000014201477347356000236530ustar00rootroot00000000000000# This file is kept in a different directory than .config in order to not be # automatically updated by dependabot. This should be kept in sync with # minimal requirements configured inside .config/requirements.in ansible-core==2.16.11 ansible-compat==25.1.5 # GPLv3 black==24.3.0 # MIT (security) filelock==3.16.1 # The Unlicense # due to tox-uv jsonschema==4.10.0 # MIT, version needed for improved errors packaging==24.2 # Due to tox-uv pathspec==0.10.3 pyyaml==6.0.2 ruamel.yaml==0.18.5 # MIT subprocess-tee==0.4.1 # MIT, used by ansible-compat # https://packages.ubuntu.com/noble/python3-wcmatch # https://packages.fedoraproject.org/pkgs/python-wcmatch/python3-wcmatch/ wcmatch==8.1.2; python_version < '3.12' # EPEL 8 wcmatch==8.5.0; python_version >= '3.12' yamllint == 1.34.0 ansible-ansible-lint-c16f018/.github/release-drafter.yml000066400000000000000000000001231477347356000232040ustar00rootroot00000000000000--- # see https://github.com/ansible/team-devtools _extends: ansible/team-devtools ansible-ansible-lint-c16f018/.github/workflows/000077500000000000000000000000001477347356000214555ustar00rootroot00000000000000ansible-ansible-lint-c16f018/.github/workflows/ack.yml000066400000000000000000000004201477347356000227320ustar00rootroot00000000000000--- # See https://github.com/ansible/devtools/blob/main/.github/workflows/ack.yml name: ack "on": pull_request_target: types: [opened, labeled, unlabeled, synchronize] jobs: ack: uses: ansible/team-devtools/.github/workflows/ack.yml@main secrets: inherit ansible-ansible-lint-c16f018/.github/workflows/push.yml000066400000000000000000000003771477347356000231660ustar00rootroot00000000000000--- # See https://github.com/ansible/devtools/blob/main/.github/workflows/push.yml name: push "on": push: branches: - main - "releases/**" - "stable/**" jobs: ack: uses: ansible/team-devtools/.github/workflows/push.yml@main ansible-ansible-lint-c16f018/.github/workflows/redirects.yml000066400000000000000000000013521477347356000241650ustar00rootroot00000000000000--- # Sync RTD redirects name: redirects "on": push: branches: - main paths: - docs/redirects.yml - .github/workflows/redirects.yml # Manually triggered using GitHub's UI workflow_dispatch: jobs: docs: environment: release runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 - name: Upgrade Python toolchain run: python3 -m pip install --upgrade pip setuptools wheel - name: Install readthedocs-cli run: python3 -m pip install readthedocs-cli - name: Sync redirects run: rtd projects ansible-lint redirects sync -f docs/redirects.yml --wet-run env: RTD_TOKEN: ${{ secrets.RTD_TOKEN }} ansible-ansible-lint-c16f018/.github/workflows/release.yml000066400000000000000000000030321477347356000236160ustar00rootroot00000000000000--- name: release "on": release: types: [published] workflow_dispatch: jobs: # https://github.com/marketplace/actions/actions-tagger actions-tagger: needs: pypi # do not move the mobile tag until we publish runs-on: windows-latest permissions: # Give the default GITHUB_TOKEN write permission. # https://github.blog/changelog/2023-02-02-github-actions-updating-the-default-github_token-permissions-to-read-only/ contents: write steps: - uses: Actions-R-Us/actions-tagger@latest with: token: "${{ github.token }}" # Do not activate latest tag because it seems to affect RTD builds # publish_latest_tag: true pypi: name: Publish to PyPI registry environment: release runs-on: ubuntu-24.04 permissions: id-token: write env: FORCE_COLOR: 1 PY_COLORS: 1 TOXENV: pkg steps: - name: Switch to using Python 3.10 by default uses: actions/setup-python@v5 with: python-version: "3.10" - name: Install tox run: python3 -m pip install --user "tox>=4.0.0" - name: Check out src from Git uses: actions/checkout@v4 with: fetch-depth: 0 # needed by setuptools-scm submodules: true - name: Build dists run: python3 -m tox - name: Publish to pypi.org if: >- # "create" workflows run separately from "push" & "pull_request" github.event_name == 'release' uses: pypa/gh-action-pypi-publish@release/v1 ansible-ansible-lint-c16f018/.github/workflows/tox.yml000066400000000000000000000207071477347356000230200ustar00rootroot00000000000000--- name: tox on: push: branches: - "main" pull_request: branches: - "main" schedule: - cron: "0 0 * * *" workflow_call: concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} cancel-in-progress: true env: FORCE_COLOR: 1 # tox, pytest, ansible-lint PY_COLORS: 1 jobs: prepare: name: prepare runs-on: ubuntu-24.04 outputs: matrix: ${{ steps.generate_matrix.outputs.matrix }} steps: - name: Determine matrix id: generate_matrix uses: coactions/dynamic-matrix@v4 with: min_python: "3.10" max_python: "3.13" default_python: "3.10" other_names: | lint pkg hook docs schemas eco pre py311-devel py310-lower py312-lower py313-devel platforms: linux,macos test-action: runs-on: ubuntu-24.04 env: # This disables the github annotations in the output of ansible-lint action # which might confuse users. GITHUB_ACTIONS_TEST: "true" steps: - uses: actions/checkout@v4 - name: Self test 1 uses: ./ with: # basically we only lint linter own configuration, which should be passing. args: .ansible-lint - name: Self test 2 uses: ./ with: # basically we only lint linter own configuration, which should be passing. args: .ansible-lint working_directory: . - name: Self test 3 uses: ./ with: # basically we only lint linter own configuration, which should be passing. args: .ansible-lint working_directory: docs expected_return_code: "2" # expected to fail because the given argument does not exist in this folder build: name: ${{ matrix.name }} runs-on: ${{ matrix.os || 'ubuntu-24.04' }} needs: - prepare defaults: run: shell: ${{ matrix.shell || 'bash'}} strategy: fail-fast: false matrix: ${{ fromJson(needs.prepare.outputs.matrix) }} # max-parallel: 5 # The matrix testing goal is to cover the *most likely* environments # which are expected to be used by users in production. Avoid adding a # combination unless there are good reasons to test it, like having # proof that we failed to catch a bug by not running it. Using # distribution should be preferred instead of custom builds. steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # needed by setuptools-scm submodules: true - name: Set pre-commit cache uses: actions/cache@v4 if: ${{ matrix.name == 'lint' }} with: path: | ~/.cache/pre-commit key: pre-commit-${{ matrix.name }}-${{ hashFiles('.pre-commit-config.yaml') }} - name: Set ansible cache(s) uses: actions/cache@v4 with: path: | .cache/eco examples/playbooks/collections/ansible_collections ~/.cache/ansible-compat ~/.ansible/collections ~/.ansible/roles .tox key: ${{ matrix.name }}-${{ matrix.os }}--${{ hashFiles('tools/test-eco.sh', 'requirements.yml', 'examples/playbooks/collections/requirements.yml') }} - name: Set up Python ${{ matrix.python_version || '3.10' }} if: "!contains(matrix.shell, 'wsl')" uses: actions/setup-python@v5 with: cache: pip python-version: ${{ matrix.python_version || '3.10' }} - uses: actions/setup-node@v4 with: node-version: 20 cache: "npm" cache-dependency-path: test/schemas/package-lock.json - name: Run ./tools/test-setup.sh run: ./tools/test-setup.sh - name: Install tox run: | python3 -m pip install --upgrade pip python3 -m pip install --upgrade "tox>=4.0.0" "tox-uv>=1.25.0" "uv>=0.6.6" - name: Log installed dists run: python3 -m pip freeze --all - run: ${{ matrix.command }} - run: ${{ matrix.command2 }} if: ${{ matrix.command2 }} - run: ${{ matrix.command3 }} if: ${{ matrix.command3 }} - run: ${{ matrix.command4 }} if: ${{ matrix.command4 }} - run: ${{ matrix.command5 }} if: ${{ matrix.command5 }} - name: Archive logs uses: actions/upload-artifact@v4 with: name: logs-${{ matrix.name }}.zip include-hidden-files: true path: | .tox/**/log/ .tox/**/.coverage* .tox/**/coverage.xml - name: Report failure if git reports dirty status run: | git checkout HEAD -- src/ansiblelint/schemas/__store__.json if [[ -n $(git status -s) ]]; then # shellcheck disable=SC2016 echo -n '::error file=git-status::' printf '### Failed as git reported modified and/or untracked files\n```\n%s\n```\n' "$(git status -s)" | tee -a "$GITHUB_STEP_SUMMARY" exit 99 fi # https://github.com/actions/toolkit/issues/193 codeql: name: codeql runs-on: ubuntu-24.04 permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: ["python"] steps: - name: Checkout repository uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # queries: security-extended,security-and-quality - name: Autobuild uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 with: category: "/language:${{matrix.language}}" check: if: always() permissions: id-token: write checks: read needs: - build - test-action runs-on: ubuntu-24.04 steps: # checkout needed for codecov action which needs codecov.yml file - uses: actions/checkout@v4 - name: Set up Python # likely needed for coverage uses: actions/setup-python@v5 with: python-version: "3.13" - run: pip3 install 'coverage>=7.5.1' - name: Merge logs into a single archive uses: actions/upload-artifact/merge@v4 with: name: logs.zip include-hidden-files: true pattern: logs-*.zip # artifacts like py312.zip and py312-macos do have overlapping files separate-directories: true - name: Download artifacts uses: actions/download-artifact@v4 continue-on-error: true # to allow rerunning this job with: name: logs.zip path: . - name: Check for expected number of coverage.xml reports run: | JOBS_PRODUCING_COVERAGE=10 if [ "$(find . -name coverage.xml | wc -l | bc)" -ne "${JOBS_PRODUCING_COVERAGE}" ]; then echo "::error::Number of coverage.xml files was not the expected one (${JOBS_PRODUCING_COVERAGE}): $(find . -name coverage.xml |xargs echo)" exit 1 fi - name: Upload coverage data uses: codecov/codecov-action@v5.4.0 with: name: ${{ matrix.name }} # verbose: true # optional (default = false) fail_ci_if_error: true use_oidc: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork) }} # cspell:ignore oidc - name: Decide whether the needed jobs succeeded or failed uses: re-actors/alls-green@release/v1 with: jobs: ${{ toJSON(needs) }} - name: Delete Merged Artifacts uses: actions/upload-artifact/merge@v4 with: include-hidden-files: true delete-merged: true pattern: logs-*.zip ansible-ansible-lint-c16f018/.gitignore000066400000000000000000000023211477347356000200460ustar00rootroot00000000000000# Byte-compiled / optimized / DLL files __pycache__ *.py[co] *$py.class # Temporary ruff file *.isorted # Packages .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib64/ parts/ pip-wheel-metadata sdist/ var/ *.egg-info/ .installed.cfg *.egg # Installer logs pip-log.txt # Unit test / coverage reports .tox # Needed for CLI tests .sandbox # pyenv .python-version # Environments .env .venv env/ venv/ # Coverage artifacts .coverage* coverage*.xml pip-wheel-metadata .test-results/ # mypy .mypy_cache # Generated by setuptools-scm src/ansiblelint/_version.py # Unformatted fixtures, need to be added with force as we need to exclude # them from being reformatted (.prettierignore is a symlink to .gitignore) test/fixtures/formatting-before/ # prettier should not edit this due to forcibly extra-long lines examples/playbooks/vars/strings.transformed.yml # prettier should not edit this due to intentionally spaced nesting examples/playbooks/vars/transform_nested_data.yml # other *.tar.gz *.tmp.* .DS_Store .cache .envrc .idea .pytest_cache .vscode/launch.json _readthedocs coverage.lcov site src/ansiblelint/_version.py test/eco test/local-content test/schemas/node_modules node_modules .direnv uv.lock .ansible ansible-ansible-lint-c16f018/.gitmodules000066400000000000000000000000001477347356000202230ustar00rootroot00000000000000ansible-ansible-lint-c16f018/.packit.yaml000066400000000000000000000024411477347356000202760ustar00rootroot00000000000000--- # spell-checker:ignore packit specfile copr epel specfile_path: dist/ansible-lint.spec actions: create-archive: # packit.dev service does have these module pre-installed: - python3 -m build --sdist --outdir dist - sh -c "ls dist/ansible_lint-*.tar.gz" get-current-version: - ./tools/get-version.sh post-upstream-clone: - "git submodule init" - "git submodule update" - ./tools/update-version.sh srpm_build_deps: - python3-build - python3-setuptools_scm jobs: # - job: copr_build # targets: # - fedora-rawhide-aarch64 # one on PR should be enough # trigger: pull_request - job: copr_build trigger: commit branch: main targets: # See https://packit.dev/docs/configuration/#aliases # API to get available targets: https://api.dev.testing-farm.io/v0.1/composes/public - fedora-rawhide-x86_64 - fedora-rawhide-aarch64 - fedora-37-x86_64 - fedora-37-aarch64 # Missing python3-build see https://bugzilla.redhat.com/show_bug.cgi?id=2129071 # - centos-stream-9-aarch64 # - centos-stream-9-x86_64 # - job: tests # trigger: pull_request # metadata: # targets: # - fedora-all # - job: propose_downstream # trigger: release # metadata: # dist-git-branch: master ansible-ansible-lint-c16f018/.pre-commit-config.yaml000066400000000000000000000167731477347356000223570ustar00rootroot00000000000000--- ci: # format compatible with commitlint autoupdate_commit_msg: "chore: pre-commit autoupdate" autoupdate_schedule: monthly autofix_commit_msg: "chore: auto fixes from pre-commit.com hooks" skip: # https://github.com/pre-commit-ci/issues/issues/55 - pip-compile - pyright - schemas submodules: true exclude: > (?x)^( .config/constraints.txt| .config/.*requirements.*| examples/broken/encoding.yml| examples/broken/encoding.j2| examples/broken/yaml-with-tabs/invalid-due-tabs.yaml| examples/playbooks/collections/.*| examples/playbooks/vars/empty.transformed.yml| examples/playbooks/vars/empty.yml| src/ansiblelint/schemas/rulebook.json| test/schemas/data/licenses.json| test/schemas/negative_test| test/schemas/package-lock.json )$ repos: - repo: meta hooks: - id: check-useless-excludes - repo: https://github.com/rbubley/mirrors-prettier # keep it before yamllint rev: v3.5.3 hooks: - id: prettier # Temporary excludes so we can gradually normalize the formatting exclude: > (?x)^( .*\.md$| examples/other/some.j2.yaml| examples/playbooks/collections/.*| examples/playbooks/example.yml| examples/playbooks/invalid-transform.yml| examples/playbooks/multiline-brackets.*| examples/playbooks/templates/not-valid.yaml| examples/playbooks/vars/empty.transformed.yml| examples/playbooks/vars/empty.yml| examples/playbooks/with-skip-tag-id.yml| examples/playbooks/with-umlaut-.*| examples/yamllint/.*| src/ansiblelint/schemas/(molecule|tasks|playbook|rulebook).json| test/fixtures/formatting-before/.*| test/schemas/(negative_test|test)/.*\.md| test/schemas/data/.*| src/ansiblelint/schemas/ansible-navigator-config.json )$ always_run: true additional_dependencies: - prettier@3.2.4 - prettier-plugin-sort-json@3.1.0 - repo: https://github.com/streetsidesoftware/cspell-cli rev: v8.17.3 hooks: - id: cspell # entry: codespell --relative args: [--relative, --no-progress, --no-summary] name: Spell check with cspell - repo: https://github.com/python-jsonschema/check-jsonschema rev: 0.31.3 hooks: - id: check-github-workflows - repo: https://github.com/pre-commit/pre-commit-hooks.git rev: v5.0.0 hooks: - id: check-added-large-files - id: check-merge-conflict - id: check-symlinks - id: debug-statements - id: detect-private-key - id: end-of-file-fixer # ignore formatting-prettier to have an accurate prettier comparison exclude: > (?x)^( test/eco/.*.result| examples/yamllint/.*| test/fixtures/formatting-before/.*| test/fixtures/formatting-prettier/.* )$ - id: trailing-whitespace exclude: > (?x)^( examples/playbooks/(with-skip-tag-id|unicode).yml| examples/playbooks/example.yml| examples/yamllint/.*| test/eco/.*.result| test/fixtures/formatting-before/.* )$ - id: mixed-line-ending - id: fix-byte-order-marker - id: check-executables-have-shebangs - id: check-merge-conflict - id: debug-statements language_version: python3 - repo: https://github.com/codespell-project/codespell rev: v2.4.1 hooks: - id: codespell exclude: > (?x)^( .config/dictionary.txt| examples/broken/encoding.j2| test/schemas/negative_test/.*| test/schemas/test/.*| src/ansiblelint/schemas/.*\.json )$ additional_dependencies: - tomli - repo: https://github.com/adrienverge/yamllint.git rev: v1.36.2 hooks: - id: yamllint exclude: > (?x)^( examples/playbooks/templates/.*| examples/yamllint/.*| examples/other/some.j2.yaml| examples/playbooks/collections/.*| test/fixtures/formatting-before/.* )$ files: \.(yaml|yml)$ types: [file, yaml] entry: yamllint --strict - repo: https://github.com/pappasam/toml-sort rev: v0.24.2 hooks: - id: toml-sort-fix alias: toml - repo: https://github.com/tox-dev/tox-ini-fmt rev: 1.5.0 hooks: - id: tox-ini-fmt - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.11.0 hooks: - id: ruff args: - --fix - --exit-non-zero-on-fix types_or: [python, pyi] # - id: ruff-format # must be after ruff # types_or: [python, pyi] - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.15.0 hooks: - id: mypy # "." and pass_files are used to make pre-commit mypy behave the same as standalone mypy args: ["."] pass_filenames: false additional_dependencies: &deps - ansible-compat>=25.1.5 - black>=22.10.0 - cryptography>=39.0.1 - filelock>=3.12.2 - importlib_metadata - jinja2 - license-expression >= 30.3.0 - pip>=22.3.1 - pytest-mock - pytest>=7.2.2 - pyyaml>=6.0.2 # types-PyYAML is not enough - ruamel-yaml-clib>=0.2.8 - ruamel-yaml>=0.18.6 - subprocess-tee - types-jsonschema>=4.20.0.0 - types-setuptools - wcmatch - yamllint>=1.34.0 - repo: https://github.com/RobertCraigie/pyright-python rev: v1.1.398 hooks: - id: pyright additional_dependencies: *deps - repo: https://github.com/pycqa/pylint rev: v3.3.6 hooks: - id: pylint args: - --output-format=colorized additional_dependencies: *deps - repo: https://github.com/jendrikseipp/vulture rev: v2.14 hooks: - id: vulture - # keep at bottom as these are slower repo: local hooks: - id: schemas name: update json schemas entry: python3 src/ansiblelint/schemas/__main__.py language: python pass_filenames: false always_run: true # stages: [manual] - id: deps name: Upgrade constraints files and requirements files: ^(pyproject\.toml|.config/.*)$ always_run: true language: python entry: python3 -m uv pip compile -q --all-extras --python-version=3.10 --output-file=.config/constraints.txt pyproject.toml --upgrade pass_filenames: false stages: - manual additional_dependencies: - uv>=0.6.6 - id: pip-compile name: Check constraints files and requirements files: ^(pyproject\.toml|\.config/.*)$ language: python entry: uv pip compile -q --all-extras --python-version=3.10 --output-file=.config/constraints.txt pyproject.toml pass_filenames: false additional_dependencies: - uv>=0.6.6 - id: lock name: Update requirements-lock.txt alias: lock always_run: true entry: python3 -m uv pip compile -q --python-version=3.10 --upgrade --output-file=.config/requirements-lock.txt pyproject.toml --strip-extras files: ^(pyproject\.toml|\.config/.*)$ language: python pass_filenames: false stages: [manual] additional_dependencies: - uv>=0.6.6 ansible-ansible-lint-c16f018/.pre-commit-hooks.yaml000066400000000000000000000012111477347356000222120ustar00rootroot00000000000000--- # For use with pre-commit. # See usage instructions at http://pre-commit.com - id: ansible-lint name: Ansible-lint description: This hook runs ansible-lint. entry: python3 -m ansiblelint -v --force-color language: python # do not pass files to ansible-lint, see: # https://github.com/ansible/ansible-lint/issues/611 pass_filenames: false always_run: true additional_dependencies: # https://github.com/pre-commit/pre-commit/issues/1526 # If you want to use specific version of ansible-core or ansible, feel # free to override `additional_dependencies` in your own hook config # file. - ansible-core>=2.16.0 ansible-ansible-lint-c16f018/.prettierignore000077700000000000000000000000001477347356000231062.gitignoreustar00rootroot00000000000000ansible-ansible-lint-c16f018/.prettierrc.yaml000066400000000000000000000005431477347356000212070ustar00rootroot00000000000000--- proseWrap: always jsonRecursiveSort: true # prettier-plugin-sort-json tabWidth: 2 useTabs: false overrides: - files: - "*.md" options: # compatibility with markdownlint proseWrap: always printWidth: 80 - files: - "*.yaml" - "*.yml" options: # compatibility with yamllint proseWrap: preserve ansible-ansible-lint-c16f018/.readthedocs.yml000066400000000000000000000005641477347356000211530ustar00rootroot00000000000000--- version: 2 mkdocs: fail_on_warning: true configuration: mkdocs.yml build: os: ubuntu-24.04 tools: python: "3.11" commands: - pip install --user tox - python3 -m tox -e docs python: install: - method: pip path: tox - method: pip path: . extra_requirements: - docs submodules: include: all recursive: true ansible-ansible-lint-c16f018/.sonarcloud.properties000066400000000000000000000001211477347356000224170ustar00rootroot00000000000000sonar.python.version=3.10, 3.11, 3.12, 3.13 sonar.sources=src/ sonar.tests=test/ ansible-ansible-lint-c16f018/.sonarlint/000077500000000000000000000000001477347356000201475ustar00rootroot00000000000000ansible-ansible-lint-c16f018/.sonarlint/connectedMode.json000066400000000000000000000001221477347356000236040ustar00rootroot00000000000000{ "sonarCloudOrganization": "ansible", "projectKey": "ansible_ansible-lint" } ansible-ansible-lint-c16f018/.taplo.toml000066400000000000000000000004661477347356000201600ustar00rootroot00000000000000[formatting] # cspell: disable-next-line # compatibility between toml-sort-fix pre-commit hook and panekj.even-betterer-toml extension align_comments = false array_trailing_comma = false compact_arrays = true compact_entries = false compact_inline_tables = true inline_table_expand = false reorder_keys = true ansible-ansible-lint-c16f018/.vault_pass000066400000000000000000000000121477347356000202330ustar00rootroot00000000000000secret123 ansible-ansible-lint-c16f018/.vscode/000077500000000000000000000000001477347356000174215ustar00rootroot00000000000000ansible-ansible-lint-c16f018/.vscode/extensions.json000066400000000000000000000007561477347356000225230ustar00rootroot00000000000000{ "recommendations": [ "Tyriar.sort-lines", "charliermarsh.ruff", "esbenp.prettier-vscode", "hbenl.vscode-test-explorer", "ms-python.mypy-type-checker", "ms-python.pylint", "ms-python.python", "ms-python.vscode-pylance", "ms-vscode.live-server", "redhat.ansible", "redhat.vscode-yaml", "ryanluker.vscode-coverage-gutters", "shardulm94.trailing-spaces", "tamasfe.even-better-toml", "timonwong.shellcheck", "znck.grammarly" ] } ansible-ansible-lint-c16f018/.vscode/settings.json000066400000000000000000000025111477347356000221530ustar00rootroot00000000000000{ "[markdown]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[python]": { "editor.codeActionsOnSave": { "source.fixAll": "explicit", "source.organizeImports": "explicit" }, "editor.defaultFormatter": "charliermarsh.ruff", "editor.formatOnSave": true }, "[toml]": { "editor.defaultFormatter": "panekj.even-betterer-toml" }, "editor.formatOnSave": true, "evenBetterToml.formatter.alignComments": false, "evenBetterToml.formatter.arrayTrailingComma": true, "files.exclude": { "*.egg-info": true, ".pytest_cache": true, ".tox": true, "__pycache__": true, "build": true }, "git.ignoreLimitWarning": true, "grammarly.config.documentDomain": "academic", "grammarly.files.include": ["**/*.txt", "**/*.md"], "mypy-type-checker.severity": { "error": "Warning" }, "python.experiments.optInto": ["pythonTestAdapter"], "python.terminal.activateEnvironment": true, "python.testing.pytestEnabled": true, "python.testing.unittestEnabled": false, "sonarlint.connectedMode.project": { "connectionId": "ansible", "projectKey": "ansible_ansible-lint" }, "sortLines.filterBlankLines": true, "yaml.completion": true, "yaml.customTags": ["!encrypted/pkcs1-oaep scalar", "!vault scalar"], "yaml.format.enable": false, "yaml.validate": true } ansible-ansible-lint-c16f018/.yamllint000066400000000000000000000013661477347356000177200ustar00rootroot00000000000000--- rules: braces: min-spaces-inside: 0 max-spaces-inside: 1 comments: # prettier compatibility min-spaces-from-content: 1 comments-indentation: false document-start: present: true key-duplicates: forbid-duplicated-merge-keys: true indentation: level: error indent-sequences: consistent octal-values: forbid-implicit-octal: true forbid-explicit-octal: true # quoted-strings: # quote-type: double # required: only-when-needed ignore: | .tox examples/playbooks/example.yml examples/playbooks/syntax-error-string.yml examples/playbooks/vars/not_decryptable.yml test/schemas/negative_test/**/*.yml test/schemas/test/**/*.yml # ignore added because this file includes on-purpose errors ansible-ansible-lint-c16f018/COPYING000066400000000000000000001045151477347356000171210ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ansible-ansible-lint-c16f018/DCO_1_1.md000066400000000000000000000031221477347356000174450ustar00rootroot00000000000000# DCO All contributors must use `git commit --signoff` for any commit to be merged, and agree that usage of --signoff constitutes agreement with the terms of DCO 1.1, which appears below: ``` Developer Certificate of Origin Version 1.1 Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 1 Letterman Drive Suite D4700 San Francisco, CA, 94129 Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. ``` ansible-ansible-lint-c16f018/README.md000066400000000000000000000066221477347356000173450ustar00rootroot00000000000000[![PyPI version](https://img.shields.io/pypi/v/ansible-lint.svg)](https://pypi.org/project/ansible-lint) [![Ansible-lint rules explanation](https://img.shields.io/badge/Ansible--lint-rules-blue.svg)](https://ansible.readthedocs.io/projects/lint/rules/) [![Discussions](https://img.shields.io/badge/Discussions-gray.svg)](https://forum.ansible.com/tag/ansible-lint) [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) # Ansible-lint `ansible-lint` checks playbooks for practices and behavior that could potentially be improved. As a community-backed project ansible-lint supports only the last two major versions of Ansible. [Visit the Ansible Lint docs site](https://ansible.readthedocs.io/projects/lint/) # Using ansible-lint as a GitHub Action This action allows you to run `ansible-lint` on your codebase without having to install it yourself. ```yaml # .github/workflows/ansible-lint.yml name: ansible-lint on: pull_request: branches: ["main", "stable", "release/v*"] jobs: build: name: Ansible Lint # Naming the build is important to use it as a status check runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - name: Run ansible-lint uses: ansible/ansible-lint@main # optional (see below): with: args: "" setup_python: "true" working_directory: "" requirements_file: "" ``` All the arguments are optional and most users should not need them: - `args`: Arguments to be passed to ansible-lint command. - `setup_python`: If python should be installed. Default is `true`. - `working_directory`: The directory where to run ansible-lint from. Default is `github.workspace`. That might be needed if you want to lint only a subset of your repository. - `requirements_file`: Path to the requirements.yml file to install role and collection dependencies. For more details, see [ansible-lint-action]. # Communication Refer to the [Talk to us](https://ansible.readthedocs.io/projects/lint/contributing/#talk-to-us) section of the Contributing guide to find out how to get in touch with us. You can also find more information in the [Ansible communication guide](https://docs.ansible.com/ansible/devel/community/communication.html). # Contributing Please read [Contribution guidelines] if you wish to contribute. # Code of Conduct Please see the [Ansible Community Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html). # Licensing The ansible-lint project is distributed as [GPLv3] due to use of [GPLv3] runtime dependencies, like `ansible` and `yamllint`. For historical reasons, its own code-base remains licensed under a more liberal [MIT] license and any contributions made are accepted as being made under original [MIT] license. # Authors ansible-lint was created by [Will Thames] and is now maintained as part of the [Ansible] by [Red Hat] project. [ansible]: https://ansible.com [contribution guidelines]: https://ansible.readthedocs.io/projects/lint/contributing [gplv3]: https://github.com/ansible/ansible-lint/blob/main/COPYING [mit]: https://github.com/ansible/ansible-lint/blob/main/docs/licenses/LICENSE.mit.txt [red hat]: https://redhat.com [will thames]: https://github.com/willthames [ansible-lint-action]: https://ansible.readthedocs.io/projects/lint/installing/#installing-from-source-code ansible-ansible-lint-c16f018/action.yml000066400000000000000000000102551477347356000200630ustar00rootroot00000000000000--- name: run-ansible-lint description: Run Ansible Lint author: Ansible by Red Hat branding: icon: shield color: red inputs: args: description: Arguments to be passed to ansible-lint command. required: false default: "" setup_python: description: If false, this action will not setup python and will instead rely on the already installed python. required: false default: true working_directory: description: The directory where to run ansible-lint from. Default is `github.workspace`. required: false default: "" requirements_file: description: Path to the requirements YAML file to install role and collection dependencies. required: false default: "" expected_return_code: description: Expected return code from ansible-lint. Default is 0. Used for self-testing purposes. required: false default: "0" gh_action_ref: description: The branch, tag, or commit to use for ansible-lint. default: "" required: false runs: using: composite steps: - name: Process inputs id: inputs shell: bash run: | if [[ -n "${{ inputs.working_directory }}" ]]; then echo "working_directory=${{ inputs.working_directory }}" >> $GITHUB_OUTPUT else echo "working_directory=${{ github.workspace }}" >> $GITHUB_OUTPUT fi # If this action is imported as part of another composite action, the value of github.action_ref is the branch/commit/tag of the source action, not this one. # This allows a user to override it using the input variable - name: Determine github action ref shell: bash run: | action_ref="${{ inputs.gh_action_ref }}" if [[ -z "${{ inputs.gh_action_ref }}" ]]; then action_ref="${{ github.action_ref || 'main' }}" fi echo "ACTION_REF=${action_ref}" >> "$GITHUB_ENV" # Due to GHA limitation, caching works only for files within GITHUB_WORKSPACE # folder, so we are forced to stick this temporary file inside .git, so it # will not affect the linted repository. # https://github.com/actions/toolkit/issues/1035 # https://github.com/actions/setup-python/issues/361 - name: Generate .git/ansible-lint-requirements.txt id: get_reqs shell: bash env: GH_ACTION_REF: ${{ env.ACTION_REF }} working-directory: ${{ steps.inputs.outputs.working_directory }} run: | reqs_file=$(git rev-parse --show-toplevel)/.git/ansible-lint-requirements.txt echo "reqs_file=$reqs_file" >> $GITHUB_OUTPUT wget --output-document=$reqs_file https://raw.githubusercontent.com/ansible/ansible-lint/$GH_ACTION_REF/.config/requirements-lock.txt - name: Set up Python if: inputs.setup_python == 'true' uses: actions/setup-python@v5 with: cache: pip cache-dependency-path: ${{ steps.get_reqs.outputs.reqs_file }} python-version: "3.11" - name: Install ansible-lint shell: bash env: GH_ACTION_REF: ${{ env.ACTION_REF }} # We need to set the version manually because $GITHUB_ACTION_PATH is not # a git clone and setuptools-scm would not be able to determine the version. # git+https://github.com/ansible/ansible-lint@${{ github.action_ref || 'main' }} # SETUPTOOLS_SCM_PRETEND_VERSION=${{ github.action_ref || 'main' }} run: | cd $GITHUB_ACTION_PATH pip install "ansible-lint[lock] @ git+https://github.com/ansible/ansible-lint@$GH_ACTION_REF" ansible-lint --version - name: Install role and collection dependencies from requirements file if: inputs.requirements_file != '' shell: bash working-directory: ${{ steps.inputs.outputs.working_directory }} run: ansible-galaxy install -r ${{ inputs.requirements_file }} - name: Run ansible-lint shell: bash working-directory: ${{ steps.inputs.outputs.working_directory }} run: | exit_code=0 expected_exit_code=${{ inputs.expected_return_code }} ansible-lint ${{ inputs.args }} || exit_code=$? if [ "$exit_code" != "$expected_exit_code" ]; then echo "Command failed: got '$exit_code', expected '$expected_exit_code'"; exit 1; fi ansible-ansible-lint-c16f018/ansible.cfg000066400000000000000000000002451477347356000201570ustar00rootroot00000000000000[defaults] collections_path = collections:examples/playbooks/collections # to avoid accidental use of vault from user environment: vault_password_file = .vault_pass ansible-ansible-lint-c16f018/codecov.yml000066400000000000000000000001531477347356000202240ustar00rootroot00000000000000--- comment: false coverage: status: patch: true project: default: threshold: 0.5% ansible-ansible-lint-c16f018/collections/000077500000000000000000000000001477347356000203765ustar00rootroot00000000000000ansible-ansible-lint-c16f018/collections/ansible_collections/000077500000000000000000000000001477347356000244115ustar00rootroot00000000000000ansible-ansible-lint-c16f018/collections/ansible_collections/local/000077500000000000000000000000001477347356000255035ustar00rootroot00000000000000ansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/000077500000000000000000000000001477347356000305365ustar00rootroot00000000000000ansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/README.md000066400000000000000000000001171477347356000320140ustar00rootroot00000000000000# Ansible Collection - local.testcollection Documentation for the collection. ansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/galaxy.yml000066400000000000000000000001671477347356000325520ustar00rootroot00000000000000--- namespace: local name: testcollection version: 1.0.0 readme: README.md authors: - your name ansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/playbooks/000077500000000000000000000000001477347356000325415ustar00rootroot00000000000000ansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/playbooks/foo.yml000066400000000000000000000002531477347356000340470ustar00rootroot00000000000000--- - name: Fixture hosts: localhost connection: local gather_facts: false tasks: - name: Another task ansible.builtin.debug: msg: debug message ansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/playbooks/test/000077500000000000000000000000001477347356000335205ustar00rootroot00000000000000bar/000077500000000000000000000000001477347356000342055ustar00rootroot00000000000000ansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/playbooks/testfoo.yml000066400000000000000000000002531477347356000355130ustar00rootroot00000000000000ansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/playbooks/test/bar--- - name: Fixture hosts: localhost connection: local gather_facts: false tasks: - name: Another task ansible.builtin.debug: msg: debug message ansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/plugins/000077500000000000000000000000001477347356000322175ustar00rootroot00000000000000module_utils/000077500000000000000000000000001477347356000346455ustar00rootroot00000000000000ansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/plugins__init__.py000066400000000000000000000001441477347356000367550ustar00rootroot00000000000000ansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/plugins/module_utils"""module_utils package.""" # Some value that can be imported from a module MY_STRING: str = "foo" py.typed000066400000000000000000000000001477347356000363320ustar00rootroot00000000000000ansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/plugins/module_utilsansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/plugins/modules/000077500000000000000000000000001477347356000336675ustar00rootroot00000000000000__init__.py000066400000000000000000000000271477347356000357200ustar00rootroot00000000000000ansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/plugins/modules"""modules package.""" module_with_relative_import.py000066400000000000000000000007621477347356000417740ustar00rootroot00000000000000ansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/plugins/modules"""module_with_relative_import module.""" from ansible.module_utils.basic import AnsibleModule # pylint: disable=E0402 from ..module_utils import MY_STRING # noqa: TID252 # type: ignore[import-untyped] DOCUMENTATION = r""" options: name: required: True """ def main() -> AnsibleModule: """The main function.""" return AnsibleModule( argument_spec={ "name": {"required": True, "aliases": [MY_STRING]}, }, ) if __name__ == "__main__": main() ansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/roles/000077500000000000000000000000001477347356000316625ustar00rootroot00000000000000ansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/roles/bug4095/000077500000000000000000000000001477347356000327615ustar00rootroot00000000000000tasks/000077500000000000000000000000001477347356000340275ustar00rootroot00000000000000ansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/roles/bug4095main.yml000066400000000000000000000000001477347356000354640ustar00rootroot00000000000000ansible-ansible-lint-c16f018/collections/ansible_collections/local/testcollection/roles/bug4095/tasksansible-ansible-lint-c16f018/conftest.py000066400000000000000000000061541477347356000202650ustar00rootroot00000000000000"""PyTest Fixtures.""" import os import platform import subprocess import sys import warnings from importlib.util import find_spec from pathlib import Path import pytest # Ensure we always run from the root of the repository if Path.cwd() != Path(__file__).parent: os.chdir(Path(__file__).parent) # checking if user is running pytest without installing test dependencies: missing = [ module for module in ["ansible", "black", "mypy", "pylint"] if not find_spec(module) ] if missing: pytest.exit( reason=f"FATAL: Missing modules: {', '.join(missing)} -- probably you missed installing test requirements with: pip install -e '.[test]'", returncode=1, ) # See: https://github.com/pytest-dev/pytest/issues/1402#issuecomment-186299177 def pytest_configure(config: pytest.Config) -> None: """Ensure we run preparation only on master thread when running in parallel.""" if is_help_option_present(config): return if is_master(config): # linter should be able de detect and convert some deprecation warnings # into validation errors but during testing we disable this to avoid # unnecessary noise. Still, we might want to enable it for particular # tests, for testing our ability to detect deprecations. os.environ["ANSIBLE_DEPRECATION_WARNINGS"] = "False" # we need to be sure that we have the requirements installed as some tests # might depend on these. This approach is compatible with GHA caching. try: subprocess.check_output( # noqa: S603 ["./tools/install-reqs.sh"], stderr=subprocess.PIPE, text=True, ) except subprocess.CalledProcessError as exc: print(f"{exc}\n{exc.stderr}\n{exc.stdout}", file=sys.stderr) # noqa: T201 sys.exit(1) def is_help_option_present(config: pytest.Config) -> bool: """Return true if pytest invocation was not about running tests.""" return any(config.getoption(x) for x in ["--fixtures", "--help", "--collect-only"]) def is_master(config: pytest.Config) -> bool: """Return true if is run on master thread.""" return not hasattr(config, "workerinput") # ruff: noqa: E402 from ansible.module_utils.common.yaml import ( # pylint: disable=wrong-import-position HAS_LIBYAML, ) if not HAS_LIBYAML: # While presence of libyaml is not required for runtime, we keep this error # fatal here in order to be sure that we spot libyaml errors during testing. arch = platform.machine() if arch not in ("arm64", "x86_64"): warnings.warn( f"This architecture ({arch}) is not supported by libyaml, performance will be degraded.", category=pytest.PytestWarning, stacklevel=1, ) else: pytest.fail( "FATAL: For testing, we require pyyaml to be installed with its native extension, missing it would make testing 3x slower and risk missing essential bugs.", ) @pytest.fixture(name="project_path") def fixture_project_path() -> Path: """Fixture to linter root folder.""" return Path(__file__).resolve().parent ansible-ansible-lint-c16f018/cspell.config.yaml000066400000000000000000000010131477347356000214650ustar00rootroot00000000000000--- dictionaryDefinitions: - name: words path: .config/dictionary.txt addWords: true dictionaries: # Use `cspell-cli trace word` to check where a work is defined - en_US - bash - words - python - python-common enabled: true ignorePaths: - cspell.config.yaml # The requirements file - .config/constraints.txt - docs/requirements.txt - docs/requirements.in # Test fixtures generated from outside - test/**/*.result - src/ansiblelint/schemas/*.json # Other - "*.svg" - ".vscode/**" ansible-ansible-lint-c16f018/docs/000077500000000000000000000000001477347356000170105ustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/.gitignore000066400000000000000000000003211477347356000207740ustar00rootroot00000000000000# Old compiled python stuff *.py[co] # package building stuff build # Emacs backup files... *~ .\#* .doctrees # Generated docs stuff ansible*.xml .buildinfo objects.inv .doctrees *.min.css _build rst_warnings ansible-ansible-lint-c16f018/docs/.nojekyll000066400000000000000000000000001477347356000206260ustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/_autofix_rules.md000066400000000000000000000006561477347356000223710ustar00rootroot00000000000000- [command-instead-of-shell](rules/command-instead-of-shell.md) - [deprecated-local-action](rules/deprecated-local-action.md) - [fqcn](rules/fqcn.md) - [jinja](rules/jinja.md) - [key-order](rules/key-order.md) - [name](rules/name.md) - [no-free-form](rules/no-free-form.md) - [no-jinja-when](rules/no-jinja-when.md) - [no-log-password](rules/no-log-password.md) - [partial-become](rules/partial-become.md) - [yaml](rules/yaml.md) ansible-ansible-lint-c16f018/docs/_static/000077500000000000000000000000001477347356000204365ustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/_static/ansible-lint.svg000066400000000000000000000067261477347356000235530ustar00rootroot00000000000000 ansible-ansible-lint-c16f018/docs/_static/images/000077500000000000000000000000001477347356000217035ustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/_static/images/ansible-lint-512.png000066400000000000000000000320101477347356000252730ustar00rootroot00000000000000PNG  IHDRxiTXtXML:com.adobe.xmp HiCCPsRGB IEC61966-2.1(uKBA?0E-2 jb6z}j{A۠ jkQAmAPAEmJnjD0s93gN+~2ٜ{ pQtu" Ps|c1U Xl㊪儧k9% kRGjr&kmdGXIiay9L:c͊ՅN?^L3}7DR ȮR@c$)r􋚗q 2۽l=и -:21=ezoU486Ewb:Ո)IuB@Rg<@x]W?7{g]jj pHYs   IDATxy%U}/32 (-") D}I4Fq9Ohp 81C?{ϽUZgu;~zڵ $I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$i:V V{;; l8l7^$|[~|$-V5H"ɦ>}.̥֨AXg|%$p1p60sO* z-ɆtG̕I7۴p0"$Μ|Jr}]Di,$[OvǟSauϋ|H+IKĪ^H>pphԲ&| In(M&aP$M&9ݺE'9bмK&$eHmCυID[+Ci|,7I^ܻ8>sHrsq&@s.z_-ڦ8G^{Oq& 4gO_Zm?I06 D(#fK?|9d4'JJ;4[L&un,q@S1?KӲb$UpX4kI6>Fٶq;pbNfڤYhV<:4OΟfKr uJ?;_I͆&n'3I5֣{R`U VI{_csܫ:bJK+p6cI<6,Z)I,۠DRl|9ɞA V(c/Tg\g$ٿ:Jr$YGo}$GTQYL>Nv |"_TQYTI;HZGVQ?yrןH/fmuCIQDcL=n QRNJr  WmWg4U%ٺ: l lSEҜ흒@dMO]x@#tǼF0r!i^_ $w>İ/\, xb߄n?u b>d$WVQժFՀWg ӁXbċf$ɝc!xp8p\St[`<x{uYnS/$UqH#i\$f(}omҚ nԥM? K{VovM _L<:*:pS$/O[$e$MbН I !4,#d]-aH?fX4#In1ǿ^@/7}s>;eIv \QgE;Gh$$w_e9NOUm>VgY|fa^5TIHlhyasFHrwݿF$"͗$ۈk,Kq p$Ur`~^,⯱I5 .βkҝ34p ߗ}{w:T%ɆG,j`$Vq`]?_c7>xcu%l eu-g,ɚWgYIrKuOؾ)㸷Vp`؎_//$oα!( =:b.>r= :bQ@s[5Y\;`,t俪H}Y+{_dCL9CH-C9&a$kU:Ԣ$>U80׊/u'_[@[.Ê3hXJR&^Qo ` Owgw3TS4,ccTjJۀ)4en>VA$_,m Ouxz1ps0 I6)p&pz`%halZ80,k$P{9,[s0,}Ro/ ^(wؚ2 \8 ǖ? ޥplM` 49 31 @* 3R-g4cYh,4^ЌY"@iЌY 4^%8 @\ 31 @51 @\ 31 @51 @\ c{ q%U:fоHhv, T/ YA(Y4 {gh-\R=σPR=σPR=p*xi}pI<4>BI<4>BI8 @<%UG, TsO, TsO, TۏσPR|4>BI<4>BI}l}in+sO,l7- /8 @*k ǖT{ Zgh_AxmؒjA4> 4^Ǡ3{ @eЌY 4^ЌYg͘}-VeSؚ @.±%uࢢ+= @*$IduEܣ) MѸE:8 @Ÿ+鎪E @,H`ЌXWU~^4;*h}H f>HӢq-4,FHPu,nd5=pK ǖG}hѸ @+$7-i1In~Y4Ej ,JpP> KmG'٠hl͒]q%-w][ @*޾^8?UyLQ8fР$k/pnؒTe80څk,mآh Ɩt){#QEck,m??ͅKZ( 4f2NKTy$om wO?4d+c8 y??I$̀-/n/\V8eHr9tm[8Vn8RUJr ZIvK|s8VF'g|'7g8:N,m'zӓ8Hrpzq5WgJ\=s iX}BVYz,VtON* iLew&پ:¢eH,I \ ZnslTDKg请1ч)EI+/Nx!Rz(3SCHZ%U8xuu) @$x[uŜV^TX˒<:#I>Ue1 iF>P` K# @O$+-,激ӪCHZuIN;b=K@Xz ہIU4c\` [_IrPuY%98 4I!JZEIN;d$ۛlr|X:R<;CH xru%`,X :XILV[4'}SITdx$ϫβbr,m-&QX:X$Y xz`4/ ۻTY݁3$7WgA݀/VB40 fI3̡xZmrpbuIst<: 8!Y _hZ(5'ɺt[{7IrauIs#t%`,+i$?34)J9݂(^u!$ͭ$/^[c;[vtXfiak>In"inM^{,3tp Yf }.{Ǚ]:d{tR}"ɹaZcX$kѽg>[M~ع.=7;CH_H^c~ be/TF@/N~ E~ QUBRwݾܿ:Ȕ܃eZwt$`}ioy$dkc|_ɽc̃ՀJ`.ɥ!$ՙ:jX=CHxߪshY$W茤=2:q9xJ[H O;Gh$,qph"&C 8\?%V+8 ]Ewwſ+ \YEs0lA$#Et[k,k`$_"=ss0L{&FuI횜CE A$/π- 80UA$ G1 p UH$7'K;}_W\K]o΢ٱo ./nٱomIMb4璜 l<x)F\WM`Mx$UJ-bTkIc4?< |8'$Iu'y0ų`n# @R_%x$,)0k0Ln^l9c8?< @2>I-\3Z t7JjQ#1uA x=ߒԤmS8?<\L7pEuI$E$`;F} t# 89IÕHrNgwwqXe/cI֬"IӐ$v[+pAqfXPc4,I%91Ƀs3`8:$ͅ$N|:O_Y뭓4HIdpzqޱϗoѽr 6ޗğI$>}क़b+`n}^nꞛ!$I&v8lShnA$I0 =k>In"I)O X6*{iU$ Hr5S$:$iYP݁7нֲMr[uI9 !I.ūVI./_<>ߪ_o_ .\x Q㬅 ~p|W`><X8m< `.\讃ˀzQ8IVOtԯ6-4ҭ 0ɣôИ$W'Fh ز8I*4(Agԗ~hlnePz_7$:LKh^Ya#EcKe<;t`.L0-qQI>FX7hL{pHuis]'{ҼI?V^q4p~]]w\44/uVyvM }fhTk3w7@ V{g/ۤ-[xGOM6i,mtѸwKRNiN$9&,'L%XvrѸw+[I>E뜆W:H8ո$W ɗ ƕ*{ݶǻg3Cˢq]M"^t^:H5 @~U4vEJSd'Y4>?Ł9 $UEedyZgVAM߹:|-A*XgVR{u퀳'pT,ZpעqIt/9pJ}U3$GMHH4`, St;x tzmd`,꽻=0X8;גlN#UoPo%ٌWѪ8iYgd]iVgQ>2NڅcZ39aث:ws>g;'WJ̡E> 4948M{ui I5皶 @*hz!Z'p͝{1MUMK}qgu ޑI:ĴXWYrI_C$V @,$ΡQYxBr T-tKiG!f>g4JIZC$W @,$:FI1z=pT) @mL$+lSb&,s@d5Mc}!f> iCHK$,h : olI @\{!e/-)dǿUV%IyI}?zi3!V} Z-h褪{a+Y4 ϣ{ԂWX9q9U$kTX @,cJ-8:ĊXg MA:4C/"@Cgv!z`UX @;P}uiz=ţ}K#guiKuue±5lMh&STv>g4!͑́^= `h3 5t 5 ^IDAT,о)%g4MU#,>oyI6RCci}-M| إ:9y)cu k:56M3jilv!p Z׋oC<ϼ}3kwui9,[ޮ:4ϜTTaX:4d]]8@uRY @\[4VEj8*_`+u@uRX{EZ4[W@Sq-HE6` ƵhʿIE,uՊ08h*.n-w}Aj8XY4{Ih0X4VMMBC0lT@*bTxHƖVY45U±ն+RX45) ƪ[@S3ຢNEcm ,6fW4fXOu T8plRg4Ug}tUusu3SR] ծ+HE$80Sh6k<:)-8 ,CXtt?cM]uy`$_1qg_ehlU,C.j), ܧWXӁTP\T@gͭTX CHZ`TX lTD&ES@cQ|x$WѼ8Mui\Wbq,P$%ټ:N[,i;eEoXFfWQ'9sF`P'VǪ,To1K]0NL0$pH UIe[> VeJ.+G-CO!MSbIKm`װX!z kiiPC&9:Ē|zĒ\ρ/1 M>;.g_[V +sHKr3Ҕ|`мIrSnq$ NjoW:ĴJe,6(10I lVEt-$TO~$ѕ0OSaI?pFu " IN2M;IBs8$yp\u ˒:ĴyS%x$S SOΡA8>3C̅9f%MCtOM}6q,뎎x`u5,oCyI֢k`G`g3`g~!b@%+UOUu _O~kdW) s}$ V=UrEu5JC@%.p p]uc|:|H$_gY[Kr~ub4 I3S%9:|rQIp*nε|:|H$NǧWtGqIId; '`gA@(%)6*Uc@҈% xu͛:H5oHW "_W&:LX$i"t>!0, }bLp"kuM9\Zo꒤,\ l<(M{ex?MuLrbu>)IZ$g>TE+N^WIZ I l^EKu$Tik$i%,\ )@OaZ$$oDHu.^AZdJT8nYFˁ'YTUI$/_g^5ɍaZg)Hrg󀍊 ͍t 0_a ISd'M;%muHH!"p8 F}In3TICIx4w-ZfAy2y_[K'Au1H<  <8-88Rۊ@ %Yxpݭ-j͙ˁӀS%8Y$'N!>5KCmytS ܴ_,SI1I7E<7 $5"ɚXkbDޏ0'<)HR&tOlftV{k&%tpў$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I$I}&,IENDB`ansible-ansible-lint-c16f018/docs/_static/images/favicon.ico000066400000000000000000000360561477347356000240360ustar00rootroot00000000000000 h6  (00 h&(  mmmmmm}~~~AЀx|{{fmmm񁁁mmm Nff{{{{x||x~~~Azzz~~~A}}( @ ~~~q̀́q{{{Ӏ{{{]ʀӀӀ~~~qq~~~QTfff̀T瀀̀qp󀀀ӀҒfff{{{ӀҀZq̀ˀp\񀀀N'iZ񀀀NN񁁁[YZfff偁fff󀀀󀀀怀UT~~~QUffffffT~~~Q]ˀʁ](0` xxx>؁؀>xxx==P聁耀P 1ڀ=耀脄<xxxxxx>>~~~a0UUU΀|؀@ꀀatt؀{tz~~~w>}}}=v~~~wxxxsu=耀悂;ykP聁怀Nttt R=;zzz2耀|||)xxx>؀ր}}}= 2ـ退؀$cـ8zzzN؀ـ88ـ耀؀$$؀退 0׀ق1 }}}1耀|||)|||) zzz2ttt ~~~SRttt ykkysuusv~~~w~~~wvz~~~w~~~wz{tt{ttttaa?退ꀀ@΀~mmm|·~~~a1UUUUUU0~~~a 1ۀڀ1 ansible-ansible-lint-c16f018/docs/_static/images/logo_invert.png000066400000000000000000000102701477347356000247400ustar00rootroot00000000000000PNG  IHDR>aiTXtXML:com.adobe.xmp ?iCCPsRGB IEC61966-2.1(uKBA?0E-2 jb6z}j{A۠ jkQAmAPAEmJnjD0s93gN+~2ٜ{ pQtu" Ps|c1U Xl㊪儧k9% kRGjr&kmdGXIiay9L:c͊ՅN?^L3}7DR ȮR@c$)r􋚗q 2۽l=и -:21=ezoU486Ewb:Ո)IuB@Rg<@x]W?7{g]jj pHYs   IDATxmVE Z:ch Xi2$Čh 5PNfiiE38ًfehRB% :Ȉ=Ͻ^sv^{-d2L&d2L&d2L&d2L&oہ2H:8 FJzMsS/I[v% `H\o,ӁyI7JML\$)I〯co|S fIp?Gi?==DŽ'C @/ˀK_2Iv$ (A}} 9Fv@1_ c-b;U'wS 3:끗;TKT|p'xXҶkIC D/yn7 0i`x `g$ W| X| 0)@fs.z`0a8]aI-XI[x Zi>MZ1gpg?b Oyp[GB !|y5E*[b)ٗ(|'8LIz:?X09h&y&#xQ6sURY)>!e+dQZ!R^ I`$pz!eUKWS@RJ51Q檛Z!]_p+[ztC pyWb`wk6]/Cn+&D# -pz]!M>̋xlvuEZW0/OG`^@I7uo)#t p.A*'&z7".RB xwp`6|@DC_qj>_@A{^Q6 ,߷*+O.I_m~]/ q?v.*Jm&J&IylW*E]|+g ŀSXx'DHU1lg`vnHeQ=ߧ`fgVG43w h7X6LI$ (Î鈪&|KZۗJZ$e*pn Oa-b3V.c92=WkkԌLdђ͒4?4M8;O`$6ۄ>;Xgr_ÎPs fF7lBt/۱_//H)LKMKt4=.Pp*lԯ[sO# z^&QE@2)ZÞ3xQ1bA  VJzc0V{ʏ EH܅4`SˆZ,б/ʑ*4%6o%T/w+f->v\R?X܉b8-sN<b܀kF`^I1ie5a V S4{cݒZJZ :tiY%)fۏH-JZ2 Cc;Q1,:I~ù,:ը4eK ָS$>;m2F 1 hH ہ.?7'v R[ :df (A LzYF b ,RkZ!I<;*(5?˯B+PyaqI)69t ^D8}>Hm/O%}\:'`faq46@D{̆k%];(3EČjl'RI"n%'QZ74ߌ_5m jGJҎ|-VI3m,ʶ #`]J,On@ש1*b+'u2xS,)cxxl_Bҋ6pk᳗ˢؾ8X4!feXKp(H~3@˒.r LO|,M*wc3dГD~ttRG lN%-^NӰ5cuQ1f K> "XK4B)"ivjlK*jZJy+V<:uXwH*;萢;cXLGg %D$-NUJ`|*Aғ|,ڊ$zfU IG8Woa37HtM" &$ z0%OX%VfZ! a5`cX`0\73d2L&d2L,3J@IENDB`ansible-ansible-lint-c16f018/docs/_static/theme_overrides.css000066400000000000000000000011611477347356000243330ustar00rootroot00000000000000/* table width fix via: https://rackerlabs.github.io/docs-rackspace/tools/rtd-tables.html */ /* override table width restrictions */ @media screen and (min-width: 767px) { .wy-table-responsive table td { /* !important prevents the common CSS stylesheets from overriding * this as on RTD they are loaded after this stylesheet */ white-space: normal !important; } .wy-table-responsive { overflow: visible !important; } } .icon-home { display: none !important; } /* Avoid using the red text for tt blocks */ .rst-content code.literal, .rst-content tt.literal { color: #888888 !important; } ansible-ansible-lint-c16f018/docs/autofix.md000066400000000000000000000012071477347356000210110ustar00rootroot00000000000000# Autofix Ansible-lint autofix can fix or simplify fixing issues identified by that rule. `ansible-lint --fix` will reformat YAML files and run transform for the given rules. You can limit the effective rule transforms (the 'write_list') by passing a keywords 'all' or 'none' or a comma separated list of rule ids or rule tags. By default it will run all transforms (effectively `write_list: ["all"]`). You can disable running transforms by setting `write_list: ["none"]`. Or only enable a subset of rule transforms by listing rules/tags here. Following is the list of supported rules covered under autofix functionality. {!_autofix_rules.md!} ansible-ansible-lint-c16f018/docs/configuring.md000066400000000000000000000077761477347356000216650ustar00rootroot00000000000000# Configuration Customize how Ansible-lint runs against automation content to suit your needs. You can ignore certain rules, enable `opt-in` rules, and control various other settings. Ansible-lint loads configuration from a file in the current working directory or from a file that you specify in the command line. Any configuration option that is passed from the command line will override the one specified inside the configuration file. ## Using local configuration files Specify Ansible-lint configuration in either `.ansible-lint`, `.ansible-lint.yml`, `.ansible-lint.yaml`, `.config/ansible-lint.yml`, or `.config/ansible-lint.yaml` in your current working directory. !!! note If Ansible-lint cannot find a configuration file in the current directory it attempts to locate it in a parent directory. However Ansible-lint does not try to load configuration that is outside the git repository. ## Specifying configuration files Use the `-c ` CLI flag with command line invocations of Ansible-lint, for example: ```bash ansible-lint -c path/to/ansible-lint-dev.yml ``` ## Ansible-lint configuration The following values are supported, and function identically to their CLI counterparts: ```yaml {!../.ansible-lint!} ``` ## Ignoring rules for entire files Ansible-lint will load skip rules from an `.ansible-lint-ignore` or `.config/ansible-lint-ignore.txt` file that should reside adjacent to the config file. The file format is very simple, containing the filename and the rule to be ignored. It also supports comments starting with `#`. ```yaml title=".ansible-lint-ignore" # this is just a comment playbook.yml package-latest # disable package-latest rule for playbook.yml playbook.yml deprecated-module ``` The file can also be created by adding `--generate-ignore` to the command line. Keep in mind that this will override any existing file content. ## Pre-commit setup To use Ansible-lint with the [pre-commit] tool, add the following to the `.pre-commit-config.yaml` file in your local repository. Do not confuse the [pre-commit] tool with the git hook feature that has the same name. While the [pre-commit] tool can also make use of git hooks, it does not require them and it does not install them by default. [pre-commit.ci] is a hosted service that can run pre-commit for you on each change but you can also run the tool yourself using the CI of your choice. Change **rev:** to either a commit sha or tag of Ansible-lint that contains `.pre-commit-hooks.yaml`. ```yaml --- ci: # This section is specific to pre-commit.ci, telling it to create a pull request # to update the linter version tag every month. autoupdate_schedule: monthly # If you have other Ansible collection dependencies (requirements.yml) # `pre-commit.ci` will not be able to install them because it runs in offline mode, # and you will need to tell it to skip the hook. # skip: # - ansible-lint repos: - repo: https://github.com/ansible/ansible-lint rev: ... # put latest release tag from https://github.com/ansible/ansible-lint/releases/ hooks: - id: ansible-lint # Uncomment if you need the full Ansible community bundle instead of ansible-core: # additional_dependencies: # - ansible ``` !!! warning [pre-commit] always uses python virtual environments. If you happen to use the [Ansible package] instead of just [ansible-core] you might be surprised to see that pre-commit is not able to find these collections, even if your local Ansible does. This is because they are installed inside a location that is not available to the virtual environment in which pre-commit hook is installed. In this case, you might want to uncomment the commented lines from the hook definition above, so the bundle will be installed. You should note that collection installed into `~/.ansible` are found by the hook. [pre-commit]: https://pre-commit.com/ [Ansible package]: https://pypi.org/project/ansible/ [ansible-core]: https://pypi.org/project/ansible-core/ [pre-commit.ci]: https://pre-commit.ci/ ansible-ansible-lint-c16f018/docs/contributing.md000066400000000000000000000124501477347356000220430ustar00rootroot00000000000000# Contributing to Ansible-lint To contribute to ansible-lint, please use pull requests on a branch of your own fork. After [creating your fork on GitHub], you can do: ```shell-session $ git clone --recursive git@github.com:your-name/ansible-lint $ cd ansible-lint $ # Recommended: Initialize and activate a Python virtual environment $ pip install --upgrade pip $ pip install -e '.[test]' # Install testing dependencies $ tox run -e lint,pkg,docs,py # Ensure subset of tox tests work in clean checkout $ git checkout -b your-branch-name # DO SOME CODING HERE $ tox run -e lint,pkg,docs,py # Ensure subset of tox tests work with your changes $ git add your new files $ git commit -v $ git push origin your-branch-name ``` You will then be able to create a pull request from your commit. All fixes to core functionality (i.e. anything except docs or examples) should be accompanied by tests that fail prior to your change and succeed afterwards. Feel free to raise issues in the repo if you feel unable to contribute a code fix. ## Standards ansible-lint works only with supported Ansible versions at the time it was released. Automated tests will be run against all PRs, to run checks locally before pushing commits, just use [tox](https://tox.wiki/en/latest/). ## Talk to us Connect with the Ansible community! Join the Ansible forum to ask questions, get help, and interact with the community. - [Get Help](https://forum.ansible.com/c/help/6): get help or help others. Please add appropriate tags if you start new discussions, for example use the `ansible-lint` or `devtools` tags. - [Social Spaces](https://forum.ansible.com/c/chat/4): meet and interact with fellow enthusiasts. - [News & Announcements](https://forum.ansible.com/c/news/5): track project-wide announcements including social events. To get release announcements and important changes from the community, see the [Bullhorn newsletter](https://docs.ansible.com/ansible/devel/community/communication.html#the-bullhorn). For a live chat experience join the [#devtools:ansible.com](https://matrix.to/#/#devtools:ansible.com) Matrix room. You can find more information in the [Ansible communication guide](https://docs.ansible.com/ansible/devel/community/communication.html). Possible security bugs should be reported via email to . ## Code of Conduct As with all Ansible projects, we have a [Code of Conduct]. [ansible communication]: https://docs.ansible.com/ansible/latest/community/communication.html [code of conduct]: https://docs.ansible.com/ansible/latest/community/code_of_conduct.html [creating your fork on github]: https://docs.github.com/en/get-started/quickstart/contributing-to-projects [discussions]: https://github.com/ansible/ansible-lint/discussions [supported ansible versions]: https://docs.ansible.com/ansible-core/devel/reference_appendices/release_and_maintenance.html#ansible-core-release-cycle [tox]: https://tox.readthedocs.io ## Module dependency graph Extra care should be taken when considering adding any dependency. Removing most dependencies on Ansible internals is desired as these can change without any warning. ```bash exec="1" source="console" uv pip tree --package ansible-lint --show-version-specifiers --strict ``` ## Adding a new rule Writing a new rule is as easy as adding a single new rule, one that combines **implementation, testing and documentation**. One good example is [MetaTagValidRule] which can easily be copied in order to create a new rule by following the steps below: - Use a short but clear class name, which must match the filename - Pick an unused `id`, the first number is used to determine rule section. Look at [rules](rules/index.md) page and pick one that matches the best your new rule and ee which one fits best. - Include `experimental` tag. Any new rule must stay as experimental for at least two weeks until this tag is removed in next major release. - Update all class level variables. - Implement linting methods needed by your rule, these are those starting with **match** prefix. Implement only those you need. For the moment you will need to look at how similar rules were implemented to figure out what to do. - Update the tests. It must have at least one test and likely also a negative match one. - If the rule is task specific, it may be best to include a test to verify its use inside blocks as well. - Optionally run only the rule specific tests with a command like: `tox -e py -- -k NewRule` - Run `tox` in order to run all ansible-lint tests. Adding a new rule can break some other tests. Update them if needed. - Run `ansible-lint -L` and check that the rule description renders correctly. - Build the docs using `tox -e docs` and check that the new rule is displayed correctly in them. [metatagvalidrule]: https://github.com/ansible/ansible-lint/blob/main/src/ansiblelint/rules/meta_no_tags.py ## Documentation changes To build the docs, run `tox -e docs`. At the end of the build, you will see the local location of your built docs. Building docs locally may not be identical to CI/CD builds. We recommend you to create a draft PR and check the RTD PR preview page too. If you do not want to learn the reStructuredText format, you can also [file an issue](https://github.com/ansible/ansible-lint/issues), and let us know how we can improve our documentation. ansible-ansible-lint-c16f018/docs/custom-rules.md000066400000000000000000000057331477347356000220040ustar00rootroot00000000000000# Custom linting rules Define and use your own sets of rules with Ansible-lint. ## Rule definitions You define each custom rule in a unique Python class file. Default rules are named _DeprecatedVariableRule.py_, etc. Each rule should have a short description as a Python docstring wrapped in triple quotes `"""` immediately after the class name. The short description should be brief and meaningfully explain the purpose of the rule to users. Each rule definition should have the following parts: - `id` provides a unique identifier to the rule. - `description` explains what the rule checks for. - `tags` specifies one or more tags for including or excluding the rule. ### Match and matchtask methods Each rule definition should also invoke one of the following methods: - `match` takes a line and returns: - None or False if the line does not match the test. - True or a custom message if the line does match the test. (This allows one rule to test multiple behaviors - see e.g. the _CommandsInsteadOfModulesRule_.) - `matchtask` operates on a single task or handler, such that tasks get standardized to always contain a _module_ key and _module_arguments_ key. Other common task modifiers, such as _when_, _with_items_, etc., are also available as keys if present in the task. The following is an example rule that uses the `match` method: ```python from typing import Union from ansiblelint.rules import AnsibleLintRule class DeprecatedVariableRule(AnsibleLintRule): """Deprecated variable declarations.""" id = 'EXAMPLE002' description = 'Check for lines that have old style ${var} ' + \ 'declarations' tags = ['deprecations'] def match(self, line: str) -> Union[bool, str]: return '${' in line ``` The following is an example rule that uses the `matchtask` method: ```python {!../examples/rules/task_has_tag.py!} ``` The task argument to `matchtask` contains a number of keys - the critical one is _action_. The value of `task['action']` contains the module being used, and the arguments passed, both as key-value pairs and a list of other arguments (e.g. the command used with shell). ## Packaging custom rules Ansible-lint automatically loads and enables custom rules in Python packages from the _custom_ subdirectory. This subdirectory is part of the Ansible-lint installation directory, for example: `/usr/lib/python3.8/site-packages/ansiblelint/rules/custom/` To automatically load custom rules, do the following: 1. Package your custom rules as a Python package with a descriptive name. 2. Configure the \[options\] section of the `setup.cfg` of your custom rules Python package as in the following example: ```yaml [options] packages = ansiblelint.rules.custom. package_dir = ansiblelint.rules.custom. = ``` 3. Install the Python package into `/custom//`. ansible-ansible-lint-c16f018/docs/google04e29a42ae6e6cbc.html000066400000000000000000000000661477347356000234460ustar00rootroot00000000000000google-site-verification: google04e29a42ae6e6cbc.html ansible-ansible-lint-c16f018/docs/images/000077500000000000000000000000001477347356000202555ustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/images/favicon.ico000066400000000000000000000360561477347356000224100ustar00rootroot00000000000000 h6  (00 h&(  0ؓؔ0 0ӛx~0G ܭ̊ؓK$ԝ"ؓr\dߴIKؓ՞4ؔ4՞u00Rˇ 0ؓؔ0( @ Xȓ꒐ꔑȔX%% $ϓϕ$0瓑畕0$瓑畕$ ϓϙ %r۬dj%/3ѕ٧ҘJXY 4Xd\tȓʄ͌ˈ2ȓꓑCTє՟꒐ܰ* 6Fܯdꓑe`ꔑȓq4 Ȕ3ӛ̊XԜҘ$X4xߵK%^% u ϓRӚϙ $瓑畕$0瓑畕0$ϓϕ$ %%Xȓ꒐ꔑȔX(0` #H֒ꓑꔑ֓H#1rᓑᓒr1 ⓑⓑ m퓑퓑m;;`哑啒`jjj듑땓j``;哑哓;mm 퓑Aګۭ֠1 J۬ 헏 &~q1ⓑ Ԝ۫^⒒1rUB2 rاVД #ᓑv# ɀMᒒ#HˈіH͋6ߴע8i0ZO{h֓۬՞aR~֓ꓑe٨>H,ꓑ!і͍ף ϐy \ꓑ)ВZꔑ֓ؤȀ֓>;;إѕHu.5H#ᓑ0Bqݱᒒ#إا߶kr:Z%r1ⓑҘ⒒1T. 퓑۫헏 mʅDm:;哑:j)哓;``j듑땓jjja哑啒`;;m퓑퓑m ⓑⓑ 1rᓑᓒr1#H֓ꓑꔑ֓H#ansible-ansible-lint-c16f018/docs/images/logo.png000066400000000000000000000253611477347356000217320ustar00rootroot00000000000000PNG  IHDR\rfiTXtXML:com.adobe.xmp devtools-logos-all _[>iCCPsRGB IEC61966-2.1(u+DQ?3CbF %Mcf/5oHU/`"ReMlsI=존U}frzp/jH n#T;jUcqC[9I՜fpĄO\Pң~8Y/Pp ®dGXI骰^Q^gfeu ~\L13,~|ʎ }3d%WGg$)rxE]qYe[W#1+Tw4ߺf 7M4R~E,i}hZ˒݁ x"zWrȴ'z ahBϊChM v[⛖~=gP6: pHYs.#.#x?v IDATxyxUսoFSHʔ@H VDPT(ZE"}߶;]۷>VAbLb:V<d&@H2s{sGp[I~,6.vh ',4j'Ie u5Lxb$ʁ8`# @.9Xxxآ;h' R L9x Ψ`qTw0H@,c Us4Q خ;h" T]LU5KLc`$X`gxݡ'0tdcq:-C Rw A$ >gh`bOՆIcFfc'1 I߯;98@t`It@h'pn4tC|& g߽kj݁-ewNEkjbu&p/9(eED8tM3ǁ'5"2ځLNgoEĄñX8e_ EĔ$Lc@T C~Jb 6eg eǞ+wb eEĕdLS݁ oшt࿢ :eSG^4$\ї,#*ξ}!}`Ԥ| #FHj"0ëƽI]'mgfrWb7 #a>`ىI9gqmVp蘚ʷngB^?)HDhNRJm.o)\@RܯNMJ" ~ewV٠#@Qn>(3]q2gk7AQfeؑq9y)&Xvğ|=w*&+ 8JLGJv5M 튰 Uѐ`݁_EHQ!)Mlq+/TU 5Hrb"{hFRь 犻`IΝ}sѡggi=/B}"OΪ$y@~ 6 0~fh`  ܙQ={z~+vl9%"}31Ȼ{f*\d$\/F,{8pchv*`$}m$ot toA>mlE]O(>~-\LxKK O݊e_"ȷ ߇GI}3`مHy@XN&c<$P#]ҘOoӛ Y  GCO'̀.** ; \yX8# &"Dfd/vΐnA rݽU9:q[N62-e9Xo#g+XT;Se20LIJ- Tmu;sJK9W;;vWӛ~? :&d@u'ٍ&( t,`WшȨtl>~ş~U5e@`ӗhnp[ '4ۧ};no:N͝\]K۶LQp"\Knm7#EDJъ ^_cO+ R& 9d :9:qk%s65?;֍ݻjC(1D#¡jqM(:55v2d.ToiC/V&{nFWWd*X,\oKۿ;\]MRߑl Q1>VQm"zm²? F6x0_<5WtUSdcN'[w[m WnNGi 46id0?[n{r }qd(*@q㦈Gud!pA,;hD @;KiU|{9 r~~7uJd_`$3TMml163uO{"?#u;sJ7Sr^gl:PƦc&SZW.jcHn\}I31IA6$%~8wy[nAD#"(Xv: G@Jb"nXE M5b*Gծv^T8'Ç]6) @@:KTL$Mqf&}YQVq]ky3*+]7cn*"" h=evd2PIA15?~҇B}zIhPRU15u;/z6?ᓃ_j#1! cى@o@hjT<|P/ 蕈 G2aYYVƆN56wVN;窍LEǝ$" Si^RdY`۷~}]_c*\ս#EX:J쑢BRݟ'Wfc,?pu;KwtJNLb53~O5"$ @;ңC{,+cѣ "+۶sl6Ғ"B& @'U+v,GsUU%ퟑ'&2Cb2֜>?Hނ|φSRwX~;bbˎ+Wm8H!_{wߩTp\ ]Pa!md$l.2_5gOL{Y7P]n:4@QUCիcO)Sxg̔cļTiiLu$%Q5T* Ε?SiAċ }MyeOܹfJ/JN"$&$0=3òfdnTH˸t |k4޿Nw7=36rUi<(" /AJNLF1KNn 8p ݹu;HC^F:7<~鞴t/IÌ@dfIܖwwagyvd'$x--9i(ikhF6q8װJU jܖ9" kSTq7pm.aCyqdi6lĄ S# kl@ py&6*{3.7Փ'QCgyH% KCwWR|u5mXmxbƛ<9y鬚4Az|ۄ/Kkus %UoɗMl}cN['\));'AKcc@$xnZD+=~s֮JՔ]M޻NZb2,w&ETrݮr۳ş9YYo_~sc:ݻG\EUQ`"Yw&u}>aSH{kjʏ;9^ɵ١&⢈[㞂|O)D`஠h`l>Mw_Bu5m ΂۸vBv)X|Ӕ6II5٣GE4#b2P(q؛iTzQ&ܵg΄/e,Bos.*dل,+SifWWFFuԮ(ө権k?:X\I,Mڽ;kNƞm-~Z( +fp |?½JITPwӮj]柗-g{{vph״4޿.?bf%2$$%);ٍ]֬¦R_ O;~;b8sǎ}JJ?_^Y\GByJpWCceYv뛜ߟU&bA$jH;Tb䢿0ãċ33tds:ĚC\_Ow(V/IdA+Wt5YJRb9UU*޸/mޢd3g-Ā$SS _I[mHɿ,?p!s)7綜>2&9?]7sRh2j$&L+fuM (kSn"ٻ/=U'25$ RNh2HK@=9̳.pG+<}KN楱7_`kGq'uQ?Amt^gd(iɿP<3nyuUx5䟿y9pk^qںL𡆀o2E5zo^7GN°,gk-[9~vg ! GK}&Ё;*i7>EG'˹fBm(@YL/.6޽D `D%E$)X_y5ϟg›o?>ij⣩II<5F=ֵ\~gImn^d"(cjfoo>?rgGݐQ@M@tܘLUÊ nh)']QrU[MF 4= (*УE]¦R*=*鷺7>%ir~>}N|Q0QK7xM~"ϊFbrK 5dwײ۷~}lpQNKϋ#?#ѽz@9zs|0J:>?#'& 91GՔ>ZQ+ۼe~ }s1#bH}OݑK해5gSi&ʼuU>jZNƁ\&X)>am1/6X(7qt̨=JWV{4#K/Y~q?վz0-'*F3:eRL.pw=->#( hPr2}J  Ts,غMI[ɵqko( bTH}60$L@ݫp)鋥ݳz[|)qR2L('=/>ؽt(|mmU8+[~EmR㲃l8*RW|竼+>Z_eTN_ I 4/EPTRzL[V߿殿)ֹ&+KFL]0>*uUXRĹsd^߱a-> pMvkTC}4`Ea' \4[8YAGvYۚ-4:`!-OD𞨑ug):6՚p~ࣰf 4o(1.7>_őyb%SYت[g)1;  leVxlJǑPD}2`+"zoKO>U^Y-2?ayJn\NٙT*VLcT$8 =BDC+u3;rMǎ@qM#j,{&;%m !B1FԹ`-D!uXU83rީbhLLc5H@ᝧTu~P?bAq)61JB!8HWxЮ#<̈́eT)+D|`T7@IBğW {` 4gzz!b`0qҫ x96IBBT L 4:BĖOy#ʉ B94n߲3pr}iByB4<0ٯ~&v|*7ఁ5\W {//geFk>08RJm1ߧ(LCGa[DzzlF-] t"b;uc!/`,P;!|R! 4>|g1/tAI!pP;!0RƞHDWjMކ2p-nD_j ' RcPS FT}=ͱ!|ڰ;zN*:G9EEč8C,$+9>.r N%g#Y8r Pi0X;bcP3,M.Y3䏩rK ܨz{Yv ζCQ#`&Nw ^@}?aш; L0ϲ;Oovњ)gq%>;e_s[  pN癉ib)?0`&pBs4B8Cs'5P^~mTPDz~32r݁A|4@\S|hzKqmc?np- Lc@H@k,{0S`<-jpvLw0A&PYv!`*A453$xŲӀ;qFcpUq:Y$I~,j_z 2C_oa5$Ͳ|.&@֘9ٗԾ`5zC/ts Jn vʁ^Ʋq 꽢 \Xi\h@@N4Lu|*-445$ 9pAC8/Sat2n< |IENDB`ansible-ansible-lint-c16f018/docs/images/logo.svg000066400000000000000000000020271477347356000217370ustar00rootroot00000000000000 ansible-ansible-lint-c16f018/docs/index.md000066400000000000000000000026061477347356000204450ustar00rootroot00000000000000# Ansible Lint Documentation ## About Ansible Lint Ansible Lint is a command-line tool for linting **playbooks, roles and collections** aimed toward any Ansible users. Its main goal is to promote proven practices, patterns and behaviors while avoiding common pitfalls that can easily lead to bugs or make code harder to maintain. Ansible lint is also supposed to help users upgrade their code to work with newer versions of Ansible. Due to this reason we recommend using it with the newest version of Ansible, even if the version used in production may be older. As any other linter, it is opinionated. Still, its rules are the result of community contributions and they can always be disabled based individually or by category by each user. [Ansible Galaxy project](https://github.com/ansible/galaxy/) makes use of this linter to compute quality scores for [Galaxy Hub](https://galaxy.ansible.com/) contributed content. This does not mean this tool only targets those that want to share their code. Files like `galaxy.yml`, or sections like `galaxy_info` inside `meta.yml` help with documentation and maintenance, even for unpublished roles or collections. The project was originally started by [@willthames](https://github.com/willthames/) and has since been adopted by the Ansible Community team. Its development is purely community driven while keeping permanent communications with other Ansible teams. ansible-ansible-lint-c16f018/docs/installing.md000066400000000000000000000140561477347356000215040ustar00rootroot00000000000000--- # YAML header render_macros: true --- # Installing Install Ansible-lint to apply rules and follow best practices with your automation content. !!! note Ansible-lint does not currently support installation on Windows systems. !!! warning Ansible-lint does not support any installation methods that are not mentioned in this document. Before raising any bugs related to installation, review all of the following details: - You should use the installation methods outlined in this document only. - You should upgrade the Python installer (`pip` or `pipx`) to the latest version available from pypi.org. If you use a system package manager, you will need to upgrade the installer to a newer version. - If you are installing from a git zip archive, which is not supported but should work, ensure you use the main branch and the latest version of pip and setuptools. - If you are installing Ansible-lint within a container or system package, you should not report the issue here. Contact the relevant container or package provider instead. - If you are using [poetry](https://python-poetry.org/), read this [discussion](https://github.com/ansible/ansible-lint/discussions/2820#discussioncomment-4400380). Pull requests to improve installation instructions are welcome. Any new issues related to the installation will be closed and locked. For a container image, we recommend using [creator-ee](https://github.com/ansible/creator-ee/) which includes `ansible-dev-tools` (it combines critical Ansible development packages into a unified Python package). If you have a use case that the `creator-ee` container doesn't satisfy, please contact the team through the [discussion](https://github.com/ansible/ansible-lint/discussions) forum. You can also run Ansible-lint on your source code with the [Ansible-lint GitHub action](https://github.com/marketplace/actions/run-ansible-lint) instead of installing it directly. ## Installing the latest version {{ install_from_adt("ansible-lint") }} You can install the most recent version of Ansible-lint with the [pip3] or [pipx] Python package manager. Use [pipx] to isolate Ansible-lint from your current Python environment as an alternative to creating a virtual environment. ```bash # This also installs ansible-core if it is not already installed pip3 install ansible-lint ``` !!! note If you want to install the exact versions of all dependencies that were used to test a specific version of ansible-lint, you can add `lock` extra. This will only work with Python 3.10 or newer. Do this only inside a virtual environment. ```bash pip3 install "ansible-lint[lock]" ``` ## Installing on Fedora and RHEL You can install Ansible-lint on Fedora, or Red Hat Enterprise Linux (RHEL) with the `dnf` package manager. ```bash dnf install ansible-lint ``` !!! note On RHEL, `ansible-lint` package is part of "Red Hat Ansible Automation Platform" subscription, which needs to be activated. ## Installing from source code **Note**: `pip>=22.3.1` is required for installation from the source repository. Please consult the [PyPA User Guide] to learn more about managing Pip versions. ```bash pip3 install git+https://github.com/ansible/ansible-lint ``` [installing_from_source]: https://pypi.org/project/pip/ [pip3]: https://pypi.org/project/pip/ [pipx]: https://pypa.github.io/pipx/ [pypa user guide]: https://packaging.python.org/en/latest/tutorials/installing-packages/#ensure-pip-setuptools-and-wheel-are-up-to-date ## Installing Ansible Lint as a GitHub Action To use the action simply create a file `.github/workflows/ansible-lint.yml` with content similar to the example below: ```yaml # .github/workflows/ansible-lint.yml name: ansible-lint on: pull_request: branches: ["stable", "release/v*"] jobs: build: name: Ansible Lint # Naming the build is important to use it as a status check runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - name: Run ansible-lint uses: ansible/ansible-lint@main # optional (see below): with: args: "" setup_python: "true" working_directory: "" requirements_file: "" ``` All the arguments are optional and most users should not need them: - `args`: Arguments to be passed to ansible-lint command. - `setup_python`: If python should be installed. Default is `true`. - `working_directory`: The directory where to run ansible-lint from. Default is `github.workspace`. That might be needed if you want to lint only a subset of your repository. - `requirements_file`: Path to the requirements.yml file to install role and collection dependencies. Due to limitations on how GitHub Actions are processing arguments, we do not plan to provide extra options. You will have to make use of [ansible-lint own configuration file](https://ansible.readthedocs.io/projects/lint/configuring/) to alter its behavior. To also enable [dependabot][dependabot] automatic updates, the newer versions of ansible-lint action you should create a file similar to [.github/dependabot.yml][.github/dependabot.yml] [dependabot]: https://docs.github.com/en/code-security/dependabot [.github/dependabot.yml]: https://github.com/ansible/ansible-lint/blob/main/.github/dependabot.yml#L13-L19 ### Installing roles and collections from private repositories To install roles and collections from private repositories, you can: 1. Create an [access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#about-personal-access-tokens) 1. Add the token as an [deploy secret](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-a-repository) 1. Add the following step before the ansible-lint step. ```yaml - name: Prepare Git for Github shell: bash run: | git config --global url."https://${{ secrets.ANSIBLE_LINT_TOKEN }}@github.com".insteadOf "https://github.com" ``` ansible-ansible-lint-c16f018/docs/licenses/000077500000000000000000000000001477347356000206155ustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/licenses/LICENSE.mit.txt000066400000000000000000000021371477347356000232330ustar00rootroot00000000000000Copyright (c) 2013-2018 Will Thames Copyright (c) 2018 Ansible by Red Hat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ansible-ansible-lint-c16f018/docs/philosophy.md000066400000000000000000000123371477347356000215360ustar00rootroot00000000000000# Philosophy of ansible-lint Ansible **playbooks, roles, and collections** should read like documentation, be production ready, unambiguous, and provide consistent results. `Ansible-lint` should be considered a trusted advisor, helping ansible content creators write and package high-quality Ansible content. While not all rules may be applicable in all situations, they should be followed whenever possible. The goal of `ansible-lint` is to ensure that content created by different people has a similar look and feel. This makes the adoption and use of Ansible content easier in the community and enterprise. By keeping the number of configurable features at a minimum, consistent outcomes between authors can be achieved. ## History and the future `ansible-lint` is almost a decade old, and its current list of rules is the result of a collaboration between many people. The tool originated as a community project and is currently part of the Ansible Galaxy submission and validation process. In the future, it will be an official component of the Red Hat Ansible Automation Platform, used during the collections certification process and the recommended Ansible content linter for Red Hat customers. Starting in 2022, additional rules will be added that help content creators ready their content for production use. It will be through the use of ansible-lint and these rules, developers can have confidence their playbooks, roles, and task files are easy to understand and produce consistent results when run against anything, from servers in a home lab to mission-critical systems in the cloud. ## Style and formatting The focus of Ansible content creators should be on automation, outcomes and readability, rather than style or formatting. This is why we follow the same concepts as other code formatting tools like [black](https://github.com/psf/black) and [prettier](https://prettier.io/). Adoption of `ansible-lint` will save time by keeping reviews focused on the quality of the content and less so on the nuances of formatting and style. As code formatting is not an art, we can save your project time and effort by applying a standardized code style and formatting. ## Q&A ### Why does ansible-lint not accept all valid ansible syntax? `ansible-core` continues to mature while maintaining backward compatibility with early versions. `ansible-lint` has never intended to support the whole historical Ansible language syntax variations, but instead only the best of it. It supports a broad vocabulary of keywords and styles. Over time, changes in the language have led to an improved experience for authors and consumers of Ansible content. The rules in `ansible-lint` suggest the use of these patterns. It is these usage patterns that are written as rules in `ansible-lint`, leading to improved readability of **playbooks, roles**, and **collections**. The linter will always be more restrictive and opinionated regarding what it accepts. It is part of its design. We are not forced to keep the same backward compatibility level as Ansible, so we can tell people to avoid specific syntax for various reasons, such as being deprecated, unsafe, or hard to maintain. Based on the extensive history of `ansible-lint` and user feedback, it notifies you about discouraged practices, sometimes before `ansible-core` starts doing so. ### What if I do not agree with a specific rule? We recognize that some projects will find at least one rule that might not suit their needs. Use the `skip_list` feature to temporarily bypass that rule until you have time to update your Ansible content. ### Who decides which best practices get adopted in ansible-lint? The main source of new ideas was and remains our community. Before proposing a change, check with a few other Ansible users that work on different projects and see if they find it useful or not. It is better to get enough relevant feedback on our discussion forum before starting to implement new rules. If the proposed rule appears popular and does not conflict with existing rules, a core (maintainer) will tell you that the proposed rule can be added to ansible-lint, so you can start working on it without fear of rejection. The core team will decide on how a new rule will be added. Usually, they are added as experimental (warnings only) or even as opt-ins, being made implicit only when a major version is released. ### Do I need to pass all rules to get my collection certified? Not really. The certification process is likely to use only a subset of rules. At this time, we are working on building that list. ### Why do many official Ansible docs examples fail to pass linting? Most of the official examples are written to exemplify specific features, and some might conflict with our rules. Still, we plan to include linting of official examples in the future and add specific exclusions where needed, making it more likely that a copy/paste from the docs will not raise a bunch of linter violations. ### Why does ansible-lint require an Ansible version newer than what I use in production? Use `ansible-lint` as a **static analysis** tool for your content. You can run it with a version of ansible that is different than what you use in production. This helps you prepare your content for the future, so don't be afraid of using it in such a way. ansible-ansible-lint-c16f018/docs/pkg/000077500000000000000000000000001477347356000175715ustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/pkg/.gitignore000066400000000000000000000000161477347356000215560ustar00rootroot00000000000000* !.gitignore ansible-ansible-lint-c16f018/docs/profiles.md000066400000000000000000000104451477347356000211610ustar00rootroot00000000000000 # Profiles Ansible-lint profiles gradually increase the strictness of rules as your Ansible content lifecycle matures. To configure linter to use a specific profile, read [applying-profiles][]. !!! note Rules with `*` in the suffix are not yet implemented but are documented with linked GitHub issues. ## min The `min` profile ensures that Ansible can load content. Rules in this profile are mandatory because they prevent fatal errors. You can add files to the exclude list or provide dependencies to load the correct files. - [internal-error](rules/internal-error.md) - [load-failure](rules/load-failure.md) - [parser-error](rules/parser-error.md) - [syntax-check](rules/syntax-check.md) ## basic The `basic` profile prevents common coding issues and enforces standard styles and formatting. It extends [min](#min) profile. - [command-instead-of-module](rules/command-instead-of-module.md) - [command-instead-of-shell](rules/command-instead-of-shell.md) - [deprecated-bare-vars](rules/deprecated-bare-vars.md) - [deprecated-local-action](rules/deprecated-local-action.md) - [deprecated-module](rules/deprecated-module.md) - [inline-env-var](rules/inline-env-var.md) - [key-order](rules/key-order.md) - [literal-compare](rules/literal-compare.md) - [jinja](rules/jinja.md) - [no-free-form](https://github.com/ansible/ansible-lint/issues/2117) - [no-jinja-when](rules/no-jinja-when.md) - [no-tabs](rules/no-tabs.md) - [partial-become](rules/partial-become.md) - [playbook-extension](rules/playbook-extension.md) - [role-name](rules/role-name.md) - [schema](rules/schema.md) - [name](rules/name.md) - [var-naming](rules/var-naming.md) - [yaml](rules/yaml.md) ## moderate The `moderate` profile ensures that content adheres to best practices for making content easier to read and maintain. It extends [basic](#basic) profile. - [name[template]](rules/name.md) - [name[imperative]](https://github.com/ansible/ansible-lint/issues/2170) - [name[casing]](rules/name.md) - [spell-var-name](https://github.com/ansible/ansible-lint/issues/2168) ## safety The `safety` profile avoids module calls that can have non-determinant outcomes or security concerns. It extends [moderate](#moderate) profile. - [avoid-implicit](rules/avoid-implicit.md) - [latest](rules/latest.md) - [package-latest](rules/package-latest.md) - [risky-file-permissions](rules/risky-file-permissions.md) - [risky-octal](rules/risky-octal.md) - [risky-shell-pipe](rules/risky-shell-pipe.md) ## shared The `shared` profile ensures that content follows best practices for packaging and publishing. This profile is intended for content creators who want to make Ansible playbooks, roles, or collections available from [galaxy.ansible.com](https://galaxy.ansible.com/), [automation-hub](https://console.redhat.com/ansible/automation-hub), or a private instance. It extends [safety](#safety) profile. - [galaxy](rules/galaxy.md) - [ignore-errors](rules/ignore-errors.md) - [layout](https://github.com/ansible/ansible-lint/issues/1900) - [meta-incorrect](rules/meta-incorrect.md) - [meta-no-tags](rules/meta-no-tags.md) - [meta-video-links](rules/meta-video-links.md) - [meta-version](https://github.com/ansible/ansible-lint/issues/2103) - [meta-runtime](rules/meta-runtime.md) - [no-changed-when](rules/no-changed-when.md) - [no-handler](rules/no-handler.md) - [no-relative-paths](rules/no-relative-paths.md) - [max-block-depth](https://github.com/ansible/ansible-lint/issues/2173) - [max-tasks](https://github.com/ansible/ansible-lint/issues/2172) - [unsafe-loop](https://github.com/ansible/ansible-lint/issues/2038) ## production The `production` profile ensures that content meets requirements for inclusion in [Ansible Automation Platform (AAP)](https://www.redhat.com/en/technologies/management/ansible) as validated or certified content. It extends [shared](#shared) profile. - [avoid-dot-notation](https://github.com/ansible/ansible-lint/issues/2174) - [sanity](https://github.com/ansible/ansible-lint/issues/2121) - [fqcn](rules/fqcn.md) - [import-task-no-when](https://github.com/ansible/ansible-lint/issues/2219) - [meta-no-dependencies](https://github.com/ansible/ansible-lint/issues/2159) - [single-entry-point](https://github.com/ansible/ansible-lint/issues/2242) - [use-loop](https://github.com/ansible/ansible-lint/issues/2204) ansible-ansible-lint-c16f018/docs/redirects.yml000066400000000000000000000015721477347356000215240ustar00rootroot00000000000000# Authoritative list of redirects we have configured in RTD, # https://pypi.org/project/readthedocs-cli/ --- - type: page from_url: /rules/git-latest/ to_url: /rules/latest/ - type: page from_url: /rules/hg-latest/ to_url: /rules/latest/ - type: page from_url: /rules/meta-no-info/ # cspell:disable-next-line to_url: /rules/schemas/#schemameta - type: page from_url: /rules/deprecated-command-syntax/ to_url: /rules/no-free-form/ - type: page from_url: /default_rules/index/ to_url: /rules/ - type: page from_url: /en/latest/ to_url: / - type: page from_url: /en/latest/installing.html to_url: /installing/ - type: page from_url: /en/latest/rules.html to_url: /rules/ - type: page from_url: /en/latest/default_rules/ to_url: /rules/ - type: page from_url: /en/latest/pkg/ansiblelint.rules.empty_string_compare/ to_url: /rules/empty-string-compare/ ansible-ansible-lint-c16f018/docs/rules/000077500000000000000000000000001477347356000201425ustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/args.md000077700000000000000000000000001477347356000275442../../src/ansiblelint/rules/args.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/avoid-implicit.md000077700000000000000000000000001477347356000335622../../src/ansiblelint/rules/avoid_implicit.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/command-instead-of-module.md000077700000000000000000000000001477347356000377622../../src/ansiblelint/rules/command_instead_of_module.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/command-instead-of-shell.md000077700000000000000000000000001477347356000374262../../src/ansiblelint/rules/command_instead_of_shell.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/complexity.md000077700000000000000000000000001477347356000322462../../src/ansiblelint/rules/complexity.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/deprecated-bare-vars.md000077700000000000000000000000001477347356000357602../../src/ansiblelint/rules/deprecated_bare_vars.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/deprecated-local-action.md000077700000000000000000000000001477347356000371262../../src/ansiblelint/rules/deprecated_local_action.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/deprecated-module.md000077700000000000000000000000001477347356000347042../../src/ansiblelint/rules/deprecated_module.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/empty-string-compare.md000077700000000000000000000000001477347356000361742../../src/ansiblelint/rules/empty_string_compare.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/fqcn.md000077700000000000000000000000001477347356000275322../../src/ansiblelint/rules/fqcn.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/galaxy-version-incorrect.md000077700000000000000000000000001477347356000377142../../src/ansiblelint/rules/galaxy_version_incorrect.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/galaxy.md000077700000000000000000000000001477347356000304262../../src/ansiblelint/rules/galaxy.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/ignore-errors.md000077700000000000000000000000001477347356000333302../../src/ansiblelint/rules/ignore_errors.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/index.md000066400000000000000000000017271477347356000216020ustar00rootroot00000000000000# Rules - [args][] - [avoid-implicit][] - [complexity][] - [command-instead-of-module][] - [command-instead-of-shell][] - [deprecated-bare-vars][] - [deprecated-local-action][] - [deprecated-module][] - [empty-string-compare][] - [fqcn][] - [galaxy][] - [ignore-errors][] - [inline-env-var][] - [internal-error][] - [jinja][] - [key-order][] - [latest][] - [literal-compare][] - [load-failure][] - [loop-var-prefix][] - [meta-incorrect][] - [meta-no-tags][] - [meta-runtime][] - [meta-video-links][] - [name][] - [no-changed-when][] - [no-free-form][] - [no-handler][] - [no-jinja-when][] - [no-log-password][] - [no-prompting][] - [no-relative-paths][] - [no-same-owner][] - [no-tabs][] - [only-builtins][] - [package-latest][] - [parser-error][] - [partial-become][] - [playbook-extension][] - [risky-file-permissions][] - [risky-octal][] - [risky-shell-pipe][] - [role-name][] - [run-once][] - [sanity][] - [schema][] - [syntax-check][] - [var-naming][] - [warning][] - [yaml][] ansible-ansible-lint-c16f018/docs/rules/inline-env-var.md000077700000000000000000000000001477347356000335042../../src/ansiblelint/rules/inline_env_var.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/internal-error.md000077700000000000000000000000001477347356000344652../../src/ansiblelint/_internal/internal_error.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/jinja.md000077700000000000000000000000001477347356000300422../../src/ansiblelint/rules/jinja.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/key-order.md000077700000000000000000000000001477347356000315402../../src/ansiblelint/rules/key_order.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/latest.md000077700000000000000000000000001477347356000304442../../src/ansiblelint/rules/latest.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/literal-compare.md000077700000000000000000000000001477347356000340762../../src/ansiblelint/rules/literal_compare.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/load-failure.md000077700000000000000000000000001477347356000334052../../src/ansiblelint/_internal/load-failure.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/loop-var-prefix.md000077700000000000000000000000001477347356000341042../../src/ansiblelint/rules/loop_var_prefix.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/meta-incorrect.md000077700000000000000000000000001477347356000335662../../src/ansiblelint/rules/meta_incorrect.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/meta-no-tags.md000077700000000000000000000000001477347356000326102../../src/ansiblelint/rules/meta_no_tags.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/meta-runtime.md000077700000000000000000000000001477347356000327542../../src/ansiblelint/rules/meta_runtime.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/meta-video-links.md000077700000000000000000000000001477347356000343402../../src/ansiblelint/rules/meta_video_links.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/name.md000077700000000000000000000000001477347356000275142../../src/ansiblelint/rules/name.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/no-changed-when.md000077700000000000000000000000001477347356000337242../../src/ansiblelint/rules/no_changed_when.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/no-free-form.md000077700000000000000000000000001477347356000326102../../src/ansiblelint/rules/no_free_form.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/no-handler.md000077700000000000000000000000001477347356000320142../../src/ansiblelint/rules/no_handler.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/no-jinja-when.md000077700000000000000000000000001477347356000331302../../src/ansiblelint/rules/no_jinja_when.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/no-log-password.md000077700000000000000000000000001477347356000341062../../src/ansiblelint/rules/no_log_password.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/no-prompting.md000077700000000000000000000000001477347356000330202../../src/ansiblelint/rules/no_prompting.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/no-relative-paths.md000077700000000000000000000000001477347356000347242../../src/ansiblelint/rules/no_relative_paths.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/no-same-owner.md000077700000000000000000000000001477347356000331762../../src/ansiblelint/rules/no_same_owner.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/no-tabs.md000077700000000000000000000000001477347356000306442../../src/ansiblelint/rules/no_tabs.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/only-builtins.md000077700000000000000000000000001477347356000333562../../src/ansiblelint/rules/only_builtins.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/package-latest.md000077700000000000000000000000001477347356000335102../../src/ansiblelint/rules/package_latest.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/parser-error.md000077700000000000000000000000001477347356000335432../../src/ansiblelint/_internal/parser-error.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/partial-become.md000077700000000000000000000000001477347356000335062../../src/ansiblelint/rules/partial_become.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/playbook-extension.md000077700000000000000000000000001477347356000354222../../src/ansiblelint/rules/playbook_extension.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/risky-file-permissions.md000077700000000000000000000000001477347356000370762../../src/ansiblelint/rules/risky_file_permissions.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/risky-octal.md000077700000000000000000000000001477347356000324402../../src/ansiblelint/rules/risky_octal.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/risky-shell-pipe.md000077700000000000000000000000001477347356000344222../../src/ansiblelint/rules/risky_shell_pipe.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/role-name.md000077700000000000000000000000001477347356000314742../../src/ansiblelint/rules/role_name.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/run-once.md000077700000000000000000000000001477347356000312122../../src/ansiblelint/rules/run_once.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/sanity.md000077700000000000000000000000001477347356000304722../../src/ansiblelint/rules/sanity.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/schema.md000077700000000000000000000000001477347356000303542../../src/ansiblelint/rules/schema.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/syntax-check.md000077700000000000000000000000001477347356000327402../../src/ansiblelint/rules/syntax_check.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/var-naming.md000077700000000000000000000000001477347356000320342../../src/ansiblelint/rules/var_naming.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/warning.md000077700000000000000000000000001477347356000316072../../src/ansiblelint/_internal/warning.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/rules/yaml.md000077700000000000000000000000001477347356000275602../../src/ansiblelint/rules/yaml.mdustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/stylesheets/000077500000000000000000000000001477347356000213645ustar00rootroot00000000000000ansible-ansible-lint-c16f018/docs/stylesheets/extra.css000066400000000000000000000063651477347356000232330ustar00rootroot00000000000000/* Inspired by https://spec.draculatheme.com/ specification */ :root { --ansi-red: #ff5555; --ansi-green: #50fa7b; --ansi-blue: #265285; --ansi-yellow: #ffb86c; /* Orange */ --ansi-magenta: #bd93f9; /* Purple */ --ansi-cyan: #8be9fd; --ansi-black: #282a36; --ansi-white: #f8f8f2; } .-Color-Green, .-Color-Faint-Green, .-Color-Bold-Green { color: var(--ansi-green); } .-Color-Red, .-Color-Faint-Red, .-Color-Bold-Red { color: var(--ansi-red); } .-Color-Yellow, .-Color-Faint-Yellow, .-Color-Bold-Yellow { color: var(--ansi-yellow); } .-Color-Blue, .-Color-Faint-Blue, .-Color-Bold-Blue { color: var(--ansi-blue); } .-Color-Magenta, .-Color-Faint-Magenta, .-Color-Bold-Magenta { color: var(--ansi-magenta); } .-Color-Cyan, .-Color-Faint-Cyan, .-Color-Bold-Cyan { color: var(--ansi-cyan); } .-Color-White, .-Color-Faint-White, .-Color-Bold-White { color: var(--ansi-white); } .-Color-Black, .-Color-Faint-Black, .-Color-Bold-Black { color: var(--ansi-black); } .-Color-Faint { opacity: 0.5; } .-Color-Bold { font-weight: bold; } .-Color-Black-BGBlack, .-Color-BGBlack, .-Color-Red-BGBlack, .-Color-Green-BGBlack, .-Color-Yellow-BGBlack, .-Color-Blue-BGBlack, .-Color-Magenta-BGBlack, .-Color-Cyan-BGBlack, .-Color-White-BGBlack { background-color: var(--ansi-black); } .-Color-Black-BGRed, .-Color-BGRed, .-Color-Red-BGRed, .-Color-Green-BGRed, .-Color-Yellow-BGRed, .-Color-Blue-BGRed, .-Color-Magenta-BGRed, .-Color-Cyan-BGRed, .-Color-White-BGRed { background-color: var(--ansi-red); } .-Color-Black-BGGreen, .-Color-BGGreen, .-Color-Red-BGGreen, .-Color-Green-BGGreen, .-Color-Yellow-BGGreen, .-Color-Blue-BGGreen, .-Color-Magenta-BGGreen, .-Color-Cyan-BGGreen, .-Color-White-BGGreen { background-color: var(--ansi-green); } .-Color-Black-BGYellow, .-Color-BGYellow, .-Color-Red-BGYellow, .-Color-Green-BGYellow, .-Color-Yellow-BGYellow, .-Color-Blue-BGYellow, .-Color-Magenta-BGYellow, .-Color-Cyan-BGYellow, .-Color-White-BGYellow { background-color: var(--ansi-yellow); } .-Color-Black-BGBlue, .-Color-BGBlue, .-Color-Red-BGBlue, .-Color-Green-BGBlue, .-Color-Yellow-BGBlue, .-Color-Blue-BGBlue, .-Color-Magenta-BGBlue, .-Color-Cyan-BGBlue, .-Color-White-BGBlue { background-color: var(--ansi-blue); } .-Color-Black-BGMagenta, .-Color-BGMagenta, .-Color-Red-BGMagenta, .-Color-Green-BGMagenta, .-Color-Yellow-BGMagenta, .-Color-Blue-BGMagenta, .-Color-Magenta-BGMagenta, .-Color-Cyan-BGMagenta, .-Color-White-BGMagenta { background-color: var(--ansi-magenta); } .-Color-Black-BGCyan, .-Color-BGCyan, .-Color-Red-BGCyan, .-Color-Green-BGCyan, .-Color-Yellow-BGCyan, .-Color-Blue-BGCyan, .-Color-Magenta-BGCyan, .-Color-Cyan-BGCyan, .-Color-White-BGCyan { background-color: var(--ansi-cyan); } .-Color-Black-BGWhite, .-Color-BGWhite, .-Color-Red-BGWhite, .-Color-Green-BGWhite, .-Color-Yellow-BGWhite, .-Color-Blue-BGWhite, .-Color-Magenta-BGWhite, .-Color-Cyan-BGWhite, .-Color-White-BGWhite { background-color: var(--ansi-white); } .-Color-Black-BGBlack, .-Color-Red-BGRed, .-Color-Blue-BGBlue { text-shadow: 0 0 1px var(--ansi-white); } .-Color-Green-BGGreen, .-Color-Yellow-BGYellow, .-Color-Cyan-BGCyan, .-Color-White-BGWhite, .-Color-Magenta-BGMagenta, .-Color-Cyan-BGGreen, .-Color-Green-BGCyan { text-shadow: 0 0 1px var(--ansi-black); } ansible-ansible-lint-c16f018/docs/usage.md000066400000000000000000000274431477347356000204500ustar00rootroot00000000000000# Using ## Using commands After you install Ansible-lint, run `ansible-lint --help` to display available commands and their options. ```console exec="1" source="console" $ ansible-lint --help ``` ### Command output Ansible-lint prints output on both `stdout` and `stderr`. - `stdout` displays rule violations. - `stderr` displays logging and free-form messages like statistics. Most `ansible-lint` examples use pep8 as the output format (`-p`) which is machine parseable. Ansible-lint also print errors using their [annotation] format when it detects the `GITHUB_ACTIONS=true` and `GITHUB_WORKFLOW=...` variables. [annotation]: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-error-message ## Caching For optimal performance, Ansible-lint creates caches with installed or mocked roles, collections, and modules in the `{project_dir}/.cache` folder. The location of `{project_dir}` is passed with a command line argument, determined by the location of the configuration file, git project top-level directory, or user home directory. To perform faster re-runs, Ansible-lint does not automatically clean the cache. If required you can do this manually by simply deleting the `.cache` folder. Ansible-lint creates a new cache on the next invocation. You should add the `.cache` folder to the `.gitignore` file in your git repositories. ## Gradual adoption For an easier gradual adoption, adopters should consider [ignore file][ignoring-rules-for-entire-files] feature. This allows the quick introduction of a linter pipeline for preventing the addition of new violations, while known violations are ignored. Some people can work on addressing these historical violations while others may continue to work on other maintenance tasks. The deprecated `--progressive` mode was removed in v6.16.0 as it added code complexity and performance overhead. It also presented several corner cases where it failed to work as expected and caused false negatives. ## Linting playbooks and roles Ansible-lint recommends following the [collection structure layout] whether you plan to build a collection or not. Following that layout assures the best integration with all ecosystem tools because it helps those tools better distinguish between random YAML files and files managed by Ansible. When you call `ansible-lint` without arguments, it uses internal heuristics to determine file types. Pass the **roles** and **playbooks** that you want to lint as arguments to the `ansible-lint` command. For example, to lint `examples/playbooks/play.yml` and `examples/roles/bobbins`, use the following command: ```console exec="1" source="console" returncode="2" $ ansible-lint examples/playbooks/play.yml examples/roles/bobbins ``` [collection structure layout]: https://docs.ansible.com/ansible-core/devel/dev_guide/developing_collections_structure.html#collection-structure ## Running example playbooks Ansible-lint includes an `ansible-lint/examples` folder that contains example playbooks with different rule violations and undesirable characteristics. You can run `ansible-lint` on the example playbooks to observe Ansible-lint in action, as follows: ```console exec="1" source="console" returncode="2" $ ansible-lint --offline -p examples/playbooks/example.yml ``` Ansible-lint also handles playbooks that include other playbooks, tasks, handlers, or roles, as the `examples/playbooks/include.yml` example demonstrates. ```console exec="1" source="console" returncode="2" $ ansible-lint --offline -q -p examples/playbooks/include.yml ``` ## Output formats ### pep8 ```console exec="1" source="console" returncode="2" $ ansible-lint --offline -q -f pep8 examples/playbooks/norole.yml ``` ### SARIF JSON Using `--format sarif` or `--format json` the linter will output on stdout a report in [SARIF] We also have an option `--sarif-file FILE` option that can make the linter dump the output to a file while not altering its normal stdout output. This can be used in CI/CD pipelines. ```bash exec="1" source="tabbed-left" result="json" returncode="2" ansible-lint --offline -q -f sarif examples/playbooks/norole.yml ``` ### Code Climate JSON You can generate `JSON` reports based on the [Code Climate] specification as the `examples/playbooks/norole.yml` example demonstrates. ```bash exec="1" source="tabbed-left" result="json" returncode="2" ansible-lint --offline -q -f codeclimate examples/playbooks/norole.yml ``` Historically `-f json` was used to generate Code Climate JSON reports but in newer versions we switched its meaning point SARIF JSON format instead. !!! warning When possible we recommend using the [SARIF](#sarif-json) format instead of the Code Climate as that one is more complete and has a full specification and also a JSON validation schema. Code Climate format does not expose our severity levels because we use that field to map warnings as `minor` and errors as `major` issues. ## Specifying rules at runtime By default, `ansible-lint` applies rules found in `ansible-lint/src/ansiblelint/rules`. Use the `-r /path/to/custom-rules` option to specify the directory path to a set of custom rules. For multiple custom rule sets, pass each set with a separate `-r` option. You can also combine the default rules with custom rules with the `-R` option along with one or more `-r` options. ### Including rules with tags Each rule has an associated set of one or more tags. Use the `-T` option to view the list of tags for each available rule. You can then use the `-t` option to specify a tag and include the associated rules in the lint run. For example, the following `ansible-lint` command applies only the rules associated with the _idempotency_ tag: ```console exec="1" source="console" returncode="0" $ ansible-lint -t idempotency playbook.yml ``` The following shows the available tags in an example set of rules and the rules associated with each tag: ```bash exec="1" source="console" ansible-lint -T 2>/dev/null ``` ### Excluding rules with tags To exclude rules by identifiers or tags, use the `-x SKIP_LIST` option. For example, the following command applies all rules except those with the _formatting_ and _metadata_ tags: ```bash $ ansible-lint -x formatting,metadata playbook.yml ``` ### Ignoring rules To only warn about rules, use the `-w WARN_LIST` option. For example, the following command displays only warns about violations with rules associated with the `experimental` tag: ```console $ ansible-lint -w experimental playbook.yml ``` By default, the `WARN_LIST` includes the `['experimental']` tag. If you define a custom `WARN_LIST` you must add `'experimental'` so that Ansible-lint does not fail against experimental rules. ## Muting warnings to avoid false positives Not all linting rules are precise, some are general rules of thumb. Advanced _git_, _yum_ or _apt_ usage, for example, can be difficult to achieve in a playbook. In cases like this, Ansible-lint can incorrectly trigger rule violations. To disable rule violations for specific tasks, and mute false positives, add `# noqa: [rule_id]` to the end of the line. It is best practice to add a comment that explains why rules are disabled. You can add the `# noqa: [rule_id]` comment to the end of any line in a task. You can also skip multiple rules with a space-separated list. ```yaml - name: This task would typically fire git-latest and partial-become rules become_user: alice # noqa: git-latest partial-become ansible.builtin.git: src=/path/to/git/repo dest=checkout ``` If the rule is line-based, `# noqa: [rule_id]` must be at the end of the line. ```yaml - name: This would typically fire jinja[spacing] get_url: url: http://example.com/file.conf dest: "{{dest_proj_path}}/foo.conf" # noqa: jinja[spacing] ``` If you want Ansible-lint to skip a rule entirely, use the `-x` command line argument or add it to `skip_list` in your configuration. The least preferred method of skipping rules is to skip all task-based rules for a task, which does not skip line-based rules. You can use the `skip_ansible_lint` tag with all tasks, for example: ```yaml - name: This would typically fire no-free-form command: warn=no chmod 644 X - name: This would typically fire git-latest git: src=/path/to/git/repo dest=checkout tags: - skip_ansible_lint ``` ## Applying profiles Ansible-lint profiles allow content creators to progressively improve the quality of Ansible playbooks, roles, and collections. During early development cycles, you need Ansible-lint rules to be less strict. Starting with the minimal profile ensures that Ansible can load your content. As you move to the next stage of developing content, you can gradually apply profiles to avoid common pitfalls and brittle complexity. Then, when you are ready to publish or share your content, you can use the `shared` and `production` profiles with much stricter rules. These profiles harden security, guarantee reliability, and ensure your Ansible content is easy for others to contribute to and use. !!! note Tags such as `opt-in` and `experimental` do not take effect for rules that are included in profiles, directly or indirectly. If a rule is in a profile, Ansible-lint applies that rule to the content. After you install and configure `ansible-lint`, you can apply profiles as follows: 1. View available profiles with the `--list-profiles` flag. ```bash ansible-lint --list-profiles ``` 2. Specify a profile with the `--profile` parameter to lint your content with those rules, for example: - Enforce standard styles and formatting with the `basic` profile. ```bash ansible-lint --profile=basic ``` - Ensure automation consistency, reliability, and security with the `safety` profile. ```bash ansible-lint --profile=safety ``` ## Vaults As ansible-lint executes ansible, it also needs access to encrypted secrets. If you do not give access to them or you are concerned about security implications, you should consider refactoring your code to allow it to be linted without access to real secrets: - Configure dummy fallback values that are used during linting, so Ansible will not complain about undefined variables. - Exclude the problematic files from the linting process. ```yaml --- # Example of avoiding undefined variable error foo: "{{ undefined_variable_name | default('dummy') }}" ``` Keep in mind that a well-written playbook or role should allow Ansible's syntax check from passing on it, even if you do not have access to the vault. Internally ansible-lint runs `ansible-playbook --syntax-check` on each playbook and also on roles. As ansible-code does not support running syntax-check directly on roles, the linter will create temporary playbooks that only include each role from your project. You will need to change the code of the role in a way that it does not produce syntax errors when called without any variables or arguments. This usually involves making use of `defaults/` but be sure that you fully understand [variable precedence]. [code climate]: https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#data-types [sarif]: https://docs.oasis-open.org/sarif/sarif/v2.1.0/csprd01/sarif-v2.1.0-csprd01.html [variable precedence]: https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#understanding-variable-precedence ## Dependencies and requirements Ansible-lint will recognize `requirements.yml` files used for runtime and testing purposes and install them automatically. Valid locations for these files are: - [`requirements.yml`](https://docs.ansible.com/ansible/latest/galaxy/user_guide.html#installing-roles-and-collections-from-the-same-requirements-yml-file) - `roles/requirements.yml` - `collections/requirements.yml` - `tests/requirements.yml` - `tests/integration/requirements.yml` - `tests/unit/requirements.yml` - [`galaxy.yml`](https://docs.ansible.com/ansible/latest/dev_guide/collections_galaxy_meta.html) ansible-ansible-lint-c16f018/examples/000077500000000000000000000000001477347356000176765ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.collection/000077500000000000000000000000001477347356000221075ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.collection/CHANGELOG.rst000066400000000000000000000000001477347356000241160ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.collection/galaxy.yml000066400000000000000000000007571477347356000241300ustar00rootroot00000000000000--- name: foo namespace: bar version: 0.0.0 # noqa: galaxy-version-incorrect authors: - John readme: ../README.md description: "..." dependencies: other_namespace.collection1: ">=1.0.0" other_namespace.collection2: ">=2.0.0,<3.0.0" anderson55.my_collection: "*" # note: "*" selects the highest version available license: - GPL # <-- invalid license value based on galaxy schema, a value like GPL-3.0-or-later would work - Apache-2.0 repository: some-url tags: [networking, test_tag] ansible-ansible-lint-c16f018/examples/.collection/meta/000077500000000000000000000000001477347356000230355ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.collection/meta/runtime.yml000066400000000000000000000000001477347356000252310ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.collection/plugins/000077500000000000000000000000001477347356000235705ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.collection/plugins/modules/000077500000000000000000000000001477347356000252405ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.collection/plugins/modules/alpha.py000066400000000000000000000012261477347356000267000ustar00rootroot00000000000000"""An ansible test module.""" DOCUMENTATION = """ module: mod_1 author: - test short_description: This is a test module description: - This is a test module version_added: 1.0.0 options: foo: description: - Dummy option I(foo) type: str bar: description: - Dummy option I(bar) default: candidate type: str choices: - candidate - running aliases: - bam notes: - This is a dummy module """ EXAMPLES = """ - name: test task-1 company_name.coll_1.mod_1: foo: some value bar: candidate """ RETURN = """ baz: description: test return 1 returned: success type: list sample: ['a','b'] """ ansible-ansible-lint-c16f018/examples/.collection/plugins/modules/deep/000077500000000000000000000000001477347356000261555ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.collection/plugins/modules/deep/beta.py000066400000000000000000000012261477347356000274430ustar00rootroot00000000000000"""An ansible test module.""" DOCUMENTATION = """ module: mod_2 author: - test short_description: This is a test module description: - This is a test module version_added: 1.0.0 options: foo: description: - Dummy option I(foo) type: str bar: description: - Dummy option I(bar) default: candidate type: str choices: - candidate - running aliases: - bam notes: - This is a dummy module """ EXAMPLES = """ - name: test task-1 company_name.coll_1.mod_2: foo: some value bar: candidate """ RETURN = """ baz: description: test return 1 returned: success type: list sample: ['a','b'] """ ansible-ansible-lint-c16f018/examples/.collection/plugins/modules/tests/000077500000000000000000000000001477347356000264025ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.collection/plugins/modules/tests/gamma.py000066400000000000000000000012261477347356000300370ustar00rootroot00000000000000"""An ansible test module.""" DOCUMENTATION = """ module: mod_1 author: - test short_description: This is a test module description: - This is a test module version_added: 1.0.0 options: foo: description: - Dummy option I(foo) type: str bar: description: - Dummy option I(bar) default: candidate type: str choices: - candidate - running aliases: - bam notes: - This is a dummy module """ EXAMPLES = """ - name: test task-1 company_name.coll_1.mod_1: foo: some value bar: candidate """ RETURN = """ baz: description: test return 1 returned: success type: list sample: ['a','b'] """ ansible-ansible-lint-c16f018/examples/.config/000077500000000000000000000000001477347356000212215ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.config/ansible-lint.yml000077700000000000000000000000001477347356000273302../../.ansible-lintustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.config/molecule/000077500000000000000000000000001477347356000230265ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.config/molecule/config.yml000066400000000000000000000000001477347356000250040ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.github/000077500000000000000000000000001477347356000212365ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.github/workflows/000077500000000000000000000000001477347356000232735ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.github/workflows/sample.yml000066400000000000000000000003121477347356000252730ustar00rootroot00000000000000--- name: ack on: # <-- ansible-lint should not complain or touch about this 'on' pull_request_target: types: [opened] jobs: ack: uses: ansible/team-devtools/.github/workflows/ack.yml@main ansible-ansible-lint-c16f018/examples/.invalid_dependencies/000077500000000000000000000000001477347356000241105ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.invalid_dependencies/CHANGELOG.rst000066400000000000000000000000001477347356000261170ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.invalid_dependencies/galaxy.yml000066400000000000000000000011061477347356000261160ustar00rootroot00000000000000--- name: foo namespace: bar version: 0.0.0 # noqa: galaxy[version-incorrect] authors: - John readme: ../README.md description: "..." dependencies: other_namespace.collection1: ">=1.0.0" other_namespace.collection2: ">=2.0.0,<3.0.0" anderson55.my_collection: "*" # note: "*" selects the highest version available foo.my_collection1: " " # note: this should error out because of invalid dependency version foo.my_collection2: "" # note: this should error out because of invalid dependency version license: - Apache-2.0 repository: some-url tags: [networking, test_tag] ansible-ansible-lint-c16f018/examples/.invalid_dependencies/meta/000077500000000000000000000000001477347356000250365ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.invalid_dependencies/meta/runtime.yml000066400000000000000000000000001477347356000272320ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.no_changelog/000077500000000000000000000000001477347356000223775ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.no_changelog/galaxy.yml000066400000000000000000000006401477347356000244070ustar00rootroot00000000000000--- name: foo namespace: bar version: 0.0.0 # noqa: galaxy[version-incorrect] authors: - John readme: ../README.md description: "..." dependencies: other_namespace.collection1: ">=1.0.0" other_namespace.collection2: ">=2.0.0,<3.0.0" anderson55.my_collection: "*" # note: "*" selects the highest version available license: - GPL-3.0-or-later - Apache-2.0 repository: some-url tags: [networking, test_tag] ansible-ansible-lint-c16f018/examples/.no_changelog/meta/000077500000000000000000000000001477347356000233255ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.no_changelog/meta/runtime.yml000066400000000000000000000000001477347356000255210ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.no_collection_version/000077500000000000000000000000001477347356000243505ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.no_collection_version/changelogs/000077500000000000000000000000001477347356000264625ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.no_collection_version/changelogs/changelog.yaml000066400000000000000000000000211477347356000312660ustar00rootroot00000000000000--- releases: {} ansible-ansible-lint-c16f018/examples/.no_collection_version/galaxy.yml000066400000000000000000000003631477347356000263620ustar00rootroot00000000000000--- name: galaxy_no_version namespace: test readme: ../README.md authors: - John description: your collection description license: - GPL-3.0-or-later dependencies: {} repository: http://example.com/repository tags: [networking, test_tag] ansible-ansible-lint-c16f018/examples/.test_collection/000077500000000000000000000000001477347356000231465ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.test_collection/.ansible-lint000066400000000000000000000000031477347356000255210ustar00rootroot00000000000000{} ansible-ansible-lint-c16f018/examples/.test_collection/README.md000066400000000000000000000001221477347356000244200ustar00rootroot00000000000000# Ansible Collection - example.test_collection Documentation for the collection. ansible-ansible-lint-c16f018/examples/.test_collection/galaxy.yml000066400000000000000000000060071477347356000251610ustar00rootroot00000000000000--- ### REQUIRED # The namespace of the collection. This can be a company/brand/organization or product namespace under which all # content lives. May only contain alphanumeric lowercase characters and underscores. Namespaces cannot start with # underscores or numbers and cannot contain consecutive underscores namespace: examples # The name of the collection. Has the same character restrictions as 'namespace' name: test_collection # The version of the collection. Must be compatible with semantic versioning version: 1.0.0 # The path to the Markdown (.md) readme file. This path is relative to the root of the collection readme: README.md # A list of the collection's content authors. Can be just the name or in the format 'Full Name (url) # @nicks:irc/im.site#channel' authors: - your name ### OPTIONAL but strongly recommended # A short summary description of the collection description: your collection description # Either a single license or a list of licenses for content inside of a collection. Ansible Galaxy currently only # accepts L(SPDX,https://spdx.org/licenses/) licenses. This key is mutually exclusive with 'license_file' license: - GPL-2.0-or-later # The path to the license file for the collection. This path is relative to the root of the collection. This key is # mutually exclusive with 'license' license_file: "" # A list of tags you want to associate with the collection for indexing/searching. A tag name has the same character # requirements as 'namespace' and 'name' tags: [] # Collections that this collection requires to be installed for it to be usable. The key of the dict is the # collection label 'namespace.name'. The value is a version range # L(specifiers,https://python-semanticversion.readthedocs.io/en/latest/#requirement-specification). Multiple version # range specifiers can be set and are separated by ',' dependencies: {} # The URL of the originating SCM repository repository: http://example.com/repository # The URL to any online docs documentation: http://docs.example.com # The URL to the homepage of the collection/project homepage: http://example.com # The URL to the collection issue tracker issues: http://example.com/issue/tracker # A list of file glob-like patterns used to filter any files or directories that should not be included in the build # artifact. A pattern is matched from the relative path of the file or directory of the collection directory. This # uses 'fnmatch' to match the files or directories. Some directories and files like 'galaxy.yml', '*.pyc', '*.retry', # and '.git' are always filtered. Mutually exclusive with 'manifest' build_ignore: [] # A dict controlling use of manifest directives used in building the collection artifact. The key 'directives' is a # list of MANIFEST.in style # L(directives,https://packaging.python.org/en/latest/guides/using-manifest-in/#manifest-in-commands). The key # 'omit_default_directives' is a boolean that controls whether the default directives are used. Mutually exclusive # with 'build_ignore' # manifest: null ansible-ansible-lint-c16f018/examples/.test_collection/roles/000077500000000000000000000000001477347356000242725ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.test_collection/roles/my_role/000077500000000000000000000000001477347356000257405ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.test_collection/roles/my_role/tasks/000077500000000000000000000000001477347356000270655ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.test_collection/roles/my_role/tasks/main.yml000066400000000000000000000004171477347356000305360ustar00rootroot00000000000000--- - name: Task ansible.builtin.include_role: name: example.test_collection.my_role2 vars: my_role2_foo: something - name: Task 2 # this task should NOT trigger var-naming[no-role-prefix] vars: foo: bar ansible.builtin.debug: msg: "{{ foo }}" ansible-ansible-lint-c16f018/examples/.test_collection/roles/my_role2/000077500000000000000000000000001477347356000260225ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.test_collection/roles/my_role2/tasks/000077500000000000000000000000001477347356000271475ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/.test_collection/roles/my_role2/tasks/main.yml000066400000000000000000000001101477347356000306060ustar00rootroot00000000000000--- - name: Task ansible.builtin.debug: msg: "{{ my_role2_foo }}" ansible-ansible-lint-c16f018/examples/Taskfile.yml000066400000000000000000000003301477347356000221570ustar00rootroot00000000000000--- # Sample taskfile, for testing linter ability to identify it version: "3" output: group vars: HOSTNAME: # <-- this is valid for Taskfiles but not for ansible files sh: echo ${HOSTNAME:-localhost} tasks: {} ansible-ansible-lint-c16f018/examples/ansible-navigator.yml000066400000000000000000000001351477347356000240250ustar00rootroot00000000000000--- # see https://ansible-navigator.readthedocs.io/en/latest/settings/ ansible-navigator: {} ansible-ansible-lint-c16f018/examples/broken/000077500000000000000000000000001477347356000211565ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/broken/.ansible-lint000066400000000000000000000001071477347356000235360ustar00rootroot00000000000000# invalid ansible-lint config file foo: bar # invalid based on schema ansible-ansible-lint-c16f018/examples/broken/ansible-navigator.yml000066400000000000000000000002111477347356000253000ustar00rootroot00000000000000--- # https://ansible-navigator.readthedocs.io/en/latest/settings/ ansible: {} # invalid as it is missing 'ansible-navigator' parent key ansible-ansible-lint-c16f018/examples/broken/encoding.j2000066400000000000000000000000041477347356000231730ustar00rootroot00000000000000- ansible-ansible-lint-c16f018/examples/broken/encoding.yml000066400000000000000000000017511477347356000234730ustar00rootroot000000000000008b'XZiΟ F5-l1g̏e Ӹ[(w^)c]" e[շ xCZ|i>`TPnNML 3%[Q :*c\bm`ع'J,^"V}6X|DUzbGZǯ4U0RѶhl5-^!x[T!OJ G>ZCx`چ/'e7G2#x~e8ȝo^M%wW'nw?qX}΍p8X5,ްH5gѸxnhBޙekSJ^di:rqH݋NSSbY7H V %~>?4ŀ˪[{[Llo@=is_*{۴Yg͞ew#@M̓sΏl .V!}UxՇ^`7Kt&I+{IIHԈqͳi^sN\*әGR@.G@HHt%PAm&_.ˆ=:I|]~g_H3ș2Jo?(bKO "Vf,Ix$Pm5>n:/Je()*Pݓ1׵x I$pFfn+-:% nׂ'9o\ rsBWgX3Oc^*[ZLkVd.XxQ@ÛiS V|s~S"&9+ 8z(dS"V!\x rQ2 OkiЙlxLЉ嵨@kn,0H1n8=H=h!{WهdnDݫ"8sXor» >C(C0KLȲY*'* {/ ansible-ansible-lint-c16f018/examples/broken/yaml-with-tabs/000077500000000000000000000000001477347356000240205ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/broken/yaml-with-tabs/invalid-due-tabs.yaml000066400000000000000000000001171477347356000300330ustar00rootroot00000000000000{ "data": "this is not a valid YAML file as specification forbids tabs", } } ansible-ansible-lint-c16f018/examples/broken_collection_meta_runtime/000077500000000000000000000000001477347356000261425ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/broken_collection_meta_runtime/meta/000077500000000000000000000000001477347356000270705ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/broken_collection_meta_runtime/meta/runtime.yml000066400000000000000000000000721477347356000312750ustar00rootroot00000000000000--- foo: bar # should fail meta-runtime schema validation ansible-ansible-lint-c16f018/examples/broken_supported_ansible_also/000077500000000000000000000000001477347356000257765ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/broken_supported_ansible_also/.ansible-lint000066400000000000000000000001031477347356000303520ustar00rootroot00000000000000# Invalid supported_ansible_also type supported_ansible_also: True ansible-ansible-lint-c16f018/examples/changelogs/000077500000000000000000000000001477347356000220105ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/changelogs/changelog.yaml000066400000000000000000000000151477347356000246170ustar00rootroot00000000000000--- foo: bar ansible-ansible-lint-c16f018/examples/collections/000077500000000000000000000000001477347356000222145ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/collections/broken_no_runtime/000077500000000000000000000000001477347356000257335ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/collections/broken_no_runtime/CHANGELOG.md000066400000000000000000000000001477347356000275320ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/collections/broken_no_runtime/galaxy.yml000066400000000000000000000003071477347356000277430ustar00rootroot00000000000000--- name: broken_no_runtime namespace: fixtures version: 1.2.3 authors: - John readme: ../README.md tags: ["tools"] description: Lorem ipsum repository: https://www.github.com/my_org/my_collection ansible-ansible-lint-c16f018/examples/ee_broken/000077500000000000000000000000001477347356000216275ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/ee_broken/execution-environment.yml000066400000000000000000000001101477347356000267070ustar00rootroot00000000000000--- # This should fail Execution Environment Schema validation foo: bar ansible-ansible-lint-c16f018/examples/execution-environment.yml000066400000000000000000000000701477347356000247630ustar00rootroot00000000000000--- version: 1 dependencies: galaxy: requirements.yml ansible-ansible-lint-c16f018/examples/galaxy_tags/000077500000000000000000000000001477347356000222015ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_count_tags/000077500000000000000000000000001477347356000257145ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_count_tags/changelogs/000077500000000000000000000000001477347356000300265ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_count_tags/changelogs/changelog.yaml000066400000000000000000000000211477347356000326320ustar00rootroot00000000000000--- releases: {} ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_count_tags/galaxy.yml000066400000000000000000000007311477347356000277250ustar00rootroot00000000000000--- namespace: bar name: foo version: "1.0.0" # <-- that version is not valid, should be 1.0.0 or greater authors: - John readme: ../README.md description: "..." license: - Apache-2.0 repository: https://github.com/ansible-collections/community.REPO_NAME tags: - application - tag2 - tag3 - tag4 - tag5 - tag6 - tag7 - tag8 - tag9 - tag10 - tag11 - tag12 - tag13 - tag14 - tag15 - tag16 - tag17 - tag18 - tag19 - tag20 - tag21 ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_count_tags/meta/000077500000000000000000000000001477347356000266425ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_count_tags/meta/runtime.yml000066400000000000000000000000001477347356000310360ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_invalid_format_tags/000077500000000000000000000000001477347356000275625ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_invalid_format_tags/changelogs/000077500000000000000000000000001477347356000316745ustar00rootroot00000000000000changelog.yaml000066400000000000000000000000211477347356000344210ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_invalid_format_tags/changelogs--- releases: {} ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_invalid_format_tags/galaxy.yml000066400000000000000000000003641477347356000315750ustar00rootroot00000000000000--- namespace: bar name: foo version: "1.0.0" authors: - John readme: ../README.md description: "..." license: - Apache-2.0 repository: https://github.com/ansible-collections/community.REPO_NAME tags: - application - invalid-tag-format ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_invalid_format_tags/meta/000077500000000000000000000000001477347356000305105ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_invalid_format_tags/meta/runtime.yml000066400000000000000000000000001477347356000327040ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_invalid_length_tags/000077500000000000000000000000001477347356000275535ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_invalid_length_tags/changelogs/000077500000000000000000000000001477347356000316655ustar00rootroot00000000000000changelog.yaml000066400000000000000000000000211477347356000344120ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_invalid_length_tags/changelogs--- releases: {} ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_invalid_length_tags/galaxy.yml000066400000000000000000000005341477347356000315650ustar00rootroot00000000000000--- namespace: bar name: foo version: "1.0.0" authors: - John readme: ../README.md description: "..." license: - Apache-2.0 repository: https://github.com/ansible-collections/community.REPO_NAME tags: - application - this_is_an_utterly_ridiculous_and_insanely_long_tag_length_eye_roll - also_a_ridiculously_long_tag_but_within_the_limits ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_invalid_length_tags/meta/000077500000000000000000000000001477347356000305015ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_invalid_length_tags/meta/runtime.yml000066400000000000000000000000001477347356000326750ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_no_required_tags/000077500000000000000000000000001477347356000271005ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_no_required_tags/changelogs/000077500000000000000000000000001477347356000312125ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_no_required_tags/changelogs/changelog.yaml000066400000000000000000000000211477347356000340160ustar00rootroot00000000000000--- releases: {} ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_no_required_tags/galaxy.yml000066400000000000000000000004361477347356000311130ustar00rootroot00000000000000--- namespace: bar name: foo version: 1.0.0 # <-- that version is not valid, should be 1.0.0 or greater authors: - John readme: ../README.md description: "..." license: - Apache-2.0 repository: https://github.com/ansible-collections/community.REPO_NAME tags: [no_required_tag_here] ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_no_required_tags/meta/000077500000000000000000000000001477347356000300265ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/galaxy_no_required_tags/meta/runtime.yml000066400000000000000000000000001477347356000322220ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/pass/000077500000000000000000000000001477347356000231475ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/pass/changelogs/000077500000000000000000000000001477347356000252615ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/pass/changelogs/changelog.yaml000066400000000000000000000000211477347356000300650ustar00rootroot00000000000000--- releases: {} ansible-ansible-lint-c16f018/examples/galaxy_tags/pass/galaxy.yml000066400000000000000000000004361477347356000251620ustar00rootroot00000000000000--- namespace: bar name: foo version: 1.0.0 # <-- that version is not valid, should be 1.0.0 or greater authors: - John readme: ../README.md description: "..." license: - Apache-2.0 repository: https://github.com/ansible-collections/community.REPO_NAME tags: [networking, test_tag] ansible-ansible-lint-c16f018/examples/galaxy_tags/pass/meta/000077500000000000000000000000001477347356000240755ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/galaxy_tags/pass/meta/runtime.yml000066400000000000000000000000001477347356000262710ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/group_vars/000077500000000000000000000000001477347356000220655ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/group_vars/all.yml000066400000000000000000000000631477347356000233570ustar00rootroot00000000000000--- some_var: some_value_defined_in_group_vars_all ansible-ansible-lint-c16f018/examples/host_vars/000077500000000000000000000000001477347356000217065ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/host_vars/localhost.yml000066400000000000000000000000701477347356000244160ustar00rootroot00000000000000--- some_var: some_value_defined_in_host_vars_localhost ansible-ansible-lint-c16f018/examples/inventory/000077500000000000000000000000001477347356000217335ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/inventory/broken_dev_inventory.yml000066400000000000000000000000741477347356000267120ustar00rootroot00000000000000--- all: foo: {} # invalid based on inventory json schema ansible-ansible-lint-c16f018/examples/inventory/inventory.yml000066400000000000000000000011141477347356000245100ustar00rootroot00000000000000--- # https://docs.ansible.com/ansible/latest/inventory_guide/intro_inventory.html ungrouped: {} all: hosts: mail.example.com: children: webservers: hosts: foo.example.com: bar.example.com: dbservers: hosts: one.example.com: two.example.com: three.example.com: east: hosts: foo.example.com: one.example.com: two.example.com: west: hosts: bar.example.com: three.example.com: prod: children: east: {} test: children: west: {} ansible-ansible-lint-c16f018/examples/inventory/production.yml000066400000000000000000000013301477347356000246410ustar00rootroot00000000000000--- all: hosts: mail.example.com: children: webservers: hosts: foo.example.com: bar.example.com: # ranges are supported: www[01:50].example.com: www[01:50:2].example.com: # these are variables: var_1: value_1 another_var: 200 dbservers: hosts: one.example.com: two.example.com: three.example.com: east: hosts: foo.example.com: one.example.com: two.example.com: west: hosts: bar.example.com: three.example.com: prod: children: east: test: children: west: # add variables for all hosts vars: my_var: 123 ansible-ansible-lint-c16f018/examples/lineno.yml000066400000000000000000000000431477347356000217020ustar00rootroot00000000000000--- - tasks: - git: repo=hello ansible-ansible-lint-c16f018/examples/meta/000077500000000000000000000000001477347356000206245ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/meta/changelogs/000077500000000000000000000000001477347356000227365ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/meta/changelogs/changelog.yaml000066400000000000000000000000211477347356000255420ustar00rootroot00000000000000--- releases: {} ansible-ansible-lint-c16f018/examples/meta/changelogs/changelog.yml000066400000000000000000000000001477347356000253760ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/meta/galaxy.yml000066400000000000000000000006201477347356000226320ustar00rootroot00000000000000--- name: foo namespace: bar version: 0.2.3 # <-- that version is not valid, should be 1.0.0 or greater authors: - John readme: ../README.md description: "..." dependencies: other_namespace.collection1: ">=1.0.0" other_namespace.collection2: ">=2.0.0,<3.0.0" anderson55.my_collection: "*" # note: "*" selects the highest version available license: - Apache-2.0 tags: [networking, test_tag] ansible-ansible-lint-c16f018/examples/meta/meta/000077500000000000000000000000001477347356000215525ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/meta/meta/runtime.yml000066400000000000000000000000001477347356000237460ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/meta/runtime.yml000066400000000000000000000001771477347356000230370ustar00rootroot00000000000000--- # https://docs.ansible.com/ansible/latest/dev_guide/developing_collections_structure.html requires_ansible: ">=2.10,<2.20" ansible-ansible-lint-c16f018/examples/meta_runtime_version_checks/000077500000000000000000000000001477347356000254545ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/meta_runtime_version_checks/fail_0/000077500000000000000000000000001477347356000266065ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/meta_runtime_version_checks/fail_0/meta/000077500000000000000000000000001477347356000275345ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/meta_runtime_version_checks/fail_0/meta/runtime.yml000066400000000000000000000000411477347356000317350ustar00rootroot00000000000000--- requires_ansible: ">=2.20.0" ansible-ansible-lint-c16f018/examples/meta_runtime_version_checks/fail_1/000077500000000000000000000000001477347356000266075ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/meta_runtime_version_checks/fail_1/meta/000077500000000000000000000000001477347356000275355ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/meta_runtime_version_checks/fail_1/meta/runtime.yml000066400000000000000000000000461477347356000317430ustar00rootroot00000000000000--- requires_ansible: ">=2.9.0,<2.20" ansible-ansible-lint-c16f018/examples/meta_runtime_version_checks/fail_2/000077500000000000000000000000001477347356000266105ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/meta_runtime_version_checks/fail_2/meta/000077500000000000000000000000001477347356000275365ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/meta_runtime_version_checks/fail_2/meta/runtime.yml000066400000000000000000000000451477347356000317430ustar00rootroot00000000000000--- requires_ansible: "2.15.0,<2.16" ansible-ansible-lint-c16f018/examples/meta_runtime_version_checks/pass_0/000077500000000000000000000000001477347356000266415ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/meta_runtime_version_checks/pass_0/meta/000077500000000000000000000000001477347356000275675ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/meta_runtime_version_checks/pass_0/meta/runtime.yml000066400000000000000000000000511477347356000317710ustar00rootroot00000000000000--- requires_ansible: ">=2.15.0,<2.17.0" ansible-ansible-lint-c16f018/examples/meta_runtime_version_checks/pass_1/000077500000000000000000000000001477347356000266425ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/meta_runtime_version_checks/pass_1/meta/000077500000000000000000000000001477347356000275705ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/meta_runtime_version_checks/pass_1/meta/runtime.yml000066400000000000000000000000411477347356000317710ustar00rootroot00000000000000--- requires_ansible: ">=2.9.10" ansible-ansible-lint-c16f018/examples/other/000077500000000000000000000000001477347356000210175ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/other/guess-1.yml000066400000000000000000000001121477347356000230200ustar00rootroot00000000000000--- - name: Minimal yaml to determine it as a playbook hosts: localhost ansible-ansible-lint-c16f018/examples/other/some.j2.yaml000066400000000000000000000001421477347356000231550ustar00rootroot00000000000000# Used to validate that a templated YAML file does not confuse the linter {% include 'port.j2' %} ansible-ansible-lint-c16f018/examples/other/some.yaml-too000066400000000000000000000000671477347356000234500ustar00rootroot00000000000000# Used to test custom kinds defined in .ansible-config ansible-ansible-lint-c16f018/examples/playbooks/000077500000000000000000000000001477347356000217015ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/.ansible-lint-only-builtins-allow000066400000000000000000000007031477347356000302050ustar00rootroot00000000000000# yaml-language-server: $schema=https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/ansible-lint-config.json # Mock modules or roles in order to pass ansible-playbook --syntax-check mock_modules: - fake_namespace.fake_collection.fake_module only_builtins_allow_collections: - fake_namespace.fake_collection only_builtins_allow_modules: - zuul_return # skip rule to test builtin rule skip_list: - args[module] ansible-ansible-lint-c16f018/examples/playbooks/4114/000077500000000000000000000000001477347356000222725ustar00rootroot00000000000000transform-with-missing-role-and-modules.transformed.yml000066400000000000000000000005021477347356000350560ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/4114--- - name: Reproducer for bug 4114 hosts: localhost roles: - this_role_is_missing tasks: - name: Task referring to a missing module this_module_does_not_exist: foo: bar - name: Use raw to echo ansible.builtin.debug: # <-- this should be converted to fqcn msg: some message! ansible-ansible-lint-c16f018/examples/playbooks/4114/transform-with-missing-role-and-modules.yml000066400000000000000000000004621477347356000326170ustar00rootroot00000000000000--- - name: Reproducer for bug 4114 hosts: localhost roles: - this_role_is_missing tasks: - name: Task referring to a missing module this_module_does_not_exist: foo: bar - name: Use raw to echo debug: # <-- this should be converted to fqcn msg: some message! ansible-ansible-lint-c16f018/examples/playbooks/README.md000066400000000000000000000001331477347356000231550ustar00rootroot00000000000000The `./roles` symlink helps Ansible find local roles used by files from current directory. ansible-ansible-lint-c16f018/examples/playbooks/action_plugins/000077500000000000000000000000001477347356000247175ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/action_plugins/some_action.py000066400000000000000000000005541477347356000275750ustar00rootroot00000000000000"""Sample action_plugin.""" from ansible.plugins.action import ActionBase class ActionModule(ActionBase): """Sample module.""" def run(self, tmp=None, task_vars=None): # type: ignore[no-untyped-def] """.""" super().run(tmp, task_vars) # type: ignore[no-untyped-call] ret = {"foo": "bar"} return {"ansible_facts": ret} ansible-ansible-lint-c16f018/examples/playbooks/adj_action.yml000066400000000000000000000003721477347356000245210ustar00rootroot00000000000000--- - name: Fixture for testing adjacent plugins hosts: localhost tasks: - name: Call adjacent action plugin some_action: {} - name: Call adjacent filter plugin ansible.builtin.debug: msg: "{{ 'foo' | some_filter }}" ansible-ansible-lint-c16f018/examples/playbooks/always-run-success.yml000066400000000000000000000000271477347356000261730ustar00rootroot00000000000000--- - hosts: localhost ansible-ansible-lint-c16f018/examples/playbooks/become.transformed.yml000066400000000000000000000005221477347356000262000ustar00rootroot00000000000000--- - name: Fixture hosts: all tasks: - name: Clone content repository ansible.builtin.git: repo: "{{ archive_services_repo_url }}" dest: /home/www accept_hostkey: true version: master update: false become: true become_user: nobody notify: - restart apache2 ansible-ansible-lint-c16f018/examples/playbooks/become.yml000066400000000000000000000005221477347356000236550ustar00rootroot00000000000000--- - name: Fixture hosts: all tasks: - name: Clone content repository ansible.builtin.git: repo: "{{ archive_services_repo_url }}" dest: /home/www accept_hostkey: true version: master update: false become: true become_user: nobody notify: - restart apache2 ansible-ansible-lint-c16f018/examples/playbooks/block.yml000066400000000000000000000014701477347356000235200ustar00rootroot00000000000000--- - hosts: all pre_tasks: - { import_tasks: does-not-exist.yml } tasks: - block: - name: Successful debug message debug: msg='i execute normally' - name: Failure command ansible.builtin.command: /bin/false changed_when: false - name: Never reached debug message debug: msg='i never execute, cause ERROR!' rescue: - name: Exception debug message ansible.builtin.debug: msg='I caught an error' - name: Another failure command ansible.builtin.command: /bin/false changed_when: false - name: Another missed debug message debug: msg='I also never execute :-(' always: - name: Always reached debug message ansible.builtin.debug: msg="this always executes" ansible-ansible-lint-c16f018/examples/playbooks/blockincludes.yml000066400000000000000000000013331477347356000252450ustar00rootroot00000000000000--- - name: Fixture hosts: localhost vars: varset: varset tasks: - name: Block level 1 block: - name: Include under block level 1 # noqa: fqcn include_tasks: tasks/nestedincludes.yml - name: Block level 2 block: # - include_tasks: "{{ varnotset }}.yml" - name: Block level 3 block: - name: Include under block level 3 # noqa: deprecated-module ansible.builtin.include_tasks: "{{ varset }}.yml" - name: Block level 4 block: - name: INCLUDE under block level 4 ansible.builtin.include_tasks: tasks/directory with spaces/main.yml ansible-ansible-lint-c16f018/examples/playbooks/blockincludes2.yml000066400000000000000000000010201477347356000253200ustar00rootroot00000000000000--- - name: Fixture hosts: webservers vars: varset: varset tasks: - name: I am a block block: - name: Include under block ansible.builtin.include_tasks: tasks/nestedincludes.yml # - block: # - include_tasks: "{{ varnotset }}.yml" rescue: - name: Include under rescue ansible.builtin.include_tasks: "{{ varset }}.yml" always: - name: Include under always ansible.builtin.include_tasks: tasks/directory with spaces/main.yml ansible-ansible-lint-c16f018/examples/playbooks/bracketsmatchtest.yml000066400000000000000000000000651477347356000261400ustar00rootroot00000000000000--- val1: "{{dest}}" val2: worry val3: "{{victory}}" ansible-ansible-lint-c16f018/examples/playbooks/bug-4095.yml000066400000000000000000000003371477347356000236030ustar00rootroot00000000000000--- - name: Test task hosts: localhost connection: local tasks: - name: Reproduce bug related bug 4095 ansible.builtin.include_role: name: local.testcollection.bug4095 vars: var1: val1 ansible-ansible-lint-c16f018/examples/playbooks/bug-core-warning-unique-filter-fallback.yml000066400000000000000000000003711477347356000321170ustar00rootroot00000000000000--- - name: Fixture for test_bug_3216 hosts: localhost gather_facts: false tasks: - name: Set fact ansible.builtin.set_fact: qq: ["qq", "ww"] - name: Print it ansible.builtin.debug: msg: "{{ qq | unique }}" ansible-ansible-lint-c16f018/examples/playbooks/capture-warning.yml000066400000000000000000000003301477347356000255260ustar00rootroot00000000000000--- - name: Fixture to generate a warning hosts: localhost tasks: - name: Generate a warning ansible.builtin.debug: msg: "This is a warning" when: "{{ false }}" # noqa: 102 jinja[spacing] ansible-ansible-lint-c16f018/examples/playbooks/collections/000077500000000000000000000000001477347356000242175ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/collections/.gitignore000066400000000000000000000000451477347356000262060ustar00rootroot00000000000000ansible_collections requirements.yml ansible-ansible-lint-c16f018/examples/playbooks/command-check-failure.yml000066400000000000000000000004071477347356000265430ustar00rootroot00000000000000--- - hosts: localhost tasks: - name: Command without checks ansible.builtin.command: echo blah args: chdir: X - name: Shell without checks ansible.builtin.shell: echo blah args: chdir: X become_method: xx ansible-ansible-lint-c16f018/examples/playbooks/command-check-success.yml000066400000000000000000000035211477347356000265640ustar00rootroot00000000000000--- - name: Fixture for no-changed-when hosts: localhost tasks: - name: Command with creates check ansible.builtin.command: echo blah args: creates: Z - name: Command with removes check ansible.builtin.command: echo blah args: removes: Z - name: Command with changed_when ansible.builtin.command: echo blah changed_when: false - name: Command with inline creates # noqa: no-free-form ansible.builtin.command: creates=Z echo blah - name: Command with inline removes # noqa: no-free-form ansible.builtin.command: removes=Z echo blah - name: Command with cmd # noqa: fqcn[action-core] command: cmd: echo blah args: creates: Z - name: Use shell with creates check # noqa: fqcn[action-core] command-instead-of-shell shell: echo blah args: creates: Z - name: Use shell with removes check # noqa: fqcn[action-core] command-instead-of-shell shell: echo blah args: removes: Z - name: Use shell with changed_when # noqa: fqcn[action-core] command-instead-of-shell shell: echo blah changed_when: false - name: Use shell with inline creates # noqa: fqcn[action-core] no-free-form command-instead-of-shell shell: creates=Z echo blah - name: Use shell with inline removes # noqa: fqcn[action-core] no-free-form command-instead-of-shell shell: removes=Z echo blah - name: Use shell with cmd # noqa: fqcn[action-core] command-instead-of-shell shell: cmd: echo blah args: creates: Z - name: Fixture hosts: localhost handlers: - name: Restart something # noqa: fqcn[action-core] no-changed-when command: do something - name: Foo # noqa: fqcn[action-core] deprecated-module include_tasks: handlers/included-handlers.yml ansible-ansible-lint-c16f018/examples/playbooks/common-include-1.yml000066400000000000000000000006611477347356000254760ustar00rootroot00000000000000--- - name: Fixture for test_files_not_scanned_twice hosts: localhost gather_facts: false tasks: - name: Some include ansible.builtin.import_tasks: tasks/included-with-lint.yml - name: Some include_tasks with file and jinja2 ansible.builtin.include_tasks: file: "{{ 'tasks/included-with-lint.yml' }}" - name: Some include 3 ansible.builtin.include_tasks: file=tasks/included-with-lint.yml ansible-ansible-lint-c16f018/examples/playbooks/common-include-2.yml000066400000000000000000000002411477347356000254710ustar00rootroot00000000000000--- - name: Fixture hosts: localhost gather_facts: false tasks: - name: Some include ansible.builtin.include_tasks: tasks/included-with-lint.yml ansible-ansible-lint-c16f018/examples/playbooks/common-include-wrong-syntax.yml000066400000000000000000000004471477347356000300200ustar00rootroot00000000000000--- - name: Fixture for test coverage hosts: localhost gather_facts: false tasks: - name: Some include with invalid syntax ansible.builtin.include_tasks: "file=" - name: Some include with invalid syntax ansible.builtin.include_tasks: other=tasks/included-with-lint.yml ansible-ansible-lint-c16f018/examples/playbooks/common-include-wrong-syntax2.yml000066400000000000000000000002751477347356000301010ustar00rootroot00000000000000--- - name: Fixture for test coverage hosts: localhost gather_facts: false tasks: - name: Some include with invalid syntax ansible.builtin.include_tasks: file: null ansible-ansible-lint-c16f018/examples/playbooks/common-include-wrong-syntax3.yml000066400000000000000000000002131477347356000300720ustar00rootroot00000000000000--- - name: Fixture hosts: localhost tasks: - name: Fixture ansible.builtin.include_role: name: include_wrong_syntax ansible-ansible-lint-c16f018/examples/playbooks/conflicting_action.yml000066400000000000000000000006131477347356000262600ustar00rootroot00000000000000--- - hosts: localhost tasks: - name: Foo ansible.builtin.debug: msg: bar ansible.builtin.command: echo # On this file ansible-playbook --syntax-check reports: # ERROR! conflicting action statements: debug, command # # The error appears to be in 'test/conflicting_action.yml': line 3, column 7, but may # be elsewhere in the file depending on the exact syntax problem. ansible-ansible-lint-c16f018/examples/playbooks/conflicting_action2.yml000066400000000000000000000002351477347356000263420ustar00rootroot00000000000000--- - hosts: localhost gather_facts: false tasks: - block: include_role: tasks_from: ghe-config-apply.yml tags: - github ansible-ansible-lint-c16f018/examples/playbooks/contains_secrets.transformed.yml000066400000000000000000000012441477347356000303160ustar00rootroot00000000000000--- - name: Fixture hosts: localhost vars: plain: hello123 # spell-checker: disable-next-line # just 'hello123' encrypted with 'letmein' for test purposes secret: !vault | $ANSIBLE_VAULT;1.1;AES256 63346434613163653866303630313238626164313961613935373137323639636333393338386232 3735313061316666343839343665383036623237353263310a623639336530383433343833653138 30393032393534316164613834393864616566646164363830316664623636643731383164376163 3736653037356435310a303533383533353739323834343637366438633766666163656330343631 3066 tasks: - name: Just a debug task ansible.builtin.debug: msg: hello world ansible-ansible-lint-c16f018/examples/playbooks/contains_secrets.yml000066400000000000000000000012441477347356000257730ustar00rootroot00000000000000--- - name: Fixture hosts: localhost vars: plain: hello123 # spell-checker: disable-next-line # just 'hello123' encrypted with 'letmein' for test purposes secret: !vault | $ANSIBLE_VAULT;1.1;AES256 63346434613163653866303630313238626164313961613935373137323639636333393338386232 3735313061316666343839343665383036623237353263310a623639336530383433343833653138 30393032393534316164613834393864616566646164363830316664623636643731383164376163 3736653037356435310a303533383533353739323834343637366438633766666163656330343631 3066 tasks: - name: Just a debug task ansible.builtin.debug: msg: hello world ansible-ansible-lint-c16f018/examples/playbooks/custom_module.yml000066400000000000000000000002511477347356000253010ustar00rootroot00000000000000--- - name: Fixture hosts: localhost gather_facts: false tags: - "{{ foo }}" tasks: - name: Run custom module # noqa: fqcn[action] fake_module: {} ansible-ansible-lint-c16f018/examples/playbooks/deep/000077500000000000000000000000001477347356000226165ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/deep/empty.yml000066400000000000000000000001541477347356000244770ustar00rootroot00000000000000--- - name: some playbook with incorrect name # <- should raise name[casing] hosts: localhost tasks: [] ansible-ansible-lint-c16f018/examples/playbooks/ematcher-rule.yml000066400000000000000000000003631477347356000251630ustar00rootroot00000000000000--- - hosts: localhost name: BANNED - hosts: localhost name: Another BANNED line tasks: - name: Foo debug: msg: A 3rd BANNED line - name: Bar ansible.builtin.command: echo something changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/empty_playbook.yml000066400000000000000000000002011477347356000254530ustar00rootroot00000000000000# an empty playbook which makes ansible-playbook --syntax-check report # ERROR! Empty playbook, nothing to do # with exit code 4 ansible-ansible-lint-c16f018/examples/playbooks/example.yml000066400000000000000000000026111477347356000240570ustar00rootroot00000000000000--- - name: Fixture for test_example hosts: webservers vars: old_school: 1.2.3 bracket: and close bracket tasks: - name: Unset variable action: ansible.builtin.command echo {{this_variable}} is not set in this playbook - name: Trailing whitespace action: ansible.builtin.command echo do nothing - name: Run git check action: ansible.builtin.git a=b c=d - name: Run git check 2 action: ansible.builtin.git version=HEAD c=d - name: Run git check 3 ansible.builtin.git: version=a1b2c3d4 repo=xyz bobbins=d - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command chdir=bobbins creates=whatever /usr/bin/git clone blah - name: Using git module action: ansible.builtin.git repo=blah - name: Passing git as an argument to another task action: ansible.builtin.debug msg="{{item}}" with_items: - git # yamllint wrong indentation - bobbins - name: Dnf latest ansible.builtin.dnf: state=latest name=httpd - ansible.builtin.debug: msg="debug task without a name" - name: Run apt latest ansible.builtin.apt: state=latest name=apache2 - ansible.builtin.meta: flush_handlers # empty task is currently accepted by ansible as valid code but not our schemas: - ansible-ansible-lint-c16f018/examples/playbooks/extra_vars.yml000066400000000000000000000003771477347356000246110ustar00rootroot00000000000000--- - name: Fixture for test_extra_vars_passed_to_command test hosts: all tags: - baz - "{{ foo }}" tasks: - name: Show `complex_variable` value loaded from `extra_vars` ansible.builtin.debug: msg: "{{ complex_variable }}" ansible-ansible-lint-c16f018/examples/playbooks/filter_plugins/000077500000000000000000000000001477347356000247275ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/filter_plugins/some_filter.py000066400000000000000000000005051477347356000276110ustar00rootroot00000000000000"""Sample adjacent filter plugin.""" from __future__ import annotations class FilterModule: # pylint: disable=too-few-public-methods """Ansible filters.""" def filters(self): # type: ignore[no-untyped-def] """Return list of exposed filters.""" return { "some_filter": str, } ansible-ansible-lint-c16f018/examples/playbooks/find_children.yml000066400000000000000000000003631477347356000252160ustar00rootroot00000000000000--- # Bug reproducer https://github.com/ansible/ansible-lint/issues/2846 - name: Play hosts: localhost gather_facts: false connection: local roles: - role: acme.sample4 vars: date_ko_1: "{{ lookup('pipe', 'date') }}" ansible-ansible-lint-c16f018/examples/playbooks/fqcn.transformed.yml000066400000000000000000000013001477347356000256700ustar00rootroot00000000000000--- - name: FQCN transform test file hosts: localhost tasks: - name: Rewrite shell to ansible.builtin.shell via the fqcn[action-core] transform # noqa: command-instead-of-shell ansible.builtin.shell: echo This rule should get matched by the fqcn[action-core] rule changed_when: false - name: Rewrite openssh_keypair to community.crypto.openssh_keypair via the fqcn[action] transform community.crypto.openssh_keypair: path: /tmp/supersecret - name: Rewrite ansible.builtin.synchronize to ansible.posix.synchronize via the fqcn[canonical] transform ansible.posix.synchronize: src: dummy dest: dummy2 owner: false group: false ansible-ansible-lint-c16f018/examples/playbooks/fqcn.yml000066400000000000000000000012411477347356000233510ustar00rootroot00000000000000--- - name: FQCN transform test file hosts: localhost tasks: - name: Rewrite shell to ansible.builtin.shell via the fqcn[action-core] transform # noqa: command-instead-of-shell shell: echo This rule should get matched by the fqcn[action-core] rule changed_when: false - name: Rewrite openssh_keypair to community.crypto.openssh_keypair via the fqcn[action] transform openssh_keypair: path: /tmp/supersecret - name: Rewrite ansible.builtin.synchronize to ansible.posix.synchronize via the fqcn[canonical] transform ansible.builtin.synchronize: src: dummy dest: dummy2 owner: false group: false ansible-ansible-lint-c16f018/examples/playbooks/handlers/000077500000000000000000000000001477347356000235015ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/handlers/empty.yml000066400000000000000000000000001477347356000253500ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/handlers/included-handlers.yml000066400000000000000000000003301477347356000276050ustar00rootroot00000000000000--- - name: Restart xyz # noqa: no-free-form fqcn[action-core] service: name=xyz state=restarted # see Issue #165 - name: Command handler issue 165 # noqa: fqcn[action-core] no-changed-when command: do something ansible-ansible-lint-c16f018/examples/playbooks/handlers/y.yml000066400000000000000000000001201477347356000244650ustar00rootroot00000000000000--- - name: Funny handler action: service name=funny state=started force=true ansible-ansible-lint-c16f018/examples/playbooks/import-failed-syntax-check.yml000066400000000000000000000001211477347356000275510ustar00rootroot00000000000000--- - name: Import syntax-error.yml playbook import_playbook: syntax-error.yml ansible-ansible-lint-c16f018/examples/playbooks/import-nonexistent-playbook.yml000066400000000000000000000001161477347356000301260ustar00rootroot00000000000000--- - name: Import nonexistent playbook import_playbook: i-do-not-exist.yml ansible-ansible-lint-c16f018/examples/playbooks/import_playbook_fqcn.yml000066400000000000000000000003241477347356000266440ustar00rootroot00000000000000--- - name: Import a playbook ansible.builtin.import_playbook: local.testcollection.foo - name: Import a playbook that is in a subdirectory ansible.builtin.import_playbook: local.testcollection.test.bar.foo ansible-ansible-lint-c16f018/examples/playbooks/include-import-tasks-in-role.yml000066400000000000000000000001121477347356000300370ustar00rootroot00000000000000--- - name: Fixture hosts: all roles: - role_with_task_inclusions ansible-ansible-lint-c16f018/examples/playbooks/include-in-block.yml000066400000000000000000000002041477347356000255370ustar00rootroot00000000000000--- - name: Fixture hosts: all tasks: - name: Include ansible.builtin.include_tasks: tasks/include-in-block-inner.yml ansible-ansible-lint-c16f018/examples/playbooks/include.yml000066400000000000000000000006371477347356000240550ustar00rootroot00000000000000--- - hosts: bobbins pre_tasks: - ansible.builtin.include_tasks: tasks/x.yml roles: - hello - { role: more_complex, t: z } tasks: - ansible.builtin.include_tasks: tasks/x.yml - ansible.builtin.include_tasks: tasks/x.yml y=z - ansible.builtin.include_tasks: file=tasks/x.yml handlers: - ansible.builtin.include_tasks: handlers/y.yml - ansible.builtin.include_tasks: play.yml ansible-ansible-lint-c16f018/examples/playbooks/incorrect_module_args.yml000066400000000000000000000002441477347356000267750ustar00rootroot00000000000000--- - name: Demonstrate linting issue. hosts: all tasks: - name: Include a role with the wrong syntax ansible.builtin.include_role: role: foo ansible-ansible-lint-c16f018/examples/playbooks/invalid-transform.yml000066400000000000000000000003151477347356000260620ustar00rootroot00000000000000# yamllint disable-file --- - name: Test hosts: localhost gather_facts: false tasks: - name: Print hello message ansible.builtin.debug: msg: "Hello!" register: vm_output ansible-ansible-lint-c16f018/examples/playbooks/jinja-nested-vars.yml000066400000000000000000000003521477347356000257500ustar00rootroot00000000000000--- - name: Test gather_facts: false hosts: - localhost tasks: - name: Test ansible.builtin.debug: msg: "{{ cron_hour_raw }}" vars: cron_hour_raw: "{{ 12 | random(seed=inventory_hostname) }}" ansible-ansible-lint-c16f018/examples/playbooks/jinja-spacing.yml000066400000000000000000000062151477347356000251450ustar00rootroot00000000000000--- # Should raise jinja[spacing] at tasks line 23, 26, 29, 54, 65 - name: Fixture for testing jinja2[spacing] hosts: all tasks: - name: Good variable format ansible.builtin.debug: msg: "{{ good_format }}" - name: Good variable format ansible.builtin.debug: msg: "Value: {{ good_format }}" - name: Good variable filter format ansible.builtin.debug: msg: "{{ good_format | filter }}" - name: Good variable filter format ansible.builtin.debug: msg: "Value: {{ good_format | filter }}" - name: Jinja escaping allowed ansible.builtin.debug: msg: "{{ '{{' }}" - name: Jinja escaping allowed # noqa: risky-shell-pipe ansible.builtin.shell: docker info --format '{{ '{{' }}json .Swarm.LocalNodeState{{ '}}' }}' | tr -d '"' changed_when: false - name: Jinja whitespace control allowed ansible.builtin.debug: msg: | {{ good_format }}/ {{- good_format }} {{- good_format -}} - name: Bad variable format ansible.builtin.debug: msg: "{{bad_format}}" # <-- 1 - name: Bad variable format ansible.builtin.debug: msg: "Value: {{ bad_format}}" # <-- 2 - name: Bad variable format ansible.builtin.debug: msg: "{{bad_format }}" # <-- 3 - name: Bad variable filter format ansible.builtin.debug: msg: "{{ bad_format|filter }}" # <-- 4 - name: Bad variable filter format ansible.builtin.debug: msg: "Value: {{ bad_format |filter }}" # <-- 5 - name: Bad variable filter format ansible.builtin.debug: msg: "{{ bad_format| filter }}" # <-- 6 - name: Not a jinja variable # noqa: jinja[spacing] ansible.builtin.debug: # spell-checker: disable-next-line msg: data = ${lookup{$local_part}lsearch{/etc/aliases}} - name: JSON inside jinja is valid ansible.builtin.debug: msg: "{{ {'test': {'subtest': variable}} }}" - name: Avoid false positive on multiline vars: cases: case1: >- http://foo.com/{{ case1 }} case2: >- http://bar.com/{{ case2 }} ansible.builtin.debug: var: cases - name: Valid single line nested JSON false positive ansible.builtin.debug: msg: "{{ {'dummy_2': {'nested_dummy_1': 'value_1', 'nested_dummy_2': value_2}} | combine(dummy_1) }}" - name: Invalid single line nested JSON ansible.builtin.debug: msg: "{{ {'dummy_2': {'nested_dummy_1': 'value_1', 'nested_dummy_2': value_2}} | combine(dummy_1)}}" # <-- 7 - name: Valid multiline nested JSON false positive ansible.builtin.debug: msg: >- {{ {'dummy_2': {'nested_dummy_1': value_1, 'nested_dummy_2': value_2}} | combine(dummy_1) }} - name: Invalid multiline nested JSON ansible.builtin.debug: # not an error currently because current implementation skips multiline expressions msg: >- {{ {'dummy_2': {'nested_dummy_1': value_1, 'nested_dummy_2': value_2}} | combine(dummy_1)}} ansible-ansible-lint-c16f018/examples/playbooks/json-schema-fail.yml000066400000000000000000000001641477347356000255450ustar00rootroot00000000000000--- - name: This should raise json-schema error, due to hosts missing the last letter host: localhost tasks: [] ansible-ansible-lint-c16f018/examples/playbooks/lots_of_warnings.transformed.yml000066400000000000000000001343631477347356000303360ustar00rootroot00000000000000--- # This playbook causes ansible-lint to output tons of warnings # Enough to exceed typical stdout buffering size and thus to show the need for # catching IOError (EPIPE) errors. - name: Fixture hosts: webservers tasks: - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah ansible-ansible-lint-c16f018/examples/playbooks/lots_of_warnings.yml000066400000000000000000001343631477347356000260130ustar00rootroot00000000000000--- # This playbook causes ansible-lint to output tons of warnings # Enough to exceed typical stdout buffering size and thus to show the need for # catching IOError (EPIPE) errors. - name: Fixture hosts: webservers tasks: - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah - name: Executing git through command action: ansible.builtin.command git clone blah ansible-ansible-lint-c16f018/examples/playbooks/mocked_dependency.yml000066400000000000000000000003651477347356000260700ustar00rootroot00000000000000--- - hosts: localhost roles: - mocked_role - fake_namespace.fake_collection.fake_role tasks: - name: Some task zuul_return: {} - name: Mocked module from collection fake_namespace.fake_collection.fake_module: {} ansible-ansible-lint-c16f018/examples/playbooks/module_relative_import.yml000066400000000000000000000002421477347356000271740ustar00rootroot00000000000000--- - name: Module relative import hosts: localhost tasks: - name: Module with relative import local.testcollection.module_with_relative_import: {} ansible-ansible-lint-c16f018/examples/playbooks/multi_yaml_doc.transformed.yml000066400000000000000000000010731477347356000277510ustar00rootroot00000000000000--- - name: First problematic play hosts: localhost tasks: - name: Echo a message ansible.builtin.shell: echo hello # <-- command-instead-of-shell changed_when: false --- - name: second problematic play # <-- name[casing] hosts: localhost tasks: - name: Remove file (delete file) ansible.builtin.file: path: /etc/foo.txt state: absent --- - name: Third problematic play hosts: localhost tasks: - name: Remove file (delete file) file: # <-- fqcn[action-core] path: /etc/foo.txt state: absent ansible-ansible-lint-c16f018/examples/playbooks/multi_yaml_doc.yml000066400000000000000000000010731477347356000254260ustar00rootroot00000000000000--- - name: First problematic play hosts: localhost tasks: - name: Echo a message ansible.builtin.shell: echo hello # <-- command-instead-of-shell changed_when: false --- - name: second problematic play # <-- name[casing] hosts: localhost tasks: - name: Remove file (delete file) ansible.builtin.file: path: /etc/foo.txt state: absent --- - name: Third problematic play hosts: localhost tasks: - name: Remove file (delete file) file: # <-- fqcn[action-core] path: /etc/foo.txt state: absent ansible-ansible-lint-c16f018/examples/playbooks/multiline-brackets-do-not-match-test.yml000066400000000000000000000014631477347356000314730ustar00rootroot00000000000000--- - hosts: foo roles: - ../../../roles/base_os - ../../../roles/repos - { role: ../../../roles/openshift_master, oo_minion_ips: "{ hostvars['localhost'].oo_minion_ips | default(['']) }}", oo_bind_ip: "{{ hostvars[inventory_hostname].ansible_eth0.ipv4.address | default(['']) }}" } - ../../../roles/pods - name: Set Origin specific facts on localhost (for later use) hosts: localhost gather_facts: false tasks: - name: Setting oo_minion_ips fact on localhost ansible.builtin.set_fact: oo_minion_ips: "{{ hostvars | oo_select_keys(groups['tag_env-host-type-' + oo_env + '-openshift-minion']) | oo_collect(attribute='ansible_eth0.ipv4.address') }" when: groups['tag_env-host-type-' + oo_env + '-openshift-minion'] is defined ansible-ansible-lint-c16f018/examples/playbooks/multiline-bracketsmatchtest.yml000066400000000000000000000014651477347356000301450ustar00rootroot00000000000000--- - hosts: foo roles: - ../../../roles/base_os - ../../../roles/repos - { role: ../../../roles/openshift_master, oo_minion_ips: "{{ hostvars['localhost'].oo_minion_ips | default(['']) }}", oo_bind_ip: "{{ hostvars[inventory_hostname].ansible_eth0.ipv4.address | default(['']) }}" } - ../../../roles/pods - name: Set Origin specific facts on localhost (for later use) hosts: localhost gather_facts: false tasks: - name: Setting oo_minion_ips fact on localhost ansible.builtin.set_fact: oo_minion_ips: "{{ hostvars | oo_select_keys(groups['tag_env-host-type-' + oo_env + '-openshift-minion']) | oo_collect(attribute='ansible_eth0.ipv4.address') }}" when: groups['tag_env-host-type-' + oo_env + '-openshift-minion'] is defined ansible-ansible-lint-c16f018/examples/playbooks/name-case.transformed.yml000066400000000000000000000013471477347356000266050ustar00rootroot00000000000000--- - name: This lacks a capitalization hosts: localhost tasks: - name: Task that always changes ansible.builtin.debug: msg: I always change! changed_when: true notify: My handler - name: Task with notify as list ansible.builtin.debug: msg: I always change! changed_when: true notify: - my handler 1 - My handler - my handler 2 - name: Task without notify ansible.builtin.debug: msg: I always change! changed_when: true handlers: - name: My handler ansible.builtin.debug: msg: I never run :( - name: Test task for listen ansible.builtin.debug: msg: I never run :( listen: My handler ansible-ansible-lint-c16f018/examples/playbooks/name-case.yml000066400000000000000000000013511477347356000242550ustar00rootroot00000000000000--- - name: this lacks a capitalization hosts: localhost tasks: - name: Task that always changes ansible.builtin.debug: msg: I always change! changed_when: true notify: my handler - name: Task with notify as list ansible.builtin.debug: msg: I always change! changed_when: true notify: - my handler 1 - my handler - my handler 2 - name: Task without notify ansible.builtin.debug: msg: I always change! changed_when: true handlers: - name: my handler ansible.builtin.debug: msg: I never run :( - name: Test task for listen ansible.builtin.debug: msg: I never run :( listen: "my handler" ansible-ansible-lint-c16f018/examples/playbooks/no_handler_fail.yml000066400000000000000000000014611477347356000255320ustar00rootroot00000000000000--- - name: Fixture for no-handler rule hosts: all tasks: - name: This should trigger no-handler rule # noqa: no-changed-when ansible.builtin.command: echo could be done better when: result is changed - name: Do anything # noqa: no-changed-when ansible.builtin.command: echo 123 when: - something.changed - name: This should be a handler ansible.builtin.debug: msg: why isn't this a handler when: result.changed - name: This should be a handler 3 # noqa: literal-compare ansible.builtin.debug: msg: why isn't this a handler when: result.changed == true - name: This should be a handler 4 # noqa: literal-compare ansible.builtin.debug: msg: why isn't this a handler when: result['changed'] == true ansible-ansible-lint-c16f018/examples/playbooks/no_handler_pass.yml000066400000000000000000000046611477347356000255720ustar00rootroot00000000000000--- - name: Fixture for no-handler-pass hosts: all tasks: - name: Execute something ansible.builtin.command: echo 123 register: result changed_when: true - name: Print helpful error message ansible.builtin.debug: var: result when: result.failed - name: Do something when hello is output ansible.builtin.debug: msg: why isn't this a handler when: result.stdout == "hello" - name: Never actually debug ansible.builtin.debug: var: result when: false - name: "Don't execute this step" ansible.builtin.debug: msg: "debug message" when: - false - name: Check when with a list ansible.builtin.debug: var: result when: - conditionA - conditionB - name: Check when with a list of size 1 ansible.builtin.debug: var: result when: - conditionA - name: Registering task 1 ansible.builtin.command: echo Hello register: r1 changed_when: true - name: Registering task 2 ansible.builtin.command: echo Hello register: r2 changed_when: true - name: Use when task # noqa: no-changed-when ansible.builtin.command: echo Hello when: r1.changed and r2.changed - name: Use when with or # noqa: no-changed-when ansible.builtin.command: echo Hello when: r1.changed or conditionA - name: Use when with list of conditions # noqa: no-changed-when ansible.builtin.command: echo Hello when: - r1.changed - conditionA - name: Registering task ansible.builtin.command: echo Hello register: r changed_when: true - name: When task not changed # noqa: no-changed-when ansible.builtin.command: echo Not changed when: not r.changed - name: Execute command # noqa: no-changed-when ansible.builtin.command: echo hello register: result - name: This should be a handler 2 ansible.builtin.debug: msg: why isn't this a handler when: result | changed handlers: # If this task would have being under 'tasks:' it should have triggered # the rule, but under 'handlers:' it should not. - name: Reproduce bug 3646 loop: "{{ _something_done.results }}" loop_control: label: "{{ item.item.name }}" when: item.changed ansible.builtin.debug: msg: "{{ item.item.name }} changed" ansible-ansible-lint-c16f018/examples/playbooks/no_relative_paths_fail.yml000066400000000000000000000012561477347356000271310ustar00rootroot00000000000000--- - name: Fixture for no-relative-paths hosts: localhost tasks: - name: Template example # <-- 1st ansible.builtin.template: src: ../templates/foo.j2 dest: /etc/file.conf mode: "0644" - name: Copy example # <-- 2nd ansible.builtin.copy: src: ../files/foo.conf dest: /etc/foo.conf mode: "0644" # Removed from test suite as module is no longer part of core # - name: Some win_template example # win_template: # src: ../win_templates/file.conf.j2 # dest: file.conf # - name: Some win_copy example # win_copy: # src: ../files/foo.conf # dest: renamed-foo.conf ansible-ansible-lint-c16f018/examples/playbooks/no_relative_paths_pass.yml000066400000000000000000000006101477347356000271550ustar00rootroot00000000000000--- - name: Fixture for no-relative-paths hosts: localhost tasks: - name: Content example with no src ansible.builtin.copy: content: "# This file was moved to /etc/other.conf" dest: /etc/mine.conf mode: "0644" - name: Copy example ansible.builtin.copy: src: /home/example/files/foo.conf dest: /etc/foo.conf mode: "0644" ansible-ansible-lint-c16f018/examples/playbooks/nodeps.yml000066400000000000000000000001631477347356000237140ustar00rootroot00000000000000--- - name: Example hosts: localhost tasks: - name: Calling a module that is not installed a.b.c: {} ansible-ansible-lint-c16f018/examples/playbooks/nodeps2.yml000066400000000000000000000003111477347356000237710ustar00rootroot00000000000000--- - name: Fixture for nodeps with missing filter hosts: localhost tasks: - name: Calling a module that is not installed ansible.builtin.debug: msg: "{{ foo | missing_filter }}" ansible-ansible-lint-c16f018/examples/playbooks/nomatches.yml000066400000000000000000000003271477347356000244070ustar00rootroot00000000000000--- - hosts: whatever tasks: - name: Hello world ansible.builtin.action: debug msg="Hello!" - name: This should be fine too ansible.builtin.action: file state=touch mode=0644 dest=./wherever ansible-ansible-lint-c16f018/examples/playbooks/nomatchestest.transformed.yml000066400000000000000000000003721477347356000276320ustar00rootroot00000000000000--- - name: Fixture hosts: whatever tasks: - name: Hello world action: debug msg="Hello!" # noqa: fqcn[action-core] - name: This should be fine too action: file state=touch dest=./wherever mode=0600 # noqa: fqcn[action-core] ansible-ansible-lint-c16f018/examples/playbooks/nomatchestest.yml000066400000000000000000000003721477347356000253070ustar00rootroot00000000000000--- - name: Fixture hosts: whatever tasks: - name: Hello world action: debug msg="Hello!" # noqa: fqcn[action-core] - name: This should be fine too action: file state=touch dest=./wherever mode=0600 # noqa: fqcn[action-core] ansible-ansible-lint-c16f018/examples/playbooks/noqa-nested.yml000066400000000000000000000003561477347356000246460ustar00rootroot00000000000000--- - hosts: localhost tasks: - name: Example of multi-level block block: - name: 2nd level block: - ansible.builtin.debug: # noqa: name[missing] msg: "test unnamed task in block" ansible-ansible-lint-c16f018/examples/playbooks/noqa.yml000066400000000000000000000003201477347356000233550ustar00rootroot00000000000000--- - hosts: localhost tasks: - name: This would typically fire latest[git] and partial-become become_user: alice # noqa: latest[git] partial-become git: src=/path/to/git/repo dest=checkout ansible-ansible-lint-c16f018/examples/playbooks/norole.yml000066400000000000000000000000671477347356000237250ustar00rootroot00000000000000--- - hosts: - localhost roles: - name: node ansible-ansible-lint-c16f018/examples/playbooks/norole2.yml000066400000000000000000000000671477347356000240070ustar00rootroot00000000000000--- - hosts: - localhost roles: - name: node ansible-ansible-lint-c16f018/examples/playbooks/package-check-failure.yml000066400000000000000000000012301477347356000265130ustar00rootroot00000000000000--- - hosts: localhost tasks: - name: Install ansible ansible.builtin.yum: name=ansible state=latest - name: Install ansible-lint ansible.builtin.pip: name=ansible-lint args: state: latest - name: Install some-package ansible.builtin.package: name: some-package state: latest - name: Install ansible with update_only to false ansible.builtin.yum: name: sudo state: latest update_only: false - name: Install ansible with only_upgrade to false ansible.builtin.apt: name: sudo state: latest upgrade: true only_upgrade: false ansible-ansible-lint-c16f018/examples/playbooks/package-check-success.yml000066400000000000000000000012021477347356000265330ustar00rootroot00000000000000--- - hosts: localhost tasks: - name: Install ansible ansible.builtin.yum: name=ansible-2.1.0.0 state=present - name: Install ansible-lint ansible.builtin.pip: name=ansible-lint args: state: present version: 3.1.2 - name: Install some-package ansible.builtin.package: name: Some-package state: present - name: Update ansible ansible.builtin.yum: name: sudo state: latest update_only: true - name: Upgrade ansible ansible.builtin.apt: name: sudo state: latest upgrade: true only_upgrade: true ansible-ansible-lint-c16f018/examples/playbooks/pass-loop-var-prefix.yml000066400000000000000000000006211477347356000264210ustar00rootroot00000000000000--- - hosts: localhost tasks: # validate that we did not trigger loop-var-prefix on playbooks - name: That should pass ansible.builtin.debug: var: item loop: - foo - bar - name: A block block: - name: That should also pass ansible.builtin.debug: var: item loop: - apples - oranges ansible-ansible-lint-c16f018/examples/playbooks/play-without-extension000066400000000000000000000001151477347356000263010ustar00rootroot00000000000000- name: A playbook without expected yml or yaml extension hosts: localhost ansible-ansible-lint-c16f018/examples/playbooks/play.yml000066400000000000000000000001611477347356000233670ustar00rootroot00000000000000--- - hosts: bobbins tasks: - name: A bad play action: ansible.builtin.command service blah restart ansible-ansible-lint-c16f018/examples/playbooks/play_miss_include.yml000066400000000000000000000000751477347356000261310ustar00rootroot00000000000000--- - name: Fixture hosts: all roles: - include_miss ansible-ansible-lint-c16f018/examples/playbooks/playbook-imported.yml000066400000000000000000000004061477347356000260650ustar00rootroot00000000000000--- - name: Fixture hosts: localhost connection: local gather_facts: false tasks: - ansible.builtin.command: cmd: echo "no name" # should generate name[missing] - name: Another task ansible.builtin.debug: msg: debug message ansible-ansible-lint-c16f018/examples/playbooks/playbook-parent.yml000066400000000000000000000004671477347356000255420ustar00rootroot00000000000000--- - name: Importing another playbook ansible.builtin.import_playbook: playbook-imported.yml - name: Importing playbook from collection import_playbook: community.molecule.validate # noqa: fqcn - name: Importing playbook using jinja2 import_playbook: "{{ 'community.molecule.validate' }}" # noqa: fqcn ansible-ansible-lint-c16f018/examples/playbooks/removed-include.yml000066400000000000000000000002201477347356000255000ustar00rootroot00000000000000--- - name: Invalid playbook hosts: localhost tasks: - name: Foo include: tasks/simple_task.yml # <-- include was removed in 2.16 ansible-ansible-lint-c16f018/examples/playbooks/role_vars_prefix_detection.yml000066400000000000000000000022111477347356000300270ustar00rootroot00000000000000--- - name: Test role-prefix hosts: localhost connection: local roles: - role_vars_prefix_detection - role: role_vars_prefix_detection var1: val1 - role: role_vars_prefix_detection var1: val1 become: true vars: var2: val2 - role: role_vars_prefix_detection become: true environment: FOO: /bar/barr role_vars_prefix_detection_var1: val1 - role: role_vars_prefix_detection vars: var1: val1 - role: role_vars_prefix_detection become: true environment: BAR: /baz vars: var1: val1 - role: role_vars_prefix_detection become: true environment: BAR: /baz vars: role_vars_prefix_detection_var1: val1 tasks: - name: Include1 ansible.builtin.include_role: name: role_vars_prefix_detection vars: var1: val1 - name: Include2 ansible.builtin.include_role: name: role_vars_prefix_detection vars: role_vars_prefix_detection_var1: val1 _role_vars_prefix_detection_var2: val2 __role_vars_prefix_detection_var3: val3 ansible-ansible-lint-c16f018/examples/playbooks/roles000077700000000000000000000000001477347356000242252../rolesustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/rule-args-module-fail.yml000066400000000000000000000024601477347356000265230ustar00rootroot00000000000000--- - name: Fixture to validate module options failure scenarios hosts: localhost tasks: - name: Clone content repository # module should produce: 'missing required arguments: repo' ansible.builtin.git: dest: /home/www accept_hostkey: true version: master update: false - name: Enable service httpd and ensure it is not masked # module should produce: 'missing parameter(s) required by 'enabled': name' ansible.builtin.systemd: enabled: true masked: false - name: Enable service httpd and ensure it is not masked # module should produce: 'Unsupported parameters for ansible.builtin.systemd module" ansible.builtin.systemd: foo: true - name: An invalid call of setup module # setup module in ansible is the only module that has a .. relative # import that used to cause problems ansible.builtin.setup: foo: # this is a nested object which will have the __ injections # that we later need to clean bar: true - name: Remove deployment dir # module should produce: 'value of state must be one of: absent, directory, file, hard, link, touch, got: away' ansible.builtin.file: path: /opt/software/deployment state: away mode: "0600" ansible-ansible-lint-c16f018/examples/playbooks/rule-args-module-pass.yml000066400000000000000000000055461477347356000265660ustar00rootroot00000000000000--- - name: Fixture to validate module options pass scenario hosts: localhost tasks: - name: Clone content repository ansible.builtin.git: repo: "{{ archive_services_repo_url }}" dest: /home/www accept_hostkey: true version: master update: false - name: Enable service httpd and ensure it is not masked ansible.builtin.systemd: name: httpd enabled: false masked: false - name: Clear deployment dir ansible.builtin.file: path: /opt/software/deployment state: "{{ item }}" mode: "0755" with_items: - absent - directory - name: Bug https://github.com/ansible/ansible-lint/issues/2962 become: true ansible.builtin.apt_key: url: "{{ zj_item['url'] | default(omit) }}" data: "{{ zj_item['data'] | default(omit) }}" loop: "{{ repositories_keys }}" loop_control: loop_var: zj_item - name: Bug 2428 daemon_reload should be allowed ansible.builtin.systemd: name: foo state: restarted daemon_reload: true - name: Bug 2424 async_status ansible.builtin.async_status: jid: "{{ 999 }}" - name: Bug https://github.com/VSChina/vscode-ansible/issues/261 ansible.builtin.set_fact: dns_nameservers: "{{ var1 }}" - name: Bug cmd should be allowed ansible.builtin.command: cmd: echo "foo" changed_when: false - name: Bag another allowed form of command ansible.builtin.command: "/etc/test.sh" changed_when: false - name: Bug 3090 community.docker.docker_container_exec: container: foo argv: - /bin/bash - "-c" - "ls -lah > /dev/stderr" chdir: /root register: result - name: "Bug 3138" become: true ansible.builtin.service: name: "jenkins" state: started # 'use' is dropped by preprocessing ... use: "{{ ansible_service_mgr }}" changed_when: false - name: "Bug 3152" ansible.posix.synchronize: src: . dest: . owner: false group: false use_ssh_args: true - name: Create software directory (Windows module - Bug 3200) ansible.windows.win_file: path: "c:\\test_dir" state: directory - name: Ansible-lint for args rule should succeed (Bug - 3199) vars: copy_vars: src: "args.json" action: ansible.builtin.copy args: "{{ copy_vars }}" # since, we're unable to analyze jinja, we skip this kind of checks - name: Variable containing list of non-strings should pass (Bug 4229) community.general.mas: id: "{{ item }}" state: present loop: "{{ mas_app_ids }}" vars: mas_app_ids: - 409183694 - 409203825 - 409201541 ansible-ansible-lint-c16f018/examples/playbooks/rule-avoid-implicit-fail.yml000066400000000000000000000003511477347356000272130ustar00rootroot00000000000000--- - name: Example playbook hosts: localhost tasks: - name: Write file content ansible.builtin.copy: content: { "foo": "bar" } # <-- avoid-implicit[copy-content] dest: /tmp/foo.txt mode: "0600" ansible-ansible-lint-c16f018/examples/playbooks/rule-avoid-implicit-pass.yml000066400000000000000000000003061477347356000272460ustar00rootroot00000000000000--- - name: Example playbook hosts: localhost tasks: - name: Write file content ansible.builtin.copy: content: "Some {{ foo }}" dest: /tmp/foo.txt mode: "0600" ansible-ansible-lint-c16f018/examples/playbooks/rule-command-instead-of-module-fail.yml000066400000000000000000000006341477347356000312350ustar00rootroot00000000000000--- - name: Test fixture for command-instead-of-module hosts: localhost tasks: - name: Run apt-get update # <-- 1 ansible.builtin.command: apt-get update changed_when: false - name: Restart sshd # <-- 2 ansible.builtin.command: systemctl restart sshd changed_when: false - name: Run yum update # <-- 3 ansible.builtin.command: yum update changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/rule-command-instead-of-module-pass.yml000066400000000000000000000032021477347356000312620ustar00rootroot00000000000000--- - name: Test fixture for command-instead-of-module hosts: localhost tasks: - name: Print current git branch ansible.builtin.command: git branch changed_when: false - name: Print git log ansible.builtin.command: git log changed_when: false - name: Install git lfs support ansible.builtin.command: git lfs install changed_when: false - name: Clean git repo (dry run) ansible.builtin.command: git clean -n -d changed_when: false - name: Show systemctl service status ansible.builtin.command: systemctl status systemd-timesyncd changed_when: false - name: Show systemd environment ansible.builtin.command: systemctl show-environment changed_when: false - name: Get systemd runlevel ansible.builtin.command: systemctl get-default changed_when: false - name: Set systemd runlevel ansible.builtin.command: systemctl set-default multi-user.target changed_when: false - name: Kill service using SIGUSR1 ansible.builtin.command: systemctl kill --signal=SIGUSR1 sshd changed_when: false - name: Reset a service with systemctl reset-failed ansible.builtin.command: systemctl reset-failed sshd changed_when: false - name: Clear yum cache ansible.builtin.command: yum clean all changed_when: false - name: Clear yum cache ansible.builtin.command: "" changed_when: false - name: Print yum history ansible.builtin.command: yum history changed_when: false - name: Print yum info ansible.builtin.command: yum info bash changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/rule-command-instead-of-shell-fail.yml000066400000000000000000000011131477347356000310500ustar00rootroot00000000000000--- - name: Fixture hosts: localhost tasks: - name: Shell no pipe ansible.builtin.shell: cmd: echo hello changed_when: false - name: Shell with jinja filter ansible.builtin.shell: cmd: echo {{ "hello" | upper }} changed_when: false - name: Shell with jinja filter (fqcn) ansible.builtin.shell: cmd: echo {{ "hello" | upper }} changed_when: false - name: Command with executable parameter ansible.builtin.shell: cmd: clear args: executable: /bin/bash changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/rule-command-instead-of-shell-pass.yml000066400000000000000000000027361477347356000311170ustar00rootroot00000000000000--- - name: Fixture hosts: localhost tasks: - name: Shell with pipe ansible.builtin.shell: cmd: echo hello | true # noqa: risky-shell-pipe changed_when: false - name: Shell with redirect ansible.builtin.shell: cmd: echo hello > /tmp/hello changed_when: false - name: Chain two shell commands ansible.builtin.shell: cmd: echo hello && echo goodbye changed_when: false - name: Run commands in succession ansible.builtin.shell: cmd: echo hello ; echo goodbye changed_when: false - name: Use variables ansible.builtin.shell: cmd: echo $HOME $USER changed_when: false - name: Use * for globbing ansible.builtin.shell: cmd: ls foo* changed_when: false - name: Use ? for globbing ansible.builtin.shell: cmd: ls foo? changed_when: false - name: Use [] for globbing ansible.builtin.shell: cmd: ls foo[1,2,3] changed_when: false - name: Use shell generator ansible.builtin.shell: cmd: ls foo{.txt,.xml} changed_when: false - name: Use backticks ansible.builtin.shell: cmd: ls `ls foo*` changed_when: false - name: Use shell with cmd ansible.builtin.shell: cmd: | set -x ls foo? changed_when: false - name: Use ! for negation ansible.builtin.shell: cmd: "! crontab -l" changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/rule-complexity-fail.yml000066400000000000000000000020321477347356000264740ustar00rootroot00000000000000--- # no of tasks required are 5 and since there are 6 tasks it will give an error - name: Test Fixture complexity rule hosts: all tasks: - name: Task 1 ansible.builtin.debug: msg: "This is task 1" - name: Task 2 ansible.builtin.debug: msg: "This is task 2" - name: Task 3 ansible.builtin.debug: msg: "This is task 3" - name: Task 4 ansible.builtin.debug: msg: "This is task 4" - name: Task 5 ansible.builtin.debug: msg: "This is task 5" - name: Task 6 ansible.builtin.debug: msg: "This is task 6" - name: Block Task 7 block: - name: 2nd level block block: - name: 3rd level block block: - name: 4th level block block: - name: 5th level block block: - name: Nested Task 1 ansible.builtin.debug: msg: "This is nested task 1" ansible-ansible-lint-c16f018/examples/playbooks/rule-complexity-pass.yml000066400000000000000000000015721477347356000265370ustar00rootroot00000000000000--- - name: Test fixture complexity rule hosts: all tasks: - name: Task 1 ansible.builtin.debug: msg: "This is task 1" - name: Task 2 ansible.builtin.debug: msg: "This is task 2" - name: Task 3 ansible.builtin.debug: msg: "This is task 3" - name: Task 4 ansible.builtin.debug: msg: "This is task 4" - name: Task 5 block: - name: Include under block level 1 ansible.builtin.debug: msg: "This is nested block" - name: Block level 2 block: - name: Include under block level 2 ansible.builtin.debug: msg: "This is block 2" - name: Block level 3 block: - name: INCLUDE under block level 3 ansible.builtin.debug: msg: "This is block 3" ansible-ansible-lint-c16f018/examples/playbooks/rule-deprecated-bare-vars-fail.yml000066400000000000000000000040741477347356000302670ustar00rootroot00000000000000--- - name: Fixture for deprecated-bare-vars rule hosts: localhost become: false vars: my_list: - foo - bar my_list2: - 1 - 2 my_list_of_dicts: - foo: 1 bar: 2 - foo: 3 bar: 4 my_list_of_lists: - "{{ my_list }}" - "{{ my_list2 }}" my_filenames: - foo.txt - bar.txt my_dict: foo: bar tasks: - name: Use with_items loop using bare variable ansible.builtin.debug: msg: "{{ item }}" with_items: my_list - name: Use with_dict loop using bare variable ansible.builtin.debug: msg: "{{ item }}" with_dict: my_dict - name: Use with_nested loop using bare variable ansible.builtin.debug: msg: "{{ item.0 }} {{ item.1 }}" with_nested: - my_list - "{{ my_list2 }}" - name: Use with_nested loop using bare variable ansible.builtin.debug: msg: "{{ item.0 }} {{ item.1 }}" with_nested: "my_list2" - name: Use with_file loop using bare variable ansible.builtin.debug: msg: "{{ item }}" with_file: my_list - name: Use with_fileglob loop using bare variable ansible.builtin.debug: msg: "{{ item }}" with_fileglob: my_list - name: Use with_together loop using bare variable ansible.builtin.debug: msg: "{{ item.0 }} {{ item.1 }}" with_together: - my_list - "{{ my_list2 }}" - name: Use with_subelements loop using bare variable ansible.builtin.debug: msg: "{{ item.0 }}" with_subelements: - my_list_of_dicts - bar - name: Use with_random_choice loop using bare variable ansible.builtin.debug: msg: "{{ item }}" with_random_choice: my_list - name: Use with_first_found loop using bare variable ansible.builtin.debug: msg: "{{ item }}" with_first_found: my_filenames - name: Use with_indexed_items loop ansible.builtin.debug: msg: "{{ item.0 }} {{ item.1 }}" with_indexed_items: my_list ansible-ansible-lint-c16f018/examples/playbooks/rule-deprecated-bare-vars-pass.yml000066400000000000000000000110701477347356000303140ustar00rootroot00000000000000--- - name: Using bare variables success hosts: localhost become: false vars: my_list: - foo - bar my_list2: - 1 - 2 my_list_of_dicts: - foo: 1 bar: 2 - foo: 3 bar: 4 my_list_of_lists: - "{{ my_list }}" - "{{ my_list2 }}" my_filenames: - foo.txt - bar.txt my_dict: foo: bar tasks: ### Testing with_items loops - name: Use with_items loop using static list ansible.builtin.debug: msg: "{{ item }}" with_items: - foo - bar - name: Use with_items using a static hash ansible.builtin.debug: msg: "{{ item.key }} - {{ item.value }}" with_items: - { key: foo, value: 1 } - { key: bar, value: 2 } - name: Use with_items loop using variable ansible.builtin.debug: msg: "{{ item }}" with_items: "{{ my_list }}" ### Testing with_nested loops - name: Use with_nested loop using static lists ansible.builtin.debug: msg: "{{ item[0] }} - {{ item[1] }}" with_nested: - [foo, bar] - ["1", "2", "3"] - name: Use with_nested loop using variable list and static ansible.builtin.debug: msg: "{{ item[0] }} - {{ item[1] }}" with_nested: - "{{ my_list }}" - ["1", "2", "3"] ### Testing with_dict - name: Use with_dict loop using variable ansible.builtin.debug: msg: "{{ item.key }} - {{ item.value }}" with_dict: "{{ my_dict }}" ### Testing with_dict with a default empty dictionary - name: Use with_dict loop using variable and default ansible.builtin.debug: msg: "{{ item.key }} - {{ item.value }}" with_dict: "{{ uwsgi_ini | default({}) }}" ### Testing with_file - name: Use with_file loop using static files list ansible.builtin.debug: msg: "{{ item }}" with_file: - foo.txt - bar.txt - name: Use with_file loop using list of filenames ansible.builtin.debug: msg: "{{ item }}" with_file: "{{ my_filenames }}" ### Testing with_fileglob - name: Use with_fileglob loop using list of *.txt ansible.builtin.debug: msg: "{{ item }}" with_fileglob: - "*.txt" ### Testing non-list form of with_fileglob - name: Use with_fileglob loop using single value *.txt ansible.builtin.debug: msg: "{{ item }}" with_fileglob: "*.txt" ### Testing non-list form of with_fileglob with trailing templated pattern - name: Use with_fileglob loop using templated pattern ansible.builtin.debug: msg: "{{ item }}" with_fileglob: foo{{ glob }} ### Testing with_together - name: Use with_together loop using variable lists ansible.builtin.debug: msg: "{{ item.0 }} - {{ item.1 }}" with_together: - "{{ my_list }}" - "{{ my_list2 }}" - name: Use with_subelements loop ansible.builtin.debug: msg: "{{ item }}" with_subelements: - "{{ my_list_of_dicts }}" - bar - name: Use with_sequence loop ansible.builtin.debug: msg: "{{ item }}" with_sequence: count=2 - name: Use with_random_choice loop ansible.builtin.debug: msg: "{{ item }}" with_random_choice: "{{ my_list }}" - name: Use with_first_found loop with static files list ansible.builtin.debug: msg: "{{ item }}" with_first_found: - foo.txt - bar.txt - name: Use with_first_found loop with list of filenames ansible.builtin.debug: msg: "{{ item }}" with_first_found: "{{ my_filenames }}" - name: Use with_indexed_items loop ansible.builtin.debug: msg: "{{ item.0 }} {{ item.1 }}" with_indexed_items: "{{ my_list }}" - name: Use with_ini loop ansible.builtin.debug: msg: "{{ item }}" with_ini: value[1-2] section=section1 file=foo.ini re=true - name: Use with_inventory_hostnames loop ansible.builtin.debug: msg: "{{ item }}" with_inventory_hostnames: all - name: Test more complex jinja is also allowed ansible.builtin.debug: msg: "{{ item }}" with_items: >- {%- set ns = [1, 1, 2] -%} {{- ns.keys | unique -}} - name: Reproduce bug 3646 ansible.builtin.file: path: "{{ item.path }}" state: directory mode: "{{ item.mode }}" with_community.general.filetree: - "../templates/SpaceVim.d/" when: item.state == "directory" and ".git" not in item.path ansible-ansible-lint-c16f018/examples/playbooks/rule-deprecated-command-syntax.yml000066400000000000000000000002451477347356000304320ustar00rootroot00000000000000--- - name: Fixture hosts: localhost tasks: - name: Shell with pipe ansible.builtin.command: creates=/tmp/foo touch /tmp/foo changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/rule-deprecated-local-action-fail.yml000066400000000000000000000002371477347356000307470ustar00rootroot00000000000000--- - name: Fixture for deprecated-local-action hosts: localhost tasks: - name: Task example local_action: module: ansible.builtin.debug ansible-ansible-lint-c16f018/examples/playbooks/rule-empty-string-compare-fail.yml000066400000000000000000000011031477347356000303630ustar00rootroot00000000000000--- - name: Empty String Compare Fail hosts: all tasks: - name: Shut down # noqa no-changed-when ansible.builtin.command: /sbin/shutdown -t now when: ansible_os_family == "" - name: Shut down # noqa no-changed-when ansible.builtin.command: /sbin/shutdown -t now when: ansible_os_family !="" - name: Shut down # noqa no-changed-when ansible.builtin.command: /sbin/shutdown -t now when: false - name: Shut down # noqa no-changed-when ansible.builtin.command: /sbin/shutdown -t now when: [ansible_os_family == ""] ansible-ansible-lint-c16f018/examples/playbooks/rule-empty-string-compare-pass.yml000066400000000000000000000006071477347356000304260ustar00rootroot00000000000000--- - name: Empty string compare success hosts: all tasks: - name: Shut down ansible.builtin.shell: | /sbin/shutdown -t now echo $var == "" changed_when: false when: ansible_os_family - name: Shut down ansible.builtin.shell: | /sbin/shutdown -t now echo $var == "" changed_when: false when: [ansible_os_family] ansible-ansible-lint-c16f018/examples/playbooks/rule-fqcn-fail.yml000066400000000000000000000005571477347356000252400ustar00rootroot00000000000000--- - name: Fixture hosts: localhost collections: - community.general tasks: - name: Shell (fqcn[action-core]) # noqa: command-instead-of-shell shell: echo This rule should get matched by the fqcn rule changed_when: false - name: Shell (fqcn[action]) ini_file: section: foo path: /tmp/test.ini mode: "0644" ansible-ansible-lint-c16f018/examples/playbooks/rule-fqcn-pass.yml000066400000000000000000000007351477347356000252710ustar00rootroot00000000000000--- - name: Fixture hosts: localhost tasks: - name: Shell (fqcn) # noqa: command-instead-of-shell changed_when: false ansible.builtin.shell: echo This rule should not get matched by the fqcn rule - name: Use FQCN with more than 3 parts community.general.system.sudoers: name: should-not-be-here state: absent - name: Command with legacy FQCN ansible.legacy.command: echo This rule should not get matched by the fqcn rule ansible-ansible-lint-c16f018/examples/playbooks/rule-jinja-before.transformed.yml000066400000000000000000000003651477347356000302530ustar00rootroot00000000000000--- # https://github.com/ansible/ansible-lint/issues/3739 - name: Reproducer bug 3739 hosts: all tasks: - name: Generate keypair community.crypto.openssh_keypair: path: "{{ env.path }}" when: ( env.path is not none ) ansible-ansible-lint-c16f018/examples/playbooks/rule-jinja-before.yml000066400000000000000000000003631477347356000257260ustar00rootroot00000000000000--- # https://github.com/ansible/ansible-lint/issues/3739 - name: Reproducer bug 3739 hosts: all tasks: - name: Generate keypair community.crypto.openssh_keypair: path: "{{env.path}}" when: ( env.path is not none ) ansible-ansible-lint-c16f018/examples/playbooks/rule-jinja-fail.yml000066400000000000000000000007261477347356000254020ustar00rootroot00000000000000--- - name: Fixture hosts: localhost tasks: - name: A block used to check that we do not identify error at correct level block: - name: Foo # <-- this is valid jinja2 ansible.builtin.debug: foo: "{{ 1 }}" # <-- jinja2[spacing] msg: "{{ 'a' b }}" # <-- jinja2[invalid] # It should be noted that even ansible --syntax-check fails to spot the jinja # error above, but ansible will throw a runtime error when running ansible-ansible-lint-c16f018/examples/playbooks/rule-jinja-pass.yml000066400000000000000000000067161477347356000254420ustar00rootroot00000000000000--- # https://github.com/ansible/ansible-lint/issues/2464 # https://github.com/ansible/ansible-lint/issues/2462 # https://github.com/ansible/ansible-lint/issues/2459 - name: Fixture to test various jinja parsing bugs that we should ignore hosts: localhost tasks: - name: Foo {{ buildset_registry.host | ipwrap }} ansible.builtin.debug: msg: "{{ lookup('template', 'lookup/redis_server__env_ports.j2') | from_yaml }}" loop: "{{ github_release_query.results | subelements('json.assets', {'skip_missing': True}) }}" - name: Zoo ansible.builtin.debug: msg: "{{ lookup('ansible.builtin.ini', 'SOME_VAR', type='properties', file='/tmp/some-file') }}" - name: Generate Dovecot main configuration file ansible.builtin.template: src: '{{ lookup("template_src", "etc/dovecot/dovecot.conf.j2") }}' dest: "/etc/dovecot/dovecot.conf" owner: "root" group: "dovecot" mode: "0640" - name: Bug https://github.com/ansible/ansible-lint/issues/2569 ansible.builtin.include_tasks: file: /dev/null vars: ns_vars: {} x: "{{ lookup('ansible.builtin.template', 'namespace.yaml.j2', template_vars=ns_vars) | from_yaml }}" - name: Bug https://github.com/ansible/ansible-lint/issues/3048 ansible.builtin.set_fact: x: "{{ y.json | community.general.json_query(edition.version) }}" - name: Bug https://github.com/ansible/ansible-lint/issues/3769 ansible.builtin.debug: msg: "{{ 65534 | ansible.builtin.random(seed=inventory_hostname) }}" # https://github.com/ansible/ansible-lint/issues/2697 - name: Test linter hosts: localhost gather_facts: false tasks: - name: Passed linter ansible.builtin.debug: msg: "{{ test | to_json }}" vars: test: one: two param: "{{ ansible_host }}" - name: Failed linter ansible.builtin.debug: msg: "{{ test | to_json }}" vars: test: one: two param: no jinja - name: Bug https://github.com/ansible/ansible-lint/issues/3048 hosts: localhost tasks: - name: "Test for bug #3048" ansible.builtin.debug: msg: "{{ __my_var | mandatory }}" loop: "{{ a_var }}" loop_control: loop_var: __my_var vars: a_var: - one - name: Bugs hosts: localhost tasks: - name: Bug https://github.com/ansible/ansible-lint/issues/3082 ansible.builtin.copy: content: "{{ item.cfg | to_nice_yaml(indent=2, width=9999) }}" dest: "/tmp/{{ item.name }}.yaml" mode: "0640" with_items: - name: file2 - name: Bug https://github.com/ansible/ansible-lint/issues/3136 ansible.builtin.debug: msg: "IP is {{ foo | ansible.utils.ipaddr('address') }}" - name: "Bug https://github.com/ansible/ansible-lint/issues/3155" ansible.builtin.debug: msg: "Is changed:{{ date_cmd is changed }}" - name: Bug https://github.com/ansible/ansible-lint/issues/3908 ansible.builtin.debug: msg: "{{ foo | ansible.builtin.mandatory(msg='My message') }}" - name: Bugs https://github.com/ansible/ansible-lint/issues/4338 hosts: localhost tasks: - name: Test task ansible.builtin.debug: msg: "Hello, world!" when: false register: result - name: Test task 2 vars: counter: "{{ result is skipped | ternary(1, 2) }}" ansible.builtin.debug: msg: "Hello, world {{ counter }}!" ansible-ansible-lint-c16f018/examples/playbooks/rule-key-order-fail.yml000066400000000000000000000014051477347356000262030ustar00rootroot00000000000000--- - name: Fixture hosts: localhost tasks: - no_log: true ansible.builtin.command: echo hello name: Task with no_log on top changed_when: false - when: true name: Task with when on top ansible.builtin.command: echo hello changed_when: false - delegate_to: localhost name: Delegate_to on top ansible.builtin.command: echo hello changed_when: false - loop: - 1 - 2 name: Loopy ansible.builtin.command: echo {{ item }} changed_when: false - become: true name: Become first ansible.builtin.command: echo hello changed_when: false - register: test ansible.builtin.command: echo hello name: Register first changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/rule-key-order-pass.yml000066400000000000000000000007341477347356000262420ustar00rootroot00000000000000--- - name: Fixture for key-order rule hosts: localhost tasks: - name: Test ansible.builtin.command: echo "test" changed_when: false - name: Test2 ansible.builtin.debug: msg: "Debug without a name" - name: Flush handlers ansible.builtin.meta: flush_handlers - no_log: true # noqa: key-order[task] command-instead-of-shell ansible.builtin.shell: echo hello name: Task with no_log on top changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/rule-name-casing.yml000066400000000000000000000005631477347356000255570ustar00rootroot00000000000000--- - name: Fixture for src/ansiblelint/rules/name.py::test_rule_name_lowercase hosts: all tasks: - name: this task has a name is not correctly capitalized ansible.builtin.command: echo "Hello World" changed_when: false - name: 测试 should not trigger name[case] rule! ansible.builtin.command: echo "Hello World" changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/rule-name-missing-fail.yml000066400000000000000000000006121477347356000266700ustar00rootroot00000000000000--- - hosts: all # <-- name[missing] tasks: - ansible.builtin.command: echo "no name" # <-- name[missing] changed_when: false - name: "" # <-- name[missing] ansible.builtin.command: echo "empty name" changed_when: false - ansible.builtin.debug: # <-- name[missing] msg: Debug without a name - ansible.builtin.meta: flush_handlers # <-- name[missing] ansible-ansible-lint-c16f018/examples/playbooks/rule-name-missing-pass.yml000066400000000000000000000006261477347356000267300ustar00rootroot00000000000000--- - name: Play for testing name[missing] rule hosts: all tasks: - name: This task has a name ansible.builtin.command: echo "Hello World" # noqa: no-free-form changed_when: false - name: Debug task with name ansible.builtin.debug: msg="Hello World" # noqa: no-free-form - name: Flush handler with name ansible.builtin.meta: flush_handlers changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/rule-name-play-fail.yml000066400000000000000000000000671477347356000261700ustar00rootroot00000000000000--- - hosts: localhost # <-- name[missing] tasks: [] ansible-ansible-lint-c16f018/examples/playbooks/rule-name-templated-fail.yml000066400000000000000000000010231477347356000271730ustar00rootroot00000000000000--- - name: Fixture for src/ansiblelint/rules/name.py::test_name_template( hosts: all tasks: - name: This task {{ sampleService }} name is not correctly templated ansible.builtin.command: echo "Hello World" changed_when: false - name: This task is correctly templated {{ sampleService }} ansible.builtin.command: echo "Hello World" changed_when: false - name: This task is correctly templated '{{ sampleService }}' ansible.builtin.command: echo "Hello World" changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/rule-no-changed-when-fail.yml000066400000000000000000000010351477347356000272430ustar00rootroot00000000000000--- - name: Fixture for no-changed-when (fail with 3 occurrences) hosts: all tasks: - name: Register command output, but cat still does not change anything ansible.builtin.command: cat {{ my_file | quote }} register: my_output - name: Block level 1 block: - name: Block level 2 block: - name: Basic command task, should fail ansible.builtin.command: cat my_file - name: Basic shell task, should fail shell: cat my_file # noqa: fqcn command-instead-of-shell ansible-ansible-lint-c16f018/examples/playbooks/rule-no-changed-when-pass.yml000066400000000000000000000014461477347356000273040ustar00rootroot00000000000000--- - name: Fixture for no-changed-when (pass) hosts: all tasks: - name: Handle command output with return code # noqa: command-instead-of-shell ansible.builtin.command: cat {{ my_file | quote }} register: my_output changed_when: my_output.rc != 0 - name: Handle shell output with return code # noqa: command-instead-of-shell ansible.builtin.shell: cat {{ my_file | quote }} register: my_output changed_when: my_output.rc != 0 - name: Handle shell output with false changed_when # noqa: command-instead-of-shell ansible.builtin.shell: cat {{ my_file | quote }} register: my_output changed_when: false - name: Command with argument command: createfile.sh # noqa: fqcn args: creates: /tmp/????unknown_files???? ansible-ansible-lint-c16f018/examples/playbooks/rule-no-free-form-fail.yml000066400000000000000000000007701477347356000266020ustar00rootroot00000000000000--- - name: Example with discouraged free-form syntax hosts: localhost tasks: - name: Create a placefolder file ansible.builtin.command: chdir=/tmp touch foo # <-- don't use shorthand changed_when: false - name: Use raw to echo ansible.builtin.raw: executable=/bin/bash echo foo # <-- don't use executable= changed_when: false - name: Testing anything else passed to raw except for string ansible.builtin.raw: args: "123" changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/rule-no-free-form-pass.yml000066400000000000000000000010731477347356000266320ustar00rootroot00000000000000--- - name: Example with discouraged free-form syntax hosts: localhost tasks: - name: Create a placefolder file ansible.builtin.command: cmd: touch foo chdir: /tmp changed_when: false - name: Use raw to echo ansible.builtin.raw: echo foo args: executable: /bin/bash changed_when: false - name: Configure locale # https://github.com/ansible/ansible-lint/issues/2573 ansible.builtin.command: localectl set-locale LANG=en_GB.UTF-8 when: not ansible_check_mode changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/rule-no-handler-fail.yml000066400000000000000000000007201477347356000263300ustar00rootroot00000000000000--- - name: Example of no-handler rule hosts: localhost tasks: - name: Register result of a task ansible.builtin.copy: dest: "/tmp/placeholder" content: "Ansible made this!" mode: "0600" register: result # <-- we register the result of the task - name: Second command to run ansible.builtin.debug: msg: The placeholder file was modified! when: result.changed # <-- this triggers no-handler rule ansible-ansible-lint-c16f018/examples/playbooks/rule-no-handler-pass.yml000066400000000000000000000006731477347356000263720ustar00rootroot00000000000000--- - name: Example of no-handler rule hosts: localhost tasks: - name: Register result of a task ansible.builtin.copy: dest: "/tmp/placeholder" content: "Ansible made this!" mode: "0600" notify: - Second command to run # <-- handler will run only when file is changed handlers: - name: Second command to run ansible.builtin.debug: msg: The placeholder file was modified! ansible-ansible-lint-c16f018/examples/playbooks/rule-no-jinja-when-fail.yml000066400000000000000000000005301477347356000267440ustar00rootroot00000000000000--- - name: One hosts: all tasks: - name: Test when with jinja2 # noqa: jinja[spacing] ansible.builtin.debug: msg: text when: "{{ false }}" - name: Two hosts: all roles: - role: test when: "{{ '1' = '1' }}" - name: Three hosts: all roles: - role: test when: - "{{ '1' = '1' }}" ansible-ansible-lint-c16f018/examples/playbooks/rule-no-jinja-when-pass.yml000066400000000000000000000005211477347356000267770ustar00rootroot00000000000000--- - name: Test fixture for no-jinja-when hosts: all tasks: - name: Test when ansible.builtin.debug: msg: text when: true - name: Test when 2 ansible.builtin.debug: msg: text2 when: 1 = 1 - name: Three ansible.builtin.debug: msg: text2 when: - "false" ansible-ansible-lint-c16f018/examples/playbooks/rule-no-prompting.yml000066400000000000000000000015571477347356000260320ustar00rootroot00000000000000--- - name: Fixture for testing no-prompting rule, lines 5,17 hosts: all vars_prompt: - name: username prompt: What is your username? private: false - name: password prompt: What is your password? tasks: - name: Pause for 5 minutes to build app cache ansible.builtin.pause: minutes: 5 # should not trigger because minutes is mentioned - name: A helpful reminder of what to look out for post-update ansible.builtin.pause: # should trigger no-prompting as neither seconds/minutes are mentioned prompt: "Make sure org.foo.FooOverload exception is not present" - name: Fixture for testing if no vars_prompt is provided, lines 34-36 hosts: all tasks: - name: Pause for 5 minutes to build app cache ansible.builtin.pause: minutes: 5 # should not trigger because minutes is mentioned ansible-ansible-lint-c16f018/examples/playbooks/rule-no-tabs.yml000066400000000000000000000023041477347356000247330ustar00rootroot00000000000000--- - name: Fixture for no-tabs rule hosts: localhost tasks: - name: Should not trigger no-tabs rules ansible.builtin.lineinfile: path: some.txt regexp: ^\t$ line: string with \t inside - name: Foo ansible.builtin.debug: msg: "Presence of \t should trigger no-tabs here." - name: Key has a tab ansible.builtin.debug: "ms\tg": "The associated key has \t and should trigger no-tabs here." - name: Should not trigger no-tabs rules # noqa fqcn lineinfile: path: some.txt regexp: "^\t$" line: string with \t inside # Disabled as attempt to mock it would trigger an error validating its arguments # - name: Should not trigger no-tabs rules # noqa fqcn # win_lineinfile: # path: some.txt # regexp: "^\t$" # line: string with \t inside - name: Should not trigger no-tabs rules community.windows.win_lineinfile: path: some.txt regexp: "^\t$" line: string with \t inside - name: Should not trigger inside jinja vars: deep: "some{{ '\t' }}stuff": true ansible.builtin.debug: msg: "{{ 'foo' + '\t' + 'bar' }}" ansible-ansible-lint-c16f018/examples/playbooks/rule-only-builtins.yml000066400000000000000000000006361477347356000262060ustar00rootroot00000000000000--- - name: Fixture for examples/playbooks/rule-only-builtins.yml hosts: localhost tasks: - name: Sysctl # noqa: args[module] # while next module is mocked in our config, we still want to see that # only-builtins rules gets matched fake_namespace.fake_collection.fake_module: name: vm.swappiness value: "5" - name: Some task # noqa: args[module] zuul_return: {} ansible-ansible-lint-c16f018/examples/playbooks/rule-partial-become-without-become-fail.yml000066400000000000000000000013121477347356000321140ustar00rootroot00000000000000--- - name: Use of become_user without become at play level hosts: localhost become_user: root tasks: - name: A task without issues ansible.builtin.debug: msg: hello - name: Use of become_user without become at task level hosts: localhost tasks: - name: Use of become_user without become task ansible.builtin.command: whoami become_user: postgres changed_when: false - name: Use of become_user without become at task level hosts: localhost tasks: - name: A block with become and become_user on different tasks block: - name: Sample become ansible.builtin.command: whoami become_user: true changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/rule-partial-become-without-become-pass.yml000066400000000000000000000013271477347356000321550ustar00rootroot00000000000000--- - name: Test play hosts: localhost become_user: root become: true tasks: - name: Debug ansible.builtin.debug: msg: hello - name: Test play hosts: localhost tasks: - name: Foo ansible.builtin.command: whoami become_user: postgres become: true changed_when: false - name: Test play hosts: localhost tasks: - name: Accepts a become from higher scope ansible.builtin.command: whoami changed_when: false - name: Test play hosts: localhost become_user: postgres become: true tasks: - name: Accepts a become from a lower scope ansible.builtin.command: whoami become: true become_user: root changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/rule-risky-file-permissions-fail.yml000066400000000000000000000041711477347356000307340ustar00rootroot00000000000000# Fixture for RiskyFilePermissionsRule should return 11 occurrences --- - name: FAIL_INI_PRESERVE hosts: all tasks: - name: Ini_file does not accept preserve mode community.general.ini_file: path: foo create: true mode: preserve section: bar - name: FAIL_INI_PERMISSION hosts: all tasks: - name: Permissions needed if create is used community.general.ini_file: path: foo create: true section: bar - name: FAIL_PRESERVE_MODE hosts: all tasks: - name: File does not allow preserve value for mode ansible.builtin.file: path: foo mode: preserve - name: FAIL_MISSING_PERMISSIONS_TOUCH hosts: all tasks: - name: Permissions missing and might create file # noqa: fqcn[action-core] file: path: foo state: touch - name: Permissions missing and might create file (fqcn) ansible.builtin.file: path: foo state: touch - name: FAIL_MISSING_PERMISSIONS_DIRECTORY hosts: all tasks: - name: Permissions missing and might create directory # noqa: fqcn[action-core] file: path: foo state: directory - name: Lineinfile when create is true (fqcn) ansible.builtin.lineinfile: path: foo create: true line: some content here - name: FAIL_MISSING_PERMISSIONS_GET_URL hosts: all tasks: - name: Permissions missing # noqa: fqcn[action-core] get_url: url: http://foo dest: foo - name: FAIL_LINEINFILE_CREATE hosts: all tasks: - name: Lineinfile when create is true ansible.builtin.lineinfile: path: foo create: true line: some content here - name: FAIL_REPLACE_PRESERVE hosts: all tasks: - name: Replace does not allow preserve mode # noqa: fqcn[action-core] replace: path: foo mode: preserve regexp: foo - name: FAIL_PERMISSION_COMMENT hosts: all tasks: - name: Permissions is only a comment # noqa: fqcn[action-core] file: path: foo owner: root group: root state: directory # mode: 0755 ansible-ansible-lint-c16f018/examples/playbooks/rule-risky-file-permissions-pass.yml000066400000000000000000000034521477347356000307700ustar00rootroot00000000000000# Fixture for RiskyFilePermissionsRule should pass --- - name: SUCCESS_PERMISSIONS_PRESENT hosts: all tasks: - name: Permissions not missing and numeric ansible.builtin.file: path: foo mode: "0600" - name: SUCCESS_PERMISSIONS_PRESENT_GET_URL hosts: all tasks: - name: Permissions not missing and numeric ansible.builtin.get_url: url: http://foo dest: foo mode: "0600" - name: SUCCESS_ABSENT_STATE hosts: all tasks: - name: Permissions missing while state is absent is fine ansible.builtin.file: path: foo state: absent - name: SUCCESS_DEFAULT_STATE hosts: all tasks: - name: Permissions missing while state is file (default) is fine ansible.builtin.file: path: foo - name: SUCCESS_LINK_STATE hosts: all tasks: - name: Permissions missing while state is link is fine ansible.builtin.file: path: foo2 src: foo state: link - name: SUCCESS_CREATE_FALSE hosts: all tasks: - name: File edit when create is false ansible.builtin.lineinfile: path: foo create: false line: some content here - name: SUCCESS_REPLACE hosts: all tasks: - name: Replace should not require mode ansible.builtin.replace: path: foo regexp: foo - name: SUCCESS_RECURSE hosts: all tasks: - name: File with recursive does not require mode ansible.builtin.file: state: directory recurse: true path: foo - name: Permissions not missing and numeric (fqcn) ansible.builtin.file: path: bar mode: "755" # noqa: risky-octal - name: File edit when create is false (fqcn) ansible.builtin.lineinfile: path: foo create: false line: some content here ansible-ansible-lint-c16f018/examples/playbooks/rule-risky-octal-fail.yml000066400000000000000000000010411477347356000265370ustar00rootroot00000000000000--- - name: Fixture for testing risky-octal rule hosts: hosts vars: varset: varset tasks: - name: Octal permissions test fail (600) ansible.builtin.file: path: foo mode: 600 - name: Octal permissions test fail (710) ansible.builtin.file: path: foo mode: 710 - name: Octal permissions test fail (123) ansible.builtin.file: path: foo mode: 123 - name: Octal permissions test fail (2000) ansible.builtin.file: path: bar mode: 2000 ansible-ansible-lint-c16f018/examples/playbooks/rule-risky-octal-pass.yml000066400000000000000000000022441477347356000266000ustar00rootroot00000000000000--- - name: Fixture for testing risky-octal rule hosts: hosts vars: varset: varset tags: - no-free-form tasks: - name: Octal permissions test success (0600) ansible.builtin.file: path: foo mode: "0600" - name: Octal permissions test success (0000) ansible.builtin.file: path: foo mode: "0000" - name: Octal permissions test success (02000) ansible.builtin.file: path: bar mode: "02000" - name: Octal permissions test success (02751) ansible.builtin.file: path: bar mode: "02751" - name: Octal permissions test success (0777) ansible.builtin.file: path=baz mode=0777 # noqa: no-free-form - name: Octal permissions test success (0711) ansible.builtin.file: path=baz mode=0711 # noqa: no-free-form - name: Permissions test success (0777) ansible.builtin.file: path=baz mode=u+rwx # noqa: no-free-form - name: Octal permissions test success (777) ansible.builtin.file: path=baz mode=777 # noqa: no-free-form - name: Octal permissions test success (733) ansible.builtin.file: path=baz mode=733 # noqa: no-free-form ansible-ansible-lint-c16f018/examples/playbooks/rule-risky-shell-pipe-fail.yml000066400000000000000000000006551477347356000275110ustar00rootroot00000000000000--- - name: Test fixture for risky-shell-pipe hosts: localhost become: false tasks: - name: Pipeline without pipefail ansible.builtin.shell: false | cat changed_when: false - name: Pipeline with or and pipe, no pipefail ansible.builtin.shell: false || true | cat changed_when: false - name: Another one ansible.builtin.shell: | df | grep '/dev' changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/rule-risky-shell-pipe-pass.yml000066400000000000000000000035621477347356000275440ustar00rootroot00000000000000--- - name: Test fixture for risky-shell-pipe hosts: localhost become: false tasks: - name: Pipeline with pipefail ansible.builtin.shell: set -o pipefail && false | cat changed_when: false - name: Pipeline with pipefail, multi-line ansible.builtin.shell: | set -o pipefail false | cat changed_when: false - name: Pipeline with pipefail, complex set ansible.builtin.shell: | set -e -x -o pipefail false | cat changed_when: false - name: Pipeline with pipefail, complex set ansible.builtin.shell: | set -e -x -o pipefail false | cat changed_when: false - name: Pipeline with pipefail, complex set ansible.builtin.shell: | set -eo pipefail false | cat changed_when: false - name: Pipeline with pipefail not at first line ansible.builtin.shell: | echo foo set -eo pipefail false | cat changed_when: false - name: Pipeline without pipefail, ignoring errors # noqa: risky-shell-pipe ansible.builtin.shell: false | cat failed_when: false changed_when: false - name: Non-pipeline without pipefail # noqa: command-instead-of-shell ansible.builtin.shell: "true" changed_when: false - name: Command without pipefail ansible.builtin.command: "true" changed_when: false - name: Shell with or ansible.builtin.shell: false || true changed_when: false - name: Another one ansible.builtin.shell: | set -o pipefail df | grep '/dev' changed_when: false - name: "PowerShell with pipefail should be ok, bug #3161" # https://github.com/ansible/ansible-lint/issues/3161 ansible.builtin.shell: executable: /bin/pwsh cmd: | $ProgressPreference = 'this | that' changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/rule-role-name-path.yml000066400000000000000000000003641477347356000262050ustar00rootroot00000000000000--- - name: Fixture for role-name[path] rule hosts: localhost roles: - subfolder/1st_role # 1st - role: subfolder/2nd_role # 2nd tasks: - name: Another ansible.builtin.import_role: name: subfolder/3rd_role # 3rd ansible-ansible-lint-c16f018/examples/playbooks/rule-schema-become-method-fail.yml000066400000000000000000000004451477347356000302530ustar00rootroot00000000000000--- - name: Test 'become_method' plugin validity hosts: localhost become: true become_method: this_is_not_an_installed_plugin tasks: - name: Another example ansible.builtin.debug: msg: "This should not be reached" become_method: this_is_not_an_installed_plugin ansible-ansible-lint-c16f018/examples/playbooks/rule-schema-become-method-pass.yml000066400000000000000000000001711477347356000303020ustar00rootroot00000000000000--- - name: Test 'become_method' plugin validity hosts: localhost become: true become_method: ansible.builtin.sudo ansible-ansible-lint-c16f018/examples/playbooks/rule-syntax-moves.yml000066400000000000000000000007201477347356000260450ustar00rootroot00000000000000--- - name: Fixture for syntax[moves] hosts: localhost tasks: - name: 1st ansible.builtin.debug: msg: "{{ item }}" with_flattened: [] # moved to community.general in 2.10 - name: 2nd ansible.builtin.debug: msg: "{{ item }}" with_cartesian: [] # moved to community.general in 2.10 - name: 3rd ansible.builtin.debug: msg: "{{ item }}" with_filetree: [] # moved to community.general in 2.10 ansible-ansible-lint-c16f018/examples/playbooks/rule-validate-module-options-pass-2.yml000066400000000000000000000004351477347356000312430ustar00rootroot00000000000000--- - name: Fixture to validate module options action pass scenarios hosts: localhost tasks: - name: Copy a new "ntp.conf" file into place with backup ansible.builtin.copy: src: /mine/ntp.conf dest: /etc/ntp.conf backup: true mode: "0600" ansible-ansible-lint-c16f018/examples/playbooks/rule-yaml-fail.yml000066400000000000000000000006371477347356000252520ustar00rootroot00000000000000--- - name: Fixture for yaml rule that should generate 3 errors # https://github.com/ansible/ansible-lint/issues/3139 hosts: localhost tasks: - name: "1" ansible.builtin.debug: msg: yes - name: "2" ansible.builtin.debug: msg: yes tags: - skip_ansible_lint # this has no effect for yamllint rule - name: "3" ansible.builtin.debug: msg: yes ansible-ansible-lint-c16f018/examples/playbooks/rule-yaml-pass.yml000066400000000000000000000003341477347356000252770ustar00rootroot00000000000000--- # yamllint disable rule:truthy - name: Fixture for yaml rule testing ability to use disable comments hosts: localhost tasks: [] become: yes # <-- allowed only due to comment above # yamllint enable rule:truthy ansible-ansible-lint-c16f018/examples/playbooks/rule_literal_compare_fail.yml000066400000000000000000000006411477347356000276110ustar00rootroot00000000000000--- - name: Fixture for literal-compare hosts: localhost tasks: - name: Example task # <-- 1st ansible.builtin.debug: msg: test when: my_var == True - name: Example task # <-- 2nd ansible.builtin.debug: msg: test when: my_var == false - name: Another example task # <-- 3rd ansible.builtin.debug: msg: test when: - my_var == false ansible-ansible-lint-c16f018/examples/playbooks/rule_literal_compare_pass.yml000066400000000000000000000007451477347356000276510ustar00rootroot00000000000000--- - name: Fixture for literal-compare hosts: localhost tasks: - name: Example task ansible.builtin.debug: msg: test when: my_var - name: Another example task ansible.builtin.debug: msg: test when: - 1 + 1 == 2 - true - name: Example task ansible.builtin.debug: msg: test when: not my_var - name: Example task ansible.builtin.debug: msg: test when: my_var not None ansible-ansible-lint-c16f018/examples/playbooks/rulebook.yml000066400000000000000000000007341477347356000242520ustar00rootroot00000000000000--- # That file is not a valid playbook but it is a valid rulebook that was # mistakenly put under a playbook directory. - name: Demo rules with kafka as source hosts: localhost sources: - name: kafka kafka: topic: eda host: localhost port: 9092 group_id: testing rules: - name: condition: event.i is defined action: debug: - name: condition: event.stop == true action: shutdown: ansible-ansible-lint-c16f018/examples/playbooks/run-once-fail.yml000066400000000000000000000006561477347356000250720ustar00rootroot00000000000000--- - name: "Example with run_once" hosts: all # strategy: free # noqa: run-once[play] (Corrected code example) strategy: free gather_facts: false tasks: # - name: Task with run_once # noqa: run-once[task] (Corrected code example) - name: Task with run_once ansible.builtin.debug: msg: "Test" run_once: true # <-- avoid use of strategy as free at play level when using run_once at task level ansible-ansible-lint-c16f018/examples/playbooks/run-once-pass.yml000066400000000000000000000002461477347356000251200ustar00rootroot00000000000000--- - name: "Example without run_once" hosts: all gather_facts: false tasks: - name: Task without run_once ansible.builtin.debug: msg: "Test" ansible-ansible-lint-c16f018/examples/playbooks/schema-error-string.yml000066400000000000000000000001631477347356000263170ustar00rootroot00000000000000--- foo # This file is valid YAML but from our point of view is an error, as is # neither a Sequence or a Mapping. ansible-ansible-lint-c16f018/examples/playbooks/skiptasks.yml000066400000000000000000000027621477347356000244470ustar00rootroot00000000000000--- - hosts: all tasks: - name: Test latest[git] action: ansible.builtin.git - name: Test latest[hg] action: ansible.builtin.hg - name: Test command-instead-of-module ansible.builtin.command: git log changed_when: false - name: Test no-free-form ansible.builtin.command: creates=B chmod 644 A - name: Test latest[git] (skip) action: ansible.builtin.git tags: - skip_ansible_lint - name: Test latest[hg] (skip) action: ansible.builtin.hg tags: - skip_ansible_lint - name: Test command-instead-of-module (skip) ansible.builtin.command: git log tags: - skip_ansible_lint - name: Test no-free-form (skip) ansible.builtin.command: chmod 644 A tags: - skip_ansible_lint - name: Test latest[git] (don't warn) ansible.builtin.command: git log changed_when: false - name: Test latest[hg] (don't warn) ansible.builtin.command: chmod 644 A args: creates: B - name: Test latest[hg] (warn) ansible.builtin.command: chmod 644 A args: creates: B - name: Test latest[git] (don't warn single line) ansible.builtin.command: warn=False chdir=/tmp/blah git log changed_when: false - name: Test latest[hg] (don't warn single line) ansible.builtin.command: warn=no creates=B chmod 644 A - name: Test latest[hg] (warn single line) ansible.builtin.command: warn=yes creates=B chmod 644 A ansible-ansible-lint-c16f018/examples/playbooks/strict-mode.yml000066400000000000000000000003751477347356000246630ustar00rootroot00000000000000--- - name: Fixture for test_strict hosts: localhost tasks: - name: Display debug information ansible.builtin.stat: path2: echo "Hello World" # <-- args[module] due to invalid use of path2 instead of path changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/syntax-error-string.yml000066400000000000000000000002521477347356000264040ustar00rootroot00000000000000# This file is valid YAML and passed JSON Schema validation but not ansible # own syntax check. - hosts: localhost tasks: - name: Invalid syntax x.y.z.w: {} ansible-ansible-lint-c16f018/examples/playbooks/syntax-error.yml000066400000000000000000000002311477347356000250750ustar00rootroot00000000000000--- - name: This should raise syntax-error hosts: localhost tasks: ansible.builtin.debug: msg: Note that `tasks` is not entered as a list. ansible-ansible-lint-c16f018/examples/playbooks/task_in_list-0.yml000066400000000000000000000010371477347356000252450ustar00rootroot00000000000000--- - name: Fixture for task_in_list hosts: localhost tasks: - name: A ansible.builtin.debug: msg: "A" - name: B ansible.builtin.debug: msg: "C" pre_tasks: - name: C ansible.builtin.debug: msg: "C" post_tasks: - name: D block: - name: E ansible.builtin.debug: msg: "E" rescue: - name: F ansible.builtin.debug: msg: "F" always: - name: G ansible.builtin.debug: msg: "G" ansible-ansible-lint-c16f018/examples/playbooks/taskimports.yml000066400000000000000000000007741477347356000250140ustar00rootroot00000000000000--- - name: Fixture hosts: localhost vars: varset: tasks/simple_task.yml tasks: - name: Import 1 # noqa: fqcn import_tasks: tasks/nestedincludes.yml # - import_tasks: "{{ varnotset }}.yml" - name: Import 2 # noqa: fqcn import_tasks: "{{ varset }}" - name: Import 3 # noqa: fqcn import_tasks: tasks/directory with spaces/main.yml # Import tasks by FQCN as well to ensure they load - name: Import 4 ansible.builtin.import_tasks: tasks/passing_task.yml ansible-ansible-lint-c16f018/examples/playbooks/taskincludes.yml000066400000000000000000000005351477347356000251200ustar00rootroot00000000000000--- - name: Fixture hosts: localhost vars: varset: tasks/simple_task.yml tasks: # - include_tasks: "{{ varnotset }}.yml" - include_tasks: "{{ varset }}.yml" - include_tasks: tasks/directory with spaces/main.yml # Include tasks by FQCN as well to ensure they load - ansible.builtin.include_tasks: tasks/passing_task.yml ansible-ansible-lint-c16f018/examples/playbooks/tasks/000077500000000000000000000000001477347356000230265ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/tasks/bug-2875.yml000066400000000000000000000003211477347356000247250ustar00rootroot00000000000000--- - name: "Reproduce bug #2875" include_tasks: "{{ lookup('first_found', __ff_params) }}" vars: __ff_params: files: - "default.yml" paths: - "{{ role_path }}/tasks/setup" ansible-ansible-lint-c16f018/examples/playbooks/tasks/conflicting-action-statements.yml000066400000000000000000000000421477347356000315040ustar00rootroot00000000000000--- - shell: pip changed: false ansible-ansible-lint-c16f018/examples/playbooks/tasks/directory with spaces/000077500000000000000000000000001477347356000272255ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/tasks/directory with spaces/main.yml000066400000000000000000000002251477347356000306730ustar00rootroot00000000000000--- # this should generate: name[missing]: All tasks should be named - ansible.builtin.assert: fail_msg: tasks in directory with spaces included ansible-ansible-lint-c16f018/examples/playbooks/tasks/empty_blocks.yml000066400000000000000000000005331477347356000262450ustar00rootroot00000000000000--- - name: A named block task block: - name: an assertion ansible.builtin.assert: fail_msg: foo rescue: # null always: {} - block: - name: Another assertion ansible.builtin.assert: fail_msg: bar rescue: {} always: - name: Yet another assertion ansible.builtin.assert: fail_msg: baz ansible-ansible-lint-c16f018/examples/playbooks/tasks/include-in-block-inner.yml000066400000000000000000000002541477347356000300020ustar00rootroot00000000000000--- - name: include-in-block-inner | I am a block block: - name: simple_task | Include tasks from inside a block ansible.builtin.include_tasks: simple_task.yml ansible-ansible-lint-c16f018/examples/playbooks/tasks/included-task-with-vars.yml000066400000000000000000000001311477347356000302150ustar00rootroot00000000000000--- - name: included-task-with-vars | Test ansible.builtin.debug: msg: "{{ foo }}" ansible-ansible-lint-c16f018/examples/playbooks/tasks/included-with-lint.yml000066400000000000000000000001061477347356000272520ustar00rootroot00000000000000--- # missing a task name - ansible.builtin.assert: fail_msg: foo ansible-ansible-lint-c16f018/examples/playbooks/tasks/local_action.transformed.yml000066400000000000000000000001201477347356000305140ustar00rootroot00000000000000--- - name: Sample ansible.builtin.command: echo 123 delegate_to: localhost ansible-ansible-lint-c16f018/examples/playbooks/tasks/local_action.yml000066400000000000000000000000641477347356000262000ustar00rootroot00000000000000--- - name: Sample local_action: command echo 123 ansible-ansible-lint-c16f018/examples/playbooks/tasks/main.yml000066400000000000000000000002341477347356000244740ustar00rootroot00000000000000--- - name: This is correct ansible.builtin.assert: that: true - name: A phony prefix | This is also correct ansible.builtin.assert: that: true ansible-ansible-lint-c16f018/examples/playbooks/tasks/malformed.yml000066400000000000000000000001301477347356000255110ustar00rootroot00000000000000--- # should produce a malformed error from ansible syntax check - oops this is invalid ansible-ansible-lint-c16f018/examples/playbooks/tasks/nestedincludes.yml000066400000000000000000000001151477347356000265570ustar00rootroot00000000000000--- - name: simple_task | One include include_tasks: tasks/simple_task.yml ansible-ansible-lint-c16f018/examples/playbooks/tasks/partial_become.yml/000077500000000000000000000000001477347356000265745ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/tasks/partial_become.yml/main.yml000066400000000000000000000001501477347356000302370ustar00rootroot00000000000000--- - name: Included with partial become ansible.builtin.debug: msg: Included with partial become ansible-ansible-lint-c16f018/examples/playbooks/tasks/partial_prefix/000077500000000000000000000000001477347356000260375ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/tasks/partial_prefix/foo.yml000066400000000000000000000004111477347356000273410ustar00rootroot00000000000000--- - name: foo | This prefix is incomplete ansible.builtin.assert: that: true - name: partial_prefix | This prefix is incomplete ansible.builtin.assert: that: true - name: partial_prefix | foo | This is correct ansible.builtin.assert: that: true ansible-ansible-lint-c16f018/examples/playbooks/tasks/partial_prefix/main.yml000066400000000000000000000004131477347356000275040ustar00rootroot00000000000000--- - name: partial_prefix | main | This is correct ansible.builtin.assert: that: true - name: main | This prefix is incomplete ansible.builtin.assert: that: true - name: partial_prefix | This prefix is incomplete ansible.builtin.assert: that: true ansible-ansible-lint-c16f018/examples/playbooks/tasks/passing_task.yml000066400000000000000000000001651477347356000262410ustar00rootroot00000000000000--- - name: passing_task | Simple task to include which generates no errors ansible.builtin.assert: that: true ansible-ansible-lint-c16f018/examples/playbooks/tasks/rule-name-prefix-fail.yml000066400000000000000000000005641477347356000276470ustar00rootroot00000000000000--- - name: rule-name-prefix-fail | this is not correctly capitalized ansible.builtin.assert: that: true - name: This is missing the prefix ansible.builtin.assert: that: true - name: name | This prefix is incomplete ansible.builtin.assert: that: true - name: rule-name-prefix-fail | This is correctly | named too ansible.builtin.assert: that: true ansible-ansible-lint-c16f018/examples/playbooks/tasks/simple_task.yml000066400000000000000000000001241477347356000260610ustar00rootroot00000000000000--- - name: simple_task | This is named ansible.builtin.assert: fail_msg: foo ansible-ansible-lint-c16f018/examples/playbooks/tasks/vars/000077500000000000000000000000001477347356000240015ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/tasks/vars/bug-3289.yml000066400000000000000000000000221477347356000256760ustar00rootroot00000000000000--- city: Dresden ansible-ansible-lint-c16f018/examples/playbooks/tasks/varset.yml000066400000000000000000000000661477347356000250570ustar00rootroot00000000000000--- - debug: msg="var was set" - git: repo=hello.git ansible-ansible-lint-c16f018/examples/playbooks/tasks/varunset.yml000066400000000000000000000000431477347356000254150ustar00rootroot00000000000000--- - debug: msg="var was not set" ansible-ansible-lint-c16f018/examples/playbooks/tasks/x.yml000066400000000000000000000002511477347356000240160ustar00rootroot00000000000000--- - # nothing, checks bug #849 - name: Test include action: funny value=clown args: key: value - # a second null task, validates yaml_utils.get_path_to_task ansible-ansible-lint-c16f018/examples/playbooks/templates/000077500000000000000000000000001477347356000236775ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/templates/not-valid.yaml000066400000000000000000000001421477347356000264550ustar00rootroot00000000000000# Used to validate that a templated YAML file does not confuse the linter {% include 'port.j2' %} ansible-ansible-lint-c16f018/examples/playbooks/test-include.yml000066400000000000000000000014441477347356000250270ustar00rootroot00000000000000--- - name: Fixture for testing various includes/imports hosts: localhost gather_facts: false pre_tasks: - name: Include 1 ansible.builtin.include_tasks: tasks/main.yml roles: - test_nop - { role: test_nop, test_nop_arg1: true } tasks: - name: Include 2 ansible.builtin.include_tasks: tasks/main.yml - name: Include 3 ansible.builtin.include_tasks: tasks/main.yml - name: Include 4 ansible.builtin.include_tasks: file=tasks/main.yml - name: Include 4 ansible.builtin.import_tasks: file=tasks/main.yml handlers: - name: Include 5 ansible.builtin.include_tasks: handlers/empty.yml - name: Include 5 ansible.builtin.import_tasks: handlers/empty.yml - name: Include 6 ansible.builtin.import_playbook: valid.yml ansible-ansible-lint-c16f018/examples/playbooks/test_import_playbook.yml000066400000000000000000000002701477347356000266740ustar00rootroot00000000000000--- - name: Fixture 1 for bug 4024 import_playbook: community.molecule.validate.yml - name: Fixture 2 for bug 4024 ansible.builtin.import_playbook: community.molecule.validate.yml ansible-ansible-lint-c16f018/examples/playbooks/test_import_playbook_invalid.yml000066400000000000000000000004051477347356000304020ustar00rootroot00000000000000--- - name: Fixture 3 - not supported (invalid syntax) ansible.builtin.import_playbook: file: community.molecule.validate.yml - name: Fixture 4 - not supported (invalid syntax) ansible.builtin.import_playbook: other: community.molecule.validate.yml ansible-ansible-lint-c16f018/examples/playbooks/test_import_with_conflicting_action_statements.yml000066400000000000000000000001261477347356000342120ustar00rootroot00000000000000--- - hosts: all tasks: - import_tasks: tasks/conflicting-action-statements.yml ansible-ansible-lint-c16f018/examples/playbooks/test_import_with_malformed.yml000066400000000000000000000002041477347356000300520ustar00rootroot00000000000000--- - name: Some test fixture hosts: all tasks: - name: Some import ansible.builtin.import_tasks: tasks/malformed.yml ansible-ansible-lint-c16f018/examples/playbooks/test_include_inplace.yml000066400000000000000000000001121477347356000265730ustar00rootroot00000000000000--- - name: Test fixture hosts: all roles: - include_in_the_place ansible-ansible-lint-c16f018/examples/playbooks/test_include_relative.yml000066400000000000000000000001421477347356000267760ustar00rootroot00000000000000--- - name: Test fixture hosts: localhost gather_facts: false roles: - include_relative ansible-ansible-lint-c16f018/examples/playbooks/test_skip_inside_yaml.yml000066400000000000000000000043351477347356000270130ustar00rootroot00000000000000--- - name: Fixture hosts: all tags: - skip_ansible_lint # should disable error at playbook level tasks: - name: Test action: community.general.hg args: repo: foo version: HEAD - name: Test latest[hg] (skipped) action: community.general.hg args: repo: foo # revision: HEAD - name: Test latest[git] and partial-become # noqa: latest[git] action: ansible.builtin.git args: repo: foo version: HEAD become_user: alice - name: Test latest[git] and partial-become (skipped) # noqa: latest[git] partial-become action: ansible.builtin.git args: repo: foo version: HEAD become_user: alice - name: Test YAML # <-- 1 jinja[spacing] ansible.builtin.get_url: # noqa: risky-file-permissions url: http://example.com/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/file.conf # <-- 2 yaml[line-length] dest: "{{dest_proj_path}}/foo.conf" - name: Test YAML and jinja[spacing] (skipped) ansible.builtin.get_url: # noqa: risky-file-permissions url: http://example.com/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/file.conf # noqa: yaml[line-length] dest: "{{dest_proj_path}}/foo.conf" # noqa: jinja[spacing] - name: Test no-free-form # <-- 3 no-free-form ansible.builtin.command: creates=B chmod 644 A # noqa: no-free-form - name: Test no-free-form # <-- 4 no-free-form ansible.builtin.command: creates=B chmod 644 A # noqa: no-free-form - name: Test no-free-form (skipped via no warn) ansible.builtin.command: creates=B chmod 644 A # noqa: no-free-form - name: Test no-free-form (skipped via skip_ansible_lint) ansible.builtin.command: creates=B chmod 644 A # noqa: no-free-form tags: - skip_ansible_lint - name: Fixture 2 hosts: localhost tasks: - name: Foo become: true block: - name: Bar become_user: john_doe ansible.builtin.command: "/etc/test.sh" changed_when: false transform-block-indentation-indicator.transformed.yml000066400000000000000000000002361477347356000342600ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks--- - name: Demo hosts: all tasks: - name: Demo ansible.builtin.debug: msg: |2 multi line message ansible-ansible-lint-c16f018/examples/playbooks/transform-block-indentation-indicator.yml000066400000000000000000000002411477347356000320100ustar00rootroot00000000000000--- - name: Demo hosts: all tasks: - name: Demo ansible.builtin.debug: msg: |3 multi line message ansible-ansible-lint-c16f018/examples/playbooks/transform-deprecated-local-action.transformed.yml000066400000000000000000000002371477347356000334250ustar00rootroot00000000000000--- - name: Fixture for deprecated-local-action hosts: localhost tasks: - name: Task example ansible.builtin.debug: delegate_to: localhost ansible-ansible-lint-c16f018/examples/playbooks/transform-deprecated-local-action.yml000066400000000000000000000002371477347356000311020ustar00rootroot00000000000000--- - name: Fixture for deprecated-local-action hosts: localhost tasks: - name: Task example local_action: module: ansible.builtin.debug ansible-ansible-lint-c16f018/examples/playbooks/transform-jinja.transformed.yml000066400000000000000000000024151477347356000300550ustar00rootroot00000000000000--- - name: Fixture hosts: localhost vars: my_list: - foo - bar tasks: - name: A block used to check that we do not identify error at correct level block: - name: Foo # <-- this is valid jinja2 ansible.builtin.debug: foo: "{{ 1 }}" # <-- jinja2[spacing] msg: "{{ 'a' b }}" # <-- jinja2[invalid] - name: A block used to check that we do not identify error at correct level block: - name: Foo # <-- this is valid jinja2 ansible.builtin.debug: msg: "{{ item }}" # <-- jinja2[spacing] with_items: - "{{ items }}" - name: Confirm a deeply nested duplicate error is corrected ansible.builtin.set_fact: fact: dict: dict: list: - one - two - dict: fix: "{{ 'VALUE_1' | lower }}" # <-- jinja2[spacing] - dict: fix: "{{ 'VALUE_1' | lower }}" # <-- jinja2[spacing] - dict: fix: "{{ 'VALUE_2' | lower }}" # <-- jinja2[spacing] # It should be noted that even ansible --syntax-check fails to spot the jinja # error above, but ansible will throw a runtime error when running ansible-ansible-lint-c16f018/examples/playbooks/transform-jinja.yml000066400000000000000000000024041477347356000255300ustar00rootroot00000000000000--- - name: Fixture hosts: localhost vars: my_list: - foo - bar tasks: - name: A block used to check that we do not identify error at correct level block: - name: Foo # <-- this is valid jinja2 ansible.builtin.debug: foo: "{{ 1 }}" # <-- jinja2[spacing] msg: "{{ 'a' b }}" # <-- jinja2[invalid] - name: A block used to check that we do not identify error at correct level block: - name: Foo # <-- this is valid jinja2 ansible.builtin.debug: msg: "{{ item }}" # <-- jinja2[spacing] with_items: - "{{ items }}" - name: Confirm a deeply nested duplicate error is corrected ansible.builtin.set_fact: fact: dict: dict: list: - one - two - dict: fix: "{{'VALUE_1'|lower}}" # <-- jinja2[spacing] - dict: fix: "{{'VALUE_1'|lower}}" # <-- jinja2[spacing] - dict: fix: "{{'VALUE_2'|lower}}" # <-- jinja2[spacing] # It should be noted that even ansible --syntax-check fails to spot the jinja # error above, but ansible will throw a runtime error when running ansible-ansible-lint-c16f018/examples/playbooks/transform-key-order-block.transformed.yml000066400000000000000000000007271477347356000317570ustar00rootroot00000000000000--- - name: Testing multiple plays in a playbook hosts: localhost tasks: - name: First block when: true block: - name: Display a message ansible.builtin.debug: msg: Hello world! - name: A second play hosts: localhost tasks: - name: Second block when: true # <-- name key should be the second one block: - name: Display a message ansible.builtin.debug: msg: Hello world! ansible-ansible-lint-c16f018/examples/playbooks/transform-key-order-block.yml000066400000000000000000000007271477347356000274340ustar00rootroot00000000000000--- - name: Testing multiple plays in a playbook hosts: localhost tasks: - name: First block when: true block: - name: Display a message ansible.builtin.debug: msg: Hello world! - name: A second play hosts: localhost tasks: - name: Second block block: - name: Display a message ansible.builtin.debug: msg: Hello world! when: true # <-- name key should be the second one ansible-ansible-lint-c16f018/examples/playbooks/transform-key-order-play.transformed.yml000066400000000000000000000003651477347356000316300ustar00rootroot00000000000000--- - name: This is a playbook # <-- name key should be the first one hosts: localhost tasks: - name: A block when: true block: - name: Display a message ansible.builtin.debug: msg: Hello world! ansible-ansible-lint-c16f018/examples/playbooks/transform-key-order-play.yml000066400000000000000000000003651477347356000273050ustar00rootroot00000000000000--- - hosts: localhost name: This is a playbook # <-- name key should be the first one tasks: - name: A block when: true block: - name: Display a message ansible.builtin.debug: msg: Hello world! ansible-ansible-lint-c16f018/examples/playbooks/transform-key-order.transformed.yml000066400000000000000000000016031477347356000306610ustar00rootroot00000000000000--- - name: Fixture hosts: localhost tasks: # comment before keys - name: Task with no_log on top # name comment no_log: true # no_log comment ansible.builtin.command: echo hello # command comment changed_when: false # changed_when comment # comment after keys - name: Task with when on top when: true ansible.builtin.command: echo hello changed_when: false - name: Delegate_to on top delegate_to: localhost ansible.builtin.command: echo hello changed_when: false - name: Loopy loop: - 1 - 2 ansible.builtin.command: echo {{ item }} changed_when: false - name: Become first become: true ansible.builtin.command: echo hello changed_when: false - name: Register first register: test ansible.builtin.command: echo hello changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/transform-key-order.yml000066400000000000000000000016051477347356000263400ustar00rootroot00000000000000--- - name: Fixture hosts: localhost tasks: - # comment before keys no_log: true # no_log comment ansible.builtin.command: echo hello # command comment name: Task with no_log on top # name comment changed_when: false # changed_when comment # comment after keys - when: true name: Task with when on top ansible.builtin.command: echo hello changed_when: false - delegate_to: localhost name: Delegate_to on top ansible.builtin.command: echo hello changed_when: false - loop: - 1 - 2 name: Loopy ansible.builtin.command: echo {{ item }} changed_when: false - become: true name: Become first ansible.builtin.command: echo hello changed_when: false - register: test ansible.builtin.command: echo hello name: Register first changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/transform-name.transformed.yml000066400000000000000000000006541477347356000277050ustar00rootroot00000000000000--- - name: Fixture testing transform name capitalize hosts: all tasks: - name: Missing capital name with notify ansible.builtin.debug: msg: "foo" notify: Missing capital name - name: Missing capital name with notify list ansible.builtin.debug: msg: "foo" notify: - Missing capital name - name: Missing capital name ansible.builtin.debug: msg: "bar" ansible-ansible-lint-c16f018/examples/playbooks/transform-name.yml000066400000000000000000000006541477347356000253620ustar00rootroot00000000000000--- - name: Fixture testing transform name capitalize hosts: all tasks: - name: missing capital name with notify ansible.builtin.debug: msg: "foo" notify: missing capital name - name: missing capital name with notify list ansible.builtin.debug: msg: "foo" notify: - missing capital name - name: missing capital name ansible.builtin.debug: msg: "bar" ansible-ansible-lint-c16f018/examples/playbooks/transform-no-free-form.transformed.yml000066400000000000000000000015241477347356000312560ustar00rootroot00000000000000--- - name: Example with discouraged free-form syntax hosts: localhost tasks: - name: Create a placefolder file ansible.builtin.command: # <-- don't use shorthand chdir: /tmp cmd: touch foo changed_when: false - name: Create a placefolder file ansible.builtin.command: # <-- command can also go first chdir: /tmp cmd: touch bar changed_when: false - name: Use raw to echo ansible.builtin.raw: echo foo # <-- don't use executable= args: executable: /bin/bash changed_when: false - name: Example task with usage for '=' as module params ansible.builtin.debug: msg: "Hello there world" changed_when: false - name: Task that has a non-debug string with spaces ansible.builtin.set_fact: foo: "String with spaces" ansible-ansible-lint-c16f018/examples/playbooks/transform-no-free-form.yml000066400000000000000000000014011477347356000267250ustar00rootroot00000000000000--- - name: Example with discouraged free-form syntax hosts: localhost tasks: - name: Create a placefolder file ansible.builtin.command: chdir=/tmp touch foo # <-- don't use shorthand changed_when: false - name: Create a placefolder file ansible.builtin.command: touch bar chdir=/tmp # <-- command can also go first changed_when: false - name: Use raw to echo ansible.builtin.raw: executable=/bin/bash echo foo # <-- don't use executable= changed_when: false - name: Example task with usage for '=' as module params ansible.builtin.debug: msg='Hello there world' changed_when: false - name: Task that has a non-debug string with spaces ansible.builtin.set_fact: foo="String with spaces" ansible-ansible-lint-c16f018/examples/playbooks/transform-no-jinja-when.transformed.yml000066400000000000000000000005101477347356000314200ustar00rootroot00000000000000--- - name: One hosts: all tasks: - name: Test when with jinja2 # noqa: jinja[spacing] ansible.builtin.debug: msg: text when: "false" - name: Two hosts: all roles: - role: hello when: "'1' = '1'" - name: Three hosts: all roles: - role: hello when: - "'1' = '1'" ansible-ansible-lint-c16f018/examples/playbooks/transform-no-jinja-when.yml000066400000000000000000000005321477347356000271010ustar00rootroot00000000000000--- - name: One hosts: all tasks: - name: Test when with jinja2 # noqa: jinja[spacing] ansible.builtin.debug: msg: text when: "{{ false }}" - name: Two hosts: all roles: - role: hello when: "{{ '1' = '1' }}" - name: Three hosts: all roles: - role: hello when: - "{{ '1' = '1' }}" ansible-ansible-lint-c16f018/examples/playbooks/transform-no-log-password.transformed.yml000066400000000000000000000007451477347356000320210ustar00rootroot00000000000000--- - name: Fixture for no log password hosts: all tasks: - name: Fail when no_log is set to False ansible.builtin.user: name: john_doe password: "{{ item }}" state: absent with_items: - wow - now no_log: true - name: Fail when no_log is absent ansible.builtin.user: name: john_doe password: "{{ item }}" state: absent with_items: - wow - now no_log: true ansible-ansible-lint-c16f018/examples/playbooks/transform-no-log-password.yml000066400000000000000000000007231477347356000274720ustar00rootroot00000000000000--- - name: Fixture for no log password hosts: all tasks: - name: Fail when no_log is set to False ansible.builtin.user: name: john_doe password: "{{ item }}" state: absent with_items: - wow - now no_log: false - name: Fail when no_log is absent ansible.builtin.user: name: john_doe password: "{{ item }}" state: absent with_items: - wow - now ansible-ansible-lint-c16f018/examples/playbooks/transform-partial-become.transformed.yml000066400000000000000000000025051477347356000316460ustar00rootroot00000000000000--- # The play has become_user and the task has become # this is fixable, copy the become_user to the task # and remove from the play - name: Play 1 hosts: localhost tasks: - name: A block block: - name: Debug ansible.builtin.debug: msg: hello become: true become_user: root # The task has become_user but the play does not # this is fixable, remove the become_user from the task - name: Play 2 hosts: localhost tasks: - name: A block block: - name: Debug ansible.builtin.debug: msg: hello # The task has become_user and the play has become # this is fixable, add become to the task - name: Play 3 hosts: localhost become: true tasks: - name: A block block: - name: Debug ansible.builtin.debug: msg: hello become: true become_user: root # The play has become_user but has an include # this is not fixable, the include could be called from multiple playbooks - name: Play 4 hosts: localhost become_user: root tasks: - name: A block block: - name: Debug ansible.builtin.debug: msg: hello become: true - name: Include ansible.builtin.include_tasks: file: ../tasks/partial_become/main.yml ansible-ansible-lint-c16f018/examples/playbooks/transform-partial-become.yml000066400000000000000000000025021477347356000273200ustar00rootroot00000000000000--- # The play has become_user and the task has become # this is fixable, copy the become_user to the task # and remove from the play - name: Play 1 hosts: localhost become_user: root tasks: - name: A block block: - name: Debug ansible.builtin.debug: msg: hello become: true # The task has become_user but the play does not # this is fixable, remove the become_user from the task - name: Play 2 hosts: localhost tasks: - name: A block block: - name: Debug ansible.builtin.debug: msg: hello become_user: root # The task has become_user and the play has become # this is fixable, add become to the task - name: Play 3 hosts: localhost become: true tasks: - name: A block block: - name: Debug ansible.builtin.debug: msg: hello become_user: root # The play has become_user but has an include # this is not fixable, the include could be called from multiple playbooks - name: Play 4 hosts: localhost become_user: root tasks: - name: A block block: - name: Debug ansible.builtin.debug: msg: hello become: true - name: Include ansible.builtin.include_tasks: file: ../tasks/partial_become/main.yml ansible-ansible-lint-c16f018/examples/playbooks/transform_command_instead_of_shell.transformed.yml000066400000000000000000000011211477347356000340350ustar00rootroot00000000000000--- - name: Fixture hosts: localhost tasks: - name: Shell no pipe ansible.builtin.command: cmd: echo hello changed_when: false - name: Shell with jinja filter ansible.builtin.command: cmd: echo {{ "hello" | upper }} changed_when: false - name: Shell with jinja filter (fqcn) ansible.builtin.command: cmd: echo {{ "hello" | upper }} changed_when: false - name: Command with executable parameter ansible.builtin.shell: cmd: clear args: executable: /bin/bash changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/transform_command_instead_of_shell.yml000066400000000000000000000011131477347356000315130ustar00rootroot00000000000000--- - name: Fixture hosts: localhost tasks: - name: Shell no pipe ansible.builtin.shell: cmd: echo hello changed_when: false - name: Shell with jinja filter ansible.builtin.shell: cmd: echo {{ "hello" | upper }} changed_when: false - name: Shell with jinja filter (fqcn) ansible.builtin.shell: cmd: echo {{ "hello" | upper }} changed_when: false - name: Command with executable parameter ansible.builtin.shell: cmd: clear args: executable: /bin/bash changed_when: false ansible-ansible-lint-c16f018/examples/playbooks/unicode.transformed.yml000066400000000000000000000002251477347356000263740ustar00rootroot00000000000000--- - name: Fixture hosts: all tasks: # cspell:disable-next-line - name: Some тест ansible.builtin.command: cmd: uname ansible-ansible-lint-c16f018/examples/playbooks/unicode.yml000066400000000000000000000002251477347356000240510ustar00rootroot00000000000000--- - name: Fixture hosts: all tasks: # cspell:disable-next-line - name: Some тест ansible.builtin.command: cmd: uname ansible-ansible-lint-c16f018/examples/playbooks/valid.yml000066400000000000000000000000751477347356000235250ustar00rootroot00000000000000--- - name: Minimal test play hosts: localhost tasks: [] ansible-ansible-lint-c16f018/examples/playbooks/valid_with_alt_extension.yaml000066400000000000000000000003161477347356000276530ustar00rootroot00000000000000--- # Used to validate that we also accept .yaml extension on playbooks - name: Fixture hosts: localhost tasks: - ansible.builtin.debug: # <-- should notify about missing 'name' msg: hello! ansible-ansible-lint-c16f018/examples/playbooks/var-naming/000077500000000000000000000000001477347356000237405ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/var-naming/rule-var-naming-fail.yml000066400000000000000000000025151477347356000304030ustar00rootroot00000000000000--- - name: Fixture hosts: localhost vars: CamelCaseIsBad: false # invalid 1 this_is_valid: # valid because content is a dict, not a variable CamelCase: ... ALL_CAPS: ... ALL_CAPS_ARE_BAD_TOO: ... # invalid 2 CamelCaseButErrorIgnored: true # noqa: var-naming tasks: - name: Foo ansible.builtin.set_fact: "{{ 'test_' }}var": "value" # noqa: var-naming[no-jinja] - name: Bar ansible.builtin.set_fact: CamelCaseButErrorIgnored: true # noqa: var-naming - name: Test in a block vars: BAD: false # invalid 3 MoreBad: ... # invalid 4 block: - name: Foo vars: ALL_CAPS_ARE_BAD_TOO: "{{ MoreBad }}" # invalid 5 ansible.builtin.set_fact: CamelCaseIsBad: "{{ BAD }}" # invalid 6 - name: Test on register ansible.builtin.debug: var: test_var register: CamelCaseIsBad # invalid 7 - name: This should not trigger due to role name being dynamic (jinja) ansible.builtin.include_role: name: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }}" vars: nginx_logrotate_conf_enable: true - name: This should not trigger due to containing a dot in role name ansible.builtin.include_role: name: "foo.bar" vars: bar_foo: true ansible-ansible-lint-c16f018/examples/playbooks/vars/000077500000000000000000000000001477347356000226545ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/vars/empty.transformed.yml000066400000000000000000000001041477347356000270530ustar00rootroot00000000000000 --- # broken vars files due to spacing at the start of the file. ansible-ansible-lint-c16f018/examples/playbooks/vars/empty.yml000066400000000000000000000001041477347356000245300ustar00rootroot00000000000000 --- # broken vars files due to spacing at the start of the file. ansible-ansible-lint-c16f018/examples/playbooks/vars/empty_vars.transformed.yml000066400000000000000000000001111477347356000301040ustar00rootroot00000000000000--- # Make sure that the Transformer does not mangle comment-only files! ansible-ansible-lint-c16f018/examples/playbooks/vars/empty_vars.yml000066400000000000000000000001111477347356000255610ustar00rootroot00000000000000--- # Make sure that the Transformer does not mangle comment-only files! ansible-ansible-lint-c16f018/examples/playbooks/vars/invalid_vars_schema.yml000066400000000000000000000000651477347356000274010ustar00rootroot00000000000000--- 123: true # invalid as schema expects string key ansible-ansible-lint-c16f018/examples/playbooks/vars/jinja-spacing.yml000066400000000000000000000034101477347356000261120ustar00rootroot00000000000000--- # Should raise jinja[spacing] at line [14, 15, 16, 17, 18, 19, 22, 32, 38], at following variables. # ".bad_var_1", ".bad_var_2", ".bad_var_3", ".invalid_multiline_nested_json", ".invalid_nested_json" good_var_1: "{{ good_format }}" good_var_2: "Value: {{ good_format }}" good_var_3: "{{ good_format | filter }}" good_var_4: "Value: {{ good_format | filter }}" jinja_escape_1: "{{ '{{' }}" jinja_escape_2: docker info --format '{{ '{{' }}json .Swarm.LocalNodeState{{ '}}' }}' | tr -d '"' jinja_whitespace_control: | {{ good_format }}/ {{- good_format }} {{- good_format -}} bad_var_1: "{{bad_format}}" # <-- 1 bad_var_2: "Value: {{ bad_format}}" # <-- 2 bad_var_3: "{{bad_format }}" # <-- 3 bad_var_4: "{{ bad_format|filter }}" # <-- 4 bad_var_5: "Value: {{ bad_format |filter }}" # <-- 5 bad_var_6: "{{ bad_format| filter }}" # <-- 6 # spell-checker: disable-next-line non_jinja_var: "data = ${lookup{$local_part}lsearch{/etc/aliases}}" # noqa: jinja[spacing] json_inside_jinja: "{{ {'test': {'subtest': variable}} }}" multiline_vars: # Assert that no false positive on multiline exists cases: case1: >- http://example.com/{{ case1 }} case2: >- http://example.com/{{ case2 }} valid_nested_json: "{{ {'dummy_2': {'nested_dummy_1': 'value_1', 'nested_dummy_2': value_2}} | combine(dummy_1) }}" invalid_nested_json: "{{ {'dummy_2': {'nested_dummy_1': 'value_1', 'nested_dummy_2': value_2}} | combine(dummy_1)}}" # <-- 7 valid_multiline_nested_json: >- {{ {'dummy_2': {'nested_dummy_1': value_1, 'nested_dummy_2': value_2}} | combine(dummy_1) }} invalid_multiline_nested_json: >- # ignored multiline expression, for now {{ {'dummy_2': {'nested_dummy_1': value_1, 'nested_dummy_2': value_2}} | combine(dummy_1)}} ansible-ansible-lint-c16f018/examples/playbooks/vars/other.yml000066400000000000000000000000571477347356000245220ustar00rootroot00000000000000--- some_var: some_value_defined_in_vars_other ansible-ansible-lint-c16f018/examples/playbooks/vars/rule_jinja_vars.yml000066400000000000000000000002071477347356000265530ustar00rootroot00000000000000# this should not trigger any errors because a 'when' inside # a vars files, does not use implicit jinja. --- foo: when: "{{ var }}" ansible-ansible-lint-c16f018/examples/playbooks/vars/rule_var_naming_fail.yml000066400000000000000000000013011477347356000275350ustar00rootroot00000000000000--- CamelCaseIsBad: false # invalid this_is_valid: # valid because content is a dict, not a variable CamelCase: ... ALL_CAPS: ... ALL_CAPS_ARE_BAD_TOO: ... # invalid # Next line should be allowed, as we should ignore jinja in var names "{{ 'test_' }}var": "value" # noqa: schema CamelCaseButErrorIgnored: true # noqa: var-naming assert: true # invalid due to being Python reserved keyword é: true # invalid due to non-ascii character hosts: true # invalid as being Ansible reserved name role_name: boo # invalid as being Ansible special magic variable ansible_facts: {} # special variable that we allow to be written ansible_python_interpreter: python3 # special variable that we allow to be written ansible-ansible-lint-c16f018/examples/playbooks/vars/rule_var_naming_fails_files/000077500000000000000000000000001477347356000303645ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/vars/rule_var_naming_fails_files/bar.yml000066400000000000000000000000621477347356000316510ustar00rootroot00000000000000--- CamelCaseIsBad: bar ALL_CAPS_ARE_BAD_TOO: bar ansible-ansible-lint-c16f018/examples/playbooks/vars/rule_var_naming_fails_files/foo.yml000066400000000000000000000000621477347356000316700ustar00rootroot00000000000000--- CamelCaseIsBad: foo ALL_CAPS_ARE_BAD_TOO: foo ansible-ansible-lint-c16f018/examples/playbooks/vars/strings.transformed.yml000066400000000000000000000025631477347356000274210ustar00rootroot00000000000000--- # Make sure that the Transformer does not mangle strings # TODO: there is a bug in ruamel.yaml that discards some EOL comments single: "single" # this is a comment single_with_double: '"single" quoted' # this is a comment single_multiline_with_octothorpe: "single over 160 char line to force wrapping. over 160 char line to force wrapping. over 160 char line to force wrapping. over 160\n # this is not a comment" double: "double" # this is a comment double_with_single: "'double' quoted" # this is a comment double_multiline_with_octothorpe: "double over 160 char line to force wrapping. over 160 char line to force wrapping. over 160 char line to force wrapping. over 160\n # this is not a comment" # this is a comment folded_block_scalar_with_octothorpe: > # comment 1 # this is not a comment # this is a comment folded_chomp_strip_block_scalar_with_octothorpe: >- # comment 2 # this is not a comment # this is a comment folded_chomp_keep_block_scalar_with_octothorpe: >+ # comment 3 # this is not a comment # this is a comment literal_block_scalar_with_octothorpe: | # this is a | EOL comment # this is not a comment # this is a comment literal_chomp_strip_block_scalar_with_octothorpe: |- # this is a | EOL comment # this is not a comment # this is a comment literal_chomp_keep_block_scalar_with_octothorpe: | # this is a | EOL comment # this is not a comment ansible-ansible-lint-c16f018/examples/playbooks/vars/strings.yml000066400000000000000000000026641477347356000251000ustar00rootroot00000000000000--- # Make sure that the Transformer does not mangle strings # TODO: there is a bug in ruamel.yaml that discards some EOL comments single: "single" # this is a comment single_with_double: '"single" quoted' # this is a comment single_multiline_with_octothorpe: # this EOL comment gets lost "single over 160 char line to force wrapping. over 160 char line to force wrapping. over 160 char line to force wrapping. over 160 # this is not a comment" double: "double" # this is a comment double_with_single: "'double' quoted" # this is a comment double_multiline_with_octothorpe: # this EOL comment gets lost "double over 160 char line to force wrapping. over 160 char line to force wrapping. over 160 char line to force wrapping. over 160 # this is not a comment" # this is a comment folded_block_scalar_with_octothorpe: > # comment 1 # this is not a comment # this is a comment folded_chomp_strip_block_scalar_with_octothorpe: >- # comment 2 # this is not a comment # this is a comment folded_chomp_keep_block_scalar_with_octothorpe: >+ # comment 3 # this is not a comment # this is a comment literal_block_scalar_with_octothorpe: | # this is a | EOL comment # this is not a comment # this is a comment literal_chomp_strip_block_scalar_with_octothorpe: |- # this is a | EOL comment # this is not a comment # this is a comment literal_chomp_keep_block_scalar_with_octothorpe: |+ # this is a | EOL comment # this is not a comment ansible-ansible-lint-c16f018/examples/playbooks/vars/subfolder/000077500000000000000000000000001477347356000246415ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks/vars/subfolder/settings.yml000066400000000000000000000000741477347356000272250ustar00rootroot00000000000000--- some_var: some_value_defined_in_vars_subfolder_settings ansible-ansible-lint-c16f018/examples/playbooks/vars/transform_nested_data.transformed.yml000066400000000000000000000001041477347356000322630ustar00rootroot00000000000000--- sequence: - - - 111 - 112 - 12 - - 21 - - 221 ansible-ansible-lint-c16f018/examples/playbooks/vars/transform_nested_data.yml000066400000000000000000000001341477347356000277430ustar00rootroot00000000000000--- sequence: - - - 111 - 112 - 12 - - 21 - - 221 ansible-ansible-lint-c16f018/examples/playbooks/vars/vault_full.yml000066400000000000000000000013531477347356000255560ustar00rootroot00000000000000--- $ANSIBLE_VAULT;1.1;AES256 35366433323361393130396530643233373262666636646439303032366431303363316232313738 3738636130636431623936303932306430316635663136610a353737333966353462333532393631 36613030643762636138613734313862333165346464626461313361353732336131633137653865 3862386136386137650a303433643531613337393735633338383163353737656339653134346363 63613436333937313738633437373566333065663662643664643261313366323236356364316663 62336264666464323066336365616634626336616537646336656266343562336533343732613539 61643661303566313664313164623731316236666235656337363632393665353536303730666532 64666639306361653963363462393966623763626566613831613739333666333665343734333630 63623730623033346163393834396639383234393637653733396466316132663131 ansible-ansible-lint-c16f018/examples/playbooks/vars/vault_partial.yml000066400000000000000000000007131477347356000262470ustar00rootroot00000000000000--- ldap_password: !vault | $ANSIBLE_VAULT;1.1;AES256 35323062386261383633623963303361313937653837333033613933623434343138663331336164 3534373564393166656664306537633035613962356662645a316562353832363736313935383665 33306432623765646338303236363061326538653163643466643446716164326364643937623365 6239383765373639390a646361343566353934633532376231653838386231653865386665303733 34336534613538326639306139363538306636383463663437643466653064646363 ansible-ansible-lint-c16f018/examples/playbooks/warning-from-module.yml000066400000000000000000000004701477347356000263160ustar00rootroot00000000000000--- # https://github.com/ansible/ansible-lint/issues/3216 - name: "Reproduce for bug #3216 warning from core module using Display.warning()" hosts: localhost gather_facts: false tasks: - name: Some task ansible.builtin.debug: msg: "{{ qq | unique }}" vars: qq: ["qq", "ww"] ansible-ansible-lint-c16f018/examples/playbooks/with-skip-tag-id.yml000066400000000000000000000002601477347356000255040ustar00rootroot00000000000000--- - hosts: all tasks: - name: Trailing whitespace on this line ansible.builtin.git: repo: "{{ archive_services_repo_url }}" dest: /home/www ansible-ansible-lint-c16f018/examples/playbooks/with-umlaut-ä.yml000066400000000000000000000000671477347356000255330ustar00rootroot00000000000000--- - hosts: - localhost roles: - name: node ansible-ansible-lint-c16f018/examples/playbooks_globs/000077500000000000000000000000001477347356000230675ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/playbooks_globs/a.yml000066400000000000000000000000551477347356000240320ustar00rootroot00000000000000--- - name: A hosts: localhost tasks: [] ansible-ansible-lint-c16f018/examples/playbooks_globs/b.yml000066400000000000000000000000641477347356000240330ustar00rootroot00000000000000--- - # missing name hosts: localhost tasks: [] ansible-ansible-lint-c16f018/examples/reqs_v1/000077500000000000000000000000001477347356000212565ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/reqs_v1/requirements.yml000066400000000000000000000005401477347356000245230ustar00rootroot00000000000000--- # v1 requirements test file # As Jeff never created releases on hit repo, we are unable to download tar.gz # archives, so we need to use the slower git cloning instead. # - src: https://github.com/geerlingguy/mysql/archive/refs/tags/4.2.0.tar.gz - name: geerlingguy.mysql src: https://github.com/geerlingguy/ansible-role-mysql version: 4.2.0 ansible-ansible-lint-c16f018/examples/reqs_v2/000077500000000000000000000000001477347356000212575ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/reqs_v2/requirements.yml000066400000000000000000000003211477347356000245210ustar00rootroot00000000000000--- roles: - name: geerlingguy.mysql src: https://github.com/geerlingguy/ansible-role-mysql version: 4.2.0 collections: - name: https://galaxy.ansible.com/download/community-molecule-0.1.0.tar.gz ansible-ansible-lint-c16f018/examples/roles/000077500000000000000000000000001477347356000210225ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/ansible-role-foo/000077500000000000000000000000001477347356000241575ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/ansible-role-foo/tasks/000077500000000000000000000000001477347356000253045ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/ansible-role-foo/tasks/main.yaml000066400000000000000000000000001477347356000271020ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/bobbins/000077500000000000000000000000001477347356000224405ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/bobbins/tasks/000077500000000000000000000000001477347356000235655ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/bobbins/tasks/imported_tasks.yml000066400000000000000000000000001477347356000273260ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/bobbins/tasks/main.yml000066400000000000000000000002001477347356000252240ustar00rootroot00000000000000--- - name: Test tasks action: git a=b c=d - name: Import tasks ansible.builtin.import_tasks: file: imported_tasks.yml ansible-ansible-lint-c16f018/examples/roles/broken_argument_specs/000077500000000000000000000000001477347356000254015ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/broken_argument_specs/meta/000077500000000000000000000000001477347356000263275ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/broken_argument_specs/meta/argument_specs.yml000066400000000000000000000001341477347356000320670ustar00rootroot00000000000000--- argument_specs: main: foo: bar # <-- invalid based on json schema options: {} ansible-ansible-lint-c16f018/examples/roles/dependency_in_meta/000077500000000000000000000000001477347356000246345ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/dependency_in_meta/meta/000077500000000000000000000000001477347356000255625ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/dependency_in_meta/meta/main.yml000066400000000000000000000022371477347356000272350ustar00rootroot00000000000000--- # meta file, determined by ending in meta/main.yml # https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html#role-dependencies allow_duplicates: true dependencies: # from Bitbucket - src: git+http://bitbucket.org/willthames/git-ansible-galaxy version: v1.4 # from Bitbucket, alternative syntax and caveats - src: http://bitbucket.org/willthames/hg-ansible-galaxy scm: hg # from galaxy - src: yatesr.timezone # from GitHub - src: https://github.com/bennojoy/nginx # from GitHub, overriding the name and specifying a specific tag - src: https://github.com/bennojoy/nginx version: master name: nginx_role # from GitLab or other git-based scm - src: git@gitlab.company.com:my-group/my-repo.git scm: git version: "0.1" # quoted, so YAML doesn't parse this as a floating-point value # from a webserver, where the role is packaged in a tar.gz - src: https://some.webserver.example.com/files/master.tar.gz name: http-role galaxy_info: standalone: true author: foo description: Testing meta company: Not applicable license: MIT min_ansible_version: "2.5" platforms: - name: Fedora ansible-ansible-lint-c16f018/examples/roles/fixture_1/000077500000000000000000000000001477347356000227305ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/fixture_1/tasks/000077500000000000000000000000001477347356000240555ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/fixture_1/tasks/main.yml000066400000000000000000000013561477347356000255310ustar00rootroot00000000000000--- - name: Bad git 1 # noqa: latest[git] action: ansible.builtin.git repo=. clone=no - name: Bad git 2 <-- 1st action: ansible.builtin.git repo=. clone=no - name: Block with rescue and always section block: - name: Bad git 3 # noqa: latest[git] action: ansible.builtin.git repo=. clone=no - name: Bad git 4 <-- 2nd action: ansible.builtin.git repo=. clone=no rescue: - name: Bad git 5 # noqa: latest[git] action: ansible.builtin.git repo=. clone=no - name: Bad git 6 <-- 3rd action: ansible.builtin.git repo=. clone=no always: - name: Bad git 7 # noqa: latest[git] action: ansible.builtin.git repo=. clone=no - name: Bad git 8 <-- 4th action: ansible.builtin.git repo=. clone=no ansible-ansible-lint-c16f018/examples/roles/foo.yml000066400000000000000000000000001477347356000223160ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/hello/000077500000000000000000000000001477347356000221255ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/hello/meta/000077500000000000000000000000001477347356000230535ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/hello/meta/argument_specs.yml000066400000000000000000000013611477347356000266160ustar00rootroot00000000000000--- # https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#role-argument-validation argument_specs: main: short_description: The main entry point for the role. description: "a longer description" options: my_app_int: type: "int" required: false default: 42 description: "The integer value, defaulting to 42." no_log: false my_app_str: type: "str" required: true description: "The string value" alternate: short_description: The alternate entry point for the my_app role. options: my_app_int: type: "int" required: false default: 1024 description: "The integer value, defaulting to 1024." ansible-ansible-lint-c16f018/examples/roles/hello/meta/main.yml000066400000000000000000000000441477347356000245200ustar00rootroot00000000000000--- dependencies: - role: bobbins ansible-ansible-lint-c16f018/examples/roles/include_in_the_place/000077500000000000000000000000001477347356000251375ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/include_in_the_place/tasks/000077500000000000000000000000001477347356000262645ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/include_in_the_place/tasks/included_file.yml000066400000000000000000000001421477347356000315720ustar00rootroot00000000000000--- - name: included_file | Test Fixture ansible.builtin.debug: msg: "was found & included" ansible-ansible-lint-c16f018/examples/roles/include_in_the_place/tasks/main.yml000066400000000000000000000001161477347356000277310ustar00rootroot00000000000000--- - name: Include a task ansible.builtin.include_tasks: included_file.yml ansible-ansible-lint-c16f018/examples/roles/include_miss/000077500000000000000000000000001477347356000235005ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/include_miss/tasks/000077500000000000000000000000001477347356000246255ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/include_miss/tasks/main.yml000066400000000000000000000001331477347356000262710ustar00rootroot00000000000000--- - name: Include a missing file ansible.builtin.include_tasks: tasks/noexist_file.yml ansible-ansible-lint-c16f018/examples/roles/include_relative/000077500000000000000000000000001477347356000243405ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/include_relative/tasks/000077500000000000000000000000001477347356000254655ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/include_relative/tasks/included_file.yml000066400000000000000000000001471477347356000310000ustar00rootroot00000000000000--- - name: included_file | Sample debug task ansible.builtin.debug: msg: "was found & included" ansible-ansible-lint-c16f018/examples/roles/include_relative/tasks/main.yml000066400000000000000000000004061477347356000271340ustar00rootroot00000000000000--- # ansible allow paths relative to role directory - name: 1st include ansible.builtin.include_tasks: tasks/included_file.yml # relative to the current file, same effect as previous line - name: 2nd include ansible.builtin.include_tasks: included_file.yml ansible-ansible-lint-c16f018/examples/roles/include_wrong_syntax/000077500000000000000000000000001477347356000252675ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/include_wrong_syntax/tasks/000077500000000000000000000000001477347356000264145ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/include_wrong_syntax/tasks/main.yml000066400000000000000000000001521477347356000300610ustar00rootroot00000000000000--- - name: Invalid syntax for import (coverage) ansible.builtin.import_tasks: wrong=imported_tasks.yml ansible-ansible-lint-c16f018/examples/roles/invalid-name/000077500000000000000000000000001477347356000233665ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/invalid-name/tasks/000077500000000000000000000000001477347356000245135ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/invalid-name/tasks/main.yaml000066400000000000000000000000661477347356000263250ustar00rootroot00000000000000--- - name: Foo ansible.builtin.debug: msg: foo ansible-ansible-lint-c16f018/examples/roles/invalid_due_syntax/000077500000000000000000000000001477347356000247135ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/invalid_due_syntax/tasks/000077500000000000000000000000001477347356000260405ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/invalid_due_syntax/tasks/main.yml000066400000000000000000000001001477347356000274760ustar00rootroot00000000000000--- - name: Fixture for testing syntax-check[specific] on roles ansible-ansible-lint-c16f018/examples/roles/invalid_due_to_meta/000077500000000000000000000000001477347356000250155ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/invalid_due_to_meta/meta/000077500000000000000000000000001477347356000257435ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/invalid_due_to_meta/meta/main.yml000066400000000000000000000003071477347356000274120ustar00rootroot00000000000000--- galaxy_info: standalone: true role_name: invalid-due-to-meta # <-- invalid role name author: foo description: foo license: MIT platforms: - name: AIX min_ansible_version: "2.7" ansible-ansible-lint-c16f018/examples/roles/invalid_due_to_meta/tasks/000077500000000000000000000000001477347356000261425ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/invalid_due_to_meta/tasks/main.yaml000066400000000000000000000000001477347356000277400ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/invalid_meta_schema/000077500000000000000000000000001477347356000247765ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/invalid_meta_schema/meta/000077500000000000000000000000001477347356000257245ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/invalid_meta_schema/meta/main.yml000066400000000000000000000002701477347356000273720ustar00rootroot00000000000000--- galaxy_info: standalone: true author: foo description: false # <-- schema fail as string is expected license: XXX platforms: - name: AIX min_ansible_version: "2.7" ansible-ansible-lint-c16f018/examples/roles/invalid_requirements_schema/000077500000000000000000000000001477347356000265735ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/invalid_requirements_schema/meta/000077500000000000000000000000001477347356000275215ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/invalid_requirements_schema/meta/requirements.yml000066400000000000000000000000531477347356000327650ustar00rootroot00000000000000--- # this should fail validation foo: bar ansible-ansible-lint-c16f018/examples/roles/invalud_meta_schema000066400000000000000000000000001477347356000247230ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/loop_var_prefix/000077500000000000000000000000001477347356000242205ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/loop_var_prefix/tasks/000077500000000000000000000000001477347356000253455ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/loop_var_prefix/tasks/fail.yml000066400000000000000000000017261477347356000270110ustar00rootroot00000000000000--- # 5 expected loop-var-prefix failures at 3, 9, 19, 26, 33 - name: fail | That should trigger loop-var-prefix ansible.builtin.debug: var: item loop: - foo - bar - name: fail | That should fail due to wrong prefix ansible.builtin.debug: var: zz_item loop: - foo - bar loop_control: loop_var: zz_item - name: fail | That should fail due to wrong prefix ansible.builtin.debug: var: zz_item with_items: - foo - bar loop_control: loop_var: zz_item - name: fail | Using a block block: - name: fail | That should also not pass ansible.builtin.debug: var: item loop: - apples - oranges rescue: - name: fail | That should also not pass ansible.builtin.debug: var: item loop: - avocados - kiwis always: - name: fail | That should also not pass ansible.builtin.debug: var: item loop: - bananas - muscats ansible-ansible-lint-c16f018/examples/roles/loop_var_prefix/tasks/pass.yml000066400000000000000000000012741477347356000270420ustar00rootroot00000000000000--- # 0 expected loop-var-prefix failures - name: pass | That should pass ansible.builtin.debug: var: loop_var_prefix_item loop: - foo - bar loop_control: loop_var: loop_var_prefix_item - name: pass | Using a block block: - name: pass | That should also pass ansible.builtin.debug: var: loop_var_prefix_item loop: - foo - bar loop_control: loop_var: loop_var_prefix_item - name: pass | Using alternative double underline prefix block: - name: pass | That should also pass ansible.builtin.debug: var: __some_item loop: - foo - bar loop_control: loop_var: __some_item ansible-ansible-lint-c16f018/examples/roles/meta_categories_as_list/000077500000000000000000000000001477347356000256735ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/meta_categories_as_list/meta/000077500000000000000000000000001477347356000266215ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/meta_categories_as_list/meta/main.yml000066400000000000000000000001501477347356000302640ustar00rootroot00000000000000--- galaxy_info: galaxy_tags: ["database", "my s q l", "MYTAG"] categories: ["networking", "posix"] ansible-ansible-lint-c16f018/examples/roles/meta_incorrect_fail/000077500000000000000000000000001477347356000250135ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/meta_incorrect_fail/meta/000077500000000000000000000000001477347356000257415ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/meta_incorrect_fail/meta/main.yml000066400000000000000000000004341477347356000274110ustar00rootroot00000000000000# Fixture for meta-incorrect --- galaxy_info: # <-- 4x meta-incorrect author: your name description: your description company: your company (optional) license: license (GPLv2, CC-BY, etc) min_ansible_version: "2.12" platforms: - name: EL versions: - "7" ansible-ansible-lint-c16f018/examples/roles/meta_no_tags_galaxy_info/000077500000000000000000000000001477347356000260425ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/meta_no_tags_galaxy_info/meta/000077500000000000000000000000001477347356000267705ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/meta_no_tags_galaxy_info/meta/main.yml000066400000000000000000000000631477347356000304360ustar00rootroot00000000000000--- galaxy_tags: ["database", "my s q l", "MYTAG"] ansible-ansible-lint-c16f018/examples/roles/meta_no_tags_valid/000077500000000000000000000000001477347356000246415ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/meta_no_tags_valid/meta/000077500000000000000000000000001477347356000255675ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/meta_no_tags_valid/meta/main.yml000066400000000000000000000001541477347356000272360ustar00rootroot00000000000000--- galaxy_info: galaxy_tags: ["database", "my s q l", "MYTAG"] categories: "my_category_not_in_a_list" ansible-ansible-lint-c16f018/examples/roles/meta_noqa/000077500000000000000000000000001477347356000227665ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/meta_noqa/meta/000077500000000000000000000000001477347356000237145ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/meta_noqa/meta/main.yml000066400000000000000000000003411477347356000253610ustar00rootroot00000000000000--- galaxy_info: # noqa: meta-incorrect standalone: true author: your-name description: missing min_ansible_version and platforms. author default not changed license: MIT min_ansible_version: "2.10" platforms: [] ansible-ansible-lint-c16f018/examples/roles/meta_tags_no_list/000077500000000000000000000000001477347356000245155ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/meta_tags_no_list/meta/000077500000000000000000000000001477347356000254435ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/meta_tags_no_list/meta/main.yml000066400000000000000000000000531477347356000271100ustar00rootroot00000000000000--- galaxy_info: galaxy_tags: "database" ansible-ansible-lint-c16f018/examples/roles/meta_tags_not_a_string/000077500000000000000000000000001477347356000255345ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/meta_tags_not_a_string/meta/000077500000000000000000000000001477347356000264625ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/meta_tags_not_a_string/meta/main.yml000066400000000000000000000001441477347356000301300ustar00rootroot00000000000000--- galaxy_info: galaxy_tags: [False, "database", "my s q l", "MYTAG"] categories: "networking" ansible-ansible-lint-c16f018/examples/roles/meta_video_links_fail/000077500000000000000000000000001477347356000253315ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/meta_video_links_fail/meta/000077500000000000000000000000001477347356000262575ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/meta_video_links_fail/meta/main.yml000066400000000000000000000016041477347356000277270ustar00rootroot00000000000000# Test fixture for mete-video-links test --- galaxy_info: standalone: true author: foo description: bar license: MIT min_ansible_version: "2.12" platforms: - name: EL versions: - "9" # https://github.com/ansible/galaxy/blob/devel/galaxy/importer/loaders/role.py video_links: - url: https://www.youtube.com/watch?v=aWmRepTSFKs&feature=youtu.be title: Proper format - url: https://drive.google.com/file/d/1spYR51l8SqQqvAhSdZE7/view title: Check for VIDEO_REGEXP validity and break - https://www.youtube.com/watch?v=aWmRepTSFKs&feature=youtu.be - my_bad_key: https://www.youtube.com/watch?v=aWmRepTSFKs&feature=youtu.be title: This has a bad key - url: www.acme.com/vid title: Bad format of url # https://github.com/ansible/galaxy/blob/devel/galaxy/importer/loaders/role.py#L303 cloud_platforms: - amazon - azure ansible-ansible-lint-c16f018/examples/roles/meta_video_links_pass/000077500000000000000000000000001477347356000253645ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/meta_video_links_pass/meta/000077500000000000000000000000001477347356000263125ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/meta_video_links_pass/meta/main.yml000066400000000000000000000003531477347356000277620ustar00rootroot00000000000000--- galaxy_info: author: foo description: bar license: MIT min_ansible_version: "2.12" platforms: - name: EL versions: - "9" video_links: - url: https://youtu.be/S49_fX47UJA title: Proper format ansible-ansible-lint-c16f018/examples/roles/more_complex/000077500000000000000000000000001477347356000235135ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/more_complex/handlers/000077500000000000000000000000001477347356000253135ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/more_complex/handlers/main.yml000066400000000000000000000001111477347356000267530ustar00rootroot00000000000000--- - name: Restart service using command command: service bar restart ansible-ansible-lint-c16f018/examples/roles/more_complex/tasks/000077500000000000000000000000001477347356000246405ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/more_complex/tasks/main.yml000066400000000000000000000002551477347356000263110ustar00rootroot00000000000000--- - name: Test bad command action: command mkdir blah - name: Test bad command v2 command: mkdir blah - name: Test bad local command local_action: shell touch foo ansible-ansible-lint-c16f018/examples/roles/name_casing/000077500000000000000000000000001477347356000232665ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/name_casing/tasks/000077500000000000000000000000001477347356000244135ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/name_casing/tasks/main.transformed.yml000066400000000000000000000005011477347356000304010ustar00rootroot00000000000000--- - name: Test nested tasks within block and always block: - name: Test1 ansible.builtin.debug: msg: Foo - name: Test2 ansible.builtin.debug: msg: Bar always: - name: From always block to be auto fixed as name[casing] scenario ansible.builtin.debug: msg: Baz ansible-ansible-lint-c16f018/examples/roles/name_casing/tasks/main.yml000066400000000000000000000005011477347356000260560ustar00rootroot00000000000000--- - name: Test nested tasks within block and always block: - name: test1 ansible.builtin.debug: msg: Foo - name: Test2 ansible.builtin.debug: msg: Bar always: - name: from always block to be auto fixed as name[casing] scenario ansible.builtin.debug: msg: Baz ansible-ansible-lint-c16f018/examples/roles/name_prefix/000077500000000000000000000000001477347356000233175ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/name_prefix/tasks/000077500000000000000000000000001477347356000244445ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/name_prefix/tasks/test.transformed.yml000066400000000000000000000001771477347356000304760ustar00rootroot00000000000000--- - name: test | Not cap ansible.builtin.debug: msg: not cap - name: test | Cap ansible.builtin.debug: msg: Cap ansible-ansible-lint-c16f018/examples/roles/name_prefix/tasks/test.yml000066400000000000000000000001771477347356000261530ustar00rootroot00000000000000--- - name: test | not cap ansible.builtin.debug: msg: not cap - name: test | Cap ansible.builtin.debug: msg: Cap ansible-ansible-lint-c16f018/examples/roles/role_detection/000077500000000000000000000000001477347356000240215ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/role_detection/base/000077500000000000000000000000001477347356000247335ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/role_detection/base/bar/000077500000000000000000000000001477347356000254775ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/role_detection/base/bar/defaults/000077500000000000000000000000001477347356000273065ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/role_detection/base/bar/defaults/main.yml000066400000000000000000000000441477347356000307530ustar00rootroot00000000000000--- base_var_1: foo base_var_2: foo ansible-ansible-lint-c16f018/examples/roles/role_detection/foo/000077500000000000000000000000001477347356000246045ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/role_detection/foo/defaults/000077500000000000000000000000001477347356000264135ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/role_detection/foo/defaults/main.yml000066400000000000000000000000421477347356000300560ustar00rootroot00000000000000--- foo_var_1: bar foo_var_2: bar ansible-ansible-lint-c16f018/examples/roles/role_for_no_same_owner/000077500000000000000000000000001477347356000255445ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/role_for_no_same_owner/tasks/000077500000000000000000000000001477347356000266715ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/role_for_no_same_owner/tasks/fail.yml000066400000000000000000000031541477347356000303320ustar00rootroot00000000000000--- - name: fail | Block block: - name: fail | Synchronize-in-block ansible.posix.synchronize: src: dummy dest: dummy - name: fail | Synchronize ansible.posix.synchronize: src: dummy dest: dummy - name: fail | Nested-block block: - name: fail | Synchronize block: - name: fail | Synchronize-in-deep-block ansible.posix.synchronize: src: dummy dest: dummy rescue: - name: fail | Synchronize-in-rescue ansible.posix.synchronize: src: dummy dest: dummy always: - name: fail | Synchronize-in-always ansible.posix.synchronize: src: dummy dest: dummy - name: fail | Unarchive-bz2 ansible.builtin.unarchive: src: "{{ file }}.tar.bz2" dest: dummy - name: fail | Unarchive delegated ansible.builtin.unarchive: src: "{{ file }}.tar.bz2" dest: dummy delegate_to: localhost - name: fail | Unarchive delegated-src-no-string ansible.builtin.unarchive: src: 4432 dest: dummy delegate_to: localhost - name: fail | Unarchive-gz ansible.builtin.unarchive: src: "{{ file }}.tar.gz" dest: dummy - name: fail | Unarchive-tar ansible.builtin.unarchive: src: "{{ file }}.tar" dest: dummy - name: fail | Unarchive-xz ansible.builtin.unarchive: src: "{{ file }}.tar.xz" dest: dummy - name: fail | Unarchive-zip ansible.builtin.unarchive: src: "{{ file }}.zip" dest: dummy extra_opts: - -X - name: fail | Unarchive-zip-same-owner ansible.builtin.unarchive: src: "{{ file }}.zip" dest: dummy extra_opts: - -X ansible-ansible-lint-c16f018/examples/roles/role_for_no_same_owner/tasks/pass.yml000066400000000000000000000012471477347356000303660ustar00rootroot00000000000000--- - name: pass | Synchronize-delegate ansible.posix.synchronize: src: dummy dest: dummy delegate_to: localhost - name: pass | Synchronize-no-same-owner ansible.posix.synchronize: src: dummy dest: dummy owner: false group: false - name: pass | Unarchive-no-same-owner ansible.builtin.unarchive: src: "{{ file }}.tar.gz" dest: dummy extra_opts: - --no-same-owner - name: pass | Unarchive-remote-src ansible.builtin.unarchive: src: "{{ file }}.tar.gz" dest: dummy extra_opts: - --no-same-owner - name: pass | Unarchive-unknown-file-ending ansible.builtin.unarchive: src: "{{ file }}" dest: dummy ansible-ansible-lint-c16f018/examples/roles/role_vars_prefix_detection/000077500000000000000000000000001477347356000264315ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/role_vars_prefix_detection/defaults/000077500000000000000000000000001477347356000302405ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/role_vars_prefix_detection/defaults/main.yml000066400000000000000000000000151477347356000317030ustar00rootroot00000000000000--- foo: bar ansible-ansible-lint-c16f018/examples/roles/role_vars_prefix_detection/vars/000077500000000000000000000000001477347356000274045ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/role_vars_prefix_detection/vars/main.yml000066400000000000000000000000611477347356000310500ustar00rootroot00000000000000--- role_vars_prefix_detection_bar: baz bar: baz ansible-ansible-lint-c16f018/examples/roles/role_with_deps_paths/000077500000000000000000000000001477347356000252305ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/role_with_deps_paths/meta/000077500000000000000000000000001477347356000261565ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/role_with_deps_paths/meta/main.yml000066400000000000000000000002551477347356000276270ustar00rootroot00000000000000--- dependencies: - role: subfolder/1st_role vars: param: baz - role: subfolder vars: param: baz - role: subfolder/2nd_role - subfolder/3rd_role ansible-ansible-lint-c16f018/examples/roles/role_with_handler/000077500000000000000000000000001477347356000245135ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/role_with_handler/handlers/000077500000000000000000000000001477347356000263135ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/role_with_handler/handlers/main.yml000066400000000000000000000003021477347356000277550ustar00rootroot00000000000000--- - name: Debug loop: "{{ _something_done.results }}" loop_control: label: "{{ item.item.name }}" when: item.changed ansible.builtin.debug: msg: "{{ item.item.name }} changed" ansible-ansible-lint-c16f018/examples/roles/role_with_handler/tasks/000077500000000000000000000000001477347356000256405ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/role_with_handler/tasks/main.yml000066400000000000000000000005221477347356000273060ustar00rootroot00000000000000--- - name: Get info delegate_to: localhost register: collected_info ansible.builtin.debug: msg: test - name: Do something delegate_to: localhost loop: "{{ collected_info['some_list'] }}" loop_control: label: "{{ item.name }}" notify: - Debug register: _something_done ansible.builtin.debug: msg: test2 ansible-ansible-lint-c16f018/examples/roles/role_with_task_inclusions/000077500000000000000000000000001477347356000263065ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/role_with_task_inclusions/tasks/000077500000000000000000000000001477347356000274335ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/role_with_task_inclusions/tasks/imported_tasks.yml000066400000000000000000000001121477347356000332000ustar00rootroot00000000000000--- # this task is missing a name (name[missing]) - ansible.builtin.ping: ansible-ansible-lint-c16f018/examples/roles/role_with_task_inclusions/tasks/included_tasks.yml000066400000000000000000000001121477347356000331440ustar00rootroot00000000000000--- # this task is missing a name (name[missing]) - ansible.builtin.ping: ansible-ansible-lint-c16f018/examples/roles/role_with_task_inclusions/tasks/main.yml000066400000000000000000000003771477347356000311110ustar00rootroot00000000000000--- - name: Include 1 ansible.builtin.include_tasks: included_tasks.yml - name: Include 2 ansible.builtin.import_tasks: imported_tasks.yml - name: Include 3 ansible.builtin.include_tasks: file: included_tasks.yml apply: tags: some_tag ansible-ansible-lint-c16f018/examples/roles/subfolder/000077500000000000000000000000001477347356000230075ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/subfolder/1st_role/000077500000000000000000000000001477347356000245375ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/subfolder/1st_role/tasks/000077500000000000000000000000001477347356000256645ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/subfolder/1st_role/tasks/main.yml000066400000000000000000000000001477347356000273210ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/subfolder/2nd_role/000077500000000000000000000000001477347356000245135ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/subfolder/2nd_role/tasks/000077500000000000000000000000001477347356000256405ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/subfolder/2nd_role/tasks/main.yml000066400000000000000000000000001477347356000272750ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/subfolder/3rd_role/000077500000000000000000000000001477347356000245205ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/subfolder/3rd_role/tasks/000077500000000000000000000000001477347356000256455ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/subfolder/3rd_role/tasks/main.yml000066400000000000000000000000001477347356000273020ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/subfolder/other_role/000077500000000000000000000000001477347356000251515ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/subfolder/other_role/tasks/000077500000000000000000000000001477347356000262765ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/subfolder/other_role/tasks/main.yml000066400000000000000000000000531477347356000277430ustar00rootroot00000000000000--- - name: Foo debug: msg: "Hello!" ansible-ansible-lint-c16f018/examples/roles/template_lookup/000077500000000000000000000000001477347356000242265ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/template_lookup/files/000077500000000000000000000000001477347356000253305ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/template_lookup/files/a_file000066400000000000000000000000001477347356000264600ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/template_lookup/tasks/000077500000000000000000000000001477347356000253535ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/template_lookup/tasks/main.yml000066400000000000000000000007301477347356000270220ustar00rootroot00000000000000--- # Place tasks in a block as templates are not rendered for top-level tasks # in roles. Specifically, in `play_children()` of src/ansiblelint/utils.py, # tasks in blocks go through `delegate_map['block']`, while top-level tasks # in a role is not handled by `delegate_map`. # Ref: https://github.com/ansible/ansible-lint/blob/v5.0.12/src/ansiblelint/utils.py#L305 - block: - name: Bug demo ansible.builtin.debug: msg: '{{ lookup("file", "a_file") }}' ansible-ansible-lint-c16f018/examples/roles/template_lookup_missing/000077500000000000000000000000001477347356000257575ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/template_lookup_missing/tasks/000077500000000000000000000000001477347356000271045ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/template_lookup_missing/tasks/main.yml000066400000000000000000000003211477347356000305470ustar00rootroot00000000000000--- # See comments in `examples/roles/template_lookup/tasks/main.yml` # for why the task is in a block. - block: - name: Bug demo ansible.builtin.debug: msg: '{{ lookup("file", "a_file") }}' ansible-ansible-lint-c16f018/examples/roles/test-no-deps-role/000077500000000000000000000000001477347356000243035ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/test-no-deps-role/meta/000077500000000000000000000000001477347356000252315ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/test-no-deps-role/meta/main.yml000066400000000000000000000034041477347356000267010ustar00rootroot00000000000000--- galaxy_info: author: audgirka description: your role description company: Red Hat role_name: test_no_deps_role # if absent directory name hosting role is used instead namespace: foo # if absent, author is used instead # If the issue tracker for your role is not on github, uncomment the # next line and provide a value # issue_tracker_url: http://example.com/issue/tracker # Choose a valid license ID from https://spdx.org - some suggested licenses: # - BSD-3-Clause (default) # - MIT # - GPL-2.0-or-later # - GPL-3.0-only # - Apache-2.0 # - CC-BY-4.0 license: GPL-2.0-or-later min_ansible_version: "2.1" # If this a Container Enabled role, provide the minimum Ansible Container version. # min_ansible_container_version: # # Provide a list of supported platforms, and for each platform a list of versions. # If you don't wish to enumerate all versions for a particular platform, use 'all'. # To view available platforms and versions (or releases), visit: # https://galaxy.ansible.com/api/v1/platforms/ # # platforms: # - name: Fedora # versions: # - all # - 25 # - name: SomePlatform # versions: # - all # - 1.0 # - 7 # - 99.99 galaxy_tags: [] # List tags for your role here, one per line. A tag is a keyword that describes # and categorizes the role. Users find roles by searching for tags. Be sure to # remove the '[]' above, if you add tags to this list. # # NOTE: A tag is limited to a single word comprised of alphanumeric characters. # Maximum 20 tags per role. # Skipping deps for testing scenario when no role deps are present # dependencies: [] # List your role dependencies here, one per line. Be sure to remove the '[]' above, # if you add dependencies to this list. ansible-ansible-lint-c16f018/examples/roles/test-role/000077500000000000000000000000001477347356000227405ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/test-role/meta/000077500000000000000000000000001477347356000236665ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/test-role/meta/requirements.yml000066400000000000000000000000361477347356000271330ustar00rootroot00000000000000--- roles: [] collections: [] ansible-ansible-lint-c16f018/examples/roles/test-role/molecule/000077500000000000000000000000001477347356000245455ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/test-role/molecule/default/000077500000000000000000000000001477347356000261715ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/test-role/molecule/default/include-import-role.yml000066400000000000000000000001611477347356000326040ustar00rootroot00000000000000--- - name: Fixture for test_run_playbook test gather_facts: false hosts: all roles: - role: test-role ansible-ansible-lint-c16f018/examples/roles/test-role/tasks/000077500000000000000000000000001477347356000240655ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/test-role/tasks/main.yml000066400000000000000000000001301477347356000255260ustar00rootroot00000000000000--- - name: Shell instead of command ansible.builtin.shell: cmd: echo hello world ansible-ansible-lint-c16f018/examples/roles/test-role/tasks/world.yml000066400000000000000000000001351477347356000257360ustar00rootroot00000000000000--- - command: # noqa: fqcn cmd: echo this is a task without a name # noqa: no-free-form ansible-ansible-lint-c16f018/examples/roles/valid-due-to-meta/000077500000000000000000000000001477347356000242405ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/valid-due-to-meta/meta/000077500000000000000000000000001477347356000251665ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/valid-due-to-meta/meta/main.yml000066400000000000000000000002601477347356000266330ustar00rootroot00000000000000--- galaxy_info: standalone: true role_name: valid_due_to_meta author: foo description: foo license: MIT platforms: - name: Fedora min_ansible_version: "2.7" ansible-ansible-lint-c16f018/examples/roles/valid-due-to-meta/tasks/000077500000000000000000000000001477347356000253655ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/valid-due-to-meta/tasks/debian/000077500000000000000000000000001477347356000266075ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/valid-due-to-meta/tasks/debian/main.yml000066400000000000000000000002021477347356000302500ustar00rootroot00000000000000# This empty task file is here to test that roles with tasks organized in subdirectories # are handled correctly by ansible-lint. ansible-ansible-lint-c16f018/examples/roles/valid-due-to-meta/tasks/main.yaml000066400000000000000000000000001477347356000271630ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/var_naming_pattern/000077500000000000000000000000001477347356000247005ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/var_naming_pattern/.ansible-lint000066400000000000000000000001151477347356000272570ustar00rootroot00000000000000--- var_naming_pattern: "^[a-z][a-z0-9_]*[a-z0-9]__[a-z][a-z0-9_]*[a-z0-9]$" ansible-ansible-lint-c16f018/examples/roles/var_naming_pattern/tasks/000077500000000000000000000000001477347356000260255ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/roles/var_naming_pattern/tasks/cacheable_set_fact.yml000066400000000000000000000002201477347356000323010ustar00rootroot00000000000000--- - name: cacheable_set_fact | Using set_fact with cacheable ansible.builtin.set_fact: var_naming_pattern_fact: bar cacheable: true ansible-ansible-lint-c16f018/examples/roles/var_naming_pattern/tasks/include_task_with_vars.yml000066400000000000000000000011741477347356000333060ustar00rootroot00000000000000--- - name: include_task_with_vars | Var1 ansible.builtin.include_tasks: file=../tasks/included-task-with-vars.yml - name: include_task_with_vars | Var2 ansible.builtin.include_tasks: ../tasks/included-task-with-vars.yml vars: var_naming_pattern_1: bar _var_naming_pattern_2: ... # we allow _ before the prefix __var_naming_pattern_3: ... # we allow __ before the prefix - name: include_task_with_vars | Var3 ansible.builtin.include_role: name: bobbins vars: bobbins_foo: bar # ^ this is valid because for include/import, the prefix should be of the # included role and from of the current role. ansible-ansible-lint-c16f018/examples/roles/var_naming_pattern/tasks/main.yml000066400000000000000000000001301477347356000274660ustar00rootroot00000000000000--- - name: Foobar ansible.builtin.set_fact: var_naming_pattern__namespace: "foo" ansible-ansible-lint-c16f018/examples/rulebooks/000077500000000000000000000000001477347356000217035ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/rulebooks/rulebook-fail.yml000066400000000000000000000011711477347356000251610ustar00rootroot00000000000000--- - name: Sample rulebooks hosts: all that_should_not_be_here: foo # <-- this is not supported sources: # <-- should be "sources" - name: listen for alerts ansible.eda.alertmanager: host: 0.0.0.0 port: 8000 rules: - name: restart web server condition: event.alert.labels.job == "fastapi" and event.alert.status == "firing" action: run_playbook: name: ansible.eda.start_app copy_files: true post_events: true - name: debug condition: event.alert.labels.job == "fastapi" action: debug: sss # <-- this should be an object ansible-ansible-lint-c16f018/examples/rulebooks/rulebook-pass.yml000066400000000000000000000004411477347356000252130ustar00rootroot00000000000000--- - name: Demo rules with kafka as source hosts: localhost sources: - name: kafka kafka: topic: eda host: localhost port: 9092 group_id: testing rules: - name: Demo rule condition: event.i is defined action: debug: ansible-ansible-lint-c16f018/examples/rules/000077500000000000000000000000001477347356000210305ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/rules/task_has_tag.py000066400000000000000000000021471477347356000240360ustar00rootroot00000000000000"""Example implementation of a rule requiring tasks to have tags set.""" from __future__ import annotations 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 TaskHasTag(AnsibleLintRule): """Tasks must have tag.""" id = "EXAMPLE001" description = "Tasks must have tag" tags = ["productivity", "tags"] def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: """Task matching method.""" if isinstance(task, str): return False # If the task include another task or make the playbook fail # Don't force to have a tag if not set(task.keys()).isdisjoint(["include", "fail"]): return False if not set(task.keys()).isdisjoint(["include_tasks", "fail"]): return False if not set(task.keys()).isdisjoint(["import_tasks", "fail"]): return False # Task should have tags return "tags" not in task ansible-ansible-lint-c16f018/examples/sanity_ignores/000077500000000000000000000000001477347356000227335ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/sanity_ignores/tests/000077500000000000000000000000001477347356000240755ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/sanity_ignores/tests/sanity/000077500000000000000000000000001477347356000254045ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/sanity_ignores/tests/sanity/ignore-2.13.txt000066400000000000000000000002121477347356000300040ustar00rootroot00000000000000plugins/module_utils/ansible_example_module.py validate-modules:deprecation-mismatch # comment tests/unit/file.py import-3.6!skip ansible-ansible-lint-c16f018/examples/sanity_ignores/tests/sanity/ignore-2.15.txt000066400000000000000000000003001477347356000300040ustar00rootroot00000000000000plugins/module_utils/ansible_example_module.incorrect-3.6!skip #plugins/module_utils/ansible_example_module.py import-3.6!skip other_dir/module_utils/ansible_example_module incorrect-3.6!skip ansible-ansible-lint-c16f018/examples/sanity_ignores/tests/sanity/ignore-2.9.txt000066400000000000000000000003561477347356000277420ustar00rootroot00000000000000# Should be fully skipped plugins/module_utils/ansible_example_module.py validate-modules:deprecation-mismatch plugins/module_utils/ansible_example_module.py import-2.6!skip plugins/module_utils/ansible_example_module.py validate-modules ansible-ansible-lint-c16f018/examples/site.yml000066400000000000000000000002061477347356000213630ustar00rootroot00000000000000--- # site.yml - ansible.builtin.import_playbook: playbooks/play.yml - ansible.builtin.import_playbook: playbooks/playbook-parent.yml ansible-ansible-lint-c16f018/examples/templates/000077500000000000000000000000001477347356000216745ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/templates/playbooks/000077500000000000000000000000001477347356000236775ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/templates/playbooks/playbook.yml000066400000000000000000000004571477347356000262500ustar00rootroot00000000000000--- # even if is hosted under playbooks and is named playbook.yml, this file # is not a real playbook because it is hosted in a "templates" directory # and that means we will avoid processing it as a playbook. Templates use # either jinja2 or another templating engine, so we cannot load them. foo: bar ansible-ansible-lint-c16f018/examples/testproject/000077500000000000000000000000001477347356000222445ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/testproject/roles/000077500000000000000000000000001477347356000233705ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/testproject/roles/test-role/000077500000000000000000000000001477347356000253065ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/testproject/roles/test-role/tasks/000077500000000000000000000000001477347356000264335ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/testproject/roles/test-role/tasks/main.yml000066400000000000000000000000771477347356000301060ustar00rootroot00000000000000--- - name: Shell instead of command shell: echo hello world ansible-ansible-lint-c16f018/examples/yamllint/000077500000000000000000000000001477347356000215275ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/yamllint/.github/000077500000000000000000000000001477347356000230675ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/yamllint/.github/workflows/000077500000000000000000000000001477347356000251245ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/yamllint/.github/workflows/ci.yml000066400000000000000000000003571477347356000262470ustar00rootroot00000000000000--- name: ack on: # <-- this is invalid by YAML 1.2 spec as it loads as true boolean. pull_request_target: types: [opened, labeled, unlabeled, synchronize] jobs: ack: uses: ansible/team-devtools/.github/workflows/ack.yml@main ansible-ansible-lint-c16f018/examples/yamllint/incompatible-config/000077500000000000000000000000001477347356000254405ustar00rootroot00000000000000ansible-ansible-lint-c16f018/examples/yamllint/incompatible-config/.yamllint000066400000000000000000000006461477347356000273000ustar00rootroot00000000000000# This config file is full of yamllint configuration settings that are # incompatible with ansible-lint. It used for testing their detection. rules: comments: min-spaces-from-content: 2 comments-indentation: false braces: min-spaces-inside: 1 max-spaces-inside: 2 key-duplicates: forbid-duplicated-merge-keys: false octal-values: forbid-implicit-octal: false forbid-explicit-octal: false ansible-ansible-lint-c16f018/examples/yamllint/invalid.yml000066400000000000000000000002611477347356000236770ustar00rootroot00000000000000# missing document-start foo: ... foo: ... # <-- key-duplicates bar: ... # <-- wrong comment indentation # next line has trailing-spaces: other: aaa # ^ empty-lines ansible-ansible-lint-c16f018/examples/yamllint/line-length.yml000066400000000000000000000003111477347356000244530ustar00rootroot00000000000000--- - name: Task example debug: msg: "This is a very long text that is used in order to verify the rule that checks for very long lines. We do hope it was long enough to go over the line limit." ansible-ansible-lint-c16f018/examples/yamllint/multi-document.yaml000066400000000000000000000000321477347356000253540ustar00rootroot00000000000000--- foo: ... --- bar: ... ansible-ansible-lint-c16f018/examples/yamllint/skipped-rule.yml000066400000000000000000000000621477347356000246540ustar00rootroot00000000000000--- - test: skipped_rule # noqa name - other: aaa ansible-ansible-lint-c16f018/examples/yamllint/valid.yml000066400000000000000000000000001477347356000233370ustar00rootroot00000000000000ansible-ansible-lint-c16f018/mkdocs.yml000066400000000000000000000123021477347356000200610ustar00rootroot00000000000000--- site_name: Ansible Lint Documentation site_url: https://ansible.readthedocs.io/projects/lint/ repo_url: https://github.com/ansible/ansible-lint edit_uri: blob/main/docs/ copyright: Copyright © Red Hat, Inc. docs_dir: docs strict: true extra_css: - stylesheets/extra.css theme: name: ansible features: - announce.dismiss - content.action.edit - content.action.view - content.code.annotate - content.code.copy - content.tabs.link - content.tooltips - header.autohide - navigation.expand - navigation.footer - navigation.indexes - navigation.instant - navigation.path - navigation.prune - navigation.sections - navigation.tabs - navigation.tabs.sticky - navigation.top - navigation.tracking - search.highlight - search.share - search.suggest - toc.integrate extra: social: - icon: fontawesome/brands/python link: https://pypi.org/project/ansible-lint/ name: PyPI - icon: fontawesome/solid/scroll link: https://github.com/ansible/ansible-lint/releases name: Releases - icon: simple/mastodon link: https://fosstodon.org/@ansible name: Mastodon - icon: fontawesome/brands/twitter link: https://twitter.com/ansible name: Twitter - icon: simple/matrix link: https://matrix.to/#/#devtools:ansible.com name: Matrix - icon: fontawesome/brands/discourse link: https://forum.ansible.com/c/project/7 name: Ansible forum - icon: fontawesome/brands/github-alt link: https://github.com/ansible/ansible-lint name: GitHub nav: - Home: - home: index.md - Philosophy: philosophy.md - usage.md - Setup: - installing.md - configuring.md - profiles.md - autofix.md - Rules: - index: rules/index.md - rules/args.md - rules/avoid-implicit.md - rules/complexity.md - rules/command-instead-of-module.md - rules/command-instead-of-shell.md - rules/deprecated-bare-vars.md - rules/deprecated-local-action.md - rules/deprecated-module.md - rules/empty-string-compare.md - rules/fqcn.md - rules/galaxy-version-incorrect.md - rules/galaxy.md - rules/ignore-errors.md - rules/inline-env-var.md - rules/internal-error.md - rules/jinja.md - rules/key-order.md - rules/latest.md - rules/literal-compare.md - rules/load-failure.md - rules/loop-var-prefix.md - rules/meta-incorrect.md - rules/meta-no-tags.md - rules/meta-runtime.md - rules/meta-video-links.md - rules/name.md - rules/no-changed-when.md - rules/no-free-form.md - rules/no-handler.md - rules/no-jinja-when.md - rules/no-log-password.md - rules/no-prompting.md - rules/no-relative-paths.md - rules/no-same-owner.md - rules/no-tabs.md - rules/only-builtins.md - rules/package-latest.md - rules/parser-error.md - rules/partial-become.md - rules/playbook-extension.md - rules/risky-file-permissions.md - rules/risky-octal.md - rules/risky-shell-pipe.md - rules/role-name.md - rules/run-once.md - rules/sanity.md - rules/schema.md - rules/syntax-check.md - rules/var-naming.md - rules/warning.md - rules/yaml.md - Developer Guide: - Contributing: contributing.md - custom-rules.md exclude_docs: | _autofix_rules.md plugins: - autorefs - macros: modules: [mkdocs-ansible:mkdocs_ansible] render_by_default: false - markdown-exec - gen-files: scripts: - tools/generate_docs.py - material/search: separator: '[\s\-,:!=\[\]()"`/]+|\.(?!\d)|&[lg]t;|(?!\b)(?=[A-Z][a-z])' - material/social - material/tags # https://github.com/manuzhang/mkdocs-htmlproofer-plugin # - htmlproofer - mkdocstrings: handlers: python: paths: [src] options: # Sphinx is for historical reasons, but we could consider switching if needed # https://mkdocstrings.github.io/griffe/docstrings/ docstring_style: sphinx merge_init_into_class: yes show_submodules: yes inventories: - url: https://docs.ansible.com/ansible/latest/objects.inv domains: [py, std] markdown_extensions: - markdown_include.include: base_path: docs - admonition - def_list - footnotes - pymdownx.highlight: anchor_linenums: true - pymdownx.inlinehilite - pymdownx.superfences - pymdownx.magiclink: repo_url_shortener: true repo_url_shorthand: true social_url_shorthand: true social_url_shortener: true user: facelessuser repo: pymdown-extensions normalize_issue_symbols: true - pymdownx.tabbed: alternate_style: true - toc: toc_depth: 2 permalink: true - pymdownx.superfences: custom_fences: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format - name: python class: python validator: !!python/name:markdown_exec.validator format: !!python/name:markdown_exec.formatter ansible-ansible-lint-c16f018/package-lock.json000066400000000000000000000012521477347356000212740ustar00rootroot00000000000000{ "name": "ansible-lint", "lockfileVersion": 3, "requires": true, "packages": { "": { "devDependencies": { "prettier": "^3.3.3" } }, "node_modules/prettier": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, "engines": { "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" } } } } ansible-ansible-lint-c16f018/package.json000066400000000000000000000000701477347356000203430ustar00rootroot00000000000000{ "devDependencies": { "prettier": "^3.3.3" } } ansible-ansible-lint-c16f018/playbook.yml000066400000000000000000000002431477347356000204220ustar00rootroot00000000000000--- - name: Example hosts: localhost gather_facts: false tasks: - name: include extra tasks ansible.builtin.include_tasks: file: /dev/null ansible-ansible-lint-c16f018/plugins/000077500000000000000000000000001477347356000175415ustar00rootroot00000000000000ansible-ansible-lint-c16f018/plugins/modules/000077500000000000000000000000001477347356000212115ustar00rootroot00000000000000ansible-ansible-lint-c16f018/plugins/modules/fake_module.py000066400000000000000000000007771477347356000240510ustar00rootroot00000000000000"""Sample custom ansible module named fake_module. This is used to test ability to detect and use custom modules. """ from ansible.module_utils.basic import AnsibleModule EXAMPLES = r""" - name: "playbook" tasks: - name: Hello debug: msg: 'world' """ def main() -> None: """Return the module instance.""" AnsibleModule( argument_spec={ "data": {"default": None}, "path": {"default": None}, "file": {"default": None}, }, ) ansible-ansible-lint-c16f018/pyproject.toml000066400000000000000000000523101477347356000207750ustar00rootroot00000000000000# cspell: ignore FURB [build-system] build-backend = "setuptools.build_meta" requires = [ "setuptools >= 65.3.0", # required by pyproject+setuptools_scm integration and editable installs "setuptools_scm[toml] >= 7.0.5" # required for "no-local-version" scheme ] [project] authors = [{"email" = "will@thames.id.au", "name" = "Will Thames"}] classifiers = [ "Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "License :: OSI Approved :: MIT License", "Operating System :: MacOS", "Operating System :: POSIX", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python", "Topic :: System :: Systems Administration", "Topic :: Software Development :: Quality Assurance", "Topic :: Software Development :: Testing", "Topic :: Utilities" ] description = "Checks playbooks for practices and behavior that could potentially be improved" dynamic = ["version", "dependencies", "optional-dependencies"] keywords = ["ansible", "lint"] license = {text = "GPLv3+"} maintainers = [{"email" = "info@ansible.com", "name" = "Ansible by Red Hat"}] name = "ansible-lint" readme = "README.md" # https://peps.python.org/pep-0621/#readme requires-python = ">=3.10" [project.scripts] ansible-lint = "ansiblelint.__main__:_run_cli_entrypoint" [project.urls] changelog = "https://github.com/ansible/ansible-lint/releases" documentation = "https://ansible.readthedocs.io/projects/lint/" homepage = "https://github.com/ansible/ansible-lint" repository = "https://github.com/ansible/ansible-lint" [tool.codespell] # indention is a typo in ruamel.yaml's API ignore-words-list = "indention" skip = ".tox,.mypy_cache,build,.git,.eggs,pip-wheel-metadata" # Keep this default because xml/report do not know to use load it from config file: # data_file = ".coverage" [tool.coverage.paths] source = ["src", ".tox/*/site-packages"] [tool.coverage.report] exclude_also = ["pragma: no cover", "if TYPE_CHECKING:"] # Increase it just so it would pass on any single-python run fail_under = 95 # During development we might remove code (files) with coverage data, and we dont want to fail: ignore_errors = true omit = ["test/*"] partial_branches = ["pragma: no cover", "if TYPE_CHECKING:"] show_missing = true skip_covered = true skip_empty = true [tool.coverage.run] concurrency = ["multiprocessing", "thread"] # Do not use branch until bug is fixes: # https://github.com/nedbat/coveragepy/issues/605 # branch = true parallel = true source = ["src"] [tool.mypy] check_untyped_defs = true color_output = true disallow_any_generics = true disallow_any_unimported = true disallow_untyped_calls = true disallow_untyped_defs = true error_summary = true # site-packages is here to help vscode mypy integration getting confused exclude = "(.cache|.config|.eggs|.tox|_readthedocs|build|dist|test/local-content|site|site-packages|~/.pyenv|examples|plugins/modules).*" # https://github.com/python/mypy/issues/12664 follow_untyped_imports = true incremental = false no_implicit_optional = true python_version = "3.10" show_error_code_links = true show_error_codes = true strict = true warn_redundant_casts = true warn_return_any = true warn_unused_configs = true [[tool.mypy.overrides]] ignore_errors = true ignore_missing_imports = true module = [ "ansiblelint._version", # generated "license_expression", "ruamel.yaml" ] [[tool.mypy.overrides]] implicit_reexport = true module = [ "ansible.*", "yamllint.*" ] [tool.pylint.IMPORTS] [tool.pylint.MASTER] bad-names = [ # spell-checker:ignore linenumber "linenumber", # use lineno instead "line_number" # use lineno instead ] # pylint defaults + f,fh,v,id good-names = ["i", "j", "k", "Run", "_", "f", "fh", "v", "id", "T"] # Ignore as being generated: ignore-paths = "^(examples|build|test/schemas/node_modules|.eggs|.cache|.direnv|.tox|src/ansiblelint/_version|.config/).*$" [tool.pylint.REPORTING] output-format = "colorized" [tool.pylint.SUMMARY] # We don't need the score spamming console, as we either pass or fail score = "n" [tool.pylint.messages_control] disable = [ "unknown-option-value", # https://gist.github.com/cidrblock/ec3412bacfeb34dbc2d334c1d53bef83 "C0103", # invalid-name / ruff N815 "C0105", # typevar-name-incorrect-variance / ruff PLC0105 "C0112", # empty-docstring / ruff D419 "C0113", # unneeded-not / ruff SIM208 "C0114", # missing-module-docstring / ruff D100 "C0115", # missing-class-docstring / ruff D101 "C0116", # missing-function-docstring / ruff D103 "C0121", # singleton-comparison / ruff PLC0121 "C0123", # unidiomatic-typecheck / ruff E721 "C0131", # typevar-double-variance / ruff PLC0131 "C0132", # typevar-name-mismatch / ruff PLC0132 "C0198", # bad-docstring-quotes / ruff Q002 "C0199", # docstring-first-line-empty / ruff D210 "C0201", # consider-iterating-dictionary / ruff SIM118 "C0202", # bad-classmethod-argument / ruff PLC0202 "C0205", # single-string-used-for-slots / ruff PLC0205 "C0208", # use-sequence-for-iteration / ruff PLC0208 "C0301", # line-too-long / ruff E501 "C0303", # trailing-whitespace / ruff W291 "C0304", # missing-final-newline / ruff W292 "C0321", # multiple-statements / ruff PLC0321 "C0410", # multiple-imports / ruff E401 "C0411", # wrong-import-order / ruff I001 "C0412", # ungrouped-imports / ruff I001 "C0413", # wrong-import-position / ruff E402 "C0414", # useless-import-alias / ruff PLC0414 "C0415", # import-outside-toplevel / ruff PLC0415 "C0501", # consider-using-any-or-all / ruff PLC0501 "C1901", # compare-to-empty-string / ruff PLC1901 "C2201", # misplaced-comparison-constant / ruff SIM300 "C2401", # non-ascii-name / ruff PLC2401 "C2403", # non-ascii-module-import / ruff PLC2403 "C2701", # import-private-name / ruff PLC2701 "C2801", # unnecessary-dunder-call / ruff PLC2801 "C3001", # unnecessary-lambda-assignment / ruff E731 "C3002", # unnecessary-direct-lambda-call / ruff PLC3002 "E0001", # syntax-error / ruff E999 "E0100", # init-is-generator / ruff PLE0100 "E0101", # return-in-init / ruff PLE0101 "E0102", # function-redefined / ruff F811 "E0103", # not-in-loop / ruff PLE0103 "E0104", # return-outside-function / ruff F706 "E0105", # yield-outside-function / ruff F704 "E0107", # nonexistent-operator / ruff B002 "E0112", # too-many-star-expressions / ruff F622 "E0115", # nonlocal-and-global / ruff PLE0115 "E0116", # continue-in-finally / ruff PLE0116 "E0117", # nonlocal-without-binding / ruff PLE0117 "E0118", # used-prior-global-declaration / ruff PLE0118 "E0211", # no-method-argument / ruff N805 "E0213", # no-self-argument / ruff N805 "E0237", # assigning-non-slot / ruff PLE0237 "E0241", # duplicate-bases / ruff PLE0241 "E0302", # unexpected-special-method-signature / ruff PLE0302 "E0303", # invalid-length-returned / ruff PLE0303 "E0304", # invalid-bool-returned / ruff PLE0304 "E0305", # invalid-index-returned / ruff PLE0305 "E0308", # invalid-bytes-returned / ruff PLE0308 "E0309", # invalid-hash-returned / ruff PLE0309 "E0402", # relative-beyond-top-level / ruff TID252 "E0602", # undefined-variable / ruff F821 "E0603", # undefined-all-variable / ruff F822 "E0604", # invalid-all-object / ruff PLE0604 "E0605", # invalid-all-format / ruff PLE0605 "E0643", # potential-index-error / ruff PLE0643 "E0704", # misplaced-bare-raise / ruff PLE0704 "E0711", # notimplemented-raised / ruff F901 "E1132", # repeated-keyword / ruff PLE1132 "E1142", # await-outside-async / ruff PLE1142 "E1205", # logging-too-many-args / ruff PLE1205 "E1206", # logging-too-few-args / ruff PLE1206 "E1300", # bad-format-character / ruff PLE1300 "E1301", # truncated-format-string / ruff F501 "E1302", # mixed-format-string / ruff F506 "E1303", # format-needs-mapping / ruff F502 "E1304", # missing-format-string-key / ruff F524 "E1305", # too-many-format-args / ruff F522 "E1306", # too-few-format-args / ruff F524 "E1307", # bad-string-format-type / ruff PLE1307 "E1310", # bad-str-strip-call / ruff PLE1310 "E1519", # singledispatch-method / ruff PLE1519 "E1520", # singledispatchmethod-function / ruff PLE5120 "E1700", # yield-inside-async-function / ruff PLE1700 "E2502", # bidirectional-unicode / ruff PLE2502 "E2510", # invalid-character-backspace / ruff PLE2510 "E2512", # invalid-character-sub / ruff PLE2512 "E2513", # invalid-character-esc / ruff PLE2513 "E2514", # invalid-character-nul / ruff PLE2514 "E2515", # invalid-character-zero-width-space / ruff PLE2515 "E4703", # modified-iterating-set / ruff PLE4703 "R0123", # literal-comparison / ruff F632 "R0124", # comparison-with-itself / ruff PLR0124 "R0133", # comparison-of-constants / ruff PLR0133 "R0202", # no-classmethod-decorator / ruff PLR0202 "R0203", # no-staticmethod-decorator / ruff PLR0203 "R0205", # useless-object-inheritance / ruff UP004 "R0206", # property-with-parameters / ruff PLR0206 "R0904", # too-many-public-methods / ruff PLR0904 "R0911", # too-many-return-statements / ruff PLR0911 "R0912", # too-many-branches / ruff PLR0912 "R0913", # too-many-arguments / ruff PLR0913 "R0914", # too-many-locals / ruff PLR0914 "R0915", # too-many-statements / ruff PLR0915 "R0916", # too-many-boolean-expressions / ruff PLR0916 "R0917", # too-many-positional-arguments / ruff PLR0917 "R1260", # too-complex / ruff C901 "R1701", # consider-merging-isinstance / ruff PLR1701 "R1702", # too-many-nested-blocks / ruff PLR1702 "R1703", # simplifiable-if-statement / ruff SIM108 "R1704", # redefined-argument-from-local / ruff PLR1704 "R1705", # no-else-return / ruff RET505 "R1706", # consider-using-ternary / ruff PLR1706 "R1707", # trailing-comma-tuple / ruff COM818 "R1710", # inconsistent-return-statements / ruff PLR1710 "R1711", # useless-return / ruff PLR1711 "R1714", # consider-using-in / ruff PLR1714 "R1715", # consider-using-get / ruff SIM401 "R1717", # consider-using-dict-comprehension / ruff C402 "R1718", # consider-using-set-comprehension / ruff C401 "R1719", # simplifiable-if-expression / ruff PLR1719 "R1720", # no-else-raise / ruff RET506 "R1721", # unnecessary-comprehension / ruff C416 "R1722", # consider-using-sys-exit / ruff PLR1722 "R1723", # no-else-break / ruff RET508 "R1724", # no-else-continue / ruff RET507 "R1725", # super-with-arguments / ruff UP008 "R1728", # consider-using-generator / ruff C417 "R1729", # use-a-generator / ruff C419 "R1730", # consider-using-min-builtin / ruff PLR1730 "R1731", # consider-using-max-builtin / ruff PLR1730 "R1732", # consider-using-with / ruff SIM115 "R1733", # unnecessary-dict-index-lookup / ruff PLR1733 "R1734", # use-list-literal / ruff C405 "R1735", # use-dict-literal / ruff C406 "R1736", # unnecessary-list-index-lookup / ruff PLR1736 "R2004", # magic-value-comparison / ruff PLR2004 "R2044", # empty-comment / ruff PLR2044 "R5501", # else-if-used / ruff PLR5501 "R6002", # consider-using-alias / ruff UP006 "R6003", # consider-alternative-union-syntax / ruff UP007 "R6104", # consider-using-augmented-assign / ruff PLR6104 "R6201", # use-set-for-membership / ruff PLR6201 "R6301", # no-self-use / ruff PLR6301 "W0102", # dangerous-default-value / ruff B006 "W0104", # pointless-statement / ruff B018 "W0106", # expression-not-assigned / ruff B018 "W0107", # unnecessary-pass / ruff PIE790 "W0108", # unnecessary-lambda / ruff PLW0108 "W0109", # duplicate-key / ruff F601 "W0120", # useless-else-on-loop / ruff PLW0120 "W0122", # exec-used / ruff S102 "W0123", # eval-used / ruff PGH001 "W0127", # self-assigning-variable / ruff PLW0127 "W0129", # assert-on-string-literal / ruff PLW0129 "W0130", # duplicate-value / ruff B033 "W0131", # named-expr-without-context / ruff PLW0131 "W0133", # pointless-exception-statement / ruff PLW0133 "W0150", # lost-exception / ruff B012 "W0160", # consider-ternary-expression / ruff SIM108 "W0177", # nan-comparison / ruff PLW0117 "W0199", # assert-on-tuple / ruff F631 "W0211", # bad-staticmethod-argument / ruff PLW0211 "W0212", # protected-access / ruff SLF001 "W0245", # super-without-brackets / ruff PLW0245 "W0301", # unnecessary-semicolon / ruff E703 "W0401", # wildcard-import / ruff F403 "W0404", # reimported / ruff F811 "W0406", # import-self / ruff PLW0406 "W0410", # misplaced-future / ruff F404 "W0511", # fixme / ruff PLW0511 "W0602", # global-variable-not-assigned / ruff PLW0602 "W0603", # global-statement / ruff PLW0603 "W0604", # global-at-module-level / ruff PLW0604 "W0611", # unused-import / ruff F401 "W0612", # unused-variable / ruff F841 "W0613", # unused-argument / ruff ARG001 "W0622", # redefined-builtin / ruff A001 "W0640", # cell-var-from-loop / ruff B023 "W0702", # bare-except / ruff E722 "W0705", # duplicate-except / ruff B014 "W0706", # try-except-raise / ruff TRY302 "W0707", # raise-missing-from / ruff TRY200 "W0711", # binary-op-exception / ruff PLW0711 "W0718", # broad-exception-caught / ruff PLW0718 "W0719", # broad-exception-raised / ruff TRY002 "W1113", # keyword-arg-before-vararg / ruff B026 "W1201", # logging-not-lazy / ruff G "W1202", # logging-format-interpolation / ruff G "W1203", # logging-fstring-interpolation / ruff G "W1300", # bad-format-string-key / ruff PLW1300 "W1301", # unused-format-string-key / ruff F504 "W1302", # bad-format-string / ruff PLW1302 "W1303", # missing-format-argument-key / ruff F524 "W1304", # unused-format-string-argument / ruff F507 "W1305", # format-combined-specification / ruff F525 "W1308", # duplicate-string-formatting-argument / ruff PLW1308 "W1309", # f-string-without-interpolation / ruff F541 "W1310", # format-string-without-interpolation / ruff F541 "W1401", # anomalous-backslash-in-string / ruff W605 "W1404", # implicit-str-concat / ruff ISC001 "W1405", # inconsistent-quotes / ruff Q000 "W1406", # redundant-u-string-prefix / ruff UP025 "W1501", # bad-open-mode / ruff PLW1501 "W1508", # invalid-envvar-default / ruff PLW1508 "W1509", # subprocess-popen-preexec-fn / ruff PLW1509 "W1510", # subprocess-run-check / ruff PLW1510 "W1514", # unspecified-encoding / ruff PLW1514 "W1515", # forgotten-debug-statement / ruff T100 "W1518", # method-cache-max-size-none / ruff B019 "W1641", # eq-without-hash / ruff PLW1641 "W2101", # useless-with-lock / ruff PLW2101 "W2402", # non-ascii-file-name / ruff N999 "W2901", # redefined-loop-name / ruff PLW2901 "W3201", # bad-dunder-name / ruff PLW3201 "W3301", # nested-min-max / ruff PLW3301 "duplicate-code", "fixme", "too-few-public-methods", "too-many-instance-attributes" ] # increase from default is 50 which is too aggressive max-statements = 60 [tool.pyright] exclude = [ ".ansible", ".cache", ".config", ".direnv", ".eggs", ".tox", ".venv", "ansible_collections", "build", "dist", "site", "venv", "examples/playbooks/collections" ] include = ["src"] mode = "standard" # https://github.com/microsoft/pyright/blob/main/docs/configuration.md#sample-pyprojecttoml-file # pythonVersion = "3.10" # reportMissingImports = false # https://github.com/microsoft/pyright/issues/9494 reportPossiblyUnboundVariable = false # Introduced in v1.1.398 but already covered by ruff reportPrivateImportUsage = false # spell-checker:ignore filterwarnings norecursedirs optionflags [tool.pytest.ini_options] # do not add options here as this will likely break either console runs or IDE # integration like vscode or pycharm addopts = "-p no:pytest_cov --durations=10 --failed-first" doctest_optionflags = ["ALLOW_UNICODE", "ELLIPSIS"] filterwarnings = [ "error", # https://sourceforge.net/p/ruamel-yaml/tickets/452/ "ignore:Deprecated call to `pkg_resources.declare_namespace:DeprecationWarning", # https://github.com/spdx/tools-python/issues/507 "ignore:pkg_resources is deprecated as an API:DeprecationWarning", # We raise one non critical warning from our own conftest.py: "always::pytest.PytestWarning", # py312 ansible-core # https://github.com/ansible/ansible/issues/81906 "ignore:'importlib.abc.TraversableResources' is deprecated and slated for removal in Python 3.14:DeprecationWarning", # https://github.com/ansible/ansible/pull/80968 "ignore:Attribute s is deprecated and will be removed in Python 3.14; use value instead:DeprecationWarning" ] junit_duration_report = "call" junit_family = "xunit1" # Our github annotation parser from .github/workflows/tox.yml requires xunit1 format. Ref: # https://github.com/shyim/junit-report-annotations-action/issues/3#issuecomment-663241378 junit_suite_name = "ansible_lint_test_suite" minversion = "4.6.6" # https://code.visualstudio.com/docs/python/testing # coverage is re-enabled in `tox.ini`. That approach is safer than # `--no-cov` which prevents activation from tox.ini and which also fails # when plugin is effectively missing. norecursedirs = [ "*.egg", ".cache", ".config", ".eggs", ".git", ".github", ".mypy_cache", ".projects", ".eggs", ".tox", "__pycache__", "ansible_collections", "build", "collections", "dist", "docs", "examples", "plugins", "site", "src/ansible_lint.egg-info", "test/schemas" ] python_files = [ "test_*.py", # Ref: https://docs.pytest.org/en/latest/reference.html#confval-python_files # Needed to discover legacy nose test modules: "Test*.py", # Needed to discover embedded Rule tests "rules/*.py" ] # Using --pyargs instead of testpath as we embed some tests # See: https://github.com/pytest-dev/pytest/issues/6451#issuecomment-687043537 # testpaths = xfail_strict = true [tool.ruff] cache-dir = "./.cache/.ruff" exclude = [".config"] fix = true # Same as Black. line-length = 88 preview = true target-version = "py310" [tool.ruff.lint] ignore = [ "COM812", # conflicts with ISC001 on format "CPY001", # missing-copyright-notice "D203", # incompatible with D211 "D213", # incompatible with D212 "E501", # we use black "ERA001", # auto-removal of commented out code affects development and vscode integration "INP001", # "is part of an implicit namespace package", all false positives "ISC001", # conflicts with COM812 on format "PLW2901", # PLW2901: Redefined loop variable "RET504", # Unnecessary variable assignment before `return` statement # temporary disabled until we fix them: "ANN", "ARG002", # Unused method argument (currently in too many places) "D102", # Missing docstring in public method (currently in too many places) "FBT001", "FBT003", "FURB189", # Subclassing `dict` can be error prone, use `collections.UserDict` instead "PD011", # We are not using pandas, any .values attributes are unrelated "PERF203", "PLR", "PLW0603", # global lock file in cache dir "RUF012", # Mutable class attributes should be annotated with `typing.ClassVar` "RUF045", # Assignment without annotation found in dataclass body # part of preview rules: "B909", # raise-missing-from "DOC201", # docstring-missing-returns "DOC402", # docstring-missing-summary "DOC501", # docstring-missing-exception "FURB101", "FURB103", "FURB110", "FURB113", "FURB118", "PLC0415", "PLC2701", "PLW1641", "S404" ] select = ["ALL"] [tool.ruff.lint.flake8-builtins] builtins-ignorelist = ["id"] [tool.ruff.lint.flake8-pytest-style] parametrize-values-type = "tuple" [tool.ruff.lint.isort] known-first-party = ["src"] [tool.ruff.lint.mccabe] # Implicit 10 is too low for our codebase, even black uses 18 as default. max-complexity = 20 [tool.ruff.lint.per-file-ignores] "src/ansiblelint/rules/*.py" = ["S"] "src/ansiblelint/testing/*.py" = ["S"] # Temporary disabled until we fix them: "src/ansiblelint/{utils,file_utils,runner,loaders,constants,config,cli,_mockings}.py" = [ "PTH" ] "test/**/*.py" = ["DOC201", "DOC501", "PLC2701", "S"] [tool.ruff.lint.pydocstyle] convention = "google" [tool.setuptools.dynamic] dependencies = {file = [".config/requirements.in"]} optional-dependencies.docs = {file = [".config/requirements-docs.in"]} optional-dependencies.test = {file = [".config/requirements-test.in"]} [tool.setuptools_scm] # To prevent accidental pick of mobile version tags such 'v6' git_describe_command = [ "git", "describe", "--dirty", "--long", "--tags", "--match", "v*.*" ] local_scheme = "no-local-version" tag_regex = "^(?Pv)?(?P\\d+[^\\+]*)(?P.*)?$" write_to = "src/ansiblelint/_version.py" [tool.tomlsort] in_place = true sort_inline_tables = true sort_table_keys = true [tool.uv.pip] annotation-style = "line" custom-compile-command = "tox run -e deps" no-emit-package = [ "ansible-core", "exceptiongroup", # =4.5.1" - community.general - community.molecule - community.windows ansible-ansible-lint-c16f018/src/000077500000000000000000000000001477347356000166475ustar00rootroot00000000000000ansible-ansible-lint-c16f018/src/ansiblelint/000077500000000000000000000000001477347356000211535ustar00rootroot00000000000000ansible-ansible-lint-c16f018/src/ansiblelint/__init__.py000066400000000000000000000023511477347356000232650ustar00rootroot00000000000000# Copyright (c) 2013-2014 Will Thames # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. """Main ansible-lint package.""" from __future__ import annotations from ansiblelint.version import __version__ __all__ = ("__version__",) ansible-ansible-lint-c16f018/src/ansiblelint/__main__.py000077500000000000000000000420361477347356000232550ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (c) 2013-2014 Will Thames # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. """Command line implementation.""" from __future__ import annotations import errno import logging import os import pathlib import shutil import site import sys import warnings from pathlib import Path from typing import TYPE_CHECKING from ansible_compat.prerun import get_cache_dir from filelock import BaseFileLock, FileLock, Timeout from ansiblelint.constants import RC, SKIP_SCHEMA_UPDATE # safety check for broken ansible core, needs to happen first try: # pylint: disable=unused-import from ansible.parsing.dataloader import DataLoader # noqa: F401 except Exception as _exc: # pylint: disable=broad-exception-caught # noqa: BLE001 logging.fatal(_exc) sys.exit(RC.INVALID_CONFIG) # pylint: disable=ungrouped-imports from ansiblelint import cli from ansiblelint._mockings import _perform_mockings_cleanup from ansiblelint.app import get_app from ansiblelint.config import ( Options, get_deps_versions, get_version_warning, log_entries, options, ) from ansiblelint.loaders import load_ignore_txt from ansiblelint.output import ( console, console_stderr, reconfigure, render_yaml, should_do_markup, ) from ansiblelint.runner import get_matches from ansiblelint.skip_utils import normalize_tag from ansiblelint.version import __version__ if TYPE_CHECKING: # RulesCollection must be imported lazily or ansible gets imported too early. from ansiblelint.rules import RulesCollection from ansiblelint.runner import LintResult _logger = logging.getLogger(__name__) class LintLogHandler(logging.Handler): """Custom handler that uses our rich stderr console.""" def emit(self, record: logging.LogRecord) -> None: try: msg = self.format(record) console_stderr.print(f"[dim]{msg}[/]") except RecursionError: # See issue 36272 raise except Exception: # pylint: disable=broad-exception-caught # noqa: BLE001 self.handleError(record) def initialize_logger(level: int = 0) -> None: """Set up the global logging level based on the verbosity number.""" # We are about to act on the root logger, which defaults to logging.WARNING. # That is where our 0 (default) value comes from. verbosity_map = { -2: logging.CRITICAL, -1: logging.ERROR, 0: logging.WARNING, 1: logging.INFO, 2: logging.DEBUG, } handler = LintLogHandler() formatter = logging.Formatter("%(levelname)-8s %(message)s") handler.setFormatter(formatter) logger = logging.getLogger() logger.addHandler(handler) # Unknown logging level is treated as DEBUG logging_level = verbosity_map.get(level, logging.DEBUG) logger.setLevel(logging_level) logging.captureWarnings(True) # pass all warnings.warn() messages through logging # Use module-level _logger instance to validate it _logger.debug("Logging initialized to level %s", logging_level) def initialize_options(arguments: list[str] | None = None) -> BaseFileLock | None: """Load config options and store them inside options module.""" cache_dir_lock = None new_options = cli.get_config(arguments or []) new_options.cwd = pathlib.Path.cwd() if new_options.colored is None: new_options.colored = should_do_markup() # persist loaded configuration inside options module for k, v in new_options.__dict__.items(): setattr(options, k, v) # rename deprecated ids/tags to newer names options.tags = [normalize_tag(tag) for tag in options.tags] options.skip_list = [normalize_tag(tag) for tag in options.skip_list] options.warn_list = [normalize_tag(tag) for tag in options.warn_list] options.configured = True options.cache_dir = get_cache_dir(pathlib.Path(options.project_dir)) # add a lock file so we do not have two instances running inside at the same time if options.cache_dir: options.cache_dir.mkdir(parents=True, exist_ok=True) if not options.offline: # pragma: no cover cache_dir_lock = FileLock( f"{options.cache_dir}/.lock", ) try: cache_dir_lock.acquire(timeout=180) except Timeout: # pragma: no cover _logger.error( # noqa: TRY400 "Timeout waiting for another instance of ansible-lint to release the lock.", ) sys.exit(RC.LOCK_TIMEOUT) # Avoid extra output noise from Ansible about using devel versions if "ANSIBLE_DEVEL_WARNING" not in os.environ: # pragma: no branch os.environ["ANSIBLE_DEVEL_WARNING"] = "false" return cache_dir_lock def _do_list(rules: RulesCollection) -> int: # On purpose lazy-imports to avoid pre-loading Ansible # pylint: disable=import-outside-toplevel from ansiblelint.generate_docs import rules_as_str if options.list_rules: console.print( rules_as_str(rules), ) return 0 if options.list_tags: console.print(render_yaml(rules.list_tags())) return 0 # we should not get here! return 1 # noinspection PyShadowingNames def _do_transform(result: LintResult, opts: Options) -> None: """Create and run Transformer.""" if "yaml" in opts.skip_list: # The transformer rewrites yaml files, but the user requested to skip # the yaml rule or anything tagged with "yaml", so there is nothing to do. return # On purpose lazy-imports to avoid loading transforms unless requested # pylint: disable=import-outside-toplevel from ansiblelint.transformer import Transformer transformer = Transformer(result, options) # this will mark any matches as fixed if the transforms repaired the issue transformer.run() def support_banner() -> None: """Display support banner when running on unsupported platform.""" def fix(runtime_options: Options, result: LintResult, rules: RulesCollection) -> None: """Fix the linting errors. :param options: Options object :param result: LintResult object """ match_count = len(result.matches) _logger.debug("Begin fixing: %s matches", match_count) ruamel_safe_version = "0.17.26" # pylint: disable=import-outside-toplevel from packaging.version import Version from ruamel.yaml import __version__ as ruamel_yaml_version_str # pylint: enable=import-outside-toplevel if Version(ruamel_safe_version) > Version( ruamel_yaml_version_str ): # pragma: no cover _logger.warning( "We detected use of `--fix` feature with a buggy ruamel-yaml %s library instead of >=%s, upgrade it before reporting any bugs like dropped comments.", ruamel_yaml_version_str, ruamel_safe_version, ) acceptable_tags = {"all", "none", *rules.known_tags()} unknown_tags = set(options.write_list).difference(acceptable_tags) if unknown_tags: # pragma: no cover _logger.error( "Found invalid value(s) (%s) for --fix arguments, must be one of: %s", ", ".join(unknown_tags), ", ".join(acceptable_tags), ) sys.exit(RC.INVALID_CONFIG) _do_transform(result, options) rerun = ["yaml"] resolved = [] for idx, match in reversed(list(enumerate(result.matches))): _logger.debug("Fixing: (%s of %s) %s", match_count - idx, match_count, match) if match.fixed: _logger.debug("Fixed, removed: %s", match) result.matches.pop(idx) continue if match.rule.id not in rerun: _logger.debug("Not rerun eligible: %s", match) continue uid = (match.rule.id, match.filename) if uid in resolved: _logger.debug("Previously resolved: %s", match) result.matches.pop(idx) continue _logger.debug("Rerunning: %s", match) runtime_options.tags = [match.rule.id] runtime_options.lintables = [match.filename] runtime_options._skip_ansible_syntax_check = True # noqa: SLF001 new_results = get_matches(rules, runtime_options) if not new_results.matches: _logger.debug("Newly resolved: %s", match) result.matches.pop(idx) resolved.append(uid) continue if match in new_results.matches: _logger.debug("Still found: %s", match) continue _logger.debug("Fixed, removed: %s", match) result.matches.pop(idx) # pylint: disable=too-many-locals,too-many-statements def main(argv: list[str] | None = None) -> int: """Linter CLI entry point.""" must_exit = False # alter PATH if needed (venv support) path_inject(argv[0] if argv and argv[0] else "") if argv is None: # pragma: no cover argv = sys.argv warnings.simplefilter( "ignore", ResourceWarning ) # suppress "enable tracemalloc to get the object allocation traceback" with warnings.catch_warnings(record=True) as warns: # do not use "ignore" as we will miss to collect them warnings.simplefilter(action="default") cache_dir_lock = initialize_options(argv[1:]) reconfigure(colored=options.colored) if options.version: deps = get_deps_versions() msg = f"ansible-lint [repr.number]{__version__}[/] using[dim]" for k, v in deps.items(): msg += f" {k}:[repr.number]{v}[/]" msg += "[/]" console.print(msg) msg = get_version_warning() if msg: # pragma: no cover console.print(msg) support_banner() must_exit = True else: support_banner() initialize_logger(options.verbosity) for level, message in log_entries: _logger.log(level, message) _logger.debug("Options: %s", options) _logger.debug("CWD: %s", Path.cwd()) for warn in warns: # pragma: no cover _logger.warning(str(warn.message)) warnings.resetwarnings() if must_exit: sys.exit(0) # checks if we have `ANSIBLE_LINT_SKIP_SCHEMA_UPDATE` set to bypass schema # update. Also skip if in offline mode. # env var set to skip schema refresh skip_schema_update = ( bool( int( os.environ.get( SKIP_SCHEMA_UPDATE, "0", ), ), ) or options.offline or options.nodeps ) if not skip_schema_update: # pragma: no cover # pylint: disable=import-outside-toplevel from ansiblelint.schemas.__main__ import refresh_schemas refresh_schemas() # pylint: disable=import-outside-toplevel from ansiblelint.rules import RulesCollection if options.list_profiles: from ansiblelint.generate_docs import profiles_as_md profiles_as_md().display() return 0 app = get_app( offline=None, cached=True, ) # to be sure we use the offline value from settings rules = RulesCollection( options.rulesdirs, profile_name=options.profile, app=app, options=options, ) if options.list_rules or options.list_tags: return _do_list(rules) if isinstance(options.tags, str): options.tags = options.tags.split(",") # pragma: no cover result = get_matches(rules, options) mark_as_success = True if options.strict and result.matches: mark_as_success = False # Remove skip_list items from the result result.matches = [m for m in result.matches if m.tag not in app.options.skip_list] # Mark matches as ignored inside ignore file ignore_map = load_ignore_txt(options.ignore_file) for match in result.matches: if match.tag in ignore_map[match.filename]: # pragma: no cover match.ignored = True _logger.debug("Ignored: %s", match) if app.yamllint_config.incompatible: # pragma: no cover _logger.log( level=logging.ERROR if options.write_list else logging.WARNING, msg=app.yamllint_config.incompatible, ) if options.write_list: if app.yamllint_config.incompatible: # pragma: no cover sys.exit(RC.INVALID_CONFIG) fix(runtime_options=options, result=result, rules=rules) app.render_matches(result.matches) _perform_mockings_cleanup(app.options) if cache_dir_lock: cache_dir_lock.release() pathlib.Path(cache_dir_lock.lock_file).unlink(missing_ok=True) if options.mock_filters: _logger.warning( "The following filters were mocked during the run: %s", ",".join(options.mock_filters), ) return app.report_outcome(result, mark_as_success=mark_as_success) def _run_cli_entrypoint() -> None: """Invoke the main entrypoint with current CLI args. This function also processes the runtime exceptions. """ try: sys.exit(main(sys.argv)) except OSError as exc: # NOTE: Only "broken pipe" is acceptable to ignore if exc.errno != errno.EPIPE: # pragma: no cover raise except KeyboardInterrupt: # pragma: no cover sys.exit(RC.EXIT_CONTROL_C) except RuntimeError as exc: # pragma: no cover raise SystemExit(exc) from exc def path_inject(own_location: str = "") -> None: """Add python interpreter path to top of PATH to fix outside venv calling.""" # This make it possible to call ansible-lint that was installed inside a # virtualenv without having to pre-activate it. Otherwise subprocess will # either fail to find ansible executables or call the wrong ones. # # This must be run before we do run any subprocesses, and loading config # does this as part of the ansible detection. paths = [x for x in os.environ.get("PATH", "").split(os.pathsep) if x] # Expand ~ in PATH as it known to break many tools expanded = False for idx, path in enumerate(paths): if path.startswith("~"): # pragma: no cover paths[idx] = str(Path(path).expanduser()) expanded = True if expanded: # pragma: no cover print( # noqa: T201 "WARNING: PATH altered to expand ~ in it. Read https://stackoverflow.com/a/44704799/99834 and correct your system configuration.", file=sys.stderr, ) inject_paths = [] userbase_bin_path = Path(site.getuserbase()) / "bin" if ( str(userbase_bin_path) not in paths and (userbase_bin_path / "bin" / "ansible").exists() ): inject_paths.append(userbase_bin_path.resolve().as_posix()) py_path = Path(sys.executable).parent.resolve() pipx_path = os.environ.get("PIPX_HOME", "pipx") if ( str(py_path) not in paths and (py_path / "ansible").exists() and pipx_path not in str(py_path) ): inject_paths.append(py_path.as_posix()) # last option, if nothing else is found, just look next to ourselves... if own_location: own_location = os.path.realpath(own_location) parent = Path(own_location).parent if (parent / "ansible").exists() and str(parent) not in paths: inject_paths.append(str(parent)) if not os.environ.get("PYENV_VIRTUAL_ENV", None): if inject_paths and not all("pipx" in p for p in inject_paths): print( # noqa: T201 f"WARNING: PATH altered to include {', '.join(inject_paths)} :: This is usually a sign of broken local setup, which can cause unexpected behaviors.", file=sys.stderr, ) if inject_paths or expanded: os.environ["PATH"] = os.pathsep.join([*inject_paths, *paths]) # We do know that finding ansible in PATH does not guarantee that it is # functioning or that is in fact the same version that was installed as # our dependency, but addressing this would be done by ansible-compat. for cmd in ("ansible",): if not shutil.which(cmd): # pragma: no cover msg = f"Failed to find runtime dependency '{cmd}' in PATH" raise RuntimeError(msg) if __name__ == "__main__": _run_cli_entrypoint() ansible-ansible-lint-c16f018/src/ansiblelint/_internal/000077500000000000000000000000001477347356000231265ustar00rootroot00000000000000ansible-ansible-lint-c16f018/src/ansiblelint/_internal/__init__.py000066400000000000000000000000001477347356000252250ustar00rootroot00000000000000ansible-ansible-lint-c16f018/src/ansiblelint/_internal/internal_error.md000066400000000000000000000025001477347356000264720ustar00rootroot00000000000000# internal-error This error can also be caused by internal bugs but also by custom rules. Instead of just stopping tool execution, we generate the errors and continue processing other files. This allows users to add this rule to their `warn_list` until the root cause is fixed. Keep in mind that once an `internal-error` is found on a specific file, no other rules will be executed on that same file. In almost all cases you will see more detailed information regarding the original error or runtime exception that triggered this rule. If these files are broken on purpose, like some test fixtures, you need to add them to the `exclude_paths`. ## Problematic code ```yaml --- - name: Some title {{ # <-- Ansible will not load this invalid jinja template hosts: localhost tasks: [] ``` ## Correct code ```yaml --- - name: Some title hosts: localhost tasks: [] ``` ## ERROR! No hosts matched the subscripted pattern If you see this error, it means that you tried to index a host group variable that is using an index above its size. Instead of doing something like `hosts: all[1]` which assumes that you have at least two hosts in your current inventory, you better write something like `hosts: "{{ all[1] | default([]) }}`, which is safe and do not produce runtime errors. Use safe fallbacks to make your code more resilient. ansible-ansible-lint-c16f018/src/ansiblelint/_internal/load-failure.md000066400000000000000000000011631477347356000260150ustar00rootroot00000000000000# load-failure "Linter failed to process a file, possible invalid file. Possible reasons: - contains unsupported encoding (only UTF-8 is supported) - not an Ansible file - it contains some unsupported custom YAML objects (`!!` prefix) - it was not able to decrypt an inline `!vault` block. This violation **is not** skippable, so it cannot be added to the `warn_list` or the `skip_list`. If a vault decryption issue cannot be avoided, the offending file can be added to `exclude_paths` configuration. Possible errors codes: - `load-failure[not-found]` - Indicates that one argument file or folder was not found on disk. ansible-ansible-lint-c16f018/src/ansiblelint/_internal/parser-error.md000066400000000000000000000001471477347356000260750ustar00rootroot00000000000000# parser-error **AnsibleParserError.** Ansible parser fails; this usually indicates an invalid file. ansible-ansible-lint-c16f018/src/ansiblelint/_internal/rules.py000066400000000000000000000176701477347356000246450ustar00rootroot00000000000000"""Internally used rule classes.""" from __future__ import annotations import inspect import logging from pathlib import Path from typing import TYPE_CHECKING, Any from packaging.version import InvalidVersion, Version from ansiblelint.constants import RULE_DOC_URL if TYPE_CHECKING: from ansiblelint.config import Options from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.rules import RulesCollection from ansiblelint.utils import Task _logger = logging.getLogger(__name__) LOAD_FAILURE_MD = """\ # load-failure "Linter failed to process a file, possible invalid file. Possible reasons: * contains unsupported encoding (only UTF-8 is supported) * not an Ansible file * it contains some unsupported custom YAML objects (`!!` prefix) * it was not able to decrypt an inline `!vault` block. This violation **is not** skippable, so it cannot be added to the `warn_list` or the `skip_list`. If a vault decryption issue cannot be avoided, the offending file can be added to `exclude_paths` configuration. """ # Derived rules are likely to want to access class members, so: # pylint: disable=unused-argument class BaseRule: """Root class used by Rules.""" id: str = "" tags: list[str] = [] description: str = "" version_changed: str = "" severity: str = "" link: str = "" has_dynamic_tags: bool = False needs_raw_task: bool = False # Used to mark rules that we will never unload (internal ones) unloadable: bool = False # We use _order to sort rules and to ensure that some run before others, # _order 0 for internal rules # _order 1 for rules that check that data can be loaded # _order 5 implicit for normal rules _order: int = 5 _help: str | None = None # Added when a rule is registered into a collection, gives access to options _collection: RulesCollection | None = None # Allow rules to provide a custom short description instead of using __doc__ _shortdesc: str = "" def __init__(self) -> None: try: Version(self.version_changed) except InvalidVersion: msg = f"Rule {self.__class__.__name__} has an invalid version_changed field '{self.version_changed}', is should be a 'X.Y.Z' format value." _logger.warning(msg) @property def help(self) -> str: """Return a help markdown string for the rule.""" if self._help is None: self._help = "" md_file = ( Path(inspect.getfile(self.__class__)).parent / f"{self.id.replace('-', '_')}.md" ) if md_file.exists(): self._help = md_file.read_text(encoding="utf-8") return self._help @property def url(self) -> str: """Return rule documentation url.""" url = self.link if not url: # pragma: no cover url = RULE_DOC_URL if self.id: url += self.id + "/" return url @property def shortdesc(self) -> str: """Return the short description of the rule, basically the docstring.""" return self._shortdesc or self.__doc__ or "" def getmatches(self, file: Lintable) -> list[MatchError]: """Return all matches while ignoring exceptions.""" matches = [] if not file.path.is_dir(): for method in [self.matchlines, self.matchtasks, self.matchyaml]: try: matches.extend(method(file)) except Exception as exc: # pylint: disable=broad-except # noqa: BLE001 _logger.warning( "Ignored exception from %s.%s while processing %s: %s", self.__class__.__name__, method.__name__, str(file), exc, ) _logger.debug("Ignored exception details", exc_info=True) else: matches.extend(self.matchdir(file)) return matches def matchlines(self, file: Lintable) -> list[MatchError]: """Return matches found for a specific line.""" return [] def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str | MatchError | list[MatchError]: """Confirm if current rule is matching a specific task. If ``needs_raw_task`` (a class level attribute) is ``True``, then the original task (before normalization) will be made available under ``task["__raw_task__"]``. """ return False def matchtasks(self, file: Lintable) -> list[MatchError]: """Return matches for a tasks file.""" return [] def matchyaml(self, file: Lintable) -> list[MatchError]: """Return matches found for a specific YAML text.""" return [] def matchplay(self, file: Lintable, data: dict[str, Any]) -> list[MatchError]: """Return matches found for a specific playbook.""" return [] def matchdir(self, lintable: Lintable) -> list[MatchError]: """Return matches for lintable folders.""" return [] def match(self, line: str) -> bool | str: """Confirm if current rule matches the given string.""" return False def __lt__(self, other: BaseRule) -> bool: """Enable us to sort rules by their id.""" return (self._order, self.id) < (other._order, other.id) def __repr__(self) -> str: # pragma: no cover """Return a AnsibleLintRule instance representation.""" return self.id + ": " + self.shortdesc @classmethod def ids(cls) -> dict[str, str]: """Return a dictionary ids and their messages. This is used by the ``--list-tags`` option to ansible-lint. """ return getattr(cls, "_ids", {cls.id: cls.shortdesc}) @property def rule_config(self) -> dict[str, Any]: """Retrieve rule specific configuration.""" rule_config = {} if self.options: rule_config = self.options.rules.get(self.id, {}) if not isinstance(rule_config, dict): # pragma: no cover msg = f"Invalid rule config for {self.id}: {rule_config}" raise RuntimeError(msg) # noqa: TRY004 return rule_config @property def options(self) -> Options | None: """Used to access linter configuration.""" if self.unloadable: # internal rules are not configurable return None if self._collection is None: # pragma: no cover msg = f"A rule ({self.id}) that is not part of a collection cannot access its configuration." _logger.warning(msg) return None return self._collection.options # pylint: enable=unused-argument class RuntimeErrorRule(BaseRule): """Unexpected internal error.""" id = "internal-error" _shortdesc = "Unexpected internal error" severity = "VERY_HIGH" tags = ["core"] version_changed = "5.0.0" _order = 0 unloadable = True class AnsibleParserErrorRule(BaseRule): """AnsibleParserError.""" id = "parser-error" description = "Ansible parser fails; this usually indicates an invalid file." severity = "VERY_HIGH" tags = ["core"] version_changed = "5.0.0" _order = 0 unloadable = True class LoadingFailureRule(BaseRule): """Failed to load or parse file.""" id = "load-failure" description = "Linter failed to process a file, possible invalid file." severity = "VERY_HIGH" tags = ["core", "unskippable"] version_changed = "4.3.0" _help = LOAD_FAILURE_MD _order = 0 _ids = { "load-failure[not-found]": "File not found", } unloadable = True class WarningRule(BaseRule): """Other warnings detected during run.""" id = "warning" severity = "LOW" # should remain experimental as that would keep it warning only tags = ["core", "experimental"] version_changed = "6.8.0" _order = 0 unloadable = True ansible-ansible-lint-c16f018/src/ansiblelint/_internal/warning.md000066400000000000000000000007621477347356000251220ustar00rootroot00000000000000# warning `warning` is a special type of internal rule that is used to report generic runtime warnings found during execution. As stated by its name, they are not counted as errors, so they do not influence the final outcome. - `warning[raw-non-string]` indicates that you are using `[raw](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/raw_module.html#ansible-collections-ansible-builtin-raw-module)` module with non-string arguments, which is not supported by Ansible. ansible-ansible-lint-c16f018/src/ansiblelint/_mockings.py000066400000000000000000000076301477347356000235040ustar00rootroot00000000000000"""Utilities for mocking ansible modules and roles.""" from __future__ import annotations import contextlib import logging import re import sys from typing import TYPE_CHECKING from ansiblelint.constants import ANSIBLE_MOCKED_MODULE, RC if TYPE_CHECKING: from pathlib import Path from ansiblelint.config import Options _logger = logging.getLogger(__name__) def _make_module_stub(module_name: str, options: Options) -> None: if not options.cache_dir: # pragma: no cover msg = "Cache directory not set" raise RuntimeError(msg) # a.b.c is treated a collection if re.match(r"^(\w+|\w+\.\w+\.[\.\w]+)$", module_name): parts = module_name.split(".") if len(parts) < 3: path = options.cache_dir / "modules" module_file = f"{options.cache_dir}/modules/{module_name}.py" namespace = None collection = None else: namespace = parts[0] collection = parts[1] path = ( options.cache_dir / "collections" / "ansible_collections" / namespace / collection / "plugins" / "modules" / ("/".join(parts[2:-1])) ) module_file = f"{path}/{parts[-1]}.py" path.mkdir(exist_ok=True, parents=True) _write_module_stub( filename=module_file, name=module_name, namespace=namespace, collection=collection, ) else: _logger.error("Config error: %s is not a valid module name.", module_name) sys.exit(RC.INVALID_CONFIG) def _write_module_stub( filename: str, name: str, namespace: str | None = None, collection: str | None = None, ) -> None: """Write module stub to disk.""" body = ANSIBLE_MOCKED_MODULE.format( name=name, collection=collection, namespace=namespace, ) with open(filename, "w", encoding="utf-8") as f: f.write(body) def _perform_mockings(options: Options) -> None: """Mock modules and roles.""" path: Path if not options.cache_dir: # pragma: no cover msg = "Cache directory not set" raise RuntimeError(msg) for role_name in options.mock_roles: if re.match(r"\w+\.\w+\.\w+$", role_name): namespace, collection, role_dir = role_name.split(".") path = ( options.cache_dir / "collections" / "ansible_collections" / namespace / collection / "roles" / role_dir ) else: path = options.cache_dir / "roles" / role_name # Avoid error from makedirs if destination is a broken symlink if path.is_symlink() and not path.exists(): # pragma: no cover _logger.warning("Removed broken symlink from %s", path) path.unlink(missing_ok=True) path.mkdir(exist_ok=True, parents=True) if options.mock_modules: for module_name in options.mock_modules: _make_module_stub(module_name=module_name, options=options) def _perform_mockings_cleanup(options: Options) -> None: """Clean up mocked modules and roles.""" if not options.cache_dir: # pragma: no cover msg = "Cache directory not set" raise RuntimeError(msg) for role_name in options.mock_roles: if re.match(r"\w+\.\w+\.\w+$", role_name): namespace, collection, role_dir = role_name.split(".") path = ( options.cache_dir / "collections" / "ansible_collections" / namespace / collection / "roles" / role_dir ) else: path = options.cache_dir / "roles" / role_name with contextlib.suppress(OSError): path.rmdir() ansible-ansible-lint-c16f018/src/ansiblelint/app.py000066400000000000000000000402621477347356000223110ustar00rootroot00000000000000"""Application.""" from __future__ import annotations import copy import itertools import logging import os import sys from functools import lru_cache from pathlib import Path from typing import TYPE_CHECKING, Any from ansible_compat.runtime import Runtime from ansiblelint import formatters from ansiblelint._mockings import _perform_mockings from ansiblelint.config import PROFILES, Options, get_version_warning from ansiblelint.config import options as default_options from ansiblelint.constants import RC, RULE_DOC_URL from ansiblelint.loaders import IGNORE_FILE from ansiblelint.output import console, console_stderr, render_yaml from ansiblelint.requirements import Reqs from ansiblelint.stats import SummarizedResults, TagStats if TYPE_CHECKING: from ansiblelint._internal.rules import BaseRule from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.runner import LintResult _logger = logging.getLogger(__package__) _CACHED_APP: App | None = None class App: """App class represents an execution of the linter.""" def __init__(self, options: Options): """Construct app run based on already loaded configuration.""" options.skip_list = _sanitize_list_options(options.skip_list) options.warn_list = _sanitize_list_options(options.warn_list) self.options = options formatter_factory = choose_formatter_factory(options) self.formatter = formatter_factory(options.cwd, options.display_relative_path) # Without require_module, our _set_collections_basedir may fail self.runtime = Runtime( isolated=True, require_module=True, verbosity=options.verbosity, ) self.reqs = Reqs("ansible-lint") package = "ansible-core" if not self.reqs.matches( package, str(self.runtime.version), ): # pragma: no cover msg = f"ansible-lint requires {package}{','.join(str(x) for x in self.reqs[package])} and current version is {self.runtime.version}" _logger.error(msg) sys.exit(RC.INVALID_CONFIG) # pylint: disable=import-outside-toplevel from ansiblelint.yaml_utils import load_yamllint_config self.yamllint_config = load_yamllint_config() def render_matches(self, matches: list[MatchError]) -> None: """Display given matches (if they are not fixed).""" matches = [match for match in matches if not match.fixed] if isinstance( self.formatter, formatters.CodeclimateJSONFormatter | formatters.SarifFormatter, ): # If formatter CodeclimateJSONFormatter or SarifFormatter is chosen, # then print only the matches in JSON console.print( self.formatter.format_result(matches), ) return ignored_matches = [match for match in matches if match.ignored] fatal_matches = [match for match in matches if not match.ignored] # Displayed ignored matches first if ignored_matches: _logger.warning( "Listing %s violation(s) marked as ignored, likely already known", len(ignored_matches), ) for match in ignored_matches: if match.ignored: console.print(self.formatter.apply(match)) if fatal_matches: _logger.warning( "Listing %s violation(s) that are fatal", len(fatal_matches), ) for match in fatal_matches: if not match.ignored: console.print(self.formatter.apply(match)) # If run under GitHub Actions we also want to emit output recognized by it. if ( os.getenv("GITHUB_ACTIONS") == "true" and os.getenv("GITHUB_WORKFLOW") and os.getenv("GITHUB_ACTIONS_TEST", "false") == "false" ): _logger.info( "GitHub Actions environment detected, adding annotations output...", ) formatter = formatters.AnnotationsFormatter(self.options.cwd, True) for match in itertools.chain(fatal_matches, ignored_matches): console_stderr.print( formatter.apply(match), ) # If sarif_file is set, we also dump the results to a sarif file. if self.options.sarif_file: sarif = formatters.SarifFormatter(self.options.cwd, True) json = sarif.format_result(matches) # Somehow, this gets set as an AnsibleUnicode under unclear circumstances. Force it to be a Path sarif_file = Path(self.options.sarif_file) sarif_file.write_text( json, encoding="utf-8", ) def count_results(self, matches: list[MatchError]) -> SummarizedResults: """Count failures and warnings in matches.""" result = SummarizedResults() for match in matches: # any ignores match counts as a warning if match.ignored: result.warnings += 1 continue # tag can include a sub-rule id: `yaml[document-start]` # rule.id is the generic rule id: `yaml` # *rule.tags is the list of the rule's tags (categories): `style` if match.tag not in result.tag_stats: result.tag_stats[match.tag] = TagStats( tag=match.tag, count=1, associated_tags=match.rule.tags, ) else: result.tag_stats[match.tag].count += 1 if {match.tag, match.rule.id, *match.rule.tags}.isdisjoint( self.options.warn_list, ): # not in warn_list if match.fixed: result.fixed_failures += 1 else: result.failures += 1 else: result.tag_stats[match.tag].warning = True if match.fixed: result.fixed_warnings += 1 else: result.warnings += 1 return result @staticmethod def count_lintables(files: set[Lintable]) -> tuple[int, int]: """Count total and modified files.""" files_count = len(files) changed_files_count = len([file for file in files if file.updated]) return files_count, changed_files_count @staticmethod def _get_matched_skippable_rules( matches: list[MatchError], ) -> dict[str, BaseRule]: """Extract the list of matched rules, if skippable, from the list of matches.""" matches_unignored = [match for match in matches if not match.ignored] # match.tag is more specialized than match.rule.id matched_rules = { match.tag or match.rule.id: match.rule for match in matches_unignored } # remove unskippable rules from the list for rule_id in list(matched_rules.keys()): if "unskippable" in matched_rules[rule_id].tags: matched_rules.pop(rule_id) return matched_rules def report_outcome( self, result: LintResult, *, mark_as_success: bool = False, ) -> int: """Display information about how to skip found rules. Returns exit code, 2 if errors were found, 0 when only warnings were found. """ msg = "" summary = self.count_results(result.matches) files_count, changed_files_count = self.count_lintables(result.files) matched_rules = self._get_matched_skippable_rules(result.matches) if matched_rules and self.options.generate_ignore: # ANSIBLE_LINT_IGNORE_FILE environment variable overrides default # dumping location in linter and is not documented or supported. We # use this only for testing purposes. ignore_file_path = Path( os.environ.get("ANSIBLE_LINT_IGNORE_FILE", IGNORE_FILE.default), ) console_stderr.print(f"Writing ignore file to {ignore_file_path}") lines: set[str] = set() lines.update(f"{rule.filename} {rule.tag}\n" for rule in result.matches) with ignore_file_path.open("w", encoding="utf-8") as ignore_file: ignore_file.write( "# This file contains ignores rule violations for ansible-lint\n", ) ignore_file.writelines(sorted(lines)) elif matched_rules and not self.options.quiet: console_stderr.print( "Read [link=https://ansible.readthedocs.io/projects/lint/configuring/#ignoring-rules-for-entire-files]documentation[/link] for instructions on how to ignore specific rule violations.", ) # Do not deprecate the old tags just yet. Why? Because it is not currently feasible # to migrate old tags to new tags. There are a lot of things out there that still # use ansible-lint 4 (for example, Ansible Galaxy and Automation Hub imports). If we # replace the old tags, those tools will report warnings. If we do not replace them, # ansible-lint 5 will report warnings. # # We can do the deprecation once the ecosystem caught up at least a bit. # for k, v in used_old_tags.items(): # _logger.warning( # "error in the future.", # k, # v, if self.options.write_list and "yaml" in self.options.skip_list: _logger.warning( "You specified '--fix', but no files can be modified " "because 'yaml' is in 'skip_list'.", ) if mark_as_success and summary.failures: mark_as_success = False if not self.options.quiet: console_stderr.print(render_yaml(msg)) self.report_summary( summary, changed_files_count, files_count, is_success=mark_as_success, ) if mark_as_success: if not files_count: # success without any file being analyzed is reported as failure # to match match, preventing accidents where linter was running # not doing anything due to misconfiguration. _logger.critical( "Linter finished without analyzing any file, check configuration and arguments given.", ) return RC.NO_FILES_MATCHED return RC.SUCCESS return RC.VIOLATIONS_FOUND def report_summary( # pylint: disable=too-many-locals # noqa: C901 self, summary: SummarizedResults, changed_files_count: int, files_count: int, is_success: bool, ) -> None: """Report match and file counts.""" # sort the stats by profiles idx = 0 rule_order = {} for profile, profile_config in PROFILES.items(): for rule in profile_config["rules"]: rule_order[rule] = (idx, profile) idx += 1 _logger.debug("Determined rule-profile order: %s", rule_order) failed_profiles = set() for tag, tag_stats in summary.tag_stats.items(): if tag in rule_order: tag_stats.order, tag_stats.profile = rule_order.get(tag, (idx, "")) elif "[" in tag: tag_stats.order, tag_stats.profile = rule_order.get( tag.split("[")[0], (idx, ""), ) if tag_stats.profile: failed_profiles.add(tag_stats.profile) summary.sort() if changed_files_count: console_stderr.print(f"Modified {changed_files_count} files.") # determine which profile passed summary.passed_profile = "" passed_profile_count = 0 for profile in PROFILES: if profile in failed_profiles: break if profile != summary.passed_profile: summary.passed_profile = profile passed_profile_count += 1 stars = "" if summary.tag_stats: table = "# Rule Violation Summary\n\n" for tag, stats in summary.tag_stats.items(): table += f"{stats.count:3} [link={RULE_DOC_URL}]{tag.split('[')[0]}[/link] [dim]profile:{profile} tags:{','.join(stats.associated_tags)}[/]\n" rating = 5 - (len(PROFILES.keys()) - passed_profile_count) if 0 < rating < 6: stars = f" Rating: {rating}/5 star" console.print(table, file=sys.stderr) msg = "[success]Passed[/]" if is_success else "[failed][bold]Failed[/][/]" msg += f": {summary.failures} failure(s), {summary.warnings} warning(s)" if summary.fixed: msg += f", and fixed {summary.fixed} issue(s)" msg += f" on {files_count} files." # Now we add some information about required and passed profile if self.options.profile: msg += f" Profile '{self.options.profile}' was required" if summary.passed_profile: if summary.passed_profile == self.options.profile: msg += ", and it passed." else: msg += f", but '{summary.passed_profile}' profile passed." else: msg += "." elif summary.passed_profile: msg += f" Last profile that met the validation criteria was '{summary.passed_profile}'." if stars: msg += stars # on offline mode and when run under pre-commit we do not want to # check for updates. if not self.options.offline and os.environ.get("PRE_COMMIT", "0") != "1": version_warning = get_version_warning() if version_warning: msg += f"\n{version_warning}" console_stderr.print(msg) def choose_formatter_factory( options_list: Options, ) -> type[formatters.BaseFormatter[Any]]: """Select an output formatter based on the incoming command line arguments.""" r: type[formatters.BaseFormatter[Any]] = formatters.Formatter if options_list.format == "quiet": r = formatters.QuietFormatter elif options_list.format in ("json", "codeclimate"): r = formatters.CodeclimateJSONFormatter elif options_list.format == "sarif": r = formatters.SarifFormatter elif options_list.parseable or options_list.format == "pep8": r = formatters.ParseableFormatter return r def _sanitize_list_options(tag_list: list[str]) -> list[str]: """Normalize list options.""" # expand comma separated entries tags = set() for tag in tag_list: tags.update(str(tag).split(",")) # remove duplicates, and return as sorted list return sorted(set(tags)) @lru_cache def get_app(*, offline: bool | None = None, cached: bool = False) -> App: """Return the application instance, caching the return value.""" # Avoids ever running the app initialization twice if cached argument # is mentioned. # pylint: disable=global-statement global _CACHED_APP if cached: if offline is not None: msg = ( "get_app should never be called with other arguments when cached=True." ) raise RuntimeError(msg) if cached and _CACHED_APP is not None: return _CACHED_APP if offline is None: offline = default_options.offline if default_options.offline != offline: options = copy.deepcopy(default_options) options.offline = offline else: options = default_options app = App(options=options) if cached: _CACHED_APP = app # Make linter use the cache dir from compat options.cache_dir = app.runtime.cache_dir role_name_check = 0 if "role-name" in app.options.warn_list: role_name_check = 1 elif "role-name" in app.options.skip_list: role_name_check = 2 # mocking must happen before prepare_environment or galaxy install might # fail. _perform_mockings(options=app.options) app.runtime.prepare_environment( install_local=(not offline), offline=offline, role_name_check=role_name_check, ) return app ansible-ansible-lint-c16f018/src/ansiblelint/cli.py000066400000000000000000000513211477347356000222760ustar00rootroot00000000000000"""CLI parser setup and helpers.""" from __future__ import annotations import argparse import logging import os import sys from argparse import Namespace from pathlib import Path from typing import TYPE_CHECKING, Any from ansiblelint.config import ( DEFAULT_KINDS, DEFAULT_WARN_LIST, PROFILES, Options, log_entries, ) from ansiblelint.constants import CUSTOM_RULESDIR_ENVVAR, DEFAULT_RULESDIR, EPILOG, RC from ansiblelint.file_utils import ( Lintable, abspath, expand_path_vars, find_project_root, normpath, ) from ansiblelint.loaders import IGNORE_FILE from ansiblelint.schemas.main import validate_file_schema from ansiblelint.yaml_utils import clean_json if TYPE_CHECKING: from collections.abc import Callable, Sequence _logger = logging.getLogger(__name__) _PATH_VARS = [ "rulesdir", ] def expand_to_normalized_paths( config: dict[str, Any], base_dir: str | None = None, ) -> None: """Mutate given config normalizing any path values in it.""" # config can be None (-c /dev/null) if not config: return base_dir = base_dir or os.getcwd() for paths_var in _PATH_VARS: if paths_var not in config: continue # Cause we don't want to add a variable not present normalized_paths = [] for path in config.pop(paths_var): normalized_path = abspath(expand_path_vars(path), base_dir=base_dir) normalized_paths.append(normalized_path) config[paths_var] = normalized_paths def load_config(config_file: str | None) -> tuple[dict[Any, Any], str | None]: """Load configuration from disk.""" config_path = None if config_file == "/dev/null": _logger.debug("Skipping config file as it was set to /dev/null") return {}, config_file if config_file: config_path = os.path.abspath(config_file) if not os.path.exists(config_path): _logger.error("Config file not found '%s'", config_path) sys.exit(RC.INVALID_CONFIG) config_path = config_path or get_config_path() if not config_path or not os.path.exists(config_path): # a missing default config file should not trigger an error return {}, None config_lintable = Lintable( config_path, kind="ansible-lint-config", base_kind="text/yaml", ) for error in validate_file_schema(config_lintable): _logger.error("Invalid configuration file %s. %s", config_path, error) sys.exit(RC.INVALID_CONFIG) config = clean_json(config_lintable.data) if not isinstance(config, dict): msg = "Schema failed to properly validate the config file." raise TypeError(msg) config["config_file"] = config_path config_dir = os.path.dirname(config_path) expand_to_normalized_paths(config, config_dir) return config, config_path def get_config_path(config_file: str | None = None) -> str | None: """Return local config file.""" if config_file: project_filenames = [config_file] else: project_filenames = [ ".ansible-lint", ".ansible-lint.yml", ".ansible-lint.yaml", ".config/ansible-lint.yml", ".config/ansible-lint.yaml", ] parent = tail = os.getcwd() while tail: for project_filename in project_filenames: filename = os.path.abspath(os.path.join(parent, project_filename)) if os.path.exists(filename): return filename if os.path.exists(os.path.abspath(os.path.join(parent, ".git"))): # Avoid looking outside .git folders as we do not want end-up # picking config files from upper level projects if current # project has no config. return None (parent, tail) = os.path.split(parent) return None class AbspathArgAction(argparse.Action): """Argparse action to convert relative paths to absolute paths.""" def __call__( self, parser: argparse.ArgumentParser, namespace: Namespace, values: str | Sequence[Any] | None, option_string: str | None = None, ) -> None: _logger.debug(option_string) if isinstance(values, str | Path): values = [values] if values: normalized_values = [ Path(expand_path_vars(str(path))).resolve() for path in values ] previous_values = getattr(namespace, self.dest, []) setattr(namespace, self.dest, previous_values + normalized_values) class WriteArgAction(argparse.Action): """Argparse action to handle the --fix flag with optional args.""" _default = "__default__" # noinspection PyShadowingBuiltins def __init__( # pylint: disable=too-many-arguments,redefined-builtin,too-many-positional-arguments self, option_strings: list[str], dest: str, nargs: int | str | None = None, const: Any = None, default: Any = None, type: Callable[[str], Any] | None = None, # noqa: A002 choices: list[Any] | None = None, *, required: bool = False, help: str | None = None, # noqa: A002 metavar: str | None = None, ) -> None: """Create the argparse action with WriteArg-specific defaults.""" if nargs is not None: msg = "nargs for WriteArgAction must not be set." raise ValueError(msg) if const is not None: msg = "const for WriteArgAction must not be set." raise ValueError(msg) super().__init__( option_strings=option_strings, dest=dest, nargs="?", # either 0 (--fix) or 1 (--fix=a,b,c) argument const=self._default, # --fix (no option) implicitly stores this default=default, type=type, choices=choices, required=required, help=help, metavar=metavar, ) def __call__( self, parser: argparse.ArgumentParser, namespace: Namespace, values: str | Sequence[Any] | None, option_string: str | None = None, ) -> None: lintables = getattr(namespace, "lintables", None) if not lintables and isinstance(values, str): # args are processed in order. # If --fix is after lintables, then that is not ambiguous. # But if --fix comes first, then it might actually be a lintable. maybe_lintable = Path(values) if maybe_lintable.exists(): namespace.lintables = [values] values = [] if isinstance(values, str): values = values.split(",") default = [self.const] if isinstance(self.const, str) else self.const previous_values = getattr(namespace, self.dest, default) or default if not values: values = previous_values elif previous_values != default: values = previous_values + values # type: ignore[operator] setattr(namespace, self.dest, values) @classmethod def merge_fix_list_config( cls, from_file: list[str], from_cli: list[str], ) -> list[str]: """Determine the write_list value based on cli vs config. When --fix is not passed from command line the from_cli is an empty list, so we use the file. When from_cli is not an empty list, we ignore the from_file value. """ if not from_file: arguments = ["all"] if from_cli == [cls._default] else from_cli else: arguments = from_file for magic_value in ("none", "all"): if magic_value in arguments and len(arguments) > 1: msg = f"When passing '{magic_value}' to '--fix', you cannot pass other values." raise RuntimeError( msg, ) if len(arguments) == 1 and arguments[0] == "none": arguments = [] return arguments def get_cli_parser() -> argparse.ArgumentParser: """Initialize an argument parser.""" parser = argparse.ArgumentParser( epilog=EPILOG, # Avoid rewrapping description and epilog formatter_class=argparse.RawTextHelpFormatter, ) listing_group = parser.add_mutually_exclusive_group() listing_group.add_argument( "-P", "--list-profiles", dest="list_profiles", default=False, action="store_true", help="List all profiles.", ) listing_group.add_argument( "-L", "--list-rules", dest="list_rules", default=False, action="store_true", help="List all the rules.", ) listing_group.add_argument( "-T", "--list-tags", dest="list_tags", action="store_true", help="List all the tags and the rules they cover.", ) parser.add_argument( "-f", "--format", dest="format", default=None, choices=[ "brief", # "plain", "full", "md", "json", "codeclimate", "quiet", "pep8", "sarif", ], help="stdout formatting, json being an alias for codeclimate. (default: %(default)s)", ) parser.add_argument( "--sarif-file", default=None, type=Path, help="SARIF output file", ) parser.add_argument( "-q", dest="quiet", default=0, action="count", help="quieter, reduce verbosity, can be specified twice.", ) parser.add_argument( "--profile", dest="profile", default=None, action="store", choices=PROFILES.keys(), help="Specify which rules profile to be used.", ) parser.add_argument( "-p", "--parseable", dest="parseable", default=False, action="store_true", help="parseable output, same as '-f pep8'", ) parser.add_argument( "--project-dir", dest="project_dir", default=None, help="Location of project/repository, autodetected based on location " "of configuration file.", ) parser.add_argument( "-r", "--rules-dir", action=AbspathArgAction, dest="rulesdir", default=[], type=Path, help="Specify custom rule directories. Add -R " f"to keep using embedded rules from {DEFAULT_RULESDIR}", ) parser.add_argument( "-R", action="store_true", default=False, dest="use_default_rules", help="Keep default rules when using -r", ) parser.add_argument( "-s", "--strict", action="store_true", default=False, dest="strict", help="Return non-zero exit code on warnings as well as errors", ) parser.add_argument( "--fix", dest="write_list", # this is a tri-state argument that takes an optional comma separated list: action=WriteArgAction, help="Allow ansible-lint to perform auto-fixes, including YAML reformatting. " "You can limit the effective rule transforms (the 'write_list') by passing a " "keywords 'all' or 'none' or a comma separated list of rule ids or rule tags. " "YAML reformatting happens whenever '--fix' or '--fix=' is used. " "'--fix' and '--fix=all' are equivalent: they allow all transforms to run. " "Presence of --fix in command overrides config file value.", ) parser.add_argument( "--show-relpath", dest="display_relative_path", action="store_false", default=True, help="Display path relative to CWD", ) parser.add_argument( "-t", "--tags", dest="tags", action="append", default=[], help="only check rules whose id/tags match these values", ) parser.add_argument( "-v", dest="verbosity", action="count", help="Increase verbosity level (-vv for more)", default=0, ) parser.add_argument( "-x", "--skip-list", dest="skip_list", default=[], action="append", help="only check rules whose id/tags do not match these values. \ e.g: --skip-list=name,run-once", ) parser.add_argument( "--generate-ignore", dest="generate_ignore", action="store_true", default=False, help="Generate a text file '.ansible-lint-ignore' that ignores all found violations. Each line contains filename and rule id separated by a space.", ) parser.add_argument( "-w", "--warn-list", dest="warn_list", default=[], action="append", help="only warn about these rules, unless overridden in " f"config file. Current version default value is: {', '.join(DEFAULT_WARN_LIST)}", ) parser.add_argument( "--enable-list", dest="enable_list", default=[], action="append", help="activate optional rules by their tag name", ) # Do not use store_true/store_false because they create opposite defaults. parser.add_argument( "--nocolor", dest="colored", action="store_const", const=False, help="disable colored output, same as NO_COLOR=1", ) parser.add_argument( "--force-color", dest="colored", action="store_const", const=True, help="Force colored output, same as FORCE_COLOR=1", ) parser.add_argument( "--exclude", dest="exclude_paths", action="extend", nargs="+", type=str, default=[], help="path to directories or files to skip. This option is repeatable.", ) parser.add_argument( "-c", "--config-file", dest="config_file", help="Specify configuration file to use. By default it will look for '.ansible-lint', '.ansible-lint.yml', '.ansible-lint.yaml', '.config/ansible-lint.yml', or '.config/ansible-lint.yaml'", ) parser.add_argument( "-i", "--ignore-file", dest="ignore_file", type=Path, default=None, help=f"Specify ignore file to use. By default it will look for '{IGNORE_FILE.default}' or '{IGNORE_FILE.alternative}'", ) parser.add_argument( "--offline", dest="offline", action="store_const", const=True, help="Disable installation of requirements.yml and schema refreshing", ) parser.add_argument( "--version", action="store_true", ) parser.add_argument( dest="lintables", nargs="*", action="extend", help="One or more files or paths. When missing it will enable auto-detection mode.", ) return parser def merge_config(file_config: dict[Any, Any], cli_config: Options) -> Options: """Combine the file config with the CLI args.""" bools = ( "display_relative_path", "parseable", "quiet", "strict", "use_default_rules", "offline", ) # maps lists to their default config values lists_map = { "exclude_paths": [".cache", ".git", ".hg", ".svn", ".tox"], "rulesdir": [], "skip_list": [], "tags": [], "warn_list": DEFAULT_WARN_LIST, "mock_modules": [], "mock_roles": [], "enable_list": [], "only_builtins_allow_collections": [], "only_builtins_allow_modules": [], "supported_ansible_also": [], # do not include "write_list" here. See special logic below. } scalar_map = { "loop_var_prefix": None, "project_dir": None, "profile": None, "sarif_file": None, } if not file_config: # use defaults if we don't have a config file and the commandline # parameter is not set for entry, default in lists_map.items(): if not getattr(cli_config, entry, None): setattr(cli_config, entry, default) if cli_config.write_list is None: cli_config.write_list = [] elif cli_config.write_list == [WriteArgAction._default]: # noqa: SLF001 # pragma: no cover cli_config.write_list = ["all"] return cli_config for entry in bools: file_value = file_config.pop(entry, False) v = getattr(cli_config, entry) or file_value setattr(cli_config, entry, v) for entry, default_scalar in scalar_map.items(): file_value = file_config.pop(entry, default_scalar) v = getattr(cli_config, entry, None) or file_value setattr(cli_config, entry, v) # if either commandline parameter or config file option is set merge # with the other, if neither is set use the default for entry, default in lists_map.items(): if getattr(cli_config, entry, None) or entry in file_config: value = getattr(cli_config, entry, []) value.extend(file_config.pop(entry, [])) else: value = default setattr(cli_config, entry, value) # "write_list" config has special merge rules entry = "write_list" setattr( cli_config, entry, WriteArgAction.merge_fix_list_config( from_file=file_config.pop(entry, []), from_cli=getattr(cli_config, entry, []) or [], ), ) if "verbosity" in file_config: cli_config.verbosity = cli_config.verbosity + file_config.pop("verbosity") # merge options that can be set only via a file config for entry, value in file_config.items(): setattr(cli_config, entry, value) # append default kinds to the custom list kinds = file_config.get("kinds", []) kinds.extend(DEFAULT_KINDS) cli_config.kinds = kinds return cli_config def get_config(arguments: list[str]) -> Options: """Extract the config based on given args.""" parser = get_cli_parser() # translate deprecated options for i, value in enumerate(arguments): if arguments[i].startswith("--write"): arguments[i] = value.replace("--write", "--fix") _logger.warning( "Replaced deprecated '--write' option with '--fix', change you call to avoid future regressions when we remove old option.", ) options = Options(**vars(parser.parse_args(arguments))) # docs is not document, being used for internal documentation building if options.list_rules and options.format not in [ None, "brief", "full", "md", ]: parser.error( f"argument -f: invalid choice: '{options.format}'. " f"In combination with argument -L only 'brief', " f"'rich' or 'md' are supported with -f.", ) # save info about custom config file, as options.config_file may be modified by merge_config file_config, options.config_file = load_config(options.config_file) config = merge_config(file_config, options) options.rulesdirs = get_rules_dirs( options.rulesdir, use_default=options.use_default_rules, ) if not options.project_dir: project_dir, method = find_project_root( srcs=options.lintables, config_file=options.config_file, ) options.project_dir = os.path.expanduser(normpath(project_dir)) log_entries.append( ( logging.INFO, f"Identified [repr.path]{project_dir}[/] as project root due [bold]{method}[/].", ), ) if not options.project_dir or not os.path.exists(options.project_dir): msg = f"Failed to determine a valid project_dir: {options.project_dir}" raise RuntimeError(msg) # expand user home dir in exclude_paths options.exclude_paths = [ os.path.expandvars(os.path.expanduser(p)) for p in options.exclude_paths ] # Compute final verbosity level by subtracting -q counter. options.verbosity -= options.quiet return config def print_help(file: Any = sys.stdout) -> None: """Print help test to the given stream.""" get_cli_parser().print_help(file=file) def get_rules_dirs(rulesdir: list[Path], *, use_default: bool = True) -> list[Path]: """Return a list of rules dirs.""" default_ruledirs = [DEFAULT_RULESDIR] default_custom_rulesdir = os.environ.get( CUSTOM_RULESDIR_ENVVAR, os.path.join(DEFAULT_RULESDIR, "custom"), ) custom_ruledirs = sorted( str(x.resolve()) for x in Path(default_custom_rulesdir).iterdir() if x.is_dir() and (x / "__init__.py").exists() ) result: list[Any] = [] if use_default: result = rulesdir + custom_ruledirs + default_ruledirs elif rulesdir: result = rulesdir else: result = custom_ruledirs + default_ruledirs return [Path(p) for p in result] ansible-ansible-lint-c16f018/src/ansiblelint/config.py000066400000000000000000000314021477347356000227720ustar00rootroot00000000000000"""Store configuration options as a singleton.""" from __future__ import annotations import json import logging import os import sys import time import urllib.request import warnings from dataclasses import dataclass, field from http.client import HTTPException from importlib.metadata import PackageNotFoundError, distribution, version from pathlib import Path from typing import Any from urllib.error import HTTPError, URLError from packaging.version import Version from ansiblelint import __version__ from ansiblelint.loaders import yaml_from_file _logger = logging.getLogger(__name__) CACHE_DIR = ( os.path.expanduser(os.environ.get("XDG_CACHE_HOME", "~/.cache")) + "/ansible-lint" ) DEFAULT_WARN_LIST = [ "experimental", "jinja[spacing]", # warning until we resolve all reported false-positives "fqcn[deep]", # 2023-05-31 added ] DEFAULT_KINDS = [ # Do not sort this list, order matters. {"jinja2": "**/*.j2"}, # jinja2 templates are not always parsable as something else {"jinja2": "**/*.j2.*"}, {"yaml": ".github/**/*.{yaml,yml}"}, # github workflows {"text": "**/templates/**/*.*"}, # templates are likely not validable {"execution-environment": "**/execution-environment.yml"}, {"ansible-lint-config": "**/.ansible-lint"}, {"ansible-lint-config": "**/.ansible-lint.{yaml,yml}"}, {"ansible-lint-config": "**/.config/ansible-lint.{yaml,yml}"}, {"ansible-navigator-config": "**/ansible-navigator.{yaml,yml}"}, {"inventory": "**/inventory/**.{yaml,yml}"}, {"requirements": "**/meta/requirements.{yaml,yml}"}, # v1 only # https://docs.ansible.com/ansible/latest/dev_guide/collections_galaxy_meta.html {"galaxy": "**/galaxy.yml"}, # Galaxy collection meta {"reno": "**/releasenotes/*/*.{yaml,yml}"}, # reno release notes {"vars": "**/{host_vars,group_vars,vars,defaults}/**/*.{yaml,yml}"}, {"tasks": "**/tasks/**/*.{yaml,yml}"}, {"rulebook": "**/rulebooks/*.{yml,yaml"}, {"playbook": "**/playbooks/*.{yml,yaml}"}, {"playbook": "**/*playbook*.{yml,yaml}"}, {"role": "**/roles/*/"}, {"handlers": "**/handlers/*.{yaml,yml}"}, {"test-meta": "**/tests/integration/targets/*/meta/main.{yaml,yml}"}, {"meta": "**/meta/main.{yaml,yml}"}, {"meta-runtime": "**/meta/runtime.{yaml,yml}"}, {"role-arg-spec": "**/meta/argument_specs.{yaml,yml}"}, # role argument specs {"yaml": ".config/molecule/config.{yaml,yml}"}, # molecule global config { "requirements": "**/molecule/*/{collections,requirements}.{yaml,yml}", }, # molecule old collection requirements (v1), ansible 2.8 only {"yaml": "**/molecule/*/{base,molecule}.{yaml,yml}"}, # molecule config {"requirements": "**/requirements.{yaml,yml}"}, # v2 and v1 {"playbook": "**/molecule/*/*.{yaml,yml}"}, # molecule playbooks {"yaml": "**/{.ansible-lint,.yamllint}"}, {"changelog": "**/changelogs/changelog.{yaml,yml}"}, {"yaml": "**/*.{yaml,yml}"}, {"yaml": "**/.*.{yaml,yml}"}, {"sanity-ignore-file": "**/tests/sanity/ignore-*.txt"}, # what are these doc_fragments? We also ignore module_utils for now { "plugin": "**/plugins/{action,become,cache,callback,connection,filter,inventory,lookup,modules,test}/**/*.py", }, {"python": "**/*.py"}, ] BASE_KINDS = [ # These assignations are only for internal use and are only inspired by # MIME/IANA model. Their purpose is to be able to process a file based on # it type, including generic processing of text files using the prefix. { "text/jinja2": "**/*.j2", }, # jinja2 templates are not always parsable as something else {"text/jinja2": "**/*.j2.*"}, {"text": "**/templates/**/*.*"}, # templates are likely not validable {"text/json": "**/*.json"}, # standardized {"text/markdown": "**/*.md"}, # https://tools.ietf.org/html/rfc7763 {"text/rst": "**/*.rst"}, # https://en.wikipedia.org/wiki/ReStructuredText {"text/ini": "**/*.ini"}, # YAML has no official IANA assignation {"text/yaml": "**/{.ansible-lint,.yamllint}"}, {"text/yaml": "**/*.{yaml,yml}"}, {"text/yaml": "**/.*.{yaml,yml}"}, {"text/python": "**/*.py"}, ] # File kinds that are recognized by ansible, used internally to force use of # YAML 1.1 instead of 1.2 due to ansible-core dependency on pyyaml. ANSIBLE_OWNED_KINDS = { "handlers", "galaxy", "meta", "meta-runtime", "playbook", "requirements", "role-arg-spec", "rulebook", "tasks", "vars", } PROFILES = yaml_from_file(Path(__file__).parent / "data" / "profiles.yml") LOOP_VAR_PREFIX = "^(__|{role}_)" @dataclass class Options: # pylint: disable=too-many-instance-attributes """Store ansible-lint effective configuration options.""" # Private attributes _skip_ansible_syntax_check: bool = False # Public attributes cache_dir: Path | None = None colored: bool = True configured: bool = False cwd: Path = Path() display_relative_path: bool = True exclude_paths: list[str] = field(default_factory=list) format: str = "brief" lintables: list[str] = field(default_factory=list) list_rules: bool = False list_tags: bool = False write_list: list[str] = field(default_factory=list) write_exclude_list: list[str] = field(default_factory=list) parseable: bool = False quiet: bool = False rulesdirs: list[Path] = field(default_factory=list) skip_list: list[str] = field(default_factory=list) tags: list[str] = field(default_factory=list) verbosity: int = 0 warn_list: list[str] = field(default_factory=list) kinds = DEFAULT_KINDS mock_filters: list[str] = field(default_factory=list) mock_modules: list[str] = field(default_factory=list) mock_roles: list[str] = field(default_factory=list) loop_var_prefix: str | None = None only_builtins_allow_collections: list[str] = field(default_factory=list) only_builtins_allow_modules: list[str] = field(default_factory=list) var_naming_pattern: str | None = None offline: bool = False project_dir: str = "." # default should be valid folder (do not use None here) extra_vars: dict[str, Any] | None = None enable_list: list[str] = field(default_factory=list) skip_action_validation: bool = True strict: bool = False rules: dict[str, Any] = field( default_factory=dict, ) # Placeholder to set and keep configurations for each rule. profile: str | None = None task_name_prefix: str = "{stem} | " sarif_file: Path | None = None config_file: str | None = None generate_ignore: bool = False rulesdir: list[Path] = field(default_factory=list) use_default_rules: bool = False version: bool = False # display version command list_profiles: bool = False # display profiles command ignore_file: Path | None = None max_tasks: int = 100 max_block_depth: int = 20 # Refer to https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html#ansible-core-support-matrix _default_supported = ["2.15.", "2.16.", "2.17.", "2.18."] supported_ansible_also: list[str] = field(default_factory=list) @property def nodeps(self) -> bool: """Returns value of nodeps feature.""" # We do not want this to be cached as it would affect our testings. return bool(int(os.environ.get("ANSIBLE_LINT_NODEPS", "0"))) def __post_init__(self) -> None: """Extra initialization logic.""" if self.nodeps: self.offline = True @property def supported_ansible(self) -> list[str]: """Returns list of ansible versions that are considered supported.""" return sorted([*self._default_supported, *self.supported_ansible_also]) options = Options() # Used to store detected tag deprecations used_old_tags: dict[str, str] = {} # Used to store log messages before logging is initialized (level, message) log_entries: list[tuple[int, str]] = [] def in_venv() -> bool: """Determine whether Python is running from a venv.""" if hasattr(sys, "real_prefix") or os.environ.get("CONDA_EXE", None) is not None: return True pfx = getattr(sys, "base_prefix", sys.prefix) return pfx != sys.prefix def guess_install_method() -> str: """Guess if pip upgrade command should be used.""" package_name = "ansible-lint" try: if (distribution(package_name).read_text("INSTALLER") or "").strip() != "pip": return "" except PackageNotFoundError as exc: _logger.debug(exc) return "" pip = "" if in_venv(): _logger.debug("Found virtualenv, assuming `pip3 install` will work.") pip = f"pip install --upgrade {package_name}" elif __file__.startswith(os.path.expanduser("~/.local/lib")): _logger.debug( "Found --user installation, assuming `pip3 install --user` will work.", ) pip = f"pip3 install --user --upgrade {package_name}" # By default we assume pip is not safe to be used use_pip = False try: # Use pip to detect if is safe to use it to upgrade the package. # We do imports here to for performance and reasons, and also in order # to avoid errors if pip internals change. Also we want to avoid having # to add pip as a dependency, so we make use of it only when present. # trick to avoid runtime warning from inside pip: _distutils_hack/__init__.py:33: UserWarning: Setuptools is replacing distutils. with warnings.catch_warnings(record=True): warnings.simplefilter("always") # pylint: disable=import-outside-toplevel from pip._internal.metadata import get_default_environment from pip._internal.req.req_uninstall import uninstallation_paths dist = get_default_environment().get_distribution(package_name) if dist: _logger.debug("Found %s dist", dist) for _ in uninstallation_paths(dist): use_pip = True else: _logger.debug("Skipping %s as it is not installed.", package_name) use_pip = False except (AttributeError, ModuleNotFoundError) as exc: # On Fedora 36, we got a AttributeError exception from pip that we want to avoid # On NixOS, we got a ModuleNotFoundError exception from pip that we want to avoid _logger.debug(exc) use_pip = False # We only want to recommend pip for upgrade if it looks safe to do so. return pip if use_pip else "" def get_deps_versions() -> dict[str, Version | None]: """Return versions of most important dependencies.""" result: dict[str, Version | None] = {} for name in ["ansible-core", "ansible-compat", "ruamel-yaml", "ruamel-yaml-clib"]: try: result[name] = Version(version(name)) except PackageNotFoundError: result[name] = None return result def get_version_warning() -> str: """Display warning if current version is outdated.""" # 0.1dev1 is special fallback version if __version__ == "0.1.dev1": # pragma: no cover return "" pip = guess_install_method() # If we do not know how to upgrade, we do not want to show any warnings # about version. if not pip: return "" msg = "" data = {} current_version = Version(__version__) if not os.path.exists(CACHE_DIR): # pragma: no cover os.makedirs(CACHE_DIR) cache_file = f"{CACHE_DIR}/latest.json" refresh = True if os.path.exists(cache_file): age = time.time() - os.path.getmtime(cache_file) if age < 24 * 60 * 60: refresh = False with open(cache_file, encoding="utf-8") as f: data = json.load(f) if not options.offline and (refresh or not data): release_url = ( "https://api.github.com/repos/ansible/ansible-lint/releases/latest" ) try: with urllib.request.urlopen(release_url) as url: # noqa: S310 data = json.load(url) with open(cache_file, "w", encoding="utf-8") as f: json.dump(data, f) except (URLError, HTTPError, HTTPException) as exc: # pragma: no cover _logger.debug( "Unable to fetch latest version from %s due to: %s", release_url, exc, ) return "" if data: html_url = data["html_url"] new_version = Version(data["tag_name"][1:]) # removing v prefix from tag if current_version > new_version: msg = "[dim]You are using a pre-release version of ansible-lint.[/]" elif current_version < new_version: msg = f"""[warning]A new release of ansible-lint is available: [warning]{current_version}[/] → [success][link={html_url}]{new_version}[/link][/][/]""" msg += f" Upgrade by running: [info]{pip}[/]" return msg ansible-ansible-lint-c16f018/src/ansiblelint/constants.py000066400000000000000000000137631477347356000235530ustar00rootroot00000000000000"""Constants used by AnsibleLint.""" import re from enum import Enum from pathlib import Path from typing import Literal TAG_NAME_REGEXP = re.compile(r"^(?!.*__)[a-z][0-9a-z_]*$") MAX_TAGS_COUNT = 20 MAX_LENGTH_TAG = 64 DEFAULT_RULESDIR = Path(__file__).parent / "rules" CUSTOM_RULESDIR_ENVVAR = "ANSIBLE_LINT_CUSTOM_RULESDIR" RULE_DOC_URL = "https://ansible.readthedocs.io/projects/lint/rules/" SKIP_SCHEMA_UPDATE = "ANSIBLE_LINT_SKIP_SCHEMA_UPDATE" ENV_VARS_HELP = { CUSTOM_RULESDIR_ENVVAR: "Used for adding another folder into the lookup path for new rules.", "ANSIBLE_LINT_IGNORE_FILE": "Define it to override the name of the default ignore file `.ansible-lint-ignore`", "ANSIBLE_LINT_WRITE_TMP": "Tells linter to dump fixes into different temp files instead of overriding original. Used internally for testing.", SKIP_SCHEMA_UPDATE: "Tells ansible-lint to skip schema refresh.", "ANSIBLE_LINT_NODEPS": "Avoids installing content dependencies and avoids performing checks that would fail when modules are not installed. Far less violations will be reported.", } EPILOG = ( "The following environment variables are also recognized but there is no guarantee that they will work in future versions:\n\n" + "\n".join(f"{key}: {value}\n" for key, value in ENV_VARS_HELP.items()) ) # Not using an IntEnum because only starting with py3.11 it will evaluate it # as int. class RC: # pylint: disable=too-few-public-methods """All exit codes used by ansible-lint.""" SUCCESS = 0 VIOLATIONS_FOUND = 2 INVALID_CONFIG = 3 LOCK_TIMEOUT = 4 NO_FILES_MATCHED = 5 EXIT_CONTROL_C = 130 ANSIBLE_MOCKED_MODULE = """\ # This is a mocked Ansible module generated by ansible-lint from ansible.module_utils.basic import AnsibleModule DOCUMENTATION = ''' module: {name} short_description: Mocked version_added: "1.0.0" description: Mocked author: - ansible-lint (@nobody) ''' EXAMPLES = '''mocked''' RETURN = '''mocked''' def main(): result = dict( changed=False, original_message='', message='') module = AnsibleModule( argument_spec=dict(), supports_check_mode=True, ) module.exit_json(**result) if __name__ == "__main__": main() """ FileType = Literal[ "playbook", "rulebook", "meta", # role meta "meta-runtime", "tasks", # includes pre_tasks, post_tasks "handlers", # very similar to tasks but with some specifics # https://docs.ansible.com/ansible/latest/galaxy/user_guide.html#installing-roles-and-collections-from-the-same-requirements-yml-file "requirements", "role", # that is a folder! "yaml", # generic yaml file, previously reported as unknown file type "ansible-lint-config", "sanity-ignore-file", # tests/sanity/ignore file "plugin", "galaxy", # galaxy.yml "", # unknown file type ] # Aliases for deprecated tags/ids and their newer names RENAMED_TAGS = { "102": "no-jinja-when", "104": "deprecated-bare-vars", "105": "deprecated-module", "106": "role-name", "202": "risky-octal", "203": "no-tabs", "205": "playbook-extension", "206": "jinja[spacing]", "207": "jinja[invalid]", "208": "risky-file-permissions", "301": "no-changed-when", "302": "deprecated-command-syntax", "303": "command-instead-of-module", "304": "inline-env-var", "305": "command-instead-of-shell", "306": "risky-shell-pipe", "401": "latest[git]", "402": "latest[hg]", "403": "package-latest", "404": "no-relative-paths", "501": "partial-become", "502": "name[missing]", "503": "no-handler", "504": "deprecated-local-action", "505": "missing-import", "601": "literal-compare", "602": "empty-string-compare", "702": "meta-no-tags", "703": "meta-incorrect", "704": "meta-video-links", "911": "syntax-check", "deprecated-command-syntax": "no-free-form", "fqcn-builtins": "fqcn[action-core]", "git-latest": "latest[git]", "hg-latest": "latest[hg]", "no-jinja-nesting": "jinja[invalid]", "no-loop-var-prefix": "loop-var-prefix", "unnamed-task": "name[missing]", "var-spacing": "jinja[spacing]", } PLAYBOOK_TASK_KEYWORDS = [ "tasks", "handlers", "pre_tasks", "post_tasks", ] PLAYBOOK_ROLE_KEYWORDS = [ "any_errors_fatal", "become", "become_exe", "become_flags", "become_method", "become_user", "check_mode", "collections", "connection", "debugger", "delegate_facts", "delegate_to", "diff", "environment", "ignore_errors", "ignore_unreachable", "module_defaults", "name", "role", "no_log", "port", "remote_user", "run_once", "tags", "throttle", "timeout", "vars", "when", ] NESTED_TASK_KEYS = [ "block", "always", "rescue", ] # Keys that are used internally when parsing YAML/JSON files SKIPPED_RULES_KEY = "__skipped_rules__" LINE_NUMBER_KEY = "__line__" FILENAME_KEY = "__file__" ANNOTATION_KEYS = [ FILENAME_KEY, LINE_NUMBER_KEY, SKIPPED_RULES_KEY, "__ansible_module__", "__ansible_module_original__", ] INCLUSION_ACTION_NAMES = { "include", "include_tasks", "import_playbook", "import_tasks", "ansible.builtin.include", "ansible.builtin.include_tasks", "ansible.builtin.import_playbook", "ansible.builtin.import_tasks", } ROLE_IMPORT_ACTION_NAMES = { "ansible.builtin.import_role", "ansible.builtin.include_role", "ansible.legacy.import_role", "ansible.legacy.include_role", "import_role", "include_role", } CONFIG_FILENAMES = [ ".ansible-lint", ".ansible-lint.yml", ".ansible-lint.yaml", ".config/ansible-lint.yml", ".config/ansible-lint.yaml", ] class States(Enum): """States used are used as sentinel values in various places.""" NOT_LOADED = "File not loaded" LOAD_FAILED = "File failed to load" UNKNOWN_DATA = "Unknown data" def __bool__(self) -> bool: """Ensure all states evaluate as False as booleans.""" return False ansible-ansible-lint-c16f018/src/ansiblelint/data/000077500000000000000000000000001477347356000220645ustar00rootroot00000000000000ansible-ansible-lint-c16f018/src/ansiblelint/data/.yamllint000066400000000000000000000016321477347356000237200ustar00rootroot00000000000000extends: default rules: comments: # https://github.com/prettier/prettier/issues/6780 min-spaces-from-content: 1 # https://github.com/adrienverge/yamllint/issues/384 comments-indentation: false document-start: disable # 160 chars was the default used by old E204 rule, but # you can easily change it or disable in your .yamllint file. line-length: max: 160 # We are adding an extra space inside braces as that's how prettier does it # and we are trying not to fight other linters. braces: min-spaces-inside: 0 # yamllint defaults to 0 max-spaces-inside: 1 # yamllint defaults to 0 # key-duplicates: # forbid-duplicated-merge-keys: true # not enabled by default octal-values: forbid-implicit-octal: true # yamllint defaults to false forbid-explicit-octal: true # yamllint defaults to false # quoted-strings: # quote-type: double # required: only-when-needed ansible-ansible-lint-c16f018/src/ansiblelint/data/profiles.yml000066400000000000000000000076741477347356000244500ustar00rootroot00000000000000--- # Do not change sorting order of the primary keys as they also represent how # progressive the profiles are, each one extending the one before it. min: description: > The `min` profile ensures that Ansible can load content. Rules in this profile are mandatory because they prevent fatal errors. You can add files to the exclude list or provide dependencies to load the correct files. extends: null rules: internal-error: load-failure: parser-error: syntax-check: basic: description: > The `basic` profile prevents common coding issues and enforces standard styles and formatting. extends: min rules: command-instead-of-module: command-instead-of-shell: deprecated-bare-vars: deprecated-local-action: deprecated-module: inline-env-var: key-order: literal-compare: jinja: no-free-form: # schema-related url: https://github.com/ansible/ansible-lint/issues/2117 no-jinja-when: no-tabs: partial-become: playbook-extension: role-name: schema: # can cover lots of rules, but not really be able to give best error messages name: var-naming: yaml: skip_list: # just because we enable them in following profiles - name[template] - name[casing] moderate: description: > The `moderate` profile ensures that content adheres to best practices for making content easier to read and maintain. extends: basic rules: name[template]: name[imperative]: url: https://github.com/ansible/ansible-lint/issues/2170 name[casing]: spell-var-name: url: https://github.com/ansible/ansible-lint/issues/2168 safety: description: > The `safety` profile avoids module calls that can have non-determinant outcomes or security concerns. extends: moderate rules: avoid-implicit: latest: package-latest: risky-file-permissions: risky-octal: risky-shell-pipe: shared: description: > The `shared` profile ensures that content follows best practices for packaging and publishing. This profile is intended for content creators who want to make Ansible playbooks, roles, or collections available from [galaxy.ansible.com](https://galaxy.ansible.com/), [automation-hub](https://console.redhat.com/ansible/automation-hub), or a private instance. extends: safety rules: galaxy: # <-- applies to both galaxy and automation-hub ignore-errors: layout: url: https://github.com/ansible/ansible-lint/issues/1900 meta-incorrect: meta-no-tags: meta-video-links: meta-version: url: https://github.com/ansible/ansible-lint/issues/2103 meta-runtime: url: https://github.com/ansible/ansible-lint/issues/2102 no-changed-when: no-changelog: url: https://github.com/ansible/ansible-lint/issues/2101 no-handler: no-relative-paths: max-block-depth: url: https://github.com/ansible/ansible-lint/issues/2173 max-tasks: url: https://github.com/ansible/ansible-lint/issues/2172 unsafe-loop: # unsafe-loop[prefix] (currently named "no-var-prefix") # [unsafe-loop[var-prefix|iterator]] url: https://github.com/ansible/ansible-lint/issues/2038 production: description: > The `production` profile ensures that content meets requirements for inclusion in [Ansible Automation Platform (AAP)](https://www.redhat.com/en/technologies/management/ansible) as validated or certified content. extends: shared rules: avoid-dot-notation: url: https://github.com/ansible/ansible-lint/issues/2174 sanity: url: https://github.com/ansible/ansible-lint/issues/2121 fqcn: import-task-no-when: url: https://github.com/ansible/ansible-lint/issues/2219 meta-no-dependencies: url: https://github.com/ansible/ansible-lint/issues/2159 single-entry-point: url: https://github.com/ansible/ansible-lint/issues/2242 use-loop: url: https://github.com/ansible/ansible-lint/issues/2204 ansible-ansible-lint-c16f018/src/ansiblelint/errors.py000066400000000000000000000135271477347356000230510ustar00rootroot00000000000000"""Exceptions and error representations.""" from __future__ import annotations import functools from dataclasses import dataclass, field from typing import TYPE_CHECKING, Any from ansiblelint._internal.rules import BaseRule, RuntimeErrorRule from ansiblelint.file_utils import Lintable if TYPE_CHECKING: from ansiblelint.utils import Task class LintWarning(Warning): """Used by linter.""" @dataclass class WarnSource: """Container for warning information, so we can later create a MatchError from it.""" filename: Lintable lineno: int tag: str message: str | None = None @dataclass(frozen=True) class RuleMatchTransformMeta: """Additional metadata about a match error to be used during transformation.""" # pylint: disable=too-many-instance-attributes @dataclass(unsafe_hash=True) @functools.total_ordering class MatchError(ValueError): """Rule violation detected during linting. It can be raised as Exception but also just added to the list of found rules violations. Note that line argument is not considered when building hash of an instance. """ # order matters for these: message: str = field(init=True, repr=False, default="") lintable: Lintable = field(init=True, repr=False, default=Lintable(name="")) tag: str = field(init=True, repr=False, default="") lineno: int = 1 details: str = "" column: int | None = None # rule is not included in hash because we might have different instances # of the same rule, but we use the 'tag' to identify the rule. rule: BaseRule = field(hash=False, default=RuntimeErrorRule()) ignored: bool = False fixed: bool = False # True when a transform has resolved this MatchError transform_meta: RuleMatchTransformMeta | None = None def __post_init__(self) -> None: """Can be use by rules that can report multiple errors type, so we can still filter by them.""" self.filename = self.lintable.name # We want to catch accidental MatchError() which contains no useful # information. When no arguments are passed, the '_message' field is # set to 'property', only if passed it becomes a string. if self.rule.__class__ is RuntimeErrorRule: # so instance was created without a rule if not self.message: msg = f"{self.__class__.__name__}() missing a required argument: one of 'message' or 'rule'" raise TypeError(msg) if not isinstance(self.tag, str): # pragma: no cover msg = "MatchErrors must be created with either rule or tag specified." raise TypeError(msg) if not self.message: self.message = self.rule.shortdesc self.match_type: str | None = None # for task matches, save the normalized task object (useful for transforms) self.task: Task | None = None # path to the problem area, like: [0,"pre_tasks",3] for [0].pre_tasks[3] self.yaml_path: list[int | str] = [] if not self.tag: self.tag = self.rule.id # Safety measure to ensure we do not end-up with incorrect indexes if self.lineno == 0: # pragma: no cover msg = "MatchError called incorrectly as line numbers start with 1" raise RuntimeError(msg) if self.column == 0: # pragma: no cover msg = "MatchError called incorrectly as column numbers start with 1" raise RuntimeError(msg) self.lineno += self.lintable.line_offset # We make the lintable aware that we found a match inside it, as this # can be used to skip running other rules that do require current one # to pass. self.lintable.matches.append(self) @functools.cached_property def level(self) -> str: """Return the level of the rule: error, warning or notice.""" if ( not self.ignored and self.rule.options and {self.tag, self.rule.id, *self.rule.tags}.isdisjoint( self.rule.options.warn_list, ) ): return "error" return "warning" def __repr__(self) -> str: """Return a MatchError instance representation.""" formatstr = "[{0}] ({1}) matched {2}:{3} {4}" # note that `rule.id` can be int, str or even missing, as users # can defined their own custom rules. id_ = getattr(self.rule, "id", "000") return formatstr.format( id_, self.message, self.filename, self.lineno, self.details, ) def __str__(self) -> str: """Return a MatchError instance string representation.""" return self.__repr__() @property def position(self) -> str: """Return error positioning, with column number if available.""" if self.column: return f"{self.lineno}:{self.column}" return str(self.lineno) @property def _hash_key(self) -> Any: # line attr is knowingly excluded, as dict is not hashable return ( self.filename, self.lineno, str(getattr(self.rule, "id", 0)), self.message, self.details, # -1 is used here to force errors with no column to sort before # all other errors. -1 if self.column is None else self.column, ) def __lt__(self, other: object) -> bool: """Return whether the current object is less than the other.""" if not isinstance(other, self.__class__): return NotImplemented return bool(self._hash_key < other._hash_key) def __eq__(self, other: object) -> bool: """Identify whether the other object represents the same rule match.""" if not isinstance(other, self.__class__): return NotImplemented return self.__hash__() == other.__hash__() ansible-ansible-lint-c16f018/src/ansiblelint/file_utils.py000066400000000000000000000523541477347356000236750ustar00rootroot00000000000000"""Utility functions related to file operations.""" from __future__ import annotations import copy import logging import os import sys from collections import defaultdict from contextlib import contextmanager from pathlib import Path from tempfile import NamedTemporaryFile from typing import TYPE_CHECKING, Any, cast import pathspec import wcmatch.pathlib import wcmatch.wcmatch from yaml.error import YAMLError from ansiblelint.app import get_app from ansiblelint.config import ANSIBLE_OWNED_KINDS, BASE_KINDS, Options, options from ansiblelint.constants import CONFIG_FILENAMES, FileType, States if TYPE_CHECKING: from collections.abc import Iterator, Sequence from ansiblelint.errors import MatchError _logger = logging.getLogger(__package__) def abspath(path: str, base_dir: str) -> str: """Make relative path absolute relative to given directory. path (str): the path to make absolute base_dir (str): the directory from which make relative paths absolute. """ if not os.path.isabs(path): # Don't use abspath as it assumes path is relative to cwd. # We want it relative to base_dir. path = os.path.join(base_dir, path) return os.path.normpath(path) def normpath(path: str | Path) -> str: """Normalize a path in order to provide a more consistent output. Currently it generates a relative path but in the future we may want to make this user configurable. """ # prevent possible ValueError with relpath(), when input is an empty string if not path: path = "." # conversion to string in order to allow receiving non string objects relpath = os.path.relpath(str(path)) path_absolute = os.path.abspath(str(path)) if path_absolute.startswith(os.getcwd()): return relpath if path_absolute.startswith(os.path.expanduser("~")): return path_absolute.replace(os.path.expanduser("~"), "~") # we avoid returning relative paths that end-up at root level if path_absolute in relpath: return path_absolute if relpath.startswith("../"): return path_absolute return relpath # That is needed for compatibility with py38, later was added to Path class def is_relative_to(path: Path, *other: Any) -> bool: """Return True if the path is relative to another path or False.""" try: path.resolve().absolute().relative_to(*other) except ValueError: return False return True def normpath_path(path: str | Path) -> Path: """Normalize a path in order to provide a more consistent output. - Any symlinks are resolved. - Any paths outside the CWD are resolved to their absolute path. - Any absolute path within current user home directory is compressed to make use of '~', so it is easier to read and more portable. """ if not isinstance(path, Path): path = Path(path) is_relative = is_relative_to(path, path.cwd()) path = path.resolve() if is_relative: path = path.relative_to(path.cwd()) # Compress any absolute path within current user home directory if path.is_absolute(): home = Path.home() if is_relative_to(path, home): path = Path("~") / path.relative_to(home) return path @contextmanager def cwd(path: Path) -> Iterator[None]: """Context manager for temporary changing current working directory.""" old_pwd = Path.cwd() os.chdir(path) try: yield finally: os.chdir(old_pwd) def expand_path_vars(path: str) -> str: """Expand the environment or ~ variables in a path string.""" # It may be possible for function to be called with a Path object path = str(path).strip() path = os.path.expanduser(path) path = os.path.expandvars(path) return path def expand_paths_vars(paths: list[str]) -> list[str]: """Expand the environment or ~ variables in a list.""" paths = [expand_path_vars(p) for p in paths] return paths def kind_from_path(path: Path, *, base: bool = False) -> FileType: """Determine the file kind based on its name. When called with base=True, it will return the base file type instead of the explicit one. That is expected to return 'yaml' for any yaml files. """ # pathlib.Path.match patterns are very limited, they do not support *a*.yml # glob.glob supports **/foo.yml but not multiple extensions pathex = wcmatch.pathlib.PurePath(str(path.absolute().resolve())) kinds = options.kinds if not base else BASE_KINDS for entry in kinds: for k, v in entry.items(): if pathex.globmatch( v, flags=( wcmatch.pathlib.GLOBSTAR | wcmatch.pathlib.BRACE | wcmatch.pathlib.DOTGLOB ), ): return str(k) # type: ignore[return-value] if base: # Unknown base file type is default return "" if path.is_dir(): known_role_subfolders = ("tasks", "meta", "vars", "defaults", "handlers") for filename in known_role_subfolders: if (path / filename).is_dir(): return "role" _logger.debug( "Folder `%s` does not look like a role due to missing any of the common subfolders such: %s.", path, ", ".join(known_role_subfolders), ) if str(path) == "/dev/stdin": return "playbook" # Unknown file types report a empty string (evaluated as False) return "" # pylint: disable=too-many-instance-attributes class Lintable: """Defines a file/folder that can be linted. Providing file content when creating the object allow creation of in-memory instances that do not need files to be present on disk. When symlinks are given, they will always be resolved to their target. """ # pylint: disable=too-many-arguments,too-many-positional-arguments def __init__( self, name: str | Path, content: str | None = None, kind: FileType | None = None, base_kind: str = "", parent: Lintable | None = None, ): """Create a Lintable instance.""" self.dir: str = "" self.kind: FileType | None = None self.stop_processing = False # Set to stop other rules from running self.state: Any = States.NOT_LOADED self.line_skips: dict[int, set[str]] = defaultdict(set) self.exc: Exception | None = None # Stores data loading exceptions self.parent = parent self.explicit = False # Indicates if the file was explicitly provided or was indirectly included. self.line_offset = ( 0 # Amount to offset line numbers by to get accurate position ) self.matches: list[MatchError] = [] if isinstance(name, str): name = Path(name) is_relative = is_relative_to(name, str(name.cwd())) name = name.resolve() if is_relative: name = name.relative_to(name.cwd()) name = normpath_path(name) # we need to be sure that we expanduser() because otherwise a simple # test like .path.exists() will return unexpected results. self.path = name.expanduser() # Filename is effective file on disk, for stdin is a namedtempfile self.name = self.filename = str(name) self._content = self._original_content = content self.updated = False # if the lintable is part of a role, we save role folder name self.role = "" parts = self.path.parent.parts if "roles" in parts: role = self.path roles_path = get_app(cached=True).runtime.config.default_roles_path while ( str(role.parent.absolute()) not in roles_path and role.parent.name != "roles" and role.name ): role = role.parent if role.exists(): self.role = role.name if str(self.path) in ["/dev/stdin", "-"]: # pylint: disable=consider-using-with self.file = NamedTemporaryFile( # noqa: SIM115 mode="w+", suffix="playbook.yml", encoding="utf-8", ) self.filename = self.file.name self._content = sys.stdin.read() self.file.write(self._content) self.file.flush() self.path = Path(self.file.name) self.name = "stdin" self.kind = "playbook" self.dir = "/" else: self.kind = kind or kind_from_path(self.path) # We store absolute directory in dir if not self.dir: if self.kind == "role": self.dir = str(self.path.resolve()) else: self.dir = str(self.path.parent.resolve()) # determine base file kind (yaml, xml, ini, ...) self.base_kind = base_kind or kind_from_path(self.path, base=True) self.abspath = self.path.expanduser().absolute() if self.kind == "tasks": self.parent = _guess_parent(self) if self.kind == "yaml": _ = self.data def __del__(self) -> None: """Clean up temporary files when the instance is cleaned up.""" if hasattr(self, "file"): self.file.close() def _guess_kind(self) -> None: if self.kind == "yaml": if ( isinstance(self.data, list) and len(self.data) > 0 and ( "hosts" in self.data[0] or "import_playbook" in self.data[0] or "ansible.builtin.import_playbook" in self.data[0] ) ): if "rules" not in self.data[0]: self.kind = "playbook" else: self.kind = "rulebook" # we we failed to guess the more specific kind, we warn user if self.kind == "yaml": _logger.debug( "Passed '%s' positional argument was identified as generic '%s' file kind.", self.name, self.kind, ) def __getitem__(self, key: Any) -> Any: """Provide compatibility subscriptable support.""" if key == "path": return str(self.path) if key == "type": return str(self.kind) raise NotImplementedError def get(self, key: Any, default: Any = None) -> Any: """Provide compatibility subscriptable support.""" try: return self[key] except NotImplementedError: return default def _populate_content_cache_from_disk(self) -> None: # Can raise UnicodeDecodeError self._content = self.path.expanduser().resolve().read_text(encoding="utf-8") if self._original_content is None: self._original_content = self._content @property def content(self) -> str: """Retrieve file content, from internal cache or disk.""" if self._content is None: self._populate_content_cache_from_disk() return cast("str", self._content) @content.setter def content(self, value: str) -> None: """Update ``content`` and calculate ``updated``. To calculate ``updated`` this will read the file from disk if the cache has not already been populated. """ if not isinstance(value, str): msg = f"Expected str but got {type(value)}" raise TypeError(msg) if self._original_content is None: if self._content is not None: self._original_content = self._content elif self.path.exists(): self._populate_content_cache_from_disk() else: # new file self._original_content = "" self.updated = self._original_content != value self._content = value @content.deleter def content(self) -> None: """Reset the internal content cache.""" self._content = None def write(self, *, force: bool = False) -> None: """Write the value of ``Lintable.content`` to disk. This only writes to disk if the content has been updated (``Lintable.updated``). For example, you can update the content, and then write it to disk like this: .. code:: python lintable.content = new_content lintable.write() Use ``force=True`` when you want to force a content rewrite even if the content has not changed. For example: .. code:: python lintable.write(force=True) """ dump_filename = self.path.expanduser().resolve() if os.environ.get("ANSIBLE_LINT_WRITE_TMP", "0") == "1": dump_filename = dump_filename.with_suffix( f".tmp{dump_filename.suffix}", ) elif not force and not self.updated: # No changes to write. return dump_filename.write_text( self._content or "", encoding="utf-8", ) def __hash__(self) -> int: """Return a hash value of the lintables.""" return hash((self.name, self.kind, self.abspath)) def __eq__(self, other: object) -> bool: """Identify whether the other object represents the same rule match.""" if isinstance(other, Lintable): return bool(self.name == other.name and self.kind == other.kind) return False def __repr__(self) -> str: """Return user friendly representation of a lintable.""" return f"{self.name} ({self.kind})" def is_owned_by_ansible(self) -> bool: """Return true for YAML files that are managed by Ansible.""" return self.kind in ANSIBLE_OWNED_KINDS def failed(self) -> bool: """Return true if we already found syntax-check errors on this file.""" return any( match.rule.id in ("syntax-check", "load-failure", "internal-error") for match in self.matches ) @property def data(self) -> Any: """Return loaded data representation for current file, if possible.""" if self.state == States.NOT_LOADED: if self.path.is_dir(): self.state = None return self.state try: if str(self.base_kind) == "text/yaml": from ansiblelint.utils import ( # pylint: disable=import-outside-toplevel parse_yaml_linenumbers, ) self.state = parse_yaml_linenumbers(self) # now that _data is not empty, we can try guessing if playbook or rulebook # it has to be done before append_skipped_rules() call as it's relying # on self.kind. if self.kind == "yaml": self._guess_kind() # Lazy import to avoid delays and cyclic-imports if "append_skipped_rules" not in globals(): # pylint: disable=import-outside-toplevel from ansiblelint.skip_utils import append_skipped_rules # pylint: disable=possibly-used-before-assignment if self.state: self.state = append_skipped_rules( self.state, self, ) else: _logger.debug( "data set to None for %s due to being '%s' (%s) kind.", self.path, self.kind, self.base_kind or "unknown", ) self.state = States.UNKNOWN_DATA except ( RuntimeError, FileNotFoundError, YAMLError, UnicodeDecodeError, ) as exc: self.state = States.LOAD_FAILED self.exc = exc return self.state # pylint: disable=redefined-outer-name def discover_lintables(options: Options) -> list[str]: """Find all files that we know how to lint. Return format is normalized, relative for stuff below cwd, ~/ for content under current user and absolute for everything else. """ if not options.lintables: options.lintables = ["."] return [ str(filename) for filename in get_all_files( *[Path(s) for s in options.lintables], exclude_paths=options.exclude_paths, ) ] def find_project_root( srcs: Sequence[str], config_file: str | None = None, ) -> tuple[Path, str]: """Return a directory containing .git or ansible-lint config files. That directory will be a common parent of all files and directories passed in `srcs`. If no directory in the tree contains a marker that would specify it's the project root, the root of the file system is returned. Returns a two-tuple with the first element as the project root path and the second element as a string describing the method by which the project root was discovered. """ directory = None if not srcs: srcs = [str(Path.cwd().resolve().absolute())] path_srcs = [Path(Path.cwd(), src).resolve() for src in srcs] cfg_files = [config_file] if config_file else CONFIG_FILENAMES # A list of lists of parents for each 'src'. 'src' is included as a # "parent" of itself if it is a directory src_parents = [ list(path.parents) + ([path] if path.is_dir() else []) for path in path_srcs ] common_base = max( set.intersection(*(set(parents) for parents in src_parents)), key=lambda path: path.parts, ) for directory in (common_base, *common_base.parents): if (directory / ".git").exists(): return directory, ".git directory" if (directory / ".hg").is_dir(): return directory, ".hg directory" for cfg_file in cfg_files: # note that if cfg_file is already absolute, 'directory' is ignored resolved_cfg_path = directory / cfg_file if resolved_cfg_path.is_file(): if os.path.isabs(cfg_file): directory = Path(cfg_file).parent if directory.name == ".config": directory = directory.parent return directory, f"config file {resolved_cfg_path}" if not directory: return Path.cwd(), "current working directory" return directory, "file system root" def expand_dirs_in_lintables(lintables: set[Lintable]) -> None: """Return all recognized lintables within given directory.""" should_expand = False for item in lintables: if item.path.is_dir(): should_expand = True break if should_expand: # this relies on git and we do not want to call unless needed all_files = discover_lintables(options) for item in copy.copy(lintables): if item.path.is_dir(): for filename in all_files: if filename.startswith((str(item.path), str(item.path.absolute()))): lintables.add(Lintable(filename)) def _guess_parent(lintable: Lintable) -> Lintable | None: """Return a parent directory for a lintable.""" try: if lintable.path.parents[2].name == "roles": # role_name = lintable.parents[1].name return Lintable(lintable.path.parents[1], kind="role") except IndexError: pass return None def get_all_files( *paths: Path, exclude_paths: list[str] | None = None, ) -> list[Path]: """Recursively retrieve all files from given folders.""" all_files: list[Path] = [] exclude_paths = [] if exclude_paths is None else exclude_paths def is_excluded(path_to_check: Path) -> bool: """Check if a file is exclude by current specs.""" return any( spec.match_file(pathspec.util.append_dir_sep(path_to_check)) for spec in pathspecs ) for path in paths: pathspecs = [ pathspec.GitIgnoreSpec.from_lines( [ ".ansible", ".git", ".tox", ".mypy_cache", "__pycache__", ".DS_Store", ".coverage", ".pytest_cache", ".ruff_cache", *exclude_paths, ], ), ] gitignore = path / ".gitignore" if gitignore.exists(): with gitignore.open(encoding="UTF-8") as f: _logger.info("Loading ignores from %s", gitignore) pathspecs.append( pathspec.GitIgnoreSpec.from_lines(f.read().splitlines()), ) # Iterate over all items in the directory if path.is_file(): all_files.append(path) else: for item in sorted(path.iterdir()): if is_excluded(item): _logger.debug("Excluded: %s", item) continue if item.is_file(): all_files.append(item) # If it's a directory, recursively call the function elif item.is_dir(): all_files.extend(get_all_files(item, exclude_paths=exclude_paths)) return all_files ansible-ansible-lint-c16f018/src/ansiblelint/formatters/000077500000000000000000000000001477347356000233415ustar00rootroot00000000000000ansible-ansible-lint-c16f018/src/ansiblelint/formatters/__init__.py000066400000000000000000000307231477347356000254570ustar00rootroot00000000000000"""Output formatters.""" from __future__ import annotations import hashlib import json import os from pathlib import Path from typing import TYPE_CHECKING, Any, Generic, TypeVar from ansiblelint.config import options from ansiblelint.version import __version__ if TYPE_CHECKING: from ansiblelint.errors import MatchError from ansiblelint.rules import BaseRule # type: ignore[attr-defined] T = TypeVar("T", bound="BaseFormatter") # type: ignore[type-arg] class BaseFormatter(Generic[T]): """Formatter of ansible-lint output. Base class for output formatters. Args: ---- base_dir (str|Path): reference directory against which display relative path. display_relative_path (bool): whether to show path as relative or absolute """ def __init__(self, base_dir: str | Path, display_relative_path: bool) -> None: """Initialize a BaseFormatter instance.""" if isinstance(base_dir, str): base_dir = Path(base_dir) if base_dir: # can be None base_dir = base_dir.absolute() self.base_dir = base_dir if display_relative_path else None def _format_path(self, path: str | Path) -> str | Path: if not self.base_dir or not path: return path # Use os.path.relpath 'cause Path.relative_to() misbehaves rel_path = os.path.relpath(path, start=self.base_dir) # Avoid returning relative paths that go outside of base_dir if rel_path.startswith(".."): return path return rel_path def apply(self, match: MatchError) -> str: """Format a match error.""" return str(match) @staticmethod def escape(text: str) -> str: """Escapes a string to avoid processing it as markup.""" return text class Formatter(BaseFormatter): # type: ignore[type-arg] """Default output formatter of ansible-lint.""" def apply(self, match: MatchError) -> str: _id = getattr(match.rule, "id", "000") result = f"[{match.level}][link={match.rule.url}]{match.tag}[/link][dim]:[/] [{match.level}]{self.escape(match.message)}[/]" if match.level != "error": result += f" [dim][{match.level}]({match.level})[/]" if match.ignored: result += " [dim]# ignored[/]" result += ( "\n" f"[repr.path]{self._format_path(match.filename or '')}[/]:{match.position}" ) if match.details: result += f" [dim]{self.escape(str(match.details))}[/]" result += "\n" return result class QuietFormatter(BaseFormatter[Any]): """Brief output formatter for ansible-lint.""" def apply(self, match: MatchError) -> str: return ( f"[{match.level}]{match.rule.id}[/] " f"[repr.path]{self._format_path(match.filename or '')}[/]:{match.position}" ) class ParseableFormatter(BaseFormatter[Any]): """Parseable uses PEP8 compatible format.""" def apply(self, match: MatchError) -> str: result = ( f"[repr.path]{self._format_path(match.filename or '')}[/][dim]:{match.position}:[/] " f"[{match.level}][bold]{self.escape(match.tag)}[/]" f"{ f': {match.message}' if not options.quiet else '' }[/]" ) if match.level != "error": result += f" [dim][{match.level}]({match.level})[/][/]" return result class AnnotationsFormatter(BaseFormatter): # type: ignore[type-arg] # https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-warning-message """Formatter for emitting violations as GitHub Workflow Commands. These commands trigger the GHA Workflow runners platform to post violations in a form of GitHub Checks API annotations that appear rendered in pull- request files view. ::debug file={name},line={line},col={col},severity={severity}::{message} ::warning file={name},line={line},col={col},severity={severity}::{message} ::error file={name},line={line},col={col},severity={severity}::{message} Supported levels: debug, warning, error """ def apply(self, match: MatchError) -> str: """Prepare a match instance for reporting as a GitHub Actions annotation.""" file_path = self._format_path(match.filename or "") line_num = match.lineno severity = match.rule.severity violation_details = self.escape(match.message) col = f",col={match.column}" if match.column else "" return ( f"::{match.level} file={file_path},line={line_num}{col},severity={severity},title={match.tag}" f"::{violation_details}" ) class CodeclimateJSONFormatter(BaseFormatter[Any]): """Formatter for emitting violations in Codeclimate JSON report format. The formatter expects a list of MatchError objects and returns a JSON formatted string. The spec for the codeclimate report can be found here: https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#user-content-data-types """ def format_result(self, matches: list[MatchError]) -> str: """Format a list of match errors as a JSON string.""" if not isinstance(matches, list): msg = f"The {self.__class__} was expecting a list of MatchError." raise TypeError(msg) result = [] for match in matches: issue: dict[str, Any] = {} issue["type"] = "issue" issue["check_name"] = match.tag or match.rule.id # rule-id[subrule-id] issue["categories"] = match.rule.tags if match.rule.url: # https://github.com/codeclimate/platform/issues/68 issue["url"] = match.rule.url issue["severity"] = self._remap_severity(match) issue["description"] = self.escape(str(match.message)) issue["fingerprint"] = hashlib.sha256( repr(match).encode("utf-8"), ).hexdigest() issue["location"] = {} issue["location"]["path"] = self._format_path(match.filename or "") if match.column: issue["location"]["positions"] = {} issue["location"]["positions"]["begin"] = {} issue["location"]["positions"]["begin"]["line"] = match.lineno issue["location"]["positions"]["begin"]["column"] = match.column else: issue["location"]["lines"] = {} issue["location"]["lines"]["begin"] = match.lineno if match.details: issue["content"] = {} issue["content"]["body"] = match.details # Append issue to result list result.append(issue) # Keep it single line due to https://github.com/ansible/ansible-navigator/issues/1490 return json.dumps(result, sort_keys=False) @staticmethod def _remap_severity(match: MatchError) -> str: # level is not part of CodeClimate specification, but there is # no other way to expose that info. We recommend switching to # SARIF format which is better suited for interoperability. # # Out current implementation will return `major` for all errors and # `warning` for all warnings. We may revisit this in the future. if match.level == "warning": return "minor" return "major" class SarifFormatter(BaseFormatter[Any]): """Formatter for emitting violations in SARIF report format. The spec of SARIF can be found here: https://docs.oasis-open.org/sarif/sarif/v2.1.0/ """ BASE_URI_ID = "SRCROOT" TOOL_NAME = "ansible-lint" TOOL_URL = "https://github.com/ansible/ansible-lint" SARIF_SCHEMA_VERSION = "2.1.0" SARIF_SCHEMA = ( "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json" ) def format_result(self, matches: list[MatchError]) -> str: """Format a list of match errors as a JSON string.""" if not isinstance(matches, list): msg = f"The {self.__class__} was expecting a list of MatchError." raise TypeError(msg) root_path = Path(str(self.base_dir)).as_uri() root_path = root_path + "/" if not root_path.endswith("/") else root_path rules, results = self._extract_results(matches) tool = { "driver": { "name": self.TOOL_NAME, "version": __version__, "informationUri": self.TOOL_URL, "rules": rules, }, } runs = [ { "tool": tool, "columnKind": "utf16CodeUnits", "results": results, "originalUriBaseIds": { self.BASE_URI_ID: {"uri": root_path}, }, }, ] report = { "$schema": self.SARIF_SCHEMA, "version": self.SARIF_SCHEMA_VERSION, "runs": runs, } # Keep it single line due to https://github.com/ansible/ansible-navigator/issues/1490 return json.dumps(report, sort_keys=False) def _extract_results( self, matches: list[MatchError], ) -> tuple[list[Any], list[Any]]: rules = {} results = [] for match in matches: if match.tag not in rules: rules[match.tag] = self._to_sarif_rule(match) results.append(self._to_sarif_result(match)) return list(rules.values()), results def _to_sarif_rule(self, match: MatchError) -> dict[str, Any]: rule: dict[str, Any] = { "id": match.tag, "name": match.tag, "shortDescription": { "text": str(match.message), }, "defaultConfiguration": { "level": self.get_sarif_rule_severity_level(match.rule), }, "help": { "text": str(match.rule.description), }, "helpUri": match.rule.url, "properties": {"tags": match.rule.tags}, } return rule def _to_sarif_result(self, match: MatchError) -> dict[str, Any]: # https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/sarif-v2.1.0-errata01-os-complete.html#_Toc141790898 if match.level not in ("warning", "error", "note", "none"): msg = "Unexpected failure to map '%s' level to SARIF." raise RuntimeError( msg, match.level, ) result: dict[str, Any] = { "ruleId": match.tag, "level": self.get_sarif_result_severity_level(match), "message": { "text": ( str(match.details) if str(match.details) else str(match.message) ), }, "locations": [ { "physicalLocation": { "artifactLocation": { "uri": self._format_path(match.filename or ""), "uriBaseId": self.BASE_URI_ID, }, "region": { "startLine": match.lineno, }, }, }, ], } if match.column: result["locations"][0]["physicalLocation"]["region"][ "startColumn" ] = match.column return result @staticmethod def get_sarif_rule_severity_level(rule: BaseRule) -> str: """General SARIF severity level for a rule. Note: Can differ from an actual result/match severity. Possible values: "none", "note", "warning", "error" see: https://github.com/oasis-tcs/sarif-spec/blob/123e95847b13fbdd4cbe2120fa5e33355d4a042b/Schemata/sarif-schema-2.1.0.json#L1934-L1939 """ if rule.severity in ["VERY_HIGH", "HIGH"]: return "error" if rule.severity in ["MEDIUM", "LOW", "VERY_LOW"]: return "warning" if rule.severity == "INFO": return "note" return "none" @staticmethod def get_sarif_result_severity_level(match: MatchError) -> str: """SARIF severity level for an actual result/match. Possible values: "none", "note", "warning", "error" see: https://github.com/oasis-tcs/sarif-spec/blob/123e95847b13fbdd4cbe2120fa5e33355d4a042b/Schemata/sarif-schema-2.1.0.json#L2066-L2071 """ if not match.level: return "none" if match.level in ["warning", "error"]: return match.level return "note" ansible-ansible-lint-c16f018/src/ansiblelint/generate_docs.py000066400000000000000000000032251477347356000243310ustar00rootroot00000000000000"""Utils to generate rules documentation.""" from ansiblelint.config import PROFILES from ansiblelint.constants import RULE_DOC_URL from ansiblelint.output import Markdown from ansiblelint.rules import RulesCollection, TransformMixin def rules_as_str(rules: RulesCollection) -> str: """Return rules as string.""" result = "" for rule in rules.alphabetical(): if issubclass(rule.__class__, TransformMixin): rule.tags.insert(0, "autofix") tag = f"{','.join(rule.tags)}" if rule.tags else "" result += f"- [link={RULE_DOC_URL}{rule.id}/]{rule.id}[/link] {rule.shortdesc}\n[dim] tags:{tag}[/]" if rule.version_changed and rule.version_changed != "historic": result += f"[dim] modified:{rule.version_changed}[/]" result += " \n" return result def profiles_as_md(*, docs_url: str = RULE_DOC_URL) -> Markdown: """Return markdown representation of supported profiles.""" result = "" for name, profile in PROFILES.items(): extends = "" if profile.get("extends", None): extends = ( f" It extends [{profile['extends']}](#{profile['extends']}) profile." ) result += f"## {name}\n\n{profile['description']}{extends}\n" for rule, rule_data in profile["rules"].items(): if "[" in rule: url = f"{docs_url}{rule.split('[')[0]}/" else: url = f"{docs_url}{rule}/" if not rule_data: result += f"- [{rule}]({url})\n" else: result += f"- [{rule}]({rule_data['url']})\n" result += "\n" return Markdown(result) ansible-ansible-lint-c16f018/src/ansiblelint/loaders.py000066400000000000000000000044411477347356000231610ustar00rootroot00000000000000"""Utilities for loading various files.""" from __future__ import annotations import logging import os from collections import defaultdict from functools import partial from typing import TYPE_CHECKING, Any, NamedTuple import yaml from yaml import YAMLError try: from yaml import CFullLoader as FullLoader from yaml import CSafeLoader as SafeLoader except (ImportError, AttributeError): # pragma: no cover from yaml import FullLoader, SafeLoader # type: ignore[assignment] if TYPE_CHECKING: from pathlib import Path class IgnoreFile(NamedTuple): """IgnoreFile n.""" default: str alternative: str IGNORE_FILE = IgnoreFile(".ansible-lint-ignore", ".config/ansible-lint-ignore.txt") yaml_load = partial(yaml.load, Loader=FullLoader) yaml_load_safe = partial(yaml.load, Loader=SafeLoader) _logger = logging.getLogger(__name__) def yaml_from_file(filepath: str | Path) -> Any: """Return a loaded YAML file.""" with open(str(filepath), encoding="utf-8") as content: return yaml_load(content) def load_ignore_txt(filepath: Path | None = None) -> dict[str, set[str]]: """Return a list of rules to ignore.""" result = defaultdict(set) ignore_file = None if filepath: if os.path.isfile(filepath): ignore_file = str(filepath) else: _logger.error("Ignore file not found '%s'", ignore_file) elif os.path.isfile(IGNORE_FILE.default): ignore_file = IGNORE_FILE.default elif os.path.isfile(IGNORE_FILE.alternative): ignore_file = IGNORE_FILE.alternative if ignore_file: with open(ignore_file, encoding="utf-8") as _ignore_file: _logger.debug("Loading ignores from '%s'", ignore_file) for line in _ignore_file: entry = line.split("#")[0].rstrip() if entry: try: path, rule = entry.split() except ValueError as exc: # pragma: no cover msg = f"Unable to parse line '{line}' from {ignore_file} file." raise RuntimeError(msg) from exc result[path].add(rule) return result __all__ = [ "IGNORE_FILE", "YAMLError", "load_ignore_txt", "yaml_from_file", "yaml_load", "yaml_load_safe", ] ansible-ansible-lint-c16f018/src/ansiblelint/logger.py000066400000000000000000000010031477347356000227760ustar00rootroot00000000000000"""Utils related to logging.""" import logging import time from collections.abc import Iterator from contextlib import contextmanager from typing import Any _logger = logging.getLogger(__name__) @contextmanager def timed_info(msg: Any, *args: Any) -> Iterator[None]: """Context manager for logging slow operations, mentions duration.""" start = time.time() try: yield finally: elapsed = time.time() - start _logger.info(msg + " (%.2fs)", *(*args, elapsed)) # noqa: G003 ansible-ansible-lint-c16f018/src/ansiblelint/output.py000066400000000000000000000304711477347356000230720ustar00rootroot00000000000000"""Console support: coloring and terminal code.""" # cspell: ignore mdcat, mdless, bbcode, noteset from __future__ import annotations import dataclasses import os import re import shutil import subprocess import sys # WARNING: When making style changes, be sure you test the output of # `ansible-lint -L` on multiple terminals with dark/light themes, including: # - iTerm2 (macOS) - bold might not be rendered differently # - vscode integrated terminal - bold might not be rendered differently, links will not work # # When it comes to colors being used, try to match: # - Ansible official documentation theme, https://docs.ansible.com/ansible/latest/dev_guide/developing_api.html # - VSCode Ansible extension for syntax highlighting # - GitHub markdown theme # # Current values: (docs) # codeblock border: #404040 # codeblock background: #edf0f2 # codeblock comment: #6a737d (also italic) # teletype-text: #e74c3c (red) # teletype-text-border: 1px solid #e1e4e5 (background white) # text: #404040 # codeblock other-text: #555555 (black-ish) # codeblock property: #22863a (green) # codeblock integer: 032f62 (blue) # codeblock command: #0086b3 (blue) - [shell] # == python == # class: #445588 (dark blue and bold) # docstring: #dd1144 (red) # self: #999999 (light-gray) # method/function: #990000 (dark-red) # number: #009999 cyan # keywords (def,None,False,len,from,import): #007020 (green) bold # super|dict|print: #0086b3 light-blue # __name__: #bb60d5 (magenta) # string: #dd1144 (light-red) # See: https://github.com/ansible/ansible-dev-environment/blob/main/src/ansible_dev_environment/output.py from collections import UserString from collections.abc import Callable from dataclasses import dataclass from io import StringIO from typing import Any, TextIO from ansiblelint.logger import _logger md_cmd: str | None = None md_renderers = { "mdcat": ["mdcat"], # (rust) "rich-cli": ["rich-cli", "--markdown"], # (python) "glow": ["glow"], # nice output but hyperlinks are exploded (go) "mdless": [ "mdless", "--autolink", "--no-pager", ], # ugly heading, no hyperlinks (ruby) } _styles = ( "dim", "b", # logging "notset", "debug", "info", "warning", "error", "critical", # results "failed", "success", # reset "normal", # data types "number", "path", ) RE_BB_LINK_PATTERN = re.compile( r"\[link=([^\]]+)\]((?:[^\[]|\[(?!\/link\]))+)\[/link\]" ) # Based on Ansible implementation def to_bool(value: Any) -> bool: # pragma: no cover """Return a bool for the arg.""" if value is None or isinstance(value, bool): return bool(value) if isinstance(value, str): value = value.lower() return value in ("yes", "on", "1", "true", 1) def should_do_markup(stream: TextIO = sys.stdout) -> bool: # pragma: no cover """Decide about use of ANSI colors.""" py_colors = None # https://xkcd.com/927/ for env_var in ["PY_COLORS", "CLICOLOR", "FORCE_COLOR", "ANSIBLE_FORCE_COLOR"]: value = os.environ.get(env_var, None) if value is not None: py_colors = to_bool(value) break # If deliberately disabled colors if os.environ.get("NO_COLOR", None): return False # User configuration requested colors if py_colors is not None: return to_bool(py_colors) term = os.environ.get("TERM", "") if "xterm" in term: return True if term == "dumb": return False # Use tty detection logic as last resort because there are numerous # factors that can make isatty return a misleading value, including: # - stdin.isatty() is the only one returning true, even on a real terminal # - stderr returning false if user user uses a error stream coloring solution return stream.isatty() @dataclasses.dataclass class PlainStyle: """Theme.""" failed = "" success = "" normal = "" dim = "" bold = "" # logging notset = "" debug = "" info = "" warning = "" error = "" critical = "" # data types number = "" path = "" link = "" @classmethod def render_link(cls, uri: str, label: str | None = None) -> str: """Return a link.""" return label or uri @dataclasses.dataclass class AnsiStyle(PlainStyle): """Theme.""" @dataclass class ANSI: """Color constants.""" BLACK = "\033[30m" RED = "\033[31m" GREEN = "\033[32m" YELLOW = "\033[33m" BLUE = "\033[34m" MAGENTA = "\033[35m" CYAN = "\033[36m" WHITE = "\033[37m" GREY = "\033[90m" # Bright black? BRIGHT_RED = "\033[91m" BRIGHT_GREEN = "\033[92m" BRIGHT_YELLOW = "\033[93m" BRIGHT_BLUE = "\033[94m" BRIGHT_MAGENTA = "\033[95m" BRIGHT_CYAN = "\033[96m" BRIGHT_WHITE = "\033[97m" END = "\033[0m" # more complex BOLD = "\033[1m" DIM = "\033[2m" BOLD_CYAN = "\033[1;36m" warning = "\033[33m" # yellow error = ANSI.RED # "\033[31m" # red info = ANSI.BLUE debug = ANSI.BLUE notset = ANSI.BLUE failed = ANSI.RED success = ANSI.GREEN normal = ANSI.END dim = ANSI.DIM bold = ANSI.BOLD # data types number = ANSI.BOLD_CYAN path = ANSI.MAGENTA # do not use same color as link link = ANSI.BLUE @classmethod def render_link(cls, uri: str, label: str | None = None) -> str: """Return a link.""" if label is None: label = uri parameters = "" # OSC 8 ; params ; URI ST OSC 8 ;; ST escape_mask = "\033]8;{};{}\033\\{}\033]8;;\033\\" return cls.link + escape_mask.format(parameters, uri, label) + cls.normal class Markdown(UserString): """Markdown string.""" def display(self) -> None: """Display markdown text in the terminal using an external renderer if available.""" global md_cmd # pylint: disable=global-statement if md_cmd is None: for v in md_renderers: if shutil.which(v): md_cmd = v break if not md_cmd: msg = f"No know markdown renderer found ({', '.join(md_renderers)}), output as plain text." _logger.warning(msg) md_cmd = "" else: msg = f"Using markdown renderer: {md_cmd}" _logger.info(msg) if md_cmd: subprocess.run( # noqa: S603 md_renderers[md_cmd], input=self.data, text=True, check=False, ) else: console.print(self.data) color: bool = True # https://peps.python.org/pep-3101/ __all__ = ("Console", "color") class Console: """Console.""" colored: bool = True style: type[PlainStyle] = AnsiStyle # Regex to find opening tags and their content tag_pattern = re.compile(r"\[([\w\.]+)(?:=(.*?))?\]|\[/\]") def __init__(self, file: TextIO | None = sys.stdout): """Console constructor.""" self._file = file def print( self, *values: Any, sep: str | None = " ", end: str | None = "\n", file: TextIO | None = None, flush: bool = False, ) -> None: """Internal print implementation.""" buffer = StringIO() print(*values, sep=sep, end="", file=buffer, flush=True) buffer.seek(0) data = buffer.read() print(self.render(data), end=end, file=file or self._file, flush=flush) def render(self, text: str) -> str: """Parses a string containing nested BBCode with a generic block terminator ([/]).""" style: type[PlainStyle] = AnsiStyle if self.colored else PlainStyle # Define bbcode-to-ansi mappings bbcode_to_ansi = { "bold": (style.bold, style.normal), "dim": (style.dim, style.normal), # logging "warning": (style.warning, style.normal), "error": (style.error, style.normal), "info": (style.info, style.normal), "debug": (style.debug, style.normal), "noteset": (style.notset, style.normal), # data types "repr.path": (style.path, style.normal), "repr.number": (style.number, style.normal), "repr.link": (style.link, style.normal), "failed": (style.failed, style.normal), "success": (style.success, style.normal), } def replace_bb_links(text: str) -> str: """Replaces BBCode-style links ([link=url]title[/link]) with HTML tags. Args: text (str): The input text containing BBCode links. Returns: str: The text with BBCode links replaced by HTML tags. """ # Replace matches with HTML tags def replacement(match: re.Match[str]) -> str: url = match.group(1) # The URL part from [link=url] title = match.group(2) return style.render_link(url, title) result = RE_BB_LINK_PATTERN.sub(replacement, text) return result def replace_bb_tags(text: str) -> str: """Processes the text with a stack-based approach to handle nested tags.""" # Incomplete implementation as it does not track full ANSI behavior # and only remembers to reset the style when tags ends. stack = [] # Stack to keep track of open tags result = [] # Result list to build the output HTML pos = 0 # Current position in the text for match in self.tag_pattern.finditer(text): start, end = match.span() tag = match.group(1) param = match.group(2) # Add plain text before this tag result.append(text[pos:start]) pos = end if tag: # Opening tag if tag in bbcode_to_ansi: # Push tag and param onto the stack stack.append((tag, param)) opening, _ = bbcode_to_ansi[tag] if param: opening = opening.replace("{param}", param) result.append(opening) else: # Preserve unknown tags as-is result.append(match.group(0)) stack.append(("unknown", None)) # Track unknown tags else: # Closing tag ([/]) if stack: open_tag, _ = stack.pop() if open_tag in bbcode_to_ansi: _, closing = bbcode_to_ansi[open_tag] result.append(closing) else: # Preserve unmatched closing tag for unknown tags result.append("[/]") else: # Preserve unmatched closing tags result.append("[/]") # Add remaining plain text after the last tag result.append(text[pos:]) # Close any unclosed tags while stack: open_tag, _ = stack.pop() if open_tag != "unknown": _, closing = bbcode_to_ansi[open_tag] result.append(closing) return "".join(result) return replace_bb_links(replace_bb_tags(text)) console = Console() console_stderr = Console(file=sys.stderr) def reconfigure(colored: bool | None = None) -> None: """Reconfigure console options.""" if colored is not None: console.colored = colored console_stderr.colored = colored def render_yaml(text: str) -> str: """Colorize YAMl for nice display.""" return text _ReStringMatch = re.Match[str] # regex match object _ReSubCallable = Callable[[_ReStringMatch], str] # Callable invoked by re.sub _EscapeSubMethod = Callable[[_ReSubCallable, str, int], str] if __name__ == "__main__": console.print("foo [bold]bold[/] [repr.number]123[/] [repr.path]/dev/null[/]") console.print("foo [dim]dimmed[/]") console.print("foo [error]dimmed[/] [link=https://google.com]google.com[/link]") console.print("foo [error]dimmed[/] [link=https://google.com]name[casing][/link]") ansible-ansible-lint-c16f018/src/ansiblelint/py.typed000066400000000000000000000000001477347356000226400ustar00rootroot00000000000000ansible-ansible-lint-c16f018/src/ansiblelint/requirements.py000066400000000000000000000017621477347356000242560ustar00rootroot00000000000000"""Utilities for checking python packages requirements.""" import importlib_metadata from packaging.requirements import Requirement from packaging.specifiers import SpecifierSet from packaging.version import Version class Reqs(dict[str, SpecifierSet]): """Utility class for working with package dependencies.""" reqs: dict[str, SpecifierSet] def __init__(self, name: str = "ansible-lint") -> None: """Load linter metadata requirements.""" for req_str in importlib_metadata.metadata(name).json["requires_dist"]: req = Requirement(req_str) if req.name: self[req.name] = req.specifier def matches(self, req_name: str, req_version: str | Version) -> bool: """Verify if given version is matching current metadata dependencies.""" if req_name not in self: return False return all( specifier.contains(str(req_version), prereleases=True) for specifier in self[req_name] ) ansible-ansible-lint-c16f018/src/ansiblelint/rules/000077500000000000000000000000001477347356000223055ustar00rootroot00000000000000ansible-ansible-lint-c16f018/src/ansiblelint/rules/__init__.py000066400000000000000000000531121477347356000244200ustar00rootroot00000000000000"""All internal ansible-lint rules.""" from __future__ import annotations import copy import inspect import logging import re import sys from collections import defaultdict from collections.abc import Iterable, Iterator, MutableMapping, MutableSequence from importlib import import_module from pathlib import Path from typing import TYPE_CHECKING, Any, cast import ansiblelint.skip_utils import ansiblelint.utils import ansiblelint.yaml_utils from ansiblelint._internal.rules import ( AnsibleParserErrorRule, BaseRule, LoadingFailureRule, RuntimeErrorRule, WarningRule, ) from ansiblelint.app import App, get_app from ansiblelint.config import PROFILES, Options from ansiblelint.config import options as default_options from ansiblelint.constants import RULE_DOC_URL, SKIPPED_RULES_KEY from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable, expand_paths_vars if TYPE_CHECKING: from ruamel.yaml.comments import CommentedMap, CommentedSeq from ansiblelint.errors import RuleMatchTransformMeta _logger = logging.getLogger(__name__) match_types = { "matchlines": "line", "match": "line", # called by matchlines "matchtasks": "task", "matchtask": "task", # called by matchtasks "matchyaml": "yaml", "matchplay": "play", # called by matchyaml "matchdir": "dir", } RE_JINJA_EXPRESSION = re.compile(r"{{.+?}}") RE_JINJA_STATEMENT = re.compile(r"{%.+?%}") RE_JINJA_COMMENT = re.compile(r"{#.+?#}") class AnsibleLintRule(BaseRule): """AnsibleLintRule should be used as base for writing new rules.""" @property def url(self) -> str: """Return rule documentation url.""" return RULE_DOC_URL + self.id + "/" def get_config(self, key: str) -> Any: """Return a configured value for given key string.""" return self.rule_config.get(key, None) @staticmethod def unjinja(text: str) -> str: """Remove jinja2 bits from a string.""" text = RE_JINJA_EXPRESSION.sub("JINJA_EXPRESSION", text) text = RE_JINJA_STATEMENT.sub("JINJA_STATEMENT", text) text = RE_JINJA_COMMENT.sub("JINJA_COMMENT", text) return text # pylint: disable=too-many-arguments,too-many-positional-arguments def create_matcherror( self, message: str = "", lineno: int = 1, column: int | None = None, details: str = "", filename: Lintable | None = None, tag: str = "", transform_meta: RuleMatchTransformMeta | None = None, data: Any | None = None, ) -> MatchError: """Instantiate a new MatchError.""" if data is not None and lineno == 1 and column is None: lineno, column = ansiblelint.yaml_utils.get_line_column( data, default_line=lineno ) match = MatchError( message=message, lineno=lineno, column=column, details=details, lintable=filename or Lintable(""), rule=copy.copy(self), tag=tag, transform_meta=transform_meta, ) # search through callers to find one of the match* methods frame = inspect.currentframe() match_type: str | None = None while not match_type and frame is not None: func_name = frame.f_code.co_name match_type = match_types.get(func_name) if match_type: # add the match_type to the match match.match_type = match_type break frame = frame.f_back # get the parent frame for the next iteration return match @staticmethod def _enrich_matcherror_with_task_details( match: MatchError, task: ansiblelint.utils.Task, ) -> None: match.task = task if not match.details: match.details = "Task/Handler: " + str(task) match.lineno = max(match.lineno, task.line) def matchlines(self, file: Lintable) -> list[MatchError]: matches: list[MatchError] = [] # arrays are 0-based, line numbers are 1-based # so use prev_line_no as the counter for prev_line_no, line in enumerate(file.content.split("\n")): if line.lstrip().startswith("#"): continue rule_id_list = ansiblelint.skip_utils.get_rule_skips_from_line( line, lintable=file, ) if self.id in rule_id_list: continue result = self.match(line) if not result: continue message = "" if isinstance(result, str): message = result matcherror = self.create_matcherror( message=message, lineno=prev_line_no + 1, details=line, filename=file, ) matches.append(matcherror) return matches def matchtasks(self, file: Lintable) -> list[MatchError]: """Call matchtask for each task inside file and return aggregate results. Most rules will never need to override matchtasks because its main purpose is to call matchtask for each task/handlers in the same file, and to aggregate the results. """ matches: list[MatchError] = [] if ( file.kind not in ["handlers", "tasks", "playbook"] or str(file.base_kind) != "text/yaml" ): return matches for task in ansiblelint.utils.task_in_list( data=file.data, kind=file.kind, file=file, ): if task.error is not None: # normalize_task converts AnsibleParserError to MatchError return [task.error] if ( self.id in task.skip_tags or ("action" not in task.normalized_task) or "skip_ansible_lint" in task.normalized_task.get("tags", []) ): continue if self.needs_raw_task: task.normalized_task["__raw_task__"] = task.raw_task result = self.matchtask(task, file=file) if not result: continue if isinstance(result, Iterable) and not isinstance( result, str, ): # list[MatchError] # https://github.com/PyCQA/pylint/issues/6044 # pylint: disable=not-an-iterable for match in result: if match.tag in task.skip_tags: continue self._enrich_matcherror_with_task_details( match, task, ) matches.append(match) continue if isinstance(result, MatchError): if result.tag in task.skip_tags: continue match = result else: # bool or string message = "" if isinstance(result, str): message = result match = self.create_matcherror( message=message, lineno=task.line, filename=file, ) self._enrich_matcherror_with_task_details(match, task) matches.append(match) return matches def matchyaml(self, file: Lintable) -> list[MatchError]: matches: list[MatchError] = [] if str(file.base_kind) != "text/yaml": return matches yaml = file.data # yaml returned can be an AnsibleUnicode (a string) when the yaml # file contains a single string. YAML spec allows this but we consider # this an fatal error. if isinstance(yaml, str): if yaml.startswith("$ANSIBLE_VAULT"): return [] if self._collection is None: # pragma: no cover msg = f"Rule {self.id} was not added to a collection." raise RuntimeError(msg) return [ # pylint: disable=E1136 MatchError( lintable=file, rule=self._collection["load-failure"], ), ] if not yaml: return matches if isinstance(yaml, dict): yaml = [yaml] for play in yaml: # Bug #849 and #4492 if play is None or not hasattr(play, "get"): continue if self.id in play.get(SKIPPED_RULES_KEY, ()): continue if "skip_ansible_lint" in play.get("tags", []): continue matches.extend(self.matchplay(file, play)) return matches class TransformMixin: """A mixin for AnsibleLintRule to enable transforming files. If ansible-lint is started with the ``--fix`` option, then the ``Transformer`` will call the ``transform()`` method for every MatchError identified if the rule that identified it subclasses this ``TransformMixin``. Only the rule that identified a MatchError can do transforms to fix that match. """ def transform( self, match: MatchError, lintable: Lintable, data: CommentedMap | CommentedSeq | str, ) -> None: """Transform ``data`` to try to fix the MatchError identified by this rule. The ``match`` was generated by this rule in the ``lintable`` file. When ``transform()`` is called on a rule, the rule should either fix the issue, if possible, or make modifications that make it easier to fix manually. The transform must set ``match.fixed = True`` when data has been transformed to fix the error. For YAML files, ``data`` is an editable YAML dict/array that preserves any comments that were in the original file. .. code:: python data[0]["tasks"][0]["when"] = False This is easier with the ``seek()`` utility method: .. code :: python target_task = self.seek(match.yaml_path, data) target_task["when"] = False For any files that aren't YAML, ``data`` is the loaded file's content as a string. To edit non-YAML files, save the updated contents in ``lintable.content``: .. code:: python new_data = self.do_something_to_fix_the_match(data) lintable.content = new_data """ @staticmethod def seek( yaml_path: list[int | str], data: MutableMapping[str, Any] | MutableSequence[Any] | str, ) -> Any: """Get the element identified by ``yaml_path`` in ``data``. Rules that work with YAML need to seek, or descend, into nested YAML data structures to perform the relevant transforms. For example: .. code:: python def transform(self, match, lintable, data): target_task = self.seek(match.yaml_path, data) # transform target_task """ if isinstance(data, str): # can't descend into a string return data target = data for segment in yaml_path: # The cast() calls tell mypy what types we expect. # Essentially this does: if isinstance(segment, str): target = cast("MutableMapping[str, Any]", target)[segment] elif isinstance(segment, int): target = cast("MutableSequence[Any]", target)[segment] return target def load_plugins( dirs: list[str], ) -> Iterator[AnsibleLintRule]: """Yield a rule class.""" def all_subclasses(cls: type) -> set[type]: return set(cls.__subclasses__()).union( [s for c in cls.__subclasses__() for s in all_subclasses(c)], ) orig_sys_path = sys.path.copy() for directory in dirs: if directory not in sys.path: sys.path.append(str(directory)) # load all modules in the directory for f in Path(directory).glob("*.py"): if "__" not in f.stem and f.stem not in "conftest": import_module(f"{f.stem}") # restore sys.path sys.path = orig_sys_path rules: dict[str, BaseRule] = {} for rule in all_subclasses(BaseRule): # we do not return the rules that are not loaded from passed 'directory' # or rules that do not have a valid id. For example, during testing # python may load other rule classes, some outside the tested rule # directories. if ( rule.id # type: ignore[attr-defined] and Path(inspect.getfile(rule)).parent.absolute() in [Path(x).absolute() for x in dirs] and issubclass(rule, BaseRule) and rule.id not in rules ): rules[rule.id] = rule() for rule in rules.values(): # type: ignore[assignment] if isinstance(rule, AnsibleLintRule) and bool(rule.id): yield rule class RulesCollection: """Container for a collection of rules.""" def __init__( # pylint: disable=too-many-arguments self, rulesdirs: list[str] | list[Path] | None = None, options: Options | None = None, profile_name: str | None = None, *, conditional: bool = True, app: App | None = None, ) -> None: """Initialize a RulesCollection instance.""" if options is None: self.options = copy.deepcopy(default_options) # When initialized without options argument we want it to always # be offline as this is done only during testing. self.options.offline = True else: self.options = options self.profile = [] # app should be defined on normal run logic, but for testing we might # not pass it, and in this case we assume offline mode for performance # reasons. self.app = app or get_app(offline=True) if profile_name: self.profile = PROFILES[profile_name] rulesdirs_str = [] if rulesdirs is None else [str(r) for r in rulesdirs] self.rulesdirs = expand_paths_vars(rulesdirs_str) self.rules: list[BaseRule] = [] # internal rules included in order to expose them for docs as they are # not directly loaded by our rule loader. self.rules.extend( [ RuntimeErrorRule(), AnsibleParserErrorRule(), LoadingFailureRule(), WarningRule(), ], ) for rule in self.rules: rule._collection = self # noqa: SLF001 for rule in load_plugins(rulesdirs_str): self.register(rule, conditional=conditional) self.rules = sorted(self.rules) # When we have a profile we unload some of the rules # But we do include all rules when listing all rules or tags if profile_name and not (self.options.list_rules or self.options.list_tags): filter_rules_with_profile(self.rules, profile_name) def register(self, obj: AnsibleLintRule, *, conditional: bool = False) -> None: """Register a rule.""" # We skip opt-in rules which were not manually enabled. # But we do include opt-in rules when listing all rules or tags obj._collection = self # pylint: disable=protected-access # noqa: SLF001 if any( [ not conditional, self.profile, # when profile is used we load all rules and filter later "opt-in" not in obj.tags, obj.id in self.options.enable_list, self.options.list_rules, self.options.list_tags, ], ): self.rules.append(obj) def __iter__(self) -> Iterator[BaseRule]: """Return the iterator over the rules in the RulesCollection.""" return iter(sorted(self.rules)) def alphabetical(self) -> Iterator[BaseRule]: """Return an iterator over the rules in the RulesCollection in alphabetical order.""" return iter(sorted(self.rules, key=lambda x: x.id)) def __len__(self) -> int: """Return the length of the RulesCollection data.""" return len(self.rules) def __getitem__(self, item: Any) -> BaseRule: """Return a rule from inside the collection based on its id.""" if not isinstance(item, str): msg = f"Expected str but got {type(item)} when trying to access rule by it's id" raise TypeError(msg) for rule in self.rules: if rule.id == item: return rule msg = f"Rule {item} is not present inside this collection." raise ValueError(msg) def run( self, file: Lintable, tags: set[str] | None = None, skip_list: list[str] | None = None, ) -> list[MatchError]: """Run all the rules against the given lintable.""" matches: list[MatchError] = [] if tags is None: tags = set() if skip_list is None: skip_list = [] if not file.path.is_dir(): try: if file.content is not None: # loads the file content pass except (OSError, UnicodeDecodeError) as exc: return [ MatchError( message=str(exc), lintable=file, rule=self["load-failure"], tag=f"{LoadingFailureRule.id}[{exc.__class__.__name__.lower()}]", ), ] for rule in self.rules: if rule.id == "syntax-check": continue if ( not tags or rule.has_dynamic_tags or not set(rule.tags).union([rule.id]).isdisjoint(tags) ): if tags and set(rule.tags).union(list(rule.ids().keys())).isdisjoint( tags, ): _logger.debug("Skipping rule %s", rule.id) else: _logger.debug("Running rule %s", rule.id) rule_definition = set(rule.tags) rule_definition.add(rule.id) if set(rule_definition).isdisjoint(skip_list): matches.extend(rule.getmatches(file)) else: _logger.debug("Skipping rule %s", rule.id) # some rules can produce matches with tags that are inside our # skip_list, so we need to cleanse the matches matches = [m for m in matches if m.tag not in skip_list] return matches def known_tags(self) -> list[str]: """Return a list of known tags, without returning no sub-tags.""" tags = set() for rule in self.rules: tags.add(rule.id) tags.update(rule.tags) return sorted(tags) def list_tags(self) -> str: """Return a string with all the tags in the RulesCollection.""" tag_desc = { "command-shell": "Specific to use of command and shell modules", "core": "Related to internal implementation of the linter", "deprecations": "Indicate use of features that are removed from Ansible", "experimental": "Newly introduced rules, by default triggering only warnings", "formatting": "Related to code-style", "idempotency": "Possible indication that consequent runs would produce different results", "idiom": "Anti-pattern detected, likely to cause undesired behavior", "metadata": "Invalid metadata, likely related to galaxy, collections or roles", "opt-in": "Rules that are not used unless manually added to `enable_list`", "security": "Rules related o potentially security issues, like exposing credentials", "syntax": "Related to wrong or deprecated syntax", "unpredictability": "Warn about code that might not work in a predictable way", "unskippable": "Indicate a fatal error that cannot be ignored or disabled", "yaml": "External linter which will also produce its own rule codes", } tags = defaultdict(list) for rule in self.rules: # Fail early if a rule does not have any of our required tags if not set(rule.tags).intersection(tag_desc.keys()): # pragma: no cover msg = f"Rule {rule} does not have any of the required tags: {', '.join(tag_desc.keys())}" raise RuntimeError(msg) for tag in rule.tags: tags[tag] = list(rule.ids()) result = "# List of tags and rules they cover\n" for tag in sorted(tags): desc = tag_desc.get(tag) if desc: result += f"{tag}: # {desc}\n" else: result += f"{tag}:\n" for name in sorted(tags[tag]): result += f" - {name}\n" return result def filter_rules_with_profile(rule_col: list[BaseRule], profile: str) -> None: """Unload rules that are not part of the specified profile.""" included = set() extends = profile total_rules = len(rule_col) while extends: for rule in PROFILES[extends]["rules"]: _logger.debug("Activating rule `%s` due to profile `%s`", rule, extends) included.add(rule) extends = PROFILES[extends].get("extends", None) for rule in rule_col.copy(): if rule.unloadable: continue if rule.id not in included: _logger.debug( "Unloading %s rule due to not being part of %s profile.", rule.id, profile, ) rule_col.remove(rule) _logger.debug("%s/%s rules included in the profile", len(rule_col), total_rules) ansible-ansible-lint-c16f018/src/ansiblelint/rules/args.md000066400000000000000000000053371477347356000235730ustar00rootroot00000000000000# args This rule validates if the task arguments conform with the plugin documentation. The rule validation will check if the option name is valid and has the correct value along with conditionals on the options like `mutually_exclusive`, `required_together`, `required_one_of` and so on. For more information see the [argument spec validator](https://docs.ansible.com/ansible/latest/reference_appendices/module_utils.html#argumentspecvalidator) topic in the Ansible module utility documentation. Possible messages: - `args[module]` - missing required arguments: ... - `args[module]` - missing parameter(s) required by ... ## Problematic Code ```yaml --- - name: Fixture to validate module options failure scenarios hosts: localhost tasks: - name: Clone content repository ansible.builtin.git: # <- Required option `repo` is missing. dest: /home/www accept_hostkey: true version: master update: false - name: Enable service httpd and ensure it is not masked ansible.builtin.systemd: # <- Missing 'name' parameter required by 'enabled'. enabled: true masked: false - name: Use quiet to avoid verbose output ansible.builtin.assert: test: - my_param <= 100 - my_param >= 0 quiet: invalid # <- Value for option `quiet` is invalid. ``` ## Correct Code ```yaml --- - name: Fixture to validate module options pass scenario hosts: localhost tasks: - name: Clone content repository ansible.builtin.git: # <- Contains required option `repo`. repo: https://github.com/ansible/ansible-examples dest: /home/www accept_hostkey: true version: master update: false - name: Enable service httpd and ensure it is not masked ansible.builtin.systemd: # <- Contains 'name' parameter required by 'enabled'. name: httpd enabled: false masked: false - name: Use quiet to avoid verbose output ansible.builtin.assert: that: - my_param <= 100 - my_param >= 0 quiet: True # <- Has correct type value for option `quiet` which is boolean. ``` ## Special cases In some complex cases where you are using jinja expressions, the linter may not able to fully validate all the possible values and report a false positive. The example below would usually report `parameters are mutually exclusive: data|file|keyserver|url` but because we added `# noqa: args[module]` it will just pass. ```yaml - name: Add apt keys # noqa: args[module] become: true ansible.builtin.apt_key: url: "{{ zj_item['url'] | default(omit) }}" data: "{{ zj_item['data'] | default(omit) }}" loop: "{{ repositories_keys }}" loop_control: loop_var: zj_item ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/args.py000066400000000000000000000276441477347356000236300ustar00rootroot00000000000000"""Rule definition to validate task options.""" from __future__ import annotations import contextlib import importlib.util import io import json import logging import re import sys from typing import TYPE_CHECKING, Any # pylint: disable=preferred-module from unittest import mock from unittest.mock import patch # pylint: disable=reimported import ansible.module_utils.basic as mock_ansible_module from ansible.module_utils import basic from ansiblelint.rules import AnsibleLintRule, RulesCollection from ansiblelint.text import has_jinja from ansiblelint.utils import load_plugin from ansiblelint.yaml_utils import clean_json if TYPE_CHECKING: from ansible.plugins.loader import PluginLoadContext from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task _logger = logging.getLogger(__name__) ignored_re = re.compile( "|".join( # noqa: FLY002 [ r"^parameters are mutually exclusive:", # https://github.com/ansible/ansible-lint/issues/3128 as strings can be jinja # Do not remove unless you manually test if the original example # from the bug does not trigger the rule anymore. We were not able # to add a regression test because it would involve installing this # collection. Attempts to reproduce same bug with other collections # failed, even if the message originates from Ansible core. r"^unable to evaluate string as dictionary$", ], ), flags=re.MULTILINE | re.DOTALL, ) workarounds_drop_map = { # https://github.com/ansible/ansible-lint/issues/3110 "ansible.builtin.copy": ["decrypt"], # https://github.com/ansible/ansible-lint/issues/2824#issuecomment-1354337466 # https://github.com/ansible/ansible-lint/issues/3138 "ansible.builtin.service": ["daemon_reload", "use"], # Avoid: Unsupported parameters for (basic.py) module: cmd. Supported parameters include: _raw_params, _uses_shell, argv, chdir, creates, executable, removes, stdin, stdin_add_newline, strip_empty_ends. "ansible.builtin.command": ["cmd"], # https://github.com/ansible/ansible-lint/issues/3152 "ansible.posix.synchronize": ["use_ssh_args"], } workarounds_inject_map = { # https://github.com/ansible/ansible-lint/issues/2824 "ansible.builtin.async_status": {"_async_dir": "/tmp/ansible-async"}, } class ValidationPassedError(Exception): """Exception to be raised when validation passes.""" class CustomAnsibleModule(basic.AnsibleModule): """Mock AnsibleModule class.""" def __init__(self, *args: Any, **kwargs: Any) -> None: """Initialize AnsibleModule mock.""" kwargs["no_log"] = True super().__init__(*args, **kwargs) # type: ignore[no-untyped-call] raise ValidationPassedError class ArgsRule(AnsibleLintRule): """Validating module arguments.""" id = "args" severity = "HIGH" description = "Check whether tasks are using correct module options." tags = ["syntax", "experimental"] version_changed = "6.10.0" module_aliases: dict[str, str] = {"block/always/rescue": "block/always/rescue"} _ids = { "args[module]": description, } RE_PATTERN = re.compile(r"(argument|option) '(?P.*)' is of type") RE_VALUE_OF = re.compile(r"value of (?P.*) must be one of:") def matchtask( self, task: Task, file: Lintable | None = None, ) -> list[MatchError]: # pylint: disable=too-many-return-statements results: list[MatchError] = [] module_name = task["action"]["__ansible_module_original__"] failed_msg = None if module_name in self.module_aliases: return [] loaded_module: PluginLoadContext = load_plugin(module_name) # https://github.com/ansible/ansible-lint/issues/3200 # since "ps1" modules cannot be executed on POSIX platforms, we will # avoid running this rule for such modules if isinstance( loaded_module.plugin_resolved_path, str, ) and loaded_module.plugin_resolved_path.endswith(".ps1"): return [] module_args = { key: value for key, value in task["action"].items() if not key.startswith("__") } # Return if 'args' is jinja string # https://github.com/ansible/ansible-lint/issues/3199 if ( "args" in task.raw_task and isinstance(task.raw_task["args"], str) and has_jinja(task.raw_task["args"]) ): return [] if loaded_module.resolved_fqcn in workarounds_inject_map: module_args.update(workarounds_inject_map[loaded_module.resolved_fqcn]) if loaded_module.resolved_fqcn in workarounds_drop_map: for key in workarounds_drop_map[loaded_module.resolved_fqcn]: module_args.pop(key, None) with mock.patch.object( mock_ansible_module, "AnsibleModule", CustomAnsibleModule, ): if not loaded_module.plugin_resolved_name: _logger.warning( "Unable to load module %s at %s:%s for options validation", module_name, file.filename if file else None, task.line, ) return [] spec = importlib.util.spec_from_file_location( name=loaded_module.plugin_resolved_name, location=loaded_module.plugin_resolved_path, ) if not spec: assert file is not None _logger.warning( "Unable to load module %s at %s:%s for options validation", module_name, file.filename, task.line, ) return [] assert spec.loader is not None module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) try: if not hasattr(module, "main"): # skip validation for module options that are implemented as action plugin # as the option values can be changed in action plugin and are not passed # through `ArgumentSpecValidator` class as in case of modules. return [] with patch.object( sys, "argv", ["", json.dumps({"ANSIBLE_MODULE_ARGS": clean_json(module_args)})], ): fio = io.StringIO() failed_msg = "" # Warning: avoid running anything while stdout is redirected # as what happens may be very hard to debug. with contextlib.redirect_stdout(fio): # pylint: disable=protected-access basic._ANSIBLE_ARGS = None # noqa: SLF001 try: module.main() except SystemExit: failed_msg = fio.getvalue() if failed_msg: results.extend( self._parse_failed_msg(failed_msg, task, module_name, file), ) sanitized_results = self._sanitize_results(results, module_name) except ValidationPassedError: return [] return sanitized_results # pylint: disable=unused-argument def _sanitize_results( self, results: list[MatchError], module_name: str, ) -> list[MatchError]: """Remove results that are false positive.""" sanitized_results = [] for result in results: result_msg = result.message if ignored_re.match(result_msg): continue sanitized_results.append(result) return sanitized_results def _parse_failed_msg( self, failed_msg: str, task: Task, module_name: str, file: Lintable | None = None, ) -> list[MatchError]: """Parse failed message and return list of MatchError.""" results: list[MatchError] = [] try: failed_obj = json.loads(failed_msg) error_message = failed_obj["msg"] except json.decoder.JSONDecodeError: # pragma: no cover error_message = failed_msg option_type_check_error = self.RE_PATTERN.search( error_message, ) if option_type_check_error: # ignore options with templated variable value with type check errors option_key = option_type_check_error.group("name") option_value = task["action"][option_key] if has_jinja(option_value): _logger.debug( "Type checking ignored for '%s' option in task '%s' at line %s.", option_key, module_name, task.line, ) return results value_not_in_choices_error = self.RE_VALUE_OF.search( error_message, ) if value_not_in_choices_error: # ignore templated value not in allowed choices choice_key = value_not_in_choices_error.group("name") choice_value = task["action"][choice_key] if has_jinja(choice_value): _logger.debug( "Value checking ignored for '%s' option in task '%s' at line %s.", choice_key, module_name, task.line, ) return results results.append( self.create_matcherror( message=error_message, lineno=task.line, tag="args[module]", 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 # noqa: TC002 from ansiblelint.runner import Runner # pylint: disable=ungrouped-imports def test_args_module_fail(default_rules_collection: RulesCollection) -> None: """Test rule invalid module options.""" success = "examples/playbooks/rule-args-module-fail.yml" results = Runner(success, rules=default_rules_collection).run() assert len(results) == 5 assert results[0].tag == "args[module]" # First part of regex is for ansible-core up to 2.18, second part is for ansible-core 2.19+ assert re.match( r"(missing required arguments|Unsupported parameters for \(basic.py\) module: foo)", results[0].message, ) assert results[1].tag == "args[module]" assert re.match( r"(missing parameter\(s\) required by |Unsupported parameters for \(basic.py\) module: foo. Supported parameters include: fact_path)", results[1].message, ) assert results[2].tag == "args[module]" assert re.match( r"(Unsupported parameters for|missing parameter\(s\) required by 'enabled': name)", results[2].message, ) assert results[3].tag == "args[module]" assert re.match( r"(Unsupported parameters for|missing required arguments: repo)", results[3].message, ) assert results[4].tag == "args[module]" assert "value of state must be one of" in results[4].message def test_args_module_pass( default_rules_collection: RulesCollection, caplog: pytest.LogCaptureFixture, ) -> None: """Test rule valid module options.""" success = "examples/playbooks/rule-args-module-pass.yml" with caplog.at_level(logging.WARNING): results = Runner(success, rules=default_rules_collection).run() assert len(results) == 0, results assert len(caplog.records) == 0, caplog.records ansible-ansible-lint-c16f018/src/ansiblelint/rules/avoid_implicit.md000066400000000000000000000016401477347356000256240ustar00rootroot00000000000000# avoid-implicit This rule identifies the use of dangerous implicit behaviors, often also undocumented. This rule will produce the following type of error messages: - `avoid-implicit[copy-content]` is not a string as [copy](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/copy_module.html#synopsis) modules also accept these, but without documenting them. ## Problematic Code ```yaml --- - name: Example playbook hosts: localhost tasks: - name: Write file content ansible.builtin.copy: content: { "foo": "bar" } # <-- should use explicit jinja template dest: /tmp/foo.txt ``` ## Correct Code ```yaml --- - name: Example playbook hosts: localhost tasks: - name: Write file content vars: content: { "foo": "bar" } ansible.builtin.copy: content: "{{ content | to_json }}" # explicit better than implicit! dest: /tmp/foo.txt ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/avoid_implicit.py000066400000000000000000000040661477347356000256610ustar00rootroot00000000000000"""Implementation of avoid-implicit rule.""" # https://github.com/ansible/ansible-lint/issues/2501 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 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_changed = "6.8.0" def matchtask( self, task: Task, 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 from ansiblelint.runner import Runner 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 ansible-ansible-lint-c16f018/src/ansiblelint/rules/command_instead_of_module.md000066400000000000000000000020651477347356000300100ustar00rootroot00000000000000# command-instead-of-module This rule will recommend you to use a specific ansible module instead for tasks that are better served by a module, as these are more reliable, provide better messaging and usually have additional features like the ability to retry. In the unlikely case that the rule triggers false positives, you can disable it by adding a comment like `# noqa: command-instead-of-module` to the same line. You can check the [source](https://github.com/ansible/ansible-lint/blob/main/src/ansiblelint/rules/command_instead_of_module.py) of the rule for all the known commands that trigger the rule and their allowed list arguments of exceptions and raise a pull request to improve them. ## Problematic Code ```yaml --- - name: Update apt cache hosts: all tasks: - name: Run apt-get update ansible.builtin.command: apt-get update # <-- better to use ansible.builtin.apt module ``` ## Correct Code ```yaml --- - name: Update apt cache hosts: all tasks: - name: Run apt-get update ansible.builtin.apt: update_cache: true ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/command_instead_of_module.py000066400000000000000000000121201477347356000300310ustar00rootroot00000000000000"""Implementation of command-instead-of-module rule.""" # Copyright (c) 2013-2014 Will Thames # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from __future__ import annotations import sys from pathlib import Path from typing import TYPE_CHECKING from ansiblelint.rules import AnsibleLintRule from ansiblelint.utils import get_first_cmd_arg, get_second_cmd_arg if TYPE_CHECKING: from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task class CommandsInsteadOfModulesRule(AnsibleLintRule): """Using command rather than module.""" id = "command-instead-of-module" description = ( "Executing a command when there is an Ansible module is generally a bad idea" ) severity = "HIGH" tags = ["command-shell", "idiom"] version_changed = "24.10.0" _commands = ["command", "shell"] _modules = { "apt-get": "apt-get", "chkconfig": "service", "curl": "get_url or uri", "git": "git", "hg": "hg", "letsencrypt": "acme_certificate", "mktemp": "tempfile", "mount": "mount", "patch": "patch", "rpm": "yum or rpm_key", "rsync": "synchronize", "sed": "template, replace or lineinfile", "service": "service", "supervisorctl": "supervisorctl", "svn": "subversion", "systemctl": "systemd", "tar": "unarchive", "unzip": "unarchive", "wget": "get_url or uri", "yum": "yum", } _executable_options = { "git": ["branch", "log", "lfs", "rev-parse", "clean"], "systemctl": [ "--version", "get-default", "kill", "set-default", "set-property", "show-environment", "status", "reset-failed", ], "yum": ["clean", "history", "info"], "rpm": ["--nodeps"], } def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: """Check if a command is used instead of an appropriate module. :param task: Task to check for shell usage :param file: File to lint :returns: False if command module isn't used, or a string showing the command used """ if task["action"]["__ansible_module__"] not in self._commands: return False first_cmd_arg = get_first_cmd_arg(task) second_cmd_arg = get_second_cmd_arg(task) if not first_cmd_arg: return False executable = Path(first_cmd_arg).name if ( second_cmd_arg and executable in self._executable_options and second_cmd_arg in self._executable_options[executable] ): return False if executable in self._modules: message = "{0} used in place of {1} module" return message.format(executable, self._modules[executable]) return False if "pytest" in sys.modules: import pytest # pylint: disable=ungrouped-imports from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner @pytest.mark.parametrize( ("file", "expected"), ( pytest.param( "examples/playbooks/rule-command-instead-of-module-pass.yml", 0, id="pass", ), pytest.param( "examples/playbooks/rule-command-instead-of-module-fail.yml", 3, id="fail", ), ), ) def test_command_instead_of_module( default_rules_collection: RulesCollection, file: str, expected: int, ) -> None: """Validate that rule works as intended. :param default_rules_collection: Default rules for testing :param file: Test file to check for violations :expected: Expected number of errors """ results = Runner(file, rules=default_rules_collection).run() for result in results: assert result.rule.id == CommandsInsteadOfModulesRule.id, result assert len(results) == expected ansible-ansible-lint-c16f018/src/ansiblelint/rules/command_instead_of_shell.md000066400000000000000000000014741477347356000276350ustar00rootroot00000000000000# command-instead-of-shell This rule identifies uses of `shell` modules instead of a `command` one when this is not really needed. Shell is considerably slower than command and should be avoided unless there is a special need for using shell features, like environment variable expansion or chaining multiple commands using pipes. ## Problematic Code ```yaml --- - name: Problematic example hosts: localhost tasks: - name: Echo a message ansible.builtin.shell: echo hello # <-- command is better in this case changed_when: false ``` ## Correct Code ```yaml --- - name: Correct example hosts: localhost tasks: - name: Echo a message ansible.builtin.command: echo hello changed_when: false ``` !!! note This rule can be automatically fixed using [`--fix`](../autofix.md) option. ansible-ansible-lint-c16f018/src/ansiblelint/rules/command_instead_of_shell.py000066400000000000000000000115011477347356000276550ustar00rootroot00000000000000"""Implementation of command-instead-of-shell rule.""" # Copyright (c) 2016 Will Thames # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from __future__ import annotations import sys from typing import TYPE_CHECKING from ansiblelint.rules import AnsibleLintRule, TransformMixin from ansiblelint.utils import get_cmd_args if TYPE_CHECKING: from ruamel.yaml.comments import CommentedMap, CommentedSeq from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task class UseCommandInsteadOfShellRule(AnsibleLintRule, TransformMixin): """Use shell only when shell functionality is required.""" id = "command-instead-of-shell" description = ( "Shell should only be used when piping, redirecting " "or chaining commands (and Ansible would be preferred " "for some of those!)" ) severity = "HIGH" tags = ["command-shell", "idiom"] version_changed = "6.18.0" def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: """Check if a shell module is used instead of an appropriate command. :param task: Task to check for shell usage :param file: File to lint :returns: False if shell module isn't used, or string output of where it is used """ # Use unjinja so that we don't match on jinja filters # rather than pipes if task["action"]["__ansible_module__"] in ["shell", "ansible.builtin.shell"]: # Since Ansible 2.4, the `command` module does not accept setting # the `executable`. If the user needs to set it, they have to use # the `shell` module. if "executable" in task["action"]: return False jinja_stripped_cmd = self.unjinja(get_cmd_args(task)) return not any(ch in jinja_stripped_cmd for ch in "&|<>;$\n*[]{}?`!") return False def transform( self, match: MatchError, lintable: Lintable, data: CommentedMap | CommentedSeq | str, ) -> None: """Transform the data. :param match: The match to transform. :param lintable: The file to transform. :param data: The data to transform. """ if match.tag == "command-instead-of-shell": target_task = self.seek(match.yaml_path, data) for _ in range(len(target_task)): k, v = target_task.popitem(False) target_task["ansible.builtin.command" if "shell" in k else k] = v match.fixed = True # 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( ("file", "expected"), ( pytest.param( "examples/playbooks/rule-command-instead-of-shell-pass.yml", 0, id="good", ), pytest.param( "examples/playbooks/rule-command-instead-of-shell-fail.yml", 3, id="bad", ), ), ) def test_rule_command_instead_of_shell( default_rules_collection: RulesCollection, file: str, expected: int, ) -> None: """Validate that rule works as intended. :param default_rules_collection: Default rules for testing :param file: Test file to check for violations :expected: Expected number of errors """ results = Runner(file, rules=default_rules_collection).run() for result in results: assert result.rule.id == UseCommandInsteadOfShellRule.id, result assert len(results) == expected ansible-ansible-lint-c16f018/src/ansiblelint/rules/complexity.md000066400000000000000000000014631477347356000250300ustar00rootroot00000000000000# complexity This rule aims to warn about Ansible content that seems to be overly complex, suggesting refactoring for better readability and maintainability. ## complexity[tasks] `complexity[tasks]` will be triggered if the total number of tasks inside a file is above 100. If encountered, you should consider using [`ansible.builtin.include_tasks`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/include_tasks_module.html) to split your tasks into smaller files. ## complexity[nesting] `complexity[nesting]` will appear when a block contains too many tasks, by default that number is 20 but it can be changed inside the configuration file by defining `max_block_depth` value. Replace nested block with an include_tasks to make code easier to maintain. Maximum block depth allowed is ... ansible-ansible-lint-c16f018/src/ansiblelint/rules/complexity.py000066400000000000000000000102021477347356000250470ustar00rootroot00000000000000"""Implementation of limiting number of tasks.""" from __future__ import annotations import re import sys from typing import TYPE_CHECKING, Any from ansiblelint.rules import AnsibleLintRule, RulesCollection if TYPE_CHECKING: from ansiblelint.config import Options from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task class ComplexityRule(AnsibleLintRule): """Rule for limiting number of tasks inside a file.""" id = "complexity" description = "There should be limited tasks executed inside any file" severity = "MEDIUM" tags = ["experimental", "idiom"] version_changed = "6.18.0" _re_templated_inside = re.compile(r".*\{\{.*\}\}.*\w.*$") def matchplay(self, file: Lintable, data: dict[str, Any]) -> list[MatchError]: """Call matchplay for up to no_of_max_tasks inside file and return aggregate results.""" results: list[MatchError] = [] if file.kind != "playbook": return [] tasks = data.get("tasks", []) if not isinstance(self._collection, RulesCollection): # pragma: no cover msg = "Rules cannot be run outside a rule collection." raise TypeError(msg) if len(tasks) > self._collection.options.max_tasks: results.append( self.create_matcherror( message=f"Maximum tasks allowed in a play is {self._collection.options.max_tasks}.", tag=f"{self.id}[play]", filename=file, data=data, ), ) return results def matchtask(self, task: Task, file: Lintable | None = None) -> list[MatchError]: """Check if the task is a block and count the number of items inside it.""" results: list[MatchError] = [] if not isinstance(self._collection, RulesCollection): # pragma: no cover msg = "Rules cannot be run outside a rule collection." raise TypeError(msg) if task.action == "block/always/rescue": block_depth = self.calculate_block_depth(task) if block_depth > self._collection.options.max_block_depth: results.append( self.create_matcherror( message=f"Replace nested block with an include_tasks to make code easier to maintain. Maximum block depth allowed is {self._collection.options.max_block_depth}.", lineno=task.line, tag=f"{self.id}[nesting]", filename=file, ), ) return results def calculate_block_depth(self, task: Task) -> int: """Recursively calculate the block depth of a task.""" if not isinstance(task.position, str): # pragma: no cover raise NotImplementedError return task.position.count(".block") if "pytest" in sys.modules: import pytest # pylint: disable=ungrouped-imports from ansiblelint.runner import Runner @pytest.mark.parametrize( ("file", "expected_results"), ( pytest.param( "examples/playbooks/rule-complexity-pass.yml", [], id="pass", ), pytest.param( "examples/playbooks/rule-complexity-fail.yml", ["complexity[play]", "complexity[nesting]"], id="fail", ), ), ) def test_complexity( file: str, expected_results: list[str], monkeypatch: pytest.MonkeyPatch, config_options: Options, ) -> None: """Test rule.""" monkeypatch.setattr(config_options, "max_tasks", 5) monkeypatch.setattr(config_options, "max_block_depth", 3) collection = RulesCollection(options=config_options) collection.register(ComplexityRule()) results = Runner(file, rules=collection).run() assert len(results) == len(expected_results) for i, result in enumerate(results): assert result.rule.id == ComplexityRule.id, result assert result.tag == expected_results[i] ansible-ansible-lint-c16f018/src/ansiblelint/rules/conftest.py000066400000000000000000000002321477347356000245010ustar00rootroot00000000000000"""Makes pytest fixtures available.""" # pylint: disable=wildcard-import,unused-wildcard-import from ansiblelint.testing.fixtures import * # noqa: F403 ansible-ansible-lint-c16f018/src/ansiblelint/rules/custom/000077500000000000000000000000001477347356000236175ustar00rootroot00000000000000ansible-ansible-lint-c16f018/src/ansiblelint/rules/custom/__init__.py000066400000000000000000000001051477347356000257240ustar00rootroot00000000000000"""A placeholder package for putting custom rules under this dir.""" ansible-ansible-lint-c16f018/src/ansiblelint/rules/deprecated_bare_vars.md000066400000000000000000000012161477347356000267530ustar00rootroot00000000000000# deprecated-bare-vars This rule identifies possible confusing expressions where it is not clear if a variable or string is to be used and asks for clarification. You should either use the full variable syntax ('{{{{ {0} }}}}') or, whenever possible, convert it to a list of strings. ## Problematic code ```yaml --- - ansible.builtin.debug: msg: "{{ item }}" with_items: foo # <-- deprecated-bare-vars ``` ## Correct code ```yaml --- # if foo is not really a variable: - ansible.builtin.debug: msg: "{{ item }}" with_items: - foo # if foo is a variable: - ansible.builtin.debug: msg: "{{ item }}" with_items: "{{ foo }}" ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/deprecated_bare_vars.py000066400000000000000000000121141477347356000270020ustar00rootroot00000000000000"""Implementation of deprecated-bare-vars rule.""" # Copyright (c) 2013-2014 Will Thames # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from __future__ import annotations import os import sys from typing import TYPE_CHECKING, Any from ansiblelint.rules import AnsibleLintRule from ansiblelint.text import has_glob, has_jinja, is_fqcn_or_name if TYPE_CHECKING: from collections.abc import Mapping from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task class UsingBareVariablesIsDeprecatedRule(AnsibleLintRule): """Using bare variables is deprecated.""" id = "deprecated-bare-vars" description = ( "Using bare variables is deprecated. Update your " "playbooks so that the environment value uses the full variable " "syntax ``{{ your_variable }}``" ) severity = "VERY_HIGH" tags = ["deprecations"] version_changed = "6.19.0" def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: loop_type = next((key for key in task if key.startswith("with_")), None) if loop_type: if loop_type in [ "with_nested", "with_together", "with_flattened", "with_filetree", "with_community.general.filetree", ]: # These loops can either take a list defined directly in the task # or a variable that is a list itself. When a single variable is used # we just need to check that one variable, and not iterate over it like # it's a list. Otherwise, loop through and check all items. items = task[loop_type] if not isinstance(items, list | tuple): items = [items] for var in items: return self._matchvar(var, task, loop_type) elif loop_type == "with_subelements": return self._matchvar(task[loop_type][0], task, loop_type) elif loop_type in ["with_sequence", "with_ini", "with_inventory_hostnames"]: pass else: return self._matchvar(task[loop_type], task, loop_type) return False def _matchvar( self, varstring: str, task: Mapping[str, Any], loop_type: str, ) -> bool | str: if ( isinstance(varstring, str) and not has_jinja(varstring) and is_fqcn_or_name(varstring) ): valid = loop_type == "with_fileglob" and bool( has_jinja(varstring) or has_glob(varstring), ) valid |= loop_type == "with_filetree" and bool( has_jinja(varstring) or varstring.endswith(os.sep), ) if not valid: message = "Possible bare variable '{0}' used in a '{1}' loop. You should use the full variable syntax ('{{{{ {0} }}}}') or convert it to a list if that is not really a variable." return message.format(task[loop_type], loop_type) return False if "pytest" in sys.modules: import pytest # pylint: disable=ungrouped-imports from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner @pytest.mark.filterwarnings("ignore::ansible_compat.runtime.AnsibleWarning") def test_use_bare_positive() -> None: """Positive test for deprecated-bare-vars.""" collection = RulesCollection() collection.register(UsingBareVariablesIsDeprecatedRule()) success = "examples/playbooks/rule-deprecated-bare-vars-pass.yml" good_runner = Runner(success, rules=collection) assert good_runner.run() == [] def test_use_bare_negative() -> None: """Negative test for deprecated-bare-vars.""" collection = RulesCollection() collection.register(UsingBareVariablesIsDeprecatedRule()) failure = "examples/playbooks/rule-deprecated-bare-vars-fail.yml" bad_runner = Runner(failure, rules=collection) errs = bad_runner.run() assert len(errs) == 11 ansible-ansible-lint-c16f018/src/ansiblelint/rules/deprecated_local_action.md000066400000000000000000000007401477347356000274370ustar00rootroot00000000000000# deprecated-local-action This rule recommends using `delegate_to: localhost` instead of the `local_action`. ## Problematic Code ```yaml --- - name: Task example local_action: # <-- this is deprecated module: ansible.builtin.debug ``` ## Correct Code ```yaml - name: Task example ansible.builtin.debug: delegate_to: localhost # <-- recommended way to run on localhost ``` !!! note This rule can be automatically fixed using [`--fix`](../autofix.md) option. ansible-ansible-lint-c16f018/src/ansiblelint/rules/deprecated_local_action.py000066400000000000000000000110011477347356000274570ustar00rootroot00000000000000"""Implementation for deprecated-local-action rule.""" # Copyright (c) 2016, Tsukinowa Inc. # Copyright (c) 2018, Ansible Project from __future__ import annotations import copy import logging import os import sys from pathlib import Path from typing import TYPE_CHECKING from ansiblelint.rules import AnsibleLintRule, TransformMixin from ansiblelint.runner import get_matches from ansiblelint.transformer import Transformer if TYPE_CHECKING: from ruamel.yaml.comments import CommentedMap, CommentedSeq from ansiblelint.config import Options from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task _logger = logging.getLogger(__name__) class TaskNoLocalActionRule(AnsibleLintRule, TransformMixin): """Do not use 'local_action', use 'delegate_to: localhost'.""" id = "deprecated-local-action" description = "Do not use ``local_action``, use ``delegate_to: localhost``" needs_raw_task = True severity = "MEDIUM" tags = ["deprecations"] version_changed = "4.0.0" def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: """Return matches for a task.""" raw_task = task["__raw_task__"] return "local_action" in raw_task def transform( self, match: MatchError, lintable: Lintable, data: CommentedMap | CommentedSeq | str, ) -> None: if match.tag == self.id: # we do not want perform a partial modification accidentally original_target_task = self.seek(match.yaml_path, data) target_task = copy.deepcopy(original_target_task) for _ in range(len(target_task)): k, v = target_task.popitem(False) if k == "local_action": if isinstance(v, dict): module_name = v["module"] target_task[module_name] = None target_task["delegate_to"] = "localhost" elif isinstance(v, str): module_name, module_value = v.split(" ", 1) target_task[module_name] = module_value target_task["delegate_to"] = "localhost" else: # pragma: no cover _logger.debug( "Ignored unexpected data inside %s transform.", self.id, ) return else: target_task[k] = v match.fixed = True original_target_task.clear() original_target_task.update(target_task) # testing code to be loaded only with pytest or when executed the rule file if "pytest" in sys.modules: from unittest import mock from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner def test_local_action(default_rules_collection: RulesCollection) -> None: """Positive test deprecated_local_action.""" results = Runner( "examples/playbooks/rule-deprecated-local-action-fail.yml", rules=default_rules_collection, ).run() assert len(results) == 1 assert results[0].tag == "deprecated-local-action" @mock.patch.dict(os.environ, {"ANSIBLE_LINT_WRITE_TMP": "1"}, clear=True) def test_local_action_transform( config_options: Options, default_rules_collection: RulesCollection, ) -> None: """Test transform functionality for no-log-password rule.""" playbook = Path("examples/playbooks/tasks/local_action.yml") config_options.write_list = ["all"] config_options.lintables = [str(playbook)] runner_result = get_matches( rules=default_rules_collection, options=config_options, ) transformer = Transformer(result=runner_result, options=config_options) transformer.run() matches = runner_result.matches assert len(matches) == 3 orig_content = playbook.read_text(encoding="utf-8") expected_content = playbook.with_suffix( f".transformed{playbook.suffix}", ).read_text(encoding="utf-8") transformed_content = playbook.with_suffix(f".tmp{playbook.suffix}").read_text( encoding="utf-8", ) assert orig_content != transformed_content assert expected_content == transformed_content playbook.with_suffix(f".tmp{playbook.suffix}").unlink() ansible-ansible-lint-c16f018/src/ansiblelint/rules/deprecated_module.md000066400000000000000000000016211477347356000262740ustar00rootroot00000000000000# deprecated-module This rule identifies deprecated modules in playbooks. You should avoid using deprecated modules because they are not maintained, which can pose a security risk. Additionally when a module is deprecated it is available temporarily with a plan for future removal. Refer to the [Ansible module index](https://docs.ansible.com/ansible/latest/collections/index_module.html) for information about replacements and removal dates for deprecated modules. ## Problematic Code ```yaml --- - name: Example playbook hosts: localhost tasks: - name: Configure VLAN ID ansible.netcommon.net_vlan: # <- Uses a deprecated module. vlan_id: 20 ``` ## Correct Code ```yaml --- - name: Example playbook hosts: localhost tasks: - name: Configure VLAN ID dellemc.enterprise_sonic.sonic_vlans: # <- Uses a platform specific module. config: - vlan_id: 20 ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/deprecated_module.py000066400000000000000000000037511477347356000263320ustar00rootroot00000000000000"""Implementation of deprecated-module rule.""" # Copyright (c) 2018, Ansible Project from __future__ import annotations 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 DeprecatedModuleRule(AnsibleLintRule): """Deprecated module.""" id = "deprecated-module" description = ( "These are deprecated modules, some modules are kept " "temporarily for backwards compatibility but usage is discouraged." ) link = "https://docs.ansible.com/ansible/latest/collections/index_module.html" severity = "HIGH" tags = ["deprecations"] version_changed = "4.0.0" _modules = [ "accelerate", "aos_asn_pool", "aos_blueprint", "aos_blueprint_param", "aos_blueprint_virtnet", "aos_device", "aos_external_router", "aos_ip_pool", "aos_logical_device", "aos_logical_device_map", "aos_login", "aos_rack_type", "aos_template", "azure", "cl_bond", "cl_bridge", "cl_img_install", "cl_interface", "cl_interface_policy", "cl_license", "cl_ports", "cs_nic", "docker", "ec2_ami_find", "ec2_ami_search", "ec2_remote_facts", "ec2_vpc", "kubernetes", "netscaler", "nxos_ip_interface", "nxos_mtu", "nxos_portchannel", "nxos_switchport", "oc", "panos_nat_policy", "panos_security_policy", "vsphere_guest", "win_msi", "include", ] def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: module = task["action"]["__ansible_module__"] if module in self._modules: message = "{0} {1}" return message.format(self.shortdesc, module) return False ansible-ansible-lint-c16f018/src/ansiblelint/rules/empty_string_compare.md000066400000000000000000000020341477347356000270600ustar00rootroot00000000000000# empty-string-compare This rule checks for empty string comparison in playbooks. To ensure code clarity you should avoid using empty strings in conditional statements with the `when` clause. - Use `when: var | length > 0` instead of `when: var != ""`. - Use `when: var | length == 0` instead of `when: var == ""`. This is an opt-in rule. You must enable it in your Ansible-lint configuration as follows: ```yaml enable_list: - empty-string-compare ``` ## Problematic Code ```yaml --- - name: Example playbook hosts: all tasks: - name: Shut down ansible.builtin.command: /sbin/shutdown -t now when: ansible_os_family == "" # <- Compares with an empty string. - name: Shut down ansible.builtin.command: /sbin/shutdown -t now when: ansible_os_family !="" # <- Compares with an empty string. ``` ## Correct Code ```yaml --- - name: Example playbook hosts: all tasks: - name: Shut down ansible.builtin.shell: | /sbin/shutdown -t now echo $var == when: ansible_os_family ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/empty_string_compare.py000066400000000000000000000047771477347356000271300ustar00rootroot00000000000000"""Implementation of empty-string-compare rule.""" # Copyright (c) 2016, Will Thames and contributors # Copyright (c) 2018, Ansible Project from __future__ import annotations import re import sys from typing import TYPE_CHECKING from ansiblelint.rules import AnsibleLintRule from ansiblelint.yaml_utils import nested_items_path if TYPE_CHECKING: from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task class ComparisonToEmptyStringRule(AnsibleLintRule): """Don't compare to empty string.""" id = "empty-string-compare" description = ( 'Use ``when: var|length > 0`` rather than ``when: var != ""`` (or ' 'conversely ``when: var|length == 0`` rather than ``when: var == ""``)' ) severity = "HIGH" tags = ["idiom", "opt-in"] version_changed = "4.0.0" empty_string_compare = re.compile(r"[=!]= ?(\"{2}|'{2})") def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: for k, v, _ in nested_items_path(task): if k == "when": if isinstance(v, str): if self.empty_string_compare.search(v): return True elif isinstance(v, bool): pass else: for item in v: if isinstance(item, str) and self.empty_string_compare.search( item, ): 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 from ansiblelint.runner import Runner def test_rule_empty_string_compare_fail() -> None: """Test rule matches.""" rules = RulesCollection() rules.register(ComparisonToEmptyStringRule()) results = Runner( "examples/playbooks/rule-empty-string-compare-fail.yml", rules=rules, ).run() assert len(results) == 3 for result in results: assert result.message == ComparisonToEmptyStringRule().shortdesc def test_rule_empty_string_compare_pass() -> None: """Test rule matches.""" rules = RulesCollection() rules.register(ComparisonToEmptyStringRule()) results = Runner( "examples/playbooks/rule-empty-string-compare-pass.yml", rules=rules, ).run() assert len(results) == 0, results ansible-ansible-lint-c16f018/src/ansiblelint/rules/fqcn.md000066400000000000000000000070301477347356000235560ustar00rootroot00000000000000# fqcn This rule checks for fully-qualified collection names (FQCN) in Ansible content. Declaring an FQCN ensures that an action uses code from the correct namespace. This avoids ambiguity and conflicts that can cause operations to fail or produce unexpected results. The `fqcn` rule has the following checks: - `fqcn[action]` - Use FQCN for module actions, such ... - `fqcn[action-core]` - Checks for FQCNs from the `ansible.legacy` or `ansible.builtin` collection. - `fqcn[canonical]` - You should use canonical module name ... instead of ... - [`fqcn[deep]`](#deep-modules) - Checks for deep/nested plugins directory inside collections. - `fqcn[keyword]` - Avoid `collections` keyword by using FQCN for all plugins, modules, roles and playbooks. !!! note In most cases you should declare the `ansible.builtin` collection for internal Ansible actions. You should declare the `ansible.legacy` collection if you use local overrides with actions, such with as the ``shell`` module. !!! warning This rule does not take [`collections` keyword](https://docs.ansible.com/ansible/latest/collections_guide/collections_using_playbooks.html#simplifying-module-names-with-the-collections-keyword) into consideration for resolving content. The `collections` keyword provided a temporary mechanism transitioning to Ansible 2.9. You should rewrite any content that uses the `collections:` key and avoid it where possible. ## Canonical module names Canonical module names are also known as **resolved module names** and they are to be preferred for most cases. Many Ansible modules have multiple aliases and redirects, as these were created over time while the content was refactored. Still, all of them do finally resolve to the same module name, but not without adding some performance overhead. As very old aliases are at some point removed, it makes to just refresh the content to make it point to the current canonical name. The only exception for using a canonical name is if your code still needs to be compatible with a very old version of Ansible, one that does not know how to resolve that name. If you find yourself in such a situation, feel free to add this rule to the ignored list. ## Deep modules When writing modules, you should avoid nesting them in deep directories, even if Ansible allows you to do so. Since early 2023, the official guidance, backed by the core team, is to use a flat directory structure for modules. This ensures optimal performance. Existing collections that still use deep directories can migrate to the flat structure in a backward-compatible way by adding redirects like in [this example](https://github.com/ansible-collections/community.general/blob/main/meta/runtime.yml#L227-L233). ## Problematic Code ```yaml --- - name: Example playbook hosts: all tasks: - name: Create an SSH connection shell: ssh ssh_user@{{ ansible_ssh_host }} # <- Does not use the FQCN for the shell module. ``` ## Correct Code ```yaml --- - name: Example playbook (1st solution) hosts: all tasks: - name: Create an SSH connection # Use the FQCN for the legacy shell module and allow local overrides. ansible.legacy.shell: ssh ssh_user@{{ ansible_ssh_host }} -o IdentityFile=path/to/my_rsa ``` ```yaml --- - name: Example playbook (2nd solution) hosts: all tasks: - name: Create an SSH connection # Use the FQCN for the builtin shell module. ansible.builtin.shell: ssh ssh_user@{{ ansible_ssh_host }} ``` !!! note This rule can be automatically fixed using [`--fix`](../autofix.md) option. ansible-ansible-lint-c16f018/src/ansiblelint/rules/fqcn.py000066400000000000000000000257521477347356000236210ustar00rootroot00000000000000"""Rule definition for usage of fully qualified collection names for builtins.""" from __future__ import annotations import logging import sys from typing import TYPE_CHECKING, Any from ruamel.yaml.comments import CommentedSeq from ansiblelint.rules import AnsibleLintRule, TransformMixin from ansiblelint.utils import load_plugin if TYPE_CHECKING: from ruamel.yaml.comments import CommentedMap from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task _logger = logging.getLogger(__name__) builtins = [ "add_host", "apt", "apt_key", "apt_repository", "assemble", "assert", "async_status", "blockinfile", "command", "copy", "cron", "debconf", "debug", "dnf", "dpkg_selections", "expect", "fail", "fetch", "file", "find", "gather_facts", "get_url", "getent", "git", "group", "group_by", "hostname", "import_playbook", "import_role", "import_tasks", "include", "include_role", "include_tasks", "include_vars", "iptables", "known_hosts", "lineinfile", "meta", "package", "package_facts", "pause", "ping", "pip", "raw", "reboot", "replace", "rpm_key", "script", "service", "service_facts", "set_fact", "set_stats", "setup", "shell", "slurp", "stat", "subversion", "systemd", "sysvinit", "tempfile", "template", "unarchive", "uri", "user", "wait_for", "wait_for_connection", "yum", "yum_repository", ] class FQCNBuiltinsRule(AnsibleLintRule, TransformMixin): """Use FQCN for builtin actions.""" id = "fqcn" severity = "MEDIUM" description = ( "Check whether actions are using using full qualified collection names." ) tags = ["formatting"] version_changed = "6.8.0" module_aliases: dict[str, str] = {"block/always/rescue": "block/always/rescue"} _ids = { "fqcn[action-core]": "Use FQCN for builtin module actions", "fqcn[action]": "Use FQCN for module actions", "fqcn[canonical]": "You should use canonical module name", } def matchtask( self, task: Task, file: Lintable | None = None, ) -> list[MatchError]: result: list[MatchError] = [] if file and file.failed(): return result module = task["action"]["__ansible_module_original__"] if not isinstance(module, str): msg = "Invalid data for module." raise TypeError(msg) if module not in self.module_aliases: loaded_module = load_plugin(module) if not isinstance(loaded_module.resolved_fqcn, str): msg = f"Invalid value ({loaded_module.resolved_fqcn})for resolved_fqcn attribute of {module} module." _logger.warning(msg) return [] target = loaded_module.resolved_fqcn self.module_aliases[module] = target if target is None: _logger.warning("Unable to resolve FQCN for module %s", module) self.module_aliases[module] = module return [] if target not in self.module_aliases: self.module_aliases[target] = target if module != self.module_aliases[module]: module_alias = self.module_aliases[module] if module_alias.startswith("ansible.builtin"): legacy_module = module_alias.replace( "ansible.builtin.", "ansible.legacy.", 1, ) if module != legacy_module: if module == "ansible.builtin.include": message = f"Avoid deprecated module ({module})" details = "Use `ansible.builtin.include_task` or `ansible.builtin.import_tasks` instead." else: message = f"Use FQCN for builtin module actions ({module})." details = f"Use `{module_alias}` or `{legacy_module}` instead." result.append( self.create_matcherror( message=message, details=details, filename=file, data=module, tag="fqcn[action-core]", ), ) elif module.count(".") < 2: result.append( self.create_matcherror( message=f"Use FQCN for module actions, such `{self.module_aliases[module]}`.", details=f"Action `{module}` is not FQCN.", filename=file, data=module, tag="fqcn[action]", ), ) # TODO(ssbarnea): Remove the c.g. and c.n. exceptions from here once # noqa: FIX002 # community team is flattening these. # https://github.com/ansible-community/community-topics/issues/147 elif not module.startswith("community.general.") or module.startswith( "community.network.", ): result.append( self.create_matcherror( message=f"You should use canonical module name `{self.module_aliases[module]}` instead of `{module}`.", filename=file, data=module, tag="fqcn[canonical]", ), ) return result def matchyaml(self, file: Lintable) -> list[MatchError]: """Return matches found for a specific YAML text.""" result = [] if file.kind == "plugin": i = file.path.resolve().parts.index("plugins") plugin_type = file.path.resolve().parts[i : i + 2] short_path = file.path.resolve().parts[i + 2 :] if len(short_path) > 1 and "test" not in str(file.path): result.append( self.create_matcherror( message=f"Deep plugins directory is discouraged. Move '{file.path}' directly under '{'/'.join(plugin_type)}' folder.", tag="fqcn[deep]", filename=file, ), ) elif file.kind == "playbook": for play in file.data: if play is None: continue result.extend(self.matchplay(file, play)) return result def matchplay(self, file: Lintable, data: dict[str, Any]) -> list[MatchError]: if file.kind != "playbook": return [] if "collections" in data: return [ self.create_matcherror( message="Avoid `collections` keyword by using FQCN for all plugins, modules, roles and playbooks.", data=data, tag="fqcn[keyword]", filename=file, ), ] return [] def transform( self, match: MatchError, lintable: Lintable, data: CommentedMap | CommentedSeq | str, ) -> None: if match.tag in self.ids(): target_task = self.seek(match.yaml_path, data) # Unfortunately, a lot of data about Ansible content gets lost here, you only get a simple dict. # For now, just parse the error messages for the data about action names etc. and fix this later. current_action = "" new_action = "" if match.tag == "fqcn[action-core]": # split at the first bracket, cut off the last bracket and dot current_action = match.message.split("(")[1][:-2] # This will always replace builtin modules with "ansible.builtin" versions, not "ansible.legacy". # The latter is technically more correct in what ansible has executed so far, the former is most likely better understood and more robust. new_action = match.details.split("`")[1] elif match.tag == "fqcn[action]": current_action = match.details.split("`")[1] new_action = match.message.split("`")[1] elif match.tag == "fqcn[canonical]": current_action = match.message.split("`")[3] new_action = match.message.split("`")[1] for _ in range(len(target_task)): if isinstance(target_task, CommentedSeq): continue k, v = target_task.popitem(False) target_task[new_action if k == current_action else k] = v match.fixed = True # testing code to be loaded only with pytest or when executed the rule file if "pytest" in sys.modules: from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner def test_fqcn_builtin_fail() -> None: """Test rule matches.""" collection = RulesCollection() collection.register(FQCNBuiltinsRule()) success = "examples/playbooks/rule-fqcn-fail.yml" results = Runner(success, rules=collection).run() assert len(results) == 3 assert results[0].tag == "fqcn[keyword]" assert "Avoid `collections` keyword" in results[0].message assert results[1].tag == "fqcn[action-core]" assert "Use FQCN for builtin module actions" in results[1].message assert results[2].tag == "fqcn[action]" assert "Use FQCN for module actions, such" in results[2].message def test_fqcn_builtin_pass() -> None: """Test rule does not match.""" collection = RulesCollection() collection.register(FQCNBuiltinsRule()) success = "examples/playbooks/rule-fqcn-pass.yml" results = Runner(success, rules=collection).run() assert len(results) == 0, results def test_fqcn_deep_fail() -> None: """Test rule matches.""" collection = RulesCollection() collection.register(FQCNBuiltinsRule()) failure = "examples/.collection/plugins/modules/deep/beta.py" results = Runner(failure, rules=collection).run() assert len(results) == 1 assert results[0].tag == "fqcn[deep]" assert "Deep plugins directory is discouraged" in results[0].message def test_fqcn_deep_pass() -> None: """Test rule does not match.""" collection = RulesCollection() collection.register(FQCNBuiltinsRule()) success = "examples/.collection/plugins/modules/alpha.py" results = Runner(success, rules=collection).run() assert len(results) == 0 def test_fqcn_deep_test_dir_pass() -> None: """Test rule does not match.""" collection = RulesCollection() collection.register(FQCNBuiltinsRule()) success = "examples/.collection/plugins/modules/tests/gamma.py" results = Runner(success, rules=collection).run() assert len(results) == 0 ansible-ansible-lint-c16f018/src/ansiblelint/rules/galaxy.md000066400000000000000000000057061477347356000241240ustar00rootroot00000000000000# galaxy This rule identifies if the collection version mentioned in galaxy.yml is ideal in terms of the version number being greater than or equal to `1.0.0`. This rule looks for a changelog file in expected locations, detailed below in the Changelog Details section. This rule checks to see if the `galaxy.yml` file includes one of the required tags for certification on Automation Hub. Additional custom tags can be added, but one or more of these tags must be present for certification. The tag list is as follows: `application`, `cloud`,`database`, `infrastructure`, `linux`, `monitoring`, `networking`, `security`,`storage`, `tools`, `windows`. This rule can produce messages such: - `galaxy[version-missing]` - `galaxy.yaml` should have version tag. - `galaxy[version-incorrect]` - collection version should be greater than or equal to `1.0.0` - `galaxy[no-changelog]` - collection is missing a changelog file in expected locations. - `galaxy[no-runtime]` - Please add a [meta/runtime.yml](https://docs.ansible.com/ansible/latest/dev_guide/developing_collections_structure.html#meta-directory-and-runtime-yml) file. - `galaxy[tags]` - `galaxy.yaml` must have one of the required tags: `application`, `cloud`, `database`, `infrastructure`, `linux`, `monitoring`, `networking`, `security`, `storage`, `tools`, `windows`. - `galaxy[tags-format]` - `galaxy.yal` tags must be formatted correctly matching regex. - `galaxy[tags-length]` - `galaxy.yml` tags character count cannot exceed 64 characters in length - `galaxy[tags-count]` - `galaxy.yml` tag count cannot exceed 20 - `galaxy[invalid-dependency-version]` = Invalid collection metadata. Dependency version spec range is invalid If you want to ignore some of the messages above, you can add any of them to the `ignore_list`. ## Problematic code ```yaml # galaxy.yml --- name: foo namespace: bar version: 0.2.3 # <-- collection version should be >= 1.0.0 authors: - John readme: ../README.md description: "..." ``` ## Correct code ```yaml # galaxy.yml --- name: foo namespace: bar version: 1.0.0 authors: - John readme: ../README.md description: "..." ``` # Changelog Details This rule expects a `CHANGELOG.md`, `CHANGELOG.rst`, `changelogs/changelog.yaml`, or `changelogs/changelog.yml` file in the collection root. If a `changelogs/changelog.yaml` or `changelogs/changelog.yml` file exists, the schema will be checked. ## Minimum required changelog.yaml/changelog.yml file ```yaml # changelog.yaml --- releases: {} ``` # Required Tag Details ## Problematic code ```yaml # galaxy.yml --- namespace: bar name: foo version: 1.0.0 authors: - John readme: ../README.md description: "..." license: - Apache-2.0 repository: https://github.com/ORG/REPO_NAME ``` ## Correct code ```yaml # galaxy.yml --- namespace: bar name: foo version: 1.0.0 authors: - John readme: ../README.md description: "..." license: - Apache-2.0 repository: https://github.com/ORG/REPO_NAME tags: [networking, test_tag, test_tag_2] ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/galaxy.py000066400000000000000000000224611477347356000241510ustar00rootroot00000000000000"""Implementation of GalaxyRule.""" from __future__ import annotations import sys from typing import TYPE_CHECKING, Any from ansiblelint.constants import ( FILENAME_KEY, LINE_NUMBER_KEY, MAX_LENGTH_TAG, MAX_TAGS_COUNT, TAG_NAME_REGEXP, ) from ansiblelint.rules import AnsibleLintRule if TYPE_CHECKING: from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable class GalaxyRule(AnsibleLintRule): """Rule for checking collections.""" id = "galaxy" description = "Confirm that collection's units are valid." severity = "MEDIUM" tags = ["metadata"] version_changed = "6.11.0" _ids = { "galaxy[tags]": "galaxy.yaml must have one of the required tags", "galaxy[tags-format]": "galaxy.yaml one or more tags are not formatted properly.", "galaxy[tags-length]": "galaxy.yaml one or more tags exceed character length.", "galaxy[tags-count]": "galaxy.yaml has too many tags.", "galaxy[no-changelog]": "No changelog found. Please add a changelog file. Refer to the galaxy.md file for more info.", "galaxy[version-missing]": "galaxy.yaml should have version tag.", "galaxy[no-runtime]": "meta/runtime.yml file not found.", "galaxy[invalid-dependency-version]": "Invalid collection metadata. Dependency version spec range is invalid", } def matchplay(self, file: Lintable, data: dict[str, Any]) -> list[MatchError]: """Return matches found for a specific play (entry in playbook).""" if file.kind != "galaxy": return [] # Defined by Automation Hub Team and Partner Engineering required_tag_list = [ "application", "cloud", "database", "eda", "infrastructure", "linux", "monitoring", "networking", "security", "storage", "tools", "windows", ] results = [] base_path = file.path.parent.resolve() changelog_found = 0 changelog_paths = [ base_path / "changelogs" / "changelog.yaml", base_path / "changelogs" / "changelog.yml", base_path / "CHANGELOG.rst", base_path / "CHANGELOG.md", ] for path in changelog_paths: if path.is_file(): changelog_found = 1 galaxy_tag_list = data.get("tags", []) galaxy_tag_invalid_format = [ tag for tag in galaxy_tag_list if not TAG_NAME_REGEXP.match(tag) ] galaxy_tag_invalid_length = [ tag for tag in galaxy_tag_list if len(tag) > MAX_LENGTH_TAG ] collection_deps = data.get("dependencies") if collection_deps: for dep, ver in collection_deps.items(): if ( dep not in [LINE_NUMBER_KEY, FILENAME_KEY] and len(str(ver).strip()) == 0 ): results.append( self.create_matcherror( message=f"Invalid collection metadata. Dependency version spec range is invalid for '{dep}'.", tag="galaxy[invalid-dependency-version]", filename=file, ), ) # Changelog Check - building off Galaxy rule as there is no current way to check # for a nonexistent file if not changelog_found: results.append( self.create_matcherror( message="No changelog found. Please add a changelog file. Refer to the galaxy.md file for more info.", tag="galaxy[no-changelog]", filename=file, ), ) # Checking if galaxy.yml contains one or more required tags for certification if not galaxy_tag_list or not any( tag in required_tag_list for tag in galaxy_tag_list ): results.append( self.create_matcherror( message=( f"galaxy.yaml must have one of the required tags: {required_tag_list}" ), tag="galaxy[tags]", filename=file, ), ) # Checking if galaxy.yml tags are formatted correctly if galaxy_tag_invalid_format: results.append( self.create_matcherror( message=( f"galaxy.yaml must have properly formatted tags. Invalid tags: {','.join(galaxy_tag_invalid_format)}" ), tag="galaxy[tags-format]", filename=file, ), ) # Checking if galaxy.yml tags length are within limits if galaxy_tag_invalid_length: results.append( self.create_matcherror( message=( f"galaxy.yaml tags must not exceed {MAX_LENGTH_TAG} characters. Invalid tags: {','.join(galaxy_tag_invalid_length)}" ), tag="galaxy[tags-length]", filename=file, ), ) # Checking if galaxy.yml tags does not exceed the max number if len(galaxy_tag_list) > MAX_TAGS_COUNT: results.append( self.create_matcherror( message=( f"galaxy.yaml exceeds {MAX_TAGS_COUNT} tags. Current count: {len(galaxy_tag_list)}" ), tag="galaxy[tags-count]", filename=file, ), ) if "version" not in data: results.append( self.create_matcherror( message="galaxy.yaml should have version tag.", data=data, tag="galaxy[version-missing]", filename=file, ), ) return results # returning here as it does not make sense # to continue for version check below if not (base_path / "meta" / "runtime.yml").is_file(): results.append( self.create_matcherror( message="meta/runtime.yml file not found.", tag="galaxy[no-runtime]", filename=file, ), ) return results if "pytest" in sys.modules: import pytest from ansiblelint.rules import RulesCollection # pylint: disable=ungrouped-imports from ansiblelint.runner import Runner def test_galaxy_no_collection_version() -> None: """Test for no collection version in galaxy.""" collection = RulesCollection() collection.register(GalaxyRule()) failure = "examples/.no_collection_version/galaxy.yml" bad_runner = Runner(failure, rules=collection) errs = bad_runner.run() assert len(errs) == 1 @pytest.mark.parametrize( ("file", "expected"), ( pytest.param( "examples/galaxy_tags/galaxy_invalid_format_tags/galaxy.yml", ["galaxy[tags-format]"], id="tags-format", ), pytest.param( "examples/galaxy_tags/galaxy_invalid_length_tags/galaxy.yml", ["galaxy[tags-length]"], id="tags-length", ), pytest.param( "examples/galaxy_tags/galaxy_count_tags/galaxy.yml", ["galaxy[tags-count]"], id="tags-count", ), pytest.param( "examples/galaxy_tags/galaxy_no_required_tags/galaxy.yml", ["galaxy[tags]"], id="tags", ), pytest.param( "examples/galaxy_tags/pass/galaxy.yml", [], id="pass", ), pytest.param( "examples/.collection/galaxy.yml", ["schema[galaxy]"], id="schema", ), pytest.param( "examples/.invalid_dependencies/galaxy.yml", [ "galaxy[invalid-dependency-version]", "galaxy[invalid-dependency-version]", ], id="invalid-dependency-version", ), pytest.param( "examples/.no_changelog/galaxy.yml", ["galaxy[no-changelog]"], id="no-changelog", ), pytest.param( "examples/.no_collection_version/galaxy.yml", ["schema[galaxy]", "galaxy[version-missing]"], id="no-collection-version", ), pytest.param( "examples/collections/broken_no_runtime/galaxy.yml", ["galaxy[no-runtime]"], id="broken_no_runtime", ), ), ) def test_galaxy_rule( default_rules_collection: RulesCollection, file: str, expected: list[str], ) -> None: """Validate that rule works as intended.""" results = Runner(file, rules=default_rules_collection).run() assert len(results) == len(expected) for index, result in enumerate(results): assert result.tag == expected[index] ansible-ansible-lint-c16f018/src/ansiblelint/rules/galaxy_version_incorrect.md000066400000000000000000000030571477347356000277360ustar00rootroot00000000000000# galaxy-version-incorrect This rule checks that the `version` key within `galaxy.yml` is greater than or equal to `1.0.0`. This is to follow semantic versioning standards that are enforced in the Ansible Automation Platform. This is an opt-in rule. You must enable it in your Ansible-lint configuration as follows: ```yaml enable_list: - galaxy-version-incorrect ``` ## Problematic Code ```yaml description: "description" namespace: "namespace_name" name: "collection_name" version: "0.0.1" # <- version key is not greater than or equal to '1.0.0'. readme: "README.md" authors: - "Author1" - "Author2 (https://author2.example.com)" - "Author3 " dependencies: "other_namespace.collection1": ">=1.0.0" "other_namespace.collection2": ">=2.0.0,<3.0.0" "anderson55.my_collection": "*" # note: "*" selects the highest version available license: - "MIT" tags: - demo - collection repository: "https://www.github.com/my_org/my_collection" ``` ## Correct Code ```yaml description: "description" namespace: "namespace_name" name: "collection_name" version: "1.0.0" # <- version key is greater than or equal to '1.0.0'. readme: "README.md" authors: - "Author1" - "Author2 (https://author2.example.com)" - "Author3 " dependencies: "other_namespace.collection1": ">=1.0.0" "other_namespace.collection2": ">=2.0.0,<3.0.0" "anderson55.my_collection": "*" # note: "*" selects the highest version available license: - "MIT" tags: - demo - collection repository: "https://www.github.com/my_org/my_collection" ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/galaxy_version_incorrect.py000066400000000000000000000072241477347356000277660ustar00rootroot00000000000000"""Implementation of GalaxyVersionIncorrectRule.""" from __future__ import annotations import sys from functools import total_ordering from typing import TYPE_CHECKING, Any from ansiblelint.rules import AnsibleLintRule if TYPE_CHECKING: from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable class GalaxyVersionIncorrectRule(AnsibleLintRule): """Rule for checking collection version is greater than 1.0.0.""" id = "galaxy-version-incorrect" description = "Confirm via galaxy.yml file if collection version is greater than or equal to 1.0.0." severity = "MEDIUM" tags = ["opt-in", "metadata"] version_changed = "24.7.0" def matchplay(self, file: Lintable, data: dict[str, Any]) -> list[MatchError]: """Return matches found for a specific play (entry in playbook).""" if file.kind != "galaxy": return [] results = [] version = data.get("version") if not version or Version(version) < Version("1.0.0"): results.append( self.create_matcherror( message="collection version should be greater than or equal to 1.0.0", data=version, filename=file, ), ) return results @total_ordering class Version: """Simple class to compare arbitrary versions.""" def __init__(self, version_string: str): """Construct a Version object.""" self.components = version_string.split(".") def __eq__(self, other: object) -> bool: """Implement equality comparison.""" try: other = _coerce(other) except NotImplementedError: return NotImplemented return self.components == other.components def __lt__(self, other: Version) -> bool: """Implement lower-than operation.""" other = _coerce(other) return self.components < other.components def _coerce(other: object) -> Version: if isinstance(other, str): other = Version(other) if isinstance(other, int | float): other = Version(str(other)) if isinstance(other, Version): return other msg = f"Unable to coerce object type {type(other)} to Version" raise NotImplementedError(msg) if "pytest" in sys.modules: import pytest from ansiblelint.rules import RulesCollection # pylint: disable=ungrouped-imports from ansiblelint.runner import Runner def test_galaxy_collection_version_positive() -> None: """Positive test for collection version in galaxy.""" collection = RulesCollection() collection.register(GalaxyVersionIncorrectRule()) success = "examples/.collection/galaxy.yml" good_runner = Runner(success, rules=collection) assert good_runner.run() == [] def test_galaxy_collection_version_negative() -> None: """Negative test for collection version in galaxy.""" collection = RulesCollection() collection.register(GalaxyVersionIncorrectRule()) failure = "examples/meta/galaxy.yml" bad_runner = Runner(failure, rules=collection) errs = bad_runner.run() assert len(errs) == 1 def test_version_class() -> None: """Test for version class.""" v = Version("1.0.0") assert v == Version("1.0.0") assert v != NotImplemented def test_coerce() -> None: """Test for _coerce function.""" assert _coerce("1.0") == Version("1.0") assert _coerce(1.0) == Version("1.0") expected = "Unable to coerce object type" with pytest.raises(NotImplementedError, match=expected): _coerce(type(Version)) ansible-ansible-lint-c16f018/src/ansiblelint/rules/ignore_errors.md000066400000000000000000000031451477347356000255110ustar00rootroot00000000000000# ignore-errors This rule checks that playbooks do not use the `ignore_errors` directive to ignore all errors. Ignoring all errors in a playbook hides actual failures, incorrectly mark tasks as failed, and result in unexpected side effects and behavior. Instead of using the `ignore_errors: true` directive, you should do the following: - Ignore errors only when using the `{{ ansible_check_mode }}` variable. - Use `register` to register errors. - Use `failed_when:` and specify acceptable error conditions. ## Problematic Code ```yaml --- - name: Example playbook hosts: all tasks: - name: Run apt-get update ansible.builtin.command: apt-get update ignore_errors: true # <- Ignores all errors, including important failures. ``` ## Correct Code ```yaml --- - name: Example playbook hosts: all tasks: - name: Run apt-get update ansible.builtin.command: apt-get update ignore_errors: "{{ ansible_check_mode }}" # <- Ignores errors in check mode. ``` ```yaml --- - name: Example playbook hosts: all tasks: - name: Run apt-get update ansible.builtin.command: apt-get update ignore_errors: true register: ignore_errors_register # <- Stores errors and failures for evaluation. ``` ```yaml --- - name: Example playbook hosts: all tasks: - name: Disable apport become: "yes" lineinfile: line: "enabled=0" dest: /etc/default/apport mode: 0644 state: present register: default_apport failed_when: default_apport.rc !=0 and not default_apport.rc == 257 # <- Defines conditions that constitute a failure. ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/ignore_errors.py000066400000000000000000000076211477347356000255440ustar00rootroot00000000000000"""IgnoreErrorsRule used with ansible-lint.""" 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 IgnoreErrorsRule(AnsibleLintRule): """Use failed_when and specify error conditions instead of using ignore_errors.""" id = "ignore-errors" description = ( "Instead of ignoring all errors, ignore the errors only when using ``{{ ansible_check_mode }}``, " "register the errors using ``register``, " "or use ``failed_when:`` and specify acceptable error conditions " "to reduce the risk of ignoring important failures." ) severity = "LOW" tags = ["unpredictability"] version_changed = "5.0.7" def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: return ( task.get("ignore_errors") and task.get("ignore_errors") != "{{ ansible_check_mode }}" and not task.get("register") ) if "pytest" in sys.modules: import pytest if TYPE_CHECKING: from ansiblelint.testing import RunFromText IGNORE_ERRORS_TRUE = """ - hosts: all tasks: - name: Run apt-get update command: apt-get update ignore_errors: true """ IGNORE_ERRORS_FALSE = """ - hosts: all tasks: - name: Run apt-get update command: apt-get update ignore_errors: false """ IGNORE_ERRORS_CHECK_MODE = """ - hosts: all tasks: - name: Run apt-get update command: apt-get update ignore_errors: "{{ ansible_check_mode }}" """ IGNORE_ERRORS_REGISTER = """ - hosts: all tasks: - name: Run apt-get update command: apt-get update ignore_errors: true register: ignore_errors_register """ FAILED_WHEN = """ - hosts: all tasks: - name: Disable apport become: 'yes' lineinfile: line: "enabled=0" dest: /etc/default/apport mode: 0644 state: present register: default_apport failed_when: default_apport.rc !=0 and not default_apport.rc == 257 """ @pytest.mark.parametrize( "rule_runner", (IgnoreErrorsRule,), indirect=["rule_runner"], ) def test_ignore_errors_true(rule_runner: RunFromText) -> None: """The task uses ignore_errors.""" results = rule_runner.run_playbook(IGNORE_ERRORS_TRUE) assert len(results) == 1 @pytest.mark.parametrize( "rule_runner", (IgnoreErrorsRule,), indirect=["rule_runner"], ) def test_ignore_errors_false(rule_runner: RunFromText) -> None: """The task uses ignore_errors: false, oddly enough.""" results = rule_runner.run_playbook(IGNORE_ERRORS_FALSE) assert len(results) == 0 @pytest.mark.parametrize( "rule_runner", (IgnoreErrorsRule,), indirect=["rule_runner"], ) def test_ignore_errors_check_mode(rule_runner: RunFromText) -> None: """The task uses ignore_errors: "{{ ansible_check_mode }}".""" results = rule_runner.run_playbook(IGNORE_ERRORS_CHECK_MODE) assert len(results) == 0 @pytest.mark.parametrize( "rule_runner", (IgnoreErrorsRule,), indirect=["rule_runner"], ) def test_ignore_errors_register(rule_runner: RunFromText) -> None: """The task uses ignore_errors: but output is registered and managed.""" results = rule_runner.run_playbook(IGNORE_ERRORS_REGISTER) assert len(results) == 0 @pytest.mark.parametrize( "rule_runner", (IgnoreErrorsRule,), indirect=["rule_runner"], ) def test_failed_when(rule_runner: RunFromText) -> None: """Instead of ignore_errors, this task uses failed_when.""" results = rule_runner.run_playbook(FAILED_WHEN) assert len(results) == 0 ansible-ansible-lint-c16f018/src/ansiblelint/rules/inline_env_var.md000066400000000000000000000016611477347356000256310ustar00rootroot00000000000000# inline-env-var This rule checks that playbooks do not set environment variables in the `ansible.builtin.command` module. You should set environment variables with the `ansible.builtin.shell` module or the `environment` keyword. ## Problematic Code ```yaml --- - name: Example playbook hosts: all tasks: - name: Set environment variable ansible.builtin.command: MY_ENV_VAR=my_value # <- Sets an environment variable in the command module. ``` ## Correct Code ```yaml --- - name: Example playbook hosts: all tasks: - name: Set environment variable ansible.builtin.shell: echo $MY_ENV_VAR environment: MY_ENV_VAR: my_value # <- Sets an environment variable with the environment keyword. ``` ```yaml --- - name: Example playbook hosts: all tasks: - name: Set environment variable ansible.builtin.shell: MY_ENV_VAR=my_value # <- Sets an environment variable with the shell module. ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/inline_env_var.py000066400000000000000000000051261477347356000256610ustar00rootroot00000000000000"""Implementation of inside-env-var rule.""" # Copyright (c) 2016 Will Thames # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from __future__ import annotations from typing import TYPE_CHECKING from ansiblelint.constants import FILENAME_KEY, LINE_NUMBER_KEY from ansiblelint.rules import AnsibleLintRule from ansiblelint.utils import Task, get_first_cmd_arg if TYPE_CHECKING: from ansiblelint.file_utils import Lintable class EnvVarsInCommandRule(AnsibleLintRule): """Command module does not accept setting environment variables inline.""" id = "inline-env-var" description = ( "Use ``environment:`` to set environment variables " "or use ``shell`` module which accepts both" ) severity = "VERY_HIGH" tags = ["command-shell", "idiom"] version_changed = "5.0.11" expected_args = [ "chdir", "creates", "executable", "removes", "stdin", "stdin_add_newline", "strip_empty_ends", "cmd", "__ansible_module__", "__ansible_module_original__", "_raw_params", LINE_NUMBER_KEY, FILENAME_KEY, ] def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: if task["action"]["__ansible_module__"] == "command": first_cmd_arg = get_first_cmd_arg(task) if not first_cmd_arg: return False return any( [arg not in self.expected_args for arg in task["action"]] + ["=" in first_cmd_arg], ) return False ansible-ansible-lint-c16f018/src/ansiblelint/rules/jinja.md000066400000000000000000000041011477347356000237160ustar00rootroot00000000000000# jinja This rule can report problems related to jinja2 string templates. The current version can report: - `jinja[spacing]` when there are no spaces between variables and operators, including filters, like `{{ var_name | filter }}`. This improves readability and makes it less likely to introduce typos. - `jinja[invalid]` when the jinja2 template is invalid, like `{{ {{ '1' }} }}`, which would result in a runtime error if you try to use it with Ansible, even if it does pass the Ansible syntax check. As jinja2 syntax is closely following Python one we aim to follow [black](https://black.readthedocs.io/en/stable/) formatting rules. If you are curious how black would reformat a small snippet feel free to visit [online black formatter](https://black.vercel.app/) site. Keep in mind to not include the entire jinja2 template, so instead of `{{ 1+2==3 }}`, do paste only `1+2==3`. In ansible, `changed_when`, `failed_when`, `until`, `when` are considered to use implicit jinja2 templating, meaning that they do not require `{{ }}`. Our rule will suggest the removal of the braces for these fields. ## Problematic code ```yaml --- - name: Some task vars: foo: "{{some|dict2items}}" # <-- jinja[spacing] bar: "{{ & }}" # <-- jinja[invalid] when: "{{ foo | bool }}" # <-- jinja[spacing] - 'when' has implicit templating ``` ## Correct code ```yaml --- - name: Some task vars: foo: "{{ some | dict2items }}" bar: "{{ '&' }}" when: foo | bool ``` ## Current limitations In its current form, this rule presents the following limitations: - Jinja2 blocks that have newlines in them will not be reformatted because we consider that the user deliberately wanted to format them in a particular way. - Jinja2 blocks that use tilde as a binary operation are ignored because black does not support tilde as a binary operator. Example: `{{ a ~ b }}`. - Jinja2 blocks that use dot notation with numbers are ignored because python and black do not allow it. Example: `{{ foo.0.bar }}` !!! note This rule can be automatically fixed using [`--fix`](../autofix.md) option. ansible-ansible-lint-c16f018/src/ansiblelint/rules/jinja.py000066400000000000000000001060611477347356000237560ustar00rootroot00000000000000"""Rule for checking content of jinja template strings.""" from __future__ import annotations import logging import os import re import sys from collections.abc import Mapping from dataclasses import dataclass from pathlib import Path from typing import TYPE_CHECKING, NamedTuple import black import jinja2 from ansible.errors import AnsibleError, AnsibleFilterError, AnsibleParserError from jinja2.exceptions import TemplateSyntaxError from ansiblelint.errors import RuleMatchTransformMeta from ansiblelint.file_utils import Lintable from ansiblelint.rules import AnsibleLintRule, TransformMixin from ansiblelint.runner import get_matches from ansiblelint.skip_utils import get_rule_skips_from_line from ansiblelint.text import has_jinja from ansiblelint.types import AnsibleTemplateSyntaxError from ansiblelint.utils import ( # type: ignore[attr-defined] Templar, parse_yaml_from_file, template, ) from ansiblelint.yaml_utils import deannotate, nested_items_path if TYPE_CHECKING: from ruamel.yaml.comments import CommentedMap, CommentedSeq from ansiblelint.config import Options from ansiblelint.errors import MatchError from ansiblelint.utils import Task _logger = logging.getLogger(__package__) KEYWORDS_WITH_IMPLICIT_TEMPLATE = ("changed_when", "failed_when", "until", "when") class Token(NamedTuple): """Token.""" lineno: int token_type: str value: str ignored_re = re.compile( "|".join( # noqa: FLY002 [ r"^Object of type method is not JSON serializable", r"^Unexpected templating type error occurred on", r"^obj must be a list of dicts or a nested dict$", r"^the template file (.*) could not be found for the lookup$", r"could not locate file in lookup", r"unable to locate collection", r"^Error in (.*)is undefined$", r"^Mandatory variable (.*) not defined.$", r"is undefined", r"Unrecognized type <> for (.*) filter $", # https://github.com/ansible/ansible-lint/issues/3155 r"^The '(.*)' test expects a dictionary$", # https://github.com/ansible/ansible-lint/issues/4338 r"An unhandled exception occurred while templating (.*). Error was a , original message: The (.*) test expects a dictionary$", ], ), flags=re.MULTILINE | re.DOTALL, ) @dataclass(frozen=True) class JinjaRuleTMetaSpacing(RuleMatchTransformMeta): """JinjaRule transform metadata. :param key: Key or index within the task :param value: Value of the key :param path: Path to the key :param fixed: Value with spacing fixed """ key: str | int value: str | int path: tuple[str | int, ...] fixed: str def __str__(self) -> str: """Return string representation.""" return f"{self.key}={self.value} at {self.path} fixed to {self.fixed}" class JinjaRule(AnsibleLintRule, TransformMixin): """Rule that looks inside jinja2 templates.""" id = "jinja" severity = "LOW" tags = ["formatting"] version_changed = "6.5.0" _ansible_error_re = re.compile( ( r"^(?P.*): (?P.*)\. String: (?P.*)$" r"|An unhandled exception occurred while templating '.*'\. Error was a .*, original message: (?P.*)" ), flags=re.MULTILINE, ) env = jinja2.Environment(trim_blocks=False) _tag2msg = { "invalid": "Syntax error in jinja2 template: {value}", "spacing": "Jinja2 spacing could be improved: {value} -> {reformatted}", } _ids = { "jinja[invalid]": "Invalid jinja2 syntax", "jinja[spacing]": "Jinja2 spacing could be improved", } def _msg(self, tag: str, value: str, reformatted: str) -> str: """Generate error message.""" return self._tag2msg[tag].format(value=value, reformatted=reformatted) # pylint: disable=too-many-locals def matchtask( self, task: Task, file: Lintable | None = None, ) -> list[MatchError]: result = [] try: for key, v, path in nested_items_path( task, ignored_keys=("block", "ansible.builtin.block", "ansible.legacy.block"), ): if isinstance(v, str): try: template( basedir=file.path.parent if file else Path(), value=v, variables=deannotate(task.get("vars", {})), fail_on_error=True, # we later decide which ones to ignore or not ) except AnsibleFilterError: bypass = True # ValueError RepresenterError except AnsibleError as exc: bypass = False orig_exc = ( exc.orig_exc if getattr(exc, "orig_exc", None) else exc ) orig_exc_message = getattr(orig_exc, "message", str(orig_exc)) match = self._ansible_error_re.match( getattr(orig_exc, "message", str(orig_exc)), ) if ignored_re.search(orig_exc_message) or isinstance( orig_exc, AnsibleParserError | TypeError, ): # An unhandled exception occurred while running the lookup plugin 'template'. Error was a , original message: the template file ... could not be found for the lookup. the template file ... could not be found for the lookup # ansible@devel (2.14) new behavior: # AnsibleError(TemplateSyntaxError): template error while templating string: Could not load "ipwrap": 'Invalid plugin FQCN (ansible.netcommon.ipwrap): unable to locate collection ansible.netcommon'. String: Foo {{ buildset_registry.host | ipwrap }}. Could not load "ipwrap": 'Invalid plugin FQCN (ansible.netcommon.ipwrap): unable to locate collection ansible.netcommon' bypass = True elif ( isinstance(orig_exc, AnsibleError | TemplateSyntaxError) and match ): error = match.group("error") detail = match.group("detail") nested_error = match.group("nested_error") if error and error.startswith( "template error while templating string", ): bypass = False elif detail and detail.startswith( "unable to locate collection", ): _logger.debug("Ignored AnsibleError: %s", exc) bypass = True elif nested_error and nested_error.startswith( "Unexpected templating type error occurred on", ): bypass = True else: bypass = False elif re.match(r"^lookup plugin (.*) not found$", exc.message): # lookup plugin 'template' not found bypass = True elif ( exc.message == "A template was resolved to an Omit scalar." or ( isinstance(orig_exc, AnsibleTemplateSyntaxError) and re.match( r"^Syntax error in template: No filter named '.*'.", exc.message, ) ) ): bypass = True # AnsibleError: template error while templating string: expected token ':', got '}'. String: {{ {{ '1' }} }} # AnsibleError: template error while templating string: unable to locate collection ansible.netcommon. String: Foo {{ buildset_registry.host | ipwrap }} if not bypass: lineno = task.get_error_line([*path, key]) result.append( self.create_matcherror( message=str(exc), lineno=lineno, data=v, filename=file, tag=f"{self.id}[invalid]", ), ) continue reformatted, details, tag = self.check_whitespace( v, key=key, lintable=file, ) if reformatted != v: lineno = task.get_error_line([*path, key]) result.append( self.create_matcherror( message=self._msg( tag=tag, value=v, reformatted=reformatted, ), lineno=lineno, data=v, details=details, filename=file, tag=f"{self.id}[{tag}]", transform_meta=JinjaRuleTMetaSpacing( key=key, value=v, path=tuple(path), fixed=reformatted, ), ), ) except Exception as exc: _logger.info("Exception in JinjaRule.matchtask: %s", exc) raise return result def matchyaml(self, file: Lintable) -> list[MatchError]: """Return matches for variables defined in vars files.""" raw_results: list[MatchError] = [] results: list[MatchError] = [] if str(file.kind) == "vars": data = parse_yaml_from_file(str(file.path)) if not isinstance(data, Mapping): return results for key, v, _path in nested_items_path(data): if isinstance(v, str): reformatted, details, tag = self.check_whitespace( v, key=key, lintable=file, ) if reformatted != v: results.append( self.create_matcherror( message=self._msg( tag=tag, value=v, reformatted=reformatted, ), data=v, details=details, filename=file, tag=f"{self.id}[{tag}]", ), ) if raw_results: lines = file.content.splitlines() for match in raw_results: # lineno starts with 1, not zero skip_list = get_rule_skips_from_line( line=lines[match.lineno - 1], lintable=file, ) if match.rule.id not in skip_list and match.tag not in skip_list: results.append(match) else: results.extend(super().matchyaml(file)) return results def lex(self, text: str) -> list[Token]: """Parse jinja template.""" # https://github.com/pallets/jinja/issues/1711 self.env.keep_trailing_newline = True self.env.lstrip_blocks = False self.env.trim_blocks = False self.env.autoescape = True self.env.newline_sequence = "\n" tokens = [ Token(lineno=t[0], token_type=t[1], value=t[2]) for t in self.env.lex(text) ] new_text = self.unlex(tokens) if text != new_text: _logger.debug( "Unable to perform full roundtrip lex-unlex on jinja template (expected when '-' modifier is used): {text} -> {new_text}", ) return tokens def unlex(self, tokens: list[Token]) -> str: """Return original text by compiling the lex output.""" result = "" last_lineno = 1 last_value = "" for lineno, _, value in tokens: if lineno > last_lineno and "\n" not in last_value: result += "\n" result += value last_lineno = lineno last_value = value return result # pylint: disable=too-many-locals def check_whitespace( self, text: str, key: str, lintable: Lintable | None = None, ) -> tuple[str, str, str]: """Check spacing inside given jinja2 template string. We aim to match Python Black formatting rules. :raises NotImplementedError: On few cases where valid jinja is not valid Python. :returns: (string, string, string) reformatted text, detailed error, error tag """ def cook(value: str, *, implicit: bool = False) -> str: """Prepare an implicit string for jinja parsing when needed.""" if not implicit: return value if value.startswith("{{") and value.endswith("}}"): # maybe we should make this an error? return value return f"{{{{ {value} }}}}" def uncook(value: str, *, implicit: bool = False) -> str: """Restore an string to original form when it was an implicit one.""" if not implicit: return value return value[3:-3] tokens = [] details = "" begin_types = ("variable_begin", "comment_begin", "block_begin") end_types = ("variable_end", "comment_end", "block_end") implicit = False # implicit templates do not have the {{ }} wrapping if ( key in KEYWORDS_WITH_IMPLICIT_TEMPLATE and lintable and lintable.kind in ( "playbook", "task", ) ): implicit = True text = cook(text, implicit=implicit) # don't try to lex strings that have no jinja inside them if not has_jinja(text): return text, "", "spacing" expr_str = None expr_type = None verb_skipped = True lineno = 1 try: for token in self.lex(text): if ( expr_type and expr_type.startswith("{%") and token.token_type in ("name", "whitespace") and not verb_skipped ): # on {% blocks we do not take first word as part of the expression tokens.append(token) if token.token_type != "whitespace": verb_skipped = True elif token.token_type in begin_types: tokens.append(token) expr_type = token.value # such {#, {{, {% expr_str = "" verb_skipped = False elif token.token_type in end_types and expr_str is not None: # process expression # pylint: disable=unsupported-membership-test if isinstance(expr_str, str) and "\n" in expr_str: raise NotImplementedError # noqa: TRY301 leading_spaces = " " * (len(expr_str) - len(expr_str.lstrip())) expr_str = leading_spaces + blacken(expr_str.lstrip()) if tokens[ -1 ].token_type != "whitespace" and not expr_str.startswith(" "): expr_str = " " + expr_str if not expr_str.endswith(" "): expr_str += " " tokens.append(Token(lineno, "data", expr_str)) tokens.append(token) expr_str = None expr_type = None elif expr_str is not None: expr_str += token.value else: tokens.append(token) lineno = token.lineno except jinja2.exceptions.TemplateSyntaxError as exc: return "", str(exc.message), "invalid" except (NotImplementedError, ValueError) as exc: # black is not able to recognize all valid jinja2 templates, so we # just ignore InvalidInput errors. # NotImplementedError is raised internally for expressions with # newlines, as we decided to not touch them yet. # These both are documented as known limitations. _logger.debug("Ignored jinja internal error %s", exc) return uncook(text, implicit=implicit), "", "spacing" # finalize reformatted = self.unlex(tokens) failed = reformatted != text reformatted = uncook(reformatted, implicit=implicit) details = ( f"Jinja2 template rewrite recommendation: `{reformatted}`." if failed else "" ) return reformatted, details, "spacing" def transform( self, match: MatchError, lintable: Lintable, data: CommentedMap | CommentedSeq | str, ) -> None: """Transform jinja2 errors. :param match: MatchError instance :param lintable: Lintable instance :param data: data to transform """ if match.tag == "jinja[spacing]": self._transform_spacing(match, data) def _transform_spacing( self, match: MatchError, data: CommentedMap | CommentedSeq | str, ) -> None: """Transform jinja2 spacing errors. The match error was found on a normalized task so we cannot compare the path instead we only compare the key and value, if the task has 2 identical keys with the exact same jinja spacing issue, we may transform them out of order :param match: MatchError instance :param data: data to transform """ if not isinstance(match.transform_meta, JinjaRuleTMetaSpacing): return if isinstance(data, str): return obj = self.seek(match.yaml_path, data) if obj is None: return ignored_keys = ("block", "ansible.builtin.block", "ansible.legacy.block") for key, value, path in nested_items_path( data_collection=obj, ignored_keys=ignored_keys, ): if key == match.transform_meta.key and value == match.transform_meta.value: if not path: continue for pth in path[:-1]: try: obj = obj[pth] except (KeyError, TypeError) as exc: err = f"Unable to transform {match.transform_meta}: {exc}" _logger.error(err) # noqa: TRY400 return try: obj[path[-1]][key] = match.transform_meta.fixed match.fixed = True except (KeyError, TypeError) as exc: err = f"Unable to transform {match.transform_meta}: {exc}" _logger.error(err) # noqa: TRY400 return def blacken(text: str) -> str: """Format Jinja2 template using black.""" return black.format_str( text, mode=black.FileMode(line_length=sys.maxsize, string_normalization=False), ).rstrip("\n") if "pytest" in sys.modules: from unittest import mock import pytest # pylint: disable=ungrouped-imports from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner from ansiblelint.transformer import Transformer def test_jinja_spacing_playbook() -> None: """Ensure that expected error lines are matching found linting error lines.""" # list unexpected error lines or non-matching error lines lineno_list = [33, 36, 39, 42, 45, 48, 74] lintable = Lintable("examples/playbooks/jinja-spacing.yml") collection = RulesCollection() collection.register(JinjaRule()) results = Runner(lintable, rules=collection).run() assert len(results) == len(lineno_list) for index, result in enumerate(results): assert result.tag == "jinja[spacing]" assert result.lineno == lineno_list[index] # error_lines_difference = list( # set(error_expected_lines).symmetric_difference(set(lint_error_lines)), # ) # assert len(error_lines_difference) == 0 def test_jinja_spacing_vars() -> None: """Ensure that expected error details are matching found linting error details.""" collection = RulesCollection() collection.register(JinjaRule()) lintable = Lintable("examples/playbooks/vars/jinja-spacing.yml") results = Runner(lintable, rules=collection).run() error_expected_lineno = [14, 15, 16, 17, 18, 19, 32] assert len(results) == len(error_expected_lineno) for idx, err in enumerate(results): assert err.lineno == error_expected_lineno[idx] @pytest.mark.parametrize( ("text", "expected", "tag"), ( pytest.param( "{{-x}}{#a#}{%1%}", "{{- x }}{# a #}{% 1 %}", "spacing", id="add-missing-space", ), pytest.param("", "", "spacing", id="1"), pytest.param("foo", "foo", "spacing", id="2"), pytest.param("{##}", "{# #}", "spacing", id="3"), # we want to keep leading spaces as they might be needed for complex multiline jinja files pytest.param("{# #}", "{# #}", "spacing", id="4"), pytest.param( "{{-aaa|xx }}foo\nbar{#some#}\n{%%}", "{{- aaa | xx }}foo\nbar{# some #}\n{% %}", "spacing", id="5", ), pytest.param( "Shell with jinja filter", "Shell with jinja filter", "spacing", id="6", ), pytest.param( "{{{'dummy_2':1}|true}}", "{{ {'dummy_2': 1} | true }}", "spacing", id="7", ), pytest.param("{{{foo:{}}}}", "{{ {foo: {}} }}", "spacing", id="8"), pytest.param( "{{ {'test': {'subtest': variable}} }}", "{{ {'test': {'subtest': variable}} }}", "spacing", id="9", ), pytest.param( "http://foo.com/{{\n case1 }}", "http://foo.com/{{\n case1 }}", "spacing", id="10", ), pytest.param("{{foo(123)}}", "{{ foo(123) }}", "spacing", id="11"), pytest.param("{{ foo(a.b.c) }}", "{{ foo(a.b.c) }}", "spacing", id="12"), # pytest.param( # "spacing", # ), pytest.param( "{{foo(x =['server_options'])}}", "{{ foo(x=['server_options']) }}", "spacing", id="14", ), pytest.param( '{{ [ "host", "NA"] }}', '{{ ["host", "NA"] }}', "spacing", id="15", ), pytest.param( "{{ {'dummy_2': {'nested_dummy_1': value_1,\n 'nested_dummy_2': value_2}} |\ncombine(dummy_1) }}", "{{ {'dummy_2': {'nested_dummy_1': value_1,\n 'nested_dummy_2': value_2}} |\ncombine(dummy_1) }}", "spacing", id="17", ), pytest.param("{{ & }}", "", "invalid", id="18"), pytest.param( "{{ good_format }}/\n{{- good_format }}\n{{- good_format -}}\n", "{{ good_format }}/\n{{- good_format }}\n{{- good_format -}}\n", "spacing", id="19", ), pytest.param( "{{ {'a': {'b': 'x', 'c': y}} }}", "{{ {'a': {'b': 'x', 'c': y}} }}", "spacing", id="20", ), pytest.param( "2*(1+(3-1)) is {{ 2 * {{ 1 + {{ 3 - 1 }}}} }}", "2*(1+(3-1)) is {{ 2 * {{1 + {{3 - 1}}}} }}", "spacing", id="21", ), pytest.param( '{{ "absent"\nif (v is version("2.8.0", ">=")\nelse "present" }}', "", "invalid", id="22", ), pytest.param( '{{lookup("x",y+"/foo/"+z+".txt")}}', '{{ lookup("x", y + "/foo/" + z + ".txt") }}', "spacing", id="23", ), pytest.param( "{{ x | map(attribute='value') }}", "{{ x | map(attribute='value') }}", "spacing", id="24", ), pytest.param( "{{ r(a= 1,b= True,c= 0.0,d= '') }}", "{{ r(a=1, b=True, c=0.0, d='') }}", "spacing", id="25", ), pytest.param("{{ r(1,[]) }}", "{{ r(1, []) }}", "spacing", id="26"), pytest.param( "{{ lookup([ddd ]) }}", "{{ lookup([ddd]) }}", "spacing", id="27", ), pytest.param( "{{ [ x ] if x is string else x }}", "{{ [x] if x is string else x }}", "spacing", id="28", ), pytest.param( "{% if a|int <= 8 -%} iptables {%- else -%} iptables-nft {%- endif %}", "{% if a | int <= 8 -%} iptables{%- else -%} iptables-nft{%- endif %}", "spacing", id="29", ), pytest.param( # "- 2" -> "-2", minus does not get separated when there is no left side "{{ - 2 }}", "{{ -2 }}", "spacing", id="30", ), pytest.param( # "-2" -> "-2", minus does get an undesired spacing "{{ -2 }}", "{{ -2 }}", "spacing", id="31", ), pytest.param( # array ranges do not have space added "{{ foo[2:4] }}", "{{ foo[2:4] }}", "spacing", id="32", ), pytest.param( # array ranges have the extra space removed "{{ foo[2: 4] }}", "{{ foo[2:4] }}", "spacing", id="33", ), pytest.param( # negative array index "{{ foo[-1] }}", "{{ foo[-1] }}", "spacing", id="34", ), pytest.param( # negative array index, repair "{{ foo[- 1] }}", "{{ foo[-1] }}", "spacing", id="35", ), pytest.param("{{ a +~'b' }}", "{{ a + ~'b' }}", "spacing", id="36"), pytest.param( "{{ (a[: -4] *~ b) }}", "{{ (a[:-4] * ~b) }}", "spacing", id="37", ), pytest.param("{{ [a,~ b] }}", "{{ [a, ~b] }}", "spacing", id="38"), # Not supported yet due to being accepted by black: pytest.param("{{ item.0.user }}", "{{ item.0.user }}", "spacing", id="39"), # Not supported by back, while jinja allows ~ to be binary operator: pytest.param("{{ a ~ b }}", "{{ a ~ b }}", "spacing", id="40"), pytest.param( "--format='{{'{{'}}.Size{{'}}'}}'", "--format='{{ '{{' }}.Size{{ '}}' }}'", "spacing", id="41", ), pytest.param( "{{ list_one + {{ list_two | max }} }}", "{{ list_one + {{list_two | max}} }}", "spacing", id="42", ), pytest.param( "{{ lookup('file' , '/tmp/non-existent', errors='ignore') }}", "{{ lookup('file', '/tmp/non-existent', errors='ignore') }}", "spacing", id="43", ), # https://github.com/ansible/ansible-lint/pull/3057 # since jinja 3.0.0, \r is converted to \n if the string has jinja in it pytest.param( "{{ 'foo' }}\r{{ 'bar' }}", "{{ 'foo' }}\n{{ 'bar' }}", "spacing", id="44", ), # if we do not have any jinja constructs, we should keep original \r # to match ansible behavior pytest.param( "foo\rbar", "foo\rbar", "spacing", id="45", ), ), ) def test_jinja(text: str, expected: str, tag: str) -> None: """Tests our ability to spot spacing errors inside jinja2 templates.""" rule = JinjaRule() reformatted, details, returned_tag = rule.check_whitespace( text, key="name", lintable=Lintable("playbook.yml"), ) assert tag == returned_tag, details assert expected == reformatted @pytest.mark.parametrize( ("text", "expected", "tag"), ( pytest.param( "1+2", "1 + 2", "spacing", id="0", ), pytest.param( "- 1", "-1", "spacing", id="1", ), # Ensure that we do not choke with double templating on implicit # and instead we remove them braces. pytest.param("{{ o | bool }}", "o | bool", "spacing", id="2"), ), ) def test_jinja_implicit(text: str, expected: str, tag: str) -> None: """Tests our ability to spot spacing errors implicit jinja2 templates.""" rule = JinjaRule() # implicit jinja2 are working only inside playbooks and tasks lintable = Lintable(name="playbook.yml", kind="playbook") reformatted, details, returned_tag = rule.check_whitespace( text, key="when", lintable=lintable, ) assert tag == returned_tag, details assert expected == reformatted @pytest.mark.parametrize( ("lintable", "matches"), (pytest.param("examples/playbooks/vars/rule_jinja_vars.yml", 0, id="0"),), ) def test_jinja_file(lintable: str, matches: int) -> None: """Tests our ability to process var filesspot spacing errors.""" collection = RulesCollection() collection.register(JinjaRule()) errs = Runner(lintable, rules=collection).run() assert len(errs) == matches for err in errs: assert isinstance(err, JinjaRule) assert errs[0].tag == "jinja[invalid]" assert errs[0].rule.id == "jinja" def test_jinja_invalid() -> None: """Tests our ability to spot spacing errors inside jinja2 templates.""" collection = RulesCollection() collection.register(JinjaRule()) success = "examples/playbooks/rule-jinja-fail.yml" errs = Runner(success, rules=collection).run() assert len(errs) == 2 assert errs[0].tag == "jinja[spacing]" assert errs[0].rule.id == "jinja" assert errs[0].lineno == 9 assert errs[1].tag == "jinja[invalid]" assert errs[1].rule.id == "jinja" assert errs[1].lineno in [9, 10] # 2.19 has better line identification def test_jinja_valid() -> None: """Tests our ability to parse jinja, even when variables may not be defined.""" collection = RulesCollection() collection.register(JinjaRule()) success = "examples/playbooks/rule-jinja-pass.yml" errs = Runner(success, rules=collection).run() assert len(errs) == 0 @mock.patch.dict(os.environ, {"ANSIBLE_LINT_WRITE_TMP": "1"}, clear=True) def test_jinja_transform( config_options: Options, default_rules_collection: RulesCollection, ) -> None: """Test transform functionality for jinja rule.""" playbook = Path("examples/playbooks/rule-jinja-before.yml") config_options.write_list = ["all"] config_options.lintables = [str(playbook)] runner_result = get_matches( rules=default_rules_collection, options=config_options, ) transformer = Transformer(result=runner_result, options=config_options) transformer.run() matches = runner_result.matches assert len(matches) == 2 orig_content = playbook.read_text(encoding="utf-8") expected_content = playbook.with_suffix( f".transformed{playbook.suffix}", ).read_text(encoding="utf-8") transformed_content = playbook.with_suffix(f".tmp{playbook.suffix}").read_text( encoding="utf-8", ) assert orig_content != transformed_content assert expected_content == transformed_content playbook.with_suffix(f".tmp{playbook.suffix}").unlink() def test_jinja_nested_var_errors() -> None: """Tests our ability to handle nested var errors from jinja2 templates.""" def _do_template(*args, **kwargs): # type: ignore[no-untyped-def] # Templar.do_template has no type hint data = args[1] if data != "{{ 12 | random(seed=inventory_hostname) }}": return do_template(*args, **kwargs) # type: ignore[no-untyped-call] msg = "Unexpected templating type error occurred on (foo): bar" raise AnsibleError(str(msg)) # type: ignore[no-untyped-call] do_template = Templar.do_template collection = RulesCollection() collection.register(JinjaRule()) lintable = Lintable("examples/playbooks/jinja-nested-vars.yml") with mock.patch.object(Templar, "do_template", _do_template): results = Runner(lintable, rules=collection).run() assert len(results) == 0 ansible-ansible-lint-c16f018/src/ansiblelint/rules/key_order.md000066400000000000000000000044541477347356000246210ustar00rootroot00000000000000# key-order This rule recommends reordering key names in ansible content to make code easier to maintain and less prone to errors. Here are some examples of common ordering checks done for tasks and handlers: - `name` must always be the first key for plays, tasks and handlers - on tasks, the `block`, `rescue` and `always` keys must be the last keys, as this would avoid accidental miss-indentation errors between the last task and the parent level. ## Problematic code ```yaml --- - hosts: localhost name: This is a playbook # <-- name key should be the first one tasks: - name: A block block: - name: Display a message debug: msg: "Hello world!" when: true # <-- when key should be before block ``` ## Correct code ```yaml --- - name: This is a playbook hosts: localhost tasks: - name: A block when: true block: - name: Display a message debug: msg: "Hello world!" ``` ## Reasoning Making decisions about the optimal order of keys for ansible tasks or plays is no easy task, as we had a huge number of combinations to consider. This is also the reason why we started with a minimal sorting rule (name to be the first), and aimed to gradually add more fields later, and only when we find the proofs that one approach is likely better than the other. ### Why I no longer can put `when` after a `block`? Try to remember that in real life, `block/rescue/always` have the habit to grow due to the number of tasks they host inside, making them exceed what a single screen. This would move the `when` task further away from the rest of the task properties. A `when` from the last task inside the block can easily be confused as being at the block level, or the reverse. When tasks are moved from one location to another, there is a real risk of moving the block level when with it. By putting the `when` before the `block`, we avoid that kind of risk. The same risk applies to any simple property at the task level, so that is why we concluded that the block keys must be the last ones. Another common practice was to put `tags` as the last property. Still, for the same reasons, we decided that they should not be put after block keys either. !!! note This rule can be automatically fixed using [`--fix`](../autofix.md) option. ansible-ansible-lint-c16f018/src/ansiblelint/rules/key_order.py000066400000000000000000000153631477347356000246520ustar00rootroot00000000000000"""All tasks should be have name come first.""" from __future__ import annotations import functools import sys from dataclasses import dataclass from typing import TYPE_CHECKING, Any from ansiblelint.constants import ANNOTATION_KEYS from ansiblelint.errors import MatchError, RuleMatchTransformMeta from ansiblelint.rules import AnsibleLintRule, TransformMixin if TYPE_CHECKING: from ruamel.yaml.comments import CommentedMap, CommentedSeq from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task SORTER_TASKS = ( "name", # "__module__", # "action", # "args", None, # <-- None include all modules that not using action and * # "when", # "notify", # "tags", "block", "rescue", "always", ) def get_property_sort_index(name: str) -> int: """Return the index of the property in the sorter.""" a_index = -1 for i, v in enumerate(SORTER_TASKS): if v == name: return i if v is None: a_index = i return a_index def task_property_sorter(property1: str, property2: str) -> int: """Sort task properties based on SORTER.""" v_1 = get_property_sort_index(property1) v_2 = get_property_sort_index(property2) return (v_1 > v_2) - (v_1 < v_2) @dataclass(frozen=True) class KeyOrderTMeta(RuleMatchTransformMeta): """Key Order transform metadata. :param fixed: tuple with updated key order """ fixed: tuple[str | int, ...] def __str__(self) -> str: # pragma: no cover """Return string representation.""" return f"Fixed to {self.fixed}" class KeyOrderRule(AnsibleLintRule, TransformMixin): """Ensure specific order of keys in mappings.""" id = "key-order" severity = "LOW" tags = ["formatting"] version_changed = "6.6.2" needs_raw_task = True _ids = { "key-order[task]": "You can improve the task key order", } def matchplay(self, file: Lintable, data: dict[str, Any]) -> list[MatchError]: """Return matches found for a specific play (entry in playbook).""" result: list[MatchError] = [] if file.kind != "playbook": return result keys = [str(key) for key, val in data.items() if key not in ANNOTATION_KEYS] sorted_keys = sorted(keys, key=functools.cmp_to_key(task_property_sorter)) if keys != sorted_keys: result.append( self.create_matcherror( f"You can improve the play key order to: {', '.join(sorted_keys)}", filename=file, tag=f"{self.id}[play]", transform_meta=KeyOrderTMeta(fixed=tuple(sorted_keys)), data=data, ), ) return result def matchtask( self, task: Task, file: Lintable | None = None, ) -> list[MatchError]: result = [] raw_task = task["__raw_task__"] keys = [str(key) for key in raw_task if not key.startswith("_")] sorted_keys = sorted(keys, key=functools.cmp_to_key(task_property_sorter)) if keys != sorted_keys: result.append( self.create_matcherror( f"You can improve the task key order to: {', '.join(sorted_keys)}", filename=file, tag="key-order[task]", transform_meta=KeyOrderTMeta(fixed=tuple(sorted_keys)), ), ) return result def transform( self, match: MatchError, lintable: Lintable, data: CommentedMap | CommentedSeq | str, ) -> None: if not isinstance(match.transform_meta, KeyOrderTMeta): # pragma: no cover return if match.tag == f"{self.id}[play]": play = self.seek(match.yaml_path, data) for key in match.transform_meta.fixed: # other transformation might change the key if key in play: play[key] = play.pop(key) match.fixed = True if match.tag == f"{self.id}[task]": task = self.seek(match.yaml_path, data) for key in match.transform_meta.fixed: # other transformation might change the key if key in task: task[key] = task.pop(key) match.fixed = True # 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/rule-key-order-pass.yml", 0, id="pass"), pytest.param("examples/playbooks/rule-key-order-fail.yml", 6, id="fail"), ), ) def test_key_order_rule( 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.rule.id == "key-order" @pytest.mark.parametrize( ("properties", "expected"), ( pytest.param([], []), pytest.param(["block", "name"], ["name", "block"]), pytest.param( ["block", "name", "action", "..."], ["name", "action", "...", "block"], ), ), ) def test_key_order_property_sorter( properties: list[str], expected: list[str], ) -> None: """Test the task property sorter.""" result = sorted(properties, key=functools.cmp_to_key(task_property_sorter)) assert expected == result @pytest.mark.parametrize( ("key", "order"), ( pytest.param("name", 0), pytest.param("action", 1), pytest.param("foobar", SORTER_TASKS.index(None)), pytest.param("block", len(SORTER_TASKS) - 3), pytest.param("rescue", len(SORTER_TASKS) - 2), pytest.param("always", len(SORTER_TASKS) - 1), ), ) def test_key_order_property_sort_index(key: str, order: int) -> None: """Test sorting index.""" assert get_property_sort_index(key) == order @pytest.mark.parametrize( ("prop1", "prop2", "result"), ( pytest.param("name", "block", -1), pytest.param("block", "name", 1), pytest.param("block", "block", 0), ), ) def test_key_order_property_sortfunc(prop1: str, prop2: str, result: int) -> None: """Test sorting function.""" assert task_property_sorter(prop1, prop2) == result ansible-ansible-lint-c16f018/src/ansiblelint/rules/latest.md000066400000000000000000000020711477347356000241230ustar00rootroot00000000000000# latest The `latest` rule checks that module arguments like those used for source control checkout do not have arguments that might generate different results based on context. This more generic rule replaced two older rules named `git-latest` and `hg-latest`. We are aware that there are genuine cases where getting the tip of the main branch is not accidental. For these cases, just add a comment such as `# noqa: latest` to the same line to prevent it from triggering. ## Possible errors messages: - `latest[git]` - `latest[hg]` ## Problematic code ```yaml --- - name: Example for `latest` rule hosts: localhost tasks: - name: Risky use of git module ansible.builtin.git: repo: "https://github.com/ansible/ansible-lint" version: HEAD # <-- HEAD value is triggering the rule ``` ## Correct code ```yaml --- - name: Example for `latest` rule hosts: localhost tasks: - name: Safe use of git module ansible.builtin.git: repo: "https://github.com/ansible/ansible-lint" version: abcd1234... # <-- that is safe ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/latest.py000066400000000000000000000027061477347356000241600ustar00rootroot00000000000000"""Implementation of latest rule.""" from __future__ import annotations from typing import TYPE_CHECKING from ansiblelint.rules import AnsibleLintRule if TYPE_CHECKING: from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task class LatestRule(AnsibleLintRule): """Result of the command may vary on subsequent runs.""" id = "latest" description = ( "All version control checkouts must point to " "an explicit commit or tag, not just ``latest``" ) severity = "MEDIUM" tags = ["idempotency"] version_changed = "6.5.2" _ids = { "latest[git]": "Use a commit hash or tag instead of 'latest' for git", "latest[hg]": "Use a commit hash or tag instead of 'latest' for hg", } def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str | MatchError: """Check if module args are safe.""" if ( task["action"]["__ansible_module__"] == "git" and task["action"].get("version", "HEAD") == "HEAD" ): return self.create_matcherror(tag="latest[git]", filename=file) if ( task["action"]["__ansible_module__"] == "hg" and task["action"].get("revision", "default") == "default" ): # pragma: no cover return self.create_matcherror(tag="latest[hg]", filename=file) return False ansible-ansible-lint-c16f018/src/ansiblelint/rules/literal_compare.md000066400000000000000000000014541477347356000257750ustar00rootroot00000000000000# literal-compare This rule checks for literal comparison with the `when` clause. Literal comparison, like `when: var == True`, is unnecessarily complex. Use `when: var` to keep your playbooks simple. Similarly, a check like `when: var != True` or `when: var == False` should be replaced with `when: not var`. ## Problematic Code ```yaml --- - name: Example playbook hosts: all tasks: - name: Print environment variable to stdout ansible.builtin.command: echo $MY_ENV_VAR when: ansible_os_family == True # <- Adds complexity to your playbook. ``` ## Correct Code ```yaml --- - name: Example playbook hosts: all tasks: - name: Print environment variable to stdout ansible.builtin.command: echo $MY_ENV_VAR when: ansible_os_family # <- Keeps your playbook simple. ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/literal_compare.py000066400000000000000000000047421477347356000260300ustar00rootroot00000000000000"""Implementation of the literal-compare rule.""" # Copyright (c) 2016, Will Thames and contributors # Copyright (c) 2018-2021, Ansible Project from __future__ import annotations import re import sys from typing import TYPE_CHECKING from ansiblelint.rules import AnsibleLintRule from ansiblelint.yaml_utils import nested_items_path if TYPE_CHECKING: from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task class ComparisonToLiteralBoolRule(AnsibleLintRule): """Don't compare to literal True/False.""" id = "literal-compare" description = ( "Use ``when: var`` rather than ``when: var == True`` " "(or conversely ``when: not var``)" ) severity = "HIGH" tags = ["idiom"] version_changed = "4.0.0" literal_bool_compare = re.compile(r"[=!]= ?(True|true|False|false)") def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: for k, v, _ in nested_items_path(task): if k == "when": if isinstance(v, str): if self.literal_bool_compare.search(v): return True elif isinstance(v, bool): pass else: for item in v: if isinstance(item, str) and self.literal_bool_compare.search( item, ): return True return False 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/rule_literal_compare_fail.yml", 3, id="fail", ), pytest.param( "examples/playbooks/rule_literal_compare_pass.yml", 0, id="pass", ), ), ) def test_literal_compare( default_rules_collection: RulesCollection, test_file: str, failures: int, ) -> None: """Test rule matches.""" # Enable checking of loop variable prefixes in roles results = Runner(test_file, rules=default_rules_collection).run() for result in results: assert result.rule.id == "literal-compare" assert len(results) == failures ansible-ansible-lint-c16f018/src/ansiblelint/rules/loop_var_prefix.md000066400000000000000000000040761477347356000260340ustar00rootroot00000000000000# loop-var-prefix This rule avoids conflicts with nested looping tasks by enforcing an individual variable name in loops. Ansible defaults to `item` as the loop variable. You can use `loop_var` to rename it. Optionally require a prefix on the variable name. The prefix can be configured via the `` setting. This rule can produce the following messages: - `loop-var-prefix[missing]` - Replace any unsafe implicit `item` loop variable by adding `loop_var: ...`. - `loop-var-prefix[wrong]` - Ensure the loop variable starts with ``. This rule originates from the [Naming parameters section of Ansible Best Practices guide][cop314]. ## Settings You can change the behavior of this rule by overriding its default regular expression used to check loop variable naming. Keep in mind that the `{role}` part is replaced with the inferred role name when applicable. ```yaml # .ansible-lint loop_var_prefix: "^(__|{role}_)" ``` This is an opt-in rule. You must enable it in your Ansible-lint configuration as follows: ```yaml enable_list: - loop-var-prefix ``` ## Problematic Code ```yaml --- - name: Example playbook hosts: localhost tasks: - name: Does not set a variable name for loop variables. ansible.builtin.debug: var: item # <- When in a nested loop, "item" is ambiguous loop: - foo - bar - name: Sets a variable name that doesn't start with . ansible.builtin.debug: var: zz_item loop: - foo - bar loop_control: loop_var: zz_item # <- zz is not the role name so the prefix is wrong ``` ## Correct Code ```yaml --- - name: Example playbook hosts: localhost tasks: - name: Sets a unique variable_name with role as prefix for loop variables. ansible.builtin.debug: var: myrole_item loop: - foo - bar loop_control: loop_var: myrole_item # <- Unique variable name with role as prefix ``` [cop314]: https://redhat-cop.github.io/automation-good-practices/#_naming_parameters ansible-ansible-lint-c16f018/src/ansiblelint/rules/loop_var_prefix.py000066400000000000000000000077601477347356000260670ustar00rootroot00000000000000"""Optional Ansible-lint rule to enforce use of prefix on role loop vars.""" from __future__ import annotations import re import sys from typing import TYPE_CHECKING from ansiblelint.config import LOOP_VAR_PREFIX, options from ansiblelint.rules import AnsibleLintRule from ansiblelint.text import toidentifier if TYPE_CHECKING: from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task class RoleLoopVarPrefix(AnsibleLintRule): """Role loop_var should use configured prefix.""" id = "loop-var-prefix" link = ( "https://docs.ansible.com/ansible/latest/playbook_guide/" "playbooks_loops.html#defining-inner-and-outer-variable-names-with-loop-var" ) description = """\ Looping inside roles has the risk of clashing with loops from user-playbooks.\ """ tags = ["idiom"] prefix = re.compile(r"") severity = "MEDIUM" _ids = { "loop-var-prefix[wrong]": "Loop variable name does not match regex.", "loop-var-prefix[missing]": "Replace unsafe implicit `item` loop variable.", } version_changed = "6.7.0" def matchtask( self, task: Task, file: Lintable | None = None, ) -> list[MatchError]: """Return matches for a task.""" if not file or not file.role or not options.loop_var_prefix: return [] self.prefix = re.compile( options.loop_var_prefix.format(role=toidentifier(file.role)), ) has_loop = False if "loop" in task.raw_task: data = task.raw_task["loop"] has_loop = True else: for key in task.raw_task: if key.startswith("with_"): data = key has_loop = True break if has_loop: loop_control = task.raw_task.get("loop_control", {}) loop_var = loop_control.get("loop_var", "") if loop_var: if not self.prefix.match(loop_var): return [ self.create_matcherror( message=f"Loop variable name does not match /{options.loop_var_prefix}/ regex, where role={toidentifier(file.role)}.", filename=file, data=loop_var, tag="loop-var-prefix[wrong]", ), ] else: return [ self.create_matcherror( message=f"Replace unsafe implicit `item` loop variable by adding a `loop_var` that is matching /{options.loop_var_prefix}/ regex.", filename=file, data=data, tag="loop-var-prefix[missing]", ), ] return [] # 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/roles/loop_var_prefix/tasks/pass.yml", 0, id="pass", ), pytest.param( "examples/playbooks/roles/loop_var_prefix/tasks/fail.yml", 6, id="fail", ), ), ) def test_loop_var_prefix( default_rules_collection: RulesCollection, test_file: str, failures: int, ) -> None: """Test rule matches.""" # Enable checking of loop variable prefixes in roles options.loop_var_prefix = LOOP_VAR_PREFIX results = Runner(test_file, rules=default_rules_collection).run() for result in results: assert result.rule.id == RoleLoopVarPrefix().id assert len(results) == failures ansible-ansible-lint-c16f018/src/ansiblelint/rules/meta_incorrect.md000066400000000000000000000011751477347356000256310ustar00rootroot00000000000000# meta-incorrect This rule checks role metadata for fields with undefined or default values. Always set appropriate values for the following metadata fields in the `meta/main.yml` file: - `author` - `description` - `company` - `license` ## Problematic Code ```yaml --- # Metadata fields for the role contain default values. galaxy_info: author: your name description: your role description company: your company (optional) license: license (GPL-2.0-or-later, MIT, etc) ``` ## Correct Code ```yaml --- galaxy_info: author: Leroy Jenkins description: This role will set you free. company: Red Hat license: Apache ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/meta_incorrect.py000066400000000000000000000047011477347356000256570ustar00rootroot00000000000000"""Implementation of meta-incorrect rule.""" # 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.errors import MatchError from ansiblelint.file_utils import Lintable class MetaChangeFromDefaultRule(AnsibleLintRule): """meta/main.yml default values should be changed.""" id = "meta-incorrect" field_defaults = [ ("author", "your name"), ("description", "your description"), ("company", "your company (optional)"), ("license", "license (GPLv2, CC-BY, etc)"), ("license", "license (GPL-2.0-or-later, MIT, etc)"), ] values = ", ".join(sorted({f[0] for f in field_defaults})) description = ( f"You should set appropriate values in meta/main.yml for these fields: {values}" ) severity = "HIGH" tags = ["metadata"] version_changed = "4.0.0" def matchyaml(self, file: Lintable) -> list[MatchError]: if file.kind != "meta" or not file.data: return [] galaxy_info = file.data.get("galaxy_info", None) if not galaxy_info: return [] results = [] for field, default in self.field_defaults: value = galaxy_info.get(field, None) if value and value == default: results.append( self.create_matcherror( filename=file, message=f"Should change default metadata: {field}", data=file.data, ), ) return results if "pytest" in sys.modules: from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner def test_default_galaxy_info( default_rules_collection: RulesCollection, ) -> None: """Test for meta-incorrect.""" results = Runner( "examples/roles/meta_incorrect_fail", rules=default_rules_collection, ).run() for result in results: assert result.rule.id == "meta-incorrect" assert len(results) == 4 assert "Should change default metadata: author" in str(results) assert "Should change default metadata: description" in str(results) assert "Should change default metadata: company" in str(results) assert "Should change default metadata: license" in str(results) ansible-ansible-lint-c16f018/src/ansiblelint/rules/meta_no_tags.md000066400000000000000000000007041477347356000252700ustar00rootroot00000000000000# meta-no-tags This rule checks role metadata for tags with special characters. Always use lowercase numbers and letters for tags in the `meta/main.yml` file. ## Problematic Code ```yaml --- # Metadata tags contain upper-case letters and special characters. galaxy_info: galaxy_tags: [MyTag#1, MyTag&^-] ``` ## Correct Code ```yaml --- # Metadata tags contain only lowercase letters and numbers. galaxy_info: galaxy_tags: [mytag1, mytag2] ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/meta_no_tags.py000066400000000000000000000117001477347356000253160ustar00rootroot00000000000000"""Implementation of meta-no-tags rule.""" from __future__ import annotations import re import sys from pathlib import Path from typing import TYPE_CHECKING from ansiblelint.rules import AnsibleLintRule # Copyright (c) 2018, Ansible Project if TYPE_CHECKING: from typing import Any from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.testing import RunFromText class MetaTagValidRule(AnsibleLintRule): """Tags must contain lowercase letters and digits only.""" id = "meta-no-tags" description = ( "Tags must contain lowercase letters and digits only, " "and ``galaxy_tags`` is expected to be a list" ) severity = "HIGH" tags = ["metadata"] version_changed = "4.0.0" TAG_REGEXP = re.compile(r"^[a-z0-9]+$") def matchyaml(self, file: Lintable) -> list[MatchError]: """Find violations inside meta files.""" if file.kind != "meta" or not file.data: return [] galaxy_info = file.data.get("galaxy_info", None) if not galaxy_info: return [] tags = [] results = [] if "galaxy_tags" in galaxy_info: if isinstance(galaxy_info["galaxy_tags"], list): tags += galaxy_info["galaxy_tags"] else: results.append( self.create_matcherror( "Expected 'galaxy_tags' to be a list", filename=file, ), ) if "categories" in galaxy_info: results.append( self.create_matcherror( "Use 'galaxy_tags' rather than 'categories'", filename=file, ), ) if isinstance(galaxy_info["categories"], list): tags += galaxy_info["categories"] else: results.append( self.create_matcherror( "Expected 'categories' to be a list", filename=file, ), ) for tag in tags: msg = self.shortdesc if not isinstance(tag, str): results.append( self.create_matcherror( f"Tags must be strings: '{tag}'", filename=file, ), ) continue if not re.match(self.TAG_REGEXP, tag): results.append( self.create_matcherror( message=f"{msg}, invalid: '{tag}'", 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 @pytest.mark.parametrize( "rule_runner", (MetaTagValidRule,), indirect=["rule_runner"], ) def test_valid_tag_rule(rule_runner: RunFromText) -> None: """Test rule matches.""" results = rule_runner.run( Path("examples/roles/meta_no_tags_valid/meta/main.yml"), ) assert "Use 'galaxy_tags' rather than 'categories'" in str(results), results assert "Expected 'categories' to be a list" in str(results) assert "invalid: 'my s q l'" in str(results) assert "invalid: 'MYTAG'" in str(results) @pytest.mark.parametrize( "rule_runner", (MetaTagValidRule,), indirect=["rule_runner"], ) def test_meta_not_tags(rule_runner: Any) -> None: """Test rule matches.""" results = rule_runner.run( "examples/roles/meta_no_tags_galaxy_info/meta/main.yml", ) assert results == [] @pytest.mark.parametrize( "rule_runner", (MetaTagValidRule,), indirect=["rule_runner"], ) def test_no_galaxy_tags_list(rule_runner: Any) -> None: """Test rule matches.""" results = rule_runner.run("examples/roles/meta_tags_no_list/meta/main.yml") assert "Expected 'galaxy_tags' to be a list" in str(results) @pytest.mark.parametrize( "rule_runner", (MetaTagValidRule,), indirect=["rule_runner"], ) def test_galaxy_categories_as_list(rule_runner: Any) -> None: """Test rule matches.""" results = rule_runner.run( "examples/roles/meta_categories_as_list/meta/main.yml", ) assert "Use 'galaxy_tags' rather than 'categories'" in str(results), results assert "Expected 'categories' to be a list" not in str(results) @pytest.mark.parametrize( "rule_runner", (MetaTagValidRule,), indirect=["rule_runner"], ) def test_tags_not_a_string(rule_runner: Any) -> None: """Test rule matches.""" results = rule_runner.run("examples/roles/meta_tags_not_a_string/meta/main.yml") assert "Tags must be strings" in str(results) ansible-ansible-lint-c16f018/src/ansiblelint/rules/meta_runtime.md000066400000000000000000000026051477347356000253230ustar00rootroot00000000000000# meta-runtime This rule checks the meta/runtime.yml `requires_ansible` key against the list of currently supported versions of ansible-core. This rule can produce messages such as: - `meta-runtime[unsupported-version]` - `requires_ansible` key must refer to a currently supported version such as: >=2.15.0, >=2.16.0, >=2.17.0, >=2.18.0 - `meta-runtime[invalid-version]` - `requires_ansible` is not a valid requirement specification Please note that the linter will allow only a full version of Ansible such `2.16.0` and not allow their short form, like `2.16`. This is a safety measure for asking authors to mention an explicit version that they tested with. Over the years we spotted multiple problems caused by the use of the short versions, users ended up trying an outdated version that was never tested against by the collection maintainer. ## Problematic code ```yaml # runtime.yml --- requires_ansible: ">=2.9" ``` ```yaml # runtime.yml --- requires_ansible: "2.17" ``` ## Correct code ```yaml # runtime.yml --- requires_ansible: ">=2.17.0" ``` ## Configuration In addition to the internal list of supported Ansible versions, users can configure additional values. This allows those that want to maintain content that requires a version of ansible-core that is already out of support. ```yaml # Also recognize these versions of Ansible as supported: supported_ansible_also: - "2.14" ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/meta_runtime.py000066400000000000000000000121331477347356000253500ustar00rootroot00000000000000"""Implementation of meta-runtime rule.""" from __future__ import annotations import sys from typing import TYPE_CHECKING from packaging.specifiers import SpecifierSet 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 CheckRequiresAnsibleVersion(AnsibleLintRule): """Required ansible version in meta/runtime.yml must be a supported version.""" id = "meta-runtime" description = ( "The ``requires_ansible`` key in runtime.yml must specify " "a supported platform version of ansible-core and be a valid version value " "in x.y.z format." ) severity = "VERY_HIGH" tags = ["metadata"] version_changed = "6.11.0" _ids = { "meta-runtime[unsupported-version]": "'requires_ansible' key must refer to a currently supported version", "meta-runtime[invalid-version]": "'requires_ansible' is not a valid requirement specification", } def matchyaml(self, file: Lintable) -> list[MatchError]: """Find violations inside meta files. :param file: Input lintable file that is a match for `meta-runtime` :returns: List of errors matched to the input file """ results = [] if file.kind != "meta-runtime": return [] requires_ansible = None if file.data and isinstance(file.data, dict): requires_ansible = file.data.get("requires_ansible", None) if requires_ansible: if self.options and not any( version in requires_ansible for version in self.options.supported_ansible ): supported_ansible = [f">={x}0" for x in self.options.supported_ansible] msg = f"'requires_ansible' key must refer to a currently supported version such as: {', '.join(supported_ansible)}" results.append( self.create_matcherror( message=msg, tag="meta-runtime[unsupported-version]", filename=file, ), ) try: SpecifierSet(requires_ansible) except ValueError: results.append( self.create_matcherror( message="'requires_ansible' is not a valid requirement specification", tag="meta-runtime[invalid-version]", 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 # pylint: disable=ungrouped-imports from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner @pytest.mark.parametrize( ("test_file", "failures", "tags"), ( pytest.param( "examples/meta_runtime_version_checks/pass_0/meta/runtime.yml", 0, "meta-runtime[unsupported-version]", id="pass0", ), pytest.param( "examples/meta_runtime_version_checks/fail_0/meta/runtime.yml", 1, "meta-runtime[unsupported-version]", id="fail0", ), pytest.param( "examples/meta_runtime_version_checks/fail_1/meta/runtime.yml", 1, "meta-runtime[unsupported-version]", id="fail1", ), pytest.param( "examples/meta_runtime_version_checks/fail_2/meta/runtime.yml", 1, "meta-runtime[invalid-version]", id="fail2", ), ), ) def test_default_meta_supported_version( default_rules_collection: RulesCollection, test_file: str, failures: int, tags: str, ) -> None: """Test for default supported ansible versions.""" default_rules_collection.register(CheckRequiresAnsibleVersion()) results = Runner(test_file, rules=default_rules_collection).run() for result in results: assert result.rule.id == CheckRequiresAnsibleVersion().id assert result.tag == tags assert len(results) == failures @pytest.mark.parametrize( ("test_file", "failures"), ( pytest.param( "examples/meta_runtime_version_checks/pass_1/meta/runtime.yml", 0, id="pass1", ), ), ) def test_added_meta_supported_version( default_rules_collection: RulesCollection, test_file: str, failures: int, ) -> None: """Test for added supported ansible versions in the config.""" default_rules_collection.register(CheckRequiresAnsibleVersion()) default_rules_collection.options.supported_ansible_also = ["2.9"] results = Runner(test_file, rules=default_rules_collection).run() assert len(results) == failures ansible-ansible-lint-c16f018/src/ansiblelint/rules/meta_video_links.md000066400000000000000000000017071477347356000261500ustar00rootroot00000000000000# meta-video-links This rule checks formatting for video links in metadata. Always use dictionaries for items in the `meta/main.yml` file. Items in the `video_links` section must be in a dictionary and use the following keys: - `url` - `title` The value of the `url` key must be a shared link from YouTube, Vimeo, or Google Drive. ## Problematic Code ```yaml --- galaxy_info: video_links: - https://www.youtube.com/watch?v=aWmRepTSFKs&feature=youtu.be # <- Does not use the url key. - my_bad_key: https://www.youtube.com/watch?v=aWmRepTSFKs&feature=youtu.be # <- Uses an unsupported key. title: Incorrect key. - url: www.acme.com/vid # <- Uses an unsupported url format. title: Incorrect url format. ``` ## Correct Code ```yaml --- galaxy_info: video_links: - url: https://www.youtube.com/watch?v=aWmRepTSFKs&feature=youtu.be # <- Uses a supported shared link with the url key. title: Correctly formatted video link. ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/meta_video_links.py000066400000000000000000000107301477347356000261740ustar00rootroot00000000000000"""Implementation of meta-video-links rule.""" # Copyright (c) 2018, Ansible Project from __future__ import annotations import re import sys from typing import TYPE_CHECKING from ansiblelint.constants import FILENAME_KEY, LINE_NUMBER_KEY from ansiblelint.rules import AnsibleLintRule if TYPE_CHECKING: from collections.abc import Sequence from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable class MetaVideoLinksRule(AnsibleLintRule): """meta/main.yml video_links should be formatted correctly.""" id = "meta-video-links" description = ( "Items in ``video_links`` in meta/main.yml should be " "dictionaries, and contain only keys ``url`` and ``title``, " "and have a shared link from a supported provider" ) severity = "LOW" tags = ["metadata"] version_changed = "4.0.0" VIDEO_REGEXP = { "google": re.compile(r"https://drive\.google\.com.*file/d/([0-9A-Za-z-_]+)/.*"), "vimeo": re.compile(r"https://vimeo\.com/([0-9]+)"), "youtube": re.compile(r"https://youtu\.be/([0-9A-Za-z-_]+)"), } def matchyaml(self, file: Lintable) -> list[MatchError]: if file.kind != "meta" or not file.data: return [] galaxy_info = file.data.get("galaxy_info", None) if not galaxy_info: return [] video_links = galaxy_info.get("video_links", None) if not video_links: return [] results = [] for video in video_links: if not isinstance(video, dict): results.append( self.create_matcherror( "Expected item in 'video_links' to be a dictionary", filename=file, data=video, ), ) continue unexpected_keys = set(video) - { "url", "title", FILENAME_KEY, LINE_NUMBER_KEY, } if unexpected_keys: results.append( self.create_matcherror( "Expected item in 'video_links' to contain " "only keys 'url' and 'title'", filename=file, data=video, ), ) continue for expr in self.VIDEO_REGEXP.values(): if expr.match(video["url"]): break else: msg = ( f"URL format '{video['url']}' is not recognized. " "Expected it be a shared link from Vimeo, YouTube, " "or Google Drive." ) results.append( self.create_matcherror(msg, filename=file, data=video["url"]) ) return results 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/roles/meta_video_links_fail/meta/main.yml", ( "URL format 'https://www.youtube.com/watch?v=aWmRepTSFKs&feature=youtu.be' is not recognized. Expected it be a shared link from Vimeo, YouTube, or Google Drive.", "Expected item in 'video_links' to be a dictionary", "Expected item in 'video_links' to contain only keys 'url' and 'title'", "URL format 'www.acme.com/vid' is not recognized. Expected it be a shared link from Vimeo, YouTube, or Google Drive.", ), id="1", ), pytest.param( "examples/roles/meta_video_links_pass/meta/main.yml", (), id="2", ), ), ) def test_video_links( default_rules_collection: RulesCollection, test_file: str, failures: Sequence[str], ) -> None: """Test rule matches.""" results = Runner(test_file, rules=default_rules_collection).run() assert len(results) == len(failures) # order of results is different between pre/post 2.19 due to increased # line precision in 2.19 for result in results: assert result.tag == "meta-video-links" assert result.message in failures ansible-ansible-lint-c16f018/src/ansiblelint/rules/name.md000066400000000000000000000056601477347356000235560ustar00rootroot00000000000000# name This rule identifies several problems related to the naming of tasks and plays. This is important because these names are the primary way to **identify** and **document** executed operations on the console, logs or web interface. This rule can produce messages as: - `name[casing]` - All names should start with an uppercase letter for languages that support it. - `name[missing]` - All tasks should be named. - `name[play]` - All plays should be named. - `name[prefix]` - Prefix task names in sub-tasks files. (opt-in) - `name[template]` - Jinja templates should only be at the end of 'name'. This helps with the identification of tasks inside the source code when they fail. The use of templating inside `name` keys is discouraged as there are multiple cases where the rendering of the name template is not possible. If you want to ignore some of the messages above, you can add any of them to the `skip_list`. ## name[prefix] This rule applies only to included task files that are not named `main.yml` or are embedded within subdirectories. It suggests adding the stems of the file path as a prefix to the task name. For example, if you have a task named `Restart server` inside a file named `tasks/deploy.yml`, this rule suggests renaming it to `deploy | Restart server`, so it would be easier to identify where it comes from. If the file was named `tasks/main.yml`, then the rule would have no effect. For task files that are embedded within subdirectories, these subdirectories will also be appended as part of the prefix. For example, if you have a task named `Terminate server` inside a file named `tasks/foo/destroy.yml`, this rule suggests renaming it to `foo | destroy | Terminate server`. If the file was named `tasks/foo/main.yml` then the rule would recommend renaming the task to `foo | main | Terminate server`. For the moment, this sub-rule is just an **opt-in**, so you need to add it to your `enable_list` to activate it. !!! note This rule was designed by [Red Hat Community of Practice](https://redhat-cop.github.io/automation-good-practices/#_prefix_task_names_in_sub_tasks_files_of_roles). The reasoning behind it being that in a complex roles or playbooks with multiple (sub-)tasks file, it becomes difficult to understand which task belongs to which file. Adding a prefix, in combination with the role’s name automatically added by Ansible, makes it a lot easier to follow and troubleshoot a role play. ## Problematic code ```yaml --- - hosts: localhost # <-- playbook name[play] tasks: - name: create placefolder file # <-- name[casing] due lack of capital letter ansible.builtin.command: touch /tmp/.placeholder ``` ## Correct code ```yaml --- - name: Play for creating placeholder hosts: localhost tasks: - name: Create placeholder file ansible.builtin.command: touch /tmp/.placeholder ``` !!! note `name[casing]` can be automatically fixed using [`--fix`](../autofix.md) option. ansible-ansible-lint-c16f018/src/ansiblelint/rules/name.py000066400000000000000000000325551477347356000236110ustar00rootroot00000000000000"""Implementation of NameRule.""" from __future__ import annotations import re import sys from collections.abc import MutableMapping from typing import TYPE_CHECKING, Any import wcmatch.pathlib import wcmatch.wcmatch from ansiblelint.file_utils import Lintable from ansiblelint.rules import AnsibleLintRule, TransformMixin if TYPE_CHECKING: from ruamel.yaml.comments import CommentedMap, CommentedSeq from ansiblelint.config import Options from ansiblelint.errors import MatchError from ansiblelint.utils import Task class NameRule(AnsibleLintRule, TransformMixin): """Rule for checking task and play names.""" id = "name" description = ( "All tasks and plays should have a distinct name for readability " "and for ``--start-at-task`` to work" ) severity = "MEDIUM" tags = ["idiom"] version_changed = "6.9.1" _re_templated_inside = re.compile(r".*\{\{.*\}\}.*\w.*$") _ids = { "name[play]": "All plays should be named.", "name[missing]": "All tasks should be named.", "name[prefix]": "Task name should start with a prefix.", "name[casing]": "All names should start with an uppercase letter.", "name[template]": "Jinja templates should only be at the end of 'name'", } def matchplay(self, file: Lintable, data: dict[str, Any]) -> list[MatchError]: """Return matches found for a specific play (entry in playbook).""" results: list[MatchError] = [] if file.kind != "playbook": return [] if file.failed(): # pragma: no cover return results if "name" not in data: return [ self.create_matcherror( message="All plays should be named.", tag="name[play]", filename=file, data=data, ), ] results.extend( self._check_name( data["name"], lintable=file, data=data, ), ) return results def matchtask( self, task: Task, file: Lintable | None = None, ) -> list[MatchError]: results: list[MatchError] = [] if file and file.failed(): # pragma: no cover return results name = task.get("name") if not name: results.append( self.create_matcherror( message="All tasks should be named.", lineno=task.line, tag="name[missing]", filename=file, ), ) else: results.extend( self._prefix_check( name, lintable=file, lineno=task.line, ), ) return results def _prefix_check( self, name: str, lintable: Lintable | None, lineno: int, ) -> list[MatchError]: results: list[MatchError] = [] effective_name = name if lintable is None: return [] if not results: results.extend( self._check_name( effective_name, lintable=lintable, data=lintable.data, ), ) return results def _check_name( self, name: str, lintable: Lintable | None, data: Any ) -> list[MatchError]: # This rules applies only to languages that do have uppercase and # lowercase letter, so we ignore anything else. On Unicode isupper() # is not necessarily the opposite of islower() results = [] # stage one check prefix effective_name = name if self._collection and lintable: full_stem = self._find_full_stem(lintable) stems = [ self._collection.options.task_name_prefix.format(stem=stem) for stem in wcmatch.pathlib.PurePath( full_stem, ).parts ] prefix = "".join(stems) if lintable.kind == "tasks" and full_stem != "main": if not name.startswith(prefix): # For the moment in order to raise errors this rule needs to be # enabled manually. Still, we do allow use of prefixes even without # having to enable the rule. if "name[prefix]" in self._collection.options.enable_list: results.append( self.create_matcherror( message=f"Task name should start with '{prefix}'.", data=data, tag="name[prefix]", filename=lintable, ), ) return results else: effective_name = name[len(prefix) :] if ( effective_name[0].isalpha() and effective_name[0].islower() and not effective_name[0].isupper() ): results.append( self.create_matcherror( message="All names should start with an uppercase letter.", data=name, tag="name[casing]", filename=lintable, ), ) if self._re_templated_inside.match(name): results.append( self.create_matcherror( message="Jinja templates should only be at the end of 'name'", data=name, tag="name[template]", filename=lintable, ), ) return results def _find_full_stem(self, lintable: Lintable) -> str: lintable_dir = wcmatch.pathlib.PurePath(lintable.dir) stem = lintable.path.stem kind = str(lintable.kind) stems = [lintable_dir.name] lintable_dir = lintable_dir.parent pathex = lintable_dir / stem glob = "" if self.options: for entry in self.options.kinds: for key, value in entry.items(): if kind == key: glob = value while pathex.globmatch( glob, flags=( wcmatch.pathlib.GLOBSTAR | wcmatch.pathlib.BRACE | wcmatch.pathlib.DOTGLOB ), ): stems.insert(0, lintable_dir.name) lintable_dir = lintable_dir.parent pathex = lintable_dir / stem if stems[0].startswith(kind): del stems[0] return str(wcmatch.pathlib.PurePath(*stems, stem)) def transform( self, match: MatchError, lintable: Lintable, data: CommentedMap | CommentedSeq | str, ) -> None: if match.tag == "name[casing]": def update_task_name(task_name: str) -> str: """Capitalize the first work of the task name.""" # Not using capitalize(), since that rewrites the rest of the name to lower case if "|" in task_name: # if using prefix [file_name, update_task_name] = task_name.split("|") return f"{file_name.strip()} | {update_task_name.strip()[:1].upper()}{update_task_name.strip()[1:]}" return f"{task_name[:1].upper()}{task_name[1:]}" target_task = self.seek(match.yaml_path, data) orig_task_name = target_task.get("name", None) # pylint: disable=too-many-nested-blocks if orig_task_name: updated_task_name = update_task_name(orig_task_name) for item in data: if isinstance(item, MutableMapping) and "tasks" in item: for task in item["tasks"]: # We want to rewrite task names in the notify keyword, but # if there isn't a notify section, there's nothing to do. if "notify" not in task: continue if ( isinstance(task["notify"], str) and orig_task_name == task["notify"] ): task["notify"] = updated_task_name elif isinstance(task["notify"], list): for idx in range(len(task["notify"])): if orig_task_name == task["notify"][idx]: task["notify"][idx] = updated_task_name target_task["name"] = updated_task_name match.fixed = True if "pytest" in sys.modules: from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner def test_file_positive() -> None: """Positive test for name[missing].""" collection = RulesCollection() collection.register(NameRule()) success = "examples/playbooks/rule-name-missing-pass.yml" good_runner = Runner(success, rules=collection) assert good_runner.run() == [] def test_file_negative() -> None: """Negative test for name[missing].""" collection = RulesCollection() collection.register(NameRule()) failure = "examples/playbooks/rule-name-missing-fail.yml" bad_runner = Runner(failure, rules=collection) errs = bad_runner.run() assert len(errs) == 5 def test_name_prefix_positive(config_options: Options) -> None: """Positive test for name[prefix].""" config_options.enable_list = ["name[prefix]"] collection = RulesCollection(options=config_options) collection.register(NameRule()) success = Lintable( "examples/playbooks/tasks/main.yml", kind="tasks", ) good_runner = Runner(success, rules=collection) results = good_runner.run() assert len(results) == 0 def test_name_prefix_negative(config_options: Options) -> None: """Negative test for name[missing].""" config_options.enable_list = ["name[prefix]"] collection = RulesCollection(options=config_options) collection.register(NameRule()) failure = Lintable( "examples/playbooks/tasks/rule-name-prefix-fail.yml", kind="tasks", ) bad_runner = Runner(failure, rules=collection) results = bad_runner.run() assert len(results) == 3 # , "\n".join(results) assert results[0].tag == "name[casing]" assert results[1].tag == "name[prefix]" assert results[2].tag == "name[prefix]" def test_name_prefix_negative_2(config_options: Options) -> None: """Negative test for name[prefix].""" config_options.enable_list = ["name[prefix]"] collection = RulesCollection(options=config_options) collection.register(NameRule()) failure = Lintable( "examples/playbooks/tasks/partial_prefix/foo.yml", kind="tasks", ) bad_runner = Runner(failure, rules=collection) results = bad_runner.run() assert len(results) == 2 assert results[0].tag == "name[prefix]" assert results[1].tag == "name[prefix]" def test_name_prefix_negative_3(config_options: Options) -> None: """Negative test for name[prefix].""" config_options.enable_list = ["name[prefix]"] collection = RulesCollection(options=config_options) collection.register(NameRule()) failure = Lintable( "examples/playbooks/tasks/partial_prefix/main.yml", kind="tasks", ) bad_runner = Runner(failure, rules=collection) results = bad_runner.run() assert len(results) == 2 assert results[0].tag == "name[prefix]" assert results[1].tag == "name[prefix]" def test_rule_name_lowercase() -> None: """Negative test for a task that starts with lowercase.""" collection = RulesCollection() collection.register(NameRule()) failure = "examples/playbooks/rule-name-casing.yml" bad_runner = Runner(failure, rules=collection) errs = bad_runner.run() assert len(errs) == 1 assert errs[0].tag == "name[casing]" assert errs[0].rule.id == "name" def test_name_play() -> None: """Positive test for name[play].""" collection = RulesCollection() collection.register(NameRule()) success = "examples/playbooks/rule-name-play-fail.yml" errs = Runner(success, rules=collection).run() assert len(errs) == 1 assert errs[0].tag == "name[play]" assert errs[0].rule.id == "name" def test_name_template() -> None: """Negative test for name[templated].""" collection = RulesCollection() collection.register(NameRule()) failure = "examples/playbooks/rule-name-templated-fail.yml" bad_runner = Runner(failure, rules=collection) errs = bad_runner.run() assert len(errs) == 1 assert errs[0].tag == "name[template]" def test_when_no_lintable() -> None: """Test when lintable is None.""" name_rule = NameRule() result = name_rule._prefix_check("Foo", None, 1) # noqa: SLF001 assert len(result) == 0 ansible-ansible-lint-c16f018/src/ansiblelint/rules/no_changed_when.md000066400000000000000000000032401477347356000257340ustar00rootroot00000000000000# no-changed-when This rule checks that tasks return changes to results or conditions. Unless tasks only read information, you should ensure that they return changes in the following ways: - Register results or conditions and use the `changed_when` clause. - Use the `creates` or `removes` argument. You should always use the `changed_when` clause on tasks that do not naturally detect if a change has occurred or not. Some of the most common examples are [shell] and [command] modules, which run arbitrary commands. One very common workaround is to use a boolean value like `changed_when: false` if the task never changes anything or `changed_when: true` if it always changes something, but you can also use any expressions, including ones that use the registered result of a task, like in our example below. This rule also applies to handlers, not only to tasks because they are also tasks. ## Problematic Code ```yaml --- - name: Example playbook hosts: localhost tasks: - name: Does not handle any output or return codes ansible.builtin.command: cat {{ my_file | quote }} # <- Does not handle the command output. ``` ## Correct Code ```yaml --- - name: Example playbook hosts: localhost tasks: - name: Handle shell output with return code ansible.builtin.command: cat {{ my_file | quote }} register: my_output # <- Registers the command output. changed_when: my_output.rc != 0 # <- Uses the return code to define when the task has changed. ``` [shell]: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/shell_module.html [command]: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/command_module.html ansible-ansible-lint-c16f018/src/ansiblelint/rules/no_changed_when.py000066400000000000000000000067451477347356000260010ustar00rootroot00000000000000"""Implementation of the no-changed-when rule.""" # Copyright (c) 2016 Will Thames # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from __future__ import annotations import sys from typing import TYPE_CHECKING from ansiblelint.rules import AnsibleLintRule if TYPE_CHECKING: from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task class CommandHasChangesCheckRule(AnsibleLintRule): """Commands should not change things if nothing needs doing.""" id = "no-changed-when" severity = "HIGH" tags = ["command-shell", "idempotency"] version_changed = "6.14.5" _commands = [ "ansible.builtin.command", "ansible.builtin.shell", "ansible.builtin.raw", "ansible.legacy.command", "ansible.legacy.shell", "ansible.legacy.raw", "command", "shell", "raw", ] def matchtask( self, task: Task, file: Lintable | None = None, ) -> list[MatchError]: result = [] # tasks in a block are "meta" type if ( task["__ansible_action_type__"] in ["task", "meta"] and task["action"]["__ansible_module__"] in self._commands and ( "changed_when" not in task.raw_task and "creates" not in task["action"] and "removes" not in task["action"] ) ): result.append(self.create_matcherror(filename=file)) return result if "pytest" in sys.modules: import pytest # pylint: disable=ungrouped-imports from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner @pytest.mark.parametrize( ("file", "expected"), ( pytest.param( "examples/playbooks/rule-no-changed-when-pass.yml", 0, id="pass", ), pytest.param( "examples/playbooks/rule-no-changed-when-fail.yml", 3, id="fail", ), ), ) def test_rule_no_changed_when( default_rules_collection: RulesCollection, file: str, expected: int, ) -> None: """Validate no-changed-when rule.""" results = Runner(file, rules=default_rules_collection).run() for result in results: assert result.rule.id == CommandHasChangesCheckRule.id, result assert len(results) == expected ansible-ansible-lint-c16f018/src/ansiblelint/rules/no_free_form.md000066400000000000000000000037021477347356000252710ustar00rootroot00000000000000# no-free-form This rule identifies any use of [free-form](https://docs.ansible.com/ansible/2.7/user_guide/playbooks_intro.html#action-shorthand) module calling syntax and asks for switching to the full syntax. **Free-form** syntax, also known as **inline** or **shorthand**, can produce subtle bugs. It can also prevent editors and IDEs from providing feedback, autocomplete and validation for the edited line. !!! note As long you just pass a YAML string that contains a `=` character inside as the parameter to the action module name, we consider this as using free-form syntax. Be sure you pass a dictionary to the module, so the free-form parsing is never triggered. As `raw` module only accepts free-form, we trigger `no-free-form[raw]` only if we detect the presence of `executable=` inside raw calls. We advise the explicit use of `args:` for configuring the executable to be run. This rule can produce messages as: - `no-free-form` - Free-form syntax is discouraged. - `no-free-form[raw-non-string]` - Passing a non-string value to `raw` module is neither documented nor supported. ## Problematic code ```yaml --- - name: Example with discouraged free-form syntax hosts: localhost tasks: - name: Create a placefolder file ansible.builtin.command: chdir=/tmp touch foo # <-- don't use free-form - name: Use raw to echo ansible.builtin.raw: executable=/bin/bash echo foo # <-- don't use executable= changed_when: false ``` ## Correct code ```yaml --- - name: Example that avoids free-form syntax hosts: localhost tasks: - name: Create a placefolder file ansible.builtin.command: cmd: touch foo # <-- ansible will not touch it chdir: /tmp - name: Use raw to echo ansible.builtin.raw: echo foo args: executable: /bin/bash # <-- explicit is better changed_when: false ``` !!! note This rule can be automatically fixed using [`--fix`](../autofix.md) option. ansible-ansible-lint-c16f018/src/ansiblelint/rules/no_free_form.py000066400000000000000000000170311477347356000253210ustar00rootroot00000000000000"""Implementation of NoFreeFormRule.""" from __future__ import annotations import functools import re import sys from typing import TYPE_CHECKING, Any from ruamel.yaml.scalarstring import DoubleQuotedScalarString, SingleQuotedScalarString from ansiblelint.constants import INCLUSION_ACTION_NAMES from ansiblelint.rules import AnsibleLintRule, TransformMixin from ansiblelint.rules.key_order import task_property_sorter if TYPE_CHECKING: from ruamel.yaml.comments import CommentedMap, CommentedSeq from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task class NoFreeFormRule(AnsibleLintRule, TransformMixin): """Rule for detecting discouraged free-form syntax for action modules.""" id = "no-free-form" description = "Avoid free-form inside files as it can produce subtle bugs." severity = "MEDIUM" tags = ["syntax", "risk"] version_changed = "6.8.0" needs_raw_task = True cmd_shell_re = re.compile( r"(chdir|creates|executable|removes|stdin|stdin_add_newline|warn)=", ) _ids = { "no-free-form[raw]": "Avoid embedding `executable=` inside raw calls, use explicit args dictionary instead.", "no-free-form[raw-non-string]": "Passing a non string value to `raw` module is neither documented or supported.", } def matchtask( self, task: Task, file: Lintable | None = None, ) -> list[MatchError]: results: list[MatchError] = [] action = task["action"]["__ansible_module_original__"] if action in INCLUSION_ACTION_NAMES: return results action_value = task["__raw_task__"].get(action, None) if task["action"].get("__ansible_module__", None) == "raw": if isinstance(action_value, str): if "executable=" in action_value: results.append( self.create_matcherror( message="Avoid embedding `executable=` inside raw calls, use explicit args dictionary instead.", lineno=task.line, filename=file, tag=f"{self.id}[raw]", ), ) else: results.append( self.create_matcherror( message="Passing a non string value to `raw` module is neither documented or supported.", lineno=task.line, filename=file, tag=f"{self.id}[raw-non-string]", ), ) elif isinstance(action_value, str) and "=" in action_value: fail = False if task["action"].get("__ansible_module__") in ( "ansible.builtin.command", "ansible.builtin.shell", "ansible.windows.win_command", "ansible.windows.win_shell", "command", "shell", "win_command", "win_shell", ): if self.cmd_shell_re.search(action_value): fail = True else: fail = True if fail: results.append( self.create_matcherror( message=f"Avoid using free-form when calling module actions. ({action})", lineno=task.line, filename=file, ), ) return results def transform( self, match: MatchError, lintable: Lintable, data: CommentedMap | CommentedSeq | str, ) -> None: if "no-free-form" in match.tag: task = self.seek(match.yaml_path, data) def filter_values( val: str, filter_key: str, filter_dict: dict[str, Any], ) -> str: """Pull out key=value pairs from a string and set them in filter_dict. Returns unmatched strings. """ if filter_key not in val: return val extra = "" [k, v] = val.split(filter_key, 1) if " " in k: extra, k = k.rsplit(" ", 1) if v[0] in "\"'": # Keep quoted strings together quote = v[0] _, v, remainder = v.split(quote, 2) v = ( DoubleQuotedScalarString if quote == '"' else SingleQuotedScalarString )(v) else: try: v, remainder = v.split(" ", 1) except ValueError: remainder = "" filter_dict[k] = v extra = " ".join( (extra, filter_values(remainder, filter_key, filter_dict)), ) return extra.strip() if match.tag == "no-free-form": module_opts: dict[str, Any] = {} for _ in range(len(task)): k, v = task.popitem(False) # identify module as key and process its value if len(k.split(".")) == 3 and isinstance(v, str): cmd = filter_values(v, "=", module_opts) if cmd: module_opts["cmd"] = cmd sorted_module_opts = {} for key in sorted( module_opts.keys(), key=functools.cmp_to_key(task_property_sorter), ): sorted_module_opts[key] = module_opts[key] task[k] = sorted_module_opts else: task[k] = v match.fixed = True elif match.tag == "no-free-form[raw]": exec_key_val: dict[str, Any] = {} for _ in range(len(task)): k, v = task.popitem(False) if isinstance(v, str) and "executable" in v: # Filter the executable and other parts from the string task[k] = " ".join( [ item for item in v.split(" ") if filter_values(item, "=", exec_key_val) ], ) task["args"] = exec_key_val else: task[k] = v match.fixed = True if "pytest" in sys.modules: import pytest # pylint: disable=ungrouped-imports from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner @pytest.mark.parametrize( ("file", "expected"), ( pytest.param("examples/playbooks/rule-no-free-form-pass.yml", 0, id="pass"), pytest.param("examples/playbooks/rule-no-free-form-fail.yml", 3, id="fail"), ), ) def test_rule_no_free_form( default_rules_collection: RulesCollection, file: str, expected: int, ) -> None: """Validate that rule works as intended.""" results = Runner(file, rules=default_rules_collection).run() for result in results: assert result.rule.id == NoFreeFormRule.id, result assert len(results) == expected ansible-ansible-lint-c16f018/src/ansiblelint/rules/no_handler.md000066400000000000000000000031121477347356000247350ustar00rootroot00000000000000# no-handler This rule checks for the correct handling of changes to results or conditions. If a task has a `when: result.changed` condition, it effectively acts as a [handler](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html#handlers). The recommended approach is to use `notify` and move tasks to `handlers`. If necessary you can silence the rule by add a `# noqa: no-handler` comment at the end of the line. ## Problematic Code ```yaml --- - name: Example of no-handler rule hosts: localhost tasks: - name: Register result of a task ansible.builtin.copy: dest: "/tmp/placeholder" content: "Ansible made this!" mode: 0600 register: result # <-- Registers the result of the task. - name: Second command to run ansible.builtin.debug: msg: The placeholder file was modified! when: result.changed # <-- Triggers the no-handler rule. ``` ```yaml --- # Optionally silences the rule. when: result.changed # noqa: no-handler ``` ## Correct Code The following code includes the same functionality as the problematic code without recording a `result` variable. ```yaml --- - name: Example of no-handler rule hosts: localhost tasks: - name: Register result of a task ansible.builtin.copy: dest: "/tmp/placeholder" content: "Ansible made this!" mode: 0600 notify: - Second command to run # <-- Handler runs only when the file changes. handlers: - name: Second command to run ansible.builtin.debug: msg: The placeholder file was modified! ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/no_handler.py000066400000000000000000000102151477347356000247670ustar00rootroot00000000000000# Copyright (c) 2016 Will Thames # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. """UseHandlerRatherThanWhenChangedRule used with ansible-lint.""" from __future__ import annotations import sys from collections.abc import Sequence from typing import TYPE_CHECKING from ansiblelint.rules import AnsibleLintRule if TYPE_CHECKING: from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task def _changed_in_when(item: str) -> bool: if not isinstance(item, str): return False item_list = item.split() if {"and", "or", "not"} & set(item_list): return False return any( changed in item for changed in [ ".changed", "|changed", '["changed"]', "['changed']", "is changed", ] ) class UseHandlerRatherThanWhenChangedRule(AnsibleLintRule): """Tasks that run when changed should likely be handlers.""" id = "no-handler" description = ( "If a task has a ``when: result.changed`` setting, it is effectively " "acting as a handler. You could use ``notify`` and move that task to " "``handlers``." ) link = "https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html#handlers" severity = "MEDIUM" tags = ["idiom"] version_changed = "24.10.0" def matchtask( self, task: Task, file: Lintable | None = None, ) -> list[MatchError]: if task.is_handler(): return [] when = task.get("when") result = [] if (isinstance(when, str) and _changed_in_when(when)) or ( isinstance(when, Sequence) and not isinstance(when, str) and len(when) <= 1 and _changed_in_when(when[0]) ): result.append( self.create_matcherror( message=self.shortdesc, data=when, filename=file, ) ) return result if "pytest" in sys.modules: import pytest # pylint: disable=ungrouped-imports from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner from ansiblelint.testing import run_ansible_lint @pytest.mark.parametrize( ("test_file", "failures"), ( pytest.param("examples/playbooks/no_handler_fail.yml", 5, id="fail"), pytest.param("examples/playbooks/no_handler_pass.yml", 0, id="pass"), ), ) def test_no_handler( 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-handler" def test_role_with_handler() -> None: """Test role with handler.""" role_path = "examples/roles/role_with_handler" results = run_ansible_lint("-v", role_path, env={"NO_COLOR": "1"}) assert "no-handler" not in results.stdout ansible-ansible-lint-c16f018/src/ansiblelint/rules/no_jinja_when.md000066400000000000000000000021041477347356000254340ustar00rootroot00000000000000# no-jinja-when This rule checks conditional statements for Jinja expressions in curly brackets `{{ }}`. Ansible processes conditionals statements that use the `when`, `failed_when`, and `changed_when` clauses as Jinja expressions. An Ansible rule is to always use `{{ }}` except with `when` keys. Using `{{ }}` in conditionals creates a nested expression, which is an Ansible anti-pattern and does not produce expected results. ## Problematic Code ```yaml --- - name: Example playbook hosts: localhost tasks: - name: Shut down Debian systems ansible.builtin.command: /sbin/shutdown -t now when: "{{ ansible_facts['os_family'] == 'Debian' }}" # <- Nests a Jinja expression in a conditional statement. ``` ## Correct Code ```yaml --- - name: Example playbook hosts: localhost tasks: - name: Shut down Debian systems ansible.builtin.command: /sbin/shutdown -t now when: ansible_facts['os_family'] == "Debian" # <- Uses facts in a conditional statement. ``` !!! note This rule can be automatically fixed using [`--fix`](../autofix.md) option. ansible-ansible-lint-c16f018/src/ansiblelint/rules/no_jinja_when.py000066400000000000000000000105431477347356000254720ustar00rootroot00000000000000"""Implementation of no-jinja-when rule.""" from __future__ import annotations import re import sys from collections.abc import MutableMapping from typing import TYPE_CHECKING, Any from ansiblelint.rules import AnsibleLintRule, TransformMixin if TYPE_CHECKING: from ruamel.yaml.comments import CommentedMap, CommentedSeq from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task RE_JINJA = re.compile(r"{{ (.*?) }}") class NoFormattingInWhenRule(AnsibleLintRule, TransformMixin): """No Jinja2 in when.""" id = "no-jinja-when" description = ( "``when`` is a raw Jinja2 expression, remove redundant {{ }} from variable(s)." ) severity = "HIGH" tags = ["deprecations"] version_changed = "6.20.0" @staticmethod def _is_valid(when: str) -> bool: if isinstance(when, list): for item in when: if ( isinstance(item, str) and item.find("{{") != -1 and item.find("}}") != -1 ): return False return True if not isinstance(when, str): return True return when.find("{{") == -1 and when.find("}}") == -1 def matchplay(self, file: Lintable, data: dict[str, Any]) -> list[MatchError]: errors: list[MatchError] = [] if isinstance(data, dict): if "roles" not in data or data["roles"] is None: return errors errors = [ self.create_matcherror( details=str({"when": role}), filename=file, data=role, ) for role in data["roles"] if ( isinstance(role, dict) and "when" in role and not self._is_valid(role["when"]) ) ] return errors def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: return "when" in task.raw_task and not self._is_valid(task.raw_task["when"]) def transform( self, match: MatchError, lintable: Lintable, data: CommentedMap | CommentedSeq | str, ) -> None: if match.tag == self.id: task = self.seek(match.yaml_path, data) key_to_check = ("when", "changed_when", "failed_when") for _ in range(len(task)): if isinstance(task, MutableMapping): for k, v in task.items(): if k == "roles" and isinstance(v, list): transform_for_roles(v, key_to_check=key_to_check) elif k in key_to_check: v = RE_JINJA.sub(r"\1", v) task[k] = v match.fixed = True def transform_for_roles(v: list[Any], key_to_check: tuple[str, ...]) -> None: """Additional transform logic in case of roles.""" for idx, new_dict in enumerate(v): for new_key, new_value in new_dict.items(): if new_key in key_to_check: if isinstance(new_value, list): for index, nested_value in enumerate(new_value): new_value[index] = RE_JINJA.sub(r"\1", nested_value) v[idx][new_key] = new_value if isinstance(new_value, str): v[idx][new_key] = RE_JINJA.sub(r"\1", new_value) if "pytest" in sys.modules: # Tests for no-jinja-when rule. from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner def test_jinja_file_positive() -> None: """Positive test for no-jinja-when.""" collection = RulesCollection() collection.register(NoFormattingInWhenRule()) success = "examples/playbooks/rule-no-jinja-when-pass.yml" good_runner = Runner(success, rules=collection) assert good_runner.run() == [] def test_jinja_file_negative() -> None: """Negative test for no-jinja-when.""" collection = RulesCollection() collection.register(NoFormattingInWhenRule()) failure = "examples/playbooks/rule-no-jinja-when-fail.yml" bad_runner = Runner(failure, rules=collection) errs = bad_runner.run() assert len(errs) == 3 ansible-ansible-lint-c16f018/src/ansiblelint/rules/no_log_password.md000066400000000000000000000022401477347356000260240ustar00rootroot00000000000000# no-log-password This rule ensures playbooks do not write passwords to logs when using loops. Always set the `no_log: true` attribute to protect sensitive data. While most Ansible modules mask sensitive data, using secrets inside a loop can result in those secrets being logged. Explicitly adding `no_log: true` prevents accidentally exposing secrets. ## Problematic Code ```yaml --- - name: Example playbook hosts: localhost tasks: - name: Log user passwords ansible.builtin.user: name: john_doe comment: John Doe uid: 1040 group: admin password: "{{ item }}" with_items: - wow no_log: false # <- Sets the no_log attribute to false. ``` ## Correct Code ```yaml --- - name: Example playbook hosts: localhost tasks: - name: Do not log user passwords ansible.builtin.user: name: john_doe comment: John Doe uid: 1040 group: admin password: "{{ item }}" with_items: - wow no_log: true # <- Sets the no_log attribute to a non-false value. ``` !!! note This rule can be automatically fixed using [`--fix`](../autofix.md) option. ansible-ansible-lint-c16f018/src/ansiblelint/rules/no_log_password.py000066400000000000000000000243151477347356000260630ustar00rootroot00000000000000# Copyright 2018, Rackspace US, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """NoLogPasswordsRule used with ansible-lint.""" from __future__ import annotations import os import sys from pathlib import Path from typing import TYPE_CHECKING from ansiblelint.rules import AnsibleLintRule, RulesCollection, TransformMixin from ansiblelint.runner import get_matches from ansiblelint.transformer import Transformer from ansiblelint.utils import Task, convert_to_boolean if TYPE_CHECKING: from ruamel.yaml.comments import CommentedMap, CommentedSeq from ansiblelint.config import Options from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable class NoLogPasswordsRule(AnsibleLintRule, TransformMixin): """Password should not be logged.""" id = "no-log-password" description = ( "When passing password argument you should have no_log configured " "to a non False value to avoid accidental leaking of secrets." ) severity = "LOW" tags = ["opt-in", "security", "experimental"] version_changed = "5.0.9" def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: if task["action"]["__ansible_module_original__"] == "ansible.builtin.user" and ( task["action"].get("password_lock") and not task["action"].get("password") ): has_password = False else: for param in task["action"]: if "password" in param: has_password = True break else: has_password = False has_loop = [key for key in task if key.startswith("with_") or key == "loop"] # No no_log and no_log: False behave the same way # and should return a failure (return True), so we # need to invert the boolean no_log = task.get("no_log", False) if ( isinstance(no_log, str) and no_log.startswith("{{") and no_log.endswith("}}") ): # we cannot really evaluate jinja expressions return False return bool( has_password and not convert_to_boolean(no_log) and len(has_loop) > 0, ) def transform( self, match: MatchError, lintable: Lintable, data: CommentedMap | CommentedSeq | str, ) -> None: if match.tag == self.id: task = self.seek(match.yaml_path, data) task["no_log"] = True match.fixed = True if "pytest" in sys.modules: from unittest import mock import pytest if TYPE_CHECKING: from ansiblelint.testing import RunFromText NO_LOG_UNUSED = """ - name: Test hosts: all tasks: - name: Succeed when no_log is not used but no loop present ansible.builtin.user: name: john_doe password: "wow" state: absent """ NO_LOG_FALSE = """ - hosts: all tasks: - name: Use of jinja for no_log is valid user: name: john_doe user_password: "{{ item }}" state: absent no_log: "{{ False }}" - name: Fail when no_log is set to False user: name: john_doe user_password: "{{ item }}" state: absent with_items: - wow - now no_log: False - name: Fail when no_log is set to False ansible.builtin.user: name: john_doe user_password: "{{ item }}" state: absent with_items: - wow - now no_log: False """ NO_LOG_NO = """ - hosts: all tasks: - name: Fail when no_log is set to no user: name: john_doe password: "{{ item }}" state: absent no_log: no loop: - wow - now """ PASSWORD_WITH_LOCK = """ - hosts: all tasks: - name: Fail when password is set and password_lock is true user: name: "{{ item }}" password: "wow" password_lock: true with_random_choice: - ansible - lint """ NO_LOG_YES = """ - hosts: all tasks: - name: Succeed when no_log is set to yes with_list: - name: user password: wow - password: now name: ansible user: name: "{{ item.name }}" password: "{{ item.password }}" state: absent no_log: yes """ NO_LOG_TRUE = """ - hosts: all tasks: - name: Succeed when no_log is set to True user: name: john_doe user_password: "{{ item }}" state: absent no_log: True loop: - wow - now """ PASSWORD_LOCK_YES = """ - hosts: all tasks: - name: Succeed when only password locking account user: name: "{{ item }}" password_lock: yes # user_password: "this is a comment, not a password" with_list: - ansible - lint """ PASSWORD_LOCK_YES_BUT_NO_PASSWORD = """ - hosts: all tasks: - name: Succeed when only password locking account ansible.builtin.user: name: "{{ item }}" password_lock: yes # user_password: "this is a comment, not a password" with_list: - ansible - lint """ PASSWORD_LOCK_FALSE = """ - hosts: all tasks: - name: Succeed when password_lock is false and password is not used user: name: lint password_lock: False """ @pytest.mark.parametrize( "rule_runner", (NoLogPasswordsRule,), indirect=["rule_runner"], ) def test_no_log_unused(rule_runner: RunFromText) -> None: """The task does not use no_log but also no loop.""" results = rule_runner.run_playbook(NO_LOG_UNUSED) assert len(results) == 0 @pytest.mark.parametrize( "rule_runner", (NoLogPasswordsRule,), indirect=["rule_runner"], ) def test_no_log_false(rule_runner: RunFromText) -> None: """The task sets no_log to false.""" results = rule_runner.run_playbook(NO_LOG_FALSE) assert len(results) == 2 for result in results: assert result.rule.id == "no-log-password" @pytest.mark.parametrize( "rule_runner", (NoLogPasswordsRule,), indirect=["rule_runner"], ) def test_no_log_no(rule_runner: RunFromText) -> None: """The task sets no_log to no.""" results = rule_runner.run_playbook(NO_LOG_NO) assert len(results) == 1 assert results[0].rule.id == "no-log-password" @pytest.mark.parametrize( "rule_runner", (NoLogPasswordsRule,), indirect=["rule_runner"], ) def test_password_with_lock(rule_runner: RunFromText) -> None: """The task sets a password but also lock the user.""" results = rule_runner.run_playbook(PASSWORD_WITH_LOCK) assert len(results) == 1 assert results[0].rule.id == "no-log-password" @pytest.mark.parametrize( "rule_runner", (NoLogPasswordsRule,), indirect=["rule_runner"], ) def test_no_log_yes(rule_runner: RunFromText) -> None: """The task sets no_log to yes.""" results = rule_runner.run_playbook(NO_LOG_YES) assert len(results) == 0 @pytest.mark.parametrize( "rule_runner", (NoLogPasswordsRule,), indirect=["rule_runner"], ) def test_no_log_true(rule_runner: RunFromText) -> None: """The task sets no_log to true.""" results = rule_runner.run_playbook(NO_LOG_TRUE) assert len(results) == 0 @pytest.mark.parametrize( "rule_runner", (NoLogPasswordsRule,), indirect=["rule_runner"], ) def test_no_log_password_lock_yes(rule_runner: RunFromText) -> None: """The task only locks the user.""" results = rule_runner.run_playbook(PASSWORD_LOCK_YES) assert len(results) == 0 @pytest.mark.parametrize( "rule_runner", (NoLogPasswordsRule,), indirect=["rule_runner"], ) def test_no_log_password_lock_yes_but_no_password(rule_runner: RunFromText) -> None: """The task only locks the user.""" results = rule_runner.run_playbook(PASSWORD_LOCK_YES_BUT_NO_PASSWORD) assert len(results) == 0 @pytest.mark.parametrize( "rule_runner", (NoLogPasswordsRule,), indirect=["rule_runner"], ) def test_password_lock_false(rule_runner: RunFromText) -> None: """The task does not actually lock the user.""" results = rule_runner.run_playbook(PASSWORD_LOCK_FALSE) assert len(results) == 0 @mock.patch.dict(os.environ, {"ANSIBLE_LINT_WRITE_TMP": "1"}, clear=True) def test_no_log_password_transform( config_options: Options, ) -> None: """Test transform functionality for no-log-password rule.""" playbook = Path("examples/playbooks/transform-no-log-password.yml") config_options.write_list = ["all"] rules = RulesCollection(options=config_options) rules.register(NoLogPasswordsRule()) config_options.lintables = [str(playbook)] runner_result = get_matches(rules=rules, options=config_options) transformer = Transformer(result=runner_result, options=config_options) transformer.run() matches = runner_result.matches assert len(matches) == 2 orig_content = playbook.read_text(encoding="utf-8") expected_content = playbook.with_suffix( f".transformed{playbook.suffix}", ).read_text(encoding="utf-8") transformed_content = playbook.with_suffix(f".tmp{playbook.suffix}").read_text( encoding="utf-8", ) assert orig_content != transformed_content assert expected_content == transformed_content playbook.with_suffix(f".tmp{playbook.suffix}").unlink() ansible-ansible-lint-c16f018/src/ansiblelint/rules/no_prompting.md000066400000000000000000000015611477347356000253450ustar00rootroot00000000000000# no-prompting This rule checks for `vars_prompt` or the `ansible.builtin.pause` module in playbooks. You should enable this rule to ensure that playbooks can run unattended and in CI/CD pipelines. This is an opt-in rule. You must enable it in your Ansible-lint configuration as follows: ```yaml enable_list: - no-prompting ``` ## Problematic Code ```yaml --- - name: Example playbook hosts: all vars_prompt: # <- Prompts the user to input credentials. - name: username prompt: What is your username? private: false - name: password prompt: What is your password? tasks: - name: Pause for 5 minutes ansible.builtin.pause: minutes: 5 # <- Pauses playbook execution for a set period of time. ``` ## Correct Code Correct code for this rule is to omit `vars_prompt` and the `ansible.builtin.pause` module from your playbook. ansible-ansible-lint-c16f018/src/ansiblelint/rules/no_prompting.py000066400000000000000000000047211477347356000253760ustar00rootroot00000000000000"""Implementation of no-prompting rule.""" from __future__ import annotations import sys from typing import TYPE_CHECKING, Any from ansiblelint.rules import AnsibleLintRule if TYPE_CHECKING: from ansiblelint.config import Options from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task 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"] severity = "VERY_LOW" version_changed = "6.0.3" def matchplay(self, file: Lintable, data: dict[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": # pragma: no cover return [] vars_prompt = data.get("vars_prompt") if not vars_prompt: return [] return [ self.create_matcherror( message="Play uses vars_prompt", data=vars_prompt[0], filename=file, ), ] def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: """Return matches for ansible.builtin.pause tasks.""" # We do not want to trigger this rule if pause has either seconds or # minutes defined, as that does not make it blocking. return task["action"]["__ansible_module_original__"] in [ "pause", "ansible.builtin.pause", ] and not ( task["action"].get("minutes", None) or task["action"].get("seconds", None) ) if "pytest" in sys.modules: from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner def test_no_prompting_fail(config_options: Options) -> None: """Negative test for no-prompting.""" # For testing we want to manually enable opt-in rules config_options.enable_list = ["no-prompting"] rules = RulesCollection(options=config_options) rules.register(NoPromptingRule()) results = Runner("examples/playbooks/rule-no-prompting.yml", rules=rules).run() assert len(results) == 2 for result in results: assert result.rule.id == "no-prompting" ansible-ansible-lint-c16f018/src/ansiblelint/rules/no_relative_paths.md000066400000000000000000000052011477347356000263330ustar00rootroot00000000000000# no-relative-paths This rule checks for relative paths in the `ansible.builtin.copy` and `ansible.builtin.template` modules. Relative paths in a task most often direct Ansible to remote files and directories on managed nodes. In the `ansible.builtin.copy` and `ansible.builtin.template` modules, the `src` argument refers to local files and directories on the control node. The recommended locations to store files are as follows: - Use the `files/` folder in the playbook or role directory for the `copy` module. - Use the `templates/` folder in the playbook or role directory for the `template` module. These folders allow you to omit the path or use a sub-folder when specifying files with the `src` argument. !!! note If resources are outside your Ansible playbook or role directory you should use an absolute path with the `src` argument. !!! warning Do not store resources at the same directory level as your Ansible playbook or tasks files. Doing this can result in disorganized projects and cause user confusion when distinguishing between resources of the same type, such as YAML. See [task paths](https://docs.ansible.com/ansible/latest/playbook_guide/playbook_pathing.html#task-paths) in the Ansible documentation for more information. ## Problematic Code ```yaml --- - name: Example playbook hosts: all tasks: - name: Template a file to /etc/file.conf ansible.builtin.template: src: ../my_templates/foo.j2 # <- Uses a relative path in the src argument. dest: /etc/file.conf owner: bin group: wheel mode: "0644" ``` ```yaml - name: Example playbook hosts: all vars: source_path: ../../my_templates/foo.j2 # <- Sets a variable to a relative path. tasks: - name: Copy a file to /etc/file.conf ansible.builtin.copy: src: "{{ source_path }}" # <- Uses the variable in the src argument. dest: /etc/foo.conf owner: foo group: foo mode: "0644" ``` ## Correct Code ```yaml --- - name: Example playbook hosts: all tasks: - name: Template a file to /etc/file.conf ansible.builtin.template: src: foo.j2 # <- Uses a path from inside templates/ directory. dest: /etc/file.conf owner: bin group: wheel mode: "0644" ``` ```yaml - name: Example playbook hosts: all vars: source_path: foo.j2 # <- Uses a path from inside files/ directory. tasks: - name: Copy a file to /etc/file.conf ansible.builtin.copy: src: "{{ source_path }}" # <- Uses the variable in the src argument. dest: /etc/foo.conf owner: foo group: foo mode: "0644" ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/no_relative_paths.py000066400000000000000000000042141477347356000263660ustar00rootroot00000000000000"""Implementation of no-relative-paths rule.""" # Copyright (c) 2016, Tsukinowa Inc. # 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_changed = "4.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]}" return path_to_check in task["action"]["src"] # 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" ansible-ansible-lint-c16f018/src/ansiblelint/rules/no_same_owner.md000066400000000000000000000032121477347356000254600ustar00rootroot00000000000000# no-same-owner This rule checks that the owner and group do not transfer across hosts. In many cases the owner and group on remote hosts do not match the owner and group assigned to source files. Preserving the owner and group during transfer can result in errors with permissions or leaking sensitive information. When you synchronize files, you should avoid transferring the owner and group by setting `owner: false` and `group: false` arguments. When you unpack archives with the `ansible.builtin.unarchive` module you should set the `--no-same-owner` option. This is an opt-in rule. You must enable it in your Ansible-lint configuration as follows: ```yaml enable_list: - no-same-owner ``` ## Problematic Code ```yaml --- - name: Example playbook hosts: all tasks: - name: Synchronize conf file ansible.posix.synchronize: src: /path/conf.yaml dest: /path/conf.yaml # <- Transfers the owner and group for the file. - name: Extract tarball to path ansible.builtin.unarchive: src: "{{ file }}.tar.gz" dest: /my/path/ # <- Transfers the owner and group for the file. ``` ## Correct Code ```yaml --- - name: Example playbook hosts: all tasks: - name: Synchronize conf file ansible.posix.synchronize: src: /path/conf.yaml dest: /path/conf.yaml owner: false group: false # <- Does not transfer the owner and group for the file. - name: Extract tarball to path ansible.builtin.unarchive: src: "{{ file }}.tar.gz" dest: /my/path/ extra_opts: - --no-same-owner # <- Does not transfer the owner and group for the file. ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/no_same_owner.py000066400000000000000000000070371477347356000255210ustar00rootroot00000000000000"""Optional rule for avoiding keeping owner/group when transferring files.""" from __future__ import annotations import re import sys from typing import TYPE_CHECKING, Any from ansible.utils.sentinel import Sentinel from ansiblelint.rules import AnsibleLintRule if TYPE_CHECKING: from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task class NoSameOwnerRule(AnsibleLintRule): """Do not preserve the owner and group when transferring files across hosts.""" id = "no-same-owner" description = """ Optional rule that highlights dangers of assuming that user/group on the remote machines may not exist on ansible controller or vice versa. Owner and group should not be preserved when transferring files between them. """ severity = "LOW" tags = ["opt-in"] version_changed = "6.4.0" RE_ARCHIVES = re.compile(r"^.*\.tar(\.(gz|bz2|xz))?$") def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: """Return matches for a task.""" action = task.get("action") if not isinstance(action, dict): # pragma: no cover return False module = action["__ansible_module__"] if module in ["synchronize", "ansible.posix.synchronize"]: return self.handle_synchronize(task, action) if module in ["unarchive", "ansible.builtin.unarchive"]: return self.handle_unarchive(task, action) return False @staticmethod def handle_synchronize(task: Any, action: dict[str, Any]) -> bool: """Process a synchronize task.""" if task.get("delegate_to") != Sentinel: return False archive = action.get("archive", True) if action.get("owner", archive) or action.get("group", archive): # noqa: SIM103 return True return False def handle_unarchive(self, task: Any, action: dict[str, Any]) -> bool: """Process unarchive task.""" delegate_to = task.get("delegate_to") if delegate_to == "localhost" or ( delegate_to != "localhost" and not action.get("remote_src") ): src = action.get("src") if not isinstance(src, str): return False if src.endswith("zip") and "-X" in action.get("extra_opts", []): return True if self.RE_ARCHIVES.match( src, ) and "--no-same-owner" not in action.get("extra_opts", []): 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/roles/role_for_no_same_owner/tasks/fail.yml", 12, id="fail", ), pytest.param( "examples/roles/role_for_no_same_owner/tasks/pass.yml", 0, id="pass", ), ), ) def test_no_same_owner_rule( 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.message == NoSameOwnerRule().shortdesc ansible-ansible-lint-c16f018/src/ansiblelint/rules/no_tabs.md000066400000000000000000000016351477347356000242610ustar00rootroot00000000000000# no-tabs This rule checks for the tab character. The `\t` tab character can result in unexpected display or formatting issues. You should always use spaces instead of tabs. !!! note This rule does not trigger alerts for tab characters in the ``ansible.builtin.lineinfile`` module. ## Problematic Code ```yaml --- - name: Example playbook hosts: all tasks: - name: Do not trigger the rule ansible.builtin.lineinfile: path: some.txt regexp: '^\t$' line: 'string with \t inside' - name: Trigger the rule with a debug message ansible.builtin.debug: msg: "Using the \t character can cause formatting issues." # <- Includes the tab character. ``` ## Correct Code ```yaml --- - name: Example playbook hosts: all tasks: - name: Do not trigger the no-tabs rule ansible.builtin.debug: msg: "Using space characters avoids formatting issues." ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/no_tabs.py000066400000000000000000000066431477347356000243150ustar00rootroot00000000000000"""Implementation of no-tabs rule.""" # Copyright (c) 2016, Will Thames and contributors # Copyright (c) 2018, Ansible Project from __future__ import annotations import sys from typing import TYPE_CHECKING from ansiblelint.rules import AnsibleLintRule from ansiblelint.text import has_jinja from ansiblelint.yaml_utils import nested_items_path if TYPE_CHECKING: from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task class NoTabsRule(AnsibleLintRule): """Most files should not contain tabs.""" id = "no-tabs" description = "Tabs can cause unexpected display issues, use spaces" severity = "LOW" tags = ["formatting"] version_changed = "4.0.0" allow_list = [ ("lineinfile", "insertafter"), ("lineinfile", "insertbefore"), ("lineinfile", "regexp"), ("lineinfile", "line"), ("win_lineinfile", "insertafter"), ("win_lineinfile", "insertbefore"), ("win_lineinfile", "regexp"), ("win_lineinfile", "line"), ("ansible.builtin.lineinfile", "insertafter"), ("ansible.builtin.lineinfile", "insertbefore"), ("ansible.builtin.lineinfile", "regexp"), ("ansible.builtin.lineinfile", "line"), ("ansible.legacy.lineinfile", "insertafter"), ("ansible.legacy.lineinfile", "insertbefore"), ("ansible.legacy.lineinfile", "regexp"), ("ansible.legacy.lineinfile", "line"), ("community.windows.win_lineinfile", "insertafter"), ("community.windows.win_lineinfile", "insertbefore"), ("community.windows.win_lineinfile", "regexp"), ("community.windows.win_lineinfile", "line"), ] def matchtask( self, task: Task, file: Lintable | None = None, ) -> list[MatchError]: result = [] action = task["action"]["__ansible_module__"] for k, v, _ in nested_items_path(task): if isinstance(k, str) and "\t" in k and not has_jinja(k): result.append( self.create_matcherror( message=self.shortdesc, data=k, filename=file, ) ) if ( isinstance(v, str) and "\t" in v and (action, k) not in self.allow_list and not has_jinja(v) ): result.append( self.create_matcherror( message=self.shortdesc, data=v, filename=file, ) ) return result # testing code to be loaded only with pytest or when executed the rule file if "pytest" in sys.modules: from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner def test_no_tabs_rule(default_rules_collection: RulesCollection) -> None: """Test rule matches.""" results = Runner( "examples/playbooks/rule-no-tabs.yml", rules=default_rules_collection, ).run() lines = [] for result in results: assert result.rule.id == "no-tabs" lines.append(result.lineno) assert lines # 2.19 has more precise line:columns numbers so the effective result # is different. assert lines == [10, 13] or lines == [12, 15, 15], lines ansible-ansible-lint-c16f018/src/ansiblelint/rules/only_builtins.md000066400000000000000000000014031477347356000255170ustar00rootroot00000000000000# only-builtins This rule checks that playbooks use actions from the `ansible.builtin` collection only. This is an opt-in rule. You must enable it in your Ansible-lint configuration as follows: ```yaml enable_list: - only-builtins ``` ## Problematic Code ```yaml --- - name: Example playbook hosts: all tasks: - name: Deploy a Helm chart for Prometheus kubernetes.core.helm: # <- Uses a non-builtin collection. name: test chart_ref: stable/prometheus release_namespace: monitoring create_namespace: true ``` ## Correct Code ```yaml - name: Example playbook hosts: localhost tasks: - name: Run a shell command ansible.builtin.shell: echo This playbook uses actions from the builtin collection only. ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/only_builtins.py000066400000000000000000000065421477347356000255600ustar00rootroot00000000000000"""Rule definition for usage of builtin actions only.""" from __future__ import annotations import os import sys from typing import TYPE_CHECKING 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"] version_changed = "6.14.0" def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: module = task["action"]["__ansible_module_original__"] allowed_collections = [ "ansible.builtin", "ansible.legacy", ] allowed_modules = builtins if self.options: allowed_collections += self.options.only_builtins_allow_collections allowed_modules += self.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 ansible-ansible-lint-c16f018/src/ansiblelint/rules/package_latest.md000066400000000000000000000051371477347356000256040ustar00rootroot00000000000000# package-latest This rule checks that package managers install software in a controlled, safe manner. Package manager modules, such as `ansible.builtin.yum`, include a `state` parameter that configures how Ansible installs software. In production environments, you should set `state` to `present` and specify a target version to ensure that packages are installed to a planned and tested version. Setting `state` to `latest` not only installs software, it performs an update and installs additional packages. This can result in performance degradation or loss of service. If you do want to update packages to the latest version, you should also set the `update_only` or `only_upgrade` parameter to `true` based on package manager to avoid installing additional packages. ## Problematic Code ```yaml --- - name: Example playbook hosts: localhost tasks: - name: Install Ansible ansible.builtin.yum: name: ansible state: latest # <- Installs the latest package. - name: Install Ansible-lint ansible.builtin.pip: name: ansible-lint args: state: latest # <- Installs the latest package. - name: Install some-package ansible.builtin.package: name: some-package state: latest # <- Installs the latest package. - name: Install sudo with update_only to false ansible.builtin.yum: name: sudo state: latest update_only: false # <- Updates and installs packages. - name: Install sudo with only_upgrade to false ansible.builtin.apt: name: sudo state: latest only_upgrade: false # <- Upgrades and installs packages ``` ## Correct Code ```yaml --- - name: Example playbook hosts: localhost tasks: - name: Install Ansible ansible.builtin.yum: name: ansible-2.12.7.0 state: present # <- Pins the version to install with yum. - name: Install Ansible-lint ansible.builtin.pip: name: ansible-lint args: state: present version: 5.4.0 # <- Pins the version to install with pip. - name: Install some-package ansible.builtin.package: name: some-package state: present # <- Ensures the package is installed. - name: Update sudo with update_only to true ansible.builtin.yum: name: sudo state: latest update_only: true # <- Updates but does not install additional packages. - name: Install sudo with only_upgrade to true ansible.builtin.apt: name: sudo state: latest only_upgrade: true # <- Upgrades but does not install additional packages. ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/package_latest.py000066400000000000000000000051331477347356000256300ustar00rootroot00000000000000"""Implementations of the package-latest rule.""" # Copyright (c) 2016 Will Thames # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from __future__ import annotations 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 PackageIsNotLatestRule(AnsibleLintRule): """Package installs should not use latest.""" id = "package-latest" description = ( "Package installs should use ``state=present`` with or without a version" ) severity = "VERY_LOW" tags = ["idempotency"] version_changed = "6.20.0" _package_managers = [ "apk", "apt", "bower", "bundler", "dnf", "easy_install", "gem", "homebrew", "jenkins_plugin", "npm", "openbsd_package", "openbsd_pkg", "package", "pacman", "pear", "pip", "pkg5", "pkgutil", "portage", "slackpkg", "sorcery", "swdepot", "win_chocolatey", "yarn", "yum", "zypper", ] def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: return ( task["action"]["__ansible_module__"] in self._package_managers and not task["action"].get("version") and not task["action"].get("update_only") and not task["action"].get("only_upgrade") and task["action"].get("state") == "latest" ) ansible-ansible-lint-c16f018/src/ansiblelint/rules/partial_become.md000066400000000000000000000061121477347356000255750ustar00rootroot00000000000000# partial-become This rule checks that privilege escalation is activated when changing users. To perform an action as a different user with the `become_user` directive, you must set `become: true`. This rule can produce the following messages: - `partial-become[play]`: become_user requires become to work as expected, at play level. - `partial-become[task]`: become_user requires become to work as expected, at task level. !!! warning While Ansible inherits have of `become` and `become_user` from upper levels, like play level or command line, we do not look at these values. This rule requires you to be explicit and always define both in the same place, mainly in order to prevent accidents when some tasks are moved from one location to another one. ## Problematic Code ```yaml --- - name: Example playbook hosts: localhost become: true # <- Activates privilege escalation. tasks: - name: Start the httpd service as the apache user ansible.builtin.service: name: httpd state: started become_user: apache # <- Does not change the user because "become: true" is not set. ``` ## Correct Code ```yaml - name: Example playbook hosts: localhost tasks: - name: Start the httpd service as the apache user ansible.builtin.service: name: httpd state: started become: true # <- Activates privilege escalation. become_user: apache # <- Changes the user with the desired privileges. # Stand alone playbook alternative, applies to all tasks - name: Example playbook hosts: localhost become: true # <- Activates privilege escalation. become_user: apache # <- Changes the user with the desired privileges. tasks: - name: Start the httpd service as the apache user ansible.builtin.service: name: httpd state: started ``` ## Problematic Code ```yaml --- - name: Example playbook 1 hosts: localhost become: true # <- Activates privilege escalation. tasks: - name: Include a task file ansible.builtin.include_tasks: tasks.yml ``` ```yaml --- - name: Example playbook 2 hosts: localhost tasks: - name: Include a task file ansible.builtin.include_tasks: tasks.yml ``` ```yaml # tasks.yml - name: Start the httpd service as the apache user ansible.builtin.service: name: httpd state: started become_user: apache # <- Does not change the user because "become: true" is not set. ``` ## Correct Code ```yaml --- - name: Example playbook 1 hosts: localhost tasks: - name: Include a task file ansible.builtin.include_tasks: tasks.yml ``` ```yaml --- - name: Example playbook 2 hosts: localhost tasks: - name: Include a task file ansible.builtin.include_tasks: tasks.yml ``` ```yaml # tasks.yml - name: Start the httpd service as the apache user ansible.builtin.service: name: httpd state: started become: true # <- Activates privilege escalation. become_user: apache # <- Does not change the user because "become: true" is not set. ``` !!! note This rule can be automatically fixed using [`--fix`](../autofix.md) option. ansible-ansible-lint-c16f018/src/ansiblelint/rules/partial_become.py000066400000000000000000000221501477347356000256250ustar00rootroot00000000000000"""Implementation of partial-become rule.""" # Copyright (c) 2016 Will Thames # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from __future__ import annotations import sys from typing import TYPE_CHECKING, Any from ruamel.yaml.comments import CommentedMap, CommentedSeq from ansiblelint.rules import AnsibleLintRule, TransformMixin if TYPE_CHECKING: from collections.abc import Iterator from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task class BecomeUserWithoutBecomeRule(AnsibleLintRule, TransformMixin): """``become_user`` should have a corresponding ``become`` at the same level as itself.""" id = "partial-become" description = "``become_user`` should have a corresponding ``become`` at the same level as itself." severity = "VERY_HIGH" tags = ["unpredictability"] version_changed = "6.20.0" def matchplay( self, file: Lintable, data: dict[str, Any], ) -> list[MatchError]: """Match become_user without become in play. :param file: The file to lint. :param data: The data to lint (play) :returns: A list of errors. """ if file.kind != "playbook": return [] errors = [] partial = "become_user" in data and "become" not in data if partial: error = self.create_matcherror( message=self.shortdesc, filename=file, tag=f"{self.id}[play]", data=data, ) errors.append(error) return errors def matchtask( self, task: Task, file: Lintable | None = None, ) -> list[MatchError]: """Match become_user without become in task. :param task: The task to lint. :param file: The file to lint. :returns: A list of errors. """ data = task.normalized_task errors = [] partial = "become_user" in data and "become" not in data if partial: error = self.create_matcherror( message=self.shortdesc, filename=file, tag=f"{self.id}[task]", lineno=task.line, ) errors.append(error) return errors def _dive(self, data: CommentedSeq) -> Iterator[Any]: """Dive into the data and yield each item. :param data: The data to dive into. :yield: Each item in the data. """ for item in data: for nested in ("block", "rescue", "always"): if nested in item: yield from self._dive(item[nested]) yield item def transform( self, match: MatchError, lintable: Lintable, data: CommentedMap | CommentedSeq | str, ) -> None: """Transform the data. :param match: The match to transform. :param lintable: The file to transform. :param data: The data to transform. """ if not isinstance(data, CommentedSeq): return obj = self.seek(match.yaml_path, data) if "become" in obj and "become_user" in obj: match.fixed = True return if "become" not in obj and "become_user" not in obj: match.fixed = True return self._transform_plays(plays=data) if "become" in obj and "become_user" in obj: match.fixed = True return if "become" not in obj and "become_user" not in obj: match.fixed = True return def is_ineligible_for_transform( self, data: CommentedMap, ) -> bool: """Check if the data is eligible for transformation. :param data: The data to check. :returns: True if ineligible, False otherwise. """ if any("include" in key for key in data): return True return "notify" in data def _transform_plays(self, plays: CommentedSeq) -> None: """Transform the plays. :param plays: The plays to transform. """ for play in plays: self._transform_play(play=play) def _transform_play(self, play: CommentedMap) -> None: """Transform the play. :param play: The play to transform. """ # Ensure we have no includes in this play task_groups = ("tasks", "pre_tasks", "post_tasks", "handlers") for task_group in task_groups: tasks = self._dive(play.get(task_group, [])) for task in tasks: if self.is_ineligible_for_transform(task): return remove_play_become_user = False for task_group in task_groups: tasks = self._dive(play.get(task_group, [])) for task in tasks: b_in_t = "become" in task bu_in_t = "become_user" in task b_in_p = "become" in play bu_in_p = "become_user" in play if b_in_t and not bu_in_t and bu_in_p: # Preserve the end comment if become is the last key comment = None if list(task.keys())[-1] == "become" and "become" in task.ca.items: comment = task.ca.items.pop("become") become_index = list(task.keys()).index("become") task.insert(become_index + 1, "become_user", play["become_user"]) if comment: self._attach_comment_end(task, comment) remove_play_become_user = True if bu_in_t and not b_in_t and b_in_p: become_user_index = list(task.keys()).index("become_user") task.insert(become_user_index, "become", play["become"]) if bu_in_t and not b_in_t and not b_in_p: # Preserve the end comment if become_user is the last key comment = None if ( list(task.keys())[-1] == "become_user" and "become_user" in task.ca.items ): comment = task.ca.items.pop("become_user") task.pop("become_user") if comment: self._attach_comment_end(task, comment) if remove_play_become_user: del play["become_user"] def _attach_comment_end( self, obj: CommentedMap | CommentedSeq, comment: Any, ) -> None: """Attach a comment to the end of the object. :param obj: The object to attach the comment to. :param comment: The comment to attach. """ if isinstance(obj, CommentedMap): last = list(obj.keys())[-1] if not isinstance(obj[last], CommentedSeq | CommentedMap): obj.ca.items[last] = comment return self._attach_comment_end(obj[last], comment) elif isinstance(obj, CommentedSeq): if not isinstance(obj[-1], CommentedSeq | CommentedMap): obj.ca.items[len(obj)] = comment return self._attach_comment_end(obj[-1], comment) # testing code to be loaded only with pytest or when executed the rule file if "pytest" in sys.modules: from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner def test_partial_become_pass() -> None: """No errors found for partial-become.""" collection = RulesCollection() collection.register(BecomeUserWithoutBecomeRule()) success = "examples/playbooks/rule-partial-become-without-become-pass.yml" good_runner = Runner(success, rules=collection) assert good_runner.run() == [] def test_partial_become_fail() -> None: """Errors found for partial-become.""" collection = RulesCollection() collection.register(BecomeUserWithoutBecomeRule()) failure = "examples/playbooks/rule-partial-become-without-become-fail.yml" bad_runner = Runner(failure, rules=collection) errs = bad_runner.run() assert len(errs) == 3 ansible-ansible-lint-c16f018/src/ansiblelint/rules/playbook_extension.md000066400000000000000000000011151477347356000265410ustar00rootroot00000000000000# playbook-extension This rule checks the file extension for playbooks is either `.yml` or `.yaml`. Ansible playbooks are expressed in YAML format with minimal syntax. The [YAML syntax](https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html#yaml-syntax) reference provides additional detail. ## Problematic Code This rule is triggered if Ansible playbooks do not have a file extension or use an unsupported file extension such as `playbook.json` or `playbook.xml`. ## Correct Code Save Ansible playbooks as valid YAML with the `.yml` or `.yaml` file extension. ansible-ansible-lint-c16f018/src/ansiblelint/rules/playbook_extension.py000066400000000000000000000034671477347356000266050ustar00rootroot00000000000000"""Implementation of playbook-extension rule.""" # Copyright (c) 2016, Tsukinowa Inc. # Copyright (c) 2018, Ansible Project from __future__ import annotations import sys from typing import TYPE_CHECKING from ansiblelint.file_utils import Lintable from ansiblelint.rules import AnsibleLintRule from ansiblelint.runner import Runner if TYPE_CHECKING: from ansiblelint.errors import MatchError class PlaybookExtensionRule(AnsibleLintRule): """Use ".yml" or ".yaml" playbook extension.""" id = "playbook-extension" description = 'Playbooks should have the ".yml" or ".yaml" extension' severity = "MEDIUM" tags = ["formatting"] done: list[str] = [] version_changed = "4.0.0" def matchyaml(self, file: Lintable) -> list[MatchError]: result: list[MatchError] = [] if file.kind != "playbook": return result path = str(file.path) ext = file.path.suffix if ext not in [".yml", ".yaml"] and path not in self.done: self.done.append(path) result.append(self.create_matcherror(filename=file)) return result if "pytest" in sys.modules: import pytest # pylint: disable=ungrouped-imports from ansiblelint.rules import RulesCollection @pytest.mark.parametrize( ("file", "expected"), (pytest.param("examples/playbooks/play-without-extension", 1, id="fail"),), ) def test_playbook_extension(file: str, expected: int) -> None: """The ini_file module does not accept preserve mode.""" rules = RulesCollection() rules.register(PlaybookExtensionRule()) results = Runner(Lintable(file, kind="playbook"), rules=rules).run() assert len(results) == expected for result in results: assert result.tag == "playbook-extension" ansible-ansible-lint-c16f018/src/ansiblelint/rules/risky_file_permissions.md000066400000000000000000000052111477347356000274210ustar00rootroot00000000000000# risky-file-permissions This rule is triggered by various modules that could end up creating new files on disk with permissions that might be too open, or unpredictable. Please read the documentation of each module carefully to understand the implications of using different argument values, as these make the difference between using the module safely or not. The fix depends on each module and also your particular situation. Some modules have a `create` argument that defaults to `true`. For those you either need to set `create: false` or provide some permissions like `mode: 0600` to make the behavior predictable and not dependent on the current system settings. Modules that are checked: - [`ansible.builtin.assemble`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/assemble_module.html) - [`ansible.builtin.copy`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/copy_module.html) - [`ansible.builtin.file`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/file_module.html) - [`ansible.builtin.get_url`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/get_url_module.html) - [`ansible.builtin.replace`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/replace_module.html) - [`ansible.builtin.template`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/template_module.html) - [`community.general.archive`](https://docs.ansible.com/ansible/latest/collections/community/general/archive_module.html) - [`community.general.ini_file`](https://docs.ansible.com/ansible/latest/collections/community/general/ini_file_module.html) !!! warning This rule does not take [module_defaults](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_module_defaults.html) configuration into account. There are currently no plans to implement this feature because changing task location can also change task behavior. ## Problematic code ```yaml --- - name: Unsafe example of using ini_file community.general.ini_file: path: foo create: true ``` ## Correct code ```yaml --- - name: Safe example of using ini_file (1st solution) community.general.ini_file: path: foo create: false # prevents creating a file with potentially insecure permissions - name: Safe example of using ini_file (2nd solution) community.general.ini_file: path: foo mode: "0600" # explicitly sets the desired permissions, to make the results predictable - name: Safe example of using copy (3rd solution) ansible.builtin.copy: src: foo dest: bar mode: preserve # copy has a special mode that sets the same permissions as the source file ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/risky_file_permissions.py000066400000000000000000000133331477347356000274550ustar00rootroot00000000000000# Copyright (c) 2020 Sorin Sbarnea # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. """MissingFilePermissionsRule used with ansible-lint.""" from __future__ import annotations import sys from pathlib import Path from typing import TYPE_CHECKING from ansiblelint.rules import AnsibleLintRule if TYPE_CHECKING: from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task # Despite documentation mentioning 'preserve' only these modules support it: _modules_with_preserve = ( "copy", "template", ) _MODULES: set[str] = { "archive", "community.general.archive", "assemble", "ansible.builtin.assemble", "copy", # supports preserve "ansible.builtin.copy", "file", "ansible.builtin.file", "get_url", "ansible.builtin.get_url", "replace", # implicit preserve behavior but mode: preserve is invalid "ansible.builtin.replace", "template", # supports preserve "ansible.builtin.template", # 'unarchive', # disabled because .tar.gz files can have permissions inside } _MODULES_WITH_CREATE: dict[str, bool] = { "blockinfile": False, "ansible.builtin.blockinfile": False, "htpasswd": True, "community.general.htpasswd": True, "ini_file": True, "community.general.ini_file": True, "lineinfile": False, "ansible.builtin.lineinfile": False, } class MissingFilePermissionsRule(AnsibleLintRule): """File permissions unset or incorrect.""" id = "risky-file-permissions" description = ( "Missing or unsupported mode parameter can cause unexpected file " "permissions based " "on version of Ansible being used. Be explicit, like `mode: 0644` to " "avoid hitting this rule. Special `preserve` value is accepted " f"only by {', '.join([f'`{x}`' for x in _modules_with_preserve])} modules." ) link = "https://github.com/ansible/ansible/issues/71200" severity = "VERY_HIGH" tags = ["unpredictability"] version_changed = "4.3.0" _modules = _MODULES _modules_with_create = _MODULES_WITH_CREATE # pylint: disable=too-many-return-statements def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: module = task["action"]["__ansible_module__"] mode = task["action"].get("mode", None) if not isinstance(task.args, dict): # We are unable to check args when using jinja templating return False if module not in self._modules and module not in self._modules_with_create: return False if mode == "preserve" and module not in _modules_with_preserve: return True if module in self._modules_with_create: create = task["action"].get("create", self._modules_with_create[module]) return create and mode is None # A file that doesn't exist cannot have a mode if task["action"].get("state", None) == "absent": return False # A symlink always has mode 0777 if task["action"].get("state", None) == "link": return False # Recurse on a directory does not allow for an uniform mode if task["action"].get("recurse", None): return False # The file module does not create anything when state==file (default) if module == "file" and task["action"].get("state", "file") == "file": return False # replace module is the only one that has a valid default preserve # behavior, but we want to trigger rule if user used incorrect # documentation and put 'preserve', which is not supported. if module == "replace" and mode is None: return False return mode is None if "pytest" in sys.modules: import pytest # pylint: disable=ungrouped-imports from ansiblelint.rules import RulesCollection from ansiblelint.testing import RunFromText @pytest.mark.parametrize( ("file", "expected"), ( pytest.param( "examples/playbooks/rule-risky-file-permissions-pass.yml", 0, id="pass", ), pytest.param( "examples/playbooks/rule-risky-file-permissions-fail.yml", 11, id="fails", ), ), ) def test_risky_file_permissions( file: str, expected: int, default_rules_collection: RulesCollection, ) -> None: """The ini_file module does not accept preserve mode.""" runner = RunFromText(default_rules_collection) results = runner.run(Path(file)) assert len(results) == expected for result in results: assert result.tag == "risky-file-permissions" ansible-ansible-lint-c16f018/src/ansiblelint/rules/risky_octal.md000066400000000000000000000033101477347356000251470ustar00rootroot00000000000000# risky-octal This rule checks that octal file permissions are strings that contain a leading zero or are written in [symbolic modes](https://www.gnu.org/software/findutils/manual/html_node/find_html/Symbolic-Modes.html), such as `u+rwx` or `u=rw,g=r,o=r`. Using integers or octal values in YAML can result in unexpected behavior. For example, the YAML loader interprets `0644` as the decimal number `420` but putting `644` there will produce very different results. Modules that are checked: - [`ansible.builtin.assemble`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/assemble_module.html) - [`ansible.builtin.copy`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/copy_module.html) - [`ansible.builtin.file`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/file_module.html) - [`ansible.builtin.replace`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/replace_module.html) - [`ansible.builtin.template`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/template_module.html) ## Problematic Code ```yaml --- - name: Example playbook hosts: localhost tasks: - name: Unsafe example of declaring Numeric file permissions ansible.builtin.file: path: /etc/foo.conf owner: foo group: foo mode: 644 ``` ## Correct Code ```yaml --- - name: Example playbook hosts: localhost tasks: - name: Safe example of declaring Numeric file permissions (1st solution) ansible.builtin.file: path: /etc/foo.conf owner: foo group: foo mode: "0644" # <- quoting and the leading zero will prevent surprises # "0o644" is also a valid alternative. ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/risky_octal.py000066400000000000000000000135541477347356000252120ustar00rootroot00000000000000"""Implementation of risky-octal rule.""" # Copyright (c) 2013-2014 Will Thames # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from __future__ import annotations import sys from typing import TYPE_CHECKING from ansiblelint.rules import AnsibleLintRule, RulesCollection from ansiblelint.runner import Runner if TYPE_CHECKING: from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task class OctalPermissionsRule(AnsibleLintRule): """Octal file permissions must contain leading zero or be a string.""" id = "risky-octal" description = ( "Numeric file permissions without leading zero can behave " "in unexpected ways." ) link = "https://docs.ansible.com/ansible/latest/collections/ansible/builtin/file_module.html" severity = "VERY_HIGH" tags = ["formatting"] version_changed = "6.9.1" _modules = [ "assemble", "copy", "file", "ini_file", "lineinfile", "replace", "synchronize", "template", "unarchive", ] @staticmethod def is_invalid_permission(mode: int) -> bool: """Check if permissions are valid. Sensible file permission modes don't have write bit set when read bit is not set and don't have execute bit set when user execute bit is not set. Also, user permissions are more generous than group permissions and user and group permissions are more generous than world permissions. """ other_write_without_read = ( mode % 8 and mode % 8 < 4 and not (mode % 8 == 1 and (mode >> 6) % 2 == 1) ) group_write_without_read = ( (mode >> 3) % 8 and (mode >> 3) % 8 < 4 and not ((mode >> 3) % 8 == 1 and (mode >> 6) % 2 == 1) ) user_write_without_read = ( (mode >> 6) % 8 and (mode >> 6) % 8 < 4 and (mode >> 6) % 8 != 1 ) other_more_generous_than_group = mode % 8 > (mode >> 3) % 8 other_more_generous_than_user = mode % 8 > (mode >> 6) % 8 group_more_generous_than_user = (mode >> 3) % 8 > (mode >> 6) % 8 return bool( other_write_without_read or group_write_without_read or user_write_without_read or other_more_generous_than_group or other_more_generous_than_user or group_more_generous_than_user, ) def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: if task["action"]["__ansible_module__"] in self._modules: mode = task["action"].get("mode", None) if isinstance(mode, str): return False if isinstance(mode, int) and self.is_invalid_permission(mode): return f'`mode: {mode}` should have a string value with leading zero `mode: "0{mode:o}"` or use symbolic mode.' return False if "pytest" in sys.modules: import pytest VALID_MODES = [ 0o777, 0o775, 0o770, 0o755, 0o750, 0o711, 0o710, 0o700, 0o666, 0o664, 0o660, 0o644, 0o640, 0o600, 0o555, 0o551, 0o550, 0o511, 0o510, 0o500, 0o444, 0o440, 0o400, ] INVALID_MODES = [ 777, 775, 770, 755, 750, 711, 710, 700, 666, 664, 660, 644, 640, 622, 620, 600, 555, 551, 550, # 511 == 0o777, 510 == 0o776, 500 == 0o764 444, 440, 400, ] @pytest.mark.parametrize( ("file", "failures"), ( pytest.param("examples/playbooks/rule-risky-octal-pass.yml", 0, id="pass"), pytest.param("examples/playbooks/rule-risky-octal-fail.yml", 4, id="fail"), ), ) def test_octal(file: str, failures: int) -> None: """Test that octal permissions are valid.""" collection = RulesCollection() collection.register(OctalPermissionsRule()) results = Runner(file, rules=collection).run() assert len(results) == failures for result in results: assert result.rule.id == "risky-octal" def test_octal_valid_modes() -> None: """Test that octal modes are valid.""" rule = OctalPermissionsRule() for mode in VALID_MODES: assert not rule.is_invalid_permission( mode, ), f"0o{mode:o} should be a valid mode" def test_octal_invalid_modes() -> None: """Test that octal modes are invalid.""" rule = OctalPermissionsRule() for mode in INVALID_MODES: assert rule.is_invalid_permission( mode, ), f"{mode:d} should be an invalid mode" ansible-ansible-lint-c16f018/src/ansiblelint/rules/risky_shell_pipe.md000066400000000000000000000021201477347356000261670ustar00rootroot00000000000000# risky-shell-pipe This rule checks for the bash `pipefail` option with the Ansible `shell` module. You should always set `pipefail` when piping output from one command to another. The return status of a pipeline is the exit status of the command. The `pipefail` option ensures that tasks fail as expected if the first command fails. As this requirement does not apply to PowerShell, for shell commands that have `pwsh` inside `executable` attribute, this rule will not trigger. ## Problematic Code ```yaml --- - name: Example playbook hosts: localhost tasks: - name: Pipeline without pipefail ansible.builtin.shell: false | cat ``` ## Correct Code ```yaml --- - name: Example playbook hosts: localhost become: false tasks: - name: Pipeline with pipefail ansible.builtin.shell: cmd: set -o pipefail && false | cat executable: /bin/bash - name: Pipeline with pipefail, multi-line ansible.builtin.shell: cmd: | set -o pipefail # <-- adding this will prevent surprises false | cat executable: /bin/bash ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/risky_shell_pipe.py000066400000000000000000000055311477347356000262300ustar00rootroot00000000000000"""Implementation of risky-shell-pipe rule.""" from __future__ import annotations import re import sys from typing import TYPE_CHECKING from ansiblelint.rules import AnsibleLintRule from ansiblelint.utils import convert_to_boolean, get_cmd_args if TYPE_CHECKING: from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task class ShellWithoutPipefail(AnsibleLintRule): """Shells that use pipes should set the pipefail option.""" id = "risky-shell-pipe" description = ( "Without the pipefail option set, a shell command that " "implements a pipeline can fail and still return 0. If " "any part of the pipeline other than the terminal command " "fails, the whole pipeline will still return 0, which may " "be considered a success by Ansible. " "Pipefail is available in the bash shell." ) severity = "MEDIUM" tags = ["command-shell"] version_changed = "4.1.0" _pipefail_re = re.compile(r"^\s*set.*[+-][A-Za-z]*o\s*pipefail", re.MULTILINE) _pipe_re = re.compile(r"(? bool | str: if task["__ansible_action_type__"] != "task": # pragma: no cover return False if task["action"]["__ansible_module__"] != "shell": return False if task.get("ignore_errors"): # pragma: no cover return False jinja_stripped_cmd = self.unjinja(get_cmd_args(task)) # https://github.com/ansible/ansible-lint/issues/3161 if "pwsh" in task["action"].get("executable", ""): return False return bool( self._pipe_re.search(jinja_stripped_cmd) and not self._pipefail_re.search(jinja_stripped_cmd) and not convert_to_boolean(task["action"].get("ignore_errors", False)), ) if "pytest" in sys.modules: import pytest # pylint: disable=ungrouped-imports from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner @pytest.mark.parametrize( ("file", "expected"), ( pytest.param( "examples/playbooks/rule-risky-shell-pipe-pass.yml", 0, id="pass", ), pytest.param( "examples/playbooks/rule-risky-shell-pipe-fail.yml", 3, id="fail", ), ), ) def test_risky_shell_pipe( default_rules_collection: RulesCollection, file: str, expected: int, ) -> None: """Validate that rule works as intended.""" results = Runner(file, rules=default_rules_collection).run() for result in results: assert result.rule.id == ShellWithoutPipefail.id, result assert len(results) == expected ansible-ansible-lint-c16f018/src/ansiblelint/rules/role_name.md000066400000000000000000000022001477347356000245620ustar00rootroot00000000000000# role-name This rule checks role names to ensure they conform with requirements. Role names must contain only lowercase alphanumeric characters and the underscore `_` character. Role names must also start with an alphabetic character. For more information see the [roles directory](https://docs.ansible.com/ansible/devel/dev_guide/developing_collections_structure.html#roles-directory) topic in Ansible documentation. `role-name[path]` message tells you to avoid using paths when importing roles. You should only rely on Ansible's ability to find the role and refer to them using fully qualified names. ## Problematic Code ```yaml --- - name: Example playbook hosts: localhost roles: - 1myrole # <- Does not start with an alphabetic character. - myrole2[*^ # <- Contains invalid special characters. - myRole_3 # <- Contains uppercase alphabetic characters. ``` ## Correct Code ```yaml --- - name: Example playbook hosts: localhost roles: - myrole1 # <- Starts with an alphabetic character. - myrole2 # <- Contains only alphanumeric characters. - myrole_3 # <- Contains only lowercase alphabetic characters. ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/role_name.py000066400000000000000000000211701477347356000246210ustar00rootroot00000000000000"""Implementation of role-name rule.""" # Copyright (c) 2020 Gael Chamoulaud # Copyright (c) 2020 Sorin Sbarnea # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from __future__ import annotations import re import sys from functools import cache from typing import TYPE_CHECKING from ansiblelint.constants import ROLE_IMPORT_ACTION_NAMES from ansiblelint.rules import AnsibleLintRule from ansiblelint.utils import parse_yaml_from_file from ansiblelint.yaml_utils import get_line_column if TYPE_CHECKING: from pathlib import Path from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task ROLE_NAME_REGEX = re.compile(r"^[a-z][a-z0-9_]*$") def _remove_prefix(text: str, prefix: str) -> str: return re.sub(rf"^{re.escape(prefix)}", "", text) @cache def _match_role_name_regex(role_name: str) -> bool: return ROLE_NAME_REGEX.match(role_name) is not None class RoleNames(AnsibleLintRule): """Role name {0} does not match ``^[a-z][a-z0-9_]*$`` pattern.""" id = "role-name" description = ( "Role names are now limited to contain only lowercase alphanumeric " "characters, plus underline and start with an alpha character." ) link = "https://docs.ansible.com/ansible/devel/dev_guide/developing_collections_structure.html#roles-directory" severity = "HIGH" tags = ["deprecations", "metadata"] version_changed = "6.8.5" _ids = { "role-name[path]": "Avoid using paths when importing roles.", } def matchtask( self, task: Task, file: Lintable | None = None, ) -> list[MatchError]: results = [] if task["action"]["__ansible_module__"] in ROLE_IMPORT_ACTION_NAMES: name = task["action"].get("name", "") if "/" in name: results.append( self.create_matcherror( f"Avoid using paths when importing roles. ({name})", filename=file, lineno=task.line, tag=f"{self.id}[path]", ), ) return results def matchdir(self, lintable: Lintable) -> list[MatchError]: return self.matchyaml(lintable) def matchyaml(self, file: Lintable) -> list[MatchError]: result: list[MatchError] = [] column: int | None = None if file.kind not in ("meta", "role", "playbook"): return result if file.kind == "meta" and file.data: for role in file.data.get("dependencies", []): if isinstance(role, dict): role_name = role["role"] elif isinstance(role, str): role_name = role else: # pragma: no cover msg = "Role dependency has unexpected type." raise TypeError(msg) if "/" in role_name: result.append( self.create_matcherror( f"Avoid using paths when importing roles. ({role_name})", filename=file, data=role_name, tag=f"{self.id}[path]", ), ) return result if file.kind == "playbook": for play in file.data: if "roles" in play: line, column = get_line_column(play) for role in play["roles"]: role_name = None if isinstance(role, dict): line, column = get_line_column(role) role_name = role["role"] elif isinstance(role, str): role_name = role if not isinstance(role_name, str): # pragma: no cover msg = "Role dependency has unexpected type." raise TypeError(msg) if "/" in role_name: result.append( self.create_matcherror( f"Avoid using paths when importing roles. ({role_name})", filename=file, lineno=line, column=column, tag=f"{self.id}[path]", ), ) return result if file.kind == "role": role_name = self._infer_role_name( meta=file.path / "meta" / "main.yml", default=file.path.name, ) else: role_name = self._infer_role_name( meta=file.path, default=file.path.resolve().parents[1].name, ) role_name = _remove_prefix(role_name, "ansible-role-") if role_name and not _match_role_name_regex(role_name): result.append( self.create_matcherror( filename=file, message=self.shortdesc.format(role_name), ), ) return result @staticmethod def _infer_role_name(meta: Path, default: str) -> str: if meta.is_file(): meta_data = parse_yaml_from_file(str(meta)) if meta_data and isinstance(meta_data, dict): try: return str(meta_data["galaxy_info"]["role_name"]) except (KeyError, TypeError): pass return default 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", "failure"), (pytest.param("examples/playbooks/rule-role-name-path.yml", 3, id="fail"),), ) def test_role_name_path( default_rules_collection: RulesCollection, test_file: str, failure: int, ) -> None: """Test rule matches.""" results = Runner(test_file, rules=default_rules_collection).run() for result in results: assert result.tag == "role-name[path]" assert len(results) == failure @pytest.mark.parametrize( ("test_file", "failure"), (pytest.param("examples/roles/role_with_deps_paths", 3, id="fail"),), ) def test_role_deps_path_names( default_rules_collection: RulesCollection, test_file: str, failure: int, ) -> None: """Test rule matches.""" results = Runner( test_file, rules=default_rules_collection, ).run() expected_errors = ( ("role-name[path]", 3), ("role-name[path]", 9), ("role-name[path]", 10), ) assert len(expected_errors) == failure for idx, result in enumerate(results): assert result.tag == expected_errors[idx][0] assert result.lineno == expected_errors[idx][1] assert len(results) == failure @pytest.mark.parametrize( ("test_file", "failure"), (pytest.param("examples/roles/test-no-deps-role", 0, id="no_deps"),), ) def test_role_no_deps( default_rules_collection: RulesCollection, test_file: str, failure: int, ) -> None: """Test role if no dependencies are present in meta/main.yml.""" results = Runner( test_file, rules=default_rules_collection, ).run() assert len(results) == failure ansible-ansible-lint-c16f018/src/ansiblelint/rules/run_once.md000066400000000000000000000042621477347356000244430ustar00rootroot00000000000000# run-once This rule warns against the use of `run_once` when the `strategy` is set to `free`. This rule can produce the following messages: - `run-once[play]`: Play uses `strategy: free`. - `run-once[task]`: Using `run_once` may behave differently if the `strategy` is set to `free`. For more information see the following topics in Ansible documentation: - [free strategy](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/free_strategy.html#free-strategy) - [selecting a strategy](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_strategies.html#selecting-a-strategy) - [run_once(playbook keyword) more info](https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html) !!! warning The reason for the existence of this rule is for reminding users that `run_once` is not providing any warranty that the task will run only once. This rule will always trigger regardless of the value configured inside the 'strategy' field. That is because the effective value used at runtime can be different than the value inside the file. For example, ansible command line arguments can alter it. It is perfectly fine to add `# noqa: run-once[task]` to mark the warning as acknowledged and ignored. ## Problematic Code ```yaml --- - name: "Example with run_once" hosts: all strategy: free # <-- avoid use of strategy as free gather_facts: false tasks: - name: Task with run_once ansible.builtin.debug: msg: "Test" run_once: true # <-- avoid use of strategy as free at play level when using run_once at task level ``` ## Correct Code ```yaml - name: "Example without run_once" hosts: all gather_facts: false tasks: - name: Task without run_once ansible.builtin.debug: msg: "Test" ``` ```yaml - name: "Example of using run_once with strategy other than free" hosts: all strategy: linear # strategy: free # noqa: run-once[play] (if using strategy: free can skip it this way) gather_facts: false tasks: # <-- use noqa to disable rule violations for specific tasks - name: Task with run_once # noqa: run-once[task] ansible.builtin.debug: msg: "Test" run_once: true ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/run_once.py000066400000000000000000000060771477347356000245010ustar00rootroot00000000000000"""Optional Ansible-lint rule to warn use of run_once with strategy free.""" from __future__ import annotations import sys from typing import TYPE_CHECKING, Any from ansiblelint.rules import AnsibleLintRule if TYPE_CHECKING: from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task class RunOnce(AnsibleLintRule): """Run once should use strategy other than free.""" id = "run-once" link = "https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html" description = "When using run_once, we should avoid using strategy as free." tags = ["idiom"] severity = "MEDIUM" version_changed = "6.12.0" _ids = { "run-once[task]": "Using run_once may behave differently if strategy is set to free.", "run-once[play]": "Play uses strategy: free", } def matchplay(self, file: Lintable, data: dict[str, Any]) -> list[MatchError]: """Return matches found for a specific playbook.""" # If the Play uses the 'strategy' and it's value is set to free if not file or file.kind != "playbook" or not data: return [] strategy: Any = data.get("strategy") run_once = data.get("run_once", False) if (not strategy and not run_once) or strategy != "free": return [] lineno = getattr(strategy, "_line_number", 1) return [ self.create_matcherror( message="Play uses strategy: free", filename=file, tag=f"{self.id}[play]", lineno=lineno, ), ] def matchtask( self, task: Task, file: Lintable | None = None, ) -> list[MatchError]: """Return matches for a task.""" if not file or file.kind != "playbook": return [] run_once = task.get("run_once", False) if not run_once: return [] return [ self.create_matcherror( message="Using run_once may behave differently if strategy is set to free.", filename=file, tag=f"{self.id}[task]", lineno=task.line, ), ] # 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", "failure"), ( pytest.param("examples/playbooks/run-once-pass.yml", 0, id="pass"), pytest.param("examples/playbooks/run-once-fail.yml", 2, id="fail"), ), ) def test_run_once( default_rules_collection: RulesCollection, test_file: str, failure: int, ) -> None: """Test rule matches.""" results = Runner(test_file, rules=default_rules_collection).run() for result in results: assert result.rule.id == RunOnce().id assert len(results) == failure ansible-ansible-lint-c16f018/src/ansiblelint/rules/sanity.md000066400000000000000000000026651477347356000241470ustar00rootroot00000000000000# sanity This rule checks the `tests/sanity/ignore-x.x.txt` file for disallowed ignores. This rule is extremely opinionated and enforced by Partner Engineering as a requirement for Red Hat Certification. The currently allowed ruleset is subject to change, but is starting at a minimal number of allowed ignores for maximum test enforcement. Any commented-out ignore entries are not evaluated, and ignore files for unsupported versions of ansible-core are not evaluated. This rule can produce messages like: - `sanity[cannot-ignore]` - Ignore file contains {test} at line {line_num}, which is not a permitted ignore. - `sanity[bad-ignore]` - Ignore file entry at {line_num} is formatted incorrectly. Please review. Currently allowed ignores for all Ansible versions are: - `validate-modules:missing-gplv3-license` - `action-plugin-docs` - `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` - `shellcheck` - `shebang` - `pylint:used-before-assignment` ## Problematic code ``` # tests/sanity/ignore-x.x.txt plugins/module_utils/ansible_example_module.py import-3.6!skip ``` ``` # tests/sanity/ignore-x.x.txt plugins/module_utils/ansible_example_module.oops-3.6!skip ``` ## Correct code ``` # tests/sanity/ignore-x.x.txt plugins/module_utils/ansible_example_module.py import-2.7!skip ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/sanity.py000066400000000000000000000125631477347356000241750ustar00rootroot00000000000000"""Implementation of sanity rule.""" from __future__ import annotations import re 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_changed = "6.14.0" # Partner Engineering defines this list. Please contact PE for changes. allowed_ignores = [ "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", "shebang", # Unreliable test "shellcheck", # Unreliable test "pylint:used-before-assignment", # Unreliable test ] no_check_ignore_files = [ "ignore-2.9", "ignore-2.10", "ignore-2.11", "ignore-2.12", ] _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 = "" check_dirs = { "plugins", "roles", } if file.kind != "sanity-ignore-file": return [] with file.path.open(encoding="utf-8") as ignore_file: entries = ignore_file.read().splitlines() if any(name in str(file.abspath) for name in self.no_check_ignore_files): return [] for line_num, entry in enumerate(entries, 1): base_ignore_dir = "" if entry: # match up to the first "/" regex = re.match(r"[^/]*", entry) if regex: base_ignore_dir = regex.group(0) if base_ignore_dir in check_dirs: try: if "#" in entry: entry, _ = entry.split("#") (_, test) = entry.split() if test not in self.allowed_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 # pylint: disable=ungrouped-imports from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner @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 ansible-ansible-lint-c16f018/src/ansiblelint/rules/schema.md000066400000000000000000000072341477347356000240750ustar00rootroot00000000000000# schema The `schema` rule validates Ansible metadata files against JSON schemas. These schemas ensure the compatibility of Ansible syntax content across versions. This `schema` rule is **mandatory**. You cannot use inline `noqa` comments to ignore it. Ansible-lint validates the `schema` rule before processing other rules. This prevents unexpected syntax from triggering multiple rule violations. ## Validated schema Ansible-lint currently validates several schemas that are maintained in separate projects and updated independently to ansible-lint. > Report bugs related to schema in their respective repository and not in the > ansible-lint project. Maintained in the [ansible-lint](https://github.com/ansible/ansible-lint) project: - `schema[ansible-lint-config]` validates [ansible-lint configuration](https://github.com/ansible/ansible-lint/blob/main/src/ansiblelint/schemas/ansible-lint-config.json) - `schema[role-arg-spec]` validates [role argument specs](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html#specification-format) which is a little bit different than the module argument spec. - `schema[execution-environment]` validates [execution environments](https://docs.ansible.com/automation-controller/latest/html/userguide/execution_environments.html) - `schema[galaxy]` validates [collection metadata](https://docs.ansible.com/ansible/latest/dev_guide/collections_galaxy_meta.html). - `schema[inventory]` validates [inventory files](https://docs.ansible.com/ansible/latest/inventory_guide/intro_inventory.html) that match `inventory/*.yml`. - `schema[meta-runtime]` validates [runtime information](https://docs.ansible.com/ansible/devel/dev_guide/developing_collections_structure.html#meta-directory-and-runtime-yml) that matches `meta/runtime.yml` - `schema[meta]` validates metadata for roles that match `meta/main.yml`. See [role-dependencies](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html#role-dependencies) or [role/metadata.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/playbook/role/metadata.py#L79)) for details. - `schema[playbook]` validates Ansible playbooks. - `schema[requirements]` validates Ansible [requirements](https://docs.ansible.com/ansible/latest/galaxy/user_guide.html#install-multiple-collections-with-a-requirements-file) files that match `requirements.yml`. - `schema[tasks]` validates Ansible task files that match `tasks/**/*.yml`. - `schema[vars]` validates Ansible [variables](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html) that match `vars/*.yml` and `defaults/*.yml`. Maintained in the [ansible-navigator](https://github.com/ansible/ansible-navigator) project: - `schema[ansible-navigator]` validates [ansible-navigator configuration](https://github.com/ansible/ansible-navigator/blob/main/src/ansible_navigator/data/ansible-navigator.json) ## schema[meta] For `meta/main.yml` files, Ansible-lint requires a `galaxy_info.standalone` property that clarifies if a role is an old standalone one or a new one, collection based: ```yaml galaxy_info: standalone: true # <-- this is a standalone role (not part of a collection) ``` Ansible-lint requires the `standalone` key to avoid confusion and provide more specific error messages. For example, the `meta` schema will require some properties only for standalone roles or prevent the use of some properties that are not supported by collections. You cannot use an empty `meta/main.yml` file or use only comments in the `meta/main.yml` file. ## schema[moves] These errors usually look like "foo was moved to bar in 2.10" and indicate module moves between Ansible versions. ansible-ansible-lint-c16f018/src/ansiblelint/rules/schema.py000066400000000000000000000341311477347356000241210ustar00rootroot00000000000000"""Rule definition for JSON Schema Validations.""" from __future__ import annotations import logging import re import sys from typing import TYPE_CHECKING, Any from ansiblelint.file_utils import Lintable from ansiblelint.rules import AnsibleLintRule from ansiblelint.schemas.__main__ import JSON_SCHEMAS from ansiblelint.schemas.main import validate_file_schema from ansiblelint.text import has_jinja if TYPE_CHECKING: from collections.abc import MutableMapping from ansiblelint.config import Options from ansiblelint.errors import MatchError from ansiblelint.utils import Task _logger = logging.getLogger(__name__) DESCRIPTION_MD = """ Returned errors will not include exact line numbers, but they will mention the schema name being used as a tag, like ``schema[playbook]``, ``schema[tasks]``. This rule is not skippable and stops further processing of the file. If incorrect schema was picked, you might want to either: * move the file to standard location, so its file is detected correctly. * use ``kinds:`` option in linter config to help it pick correct file type. """ pre_checks = { "task": { "with_flattened": { "msg": "with_flattened was moved to with_community.general.flattened in 2.10", "tag": "moves", }, "with_filetree": { "msg": "with_filetree was moved to with_community.general.filetree in 2.10", "tag": "moves", }, "with_cartesian": { "msg": "with_cartesian was moved to with_community.general.flattened in 2.10", "tag": "moves", }, }, } class ValidateSchemaRule(AnsibleLintRule): """Perform JSON Schema Validation for known lintable kinds.""" description = DESCRIPTION_MD id = "schema" severity = "VERY_HIGH" tags = ["core"] version_changed = "6.1.0" _ids = { "schema[ansible-lint-config]": "", "schema[ansible-navigator-config]": "", "schema[changelog]": "", "schema[execution-environment]": "", "schema[galaxy]": "", "schema[inventory]": "", "schema[meta]": "", "schema[meta-runtime]": "", "schema[molecule]": "", "schema[playbook]": "", "schema[requirements]": "", "schema[role-arg-spec]": "", "schema[rulebook]": "", "schema[tasks]": "", "schema[vars]": "", } _field_checks: dict[str, list[str]] = {} @property def field_checks(self) -> dict[str, list[str]]: """Lazy property for returning field checks.""" if not self._collection: msg = "Rule was not registered to a RuleCollection." raise RuntimeError(msg) if not self._field_checks: self._field_checks = { "become_method": sorted( self._collection.app.runtime.plugins.become.keys(), ), } return self._field_checks def matchplay(self, file: Lintable, data: dict[str, Any]) -> list[MatchError]: """Return matches found for a specific playbook.""" results: list[MatchError] = [] if ( not data or file.kind not in ("tasks", "handlers", "playbook") or file.failed() ): return results # check at play level results.extend(self._get_field_matches(file=file, data=data)) return results def _get_field_matches( self, file: Lintable | None, data: MutableMapping[str, Any], ) -> list[MatchError]: """Retrieve all matches related to fields for the given data block.""" results = [] kind = "tasks" if not file else file.kind for key, values in self.field_checks.items(): if key in data: plugin_value = data[key] if not has_jinja(plugin_value) and plugin_value not in values: msg = f"'{key}' must be one of the currently available values: {', '.join(values)}" results.append( self.create_matcherror( message=msg, data=plugin_value, filename=file, details=ValidateSchemaRule.description, tag=f"schema[{kind}]", ), ) return results def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str | MatchError | list[MatchError]: results: list[MatchError] = [] if not file: file = Lintable("", kind="tasks") if file and file.failed(): return results results.extend(self._get_field_matches(file=file, data=task.raw_task)) for key in pre_checks["task"]: if key in task.raw_task: msg = pre_checks["task"][key]["msg"] tag = pre_checks["task"][key]["tag"] results.append( self.create_matcherror( message=msg, filename=file, details=ValidateSchemaRule.description, tag=f"schema[{tag}]", ), ) return results def matchyaml(self, file: Lintable) -> list[MatchError]: """Return JSON validation errors found as a list of MatchError(s).""" result: list[MatchError] = [] if file.failed(): return result if file.kind not in JSON_SCHEMAS: return result for error in validate_file_schema(file): if error.startswith("Failed to load YAML file"): _logger.debug( "Ignored failure to load %s for schema validation, as !vault may cause it.", file, ) return [] result.append( self.create_matcherror( message=error, filename=file, details=ValidateSchemaRule.description, tag=f"schema[{file.kind}]", ), ) break if not result: result = super().matchyaml(file) return result # 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( ("file", "expected_kind", "expected"), ( pytest.param( "examples/.collection/galaxy.yml", "galaxy", [r".*'GPL' is not one of.*https://"], id="galaxy", ), pytest.param( "examples/roles/invalid_requirements_schema/meta/requirements.yml", "requirements", [ # r".*{'foo': 'bar'} is not valid under any of the given schemas.*https://", r".*{'foo': 'bar'} is not of type 'array'.*https://", ], id="requirements", ), pytest.param( "examples/roles/invalid_meta_schema/meta/main.yml", "meta", [r".*False is not of type 'string'.*https://"], id="meta", ), pytest.param( "examples/playbooks/vars/invalid_vars_schema.yml", "vars", [r".* '123' does not match any of the regexes.*https://"], id="vars", ), pytest.param( "examples/execution-environment.yml", "execution-environment", [], id="execution-environment", ), pytest.param( "examples/ee_broken/execution-environment.yml", "execution-environment", [ r".*Additional properties are not allowed \('foo' was unexpected\).*https://", ], id="execution-environment-broken", ), pytest.param( "examples/meta/runtime.yml", "meta-runtime", [], id="meta-runtime", ), pytest.param( "examples/broken_collection_meta_runtime/meta/runtime.yml", "meta-runtime", [ r".*Additional properties are not allowed \('foo' was unexpected\).*https://", ], id="meta-runtime-broken", ), pytest.param( "examples/inventory/production.yml", "inventory", [], id="inventory", ), pytest.param( "examples/inventory/broken_dev_inventory.yml", "inventory", [ r".*Additional properties are not allowed \('foo' was unexpected\).*https://", ], id="inventory-broken", ), pytest.param( ".ansible-lint", "ansible-lint-config", [], id="ansible-lint-config", ), pytest.param( "examples/.config/ansible-lint.yml", "ansible-lint-config", [], id="ansible-lint-config2", ), pytest.param( "examples/broken/.ansible-lint", "ansible-lint-config", [ r".*Additional properties are not allowed \('foo' was unexpected\).*https://", ], id="ansible-lint-config-broken", ), pytest.param( "examples/broken_supported_ansible_also/.ansible-lint", "ansible-lint-config", [ r".*supported_ansible_also True is not of type 'array'.*https://", ], id="ansible-lint-config-broken", ), pytest.param( "examples/ansible-navigator.yml", "ansible-navigator-config", [], id="ansible-navigator-config", ), pytest.param( "examples/broken/ansible-navigator.yml", "ansible-navigator-config", [ r".*Additional properties are not allowed \('ansible' was unexpected\).*https://", ], id="ansible-navigator-config-broken", ), pytest.param( "examples/roles/hello/meta/argument_specs.yml", "role-arg-spec", [], id="role-arg-spec", ), pytest.param( "examples/roles/broken_argument_specs/meta/argument_specs.yml", "role-arg-spec", [ r".*Additional properties are not allowed \('foo' was unexpected\).*https://", ], id="role-arg-spec-broken", ), pytest.param( "examples/changelogs/changelog.yaml", "changelog", [ r".*Additional properties are not allowed \('foo' was unexpected\).*https://", ], id="changelog", ), pytest.param( "examples/rulebooks/rulebook-fail.yml", "rulebook", [ # r".*Additional properties are not allowed \('that_should_not_be_here' was unexpected\).*https://", r".*'sss' is not of type 'object'.*https://", ], id="rulebook", ), pytest.param( "examples/rulebooks/rulebook-pass.yml", "rulebook", [], id="rulebook2", ), pytest.param( "examples/playbooks/rule-schema-become-method-pass.yml", "playbook", [], id="playbook", ), pytest.param( "examples/playbooks/rule-schema-become-method-fail.yml", "playbook", [ "'become_method' must be one of the currently available values", "'become_method' must be one of the currently available values", ], id="playbook2", ), ), ) def test_schema( file: str, expected_kind: str, expected: list[str], config_options: Options, ) -> None: """Validate parsing of ansible output.""" lintable = Lintable(file) assert lintable.kind == expected_kind rules = RulesCollection(options=config_options) rules.register(ValidateSchemaRule()) results = Runner(lintable, rules=rules).run() assert len(results) == len(expected), results for idx, result in enumerate(results): assert result.filename.endswith(file) assert re.match(expected[idx], result.message) assert result.tag == f"schema[{expected_kind}]" @pytest.mark.parametrize( ("file", "expected_kind", "expected_tag", "count"), ( pytest.param( "examples/playbooks/rule-syntax-moves.yml", "playbook", "schema[moves]", 3, id="playbook", ), ), ) def test_schema_moves( file: str, expected_kind: str, expected_tag: str, count: int, config_options: Options, ) -> None: """Validate ability to detect schema[moves].""" lintable = Lintable(file) assert lintable.kind == expected_kind rules = RulesCollection(options=config_options) rules.register(ValidateSchemaRule()) results = Runner(lintable, rules=rules).run() assert len(results) == count, results for result in results: assert result.filename.endswith(file) assert result.tag == expected_tag ansible-ansible-lint-c16f018/src/ansiblelint/rules/syntax_check.md000066400000000000000000000047741477347356000253260ustar00rootroot00000000000000# syntax-check Our linter runs `ansible-playbook --syntax-check` on all playbooks, and if any of these reports a syntax error, this stops any further processing of these files. This error **cannot be disabled** due to being a prerequisite for other steps. You can exclude these files from linting, but it is better to make sure they can be loaded by Ansible. This is often achieved by editing the inventory file and/or `ansible.cfg` so ansible can load required variables. If undefined variables cause the failure, you can use the Jinja `default()` filter to provide fallback values, like in the example below. This rule is among the few `unskippable` rules that cannot be added to `skip_list` or `warn_list`. One possible workaround is to add the entire file to the `exclude_paths`. This is a valid approach for special cases, like testing fixtures that are invalid on purpose. One of the most common sources of errors is a failure to assert the presence of various variables at the beginning of the playbook. This rule can produce messages like: - `syntax-check[empty-playbook]`: Empty playbook, nothing to do - `syntax-check[malformed]`: A malformed block was encountered while loading a block - `syntax-check[missing-file]`: Unable to retrieve file contents ... Could not find or access ... - `syntax-check[unknown-module]`: couldn't resolve module/action - `syntax-check[specific]`: for other errors not mentioned above. ## syntax-check[unknown-module] The linter relies on ansible-core code to load the ansible code and it will produce a syntax error if the code refers to ansible content that is not installed. You must ensure that all collections and roles used inside your repository are listed inside a [`requirements.yml`](https://docs.ansible.com/ansible/latest/galaxy/user_guide.html#installing-roles-and-collections-from-the-same-requirements-yml-file) file, so the linter can install them when they are missing. Valid location for `requirements.yml` are: - `requirements.yml` - `roles/requirements.yml` - `collections/requirements.yml` - `tests/requirements.yml` - `tests/integration/requirements.yml` - `tests/unit/requirements.yml` Note: If requirements are test related then they should be inside `tests/`. ## Problematic code ```yaml --- - name: Bad use of variable inside hosts block (wrong assumption of it being defined) hosts: "{{ my_hosts }}" tasks: [] ``` ## Correct code ```yaml --- - name: Good use of variable inside hosts, without assumptions hosts: "{{ my_hosts | default([]) }}" tasks: [] ``` ansible-ansible-lint-c16f018/src/ansiblelint/rules/syntax_check.py000066400000000000000000000073651477347356000253550ustar00rootroot00000000000000"""Rule definition for ansible syntax check.""" from __future__ import annotations import re from dataclasses import dataclass from ansiblelint.rules import AnsibleLintRule from ansiblelint.types import ansible_error_format @dataclass class KnownError: """Class that tracks result of linting.""" tag: str regex: re.Pattern[str] if ansible_error_format == 1: _ansible_error_prefix = "ERROR! " _ansible_error_detail = r"\n\nThe error appears to be in '(?P[\w\/\.\-]+)': line (?P\d+), column (?P\d+)" elif ansible_error_format == 2: # 2.19 with data tagging _ansible_error_prefix = r"\[ERROR\]: " _ansible_error_detail = ( r"\nOrigin: (?P[\w\/\.\-]+):(?P\d+):(?P\d+)" ) else: # pragma: no cover msg = f"Unsupported ansible_error_format: {ansible_error_format}" raise NotImplementedError(msg) # Order matters, we only report the first matching pattern, the one at the end # is used to match generic or less specific patterns. OUTPUT_PATTERNS = ( KnownError( tag="missing-file", regex=re.compile( # do not use capture group for this because we want to report original file, not the missing target one r"(?PUnable to retrieve file contents)\n(?P<details>Could not find or access '(?P<value>.*)'[^\n]*)", re.MULTILINE | re.DOTALL | re.DOTALL, ), ), KnownError( tag="no-file", regex=re.compile( rf"^{_ansible_error_prefix}(?P<title>No file specified for [^\n]*){_ansible_error_detail}", re.MULTILINE | re.DOTALL | re.DOTALL, ), ), KnownError( tag="empty-playbook", regex=re.compile( r"Empty playbook, nothing to do", re.MULTILINE | re.DOTALL | re.DOTALL, ), ), KnownError( tag="malformed", regex=re.compile( rf"^(statically imported: (?P<filename>[\w\/\.\-]+)\n)?{_ansible_error_prefix}(?P<title>A malformed block was encountered while loading a block[^\n]*)", re.MULTILINE | re.DOTALL | re.DOTALL, ), ), KnownError( tag="unknown-module", regex=re.compile( rf"^{_ansible_error_prefix}(?P<title>couldn't resolve module/action [^\n]*){_ansible_error_detail}", re.MULTILINE | re.DOTALL | re.DOTALL, ), ), KnownError( tag="specific", regex=re.compile( rf"^{_ansible_error_prefix}(?P<title>[^\n]*){_ansible_error_detail}", re.MULTILINE | re.DOTALL | re.DOTALL, ), ), # "ERROR! the role 'this_role_is_missing' was not found in ROLE_INCLUDE_PATHS\n\nThe error appears to be in 'FILE_PATH': line 5, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n roles:\n - this_role_is_missing\n ^ here\n" KnownError( tag="specific", regex=re.compile( rf"^{_ansible_error_prefix}(?P<title>the role '.*' was not found in[^\n]*){_ansible_error_detail}", re.MULTILINE | re.DOTALL | re.DOTALL, ), ), # 2.19: # [ERROR]: no module/action detected in task. # Origin: /Users/ssbarnea/code/a/ansible-lint/examples/roles/invalid_due_syntax/tasks/main.yml:2:3 # KnownError( # tag="specific", # regex=re.compile( # r"^\[ERROR\]: (?P<title>[^\n]*)\nOrigin: (?P<filename>[\w\/\.\-]+):(?P<line>\d+):(?P<column>\d+)", # re.MULTILINE | re.DOTALL | re.DOTALL, # ), # ), ) class AnsibleSyntaxCheckRule(AnsibleLintRule): """Ansible syntax check failed.""" id = "syntax-check" severity = "VERY_HIGH" tags = ["core", "unskippable"] version_changed = "5.0.0" _order = 0 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/rules/var_naming.md������������������������������������0000664�0000000�0000000�00000005524�14773473560�0024756�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# var-naming This rule checks variable names to ensure they conform with requirements. Variable names must contain only lowercase alphanumeric characters and the underscore `_` character. Variable names must also start with either an alphabetic or underscore `_` character. For more information see the [creating valid variable names][var-names] topic in Ansible documentation and [Naming things (Good Practices for Ansible)][cop]. You should also be fully aware of [special variables][magic-vars], also known as magic variables, especially as most of them can only be read. While Ansible will just ignore any attempt to set them, the linter will notify the user, so they would not be confused about a line that does not effectively do anything. Possible errors messages: - `var-naming[non-string]`: Variables names must be strings. - `var-naming[non-ascii]`: Variables names must be ASCII. - `var-naming[no-keyword]`: Variables names must not be Python keywords. - `var-naming[no-jinja]`: Variables names must not contain jinja2 templating. - `var-naming[pattern]`: Variables names should match ... regex. - `var-naming[no-role-prefix]`: Variables names from within roles should use `role_name_` as a prefix. Underlines are accepted before the prefix. - `var-naming[no-reserved]`: Variables names must not be Ansible reserved names. - `var-naming[read-only]`: This special variable is read-only. !!! note When using `include_role` or `import_role` with `vars`, vars should start with included role name prefix. As this role might not be compliant with this rule yet, you might need to temporarily disable this rule using a `# noqa: var-naming[no-role-prefix]` comment. ## Settings This rule behavior can be changed by altering the below settings: ```yaml # .ansible-lint var_naming_pattern: "^[a-z_][a-z0-9_]*$" ``` ## Problematic Code ```yaml --- - name: Example playbook hosts: localhost vars: CamelCase: true # <- Contains a mix of lowercase and uppercase characters. ALL_CAPS: bar # <- Contains only uppercase characters. v@r!able: baz # <- Contains special characters. hosts: [] # <- hosts is an Ansible reserved name role_name: boo # <-- invalid as being Ansible special magic variable ``` ## Correct Code ```yaml --- - name: Example playbook hosts: localhost vars: lowercase: true # <- Contains only lowercase characters. no_caps: bar # <- Does not contains uppercase characters. variable: baz # <- Does not contain special characters. my_hosts: [] # <- Does not use a reserved names. my_role_name: boo ``` [cop]: https://redhat-cop.github.io/automation-good-practices/#_naming_things [var-names]: https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#creating-valid-variable-names [magic-vars]: https://docs.ansible.com/ansible/latest/reference_appendices/special_variables.html ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/rules/var_naming.py������������������������������������0000664�0000000�0000000�00000043420�14773473560�0025003�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Implementation of var-naming rule.""" from __future__ import annotations import keyword import re import sys from typing import TYPE_CHECKING, Any, NamedTuple from ansible.vars.reserved import get_reserved_names from ansiblelint.config import Options, options from ansiblelint.constants import ( ANNOTATION_KEYS, PLAYBOOK_ROLE_KEYWORDS, RC, ) from ansiblelint.file_utils import Lintable from ansiblelint.rules import AnsibleLintRule, RulesCollection from ansiblelint.runner import Runner from ansiblelint.skip_utils import get_rule_skips_from_line from ansiblelint.text import has_jinja, is_fqcn, is_fqcn_or_name from ansiblelint.utils import parse_yaml_from_file if TYPE_CHECKING: from ansiblelint.errors import MatchError from ansiblelint.utils import Task class Prefix(NamedTuple): """Prefix.""" value: str = "" from_fqcn: bool = False class VariableNamingRule(AnsibleLintRule): """All variables should be named using only lowercase and underscores.""" id = "var-naming" severity = "MEDIUM" tags = ["idiom"] version_changed = "5.0.10" needs_raw_task = True re_pattern_str = options.var_naming_pattern or "^[a-z_][a-z0-9_]*$" re_pattern = re.compile(re_pattern_str) reserved_names = get_reserved_names() # List of special variables that should be treated as read-only. This list # does not include connection variables, which we expect users to tune in # specific cases. # https://docs.ansible.com/ansible/latest/reference_appendices/special_variables.html read_only_names = { "ansible_check_mode", "ansible_collection_name", "ansible_config_file", "ansible_dependent_role_names", "ansible_diff_mode", "ansible_forks", "ansible_index_var", "ansible_inventory_sources", "ansible_limit", "ansible_local", # special fact "ansible_loop", "ansible_loop_var", "ansible_parent_role_names", "ansible_parent_role_paths", "ansible_play_batch", "ansible_play_hosts", "ansible_play_hosts_all", "ansible_play_name", "ansible_play_role_names", "ansible_playbook_python", "ansible_role_name", "ansible_role_names", "ansible_run_tags", "ansible_search_path", "ansible_skip_tags", "ansible_verbosity", "ansible_version", "group_names", "groups", "hostvars", "inventory_dir", "inventory_file", "inventory_hostname", "inventory_hostname_short", "omit", "play_hosts", "playbook_dir", "role_name", "role_names", "role_path", } # These special variables are used by Ansible but we allow users to set # them as they might need it in certain cases. allowed_special_names = { "ansible_facts", "ansible_become_user", "ansible_connection", "ansible_host", "ansible_python_interpreter", "ansible_user", "ansible_remote_tmp", # no included in docs } _ids = { "var-naming[no-reserved]": "Variables names must not be Ansible reserved names.", "var-naming[no-jinja]": "Variables names must not contain jinja2 templating.", "var-naming[pattern]": f"Variables names should match {re_pattern_str} regex.", } # pylint: disable=too-many-return-statements def get_var_naming_matcherror( self, ident: str, *, prefix: Prefix | None = None, file: Lintable, ) -> MatchError | None: """Return a MatchError if the variable name is not valid, otherwise None.""" if not isinstance(ident, str): # pragma: no cover return self.create_matcherror( tag="var-naming[non-string]", message="Variables names must be strings.", filename=file, ) if ident in ANNOTATION_KEYS or ident in self.allowed_special_names: return None try: ident.encode("ascii") except UnicodeEncodeError: return self.create_matcherror( tag="var-naming[non-ascii]", message=f"Variables names must be ASCII. ({ident})", filename=file, data=ident, ) if keyword.iskeyword(ident): return self.create_matcherror( tag="var-naming[no-keyword]", message=f"Variables names must not be Python keywords. ({ident})", filename=file, data=ident, ) if ident in self.reserved_names: return self.create_matcherror( tag="var-naming[no-reserved]", message=f"Variables names must not be Ansible reserved names. ({ident})", filename=file, data=ident, ) if ident in self.read_only_names: return self.create_matcherror( tag="var-naming[read-only]", message=f"This special variable is read-only. ({ident})", filename=file, data=ident, ) # We want to allow use of jinja2 templating for variable names if "{{" in ident: return None if not bool(self.re_pattern.match(ident)) and ( not prefix or not prefix.from_fqcn ): return self.create_matcherror( tag="var-naming[pattern]", message=f"Variables names should match {self.re_pattern_str} regex. ({ident})", filename=file, data=ident, ) if ( prefix and not ident.lstrip("_").startswith(f"{prefix.value}_") and not has_jinja(prefix.value) and is_fqcn_or_name(prefix.value) ): return self.create_matcherror( tag="var-naming[no-role-prefix]", message=f"Variables names from within roles should use {prefix.value}_ as a prefix.", filename=file, data=ident, ) return None def matchplay(self, file: Lintable, data: dict[str, Any]) -> list[MatchError]: """Return matches found for a specific playbook.""" results: list[MatchError] = [] raw_results: list[MatchError] = [] if not data or file.kind not in ("tasks", "handlers", "playbook", "vars"): return results # If the Play uses the 'vars' section to set variables our_vars = data.get("vars", {}) for key in our_vars: match_error = self.get_var_naming_matcherror(key, file=file) if match_error: raw_results.append(match_error) roles = data.get("roles", []) for role in roles: if isinstance(role, str): continue role_fqcn = role.get("role", role.get("name")) prefix = self._parse_prefix(role_fqcn) for key in list(role.keys()): if key not in PLAYBOOK_ROLE_KEYWORDS: match_error = self.get_var_naming_matcherror( key, prefix=prefix, file=file ) if match_error: match_error.message += f" (vars: {key})" raw_results.append(match_error) our_vars = role.get("vars", {}) for key in our_vars: match_error = self.get_var_naming_matcherror( key, prefix=prefix, file=file, ) if match_error: match_error.message += f" (vars: {key})" raw_results.append(match_error) if raw_results: lines = file.content.splitlines() for match in raw_results: # lineno starts with 1, not zero skip_list = get_rule_skips_from_line( line=lines[match.lineno - 1], lintable=file, ) if match.rule.id not in skip_list and match.tag not in skip_list: results.append(match) return results def matchtask( self, task: Task, file: Lintable | None = None, ) -> list[MatchError]: """Return matches for task based variables.""" results = [] prefix = Prefix() if file and file.parent and file.parent.kind == "role": prefix = Prefix(file.parent.path.name) ansible_module = task["action"]["__ansible_module__"] # If the task uses the 'vars' section to set variables our_vars = task.get("vars", {}) if ansible_module in ("include_role", "import_role"): action = task["action"] if isinstance(action, dict): role_fqcn = action.get("name", "") prefix = self._parse_prefix(role_fqcn) else: prefix = Prefix() for key in our_vars: match_error = self.get_var_naming_matcherror( key, prefix=prefix, file=file or Lintable(""), ) if match_error: match_error.message += f" (vars: {key})" results.append(match_error) # If the task uses the 'set_fact' module if ansible_module == "set_fact": for key in filter( lambda x: isinstance(x, str) and not x.startswith("__") and x != "cacheable", task["action"].keys(), ): match_error = self.get_var_naming_matcherror( key, prefix=prefix, file=file or Lintable(""), ) if match_error: match_error.lineno = task.line match_error.message += f" (set_fact: {key})" results.append(match_error) # If the task registers a variable registered_var = task.get("register", None) if registered_var: match_error = self.get_var_naming_matcherror( registered_var, prefix=prefix, file=file or Lintable(""), ) if match_error: match_error.message += f" (register: {registered_var})" match_error.lineno = task.line results.append(match_error) return results def matchyaml(self, file: Lintable) -> list[MatchError]: """Return matches for variables defined in vars files.""" results: list[MatchError] = [] raw_results: list[MatchError] = [] if str(file.kind) == "vars" and file.data: meta_data = parse_yaml_from_file(str(file.path)) if not isinstance(meta_data, dict): msg = f"Content if vars file {file} is not a dictionary." raise TypeError(msg) for key in meta_data: prefix = Prefix(file.role) if file.role else Prefix() match_error = self.get_var_naming_matcherror( key, prefix=prefix, file=file, ) if match_error: match_error.message += f" (vars: {key})" raw_results.append(match_error) if raw_results: lines = file.content.splitlines() for match in raw_results: # lineno starts with 1, not zero skip_list = get_rule_skips_from_line( line=lines[match.lineno - 1], lintable=file, ) if match.rule.id not in skip_list and match.tag not in skip_list: results.append(match) else: results.extend(super().matchyaml(file)) return results def _parse_prefix(self, fqcn: str) -> Prefix: return Prefix("" if "." in fqcn else fqcn.split("/")[-1], is_fqcn(fqcn)) # testing code to be loaded only with pytest or when executed the rule file if "pytest" in sys.modules: import pytest from ansiblelint.testing import ( # pylint: disable=ungrouped-imports run_ansible_lint, ) @pytest.mark.parametrize( ("file", "expected"), ( pytest.param( "examples/playbooks/var-naming/rule-var-naming-fail.yml", 7, id="0", ), pytest.param("examples/Taskfile.yml", 0, id="1"), ), ) def test_invalid_var_name_playbook( file: str, expected: int, config_options: Options, ) -> None: """Test rule matches.""" rules = RulesCollection(options=config_options) rules.register(VariableNamingRule()) results = Runner(Lintable(file), rules=rules).run() assert len(results) == expected for result in results: assert result.rule.id == VariableNamingRule.id # We are not checking line numbers because they can vary between # different versions of ruamel.yaml (and depending on presence/absence # of its c-extension) def test_invalid_var_name_varsfile( default_rules_collection: RulesCollection, ) -> None: """Test rule matches.""" results = Runner( Lintable("examples/playbooks/vars/rule_var_naming_fail.yml"), rules=default_rules_collection, ).run() expected_errors = ( ("schema[vars]", 1), ("var-naming[pattern]", 2), ("var-naming[pattern]", 6), ("var-naming[no-keyword]", 10), ("var-naming[non-ascii]", 11), ("var-naming[no-reserved]", 12), ("var-naming[read-only]", 13), ) assert len(results) == len(expected_errors) for idx, result in enumerate(results): assert result.tag == expected_errors[idx][0] assert result.lineno == expected_errors[idx][1] def test_invalid_vars_diff_files( default_rules_collection: RulesCollection, ) -> None: """Test rule matches.""" results = Runner( Lintable("examples/playbooks/vars/rule_var_naming_fails_files"), rules=default_rules_collection, ).run() expected_errors = ( ("var-naming[pattern]", 2), ("var-naming[pattern]", 3), ("var-naming[pattern]", 2), ("var-naming[pattern]", 3), ) assert len(results) == len(expected_errors) for idx, result in enumerate(results): assert result.tag == expected_errors[idx][0] assert result.lineno == expected_errors[idx][1] def test_var_naming_with_role_prefix( default_rules_collection: RulesCollection, ) -> None: """Test rule matches.""" results = Runner( Lintable("examples/roles/role_vars_prefix_detection"), rules=default_rules_collection, ).run() assert len(results) == 2 for result in results: assert result.tag == "var-naming[no-role-prefix]" def test_var_naming_with_role_prefix_plays( default_rules_collection: RulesCollection, ) -> None: """Test rule matches.""" results = Runner( Lintable("examples/playbooks/role_vars_prefix_detection.yml"), rules=default_rules_collection, exclude_paths=["examples/roles/role_vars_prefix_detection"], ).run() expected_errors = ( ("var-naming[no-role-prefix]", 9), ("var-naming[no-role-prefix]", 12), ("var-naming[no-role-prefix]", 15), ("var-naming[no-role-prefix]", 25), ("var-naming[no-role-prefix]", 32), ("var-naming[no-role-prefix]", 45), ) assert len(results) == len(expected_errors) for idx, result in enumerate(results): assert result.tag == expected_errors[idx][0] assert result.lineno == expected_errors[idx][1] def test_var_naming_with_pattern() -> None: """Test rule matches.""" role_path = "examples/roles/var_naming_pattern/tasks/main.yml" conf_path = "examples/roles/var_naming_pattern/.ansible-lint" result = run_ansible_lint( f"--config-file={conf_path}", role_path, ) assert result.returncode == RC.SUCCESS assert "var-naming" not in result.stdout def test_var_naming_with_pattern_foreign_role() -> None: """Test rule matches.""" role_path = "examples/playbooks/bug-4095.yml" conf_path = "examples/roles/var_naming_pattern/.ansible-lint" result = run_ansible_lint( f"--config-file={conf_path}", role_path, ) assert result.returncode == RC.SUCCESS assert "var-naming" not in result.stdout def test_var_naming_with_include_tasks_and_vars() -> None: """Test with include tasks and vars.""" role_path = "examples/roles/var_naming_pattern/tasks/include_task_with_vars.yml" result = run_ansible_lint(role_path) assert result.returncode == RC.SUCCESS assert "var-naming" not in result.stdout def test_var_naming_with_set_fact_and_cacheable() -> None: """Test with include tasks and vars.""" role_path = "examples/roles/var_naming_pattern/tasks/cacheable_set_fact.yml" result = run_ansible_lint(role_path) assert result.returncode == RC.SUCCESS assert "var-naming" not in result.stdout def test_var_naming_with_include_role_import_role() -> None: """Test with include role and import role.""" role_path = "examples/.test_collection/roles/my_role/tasks/main.yml" result = run_ansible_lint(role_path) assert result.returncode == RC.SUCCESS assert "var-naming" not in result.stdout ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/rules/yaml.md������������������������������������������0000664�0000000�0000000�00000012745�14773473560�0023602�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# yaml This rule checks YAML syntax by using [yamllint] library but with a [specific default configuration](#yamllint-configuration), one that is compatible with both, our internal reformatter (`--fix`) and also [prettier]. You can disable YAML syntax violations by adding `yaml` to the `skip_list` in your Ansible-lint configuration as follows: ```yaml skip_list: - yaml ``` For more fine-grained control, disable violations for specific rules using tag identifiers in the `yaml[yamllint_rule]` format as follows: ```yaml skip_list: - yaml[trailing-spaces] - yaml[indentation] ``` If you want Ansible-lint to report YAML syntax violations as warnings, and not fatal errors, add tag identifiers to the `warn_list` in your configuration, for example: ```yaml warn_list: - yaml[document-start] ``` !!! warning You cannot use `tags: [skip_ansible_lint]` to disable this rule but you can use [yamllint magic comments](https://yamllint.readthedocs.io/en/stable/disable_with_comments.html#disabling-checks-for-all-or-part-of-the-file) for tuning it. See the [list of yamllint rules](https://yamllint.readthedocs.io/en/stable/rules.html) for more information. Some of the detailed error codes that you might see are: - `yaml[brackets]` - _too few spaces inside empty brackets_, or _too many spaces inside brackets_ - `yaml[colons]` - _too many spaces before colon_, or _too many spaces after colon_ - `yaml[commas]` - _too many spaces before comma_, or _too few spaces after comma_ - `yaml[comments-indentation]` - _Comment not indented like content_ - `yaml[comments]` - _Too few spaces before comment_, or _Missing starting space in comment_ - `yaml[document-start]` - _missing document start "---"_ or _found forbidden document start "---"_ - `yaml[empty-lines]` - _too many blank lines (...> ...)_ - `yaml[indentation]` - _Wrong indentation: expected ... but found ..._ - `yaml[key-duplicates]` - _Duplication of key "..." in mapping_ - `yaml[line-length]` - _Line too long (... > ... characters)_ - `yaml[new-line-at-end-of-file]` - _No new line character at the end of file_ - `yaml[octal-values]`: forbidden implicit or explicit [octal](#octals) value - `yaml[syntax]` - YAML syntax is broken - `yaml[trailing-spaces]` - Spaces are found at the end of lines - `yaml[truthy]` - _Truthy value should be one of ..._ ## Octals As [YAML specification] regarding octal values changed at least 3 times in [1.1], [1.2.0] and [1.2.2] we now require users to always add quotes around octal values, so the YAML loaders will all load them as strings, providing a consistent behavior. This is also safer as JSON does not support octal values either. By default, yamllint does not check for octals but our custom default ruleset for it does check these. If for some reason, you do not want to follow our defaults, you can create a `.yamllint` file in your project and this will take precedence over our defaults. ## Problematic code ```yaml # Missing YAML document start. foo: 0777 # <-- yaml[octal-values] foo2: 0o777 # <-- yaml[octal-values] foo2: ... # <-- yaml[key-duplicates] bar: ... # <-- yaml[comments-indentation] ``` ## Correct code ```yaml --- foo: "0777" # <-- Explicitly quoting octal is less risky. foo2: "0o777" # <-- Explicitly quoting octal is less risky. bar: ... # Correct comment indentation. ``` ## Additional Information for Multiline Strings Adhering to yaml[line-length] rule, for writing multiline strings we recommend using Block Style Indicator: literal style indicated by a pipe (|) or folded style indicated by a right angle bracket (>), instead of escaping the newlines with backslashes. Reference [guide] for writing multiple line strings in yaml. ## Yamllint configuration If you decide to add a custom yamllint config to your project, ansible-lint might refuse to run if it detects that some of your options are incompatible and ask you to correct them. When this happens, you will see a message like the one below: ```shell CRITICAL Found incompatible custom yamllint configuration (.yamllint), please either remove the file or edit it to comply with: - comments.min-spaces-from-content must be 1 - braces.min-spaces-inside must be 0 - braces.max-spaces-inside must be 1 - octal-values.forbid-implicit-octal must be true - octal-values.forbid-explicit-octal must be true Read https://ansible.readthedocs.io/projects/lint/rules/yaml/ for more details regarding why we have these requirements. ``` !!! warning [Auto-fix](../autofix.md) functionality will change **inline comment indentation to one character instead of two**, which is the default of [yamllint]. The reason for this decision was to keep reformatting compatibility with [prettier], which is the most popular reformatter. ```yaml title=".yamllint" rules: comments: min-spaces-from-content: 1 # prettier compatibility ``` There is no need to create this yamllint config file, but if you also run yamllint yourself, you might want to create it to make it behave the same way as ansible-lint. Below you can find the default yamllint configuration that our linter will use when there is no custom file present. ```yaml {!../src/ansiblelint/data/.yamllint!} ``` [1.1]: https://yaml.org/spec/1.1/ [1.2.0]: https://yaml.org/spec/1.2.0/ [1.2.2]: https://yaml.org/spec/1.2.2/ [yaml specification]: https://yaml.org/ [guide]: https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html#yaml-basics [prettier]: https://prettier.io/ [yamllint]: https://yamllint.readthedocs.io/en/stable/ ���������������������������ansible-ansible-lint-c16f018/src/ansiblelint/rules/yaml_rule.py�������������������������������������0000664�0000000�0000000�00000015334�14773473560�0024656�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Implementation of yaml linting rule (yamllint integration).""" from __future__ import annotations import logging import sys from typing import TYPE_CHECKING from yamllint.linter import run as run_yamllint from ansiblelint.file_utils import Lintable from ansiblelint.rules import AnsibleLintRule, TransformMixin from ansiblelint.yaml_utils import load_yamllint_config if TYPE_CHECKING: from collections.abc import MutableMapping, MutableSequence from typing import Any from ansiblelint.config import Options from ansiblelint.errors import MatchError _logger = logging.getLogger(__name__) class YamllintRule(AnsibleLintRule, TransformMixin): """Violations reported by yamllint.""" id = "yaml" severity = "VERY_LOW" tags = ["formatting", "yaml"] version_changed = "5.0.0" config = load_yamllint_config() has_dynamic_tags = True link = "https://yamllint.readthedocs.io/en/stable/rules.html" # ensure this rule runs before most of other common rules _order = 1 _ids = { "yaml[anchors]": "", "yaml[braces]": "", "yaml[brackets]": "", "yaml[colons]": "", "yaml[commas]": "", "yaml[comments-indentation]": "", "yaml[comments]": "", "yaml[document-end]": "", "yaml[document-start]": "", "yaml[empty-lines]": "", "yaml[empty-values]": "", "yaml[float-values]": "", "yaml[hyphens]": "", "yaml[indentation]": "", "yaml[key-duplicates]": "", "yaml[key-ordering]": "", "yaml[line-length]": "", "yaml[new-line-at-end-of-file]": "", "yaml[new-lines]": "", "yaml[octal-values]": "", "yaml[quoted-strings]": "", "yaml[trailing-spaces]": "", "yaml[truthy]": "", } def matchyaml(self, file: Lintable) -> list[MatchError]: """Return matches found for a specific YAML text.""" matches: list[MatchError] = [] if str(file.base_kind) != "text/yaml": return matches for problem in run_yamllint( # type: ignore[no-untyped-call] file.content, YamllintRule.config, filepath=file.path, ): self.severity = "VERY_LOW" if problem.level == "error": self.severity = "MEDIUM" # Ignore truthy violation with github workflows ("on:" keys) if problem.rule == "truthy" and file.path.parent.parts[-2:] == ( ".github", "workflows", ): continue matches.append( self.create_matcherror( # yamllint does return lower-case sentences message=problem.desc.capitalize(), lineno=problem.line, details="", filename=file, tag=f"yaml[{problem.rule}]", ), ) return matches def transform( self: YamllintRule, match: MatchError, lintable: Lintable, data: MutableMapping[str, Any] | MutableSequence[Any] | str, ) -> None: """Transform yaml. :param match: MatchError instance :param lintable: Lintable instance :param data: data to transform """ # This method does nothing because the YAML reformatting is implemented # in data dumper. Still presence of this method helps us with # documentation generation. # 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( ("file", "expected_kind", "expected"), ( pytest.param( "examples/yamllint/invalid.yml", "yaml", [ 'Missing document start "---"', 'Duplication of key "foo" in mapping', "Trailing spaces", ], id="invalid", ), pytest.param("examples/yamllint/valid.yml", "yaml", [], id="valid"), pytest.param( "examples/yamllint/line-length.yml", "yaml", ["Line too long (166 > 160 characters)"], id="line-length", ), pytest.param( "examples/yamllint/multi-document.yaml", "yaml", [], id="multi-document", ), pytest.param( "examples/yamllint/skipped-rule.yml", "yaml", [], id="skipped-rule", ), pytest.param( "examples/playbooks/rule-yaml-fail.yml", "playbook", [ "Truthy value should be one of [false, true]", "Truthy value should be one of [false, true]", "Truthy value should be one of [false, true]", ], id="rule-yaml-fail", ), pytest.param( "examples/playbooks/rule-yaml-pass.yml", "playbook", [], id="rule-yaml-pass", ), pytest.param( "examples/yamllint/.github/workflows/ci.yml", "yaml", [], id="rule-yaml-github-workflow", ), ), ) @pytest.mark.filterwarnings("ignore::ansible_compat.runtime.AnsibleWarning") def test_yamllint( file: str, expected_kind: str, expected: list[str], config_options: Options, ) -> None: """Validate parsing of ansible output.""" lintable = Lintable(file) assert lintable.kind == expected_kind rules = RulesCollection(options=config_options) rules.register(YamllintRule()) results = Runner(lintable, rules=rules).run() assert len(results) == len(expected), results for idx, result in enumerate(results): assert result.filename.endswith(file) assert expected[idx] in result.message assert isinstance(result.tag, str) assert result.tag.startswith("yaml[") def test_yamllint_has_help(default_rules_collection: RulesCollection) -> None: """Asserts that we loaded markdown documentation in help property.""" for rule in default_rules_collection: if rule.id == "yaml": assert rule.help is not None assert len(rule.help) > 100 break else: # pragma: no cover pytest.fail("No yaml rule found") ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/runner.py����������������������������������������������0000664�0000000�0000000�00000066402�14773473560�0023046�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Runner implementation.""" from __future__ import annotations import json import logging import math import multiprocessing import multiprocessing.pool import os import re import subprocess import tempfile import warnings from dataclasses import dataclass from fnmatch import fnmatch from functools import cache from pathlib import Path from tempfile import NamedTemporaryFile from typing import TYPE_CHECKING, Any from ansible.errors import AnsibleError from ansible.parsing.splitter import split_args from ansible.plugins.loader import add_all_plugin_dirs from ansible_compat.runtime import AnsibleWarning import ansiblelint.skip_utils import ansiblelint.utils from ansiblelint.constants import States from ansiblelint.errors import LintWarning, MatchError, WarnSource from ansiblelint.file_utils import ( Lintable, expand_dirs_in_lintables, expand_paths_vars, normpath, ) from ansiblelint.logger import timed_info from ansiblelint.rules.syntax_check import OUTPUT_PATTERNS from ansiblelint.text import strip_ansi_escape from ansiblelint.types import AnsibleJSON, AnsibleMapping from ansiblelint.utils import ( PLAYBOOK_DIR, HandleChildren, parse_examples_from_plugin, template, ) if TYPE_CHECKING: from collections.abc import Callable, Generator from ansiblelint._internal.rules import BaseRule from ansiblelint.app import App from ansiblelint.config import Options from ansiblelint.constants import FileType from ansiblelint.rules import RulesCollection _logger = logging.getLogger(__name__) @dataclass class LintResult: """Class that tracks result of linting.""" matches: list[MatchError] files: set[Lintable] class Runner: """Runner class performs the linting process.""" # pylint: disable=too-many-arguments,too-many-instance-attributes def __init__( self, *lintables: Lintable | str | Path, rules: RulesCollection, tags: frozenset[Any] = frozenset(), skip_list: list[str] | None = None, exclude_paths: list[str] | None = None, verbosity: int = 0, checked_files: set[Lintable] | None = None, project_dir: str | None = None, _skip_ansible_syntax_check: bool = False, ) -> None: """Initialize a Runner instance.""" self.rules = rules self.lintables: set[Lintable] = set() self.project_dir = os.path.abspath(project_dir) if project_dir else None self.skip_ansible_syntax_check = _skip_ansible_syntax_check if skip_list is None: skip_list = [] if exclude_paths is None: exclude_paths = [] # Assure consistent type and configure given lintables as explicit (so # excludes paths would not apply on them). for item in lintables: if not isinstance(item, Lintable): item = Lintable(item) item.explicit = True self.lintables.add(item) # Expand folders (roles) to their components expand_dirs_in_lintables(self.lintables) self.tags = tags self.skip_list = skip_list self._update_exclude_paths(exclude_paths) self.verbosity = verbosity if checked_files is None: checked_files = set() self.checked_files = checked_files self.app = self.rules.app def _update_exclude_paths(self, exclude_paths: list[str]) -> None: if exclude_paths: # These will be (potentially) relative paths paths = expand_paths_vars(exclude_paths) # Since ansiblelint.utils.find_children returns absolute paths, # and the list of files we create in `Runner.run` can contain both # relative and absolute paths, we need to cover both bases. self.exclude_paths = paths + [os.path.abspath(p) for p in paths] else: self.exclude_paths = [] def is_excluded(self, lintable: Lintable) -> bool: """Verify if a file path should be excluded.""" # Any will short-circuit as soon as something returns True, but will # be poor performance for the case where the path under question is # not excluded. # Exclusions should be evaluated only using absolute paths in order # to work correctly. # Explicit lintables are never excluded if lintable.explicit: return False abs_path = str(lintable.abspath) if self.project_dir and not abs_path.startswith(self.project_dir): _logger.debug( "Skipping %s as it is outside of the project directory.", abs_path, ) return True return any( abs_path.startswith(path) or lintable.path.match(path) or fnmatch(str(abs_path), path) or fnmatch(str(lintable), path) for path in self.exclude_paths ) def run(self) -> list[MatchError]: """Execute the linting process.""" matches: list[MatchError] = [] with warnings.catch_warnings(record=True) as captured_warnings: warnings.simplefilter("always") matches = self._run() for warn in captured_warnings: # Silence Ansible runtime warnings that are unactionable # https://github.com/ansible/ansible-lint/issues/3216 if warn.category is AnsibleWarning and isinstance(warn.source, dict): msg = warn.source["msg"] if msg.startswith( "Falling back to Ansible unique filter as Jinja2 one failed", ): continue # For the moment we are ignoring deprecation warnings as Ansible # modules outside current content can generate them and user # might not be able to do anything about them. if warn.category is DeprecationWarning: # pragma: no cover continue if warn.category is LintWarning: if isinstance(warn.source, WarnSource): match = MatchError( message=warn.source.message or warn.category.__name__, rule=self.rules["warning"], lintable=Lintable(warn.source.filename.filename), tag=warn.source.tag, lineno=warn.source.lineno, ) else: match = MatchError( message=( warn.message if isinstance(warn.message, str) else "?" ), rule=self.rules["warning"], lintable=Lintable(str(warn.source)), ) matches.append(match) continue _logger.warning( "%s:%s %s %s", warn.filename, warn.lineno or 1, warn.category.__name__, warn.message, ) return matches def _run(self) -> list[MatchError]: """Run the linting (inner loop).""" files: list[Lintable] = [] matches: list[MatchError] = [] # remove exclusions for lintable in self.lintables.copy(): if self.is_excluded(lintable): _logger.debug("Excluded %s", lintable) self.lintables.remove(lintable) continue if isinstance(lintable.data, States) and lintable.exc: lintable.exc.__class__.__name__.lower() matches.append( MatchError( lintable=lintable, message=str(lintable.exc), details=str(lintable.exc.__cause__), rule=self.rules["load-failure"], tag=f"load-failure[{lintable.exc.__class__.__name__.lower()}]", ), ) lintable.stop_processing = True # identify missing files/folders if not lintable.path.exists(): matches.append( MatchError( lintable=lintable, message="File or directory not found.", rule=self.rules["load-failure"], tag="load-failure[not-found]", ), ) # -- phase 1 : syntax check in parallel -- if not self.skip_ansible_syntax_check: # app = get_app(cached=True) def worker(lintable: Lintable) -> list[MatchError]: return self._get_ansible_syntax_check_matches( lintable=lintable, app=self.app, ) for lintable in self.lintables: if ( lintable.kind not in ("playbook", "role") or lintable.stop_processing ): continue files.append(lintable) # avoid resource leak warning, https://github.com/python/cpython/issues/90549 # pylint: disable=unused-variable global_resource = multiprocessing.Semaphore() # noqa: F841 pool = multiprocessing.pool.ThreadPool(processes=threads()) return_list = pool.map(worker, files, chunksize=1) pool.close() pool.join() for data in return_list: matches.extend(data) matches = self._filter_excluded_matches(matches) # -- phase 2 --- # do our processing only when ansible syntax check passed in order # to avoid causing runtime exceptions. Our processing is not as # resilient to be able process garbage. matches.extend( self._emit_matches([file for file in files if not file.failed()]) ) # mark failed failed lintables as stop processing in order to avoid # duplicated errors from further processing of the other rules for match in matches: if match.lintable.failed(): match.lintable.stop_processing = True # Look into making lintables singletons to avoid having to update them for lintable in self.lintables: if lintable == match.lintable: lintable.stop_processing = True break # remove duplicates from files list files = list(dict.fromkeys(files)) for file in self.lintables: if ( file in self.checked_files or not file.kind or file.failed() or file.stop_processing ): continue _logger.debug( "Examining %s of type %s", normpath(file.path), file.kind, ) matches.extend( self.rules.run(file, tags=set(self.tags), skip_list=self.skip_list), ) # update list of checked files self.checked_files.update(self.lintables) # remove any matches made inside excluded files matches = self._filter_excluded_matches(matches) return sorted(set(matches)) # pylint: disable=too-many-locals,too-many-statements def _get_ansible_syntax_check_matches( self, lintable: Lintable, app: App, ) -> list[MatchError]: """Run ansible syntax check and return a list of MatchError(s).""" try: default_rule: BaseRule = self.rules["syntax-check"] except ValueError: # if syntax-check is not loaded, we do not perform any syntax check, # that might happen during testing return [] fh = None results = [] if lintable.kind not in ("playbook", "role"): return [] with timed_info( "Executing syntax check on %s %s", lintable.kind, lintable.path, ): if lintable.kind == "role": playbook_text = f""" --- - name: Temporary playbook for role syntax check hosts: localhost tasks: - ansible.builtin.import_role: name: {lintable.path.expanduser()!s} """ fh = tempfile.NamedTemporaryFile( # noqa: SIM115 mode="w", suffix=".yml", prefix="play", encoding="utf-8", ) fh.write(playbook_text) fh.flush() playbook_path = fh.name else: playbook_path = str(lintable.path.expanduser()) # To avoid noisy warnings we pass localhost as current inventory: # [WARNING]: No inventory was parsed, only implicit localhost is available # [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all' cmd = [ "ansible-playbook", "--syntax-check", "-vv", # needed or ansible-core will fail to mention the loaded file with includes: # statically imported: /foo/bar/malformed.yml # ERROR! A malformed block was encountered while loading a block. ..." playbook_path, ] if app.options.extra_vars: cmd.extend(["--extra-vars", json.dumps(app.options.extra_vars)]) # To reduce noisy warnings like # CryptographyDeprecationWarning: Blowfish has been deprecated # https://github.com/paramiko/paramiko/issues/2038 env = app.runtime.environ.copy() env["PYTHONWARNINGS"] = "ignore" # Avoid execution failure if user customized any_unparsed_is_failed setting # https://github.com/ansible/ansible-lint/issues/3650 env["ANSIBLE_INVENTORY_ANY_UNPARSED_IS_FAILED"] = "False" run = subprocess.run( # noqa: S603 cmd, stdin=subprocess.PIPE, capture_output=True, shell=False, # needed when command is a list text=True, check=False, env=env, ) if run.returncode != 0: message = None filename = lintable lineno = 1 column = None ignore_rc = False stderr = strip_ansi_escape(run.stderr) stdout = strip_ansi_escape(run.stdout) if stderr: details = stderr if stdout: # pragma: no cover details += "\n" + stdout else: details = stdout for pattern in OUTPUT_PATTERNS: rule = default_rule match = re.search(pattern.regex, stderr) if match: groups = match.groupdict() title = groups.get("title", match.group(0)) details = groups.get("details", "") lineno = int(groups.get("line", 1)) if ( "filename" in groups and str(lintable.path.absolute()) != groups["filename"] and lintable.filename != groups["filename"] ): # avoids creating a new lintable object if the filename # is matching as this might prevent Lintable.failed() # feature from working well. filename = Lintable(groups["filename"]) else: filename = lintable column = int(groups.get("column", 1)) if ( pattern.tag in ("unknown-module", "specific") and app.options.nodeps ): ignore_rc = True else: results.append( MatchError( message=title, lintable=filename, lineno=lineno, column=column, rule=rule, details=details, tag=f"{rule.id}[{pattern.tag}]", ), ) break if not results and not ignore_rc: rule = self.rules["internal-error"] message = ( f"Unexpected error code {run.returncode} from " f"execution of: {' '.join(cmd)}" ) filename.failed() results.append( MatchError( message=message, lintable=filename, lineno=lineno, column=column, rule=rule, details=details, tag="", ), ) if fh: fh.close() return results def _filter_excluded_matches(self, matches: list[MatchError]) -> list[MatchError]: return [ match for match in matches if not self.is_excluded(match.lintable) and match.tag not in match.lintable.line_skips[match.lineno] ] def _emit_matches(self, files: list[Lintable]) -> Generator[MatchError, None, None]: visited: set[Lintable] = set() while visited != self.lintables: for lintable in self.lintables - visited: visited.add(lintable) if lintable.failed(): continue if not lintable.path.exists(): continue try: children = self.find_children(lintable) for child in children: if self.is_excluded(child): continue self.lintables.add(child) files.append(child) except MatchError as exc: if not exc.filename: # pragma: no branch exc.filename = str(lintable.path) exc.rule = self.rules["load-failure"] yield exc except AttributeError: yield MatchError( lintable=lintable, rule=self.rules["load-failure"], ) def find_children(self, lintable: Lintable) -> list[Lintable]: """Traverse children of a single file or folder.""" playbook_ds: AnsibleJSON if not lintable.path.exists(): return [] playbook_dir = str(lintable.path.parent) ansiblelint.utils.set_collections_basedir(lintable.path.parent) add_all_plugin_dirs(playbook_dir or ".") # type: ignore[no-untyped-call] if lintable.kind == "role": playbook_ds = AnsibleMapping({"roles": [{"role": str(lintable.path)}]}) elif lintable.kind == "plugin": return self.plugin_children(lintable) elif lintable.kind not in ("playbook", "tasks"): return [] else: try: playbook_ds = ansiblelint.utils.parse_yaml_from_file(str(lintable.path)) except AnsibleError as exc: raise MatchError( lintable=lintable, rule=self.rules["load-failure"] ) from exc results = [] # playbook_ds can be an AnsibleUnicode string, which we consider invalid if isinstance(playbook_ds, str): raise MatchError(lintable=lintable, rule=self.rules["load-failure"]) for item in ansiblelint.utils.playbook_items(playbook_ds): # if lintable.kind not in ["playbook"]: for child in self.play_children( lintable, item, lintable.kind, playbook_dir, ): # We avoid processing parametrized children path_str = str(child.path) if "$" in path_str or "{{" in path_str: continue # Repair incorrect paths obtained when old syntax was used, like: # - include: simpletask.yml tags=nginx valid_tokens = [] for token in split_args(path_str): # type: ignore[no-untyped-call] if "=" in token: break valid_tokens.append(token) path = " ".join(valid_tokens) if path != path_str: child.path = Path(path) child.name = child.path.name results.append(child) return results def play_children( self, lintable: Lintable, item: tuple[str, Any], parent_type: FileType, playbook_dir: str, ) -> list[Lintable]: """Flatten the traversed play tasks.""" # pylint: disable=unused-argument basedir = lintable.path.parent handlers = HandleChildren(self.rules, app=self.app) delegate_map: dict[ str, Callable[[Lintable, Any, Any, FileType], list[Lintable]], ] = { "tasks": handlers.taskshandlers_children, "pre_tasks": handlers.taskshandlers_children, "post_tasks": handlers.taskshandlers_children, "block": handlers.taskshandlers_children, "include": handlers.include_children, "ansible.builtin.include": handlers.include_children, "import_playbook": handlers.import_playbook_children, "ansible.builtin.import_playbook": handlers.import_playbook_children, "roles": handlers.roles_children, "dependencies": handlers.roles_children, "handlers": handlers.taskshandlers_children, "include_tasks": handlers.include_children, "ansible.builtin.include_tasks": handlers.include_children, "import_tasks": handlers.include_children, "ansible.builtin.import_tasks": handlers.include_children, } (k, v) = item add_all_plugin_dirs(str(basedir.resolve())) # type: ignore[no-untyped-call] if k in delegate_map and v: v = template( basedir, v, {"playbook_dir": PLAYBOOK_DIR or str(basedir.resolve())}, fail_on_undefined=False, ) return delegate_map[k](lintable, k, v, parent_type) return [] def plugin_children(self, lintable: Lintable) -> list[Lintable]: """Collect lintable sections from plugin file.""" offset, content = parse_examples_from_plugin(lintable) if not content: # No examples, nothing to see here return [] examples = Lintable( name=lintable.name, content=content, kind="yaml", base_kind="text/yaml", parent=lintable, ) examples.line_offset = offset # pylint: disable=consider-using-with examples.file = NamedTemporaryFile( # noqa: SIM115 mode="w+", suffix=f"_{lintable.path.name}.yaml", encoding="utf-8", ) examples.file.write(content) examples.file.flush() examples.filename = examples.file.name examples.path = Path(examples.file.name) return [examples] @cache def threads() -> int: """Determine how many threads to use. Inside containers we want to respect limits imposed. When present /sys/fs/cgroup/cpu.max can contain something like: $ podman/docker run -it --rm --cpus 1.5 ubuntu:latest cat /sys/fs/cgroup/cpu.max 150000 100000 # "max 100000" is returned when no limits are set. See: https://github.com/python/cpython/issues/80235 See: https://github.com/python/cpython/issues/70879 """ os_cpu_count = multiprocessing.cpu_count() # Cgroup CPU bandwidth limit available in Linux since 2.6 kernel cpu_max_fname = "/sys/fs/cgroup/cpu.max" cfs_quota_fname = "/sys/fs/cgroup/cpu/cpu.cfs_quota_us" cfs_period_fname = "/sys/fs/cgroup/cpu/cpu.cfs_period_us" if os.path.exists(cpu_max_fname): # cgroup v2 # https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html with open(cpu_max_fname, encoding="utf-8") as fh: # pragma: no cover cpu_quota_us, cpu_period_us = fh.read().strip().split() elif os.path.exists(cfs_quota_fname) and os.path.exists(cfs_period_fname): # cgroup v1 # https://www.kernel.org/doc/html/latest/scheduler/sched-bwc.html#management with open(cfs_quota_fname, encoding="utf-8") as fh: # pragma: no cover cpu_quota_us = fh.read().strip() with open(cfs_period_fname, encoding="utf-8") as fh: # pragma: no cover cpu_period_us = fh.read().strip() else: # No Cgroup CPU bandwidth limit (e.g. non-Linux platform) cpu_quota_us = "max" cpu_period_us = "100000" # unused, for consistency with default values if cpu_quota_us == "max": # No active Cgroup quota on a Cgroup-capable platform return os_cpu_count cpu_quota_us_int = int(cpu_quota_us) cpu_period_us_int = int(cpu_period_us) if cpu_quota_us_int > 0 and cpu_period_us_int > 0: return math.ceil(cpu_quota_us_int / cpu_period_us_int) # Setting a negative cpu_quota_us value is a valid way to disable # cgroup CPU bandwidth limits return os_cpu_count def get_matches(rules: RulesCollection, options: Options) -> LintResult: """Get matches for given rules and options. :param rules: Rules to use for linting. :param options: Options to use for linting. :returns: LintResult containing matches and checked files. """ lintables = ansiblelint.utils.get_lintables(opts=options, args=options.lintables) for rule in rules: if "unskippable" in rule.tags: for entry in (*options.skip_list, *options.warn_list): if rule.id == entry or entry.startswith(f"{rule.id}["): msg = f"Rule '{rule.id}' is unskippable, you cannot use it in 'skip_list' or 'warn_list'. Still, you could exclude the file." raise RuntimeError(msg) matches = [] checked_files: set[Lintable] = set() runner = Runner( *lintables, rules=rules, tags=frozenset(options.tags), skip_list=options.skip_list, exclude_paths=options.exclude_paths, verbosity=options.verbosity, checked_files=checked_files, project_dir=options.project_dir, _skip_ansible_syntax_check=options._skip_ansible_syntax_check, # noqa: SLF001 ) matches.extend(runner.run()) # Assure we do not print duplicates and the order is consistent matches = sorted(set(matches)) # Convert reported filenames into human readable ones, so we hide the # fact we used temporary files when processing input from stdin. for match in matches: for lintable in lintables: if match.filename == lintable.filename: match.filename = lintable.name break return LintResult(matches=matches, files=checked_files) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/�����������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0022576�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/README.md��������������������������������������0000664�0000000�0000000�00000010361�14773473560�0024056�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Schemas for Ansible and its related tools [![ci](https://github.com/ansible-community/schemas/actions/workflows/task.yml/badge.svg)](https://github.com/ansible-community/schemas/actions/workflows/task.yml) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![Repository License: MIT](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE) ## About Schemas This project aims to generate JSON/YAML validation schemas for Ansible files such as playbooks, tasks, requirements, meta or vars and also for Molecule configuration. Keep in mind that these schemas will limit your freedom of choice regarding the syntax you can use to write Ansible tasks as they do not allow some historical forms which are still allowed by Ansible itself. Not any file accepted by Ansible will pass these schemas but we do expect that any file that passed these schemas should be accepted by Ansible. - YAML 1.2 booleans are required as `true` or `false`, while Ansible itself allows you to use more relaxed forms like `yes` or `no`. - Inline actions are not allowed, as schema cannot validate them - Non-built-in modules must be called using `action:` blocks - Module arguments are not yet verified but we plan to implement it - Out schemas are strict about usage of jinja2 templating and require `{{` on arguments declared as **explicit**, which forbid the use of `{{` on those marked as **implicit**. See the section below for details. As these schemas are still experimental, creating pull requests to improve the schema is of much greater help. Though you are still welcome to report bugs but expect them to take a long time until someone finds time to fix them. If you want to help improve the schemas, have a look at the [development documentation](CONTRIBUTING.md). ## Schema Bundle We are currently migrating towards a single [ansible.json](/f/ansible.json) schema bundle, one that contains subschema definitions for all the supported file types. To configure your validator or editor to use the bundle, use the new URLs below, the part after the `#` in the URLs is essential for informing the loader about which subschema to use. You can also look at our [settings.json](.vscode/settings.json) to understand how to configure the [vscode-yaml](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) extension. - [playbook subschema url](https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/ansible.json#/$defs/playbook) - [tasks subschema uri](https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/ansible.json#/$defs/tasks) ## Jinja2 implicit vs explicit templating While Ansible might allow you to combine implicit and explicit templating, our schema will not. Our schemas will only allow you to use the recommended form, either by forbidding you to use the curly braces on implicit ones or forcing you to add them on explicit ones. Examples: ```yaml - name: some task command: echo 123 register: result vars: become_method_var: sudo become_method: become_method_var # <-- schema will not allow this # become_method: "{{ become_method_var }}" # <-- that is allowed ``` ### How to find if a field is implicit or explicit? Run assuming that your keyword is `no_log`, you can run `ansible-doc -t keyword no_log`, which will give you the following output: ```yaml failed_when: applies_to: - Task description: Conditional expression that overrides the task's normal 'failed' status. priority: 0 template: implicit type: list ``` As you can see the `template` field tells you if is implicit or explicit. Being more restrictive, schema protects you from common accidents, like writing a simple string in an explicit field. That will always evaluate as true instead of being evaluated as a jinja template. ## Activating the schemas At this moment installing [Ansible VS Code Extension by Red Hat](https://marketplace.visualstudio.com/items?itemName=redhat.ansible) will activate these schemas. The file patterns used to trigger their use can be seen [here](https://github.com/ansible-community/vscode-ansible/blob/master/package.json#L44-L94) Because these schemas are generic, you can easily use them with any validators that support them. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/__init__.py������������������������������������0000664�0000000�0000000�00000000055�14773473560�0024707�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Module containing cached JSON schemas.""" �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/__main__.py������������������������������������0000664�0000000�0000000�00000010572�14773473560�0024675�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Module containing cached JSON schemas.""" import json import logging import os import sys import time import urllib.request from collections import defaultdict from functools import cache from http.client import HTTPException from pathlib import Path from typing import Any from urllib.error import HTTPError from urllib.request import Request _logger = logging.getLogger(__package__) # Maps kinds to JSON schemas # See https://www.schemastore.org/json/ store_file = Path(f"{__file__}/../__store__.json").resolve() with store_file.open(encoding="utf-8") as json_file: JSON_SCHEMAS = json.load(json_file) class SchemaCacheDict(defaultdict): # type: ignore[type-arg] """Caching schema store.""" def __missing__(self, key: str) -> Any: """Load schema on its first use.""" value = get_schema(key) self[key] = value return value @cache def get_schema(kind: str) -> Any: """Return the schema for the given kind.""" schema_file = Path(__file__).parent / f"{kind}.json" with schema_file.open(encoding="utf-8") as f: return json.load(f) _schema_cache = SchemaCacheDict() def refresh_schemas(min_age_seconds: int = 3600 * 24) -> int: """Refresh JSON schemas by downloading latest versions. Returns number of changed schemas. """ age = int(time.time() - store_file.stat().st_mtime) # never check for updated schemas more than once a day if min_age_seconds > age: return 0 if not os.access(store_file, os.W_OK): # pragma: no cover _logger.debug( "Skipping schema update due to lack of writing rights on %s", store_file, ) return -1 _logger.debug("Checking for updated schemas...") changed = 0 for kind, data in JSON_SCHEMAS.items(): url = data["url"] if "#" in url: # pragma: no cover msg = f"Schema URLs cannot contain # due to python-jsonschema limitation: {url}" raise RuntimeError(msg) path = Path(__file__).parent.resolve() / f"{kind}.json" _logger.debug("Refreshing %s schema ...", kind) if not url.startswith(("http:", "https:")): # pragma: no cover msg = f"Unexpected url schema: {url}" raise ValueError(msg) request = Request(url) # noqa: S310 etag = data.get("etag", "") if etag: request.add_header("If-None-Match", f'"{data.get("etag")}"') try: with urllib.request.urlopen(request, timeout=10) as response: # noqa: S310 if response.status == 200: # pragma: no cover content = response.read().decode("utf-8").rstrip() etag = response.headers["etag"].strip('"') if etag != data.get("etag", ""): JSON_SCHEMAS[kind]["etag"] = etag changed += 1 with path.open("w", encoding="utf-8") as f_out: _logger.info("Schema %s was updated", kind) f_out.write(content) f_out.write("\n") # prettier/editors f_out.truncate() os.fsync(f_out.fileno()) # unload possibly loaded schema if kind in _schema_cache: # pragma: no cover del _schema_cache[kind] except (ConnectionError, OSError, HTTPException) as exc: if isinstance(exc, HTTPError) and getattr(exc, "code", None) == 304: _logger.debug("Schema %s is not modified", url) continue # In case of networking issues, we just stop and use last-known good _logger.debug("Skipped schema refresh due to unexpected exception: %s", exc) break if changed: # pragma: no cover with store_file.open("w", encoding="utf-8") as f_out: # formatting should match our .prettierrc.yaml json.dump(JSON_SCHEMAS, f_out, indent=2, sort_keys=True) f_out.write("\n") # prettier and editors in general # clear schema cache get_schema.cache_clear() else: store_file.touch() return changed if __name__ == "__main__": if refresh_schemas(60 * 10): # pragma: no cover print("Schemas were updated.") # noqa: T201 sys.exit(1) else: # pragma: no cover print("Schemas not updated", 0) # noqa: T201 ��������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/__store__.json���������������������������������0000664�0000000�0000000�00000006316�14773473560�0025427�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "ansible-lint-config": { "etag": "edfce2b56aae684bf1f0b9978dcfaaaa588dbc236f6e0ce29427277f6a327ddc", "url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/ansible-lint-config.json" }, "ansible-navigator-config": { "etag": "730a0572f872af3ce271fb5116bc9d4609da10dc2e35448b5ec1050f12b72e2b", "url": "https://raw.githubusercontent.com/ansible/ansible-navigator/main/src/ansible_navigator/data/ansible-navigator.json" }, "changelog": { "etag": "593ed5eef7c1e670f3667de70d43a41a5138513bd9640a85cbe8cb6faaa59793", "url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/changelog.json" }, "execution-environment": { "etag": "075ab552988793a43ddfe9907b0e391331c54b5dbee2ad1a194e6fc9268e5df9", "url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/execution-environment.json" }, "galaxy": { "etag": "99546ef979c934ab40d88261957fcce1ee7970d958c4bbe197ad5ca3f67ccc73", "url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/galaxy.json" }, "inventory": { "etag": "b52c251a121e2e807928db7b4e09338babde9e74a50d0f74e8908f6e230d101d", "url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/inventory.json" }, "meta": { "etag": "62cce45a9b8bd96872d8ee1c465d3ff6b60facf6a4aeba5c2e128df02b5f52a5", "url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/meta.json" }, "meta-runtime": { "etag": "448b614e9d4411b82d220950b7a415c248cc75d5431f9b8058c771a595d40163", "url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/meta-runtime.json" }, "molecule": { "etag": "3b625438c28e884ac42a14c09ca542fc3e1b4466abaf47d0c28646e0857d3fb5", "url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/molecule.json" }, "playbook": { "etag": "4f8cbba62fcf8a1fa6e8ef5e42696aec5b0876487478df83a7ffdf8bdbb4abcf", "url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/playbook.json" }, "requirements": { "etag": "5ae3a6058ac626a341338c760db7cef7f02a8911c7293c7e129dbc6b0f8bb86d", "url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/requirements.json" }, "role-arg-spec": { "etag": "c470f67bc8eec3937957773074d7b6549deefd83dd0c3e13db725df166a66df3", "url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/role-arg-spec.json" }, "rulebook": { "etag": "8113782a066a9a7aba1f3f42aeb7f8315fa49b5bf0b158a61e44a3eba22dd22f", "url": "https://raw.githubusercontent.com/ansible/ansible-rulebook/main/ansible_rulebook/schema/ruleset_schema.json" }, "tasks": { "etag": "9f3b54cf5cc432d57c9691fb3108a7f37996ab0875e2abb66eda0aa62437dcdc", "url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/tasks.json" }, "vars": { "etag": "73feaa77561d1d5b0bebe6cd66d499a28d67037055ac6d746139a38c9d28ca04", "url": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/vars.json" } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/ansible-lint-config.json�����������������������0000664�0000000�0000000�00000016417�14773473560�0027326�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "$defs": { "rule": { "additionalProperties": false, "properties": { "exclude_paths": { "items": { "type": "string" }, "title": "Glob-like paths to be excluded.", "type": "array" } }, "type": "object" } }, "$id": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/ansible-lint-config.json", "$schema": "http://json-schema.org/draft-07/schema", "additionalProperties": false, "description": "https://ansible.readthedocs.io/projects/lint/configuring/", "examples": [ ".ansible-lint", ".ansible-lint.yml", ".ansible-lint.yaml", ".config/ansible-lint.yml", ".config/ansible-lint.yaml" ], "properties": { "display_relative_path": { "default": true, "title": "Configure how to display file paths", "type": "boolean" }, "enable_list": { "items": { "type": "string" }, "title": "Enable List", "type": "array" }, "exclude_paths": { "items": { "type": "string" }, "title": "Exclude Paths", "type": "array" }, "extra_vars": { "title": "Extra Vars", "type": "object" }, "kinds": { "items": { "additionalProperties": { "type": "string" }, "type": "object" }, "title": "Kinds", "type": "array" }, "loop_var_prefix": { "title": "Loop Var Prefix", "type": "string" }, "max_block_depth": { "title": "Maximum Block Depth", "type": "integer", "default": 20 }, "mock_modules": { "items": { "type": "string" }, "title": "Mock Modules", "type": "array" }, "mock_roles": { "items": { "type": "string" }, "title": "Mock Roles", "type": "array" }, "offline": { "default": false, "title": "Offline", "type": "boolean" }, "only_builtins_allow_collections": { "items": { "type": "string" }, "title": "Only Builtins Allow Collections", "type": "array" }, "only_builtins_allow_modules": { "items": { "type": "string" }, "title": "Only Builtins Allow Modules", "type": "array" }, "parseable": { "default": true, "title": "Parseable", "type": "boolean" }, "profile": { "enum": [ "min", "basic", "moderate", "safety", "shared", "production", null ], "title": "Profile", "type": ["null", "string"] }, "progressive": { "default": false, "title": "Progressive (removed feature)", "type": "boolean" }, "project_dir": { "default": null, "title": "Project Directory", "type": ["string", "null"] }, "quiet": { "default": true, "title": "Quiet", "type": "boolean" }, "rules": { "additionalProperties": { "$ref": "#/$defs/rule" }, "propertyNames": { "oneOf": [ { "enum": [ "command-instead-of-module", "command-instead-of-shell", "deprecated-bare-vars", "deprecated-local-action", "deprecated-module", "empty-string-compare", "fqcn", "fqcn[action-core]", "fqcn[action]", "fqcn[canonical]", "fqcn[keyword]", "galaxy", "galaxy[no-changelog]", "galaxy[no-runtime]", "galaxy[tags]", "galaxy[version-incorrect]", "galaxy[version-missing]", "ignore-errors", "inline-env-var", "internal-error", "jinja", "jinja[invalid]", "jinja[spacing]", "key-order", "latest", "literal-compare", "load-failure", "load-failure[not-found]", "loop-var-prefix", "loop-var-prefix[missing]", "loop-var-prefix[wrong]", "meta-incorrect", "meta-no-tags", "meta-runtime", "meta-video-links", "name", "name[casing]", "name[play]", "name[prefix]", "name[template]", "no-changed-when", "no-handler", "no-jinja-when", "no-log-password", "no-prompting", "no-relative-paths", "no-same-owner", "no-tabs", "only-builtins", "package-latest", "parser-error", "partial-become", "playbook-extension", "risky-file-permissions", "risky-octal", "risky-shell-pipe", "role-name", "run-once", "run-once[play]", "run-once[task]", "sanity", "sanity[bad-ignore]", "sanity[cannot-ignore]", "schema", "syntax-check", "var-naming", "yaml" ], "type": "string" }, { "pattern": "^[a-z0-9-\\[\\]]+$", "type": "string" } ] }, "title": "Rules specific configuration.", "type": "object" }, "rulesdir": { "items": { "type": "string" }, "title": "Rulesdir", "type": "array" }, "sarif_file": { "default": null, "title": "SARIF Output filename", "type": ["null", "string"] }, "skip_action_validation": { "default": false, "title": "Skip Action Validation", "type": "boolean" }, "skip_list": { "items": { "type": "string" }, "title": "Skip List", "type": "array" }, "strict": { "default": false, "title": "Strict", "type": "boolean" }, "supported_ansible_also": { "items": { "type": "string" }, "title": "Add supported ansible versions", "type": "array" }, "tags": { "items": { "type": "string" }, "title": "Tags", "type": "array" }, "task_name_prefix": { "default": "{stem} | ", "title": "Allow custom prefix for task[prefix]", "type": "string" }, "use_default_rules": { "default": true, "title": "Use Default Rules", "type": "boolean" }, "var_naming_pattern": { "default": "^[a-z_][a-z0-9_]*$", "title": "Regex used to verify variable names", "type": "string" }, "verbosity": { "default": 0, "title": "Verbosity", "type": "integer" }, "warn_list": { "items": { "type": "string" }, "title": "Warn List", "type": "array" }, "write_exclude_list": { "items": { "type": "string" }, "title": "Write Exclude List", "type": "array" }, "write_list": { "items": { "type": "string" }, "title": "Write List", "type": "array" } }, "title": "Ansible-lint Configuration Schema", "type": "object" } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/ansible-navigator-config.json������������������0000664�0000000�0000000�00000060665�14773473560�0030356�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "$schema": "http://json-schema.org/draft-07/schema", "additionalProperties": false, "description": "See https://ansible.readthedocs.io/projects/navigator/settings/", "properties": { "ansible-navigator": { "additionalProperties": false, "properties": { "ansible": { "additionalProperties": false, "properties": { "cmdline": { "description": "Extra parameters passed to the underlying ansible command (e.g. ansible-playbook, ansible-doc, etc)", "type": "string" }, "config": { "additionalProperties": false, "properties": { "help": { "default": false, "description": "Help options for ansible-config command in stdout mode", "enum": [ true, false ], "type": "boolean" }, "path": { "description": "Specify the path to the ansible configuration file", "type": "string" } } }, "doc": { "additionalProperties": false, "properties": { "help": { "default": false, "description": "Help options for ansible-doc command in stdout mode", "enum": [ true, false ], "type": "boolean" }, "plugin": { "additionalProperties": false, "properties": { "name": { "description": "Specify the plugin name", "type": "string" }, "type": { "default": "module", "description": "Specify the plugin type, 'become', 'cache', 'callback', 'cliconf', 'connection', 'filter', 'httpapi', 'inventory', 'keyword', 'lookup', 'module', 'netconf', 'role', 'shell', 'strategy', 'test' or 'vars'", "enum": [ "become", "cache", "callback", "cliconf", "connection", "filter", "httpapi", "inventory", "keyword", "lookup", "module", "netconf", "role", "shell", "strategy", "test", "vars" ], "type": "string" } }, "type": "object" } }, "type": "object" }, "inventory": { "additionalProperties": false, "properties": { "entries": { "description": "Specify an inventory file path or comma separated host list", "items": { "type": "string" }, "type": "array" }, "help": { "default": false, "description": "Help options for ansible-inventory command in stdout mode", "enum": [ true, false ], "type": "boolean" } } }, "playbook": { "additionalProperties": false, "properties": { "help": { "default": false, "description": "Help options for ansible-playbook command in stdout mode", "enum": [ true, false ], "type": "boolean" }, "path": { "description": "Specify the playbook name", "type": "string" } } } }, "type": "object" }, "ansible-builder": { "additionalProperties": false, "properties": { "help": { "default": false, "description": "Help options for ansible-builder command in stdout mode", "enum": [ true, false ], "type": "boolean" }, "workdir": { "default": ".", "description": "Specify the path that contains ansible-builder manifest files", "type": "string" } }, "type": "object" }, "ansible-lint": { "additionalProperties": false, "properties": { "config": { "description": "Specify the path to the ansible-lint configuration file", "type": "string" }, "lintables": { "description": "Path to files on which to run ansible-lint", "type": "string" } }, "type": "object" }, "ansible-runner": { "additionalProperties": false, "properties": { "artifact-dir": { "description": "The directory path to store artifacts generated by ansible-runner", "type": "string" }, "job-events": { "default": false, "description": "Write ansible-runner job_events in the artifact directory", "enum": [ true, false ], "type": "boolean" }, "rotate-artifacts-count": { "description": "Keep ansible-runner artifact directories, for last n runs, if set to 0 artifact directories won't be deleted", "type": "integer" }, "timeout": { "description": "The timeout value after which ansible-runner will forcefully stop the execution", "type": "integer" } }, "type": "object" }, "app": { "default": "welcome", "description": "Subcommands", "enum": [ "builder", "collections", "config", "doc", "exec", "images", "inventory", "lint", "replay", "run", "settings", "welcome" ], "type": "string" }, "collection-doc-cache-path": { "default": "~/.cache/ansible-navigator/collection_doc_cache.db", "description": "The path to collection doc cache", "type": "string" }, "color": { "additionalProperties": false, "properties": { "enable": { "default": true, "description": "Enable the use of color for mode interactive and stdout", "enum": [ true, false ], "type": "boolean" }, "osc4": { "default": true, "description": "Enable or disable terminal color changing support with OSC 4", "enum": [ true, false ], "type": "boolean" } }, "type": "object" }, "editor": { "additionalProperties": false, "properties": { "command": { "default": "vi +{line_number} {filename}", "description": "Specify the editor command", "type": "string" }, "console": { "default": true, "description": "Specify if the editor is console based", "enum": [ true, false ], "type": "boolean" } }, "type": "object" }, "enable-prompts": { "default": false, "description": "Enable prompts for password and in playbooks. This will set mode to stdout and disable playbook artifact creation", "enum": [ true, false ], "type": "boolean" }, "exec": { "additionalProperties": false, "properties": { "command": { "default": "/bin/bash", "description": "Specify the command to run within the execution environment", "type": "string" }, "shell": { "default": true, "description": "Specify the exec command should be run in a shell", "enum": [ true, false ], "type": "boolean" } }, "type": "object" }, "execution-environment": { "additionalProperties": false, "properties": { "container-engine": { "default": "auto", "description": "Specify the container engine (auto=podman then docker)", "enum": [ "auto", "podman", "docker" ], "type": "string" }, "container-options": { "description": "Extra parameters passed to the container engine command", "items": { "type": "string" }, "type": "array" }, "enabled": { "default": true, "description": "Enable or disable the use of an execution environment", "enum": [ true, false ], "type": "boolean" }, "environment-variables": { "additionalProperties": false, "properties": { "pass": { "description": "Specify an existing environment variable to be passed through to and set within the execution environment (--penv MY_VAR)", "items": { "type": "string" }, "type": "array" }, "set": { "description": "Specify an environment variable and a value to be set within the execution environment (--senv MY_VAR=42)", "type": "object" } }, "type": "object" }, "image": { "description": "Specify the name of the execution environment image", "type": "string" }, "pull": { "additionalProperties": false, "properties": { "arguments": { "description": "Specify any additional parameters that should be added to the pull command when pulling an execution environment from a container registry. e.g. --pa='--tls-verify=false'", "items": { "type": "string" }, "type": "array" }, "policy": { "default": "tag", "description": "Specify the image pull policy always:Always pull the image, missing:Pull if not locally available, never:Never pull the image, tag:if the image tag is 'latest', always pull the image, otherwise pull if not locally available", "enum": [ "always", "missing", "never", "tag" ], "type": "string" } } }, "volume-mounts": { "additionalProperties": false, "description": "Specify volume to be bind mounted within an execution environment (--eev /home/user/test:/home/user/test:Z)", "items": { "additionalProperties": false, "properties": { "dest": { "type": "string" }, "options": { "type": "string" }, "src": { "type": "string" } }, "required": [ "src", "dest" ], "type": "object" }, "type": "array" } }, "type": "object" }, "format": { "default": "yaml", "description": "Specify the format for stdout output.", "enum": [ "json", "yaml" ], "type": "string" }, "images": { "additionalProperties": false, "properties": { "details": { "default": [ "everything" ], "description": "Provide detailed information about the selected execution environment image", "items": { "enum": [ "ansible_collections", "ansible_version", "everything", "os_release", "python_packages", "python_version", "redhat_release", "system_packages" ], "type": "string" }, "type": "array" } } }, "inventory-columns": { "description": "Specify a host attribute to show in the inventory view", "items": { "type": "string" }, "type": "array" }, "logging": { "additionalProperties": false, "properties": { "append": { "default": true, "description": "Specify if log messages should be appended to an existing log file, otherwise a new log file will be created per session", "enum": [ true, false ], "type": "boolean" }, "file": { "default": "./ansible-navigator.log", "description": "Specify the full path for the ansible-navigator log file", "type": "string" }, "level": { "default": "warning", "description": "Specify the ansible-navigator log level", "enum": [ "debug", "info", "warning", "error", "critical" ], "type": "string" } }, "type": "object" }, "mode": { "default": "interactive", "description": "Specify the user-interface mode", "enum": [ "stdout", "interactive" ], "type": "string" }, "playbook-artifact": { "additionalProperties": false, "properties": { "enable": { "default": true, "description": "Enable or disable the creation of artifacts for completed playbooks. Note: not compatible with '--mode stdout' when playbooks require user input", "enum": [ true, false ], "type": "boolean" }, "replay": { "description": "Specify the path for the playbook artifact to replay", "type": "string" }, "save-as": { "default": "{playbook_dir}/{playbook_name}-artifact-{time_stamp}.json", "description": "Specify the name for artifacts created from completed playbooks. The following placeholders are available: {playbook_dir}, {playbook_name}, {playbook_status}, and {time_stamp}", "type": "string" } }, "type": "object" }, "settings": { "additionalProperties": false, "properties": { "effective": { "default": false, "description": "Show the effective settings. Defaults, CLI parameters, environment variables, and the settings file will be combined", "type": "boolean" }, "sample": { "default": false, "description": "Generate a sample settings file", "type": "boolean" }, "schema": { "default": "json", "description": "Generate a schema for the settings file ('json'= draft-07 JSON Schema)", "enum": [ "json" ], "type": "string" }, "sources": { "default": false, "description": "Show the source of each current settings entry", "type": "boolean" } } }, "time-zone": { "default": "UTC", "description": "Specify the IANA time zone to use or 'local' to use the system time zone", "type": "string" } } } }, "required": [ "ansible-navigator" ], "title": "ansible-navigator settings v25", "type": "object", "version": "25" } ���������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/ansible-navigator.json�������������������������0000664�0000000�0000000�00000031504�14773473560�0027101�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "$defs": { "AnsibleBuilderModel": { "additionalProperties": false, "properties": { "workdir": { "default": "/tmp/", "description": "Specify the path that contains ansible-builder manifest files", "title": "Workdir", "type": "string" } }, "type": "object" }, "AnsibleModel": { "additionalProperties": false, "properties": { "cmdline": { "description": "Extra parameters passed to the corresponding command", "title": "Cmdline", "type": "string" }, "config": { "description": "Specify the path to the ansible configuration file", "title": "Config", "type": "string" }, "inventories": { "description": "Specify an inventory file path or host list", "items": { "type": "string" }, "title": "Inventories", "type": "array" }, "playbook": { "description": "Specify the playbook name", "title": "Playbook", "type": "string" } }, "title": "AnsibleModel", "type": "object" }, "AnsibleNavigatorModel": { "additionalProperties": false, "properties": { "ansible": { "$ref": "#/$defs/AnsibleModel" }, "ansible-builder": { "$ref": "#/$defs/AnsibleBuilderModel" }, "ansible-runner": { "$ref": "#/$defs/AnsibleRunnerModel" }, "app": { "default": "welcome", "description": "Subcommands", "enum": [ "collections", "config", "doc", "exec", "images", "inventory", "replay", "run", "welcome" ], "title": "App", "type": "string" }, "collection-doc-cache-path": { "default": "$HOME/.cache/ansible-navigator/collection_doc_cache.db", "description": "The path to collection doc cache", "title": "Collection-Doc-Cache-Path", "type": "string" }, "color": { "$ref": "#/$defs/ColorModel" }, "documentation": { "$ref": "#/$defs/DocumentationModel" }, "editor": { "$ref": "#/$defs/EditorModel" }, "exec": { "$ref": "#/$defs/ExecModel" }, "execution-environment": { "$ref": "#/$defs/ExecutionEnvironmentModel" }, "help-builder": { "default": false, "description": "Help options for ansible-builder command in stdout mode", "title": "Help-Builder", "type": "boolean" }, "help-config": { "default": false, "description": "Help options for ansible-config command in stdout mode", "title": "Help-Config", "type": "boolean" }, "help-doc": { "default": false, "description": "Help options for ansible-doc command in stdout mode", "title": "Help-Doc", "type": "boolean" }, "help-inventory": { "default": false, "description": "Help options for ansible-inventory command in stdout mode", "title": "Help-Inventory", "type": "boolean" }, "help-playbook": { "default": false, "description": "Help options for ansible-playbook command in stdout mode", "title": "Help-Playbook", "type": "boolean" }, "inventory-columns": { "description": "Specify a host attribute to show in the inventory view", "items": { "type": "string" }, "title": "Inventory-Columns", "type": "array" }, "logging": { "$ref": "#/$defs/LoggingModel" }, "mode": { "default": "interactive", "description": "Specify the user-interface mode", "enum": ["stdout", "interactive"], "title": "Mode", "type": "string" }, "playbook-artifact": { "$ref": "#/$defs/PlaybookArtifactModel" } }, "title": "AnsibleNavigatorModel", "type": "object" }, "AnsibleRunnerModel": { "additionalProperties": false, "properties": { "artifact-dir": { "description": "The directory path to store artifacts generated by ansible-runner", "title": "Artifact-Dir", "type": "string" }, "rotate-artifacts-count": { "description": "Keep ansible-runner artifact directories, for last n runs, if set to 0 artifact directories won't be deleted", "title": "Rotate-Artifacts-Count", "type": "integer" }, "timeout": { "description": "The timeout value after which ansible-runner will force stop the execution", "title": "Timeout", "type": "integer" } }, "title": "AnsibleRunnerModel", "type": "object" }, "ColorModel": { "additionalProperties": false, "properties": { "enable": { "default": false, "description": "Enable the use of color in the display", "title": "Enable", "type": "boolean" }, "osc4": { "default": true, "description": "Enable or disable terminal color changing support with OSC 4", "title": "Osc4", "type": "boolean" } }, "title": "ColorModel", "type": "object" }, "DocumentationModel": { "additionalProperties": false, "properties": { "plugin": { "$ref": "#/$defs/PluginModel" } }, "title": "DocumentationModel", "type": "object" }, "EditorModel": { "additionalProperties": false, "properties": { "command": { "default": "vi +{line_number} {filename}", "description": "Specify the editor command", "title": "Command", "type": "string" }, "console": { "default": true, "description": "Specify if the editor is console based", "title": "Console", "type": "boolean" } }, "title": "EditorModel", "type": "object" }, "EnvironmentVariablesModel": { "additionalProperties": false, "properties": { "pass": { "description": "Specify an exiting environment variable to be passed through to and set within the execution environment", "items": { "type": "string" }, "title": "Pass", "type": "array" }, "set": { "additionalProperties": { "type": "string" }, "description": "Specify an environment variable and a value to be set within the execution environment", "title": "Set", "type": "object" } }, "title": "EnvironmentVariablesModel", "type": "object" }, "ExecModel": { "additionalProperties": false, "properties": { "command": { "default": "/bin/bash", "description": "Specify the command to run within the execution environment", "title": "Command", "type": "string" }, "shell": { "default": true, "description": "Specify the exec command should be run in a shell", "title": "Shell", "type": "boolean" } }, "title": "ExecModel", "type": "object" }, "ExecutionEnvironmentModel": { "additionalProperties": false, "properties": { "container-engine": { "default": "auto", "description": "Specify the container engine (auto=podman then docker)", "enum": ["auto", "podman", "docker"], "title": "Container-Engine", "type": "string" }, "container-options": { "description": "Extra parameters passed to the container engine command", "items": { "type": "string" }, "title": "Container-Options", "type": "array" }, "enabled": { "default": true, "description": "Enable or disable the use of an execution environment", "title": "Enabled", "type": "boolean" }, "environment-variables": { "$ref": "#/$defs/EnvironmentVariablesModel" }, "image": { "default": "quay.io/ansible/creator-ee:v0.2.0", "description": "Specify the name of the execution environment image", "title": "Image", "type": "string" }, "pull-policy": { "default": "tag", "description": "Specify the image pull policy.\nalways: Always pull the image\nmissing: Pull if not locally available\nnever: Never pull the image\ntag: if the image tag is 'latest', always pull the image, otherwise pull if not locally available", "enum": ["always", "missing", "never", "tag"], "title": "Pull-Policy", "type": "string" }, "volume-mounts": { "description": "Specify volume to be bind mounted within an execution environment", "items": { "$ref": "#/$defs/VolumeMountsModel" }, "title": "Volume-Mounts", "type": "array" } }, "title": "ExecutionEnvironmentModel", "type": "object" }, "LoggingModel": { "additionalProperties": false, "properties": { "append": { "default": true, "description": "Specify if log messages should be appended to an existing log file, otherwise a new log file will be created per session", "title": "Append", "type": "boolean" }, "file": { "default": "$PWD/ansible-navigator.", "description": "Specify the full path for the ansible-navigator log file", "title": "File", "type": "string" }, "level": { "default": "warning", "description": "Specify the ansible-navigator log level", "enum": ["debug", "info", "warning", "error", "critical"], "title": "Level", "type": "string" } }, "title": "LoggingModel", "type": "object" }, "PlaybookArtifactModel": { "additionalProperties": false, "properties": { "enable": { "default": true, "description": "Enable or disable the creation of artifacts for completed playbooks.\nNote: not compatible with 'mode: stdout' when playbooks require user input", "title": "Enable", "type": "boolean" }, "replay": { "description": "Specify the path for the playbook artifact to replay", "title": "Replay", "type": "string" }, "save-as": { "default": "{playbook_dir}/{playbook_name}-artifact-{ts_utc}.json", "description": "Specify the name for artifacts created from completed playbooks", "title": "Save-As", "type": "string" } }, "title": "PlaybookArtifactModel", "type": "object" }, "PluginModel": { "additionalProperties": false, "properties": { "name": { "description": "Specify the plugin name", "title": "Name", "type": "string" }, "type": { "default": "module", "description": "Specify the plugin type", "enum": [ "become", "cache", "callback", "cliconf", "connection", "httpapi", "inventory", "lookup", "module", "netconf", "shell", "strategy", "vars" ], "title": "Type", "type": "string" } }, "title": "PluginModel", "type": "object" }, "VolumeMountsModel": { "additionalProperties": false, "properties": { "dest": { "title": "Dest", "type": "string" }, "label": { "title": "Label", "type": "string" }, "src": { "title": "Src", "type": "string" } }, "required": ["src", "dest"], "title": "VolumeMountsModel", "type": "object" } }, "$id": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/ansible-navigator.json", "$schema": "http://json-schema.org/draft-07/schema", "additionalProperties": false, "examples": ["ansible-navigator.yml"], "properties": { "ansible-navigator": { "$ref": "#/$defs/AnsibleNavigatorModel" } }, "required": ["ansible-navigator"], "title": "Ansible-Navigator Configuration Schema", "type": "object" } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/ansible.json�����������������������������������0000664�0000000�0000000�00000100062�14773473560�0025105�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "$defs": { "removed-include-module": { "markdownDescription": "See [include module](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/include_module.html)", "not": {}, "title": "Replace 'include' with either 'ansible.builtin.include_tasks' or 'ansible.builtin.import_tasks'" }, "ansible.builtin.import_playbook": { "additionalProperties": false, "oneOf": [ { "not": { "required": ["import_playbook"] }, "required": ["ansible.builtin.import_playbook"] }, { "not": { "required": ["ansible.builtin.import_playbook"] }, "required": ["import_playbook"] } ], "patternProperties": { "^(ansible\\.builtin\\.)?import_playbook$": { "markdownDescription": "* Includes a file with a list of plays to be executed.\n * Files with a list of plays can only be included at the top level.\n * You cannot use this action inside a play.\n\nSee [import_playbook](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/import_playbook_module.html)", "title": "Import Playbook", "type": "string" }, "name": { "title": "Name", "type": "string" }, "tags": { "$ref": "#/$defs/tags" }, "vars": { "title": "Vars", "type": "object" }, "when": { "$ref": "#/$defs/complex_conditional", "title": "When" } }, "type": "object" }, "become_method": { "anyOf": [ { "enum": [ "ansible.builtin.sudo", "ansible.builtin.su", "community.general.pbrun", "community.general.pfexec", "ansible.builtin.runas", "community.general.dzdo", "community.general.ksu", "community.general.doas", "community.general.machinectl", "community.general.pmrun", "community.general.sesu", "community.general.sudosu" ], "type": "string" }, { "$ref": "#/$defs/full-jinja" }, { "pattern": "[A-Za-z0-9_\\.]+", "type": "string" } ], "markdownDescription": "See [become](https://docs.ansible.com/ansible/latest/user_guide/become.html)", "title": "Become Method" }, "block": { "properties": { "always": { "items": { "anyOf": [ { "$ref": "#/$defs/task" }, { "$ref": "#/$defs/block" } ] }, "title": "Always", "type": "array" }, "any_errors_fatal": { "$ref": "#/$defs/templated-boolean", "title": "Any Errors Fatal" }, "become": { "$ref": "#/$defs/templated-boolean", "title": "Become" }, "become_exe": { "title": "Become Exe", "type": "string" }, "become_flags": { "title": "Become Flags", "type": "string" }, "become_method": { "$ref": "#/$defs/become_method" }, "become_user": { "title": "Become User", "type": "string" }, "block": { "items": { "anyOf": [ { "$ref": "#/$defs/task" }, { "$ref": "#/$defs/block" } ] }, "markdownDescription": "Blocks create logical groups of tasks. Blocks also offer ways to handle task errors, similar to exception handling in many programming languages. See [blocks](https://docs.ansible.com/ansible/latest/user_guide/playbooks_blocks.html)", "title": "Block", "type": "array" }, "check_mode": { "$ref": "#/$defs/complex_conditional", "title": "Check Mode" }, "collections": { "items": { "type": "string" }, "title": "Collections", "type": "array" }, "connection": { "title": "Connection", "type": "string" }, "debugger": { "title": "Debugger", "type": "string" }, "delegate_facts": { "title": "Delegate Facts", "type": "boolean" }, "delegate_to": { "title": "Delegate To", "type": "string" }, "diff": { "$ref": "#/$defs/templated-boolean", "title": "Diff" }, "environment": { "$ref": "#/$defs/environment" }, "ignore_errors": { "$ref": "#/$defs/ignore_errors" }, "ignore_unreachable": { "title": "Ignore Unreachable", "$ref": "#/$defs/templated-boolean" }, "module_defaults": { "title": "Module Defaults" }, "name": { "title": "Name", "type": "string" }, "no_log": { "$ref": "#/$defs/templated-boolean" }, "port": { "$ref": "#/$defs/templated-integer" }, "remote_user": { "title": "Remote User", "type": "string" }, "rescue": { "items": { "anyOf": [ { "$ref": "#/$defs/task" }, { "$ref": "#/$defs/block" } ] }, "title": "Rescue", "type": "array" }, "run_once": { "$ref": "#/$defs/templated-boolean", "title": "Run Once" }, "tags": { "$ref": "#/$defs/tags", "title": "Tags" }, "throttle": { "$ref": "#/$defs/templated-integer", "title": "Throttle" }, "timeout": { "$ref": "#/$defs/templated-integer", "title": "Timeout" }, "vars": { "title": "Vars", "type": "object" }, "when": { "$ref": "#/$defs/complex_conditional", "title": "When" } }, "required": ["block"], "type": "object" }, "complex_conditional": { "oneOf": [ { "type": "boolean" }, { "type": "string" }, { "items": { "anyOf": [ { "type": "boolean" }, { "type": "string" } ] }, "type": "array" } ] }, "environment": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "$ref": "#/$defs/full-jinja" } ], "title": "Environment" }, "full-jinja": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$", "type": "string" }, "ignore_errors": { "$ref": "#/$defs/templated-boolean", "markdownDescription": "See [ignore_errors](https://docs.ansible.com/ansible/latest/user_guide/playbooks_error_handling.html#ignoring-failed-commands)", "title": "Ignore Errors" }, "no_log": { "$ref": "#/$defs/templated-boolean", "markdownDescription": "Use for protecting sensitive data. See [no_log](https://docs.ansible.com/ansible/latest/reference_appendices/logging.html)", "title": "no_log" }, "play": { "additionalProperties": false, "allOf": [ { "not": { "required": ["ansible.builtin.import_playbook"] } }, { "not": { "required": ["import_playbook"] } } ], "properties": { "any_errors_fatal": { "$ref": "#/$defs/templated-boolean", "title": "Any Errors Fatal" }, "become": { "$ref": "#/$defs/templated-boolean", "title": "Become" }, "become_exe": { "title": "Become Exe", "type": "string" }, "become_flags": { "title": "Become Flags", "type": "string" }, "become_method": { "$ref": "#/$defs/become_method" }, "become_user": { "title": "Become User", "type": "string" }, "check_mode": { "$ref": "#/$defs/complex_conditional", "title": "Check Mode" }, "collections": { "items": { "type": "string" }, "title": "Collections", "type": "array" }, "connection": { "title": "Connection", "type": "string" }, "debugger": { "title": "Debugger", "type": "string" }, "diff": { "$ref": "#/$defs/templated-boolean", "title": "Diff" }, "environment": { "$ref": "#/$defs/environment" }, "fact_path": { "title": "Fact Path", "type": "string" }, "force_handlers": { "title": "Force Handlers", "type": "boolean" }, "gather_facts": { "$ref": "#/$defs/templated-boolean", "title": "Gather Facts" }, "gather_subset": { "items": { "anyOf": [ { "enum": [ "all", "min", "all_ipv4_addresses", "all_ipv6_addresses", "apparmor", "architecture", "caps", "chroot,cmdline", "date_time", "default_ipv4", "default_ipv6", "devices", "distribution", "distribution_major_version", "distribution_release", "distribution_version", "dns", "effective_group_ids", "effective_user_id", "env", "facter", "fips", "hardware", "interfaces", "is_chroot", "iscsi", "kernel", "local", "lsb", "machine", "machine_id", "mounts", "network", "ohai", "os_family", "pkg_mgr", "platform", "processor", "processor_cores", "processor_count", "python", "python_version", "real_user_id", "selinux", "service_mgr", "ssh_host_key_dsa_public", "ssh_host_key_ecdsa_public", "ssh_host_key_ed25519_public", "ssh_host_key_rsa_public", "ssh_host_pub_keys", "ssh_pub_keys", "system", "system_capabilities", "system_capabilities_enforced", "user", "user_dir", "user_gecos", "user_gid", "user_id", "user_shell", "user_uid", "virtual", "virtualization_role", "virtualization_type" ], "type": "string" }, { "enum": [ "!all", "!min", "!all_ipv4_addresses", "!all_ipv6_addresses", "!apparmor", "!architecture", "!caps", "!chroot,cmdline", "!date_time", "!default_ipv4", "!default_ipv6", "!devices", "!distribution", "!distribution_major_version", "!distribution_release", "!distribution_version", "!dns", "!effective_group_ids", "!effective_user_id", "!env", "!facter", "!fips", "!hardware", "!interfaces", "!is_chroot", "!iscsi", "!kernel", "!local", "!lsb", "!machine", "!machine_id", "!mounts", "!network", "!ohai", "!os_family", "!pkg_mgr", "!platform", "!processor", "!processor_cores", "!processor_count", "!python", "!python_version", "!real_user_id", "!selinux", "!service_mgr", "!ssh_host_key_dsa_public", "!ssh_host_key_ecdsa_public", "!ssh_host_key_ed25519_public", "!ssh_host_key_rsa_public", "!ssh_host_pub_keys", "!ssh_pub_keys", "!system", "!system_capabilities", "!system_capabilities_enforced", "!user", "!user_dir", "!user_gecos", "!user_gid", "!user_id", "!user_shell", "!user_uid", "!virtual", "!virtualization_role", "!virtualization_type" ], "type": "string" } ] }, "title": "Gather Subset", "type": "array" }, "gather_timeout": { "$ref": "#/$defs/templated-integer", "title": "Gather Timeout" }, "handlers": { "$ref": "#/$defs/tasks" }, "hosts": { "anyOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ], "title": "Hosts" }, "ignore_errors": { "$ref": "#/$defs/ignore_errors" }, "ignore_unreachable": { "title": "Ignore Unreachable", "$ref": "#/$defs/templated-boolean" }, "max_fail_percentage": { "title": "Max Fail Percentage", "$ref": "#/$defs/templated-integer" }, "module_defaults": { "title": "Module Defaults" }, "name": { "title": "Name", "type": "string" }, "no_log": { "$ref": "#/$defs/templated-boolean" }, "order": { "oneOf": [ { "enum": [ "inventory", "reverse_inventory", "reverse_sorted", "shuffle", "sorted" ], "type": "string" }, { "$ref": "#/$defs/full-jinja" } ], "title": "Order", "markdownDescription": "See https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_strategies.html#ordering-execution-based-on-inventory" }, "port": { "$ref": "#/$defs/templated-integer", "title": "Port" }, "post_tasks": { "$ref": "#/$defs/tasks" }, "pre_tasks": { "$ref": "#/$defs/tasks" }, "remote_user": { "title": "Remote User", "type": "string" }, "roles": { "items": { "anyOf": [ { "$ref": "#/$defs/play-role" }, { "type": "string" } ] }, "markdownDescription": "Roles let you automatically load related vars, files, tasks, handlers, and other Ansible artifacts based on a known file structure. After you group your content in roles, you can easily reuse them and share them with other users.\n See [roles](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#roles)", "title": "Roles", "type": "array" }, "run_once": { "$ref": "#/$defs/templated-boolean", "title": "Run Once" }, "serial": { "anyOf": [ { "$ref": "#/$defs/templated-integer-or-percent" }, { "items": { "$ref": "#/$defs/templated-integer-or-percent" }, "type": "array" } ], "markdownDescription": "Integer, percentage or list of those. See [Setting the batch size with serial](https://docs.ansible.com/ansible/latest/user_guide/playbooks_strategies.html#setting-the-batch-size-with-serial)", "title": "Batch size" }, "strategy": { "title": "Strategy", "type": "string" }, "tags": { "$ref": "#/$defs/tags", "title": "Tags" }, "tasks": { "$ref": "#/$defs/tasks" }, "throttle": { "$ref": "#/$defs/templated-integer", "title": "Throttle" }, "timeout": { "$ref": "#/$defs/templated-integer", "title": "Timeout" }, "user": { "title": "Remote User", "type": "string" }, "vars": { "title": "Vars", "type": "object" }, "vars_files": { "items": { "oneOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ] }, "title": "Vars Files", "type": ["array", "string", "null"] }, "vars_prompt": { "items": { "$ref": "#/$defs/vars_prompt" }, "markdownDescription": "See [vars_prompt](https://docs.ansible.com/ansible/latest/user_guide/playbooks_prompts.html)", "title": "vars_prompt", "type": "array" }, "when": { "$ref": "#/$defs/complex_conditional", "title": "When" } }, "required": ["hosts"], "title": "play", "type": "object" }, "play-role": { "markdownDescription": "See [roles](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#roles)", "properties": { "any_errors_fatal": { "$ref": "#/$defs/templated-boolean", "title": "Any Errors Fatal" }, "become": { "$ref": "#/$defs/templated-boolean", "title": "Become" }, "become_exe": { "title": "Become Exe", "type": "string" }, "become_flags": { "title": "Become Flags", "type": "string" }, "become_method": { "$ref": "#/$defs/become_method" }, "become_user": { "title": "Become User", "type": "string" }, "check_mode": { "$ref": "#/$defs/complex_conditional", "title": "Check Mode" }, "collections": { "items": { "type": "string" }, "title": "Collections", "type": "array" }, "connection": { "title": "Connection", "type": "string" }, "debugger": { "title": "Debugger", "type": "string" }, "delegate_to": { "title": "Delegate To", "type": "string" }, "diff": { "$ref": "#/$defs/templated-boolean", "title": "Diff" }, "environment": { "$ref": "#/$defs/environment" }, "ignore_errors": { "$ref": "#/$defs/ignore_errors" }, "ignore_unreachable": { "title": "Ignore Unreachable", "$ref": "#/$defs/templated-boolean" }, "module_defaults": { "title": "Module Defaults" }, "name": { "title": "Name", "type": "string" }, "no_log": { "$ref": "#/$defs/templated-boolean" }, "port": { "$ref": "#/$defs/templated-integer", "title": "Port" }, "remote_user": { "title": "Remote User", "type": "string" }, "role": { "title": "Role", "type": "string" }, "run_once": { "$ref": "#/$defs/templated-boolean", "title": "Run Once" }, "tags": { "$ref": "#/$defs/tags", "title": "Tags" }, "throttle": { "$ref": "#/$defs/templated-integer", "title": "Throttle" }, "timeout": { "$ref": "#/$defs/templated-integer", "title": "Timeout" }, "vars": { "title": "Vars", "type": "object" }, "when": { "$ref": "#/$defs/complex_conditional", "title": "When" } }, "required": ["role"], "title": "play-role", "type": "object" }, "playbook": { "examples": ["playbooks/*.yml", "playbooks/*.yaml"], "items": { "oneOf": [ { "$ref": "#/$defs/ansible.builtin.import_playbook" }, { "$ref": "#/$defs/play" } ] }, "title": "Ansible Playbook", "type": "array" }, "tags": { "anyOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ], "title": "Tags" }, "task": { "additionalProperties": true, "allOf": [ { "not": { "required": ["hosts"] } }, { "not": { "required": ["tasks"] } }, { "not": { "required": ["import_playbook"] } }, { "not": { "required": ["block"] } } ], "properties": { "action": { "title": "Action", "type": "string" }, "ansible.builtin.include": { "$ref": "#/$defs/removed-include-module" }, "include": { "$ref": "#/$defs/removed-include-module" }, "ansible.legacy.include": { "$ref": "#/$defs/removed-include-module" }, "any_errors_fatal": { "$ref": "#/$defs/templated-boolean", "title": "Any Errors Fatal" }, "args": { "$ref": "#/$defs/templated-object", "title": "Args" }, "async": { "$ref": "#/$defs/templated-integer", "title": "Async" }, "become": { "$ref": "#/$defs/templated-boolean", "title": "Become" }, "become_exe": { "title": "Become Exe", "type": "string" }, "become_flags": { "title": "Become Flags", "type": "string" }, "become_method": { "$ref": "#/$defs/become_method" }, "become_user": { "title": "Become User", "type": "string" }, "changed_when": { "$ref": "#/$defs/complex_conditional", "markdownDescription": "See [changed_when](https://docs.ansible.com/ansible/latest/user_guide/playbooks_error_handling.html#defining-changed)", "title": "Changed When" }, "check_mode": { "$ref": "#/$defs/complex_conditional", "title": "Check Mode" }, "collections": { "items": { "type": "string" }, "title": "Collections", "type": "array" }, "connection": { "title": "Connection", "type": "string" }, "debugger": { "title": "Debugger", "type": "string" }, "delay": { "$ref": "#/$defs/templated-integer", "title": "Delay" }, "delegate_facts": { "title": "Delegate Facts", "type": "boolean" }, "delegate_to": { "title": "Delegate To", "type": "string" }, "diff": { "$ref": "#/$defs/templated-boolean", "title": "Diff" }, "environment": { "$ref": "#/$defs/environment" }, "failed_when": { "$ref": "#/$defs/complex_conditional", "title": "Failed When" }, "ignore_errors": { "$ref": "#/$defs/ignore_errors" }, "ignore_unreachable": { "title": "Ignore Unreachable", "$ref": "#/$defs/templated-boolean" }, "listen": { "anyOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ], "markdownDescription": "Applies only to handlers. See [listen](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html)", "title": "Listen" }, "local_action": { "title": "Local Action", "type": ["string", "object"] }, "loop": { "title": "Loop", "type": ["string", "array"] }, "loop_control": { "title": "Loop Control" }, "module_defaults": { "title": "Module Defaults" }, "name": { "title": "Name", "type": "string" }, "no_log": { "$ref": "#/$defs/no_log" }, "notify": { "anyOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ], "title": "Notify" }, "poll": { "$ref": "#/$defs/templated-integer", "title": "Poll" }, "port": { "$ref": "#/$defs/templated-integer", "title": "Port" }, "register": { "title": "Register", "type": "string" }, "remote_user": { "title": "Remote User", "type": "string" }, "retries": { "$ref": "#/$defs/templated-integer", "title": "Retries" }, "run_once": { "$ref": "#/$defs/templated-boolean", "title": "Run Once" }, "tags": { "$ref": "#/$defs/tags", "title": "Tags" }, "throttle": { "$ref": "#/$defs/templated-integer", "title": "Throttle" }, "timeout": { "$ref": "#/$defs/templated-integer", "title": "Timeout" }, "until": { "$ref": "#/$defs/complex_conditional", "title": "Until" }, "vars": { "title": "Vars", "type": "object" }, "when": { "$ref": "#/$defs/complex_conditional", "title": "When" }, "with_dict": { "title": "With Dict" }, "with_fileglob": { "title": "With Fileglob" }, "with_filetree": { "title": "With Filetree" }, "with_first_found": { "title": "With First Found" }, "with_indexed_items": { "title": "With Indexed Items" }, "with_ini": { "title": "With Ini" }, "with_inventory_hostnames": { "title": "With Inventory Hostnames" }, "with_items": { "anyOf": [ { "$ref": "#/$defs/full-jinja" }, { "type": "array" } ], "markdownDescription": "See [loops](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#loops)", "title": "With Items" }, "with_lines": { "title": "With Lines" }, "with_random_choice": { "title": "With Random Choice" }, "with_sequence": { "title": "With Sequence" }, "with_subelements": { "title": "With Subelements" }, "with_together": { "title": "With Together" } }, "title": "task", "type": "object" }, "tasks": { "$schema": "http://json-schema.org/draft-07/schema", "examples": ["tasks/*.yml", "handlers/*.yml"], "items": { "anyOf": [ { "$ref": "#/$defs/block" }, { "$ref": "#/$defs/task" } ] }, "title": "Ansible Tasks Schema", "type": ["array", "null"] }, "templated-boolean": { "oneOf": [ { "type": "boolean" }, { "$ref": "#/$defs/full-jinja", "type": "string" } ] }, "templated-integer": { "oneOf": [ { "type": "integer" }, { "$ref": "#/$defs/full-jinja", "type": "string" } ] }, "templated-integer-or-percent": { "oneOf": [ { "type": "integer" }, { "pattern": "^\\d+\\.?\\d*%?$", "type": "string" }, { "$ref": "#/$defs/full-jinja", "type": "string" } ] }, "templated-object": { "oneOf": [ { "type": "object" }, { "$ref": "#/$defs/full-jinja", "type": "string" } ] }, "vars_prompt": { "additionalProperties": false, "properties": { "confirm": { "title": "Confirm", "type": "boolean" }, "default": { "title": "Default", "type": "string" }, "encrypt": { "enum": [ "des_crypt", "bsdi_crypt", "bigcrypt", "crypt16", "md5_crypt", "bcrypt", "sha1_crypt", "sun_md5_crypt", "sha256_crypt", "sha512_crypt", "apr_md5_crypt", "phpass", "pbkdf2_digest", "cta_pbkdf2_sha1", "dlitz_pbkdf2_sha1", "scram", "bsd_nthash" ], "title": "Encrypt", "type": "string" }, "name": { "title": "Name", "type": "string" }, "private": { "default": true, "title": "Private", "type": "boolean" }, "prompt": { "title": "Prompt", "type": "string" }, "salt_size": { "default": 8, "title": "Salt Size", "type": "integer" }, "unsafe": { "default": false, "markdownDescription": "See [unsafe](https://docs.ansible.com/ansible/latest/user_guide/playbooks_prompts.html#allowing-special-characters-in-vars-prompt-values)", "title": "Unsafe", "type": "boolean" } }, "required": ["name", "prompt"], "type": "object" } }, "$id": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/ansible.json", "$schema": "http://json-schema.org/draft-07/schema", "additionalProperties": false, "description": "https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html", "examples": [], "title": "Ansible Schemas Bundle 22.4", "type": ["array", "object"] } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/changelog.json���������������������������������0000664�0000000�0000000�00000020025�14773473560�0025417�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "$defs": { "plugin-descriptions": { "items": { "properties": { "description": { "markdownDescription": "Value of `short_description` from plugin `DOCUMENTATION`.", "title": "Description", "type": "string" }, "name": { "markdownDescription": "It must not be the FQCN, but the name inside the collection.", "pattern": "[a-zA-Z0-9_]+", "title": "Name", "type": "string" }, "namespace": { "type": "null" } }, "type": "object" }, "type": "array" }, "release": { "additionalProperties": false, "properties": { "changes": { "additionalProperties": true, "properties": { "breaking_changes": { "items": { "type": "string" }, "type": "array" }, "bugfixes": { "items": { "type": "string" }, "type": "array" }, "deprecated_features": { "items": { "type": "string" }, "type": "array" }, "known_issues": { "items": { "type": "string" }, "type": "array" }, "major_changes": { "items": { "type": "string" }, "type": "array" }, "minor_changes": { "items": { "type": "string" }, "type": "array" }, "release_summary": { "markdownDescription": "This must be valid [reStructuredText](https://en.wikipedia.org/wiki/ReStructuredText).", "title": "Release Summary", "type": "string" }, "removed_features": { "items": { "type": "string" }, "type": "array" }, "security_fixes": { "items": { "type": "string" }, "type": "array" }, "trivial": { "items": { "type": "string" }, "type": "array" } }, "type": "object" }, "codename": { "type": "string" }, "fragments": { "items": { "type": "string" }, "markdownDescription": "List of strings representing filenames of changelog framents.", "type": "array" }, "modules": { "items": { "properties": { "description": { "markdownDescription": "Value of `short_description` from plugin `DOCUMENTATION`.", "title": "Description", "type": "string" }, "name": { "markdownDescription": "It must not be the FQCN, but the name inside the collection.", "pattern": "[a-zA-Z0-9_]+", "title": "Short module name", "type": "string" }, "namespace": { "markdownDescription": "Must be `''` for modules directly in `plugins/modules/`, or the dot-separated list of directories the module is in inside the `plugins/modules/` directory. The namespace is used to group new modules by their namespace inside the collection.", "title": "Namespace", "type": "string" } }, "type": "object" }, "type": "array" }, "objects": { "additionalProperties": false, "properties": { "playbook": { "items": { "properties": { "description": { "markdownDescription": "A short description of what the playbook does.", "title": "Description", "type": "string" }, "name": { "markdownDescription": "It must not be the FQCN, but the name inside the collection.", "pattern": "[a-zA-Z0-9_]+", "title": "Short playbook name", "type": "string" }, "namespace": { "type": "null" } }, "type": "object" }, "type": "array" }, "role": { "items": { "properties": { "description": { "markdownDescription": "Value of `short_description` from role's argument spec.", "title": "Description", "type": "string" }, "name": { "markdownDescription": "It must not be the FQCN, but the name inside the collection.", "pattern": "[a-zA-Z0-9_]+", "title": "Short role name", "type": "string" }, "namespace": { "type": "null" } }, "type": "object" }, "type": "array" } }, "type": "object" }, "plugins": { "additionalProperties": false, "properties": { "become": { "$ref": "#/$defs/plugin-descriptions" }, "cache": { "$ref": "#/$defs/plugin-descriptions" }, "callback": { "$ref": "#/$defs/plugin-descriptions" }, "cliconf": { "$ref": "#/$defs/plugin-descriptions" }, "connection": { "$ref": "#/$defs/plugin-descriptions" }, "filter": { "$ref": "#/$defs/plugin-descriptions" }, "httpapi": { "$ref": "#/$defs/plugin-descriptions" }, "inventory": { "$ref": "#/$defs/plugin-descriptions" }, "lookup": { "$ref": "#/$defs/plugin-descriptions" }, "netconf": { "$ref": "#/$defs/plugin-descriptions" }, "shell": { "$ref": "#/$defs/plugin-descriptions" }, "strategy": { "$ref": "#/$defs/plugin-descriptions" }, "test": { "$ref": "#/$defs/plugin-descriptions" }, "vars": { "$ref": "#/$defs/plugin-descriptions" } }, "type": "object" }, "release_date": { "format": "date", "markdownDescription": "Use ISO-8601 date format, like 2020-12-31", "pattern": "\\d\\d\\d\\d-\\d\\d-\\d\\d", "title": "Date of the release.", "type": "string" } }, "type": "object" }, "semver": { "pattern": "\\d+.\\d+.\\d+.*", "title": "Version string following SemVer specification.", "type": ["string", "null"] } }, "$id": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/changelog.json", "$schema": "http://json-schema.org/draft-07/schema", "additionalProperties": false, "examples": ["changelogs/changelog.yaml"], "markdownDescription": "Antsibull Changelog Schema is based on [changelog.yaml-format.md](https://github.com/ansible-community/antsibull-changelog/blob/main/docs/changelog.yaml-format.md).", "properties": { "ancestor": { "$ref": "#/$defs/semver" }, "releases": { "patternProperties": { "\\d+.\\d+.\\d+.*": { "$ref": "#/$defs/release", "type": "object" } }, "type": "object" } }, "title": "Antsibull Changelog Schema", "type": "object" } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/execution-environment.json���������������������0000664�0000000�0000000�00000026005�14773473560�0030041�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "$defs": { "TYPE_DictOrStringOrListOfStrings": { "anyOf": [ { "type": "object" }, { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ] }, "TYPE_StringOrListOfStrings": { "anyOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ] }, "v1": { "additionalProperties": false, "properties": { "additional_build_steps": { "properties": { "append": { "$ref": "#/$defs/TYPE_StringOrListOfStrings", "examples": ["RUN cat /etc/os-release"] }, "prepend": { "$ref": "#/$defs/TYPE_StringOrListOfStrings", "examples": ["RUN cat /etc/os-release"] } }, "title": "Commands to append or prepend to container build process.", "type": "object" }, "ansible_config": { "examples": ["ansible.cfg"], "title": "Ansible configuration file", "type": "string" }, "build_arg_defaults": { "additionalProperties": true, "properties": { "EE_BASE_IMAGE": { "type": "string" } }, "type": "object" }, "dependencies": { "description": "Allows adding system, python or galaxy dependencies.", "properties": { "galaxy": { "examples": ["requirements.yml"], "markdownDescription": "Example `requirements.yml`", "title": "Optional galaxy file", "type": "string" }, "python": { "examples": ["requirements.txt"], "markdownDescription": "Example `requirements.txt`", "title": "Optional python package dependencies", "type": "string" }, "system": { "examples": ["bindep.txt"], "markdownDescription": "Example `bindep.txt`", "title": "Optional system dependencies using bindep format", "type": "string" } }, "title": "Dependencies", "type": "object" }, "version": { "enum": [1], "title": "Version", "type": "integer" } }, "required": ["version", "dependencies"], "title": "Ansible Execution Environment Schema v1", "type": "object" }, "v3": { "additionalProperties": false, "properties": { "additional_build_files": { "description": "Describes files to add to the build context", "items": { "additionalProperties": false, "properties": { "dest": { "description": "Relative subdirectory under build context to place file", "type": "string" }, "src": { "description": "File to add to build context", "type": "string" } }, "required": ["src", "dest"], "type": "object" }, "type": "array" }, "additional_build_steps": { "properties": { "append_base": { "$ref": "#/$defs/TYPE_StringOrListOfStrings", "examples": ["RUN cat /etc/os-release"] }, "append_builder": { "$ref": "#/$defs/TYPE_StringOrListOfStrings", "examples": ["RUN cat /etc/os-release"] }, "append_final": { "$ref": "#/$defs/TYPE_StringOrListOfStrings", "examples": ["RUN cat /etc/os-release"] }, "append_galaxy": { "$ref": "#/$defs/TYPE_StringOrListOfStrings", "examples": ["RUN cat /etc/os-release"] }, "prepend_base": { "$ref": "#/$defs/TYPE_StringOrListOfStrings", "examples": ["RUN cat /etc/os-release"] }, "prepend_builder": { "$ref": "#/$defs/TYPE_StringOrListOfStrings", "examples": ["RUN cat /etc/os-release"] }, "prepend_final": { "$ref": "#/$defs/TYPE_StringOrListOfStrings", "examples": ["RUN cat /etc/os-release"] }, "prepend_galaxy": { "$ref": "#/$defs/TYPE_StringOrListOfStrings", "examples": ["RUN cat /etc/os-release"] } }, "title": "Commands to append or prepend to container build process.", "type": "object" }, "build_arg_defaults": { "additionalProperties": false, "properties": { "ANSIBLE_GALAXY_CLI_COLLECTION_OPTS": { "type": "string" }, "ANSIBLE_GALAXY_CLI_ROLE_OPTS": { "type": "string" }, "PKGMGR_PRESERVE_CACHE": { "type": "string" } }, "type": "object" }, "dependencies": { "description": "Allows adding system, python or galaxy dependencies.", "properties": { "ansible_core": { "additionalProperties": false, "description": "Ansible package installation", "oneOf": [{ "required": ["package_pip"] }], "properties": { "package_pip": { "description": "Ansible package to install via pip", "type": "string" } }, "type": "object" }, "ansible_runner": { "additionalProperties": false, "description": "Ansible Runner package installation", "oneOf": [{ "required": ["package_pip"] }], "properties": { "package_pip": { "description": "Ansible Runner package to install via pip", "type": "string" } }, "type": "object" }, "galaxy": { "$ref": "#/$defs/TYPE_DictOrStringOrListOfStrings", "examples": ["requirements.yml"], "markdownDescription": "Example `requirements.yml`", "title": "Optional galaxy file" }, "python": { "$ref": "#/$defs/TYPE_StringOrListOfStrings", "examples": ["requirements.txt"], "markdownDescription": "Example `requirements.txt`", "title": "Optional python package dependencies" }, "python_interpreter": { "additionalProperties": false, "description": "Python package name and path", "properties": { "package_system": { "description": "The python package to install via system package manager", "type": "string" }, "python_path": { "description": "Path to the python interpreter", "type": "string" } }, "type": "object" }, "system": { "$ref": "#/$defs/TYPE_StringOrListOfStrings", "examples": ["bindep.txt"], "markdownDescription": "Example `bindep.txt`", "title": "Optional system dependencies using bindep format" } }, "title": "Dependencies", "type": "object" }, "images": { "additionalProperties": false, "properties": { "base_image": { "name": { "examples": [ "registry.redhat.io/ansible-automation-platform-21/ee-minimal-rhel8:latest" ], "type": "string" }, "type": "object" } }, "type": "object" }, "options": { "additionalProperties": false, "description": "Options that effect runtime behavior", "properties": { "container_init": { "additionalProperties": false, "description": "Customize container startup behavior", "properties": { "cmd": { "description": "literal value for CMD Containerfile directive", "type": "string" }, "entrypoint": { "description": "literal value for ENTRYPOINT Containerfile directive", "type": "string" }, "package_pip": { "description": "package to install via pip for entrypoint support", "type": "string" } }, "type": "object" }, "package_manager_path": { "description": "Path to the system package manager to use", "type": "string" }, "relax_passwd_permissions": { "description": "allows GID0 write access to /etc/passwd; currently necessary for many uses", "type": "boolean" }, "skip_ansible_check": { "description": "Disables the check for Ansible/Runner in final image", "type": "boolean" }, "skip_pip_install": { "description": "Disables the installation of pip in the base image", "type": "boolean" }, "user": { "description": "Sets the username or UID", "type": "string" }, "workdir": { "description": "Default working directory, also often the homedir for ephemeral UIDs", "type": ["string", "null"] }, "tags": { "description": "A list of names to assign to the resulting image if build process completes successfully", "type": "array", "items": { "type": "string" } } }, "type": "object" }, "version": { "enum": [3], "title": "Version", "type": "integer" } }, "required": ["version", "dependencies"], "title": "Ansible Execution Environment Schema v3", "type": "object" } }, "$id": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/execution-environment.json", "$schema": "http://json-schema.org/draft-07/schema", "description": "See https://ansible-builder.readthedocs.io/en/latest/definition/ for V3 or https://docs.ansible.com/automation-controller/latest/html/userguide/ee_reference.html for older V1 format.\n", "documentation_url": "https://ansible.readthedocs.io/projects/builder/en/latest/definition/", "examples": ["execution-environment.yml"], "oneOf": [{ "$ref": "#/$defs/v3" }, { "$ref": "#/$defs/v1" }], "title": "Ansible Execution Environment Schema v1/v3" } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/galaxy.json������������������������������������0000664�0000000�0000000�00000051634�14773473560�0024767�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "$defs": { "CollectionVersionConstraintModel": { "additionalProperties": false, "title": "CollectionVersionConstraintModel", "type": "string" }, "SPDXLicense": { "$ref": "#/$defs/SPDXLicenseEnum", "title": "SPDXLicense" }, "SPDXLicenseEnum": { "description": "An enumeration.", "enum": [ "0BSD", "389-exception", "3D-Slicer-1.0", "AAL", "ADSL", "AFL-1.1", "AFL-1.2", "AFL-2.0", "AFL-2.1", "AFL-3.0", "AGPL-1.0-only", "AGPL-1.0-or-later", "AGPL-3.0-only", "AGPL-3.0-or-later", "AMD-newlib", "AMDPLPA", "AML", "AML-glslang", "AMPAS", "ANTLR-PD", "ANTLR-PD-fallback", "APAFML", "APL-1.0", "APSL-1.0", "APSL-1.1", "APSL-1.2", "APSL-2.0", "ASWF-Digital-Assets-1.0", "ASWF-Digital-Assets-1.1", "Abstyles", "AdaCore-doc", "Adobe-2006", "Adobe-Display-PostScript", "Adobe-Glyph", "Adobe-Utopia", "Afmparse", "Aladdin", "Apache-1.0", "Apache-1.1", "Apache-2.0", "App-s2p", "Arphic-1999", "Artistic-1.0", "Artistic-1.0-Perl", "Artistic-1.0-cl8", "Artistic-2.0", "Asterisk-exception", "Asterisk-linking-protocols-exception", "Autoconf-exception-2.0", "Autoconf-exception-3.0", "Autoconf-exception-generic", "Autoconf-exception-generic-3.0", "Autoconf-exception-macro", "BSD-1-Clause", "BSD-2-Clause", "BSD-2-Clause-Darwin", "BSD-2-Clause-Patent", "BSD-2-Clause-Views", "BSD-2-Clause-first-lines", "BSD-3-Clause", "BSD-3-Clause-Attribution", "BSD-3-Clause-Clear", "BSD-3-Clause-HP", "BSD-3-Clause-LBNL", "BSD-3-Clause-Modification", "BSD-3-Clause-No-Military-License", "BSD-3-Clause-No-Nuclear-License", "BSD-3-Clause-No-Nuclear-License-2014", "BSD-3-Clause-No-Nuclear-Warranty", "BSD-3-Clause-Open-MPI", "BSD-3-Clause-Sun", "BSD-3-Clause-acpica", "BSD-3-Clause-flex", "BSD-4-Clause", "BSD-4-Clause-Shortened", "BSD-4-Clause-UC", "BSD-4.3RENO", "BSD-4.3TAHOE", "BSD-Advertising-Acknowledgement", "BSD-Attribution-HPND-disclaimer", "BSD-Inferno-Nettverk", "BSD-Protection", "BSD-Source-Code", "BSD-Source-beginning-file", "BSD-Systemics", "BSD-Systemics-W3Works", "BSL-1.0", "BUSL-1.1", "Baekmuk", "Bahyph", "Barr", "Beerware", "Bison-exception-1.24", "Bison-exception-2.2", "BitTorrent-1.0", "BitTorrent-1.1", "Bitstream-Charter", "Bitstream-Vera", "BlueOak-1.0.0", "Boehm-GC", "Boehm-GC-without-fee", "Bootloader-exception", "Borceux", "Brian-Gladman-2-Clause", "Brian-Gladman-3-Clause", "C-UDA-1.0", "CAL-1.0", "CAL-1.0-Combined-Work-Exception", "CATOSL-1.1", "CC-BY-1.0", "CC-BY-2.0", "CC-BY-2.5", "CC-BY-2.5-AU", "CC-BY-3.0", "CC-BY-3.0-AT", "CC-BY-3.0-AU", "CC-BY-3.0-DE", "CC-BY-3.0-IGO", "CC-BY-3.0-NL", "CC-BY-3.0-US", "CC-BY-4.0", "CC-BY-NC-1.0", "CC-BY-NC-2.0", "CC-BY-NC-2.5", "CC-BY-NC-3.0", "CC-BY-NC-3.0-DE", "CC-BY-NC-4.0", "CC-BY-NC-ND-1.0", "CC-BY-NC-ND-2.0", "CC-BY-NC-ND-2.5", "CC-BY-NC-ND-3.0", "CC-BY-NC-ND-3.0-DE", "CC-BY-NC-ND-3.0-IGO", "CC-BY-NC-ND-4.0", "CC-BY-NC-SA-1.0", "CC-BY-NC-SA-2.0", "CC-BY-NC-SA-2.0-DE", "CC-BY-NC-SA-2.0-FR", "CC-BY-NC-SA-2.0-UK", "CC-BY-NC-SA-2.5", "CC-BY-NC-SA-3.0", "CC-BY-NC-SA-3.0-DE", "CC-BY-NC-SA-3.0-IGO", "CC-BY-NC-SA-4.0", "CC-BY-ND-1.0", "CC-BY-ND-2.0", "CC-BY-ND-2.5", "CC-BY-ND-3.0", "CC-BY-ND-3.0-DE", "CC-BY-ND-4.0", "CC-BY-SA-1.0", "CC-BY-SA-2.0", "CC-BY-SA-2.0-UK", "CC-BY-SA-2.1-JP", "CC-BY-SA-2.5", "CC-BY-SA-3.0", "CC-BY-SA-3.0-AT", "CC-BY-SA-3.0-DE", "CC-BY-SA-3.0-IGO", "CC-BY-SA-4.0", "CC-PDDC", "CC-PDM-1.0", "CC-SA-1.0", "CC0-1.0", "CDDL-1.0", "CDDL-1.1", "CDL-1.0", "CDLA-Permissive-1.0", "CDLA-Permissive-2.0", "CDLA-Sharing-1.0", "CECILL-1.0", "CECILL-1.1", "CECILL-2.0", "CECILL-2.1", "CECILL-B", "CECILL-C", "CERN-OHL-1.1", "CERN-OHL-1.2", "CERN-OHL-P-2.0", "CERN-OHL-S-2.0", "CERN-OHL-W-2.0", "CFITSIO", "CGAL-linking-exception", "CLISP-exception-2.0", "CMU-Mach", "CMU-Mach-nodoc", "CNRI-Jython", "CNRI-Python", "CNRI-Python-GPL-Compatible", "COIL-1.0", "CPAL-1.0", "CPL-1.0", "CPOL-1.02", "CUA-OPL-1.0", "Caldera", "Caldera-no-preamble", "Catharon", "ClArtistic", "Classpath-exception-2.0", "Clips", "Community-Spec-1.0", "Condor-1.1", "Cornell-Lossless-JPEG", "Cronyx", "Crossword", "CrystalStacker", "Cube", "D-FSL-1.0", "DEC-3-Clause", "DL-DE-BY-2.0", "DL-DE-ZERO-2.0", "DOC", "DRL-1.0", "DRL-1.1", "DSDP", "DigiRule-FOSS-exception", "DocBook-Schema", "DocBook-Stylesheet", "DocBook-XML", "Dotseqn", "ECL-1.0", "ECL-2.0", "EFL-1.0", "EFL-2.0", "EPICS", "EPL-1.0", "EPL-2.0", "EUDatagrid", "EUPL-1.0", "EUPL-1.1", "EUPL-1.2", "Elastic-2.0", "Entessa", "ErlPL-1.1", "Eurosym", "FBM", "FDK-AAC", "FLTK-exception", "FSFAP", "FSFAP-no-warranty-disclaimer", "FSFUL", "FSFULLR", "FSFULLRWD", "FTL", "Fair", "Fawkes-Runtime-exception", "Ferguson-Twofish", "Font-exception-2.0", "Frameworx-1.0", "FreeBSD-DOC", "FreeImage", "Furuseth", "GCC-exception-2.0", "GCC-exception-2.0-note", "GCC-exception-3.1", "GCR-docs", "GD", "GFDL-1.1-invariants-only", "GFDL-1.1-invariants-or-later", "GFDL-1.1-no-invariants-only", "GFDL-1.1-no-invariants-or-later", "GFDL-1.1-only", "GFDL-1.1-or-later", "GFDL-1.2-invariants-only", "GFDL-1.2-invariants-or-later", "GFDL-1.2-no-invariants-only", "GFDL-1.2-no-invariants-or-later", "GFDL-1.2-only", "GFDL-1.2-or-later", "GFDL-1.3-invariants-only", "GFDL-1.3-invariants-or-later", "GFDL-1.3-no-invariants-only", "GFDL-1.3-no-invariants-or-later", "GFDL-1.3-only", "GFDL-1.3-or-later", "GL2PS", "GLWTPL", "GNAT-exception", "GNOME-examples-exception", "GNU-compiler-exception", "GPL-1.0-only", "GPL-1.0-or-later", "GPL-2.0-only", "GPL-2.0-or-later", "GPL-3.0-389-ds-base-exception", "GPL-3.0-interface-exception", "GPL-3.0-linking-exception", "GPL-3.0-linking-source-exception", "GPL-3.0-only", "GPL-3.0-or-later", "GPL-CC-1.0", "GStreamer-exception-2005", "GStreamer-exception-2008", "Giftware", "Glide", "Glulxe", "Gmsh-exception", "Graphics-Gems", "Gutmann", "HIDAPI", "HP-1986", "HP-1989", "HPND", "HPND-DEC", "HPND-Fenneberg-Livingston", "HPND-INRIA-IMAG", "HPND-Intel", "HPND-Kevlin-Henney", "HPND-MIT-disclaimer", "HPND-Markus-Kuhn", "HPND-Netrek", "HPND-Pbmplus", "HPND-UC", "HPND-UC-export-US", "HPND-doc", "HPND-doc-sell", "HPND-export-US", "HPND-export-US-acknowledgement", "HPND-export-US-modify", "HPND-export2-US", "HPND-merchantability-variant", "HPND-sell-MIT-disclaimer-xserver", "HPND-sell-regexpr", "HPND-sell-variant", "HPND-sell-variant-MIT-disclaimer", "HPND-sell-variant-MIT-disclaimer-rev", "HTMLTIDY", "HaskellReport", "Hippocratic-2.1", "IBM-pibs", "ICU", "IEC-Code-Components-EULA", "IJG", "IJG-short", "IPA", "IPL-1.0", "ISC", "ISC-Veillard", "ImageMagick", "Imlib2", "Independent-modules-exception", "Info-ZIP", "Inner-Net-2.0", "InnoSetup", "Intel", "Intel-ACPI", "Interbase-1.0", "JPL-image", "JPNIC", "JSON", "Jam", "JasPer-2.0", "Kastrup", "Kazlib", "KiCad-libraries-exception", "Knuth-CTAN", "LAL-1.2", "LAL-1.3", "LGPL-2.0-only", "LGPL-2.0-or-later", "LGPL-2.1-only", "LGPL-2.1-or-later", "LGPL-3.0-linking-exception", "LGPL-3.0-only", "LGPL-3.0-or-later", "LGPLLR", "LLGPL", "LLVM-exception", "LOOP", "LPD-document", "LPL-1.0", "LPL-1.02", "LPPL-1.0", "LPPL-1.1", "LPPL-1.2", "LPPL-1.3a", "LPPL-1.3c", "LZMA-SDK-9.11-to-9.20", "LZMA-SDK-9.22", "LZMA-exception", "Latex2e", "Latex2e-translated-notice", "Leptonica", "LiLiQ-P-1.1", "LiLiQ-R-1.1", "LiLiQ-Rplus-1.1", "Libpng", "Libtool-exception", "Linux-OpenIB", "Linux-man-pages-1-para", "Linux-man-pages-copyleft", "Linux-man-pages-copyleft-2-para", "Linux-man-pages-copyleft-var", "Linux-syscall-note", "Lucida-Bitmap-Fonts", "MIPS", "MIT", "MIT-0", "MIT-CMU", "MIT-Click", "MIT-Festival", "MIT-Khronos-old", "MIT-Modern-Variant", "MIT-Wu", "MIT-advertising", "MIT-enna", "MIT-feh", "MIT-open-group", "MIT-testregex", "MITNFA", "MMIXware", "MPEG-SSG", "MPL-1.0", "MPL-1.1", "MPL-2.0", "MPL-2.0-no-copyleft-exception", "MS-LPL", "MS-PL", "MS-RL", "MTLL", "Mackerras-3-Clause", "Mackerras-3-Clause-acknowledgment", "MakeIndex", "Martin-Birgmeier", "McPhee-slideshow", "Minpack", "MirOS", "Motosoto", "MulanPSL-1.0", "MulanPSL-2.0", "Multics", "Mup", "NAIST-2003", "NASA-1.3", "NBPL-1.0", "NCBI-PD", "NCGL-UK-2.0", "NCL", "NCSA", "NGPL", "NICTA-1.0", "NIST-PD", "NIST-PD-fallback", "NIST-Software", "NLOD-1.0", "NLOD-2.0", "NLPL", "NOSL", "NPL-1.0", "NPL-1.1", "NPOSL-3.0", "NRL", "NTP", "NTP-0", "Naumen", "NetCDF", "Newsletr", "Nokia", "Noweb", "O-UDA-1.0", "OAR", "OCCT-PL", "OCCT-exception-1.0", "OCLC-2.0", "OCaml-LGPL-linking-exception", "ODC-By-1.0", "ODbL-1.0", "OFFIS", "OFL-1.0", "OFL-1.0-RFN", "OFL-1.0-no-RFN", "OFL-1.1", "OFL-1.1-RFN", "OFL-1.1-no-RFN", "OGC-1.0", "OGDL-Taiwan-1.0", "OGL-Canada-2.0", "OGL-UK-1.0", "OGL-UK-2.0", "OGL-UK-3.0", "OGTSL", "OLDAP-1.1", "OLDAP-1.2", "OLDAP-1.3", "OLDAP-1.4", "OLDAP-2.0", "OLDAP-2.0.1", "OLDAP-2.1", "OLDAP-2.2", "OLDAP-2.2.1", "OLDAP-2.2.2", "OLDAP-2.3", "OLDAP-2.4", "OLDAP-2.5", "OLDAP-2.6", "OLDAP-2.7", "OLDAP-2.8", "OLFL-1.3", "OML", "OPL-1.0", "OPL-UK-3.0", "OPUBL-1.0", "OSET-PL-2.1", "OSL-1.0", "OSL-1.1", "OSL-2.0", "OSL-2.1", "OSL-3.0", "OpenJDK-assembly-exception-1.0", "OpenPBS-2.3", "OpenSSL", "OpenSSL-standalone", "OpenVision", "PADL", "PCRE2-exception", "PDDL-1.0", "PHP-3.0", "PHP-3.01", "PPL", "PS-or-PDF-font-exception-20170817", "PSF-2.0", "Parity-6.0.0", "Parity-7.0.0", "Pixar", "Plexus", "PolyForm-Noncommercial-1.0.0", "PolyForm-Small-Business-1.0.0", "PostgreSQL", "Python-2.0", "Python-2.0.1", "QPL-1.0", "QPL-1.0-INRIA-2004", "QPL-1.0-INRIA-2004-exception", "Qhull", "Qt-GPL-exception-1.0", "Qt-LGPL-exception-1.1", "Qwt-exception-1.0", "RHeCos-1.1", "RPL-1.1", "RPL-1.5", "RPSL-1.0", "RRDtool-FLOSS-exception-2.0", "RSA-MD", "RSCPL", "Rdisc", "Ruby", "Ruby-pty", "SANE-exception", "SAX-PD", "SAX-PD-2.0", "SCEA", "SGI-B-1.0", "SGI-B-1.1", "SGI-B-2.0", "SGI-OpenGL", "SGP4", "SHL-0.5", "SHL-0.51", "SHL-2.0", "SHL-2.1", "SISSL", "SISSL-1.2", "SL", "SMAIL-GPL", "SMLNJ", "SMPPL", "SNIA", "SPL-1.0", "SSH-OpenSSH", "SSH-short", "SSLeay-standalone", "SSPL-1.0", "SWI-exception", "SWL", "Saxpath", "SchemeReport", "Sendmail", "Sendmail-8.23", "Sendmail-Open-Source-1.1", "SimPL-2.0", "Sleepycat", "Soundex", "Spencer-86", "Spencer-94", "Spencer-99", "SugarCRM-1.1.3", "Sun-PPP", "Sun-PPP-2000", "SunPro", "Swift-exception", "Symlinks", "TAPR-OHL-1.0", "TCL", "TCP-wrappers", "TGPPL-1.0", "TMate", "TORQUE-1.1", "TOSL", "TPDL", "TPL-1.0", "TTWL", "TTYP0", "TU-Berlin-1.0", "TU-Berlin-2.0", "TermReadKey", "Texinfo-exception", "ThirdEye", "TrustedQSL", "UBDL-exception", "UCAR", "UCL-1.0", "UMich-Merit", "UPL-1.0", "URT-RLE", "Ubuntu-font-1.0", "Unicode-3.0", "Unicode-DFS-2015", "Unicode-DFS-2016", "Unicode-TOU", "Universal-FOSS-exception-1.0", "UnixCrypt", "Unlicense", "VOSTROM", "VSL-1.0", "Vim", "W3C", "W3C-19980720", "W3C-20150513", "WTFPL", "Watcom-1.0", "Widget-Workshop", "Wsuipa", "WxWindows-exception-3.1", "X11", "X11-distribute-modifications-variant", "X11-swapped", "XFree86-1.1", "XSkat", "Xdebug-1.03", "Xerox", "Xfig", "Xnet", "YPL-1.0", "YPL-1.1", "ZPL-1.1", "ZPL-2.0", "ZPL-2.1", "Zed", "Zeeff", "Zend-2.0", "Zimbra-1.3", "Zimbra-1.4", "Zlib", "any-OSI", "any-OSI-perl-modules", "bcrypt-Solar-Designer", "blessing", "bzip2-1.0.6", "check-cvs", "checkmk", "copyleft-next-0.3.0", "copyleft-next-0.3.1", "cryptsetup-OpenSSL-exception", "curl", "cve-tou", "diffmark", "dtoa", "dvipdfm", "eCos-exception-2.0", "eGenix", "erlang-otp-linking-exception", "etalab-2.0", "fmt-exception", "freertos-exception-2.0", "fwlw", "gSOAP-1.3b", "generic-xts", "gnu-javamail-exception", "gnuplot", "gtkbook", "harbour-exception", "hdparm", "i2p-gpl-java-exception", "iMatix", "libpng-2.0", "libpri-OpenH323-exception", "libselinux-1.0", "libtiff", "libutil-David-Nugent", "lsof", "magaz", "mailprio", "metamail", "mif-exception", "mpi-permissive", "mpich2", "mplus", "mxml-exception", "openvpn-openssl-exception", "pkgconf", "pnmstitch", "psfrag", "psutils", "python-ldap", "radvd", "romic-exception", "snprintf", "softSurfer", "ssh-keyscan", "stunnel-exception", "swrule", "threeparttable", "u-boot-exception-2.0", "ulem", "vsftpd-openssl-exception", "w3m", "wwl", "x11vnc-openssl-exception", "xinetd", "xkeyboard-config-Zinoviev", "xlock", "xpp", "xzoom", "zlib-acknowledgement" ], "title": "SPDXLicenseEnum" } }, "$id": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/galaxy.json", "$schema": "http://json-schema.org/draft-07/schema", "additionalProperties": false, "examples": ["galaxy.yml"], "markdownDescription": "https://docs.ansible.com/ansible/latest/dev_guide/collections_galaxy_meta.html", "properties": { "authors": { "items": { "type": "string" }, "title": "Authors", "type": "array" }, "build_ignore": { "items": { "type": "string" }, "title": "Build Ignore", "type": "array" }, "dependencies": { "additionalProperties": { "$ref": "#/$defs/CollectionVersionConstraintModel" }, "title": "Dependencies", "type": "object" }, "description": { "title": "Description", "type": "string" }, "documentation": { "title": "Documentation", "type": "string" }, "homepage": { "title": "Homepage", "type": "string" }, "issues": { "title": "Issues", "type": "string" }, "license": { "items": { "$ref": "#/$defs/SPDXLicense" }, "title": "License", "type": "array" }, "license_file": { "title": "License File", "type": "string" }, "manifest": { "additionalProperties": false, "markdownDescription": "A dict controlling use of manifest directives used in building the collection artifact.\nThe key directives is a list of MANIFEST.in style directives\nThe key omit_default_directives is a boolean that controls whether the default directives are used.\nMutually exclusive with build_ignore.", "properties": { "directives": { "items": { "type": "string" }, "title": "Directives", "type": "array" }, "omit_default_directives": { "title": "Omit Default Directives", "type": "boolean" } }, "title": "Manifest", "type": "object" }, "name": { "minLength": 2, "pattern": "^[a-z][a-z0-9_]+$", "title": "Name", "type": "string" }, "namespace": { "minLength": 2, "pattern": "^[a-z][a-z0-9_]+$", "title": "Namespace", "type": "string" }, "readme": { "markdownDescription": "The path to the Markdown (.md) readme file. This path is relative to the root of the collection.\nSee [metadata structure](https://docs.ansible.com/ansible/latest/dev_guide/collections_galaxy_meta.html)", "title": "Readme", "type": "string" }, "repository": { "title": "Repository", "type": "string" }, "tags": { "items": { "type": "string" }, "title": "Tags", "type": "array" }, "version": { "markdownDescription": "Version must use [SemVer](https://semver.org/) format, which is more restrictive than [PEP-440](https://peps.python.org/pep-0440/). For example `1.0.0-rc1` is valid but `1.0.0rc` is not.", "minLength": 5, "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$", "title": "Version", "type": "string" } }, "required": [ "namespace", "name", "version", "readme", "authors", "description", "repository" ], "title": "Ansible galaxy.yml Schema", "type": "object" } ����������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/inventory.json���������������������������������0000664�0000000�0000000�00000003325�14773473560�0025531�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "$defs": { "group": { "properties": { "children": { "patternProperties": { "[a-zA-Z-_0-9]": { "$ref": "#/$defs/group" } } }, "hosts": { "patternProperties": { "[a-zA-Z.-_0-9]": { "type": ["object", "null"] } }, "type": ["object", "string"] }, "vars": { "type": "object" } }, "type": ["object", "null"] }, "special-group": { "additionalProperties": false, "properties": { "children": { "type": ["object", "null"] }, "groups": { "type": ["object", "null"] }, "hosts": { "type": ["object", "null"] }, "vars": { "type": ["object", "null"] } }, "type": "object" } }, "$id": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/inventory.json", "$schema": "http://json-schema.org/draft-07/schema", "additionalProperties": true, "description": "See https://docs.ansible.com/ansible/latest/inventory_guide/intro_inventory.html", "examples": [ "inventory.yaml", "inventory.yml", "inventory/*.yml", "inventory/*.yaml" ], "markdownDescription": "All keys at top levels are groups with `all` and `ungrouped` having a special meaning.\n\nSee [How to build your inventory](https://docs.ansible.com/ansible/latest/inventory_guide/intro_inventory.html)", "properties": { "all": { "$ref": "#/$defs/special-group" }, "ungrouped": { "$ref": "#/$defs/group" } }, "title": "Ansible Inventory Schema", "type": "object" } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/main.py����������������������������������������0000664�0000000�0000000�00000010334�14773473560�0024075�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Module containing cached JSON schemas.""" from __future__ import annotations import json import logging import re from typing import TYPE_CHECKING, Any import yaml from jsonschema.exceptions import ValidationError from jsonschema.validators import validator_for from ansiblelint.loaders import yaml_load_safe from ansiblelint.schemas.__main__ import JSON_SCHEMAS, _schema_cache _logger = logging.getLogger(__package__) if TYPE_CHECKING: from collections.abc import Iterator from ansiblelint.file_utils import Lintable RE_MD_URLS = re.compile( r"\[.{0,256}?\]\((?P<url>https?://[^\s]+)\)|(?P<url2>https?://[^\s]+)" ) RE_URLS_AND_MD_URLS = re.compile(r"\[.{0,256}?\]\((https?://[^\s]+)\)|https?://[^\s]+") def find_best_deep_match( errors: ValidationError, ) -> ValidationError: """Return the deepest schema validation error.""" def iter_validation_error( err: ValidationError, ) -> Iterator[ValidationError]: if err.context: for e in err.context: yield e yield from iter_validation_error(e) return max(iter_validation_error(errors), key=_deep_match_relevance) def validate_file_schema(file: Lintable) -> list[str]: """Return list of JSON validation errors found.""" schema: dict[Any, Any] = {} if file.kind not in JSON_SCHEMAS: return [f"Unable to find JSON Schema '{file.kind}' for '{file.path}' file."] try: # convert yaml to json (keys are converted to strings) yaml_data = yaml_load_safe(file.content) json_data = json.loads(json.dumps(yaml_data)) schema = _schema_cache[file.kind] validator = validator_for(schema) v = validator(schema) try: error = next(v.iter_errors(json_data)) except StopIteration: return [] if error.context: error = find_best_deep_match(error) # determine if we want to use our own messages embedded into schemas inside title/markdownDescription fields if not hasattr(error, "schema") or not isinstance( error.schema, dict ): # pragma: no cover msg = "error object does not have schema attribute" raise TypeError(msg) if "not" in error.schema and len(error.schema["not"]) == 0: message = error.schema["title"] schema = error.schema else: message = f"{error.json_path} {error.message}" documentation_url = "" for json_schema in (error.schema, schema): for k in ("description", "markdownDescription"): if k in json_schema: # Find standalone URLs and also markdown urls. match = RE_MD_URLS.search( json_schema[k], ) if match: documentation_url = next( x for x in match.groups() if x is not None ) break if documentation_url: break if documentation_url: if not message.endswith("."): message += "." message += f" See {documentation_url}" except yaml.constructor.ConstructorError as exc: return [f"Failed to load YAML file '{file.path}': {exc.problem}"] except ValidationError as exc: # pragma: no cover message = exc.message documentation_url = "" for k in ("description", "markdownDescription"): if k in schema: # Find standalone URLs and also markdown urls. match = RE_URLS_AND_MD_URLS.search( schema[k], ) if match: documentation_url = match.groups()[0] break if documentation_url: if not message.endswith("."): message += "." message += f" See {documentation_url}" return [message] return [message] def _deep_match_relevance(error: ValidationError) -> tuple[bool | int, ...]: validator = error.validator return ( validator not in ("anyOf", "oneOf"), # type: ignore[comparison-overlap] len(error.absolute_path), -len(error.path), ) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/meta-runtime.json������������������������������0000664�0000000�0000000�00000005576�14773473560�0026115�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "$defs": { "ActionGroup": { "items": { "oneOf": [ { "type": "string" }, { "$ref": "#/$defs/Metadata" } ] }, "type": "array" }, "Metadata": { "properties": { "metadata": { "properties": { "extend_group": { "items": { "type": "string" }, "type": "array" } }, "type": "object" } }, "type": "object" }, "Redirect": { "properties": { "redirect": { "type": "string" } }, "type": "object" } }, "$id": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/meta-runtime.json", "$schema": "http://json-schema.org/draft-07/schema", "additionalProperties": false, "description": "See https://docs.ansible.com/ansible/devel/dev_guide/developing_collections_structure.html#meta-directory", "examples": ["**/meta/runtime.yml"], "properties": { "action_groups": { "additionalProperties": { "$ref": "#/$defs/ActionGroup" }, "description": "A mapping of groups and the list of action plugin and module names they contain. They may also have a special ‘metadata’ dictionary in the list, which can be used to include actions from other groups.", "title": "Action Groups", "type": "object" }, "import_redirection": { "additionalProperties": { "$ref": "#/$defs/Redirect" }, "description": "A mapping of names for Python import statements and their redirected locations.", "title": "Import Redirection", "type": "object" }, "plugin_routing": { "markdownDescription": "Content in a collection that Ansible needs to load from another location or that has been deprecated/removed. The top level keys of plugin_routing are types of plugins, with individual plugin names as subkeys. To define a new location for a plugin, set the redirect field to another name. To deprecate a plugin, use the deprecation field to provide a custom warning message and the removal version or date. If the plugin has been renamed or moved to a new location, the redirect field should also be provided. If a plugin is being removed entirely, tombstone can be used for the fatal error message and removal version or date.", "properties": { "inventory": {}, "module_utils": {}, "modules": {} }, "title": "Plugin Routing", "type": "object" }, "requires_ansible": { "examples": [">=2.10,<2.11"], "pattern": "^[^\\s]*$", "title": "The version of Ansible Core (ansible-core) required to use the collection. Multiple versions can be separated with a comma.", "type": "string" } }, "title": "Ansible Meta Runtime Schema", "type": "object" } ����������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/meta.json��������������������������������������0000664�0000000�0000000�00000107642�14773473560�0024431�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "$defs": { "AIXPlatformModel": { "properties": { "name": { "const": "AIX", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["6.1", "7.1", "7.2", "all"], "type": "string" }, "type": "array" } }, "title": "AIXPlatformModel", "type": "object" }, "AlpinePlatformModel": { "properties": { "name": { "const": "Alpine", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["all"], "type": "string" }, "type": "array" } }, "title": "AlpinePlatformModel", "type": "object" }, "AmazonLinuxPlatformModel": { "properties": { "name": { "const": "Amazon Linux", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["all", "1", "2", "2023"], "type": "string" }, "type": "array" } }, "title": "Amazon Linux 2PlatformModel", "type": "object" }, "AmazonPlatformModel": { "properties": { "name": { "const": "Amazon", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": [ "2013.03", "2013.09", "2014.03", "2014.09", "2015.03", "2015.09", "2016.03", "2016.09", "2017.03", "2017.09", "2017.12", "2018.03", "Candidate", "all" ], "type": "string" }, "type": "array" } }, "title": "AmazonPlatformModel", "type": "object" }, "ArchLinuxPlatformModel": { "properties": { "name": { "const": "ArchLinux", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["all"], "type": "string" }, "type": "array" } }, "title": "ArchLinuxPlatformModel", "type": "object" }, "AstraLinuxPlatformModel": { "properties": { "name": { "const": "Astra Linux", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["1.8", "1.7", "1.6", "2.12", "all"], "type": "string" }, "type": "array" } }, "title": "AstraLinuxPlatformModel", "type": "object" }, "ClearLinuxPlatformModel": { "properties": { "name": { "const": "ClearLinux", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["all"], "type": "string" }, "type": "array" } }, "title": "ClearLinuxPlatformModel", "type": "object" }, "CumulusPlatformModel": { "properties": { "name": { "const": "Cumulus", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["2.5", "3.0", "3.1", "3.2", "3.3", "3.4", "3.5", "all"], "type": "string" }, "type": "array" } }, "title": "CumulusPlatformModel", "type": "object" }, "DebianPlatformModel": { "properties": { "name": { "const": "Debian", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": [ "bookworm", "bullseye", "buster", "etch", "jessie", "lenny", "sid", "squeeze", "stretch", "trixie", "wheezy", "all" ], "type": "string" }, "type": "array" } }, "title": "DebianPlatformModel", "type": "object" }, "DellOSPlatformModel": { "properties": { "name": { "const": "DellOS", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["10", "6", "9", "all"], "type": "string" }, "type": "array" } }, "title": "DellOSPlatformModel", "type": "object" }, "DependencyModel": { "additionalProperties": true, "anyOf": [ { "required": ["role"] }, { "required": ["src"] }, { "required": ["name"] } ], "markdownDescription": "See https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html#role-dependencies and https://github.com/ansible/ansible/blob/devel/lib/ansible/playbook/role/metadata.py#L79\n\nOther keys are treated as role [parameters](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#passing-different-parameters).", "properties": { "become": { "title": "Become", "type": "boolean" }, "name": { "title": "Name", "type": "string" }, "role": { "title": "Role", "type": "string" }, "scm": { "enum": ["hg", "git"], "title": "Scm", "type": "string" }, "src": { "title": "Src", "type": "string" }, "tags": { "items": { "type": "string" }, "title": "Tags", "type": ["array", "string"] }, "vars": { "title": "Vars", "type": "object" }, "version": { "title": "Version", "type": "string" }, "when": { "$ref": "#/$defs/complex_conditional", "title": "When" } }, "title": "Dependency entry", "type": "object" }, "DevuanPlatformModel": { "properties": { "name": { "const": "Devuan", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": [ "ascii", "beowulf", "chimaera", "daedalus", "jessie", "all" ], "type": "string" }, "type": "array" } }, "title": "DevuanPlatformModel", "type": "object" }, "DragonFlyBSDPlatformModel": { "properties": { "name": { "const": "DragonFlyBSD", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["5.2", "5.4", "5.6", "5.8", "6.0", "6.2", "6.4", "all"], "type": "string" }, "type": "array" } }, "title": "DragonFlyBSDPlatformModel", "type": "object" }, "ELPlatformModel": { "properties": { "name": { "const": "EL", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["5", "6", "7", "8", "9", "10", "all"], "type": "string" }, "type": "array" } }, "title": "ELPlatformModel", "type": "object" }, "FedoraPlatformModel": { "properties": { "name": { "const": "Fedora", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": [ "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", "all" ], "type": "string" }, "type": "array" } }, "title": "FedoraPlatformModel", "type": "object" }, "FreeBSDPlatformModel": { "properties": { "name": { "const": "FreeBSD", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": [ "10.0", "10.1", "10.2", "10.3", "10.4", "11.0", "11.1", "11.2", "11.3", "11.4", "12.0", "12.1", "12.2", "13.0", "13.1", "13.2", "14.0", "8.0", "8.1", "8.2", "8.3", "8.4", "9.0", "9.1", "9.2", "9.3", "all" ], "type": "string" }, "type": "array" } }, "title": "FreeBSDPlatformModel", "type": "object" }, "GalaxyInfoModel": { "additionalProperties": false, "allOf": [ { "if": { "properties": { "standalone": { "const": true } } }, "then": { "$comment": "Standalone role, so we require several fields.", "required": [ "author", "description", "license", "min_ansible_version" ] } }, { "if": { "properties": { "standalone": { "const": false } } }, "then": { "$comment": "Collection roles do not use most galaxy fields.", "not": { "required": [ "cloud_platforms", "galaxy_tags", "min_ansible_version", "namespace", "platforms", "role_name", "video_links" ] }, "required": ["description"] } } ], "else": { "$comment": "If standalone is false, then we have a collection role and only description is required", "required": ["description"] }, "properties": { "author": { "title": "Author", "type": "string" }, "cloud_platforms": { "markdownDescription": "Only valid for old standalone roles." }, "company": { "title": "Company", "type": "string" }, "description": { "title": "Description", "type": "string" }, "galaxy_tags": { "items": { "type": "string" }, "markdownDescription": "See https://galaxy.ansible.com/docs/contributing/creating_role.html", "title": "Galaxy Tags", "type": "array" }, "github_branch": { "markdownDescription": "Optionally specify the branch Galaxy will use when accessing the GitHub repo for this role", "title": "GitHub Branch", "type": "string" }, "issue_tracker_url": { "title": "Issue Tracker Url", "type": "string" }, "license": { "title": "License", "type": "string" }, "min_ansible_container_version": { "title": "Min Ansible Container Version", "type": "string" }, "min_ansible_version": { "title": "Min Ansible Version", "type": "string" }, "namespace": { "markdownDescription": "Used by molecule and ansible-lint to compute FQRN for roles outside collections", "minLength": 2, "pattern": "^[a-z][a-z0-9_-]+$", "title": "Namespace Name", "type": "string" }, "platforms": { "$ref": "#/$defs/platforms" }, "role_name": { "minLength": 2, "pattern": "^[a-z][a-z0-9_]+$", "title": "Role Name", "type": "string" }, "standalone": { "description": "Set to true for old standalone roles, or false for new collection roles.", "title": "Standalone", "type": "boolean" }, "video_links": { "markdownDescription": "Only valid for old standalone roles.", "type": "array" } }, "title": "GalaxyInfoModel", "type": "object" }, "GenericBSDPlatformModel": { "properties": { "name": { "const": "GenericBSD", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["all"], "type": "string" }, "type": "array" } }, "title": "GenericBSDPlatformModel", "type": "object" }, "GenericLinuxPlatformModel": { "properties": { "name": { "const": "GenericLinux", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["all"], "type": "string" }, "type": "array" } }, "title": "GenericLinuxPlatformModel", "type": "object" }, "GenericUNIXPlatformModel": { "properties": { "name": { "const": "GenericUNIX", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["all"], "type": "string" }, "type": "array" } }, "title": "GenericUNIXPlatformModel", "type": "object" }, "GentooPlatformModel": { "properties": { "name": { "const": "Gentoo", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["all"], "type": "string" }, "type": "array" } }, "title": "GentooPlatformModel", "type": "object" }, "HardenedBSDPlatformModel": { "properties": { "name": { "const": "HardenedBSD", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["10", "11", "all"], "type": "string" }, "type": "array" } }, "title": "HardenedBSDPlatformModel", "type": "object" }, "IOSPlatformModel": { "properties": { "name": { "const": "IOS", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["all"], "type": "string" }, "type": "array" } }, "title": "IOSPlatformModel", "type": "object" }, "JunosPlatformModel": { "properties": { "name": { "const": "Junos", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["all"], "type": "string" }, "type": "array" } }, "title": "JunosPlatformModel", "type": "object" }, "KaliPlatformModel": { "properties": { "name": { "const": "Kali", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": [ "2.0", "2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "all" ], "type": "string" }, "type": "array" } }, "title": "KaliPlatformModel", "type": "object" }, "MacOSXPlatformModel": { "properties": { "name": { "const": "MacOSX", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": [ "10.10", "10.11", "10.12", "10.13", "10.14", "10.15", "10.7", "10.8", "10.9", "all" ], "type": "string" }, "type": "array" } }, "title": "MacOSXPlatformModel", "type": "object" }, "MageiaPlatformModel": { "properties": { "name": { "const": "Mageia", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["7", "8", "all"], "type": "string" }, "type": "array" } }, "title": "MageiaPlatformModel", "type": "object" }, "NXOSPlatformModel": { "properties": { "name": { "const": "NXOS", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["all"], "type": "string" }, "type": "array" } }, "title": "NXOSPlatformModel", "type": "object" }, "NetBSDPlatformModel": { "properties": { "name": { "const": "NetBSD", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": [ "8.0", "8.1", "8.2", "9.0", "9.1", "9.2", "9.3", "10.0", "all" ], "type": "string" }, "type": "array" } }, "title": "NetBSDPlatformModel", "type": "object" }, "OpenBSDPlatformModel": { "properties": { "name": { "const": "OpenBSD", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": [ "5.6", "5.7", "5.8", "5.9", "6.0", "6.1", "6.2", "6.3", "6.4", "6.5", "6.6", "6.7", "6.8", "6.9", "7.0", "7.1", "7.2", "7.3", "all" ], "type": "string" }, "type": "array" } }, "title": "OpenBSDPlatformModel", "type": "object" }, "OpenWrtPlatformModel": { "properties": { "name": { "const": "OpenWrt", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": [ "17.01", "18.06", "19.07", "21.02", "22.03", "23.05", "all" ], "type": "string" }, "type": "array" } }, "title": "OpenWrtPlatformModel", "type": "object" }, "OracleLinuxPlatformModel": { "properties": { "name": { "const": "OracleLinux", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": [ "7.0", "7.1", "7.2", "7.3", "7.4", "7.5", "7.6", "7.7", "7.8", "7.9", "8.0", "8.1", "8.2", "8.3", "8.4", "8.5", "8.6", "8.7", "8.8", "8.9", "8.10", "9.0", "9.1", "9.2", "9.3", "9.4", "all" ], "type": "string" }, "type": "array" } }, "title": "OracleLinuxPlatformModel", "type": "object" }, "PAN-OSPlatformModel": { "properties": { "name": { "const": "PAN-OS", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["7.1", "8.0", "8.1", "9.0", "all"], "type": "string" }, "type": "array" } }, "title": "PAN-OSPlatformModel", "type": "object" }, "RockyLinuxPlatformModel": { "properties": { "name": { "const": "Rocky", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": [ "8.0", "8.1", "8.2", "8.3", "8.4", "8.5", "8.6", "8.7", "8.8", "9.0", "9.1", "9.2", "all" ], "type": "string" }, "type": "array" } }, "title": "RockyLinuxPlatformModel", "type": "object" }, "SLESPlatformModel": { "properties": { "name": { "const": "SLES", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": [ "10SP3", "10SP4", "11", "11SP1", "11SP2", "11SP3", "11SP4", "12", "12SP1", "12SP2", "12SP3", "12SP4", "12SP5", "15", "15SP1", "15SP2", "15SP3", "15SP4", "15SP5", "all" ], "type": "string" }, "type": "array" } }, "title": "SLESPlatformModel", "type": "object" }, "SmartOSPlatformModel": { "properties": { "name": { "const": "SmartOS", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["all"], "type": "string" }, "type": "array" } }, "title": "SmartOSPlatformModel", "type": "object" }, "SolarisPlatformModel": { "properties": { "name": { "const": "Solaris", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["10", "11.0", "11.1", "11.2", "11.3", "11.4", "all"], "type": "string" }, "type": "array" } }, "title": "SolarisPlatformModel", "type": "object" }, "SynologyPlatformModel": { "properties": { "name": { "const": "Synology", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["6.0", "6.1", "6.2", "7.0", "all"], "type": "string" }, "type": "array" } }, "title": "SynologyPlatformModel", "type": "object" }, "TMOSPlatformModel": { "properties": { "name": { "const": "TMOS", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["12.1", "13.0", "13.1", "14.0", "all"], "type": "string" }, "type": "array" } }, "title": "TMOSPlatformModel", "type": "object" }, "UbuntuPlatformModel": { "properties": { "name": { "const": "Ubuntu", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": [ "artful", "bionic", "cosmic", "disco", "eoan", "focal", "groovy", "hirsute", "impish", "jammy", "kinetic", "lucid", "lunar", "mantic", "noble", "maverick", "natty", "oneiric", "precise", "quantal", "raring", "saucy", "trusty", "utopic", "vivid", "wily", "xenial", "yakkety", "zesty", "all" ], "type": "string" }, "type": "array" } }, "title": "UbuntuPlatformModel", "type": "object" }, "Void_LinuxPlatformModel": { "properties": { "name": { "const": "Void Linux", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["all"], "type": "string" }, "type": "array" } }, "title": "Void LinuxPlatformModel", "type": "object" }, "WindowsPlatformModel": { "properties": { "name": { "const": "Windows", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": [ "2008R2", "2008x64", "2008x86", "2012", "2012R2", "2016", "2019", "2022", "2025", "all" ], "type": "string" }, "type": "array" } }, "title": "WindowsPlatformModel", "type": "object" }, "aosPlatformModel": { "properties": { "name": { "const": "aos", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["all"], "type": "string" }, "type": "array" } }, "title": "aosPlatformModel", "type": "object" }, "collections": { "items": { "markdownDescription": "See [Using collections in roles](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html#using-collections-in-roles) and [collection naming conventions](https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_in_groups.html#naming-conventions)", "pattern": "^[a-z_]+\\.[a-z_]+$", "type": "string" }, "title": "Collections", "type": "array" }, "complex_conditional": { "oneOf": [ { "type": "boolean" }, { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ] }, "eosPlatformModel": { "properties": { "name": { "const": "eos", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["all"], "type": "string" }, "type": "array" } }, "title": "eosPlatformModel", "type": "object" }, "macOSPlatformModel": { "properties": { "name": { "const": "macOS", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": [ "Big-Sur", "Catalina", "High-Sierra", "Mojave", "Monterey", "Sierra", "Sonoma", "Ventura", "all" ], "type": "string" }, "type": "array" } }, "title": "macOSPlatformModel", "type": "object" }, "opensusePlatformModel": { "properties": { "name": { "const": "opensuse", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": [ "12.1", "12.2", "12.3", "13.1", "13.2", "15.0", "15.1", "15.2", "15.3", "15.4", "15.5", "42.1", "42.2", "42.3", "all" ], "type": "string" }, "type": "array" } }, "title": "opensusePlatformModel", "type": "object" }, "os10PlatformModel": { "properties": { "name": { "const": "os10", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["all"], "type": "string" }, "type": "array" } }, "title": "os10PlatformModel", "type": "object" }, "platforms": { "items": { "anyOf": [ { "$ref": "#/$defs/AIXPlatformModel" }, { "$ref": "#/$defs/AlpinePlatformModel" }, { "$ref": "#/$defs/AmazonPlatformModel" }, { "$ref": "#/$defs/AmazonLinuxPlatformModel" }, { "$ref": "#/$defs/aosPlatformModel" }, { "$ref": "#/$defs/ArchLinuxPlatformModel" }, { "$ref": "#/$defs/AstraLinuxPlatformModel" }, { "$ref": "#/$defs/ClearLinuxPlatformModel" }, { "$ref": "#/$defs/CumulusPlatformModel" }, { "$ref": "#/$defs/NetBSDPlatformModel" }, { "$ref": "#/$defs/DebianPlatformModel" }, { "$ref": "#/$defs/DellOSPlatformModel" }, { "$ref": "#/$defs/DevuanPlatformModel" }, { "$ref": "#/$defs/DragonFlyBSDPlatformModel" }, { "$ref": "#/$defs/ELPlatformModel" }, { "$ref": "#/$defs/eosPlatformModel" }, { "$ref": "#/$defs/FedoraPlatformModel" }, { "$ref": "#/$defs/FreeBSDPlatformModel" }, { "$ref": "#/$defs/GenericBSDPlatformModel" }, { "$ref": "#/$defs/GenericLinuxPlatformModel" }, { "$ref": "#/$defs/GenericUNIXPlatformModel" }, { "$ref": "#/$defs/GentooPlatformModel" }, { "$ref": "#/$defs/HardenedBSDPlatformModel" }, { "$ref": "#/$defs/IOSPlatformModel" }, { "$ref": "#/$defs/JunosPlatformModel" }, { "$ref": "#/$defs/KaliPlatformModel" }, { "$ref": "#/$defs/macOSPlatformModel" }, { "$ref": "#/$defs/MacOSXPlatformModel" }, { "$ref": "#/$defs/MageiaPlatformModel" }, { "$ref": "#/$defs/NXOSPlatformModel" }, { "$ref": "#/$defs/OpenBSDPlatformModel" }, { "$ref": "#/$defs/opensusePlatformModel" }, { "$ref": "#/$defs/OpenWrtPlatformModel" }, { "$ref": "#/$defs/OracleLinuxPlatformModel" }, { "$ref": "#/$defs/os10PlatformModel" }, { "$ref": "#/$defs/PAN-OSPlatformModel" }, { "$ref": "#/$defs/RockyLinuxPlatformModel" }, { "$ref": "#/$defs/SLESPlatformModel" }, { "$ref": "#/$defs/SmartOSPlatformModel" }, { "$ref": "#/$defs/SolarisPlatformModel" }, { "$ref": "#/$defs/SynologyPlatformModel" }, { "$ref": "#/$defs/TMOSPlatformModel" }, { "$ref": "#/$defs/UbuntuPlatformModel" }, { "$ref": "#/$defs/vCenterPlatformModel" }, { "$ref": "#/$defs/Void_LinuxPlatformModel" }, { "$ref": "#/$defs/vSpherePlatformModel" }, { "$ref": "#/$defs/WindowsPlatformModel" } ] }, "title": "Platforms", "type": "array" }, "vCenterPlatformModel": { "properties": { "name": { "const": "vCenter", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["5.5", "6.0", "6.5", "6.7", "7.0", "all"], "type": "string" }, "type": "array" } }, "title": "vCenterPlatformModel", "type": "object" }, "vSpherePlatformModel": { "properties": { "name": { "const": "vSphere", "title": "Name", "type": "string" }, "versions": { "default": "all", "items": { "enum": ["5.5", "6.0", "6.5", "6.7", "7.0", "all"], "type": "string" }, "type": "array" } }, "title": "vSpherePlatformModel", "type": "object" } }, "$id": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/meta.json", "$schema": "http://json-schema.org/draft-07/schema", "description": "https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html#using-role-dependencies", "examples": ["meta/main.yml"], "properties": { "additionalProperties": false, "allow_duplicates": { "title": "Allow Duplicates", "type": "boolean" }, "collections": { "$ref": "#/$defs/collections" }, "dependencies": { "items": { "anyOf": [ { "type": "string" }, { "$ref": "#/$defs/DependencyModel" } ] }, "title": "Dependencies", "type": "array" }, "galaxy_info": { "$ref": "#/$defs/GalaxyInfoModel" } }, "title": "Ansible Meta Schema v1/v2", "type": ["object", "null"] } ����������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/molecule.json����������������������������������0000664�0000000�0000000�00000033143�14773473560�0025302�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "$defs": { "ContainerRegistryModel": { "additionalProperties": false, "properties": { "url": { "title": "Url", "type": "string" } }, "required": ["url"], "title": "ContainerRegistryModel", "type": "object" }, "MoleculeDependencyModel": { "additionalProperties": false, "properties": { "command": { "title": "Command", "type": ["string", "null"] }, "enabled": { "default": true, "title": "Enabled", "type": "boolean" }, "env": { "title": "Env", "type": "object" }, "name": { "enum": ["galaxy", "shell"], "title": "Name", "type": "string" }, "options": { "title": "Options", "type": "object" } }, "required": ["name"], "title": "MoleculeDependencyModel", "type": "object" }, "MoleculeDriverModel": { "additionalProperties": false, "properties": { "cachier": { "title": "Cachier", "type": "string" }, "default_box": { "title": "DefaultBox", "type": "string" }, "name": { "enum": [ "azure", "ec2", "delegated", "docker", "containers", "openstack", "podman", "vagrant", "digitalocean", "gce", "libvirt", "lxd" ], "title": "Name", "type": "string" }, "options": { "$ref": "#/$defs/MoleculeDriverOptionsModel" }, "parallel": { "title": "Parallel", "type": "boolean" }, "provider": { "title": "Provider", "type": "object" }, "provision": { "title": "Provision", "type": "boolean" }, "safe_files": { "items": { "type": "string" }, "title": "SafeFiles", "type": "array" }, "ssh_connection_options": { "items": { "type": "string" }, "title": "SshConnectionOptions", "type": "array" } }, "title": "MoleculeDriverModel", "type": "object" }, "MoleculeDriverOptionsModel": { "additionalProperties": false, "properties": { "ansible_connection_options": { "additionalProperties": { "type": "string" }, "title": "Ansible Connection Options", "type": "object" }, "login_cmd_template": { "title": "Login Cmd Template", "type": "string" }, "managed": { "title": "Managed", "type": "boolean" } }, "title": "MoleculeDriverOptionsModel", "type": "object" }, "MoleculePlatformModel": { "additionalProperties": true, "properties": { "box": { "title": "Box", "type": "string" }, "cgroupns": { "title": "Cgroupns", "type": "string" }, "children": { "items": { "type": "string" }, "type": "array" }, "command": { "title": "Command", "type": "string" }, "cpus": { "title": "Cpus", "type": "integer" }, "dockerfile": { "title": "Dockerfile", "type": "string" }, "env": { "items": { "type": "object" }, "title": "Platform Environment Variables", "type": "array" }, "environment": { "additionalProperties": { "type": "string" }, "title": "Environment", "type": "object" }, "groups": { "items": { "type": "string" }, "title": "Groups", "type": "array" }, "hostname": { "title": "Hostname", "type": ["string", "boolean"] }, "image": { "title": "Image", "type": ["string", "null"] }, "interfaces": { "title": "Interfaces", "type": "array" }, "memory": { "title": "Memory", "type": "integer" }, "name": { "title": "Name", "type": "string" }, "network_mode": { "anyOf": [ { "enum": ["bridge", "host", "none"], "type": "string" }, { "pattern": "^service:[a-zA-Z0-9:_.\\\\-]+$", "type": "string" }, { "pattern": "^container:[a-zA-Z0-9][a-zA-Z0-9_.-]+$", "type": "string" } ], "title": "Network Mode" }, "networks": { "items": { "$ref": "#/$defs/platform-network" }, "markdownDescription": "Used by docker and podman drivers.", "title": "Networks", "type": "array" }, "pkg_extras": { "title": "Pkg Extras", "type": "string" }, "pre_build_image": { "title": "Pre Build Image", "type": "boolean" }, "privileged": { "title": "Privileged", "type": "boolean" }, "provider_options": { "title": "Provider options", "type": "object" }, "provider_raw_config_args": { "items": { "type": "string" }, "title": "Provider Raw Config Args", "type": "array" }, "registry": { "$ref": "#/$defs/ContainerRegistryModel" }, "tmpfs": { "items": { "type": "string" }, "title": "Tmpfs", "type": "array" }, "ulimits": { "items": { "type": "string" }, "title": "Ulimits", "type": "array" }, "volumes": { "items": { "type": "string" }, "title": "Volumes", "type": "array" } }, "required": ["name"], "title": "MoleculePlatformModel", "type": "object" }, "MoleculeScenarioModel": { "additionalProperties": false, "properties": { "check_sequence": { "$ref": "#/$defs/ScenarioSequence" }, "cleanup_sequence": { "$ref": "#/$defs/ScenarioSequence" }, "converge_sequence": { "$ref": "#/$defs/ScenarioSequence" }, "create_sequence": { "$ref": "#/$defs/ScenarioSequence" }, "dependency_sequence": { "$ref": "#/$defs/ScenarioSequence" }, "destroy_sequence": { "$ref": "#/$defs/ScenarioSequence" }, "idempotence_sequence": { "$ref": "#/$defs/ScenarioSequence" }, "lint_sequence": { "$ref": "#/$defs/ScenarioSequence" }, "name": { "title": "Name", "type": "string" }, "prepare_sequence": { "$ref": "#/$defs/ScenarioSequence" }, "side_effect_sequence": { "$ref": "#/$defs/ScenarioSequence" }, "syntax_sequence": { "$ref": "#/$defs/ScenarioSequence" }, "test_sequence": { "$ref": "#/$defs/ScenarioSequence" }, "verify_sequence": { "$ref": "#/$defs/ScenarioSequence" } }, "title": "MoleculeScenarioModel", "type": "object" }, "ProvisionerConfigOptionsDefaultsModel": { "additionalProperties": true, "properties": { "ansible_managed": { "default": "Ansible managed: Do NOT edit this file manually!", "title": "Ansible Managed", "type": "string" }, "display_failed_stderr": { "default": true, "title": "Display Failed Stderr", "type": "boolean" }, "fact_caching": { "title": "Fact Caching", "type": "string" }, "fact_caching_connection": { "title": "Fact Caching Connection", "type": "string" }, "forks": { "default": 50, "title": "Forks", "type": "integer" }, "host_key_checking": { "default": false, "title": "Host Key Checking", "type": "boolean" }, "interpreter_python": { "default": "auto_silent", "description": "See https://docs.ansible.com/ansible/devel/reference_appendices/interpreter_discovery.html", "title": "Interpreter Python", "type": "string" }, "nocows": { "default": 1, "title": "Nocows", "type": "integer" }, "retry_files_enabled": { "default": false, "title": "Retry Files Enabled", "type": "boolean" } }, "title": "ProvisionerConfigOptionsDefaultsModel", "type": "object" }, "ProvisionerConfigOptionsModel": { "additionalProperties": true, "properties": { "defaults": { "$ref": "#/$defs/ProvisionerConfigOptionsDefaultsModel" }, "ssh_connection": { "$ref": "#/$defs/ProvisionerConfigOptionsSshConnectionModel" } }, "title": "ProvisionerConfigOptionsModel", "type": "object" }, "ProvisionerConfigOptionsSshConnectionModel": { "additionalProperties": false, "properties": { "control_path": { "default": "%(directory)s/%%h-%%p-%%r", "title": "Control Path", "type": "string" }, "scp_if_ssh": { "default": true, "title": "Scp If Ssh", "type": "boolean" } }, "title": "ProvisionerConfigOptionsSshConnectionModel", "type": "object" }, "ProvisionerModel": { "additionalProperties": true, "properties": { "config_options": { "$ref": "#/$defs/ProvisionerConfigOptionsModel" }, "env": { "title": "Env", "type": "object" }, "inventory": { "title": "Inventory", "type": "object" }, "log": { "title": "Log", "type": "boolean" }, "name": { "enum": ["ansible"], "title": "Name", "type": "string" }, "playbooks": { "title": "Playbooks", "type": "object" } }, "title": "ProvisionerModel", "type": "object" }, "ScenarioSequence": { "additionalProperties": false, "items": { "enum": [ "check", "cleanup", "converge", "create", "dependency", "destroy", "idempotence", "lint", "prepare", "side_effect", "syntax", "test", "verify" ], "type": "string" }, "title": "ScenarioSequence", "type": "array" }, "VerifierModel": { "additionalProperties": false, "properties": { "additional_files_or_dirs": { "items": { "type": "string" }, "title": "AdditionalFilesOrDirs", "type": "array" }, "enabled": { "title": "Enabled", "type": "boolean" }, "env": { "title": "Env", "type": "object" }, "name": { "default": "ansible", "enum": ["ansible", "goss", "inspec", "testinfra"], "title": "Name", "type": "string" }, "options": { "title": "Options", "type": "object" } }, "title": "VerifierModel", "type": "object" }, "platform-network": { "properties": { "aliases": { "items": { "type": "string" }, "type": "array" }, "ipv4_address": { "type": "string" }, "name": { "type": "string" } }, "required": ["name"], "type": "object" } }, "$id": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/molecule.json", "$schema": "http://json-schema.org/draft-07/schema", "additionalProperties": false, "description": "https://ansible.readthedocs.io/projects/molecule/configuration/", "examples": ["molecule/*/molecule.yml"], "properties": { "dependency": { "$ref": "#/$defs/MoleculeDependencyModel" }, "driver": { "$ref": "#/$defs/MoleculeDriverModel" }, "lint": { "title": "Lint", "type": "string" }, "log": { "default": true, "title": "Log", "type": "boolean" }, "platforms": { "items": { "$ref": "#/$defs/MoleculePlatformModel" }, "title": "Platforms", "type": "array" }, "prerun": { "title": "Prerun", "type": "boolean" }, "provisioner": { "$ref": "#/$defs/ProvisionerModel" }, "role_name_check": { "enum": [0, 1, 2], "title": "RoleNameCheck", "type": "integer" }, "scenario": { "$ref": "#/$defs/MoleculeScenarioModel" }, "verifier": { "$ref": "#/$defs/VerifierModel" } }, "required": ["driver", "platforms"], "title": "Molecule Scenario Schema", "type": "object" } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/playbook.json����������������������������������0000664�0000000�0000000�00000100511�14773473560�0025307�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "$comment": "Generated from ansible.json, do not edit.", "$defs": { "ansible.builtin.import_playbook": { "additionalProperties": false, "oneOf": [ { "not": { "required": [ "import_playbook" ] }, "required": [ "ansible.builtin.import_playbook" ] }, { "not": { "required": [ "ansible.builtin.import_playbook" ] }, "required": [ "import_playbook" ] } ], "patternProperties": { "^(ansible\\.builtin\\.)?import_playbook$": { "markdownDescription": "* Includes a file with a list of plays to be executed.\n * Files with a list of plays can only be included at the top level.\n * You cannot use this action inside a play.\n\nSee [import_playbook](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/import_playbook_module.html)", "title": "Import Playbook", "type": "string" }, "name": { "title": "Name", "type": "string" }, "tags": { "$ref": "#/$defs/tags" }, "vars": { "title": "Vars", "type": "object" }, "when": { "$ref": "#/$defs/complex_conditional", "title": "When" } }, "type": "object" }, "become_method": { "anyOf": [ { "enum": [ "ansible.builtin.sudo", "ansible.builtin.su", "community.general.pbrun", "community.general.pfexec", "ansible.builtin.runas", "community.general.dzdo", "community.general.ksu", "community.general.doas", "community.general.machinectl", "community.general.pmrun", "community.general.sesu", "community.general.sudosu" ], "type": "string" }, { "$ref": "#/$defs/full-jinja" }, { "pattern": "[A-Za-z0-9_\\.]+", "type": "string" } ], "markdownDescription": "See [become](https://docs.ansible.com/ansible/latest/user_guide/become.html)", "title": "Become Method" }, "block": { "properties": { "always": { "items": { "anyOf": [ { "$ref": "#/$defs/task" }, { "$ref": "#/$defs/block" } ] }, "title": "Always", "type": "array" }, "any_errors_fatal": { "$ref": "#/$defs/templated-boolean", "title": "Any Errors Fatal" }, "become": { "$ref": "#/$defs/templated-boolean", "title": "Become" }, "become_exe": { "title": "Become Exe", "type": "string" }, "become_flags": { "title": "Become Flags", "type": "string" }, "become_method": { "$ref": "#/$defs/become_method" }, "become_user": { "title": "Become User", "type": "string" }, "block": { "items": { "anyOf": [ { "$ref": "#/$defs/task" }, { "$ref": "#/$defs/block" } ] }, "markdownDescription": "Blocks create logical groups of tasks. Blocks also offer ways to handle task errors, similar to exception handling in many programming languages. See [blocks](https://docs.ansible.com/ansible/latest/user_guide/playbooks_blocks.html)", "title": "Block", "type": "array" }, "check_mode": { "$ref": "#/$defs/complex_conditional", "title": "Check Mode" }, "collections": { "items": { "type": "string" }, "title": "Collections", "type": "array" }, "connection": { "title": "Connection", "type": "string" }, "debugger": { "title": "Debugger", "type": "string" }, "delegate_facts": { "title": "Delegate Facts", "type": "boolean" }, "delegate_to": { "title": "Delegate To", "type": "string" }, "diff": { "$ref": "#/$defs/templated-boolean", "title": "Diff" }, "environment": { "$ref": "#/$defs/environment" }, "ignore_errors": { "$ref": "#/$defs/ignore_errors" }, "ignore_unreachable": { "$ref": "#/$defs/templated-boolean", "title": "Ignore Unreachable" }, "module_defaults": { "title": "Module Defaults" }, "name": { "title": "Name", "type": "string" }, "no_log": { "$ref": "#/$defs/templated-boolean" }, "port": { "$ref": "#/$defs/templated-integer" }, "remote_user": { "title": "Remote User", "type": "string" }, "rescue": { "items": { "anyOf": [ { "$ref": "#/$defs/task" }, { "$ref": "#/$defs/block" } ] }, "title": "Rescue", "type": "array" }, "run_once": { "$ref": "#/$defs/templated-boolean", "title": "Run Once" }, "tags": { "$ref": "#/$defs/tags", "title": "Tags" }, "throttle": { "$ref": "#/$defs/templated-integer", "title": "Throttle" }, "timeout": { "$ref": "#/$defs/templated-integer", "title": "Timeout" }, "vars": { "title": "Vars", "type": "object" }, "when": { "$ref": "#/$defs/complex_conditional", "title": "When" } }, "required": [ "block" ], "type": "object" }, "complex_conditional": { "oneOf": [ { "type": "boolean" }, { "type": "string" }, { "items": { "anyOf": [ { "type": "boolean" }, { "type": "string" } ] }, "type": "array" } ] }, "environment": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "$ref": "#/$defs/full-jinja" } ], "title": "Environment" }, "full-jinja": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$", "type": "string" }, "ignore_errors": { "$ref": "#/$defs/templated-boolean", "markdownDescription": "See [ignore_errors](https://docs.ansible.com/ansible/latest/user_guide/playbooks_error_handling.html#ignoring-failed-commands)", "title": "Ignore Errors" }, "no_log": { "$ref": "#/$defs/templated-boolean", "markdownDescription": "Use for protecting sensitive data. See [no_log](https://docs.ansible.com/ansible/latest/reference_appendices/logging.html)", "title": "no_log" }, "play": { "additionalProperties": false, "allOf": [ { "not": { "required": [ "ansible.builtin.import_playbook" ] } }, { "not": { "required": [ "import_playbook" ] } } ], "properties": { "any_errors_fatal": { "$ref": "#/$defs/templated-boolean", "title": "Any Errors Fatal" }, "become": { "$ref": "#/$defs/templated-boolean", "title": "Become" }, "become_exe": { "title": "Become Exe", "type": "string" }, "become_flags": { "title": "Become Flags", "type": "string" }, "become_method": { "$ref": "#/$defs/become_method" }, "become_user": { "title": "Become User", "type": "string" }, "check_mode": { "$ref": "#/$defs/complex_conditional", "title": "Check Mode" }, "collections": { "items": { "type": "string" }, "title": "Collections", "type": "array" }, "connection": { "title": "Connection", "type": "string" }, "debugger": { "title": "Debugger", "type": "string" }, "diff": { "$ref": "#/$defs/templated-boolean", "title": "Diff" }, "environment": { "$ref": "#/$defs/environment" }, "fact_path": { "title": "Fact Path", "type": "string" }, "force_handlers": { "title": "Force Handlers", "type": "boolean" }, "gather_facts": { "$ref": "#/$defs/templated-boolean", "title": "Gather Facts" }, "gather_subset": { "items": { "anyOf": [ { "enum": [ "all", "min", "all_ipv4_addresses", "all_ipv6_addresses", "apparmor", "architecture", "caps", "chroot,cmdline", "date_time", "default_ipv4", "default_ipv6", "devices", "distribution", "distribution_major_version", "distribution_release", "distribution_version", "dns", "effective_group_ids", "effective_user_id", "env", "facter", "fips", "hardware", "interfaces", "is_chroot", "iscsi", "kernel", "local", "lsb", "machine", "machine_id", "mounts", "network", "ohai", "os_family", "pkg_mgr", "platform", "processor", "processor_cores", "processor_count", "python", "python_version", "real_user_id", "selinux", "service_mgr", "ssh_host_key_dsa_public", "ssh_host_key_ecdsa_public", "ssh_host_key_ed25519_public", "ssh_host_key_rsa_public", "ssh_host_pub_keys", "ssh_pub_keys", "system", "system_capabilities", "system_capabilities_enforced", "user", "user_dir", "user_gecos", "user_gid", "user_id", "user_shell", "user_uid", "virtual", "virtualization_role", "virtualization_type" ], "type": "string" }, { "enum": [ "!all", "!min", "!all_ipv4_addresses", "!all_ipv6_addresses", "!apparmor", "!architecture", "!caps", "!chroot,cmdline", "!date_time", "!default_ipv4", "!default_ipv6", "!devices", "!distribution", "!distribution_major_version", "!distribution_release", "!distribution_version", "!dns", "!effective_group_ids", "!effective_user_id", "!env", "!facter", "!fips", "!hardware", "!interfaces", "!is_chroot", "!iscsi", "!kernel", "!local", "!lsb", "!machine", "!machine_id", "!mounts", "!network", "!ohai", "!os_family", "!pkg_mgr", "!platform", "!processor", "!processor_cores", "!processor_count", "!python", "!python_version", "!real_user_id", "!selinux", "!service_mgr", "!ssh_host_key_dsa_public", "!ssh_host_key_ecdsa_public", "!ssh_host_key_ed25519_public", "!ssh_host_key_rsa_public", "!ssh_host_pub_keys", "!ssh_pub_keys", "!system", "!system_capabilities", "!system_capabilities_enforced", "!user", "!user_dir", "!user_gecos", "!user_gid", "!user_id", "!user_shell", "!user_uid", "!virtual", "!virtualization_role", "!virtualization_type" ], "type": "string" } ] }, "title": "Gather Subset", "type": "array" }, "gather_timeout": { "$ref": "#/$defs/templated-integer", "title": "Gather Timeout" }, "handlers": { "$ref": "#/$defs/tasks" }, "hosts": { "anyOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ], "title": "Hosts" }, "ignore_errors": { "$ref": "#/$defs/ignore_errors" }, "ignore_unreachable": { "$ref": "#/$defs/templated-boolean", "title": "Ignore Unreachable" }, "max_fail_percentage": { "$ref": "#/$defs/templated-integer", "title": "Max Fail Percentage" }, "module_defaults": { "title": "Module Defaults" }, "name": { "title": "Name", "type": "string" }, "no_log": { "$ref": "#/$defs/templated-boolean" }, "order": { "markdownDescription": "See https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_strategies.html#ordering-execution-based-on-inventory", "oneOf": [ { "enum": [ "inventory", "reverse_inventory", "reverse_sorted", "shuffle", "sorted" ], "type": "string" }, { "$ref": "#/$defs/full-jinja" } ], "title": "Order" }, "port": { "$ref": "#/$defs/templated-integer", "title": "Port" }, "post_tasks": { "$ref": "#/$defs/tasks" }, "pre_tasks": { "$ref": "#/$defs/tasks" }, "remote_user": { "title": "Remote User", "type": "string" }, "roles": { "items": { "anyOf": [ { "$ref": "#/$defs/play-role" }, { "type": "string" } ] }, "markdownDescription": "Roles let you automatically load related vars, files, tasks, handlers, and other Ansible artifacts based on a known file structure. After you group your content in roles, you can easily reuse them and share them with other users.\n See [roles](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#roles)", "title": "Roles", "type": "array" }, "run_once": { "$ref": "#/$defs/templated-boolean", "title": "Run Once" }, "serial": { "anyOf": [ { "$ref": "#/$defs/templated-integer-or-percent" }, { "items": { "$ref": "#/$defs/templated-integer-or-percent" }, "type": "array" } ], "markdownDescription": "Integer, percentage or list of those. See [Setting the batch size with serial](https://docs.ansible.com/ansible/latest/user_guide/playbooks_strategies.html#setting-the-batch-size-with-serial)", "title": "Batch size" }, "strategy": { "title": "Strategy", "type": "string" }, "tags": { "$ref": "#/$defs/tags", "title": "Tags" }, "tasks": { "$ref": "#/$defs/tasks" }, "throttle": { "$ref": "#/$defs/templated-integer", "title": "Throttle" }, "timeout": { "$ref": "#/$defs/templated-integer", "title": "Timeout" }, "user": { "title": "Remote User", "type": "string" }, "vars": { "title": "Vars", "type": "object" }, "vars_files": { "items": { "oneOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ] }, "title": "Vars Files", "type": [ "array", "string", "null" ] }, "vars_prompt": { "items": { "$ref": "#/$defs/vars_prompt" }, "markdownDescription": "See [vars_prompt](https://docs.ansible.com/ansible/latest/user_guide/playbooks_prompts.html)", "title": "vars_prompt", "type": "array" }, "when": { "$ref": "#/$defs/complex_conditional", "title": "When" } }, "required": [ "hosts" ], "title": "play", "type": "object" }, "play-role": { "markdownDescription": "See [roles](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#roles)", "properties": { "any_errors_fatal": { "$ref": "#/$defs/templated-boolean", "title": "Any Errors Fatal" }, "become": { "$ref": "#/$defs/templated-boolean", "title": "Become" }, "become_exe": { "title": "Become Exe", "type": "string" }, "become_flags": { "title": "Become Flags", "type": "string" }, "become_method": { "$ref": "#/$defs/become_method" }, "become_user": { "title": "Become User", "type": "string" }, "check_mode": { "$ref": "#/$defs/complex_conditional", "title": "Check Mode" }, "collections": { "items": { "type": "string" }, "title": "Collections", "type": "array" }, "connection": { "title": "Connection", "type": "string" }, "debugger": { "title": "Debugger", "type": "string" }, "delegate_to": { "title": "Delegate To", "type": "string" }, "diff": { "$ref": "#/$defs/templated-boolean", "title": "Diff" }, "environment": { "$ref": "#/$defs/environment" }, "ignore_errors": { "$ref": "#/$defs/ignore_errors" }, "ignore_unreachable": { "$ref": "#/$defs/templated-boolean", "title": "Ignore Unreachable" }, "module_defaults": { "title": "Module Defaults" }, "name": { "title": "Name", "type": "string" }, "no_log": { "$ref": "#/$defs/templated-boolean" }, "port": { "$ref": "#/$defs/templated-integer", "title": "Port" }, "remote_user": { "title": "Remote User", "type": "string" }, "role": { "title": "Role", "type": "string" }, "run_once": { "$ref": "#/$defs/templated-boolean", "title": "Run Once" }, "tags": { "$ref": "#/$defs/tags", "title": "Tags" }, "throttle": { "$ref": "#/$defs/templated-integer", "title": "Throttle" }, "timeout": { "$ref": "#/$defs/templated-integer", "title": "Timeout" }, "vars": { "title": "Vars", "type": "object" }, "when": { "$ref": "#/$defs/complex_conditional", "title": "When" } }, "required": [ "role" ], "title": "play-role", "type": "object" }, "removed-include-module": { "markdownDescription": "See [include module](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/include_module.html)", "not": {}, "title": "Replace 'include' with either 'ansible.builtin.include_tasks' or 'ansible.builtin.import_tasks'" }, "tags": { "anyOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ], "title": "Tags" }, "task": { "additionalProperties": true, "allOf": [ { "not": { "required": [ "hosts" ] } }, { "not": { "required": [ "tasks" ] } }, { "not": { "required": [ "import_playbook" ] } }, { "not": { "required": [ "block" ] } } ], "properties": { "action": { "title": "Action", "type": "string" }, "ansible.builtin.include": { "$ref": "#/$defs/removed-include-module" }, "ansible.legacy.include": { "$ref": "#/$defs/removed-include-module" }, "any_errors_fatal": { "$ref": "#/$defs/templated-boolean", "title": "Any Errors Fatal" }, "args": { "$ref": "#/$defs/templated-object", "title": "Args" }, "async": { "$ref": "#/$defs/templated-integer", "title": "Async" }, "become": { "$ref": "#/$defs/templated-boolean", "title": "Become" }, "become_exe": { "title": "Become Exe", "type": "string" }, "become_flags": { "title": "Become Flags", "type": "string" }, "become_method": { "$ref": "#/$defs/become_method" }, "become_user": { "title": "Become User", "type": "string" }, "changed_when": { "$ref": "#/$defs/complex_conditional", "markdownDescription": "See [changed_when](https://docs.ansible.com/ansible/latest/user_guide/playbooks_error_handling.html#defining-changed)", "title": "Changed When" }, "check_mode": { "$ref": "#/$defs/complex_conditional", "title": "Check Mode" }, "collections": { "items": { "type": "string" }, "title": "Collections", "type": "array" }, "connection": { "title": "Connection", "type": "string" }, "debugger": { "title": "Debugger", "type": "string" }, "delay": { "$ref": "#/$defs/templated-integer", "title": "Delay" }, "delegate_facts": { "title": "Delegate Facts", "type": "boolean" }, "delegate_to": { "title": "Delegate To", "type": "string" }, "diff": { "$ref": "#/$defs/templated-boolean", "title": "Diff" }, "environment": { "$ref": "#/$defs/environment" }, "failed_when": { "$ref": "#/$defs/complex_conditional", "title": "Failed When" }, "ignore_errors": { "$ref": "#/$defs/ignore_errors" }, "ignore_unreachable": { "$ref": "#/$defs/templated-boolean", "title": "Ignore Unreachable" }, "include": { "$ref": "#/$defs/removed-include-module" }, "listen": { "anyOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ], "markdownDescription": "Applies only to handlers. See [listen](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html)", "title": "Listen" }, "local_action": { "title": "Local Action", "type": [ "string", "object" ] }, "loop": { "title": "Loop", "type": [ "string", "array" ] }, "loop_control": { "title": "Loop Control" }, "module_defaults": { "title": "Module Defaults" }, "name": { "title": "Name", "type": "string" }, "no_log": { "$ref": "#/$defs/no_log" }, "notify": { "anyOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ], "title": "Notify" }, "poll": { "$ref": "#/$defs/templated-integer", "title": "Poll" }, "port": { "$ref": "#/$defs/templated-integer", "title": "Port" }, "register": { "title": "Register", "type": "string" }, "remote_user": { "title": "Remote User", "type": "string" }, "retries": { "$ref": "#/$defs/templated-integer", "title": "Retries" }, "run_once": { "$ref": "#/$defs/templated-boolean", "title": "Run Once" }, "tags": { "$ref": "#/$defs/tags", "title": "Tags" }, "throttle": { "$ref": "#/$defs/templated-integer", "title": "Throttle" }, "timeout": { "$ref": "#/$defs/templated-integer", "title": "Timeout" }, "until": { "$ref": "#/$defs/complex_conditional", "title": "Until" }, "vars": { "title": "Vars", "type": "object" }, "when": { "$ref": "#/$defs/complex_conditional", "title": "When" }, "with_dict": { "title": "With Dict" }, "with_fileglob": { "title": "With Fileglob" }, "with_filetree": { "title": "With Filetree" }, "with_first_found": { "title": "With First Found" }, "with_indexed_items": { "title": "With Indexed Items" }, "with_ini": { "title": "With Ini" }, "with_inventory_hostnames": { "title": "With Inventory Hostnames" }, "with_items": { "anyOf": [ { "$ref": "#/$defs/full-jinja" }, { "type": "array" } ], "markdownDescription": "See [loops](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#loops)", "title": "With Items" }, "with_lines": { "title": "With Lines" }, "with_random_choice": { "title": "With Random Choice" }, "with_sequence": { "title": "With Sequence" }, "with_subelements": { "title": "With Subelements" }, "with_together": { "title": "With Together" } }, "title": "task", "type": "object" }, "tasks": { "$schema": "http://json-schema.org/draft-07/schema", "examples": [ "tasks/*.yml", "handlers/*.yml" ], "items": { "anyOf": [ { "$ref": "#/$defs/block" }, { "$ref": "#/$defs/task" } ] }, "title": "Ansible Tasks Schema", "type": [ "array", "null" ] }, "templated-boolean": { "oneOf": [ { "type": "boolean" }, { "$ref": "#/$defs/full-jinja", "type": "string" } ] }, "templated-integer": { "oneOf": [ { "type": "integer" }, { "$ref": "#/$defs/full-jinja", "type": "string" } ] }, "templated-integer-or-percent": { "oneOf": [ { "type": "integer" }, { "pattern": "^\\d+\\.?\\d*%?$", "type": "string" }, { "$ref": "#/$defs/full-jinja", "type": "string" } ] }, "templated-object": { "oneOf": [ { "type": "object" }, { "$ref": "#/$defs/full-jinja", "type": "string" } ] }, "vars_prompt": { "additionalProperties": false, "properties": { "confirm": { "title": "Confirm", "type": "boolean" }, "default": { "title": "Default", "type": "string" }, "encrypt": { "enum": [ "des_crypt", "bsdi_crypt", "bigcrypt", "crypt16", "md5_crypt", "bcrypt", "sha1_crypt", "sun_md5_crypt", "sha256_crypt", "sha512_crypt", "apr_md5_crypt", "phpass", "pbkdf2_digest", "cta_pbkdf2_sha1", "dlitz_pbkdf2_sha1", "scram", "bsd_nthash" ], "title": "Encrypt", "type": "string" }, "name": { "title": "Name", "type": "string" }, "private": { "default": true, "title": "Private", "type": "boolean" }, "prompt": { "title": "Prompt", "type": "string" }, "salt_size": { "default": 8, "title": "Salt Size", "type": "integer" }, "unsafe": { "default": false, "markdownDescription": "See [unsafe](https://docs.ansible.com/ansible/latest/user_guide/playbooks_prompts.html#allowing-special-characters-in-vars-prompt-values)", "title": "Unsafe", "type": "boolean" } }, "required": [ "name", "prompt" ], "type": "object" } }, "$id": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/playbook.json", "$schema": "http://json-schema.org/draft-07/schema", "examples": [ "playbooks/*.yml", "playbooks/*.yaml" ], "items": { "oneOf": [ { "$ref": "#/$defs/ansible.builtin.import_playbook" }, { "$ref": "#/$defs/play" } ] }, "title": "Ansible Playbook", "type": "array" } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/requirements.json������������������������������0000664�0000000�0000000�00000006070�14773473560�0026217�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "$defs": { "CollectionModel": { "additionalProperties": false, "properties": { "name": { "title": "Name", "type": "string" }, "source": { "title": "Source", "type": "string" }, "type": { "enum": ["galaxy", "url", "file", "git", "dir", "subdirs"], "title": "Type", "type": "string" }, "version": { "title": "Version", "type": "string" } }, "title": "CollectionModel", "type": "object" }, "CollectionStringModel": { "title": "CollectionStringModel", "type": "string" }, "IncludeModel": { "properties": { "include": { "title": "Include", "type": "string" } }, "required": ["include"], "title": "IncludeModel", "type": "object" }, "RequirementsV2Model": { "additionalProperties": false, "anyOf": [ { "required": ["collections"] }, { "required": ["roles"] } ], "properties": { "collections": { "items": { "anyOf": [ { "$ref": "#/$defs/CollectionModel" }, { "$ref": "#/$defs/CollectionStringModel" } ] }, "title": "Collections", "type": "array" }, "roles": { "items": { "$ref": "#/$defs/RoleModel" }, "title": "Roles", "type": "array" } }, "title": "Requirements v2", "type": "object" }, "RoleModel": { "additionalProperties": false, "properties": { "name": { "title": "Name", "type": "string" }, "scm": { "anyOf": [ { "enum": ["git"], "type": "string" }, { "enum": ["hg"], "type": "string" } ], "default": "git", "title": "Scm" }, "src": { "title": "Src", "type": "string" }, "version": { "default": "master", "title": "Version", "type": "string" } }, "title": "Role", "type": "object" } }, "$id": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/requirements.json", "$schema": "http://json-schema.org/draft-07/schema", "anyOf": [ { "items": { "anyOf": [ { "$ref": "#/$defs/RoleModel" }, { "$ref": "#/$defs/IncludeModel" } ] }, "type": "array" }, { "$ref": "#/$defs/RequirementsV2Model" } ], "description": "https://docs.ansible.com/ansible/latest/galaxy/user_guide.html#installing-roles-and-collections-from-the-same-requirements-yml-file", "examples": ["requirements.yml"], "title": "Ansible Requirements Schema" } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/role-arg-spec.json�����������������������������0000664�0000000�0000000�00000022735�14773473560�0026142�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "$defs": { "attribute": { "additionalProperties": false, "properties": { "description": { "description": "Detailed explanation of what this attribute does. It should be written in full sentences.", "oneOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ] }, "details": { "description": "Detailed explanation of what this attribute does. It should be written in full sentences.", "oneOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ] }, "membership": { "oneOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ] }, "platform": { "oneOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ] }, "support": { "enum": ["full", "partial", "none", "N/A"], "type": "string" }, "version_added": { "type": "string" } }, "required": ["description", "support"], "title": "Attribute" }, "datatype": { "enum": [ "str", "list", "dict", "bool", "int", "float", "path", "raw", "jsonarg", "json", "bytes", "bits" ], "type": "string" }, "deprecated_alias": { "properties": { "collection_name": { "type": "string" }, "date": { "type": "string" }, "name": { "type": "string" }, "version": { "type": "string" } }, "required": ["name"], "type": "object" }, "entry_point": { "additionalProperties": false, "properties": { "attributes": { "additionalProperties": { "$ref": "#/$defs/attribute" }, "type": "object" }, "author": { "oneOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ] }, "description": { "oneOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ] }, "examples": { "type": "string" }, "options": { "additionalProperties": { "$ref": "#/$defs/option" }, "type": "object" }, "seealso": { "items": { "oneOf": [ { "additionalProperties": false, "properties": { "description": { "type": "string" }, "module": { "type": "string" } }, "required": ["module"], "type": "object" }, { "additionalProperties": false, "properties": { "description": { "type": "string" }, "plugin": { "type": "string" }, "plugin_type": { "type": "string" } }, "required": ["plugin", "plugin_type"], "type": "object" }, { "additionalProperties": false, "properties": { "description": { "type": "string" }, "ref": { "type": "string" } }, "required": ["description", "ref"], "type": "object" }, { "additionalProperties": false, "properties": { "description": { "type": "string" }, "link": { "type": "string" }, "name": { "type": "string" } }, "required": ["description", "link", "name"], "type": "object" } ] }, "type": "array" }, "short_description": { "type": "string" }, "version_added": { "type": "string" } }, "title": "Entry Point", "type": "object" }, "full-jinja": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$", "type": "string" }, "option": { "additionalProperties": false, "markdownDescription": "See [argument-spec](https://docs.ansible.com/ansible/latest/dev_guide/developing_program_flow_modules.html#argument-spec)", "properties": { "apply_defaults": { "type": "string" }, "choices": { "oneOf": [ { "type": "array" }, { "$ref": "#/$defs/full-jinja", "type": "string" } ] }, "default": { "default": "None" }, "description": { "description": "Detailed explanation of what this option does. It should be written in full sentences.", "oneOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ] }, "elements": { "$ref": "#/$defs/datatype" }, "fallback": { "default": "None", "type": "string" }, "no_log": { "default": false, "type": "boolean" }, "option-name": { "description": "The name of the option/argument.", "type": "string" }, "options": { "additionalProperties": { "$ref": "#/$defs/option" }, "type": "object" }, "required": { "default": false, "type": "boolean" }, "mutually_exclusive": { "type": "array", "items": { "items": { "type": "string" } } }, "required_together": { "type": "array", "items": { "type": "array", "items": { "type": "string" } } }, "required_one_of": { "type": "array", "items": { "items": { "type": "string" } } }, "required_if": { "type": "array", "items": { "type": "array", "prefixItems": [ { "type": "string" }, {}, { "type": "array", "items": { "type": "string" } }, { "type": "boolean" } ], "minItems": 3, "maxItems": 4 } }, "required_by": { "type": "object", "additionalProperties": { "oneOf": [ { "type": "string" }, { "type": "array", "items": { "type": "string" } } ] } }, "type": { "$ref": "#/$defs/datatype", "markdownDescription": "See [argument-spec](https://docs.ansible.com/ansible/latest/dev_guide/developing_program_flow_modules.html#argument-spec" }, "version_added": { "type": "string" } }, "removed_at_date": { "type": "string" }, "removed_from_collection": { "type": "string" }, "removed_in_version": { "type": "string" }, "title": "Option" } }, "$id": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/role-arg-spec.json", "$schema": "http://json-schema.org/draft-07/schema", "additionalProperties": false, "examples": ["meta/argument_specs.yml"], "markdownDescription": "See [role-argument-validation](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#role-argument-validation)", "properties": { "argument_specs": { "additionalProperties": { "$ref": "#/$defs/entry_point" }, "markdownDescription": "Add entry point, usually `main`.\nSee [role-argument-validation](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#role-argument-validation)" } }, "title": "Ansible Role Argument Specs Schema" } �����������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/rulebook.json����������������������������������0000664�0000000�0000000�00000060120�14773473560�0025312�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "https://raw.githubusercontent.com/ansible/ansible-rulebook/main/ansible_rulebook/schema/ruleset_schema.json", "title": "Ansible Rulebook", "description": "See https://ansible.readthedocs.io/projects/rulebook/en/stable/rulebooks.html", "type": "array", "items": { "$ref": "#/$defs/ruleset" }, "minItems": 1, "examples": [ "rulebooks/*.yml", "rulebooks/*.yaml" ], "$defs": { "ruleset": { "type": "object", "properties": { "default_events_ttl": { "type": "string", "pattern": "^\\d+\\s(seconds?|minutes?|hours?|days?)$" }, "hosts": { "type": "string" }, "gather_facts": { "type": "boolean", "default": false }, "match_multiple_rules": { "type": "boolean", "default": false }, "name": { "type": "string" }, "execution_strategy": { "type": "string", "enum": [ "parallel", "sequential" ], "default": "sequential" }, "sources": { "type": "array", "items": { "$ref": "#/$defs/source" } }, "rules": { "type": "array", "items": { "$ref": "#/$defs/rule" } } }, "required": [ "name", "hosts", "sources", "rules" ], "additionalProperties": false }, "source": { "type": "object", "properties": { "name": { "type": "string" }, "filters": { "type": "array", "items": { "type": "object" } } }, "additionalProperties": { "oneOf": [ { "type": "object" }, { "type": "null" } ] } }, "throttle": { "type": "object", "oneOf": [ { "required": [ "once_within", "group_by_attributes" ] }, { "required": [ "once_after", "group_by_attributes" ] } ], "properties": { "once_within": { "type": "string", "pattern": "^\\d+\\s(milliseconds?|seconds?|minutes?|hours?|days?)$" }, "once_after": { "type": "string", "pattern": "^\\d+\\s(milliseconds?|seconds?|minutes?|hours?|days?)$" }, "group_by_attributes": { "type": "array", "items": { "type": "string" } } }, "additionalProperties": false }, "rule": { "type": "object", "oneOf": [ { "required": [ "name", "condition", "actions" ] }, { "required": [ "name", "condition", "action" ] } ], "properties": { "name": { "type": "string", "minLength": 1, "pattern": "\\S" }, "enabled": { "type": "boolean" }, "throttle": { "$ref": "#/$defs/throttle" }, "condition": { "anyOf": [ { "type": "string" }, { "type": "boolean" }, { "$ref": "#/$defs/all-condition" }, { "$ref": "#/$defs/any-condition" }, { "$ref": "#/$defs/not-all-condition" } ] }, "actions": { "type": "array", "items": { "oneOf": [ { "$ref": "#/$defs/run-playbook-action" }, { "$ref": "#/$defs/run-module-action" }, { "$ref": "#/$defs/run-job-template-action" }, { "$ref": "#/$defs/run-workflow-template-action" }, { "$ref": "#/$defs/post-event-action" }, { "$ref": "#/$defs/set-fact-action" }, { "$ref": "#/$defs/retract-fact-action" }, { "$ref": "#/$defs/print-event-action" }, { "$ref": "#/$defs/debug-action" }, { "$ref": "#/$defs/none-action" }, { "$ref": "#/$defs/shutdown-action" }, { "$ref": "#/$defs/pg-notify-action" } ] } }, "action": { "oneOf": [ { "$ref": "#/$defs/run-playbook-action" }, { "$ref": "#/$defs/run-module-action" }, { "$ref": "#/$defs/run-job-template-action" }, { "$ref": "#/$defs/run-workflow-template-action" }, { "$ref": "#/$defs/post-event-action" }, { "$ref": "#/$defs/set-fact-action" }, { "$ref": "#/$defs/retract-fact-action" }, { "$ref": "#/$defs/print-event-action" }, { "$ref": "#/$defs/debug-action" }, { "$ref": "#/$defs/none-action" }, { "$ref": "#/$defs/shutdown-action" }, { "$ref": "#/$defs/pg-notify-action" } ] } }, "additionalProperties": false }, "all-condition": { "type": "object", "properties": { "all": { "type": "array", "items": { "type": "string" } }, "timeout": { "type": "string", "pattern": "^\\d+\\s(milliseconds?|seconds?|minutes?|hours?|days?)$" } }, "additionalProperties": false }, "not-all-condition": { "type": "object", "properties": { "not_all": { "type": "array", "items": { "type": "string" } }, "timeout": { "type": "string", "pattern": "^\\d+\\s(milliseconds?|seconds?|minutes?|hours?|days?)$" } }, "required": [ "timeout", "not_all" ], "additionalProperties": false }, "any-condition": { "type": "object", "properties": { "any": { "type": "array", "items": { "type": "string" } } }, "additionalProperties": false }, "run-playbook-action": { "type": "object", "properties": { "run_playbook": { "type": "object", "properties": { "copy_files": { "type": "boolean" }, "name": { "type": "string" }, "post_events": { "type": "boolean" }, "set_facts": { "type": "boolean" }, "ruleset": { "type": "string" }, "verbosity": { "type": "integer" }, "var_root": { "type": [ "string", "object" ] }, "json_mode": { "type": "boolean" }, "retry": { "type": "boolean" }, "retries": { "type": "integer" }, "delay": { "type": "number" }, "extra_vars": { "type": "object" } }, "required": [ "name" ], "additionalProperties": false } }, "required": [ "run_playbook" ], "additionalProperties": false }, "run-module-action": { "type": "object", "properties": { "run_module": { "type": "object", "properties": { "name": { "type": "string" }, "post_events": { "type": "boolean" }, "set_facts": { "type": "boolean" }, "verbosity": { "type": "integer" }, "var_root": { "type": [ "string", "object" ] }, "json_mode": { "type": "boolean" }, "retry": { "type": "boolean" }, "retries": { "type": "integer" }, "delay": { "type": "number" }, "module_args": { "type": [ "object", "string" ] }, "extra_vars": { "type": "object" } }, "required": [ "name" ], "additionalProperties": false } }, "required": [ "run_module" ], "additionalProperties": false }, "run-job-template-action": { "type": "object", "properties": { "run_job_template": { "type": "object", "properties": { "name": { "type": "string" }, "organization": { "type": "string" }, "job_args": { "type": "object" }, "post_events": { "type": "boolean" }, "set_facts": { "type": "boolean" }, "ruleset": { "type": "string" }, "var_root": { "type": "string" }, "retry": { "type": "boolean" }, "retries": { "type": "integer" }, "delay": { "type": "integer" }, "include_events": { "type": "boolean", "default": true } }, "required": [ "name", "organization" ], "additionalProperties": false } }, "required": [ "run_job_template" ], "additionalProperties": false }, "run-workflow-template-action": { "type": "object", "properties": { "run_workflow_template": { "type": "object", "properties": { "name": { "type": "string" }, "organization": { "type": "string" }, "job_args": { "type": "object" }, "post_events": { "type": "boolean" }, "set_facts": { "type": "boolean" }, "ruleset": { "type": "string" }, "var_root": { "type": "string" }, "retry": { "type": "boolean" }, "retries": { "type": "integer" }, "delay": { "type": "integer" }, "include_events": { "type": "boolean", "default": true } }, "required": [ "name", "organization" ], "additionalProperties": false } }, "required": [ "run_workflow_template" ], "additionalProperties": false }, "pg-notify-action": { "type": "object", "properties": { "pg_notify": { "type": "object", "properties": { "dsn": { "type": "string" }, "channel": { "type": "string" }, "event": { "type": [ "string", "object" ] }, "remove_meta": { "type": "boolean", "default": false } }, "required": [ "dsn", "channel", "event" ], "additionalProperties": false } }, "required": [ "pg_notify" ], "additionalProperties": false }, "post-event-action": { "type": "object", "properties": { "post_event": { "type": "object", "properties": { "ruleset": { "type": "string" }, "event": { "type": "object" } }, "required": [ "event" ], "additionalProperties": false } }, "required": [ "post_event" ], "additionalProperties": false }, "set-fact-action": { "type": "object", "properties": { "set_fact": { "type": "object", "properties": { "ruleset": { "type": "string" }, "fact": { "type": "object" } }, "required": [ "fact" ], "additionalProperties": false } }, "required": [ "set_fact" ], "additionalProperties": false }, "retract-fact-action": { "type": "object", "properties": { "retract_fact": { "type": "object", "properties": { "ruleset": { "type": "string" }, "fact": { "type": "object" }, "partial": { "type": "boolean", "default": true } }, "required": [ "fact" ], "additionalProperties": false } }, "required": [ "retract_fact" ], "additionalProperties": false }, "print-event-action": { "type": "object", "properties": { "print_event": { "type": [ "object", "null" ], "properties": { "var_root": { "type": [ "string", "object" ] }, "pretty": { "type": "boolean" } }, "additionalProperties": false } }, "required": [ "print_event" ], "additionalProperties": false }, "debug-msg": { "type": "object", "properties": { "msg": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "type": "string" } } ] } }, "additionalProperties": false }, "debug-var": { "type": "object", "properties": { "var": { "type": "string" } }, "additionalProperties": false }, "debug-action": { "type": "object", "properties": { "debug": { "anyOf": [ { "$ref": "#/$defs/debug-msg" }, { "$ref": "#/$defs/debug-var" }, { "type": "null" } ] } }, "additionalProperties": false, "required": [ "debug" ] }, "none-action": { "type": "object", "properties": { "none": { "type": [ "object", "null" ] } }, "required": [ "none" ], "additionalProperties": false }, "shutdown-action": { "type": "object", "properties": { "shutdown": { "type": [ "object", "null" ], "properties": { "delay": { "type": "number" }, "message": { "type": "string" }, "kind": { "type": "string", "enum": [ "graceful", "now" ] } }, "additionalProperties": false } }, "required": [ "shutdown" ], "additionalProperties": false } } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/tasks.json�������������������������������������0000664�0000000�0000000�00000035036�14773473560�0024625�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "$comment": "Generated from ansible.json, do not edit.", "$defs": { "become_method": { "anyOf": [ { "enum": [ "ansible.builtin.sudo", "ansible.builtin.su", "community.general.pbrun", "community.general.pfexec", "ansible.builtin.runas", "community.general.dzdo", "community.general.ksu", "community.general.doas", "community.general.machinectl", "community.general.pmrun", "community.general.sesu", "community.general.sudosu" ], "type": "string" }, { "$ref": "#/$defs/full-jinja" }, { "pattern": "[A-Za-z0-9_\\.]+", "type": "string" } ], "markdownDescription": "See [become](https://docs.ansible.com/ansible/latest/user_guide/become.html)", "title": "Become Method" }, "block": { "properties": { "always": { "items": { "anyOf": [ { "$ref": "#/$defs/task" }, { "$ref": "#/$defs/block" } ] }, "title": "Always", "type": "array" }, "any_errors_fatal": { "$ref": "#/$defs/templated-boolean", "title": "Any Errors Fatal" }, "become": { "$ref": "#/$defs/templated-boolean", "title": "Become" }, "become_exe": { "title": "Become Exe", "type": "string" }, "become_flags": { "title": "Become Flags", "type": "string" }, "become_method": { "$ref": "#/$defs/become_method" }, "become_user": { "title": "Become User", "type": "string" }, "block": { "items": { "anyOf": [ { "$ref": "#/$defs/task" }, { "$ref": "#/$defs/block" } ] }, "markdownDescription": "Blocks create logical groups of tasks. Blocks also offer ways to handle task errors, similar to exception handling in many programming languages. See [blocks](https://docs.ansible.com/ansible/latest/user_guide/playbooks_blocks.html)", "title": "Block", "type": "array" }, "check_mode": { "$ref": "#/$defs/complex_conditional", "title": "Check Mode" }, "collections": { "items": { "type": "string" }, "title": "Collections", "type": "array" }, "connection": { "title": "Connection", "type": "string" }, "debugger": { "title": "Debugger", "type": "string" }, "delegate_facts": { "title": "Delegate Facts", "type": "boolean" }, "delegate_to": { "title": "Delegate To", "type": "string" }, "diff": { "$ref": "#/$defs/templated-boolean", "title": "Diff" }, "environment": { "$ref": "#/$defs/environment" }, "ignore_errors": { "$ref": "#/$defs/ignore_errors" }, "ignore_unreachable": { "$ref": "#/$defs/templated-boolean", "title": "Ignore Unreachable" }, "module_defaults": { "title": "Module Defaults" }, "name": { "title": "Name", "type": "string" }, "no_log": { "$ref": "#/$defs/templated-boolean" }, "port": { "$ref": "#/$defs/templated-integer" }, "remote_user": { "title": "Remote User", "type": "string" }, "rescue": { "items": { "anyOf": [ { "$ref": "#/$defs/task" }, { "$ref": "#/$defs/block" } ] }, "title": "Rescue", "type": "array" }, "run_once": { "$ref": "#/$defs/templated-boolean", "title": "Run Once" }, "tags": { "$ref": "#/$defs/tags", "title": "Tags" }, "throttle": { "$ref": "#/$defs/templated-integer", "title": "Throttle" }, "timeout": { "$ref": "#/$defs/templated-integer", "title": "Timeout" }, "vars": { "title": "Vars", "type": "object" }, "when": { "$ref": "#/$defs/complex_conditional", "title": "When" } }, "required": [ "block" ], "type": "object" }, "complex_conditional": { "oneOf": [ { "type": "boolean" }, { "type": "string" }, { "items": { "anyOf": [ { "type": "boolean" }, { "type": "string" } ] }, "type": "array" } ] }, "environment": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "$ref": "#/$defs/full-jinja" } ], "title": "Environment" }, "full-jinja": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$", "type": "string" }, "ignore_errors": { "$ref": "#/$defs/templated-boolean", "markdownDescription": "See [ignore_errors](https://docs.ansible.com/ansible/latest/user_guide/playbooks_error_handling.html#ignoring-failed-commands)", "title": "Ignore Errors" }, "no_log": { "$ref": "#/$defs/templated-boolean", "markdownDescription": "Use for protecting sensitive data. See [no_log](https://docs.ansible.com/ansible/latest/reference_appendices/logging.html)", "title": "no_log" }, "removed-include-module": { "markdownDescription": "See [include module](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/include_module.html)", "not": {}, "title": "Replace 'include' with either 'ansible.builtin.include_tasks' or 'ansible.builtin.import_tasks'" }, "tags": { "anyOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ], "title": "Tags" }, "task": { "additionalProperties": true, "allOf": [ { "not": { "required": [ "hosts" ] } }, { "not": { "required": [ "tasks" ] } }, { "not": { "required": [ "import_playbook" ] } }, { "not": { "required": [ "block" ] } } ], "properties": { "action": { "title": "Action", "type": "string" }, "ansible.builtin.include": { "$ref": "#/$defs/removed-include-module" }, "ansible.legacy.include": { "$ref": "#/$defs/removed-include-module" }, "any_errors_fatal": { "$ref": "#/$defs/templated-boolean", "title": "Any Errors Fatal" }, "args": { "$ref": "#/$defs/templated-object", "title": "Args" }, "async": { "$ref": "#/$defs/templated-integer", "title": "Async" }, "become": { "$ref": "#/$defs/templated-boolean", "title": "Become" }, "become_exe": { "title": "Become Exe", "type": "string" }, "become_flags": { "title": "Become Flags", "type": "string" }, "become_method": { "$ref": "#/$defs/become_method" }, "become_user": { "title": "Become User", "type": "string" }, "changed_when": { "$ref": "#/$defs/complex_conditional", "markdownDescription": "See [changed_when](https://docs.ansible.com/ansible/latest/user_guide/playbooks_error_handling.html#defining-changed)", "title": "Changed When" }, "check_mode": { "$ref": "#/$defs/complex_conditional", "title": "Check Mode" }, "collections": { "items": { "type": "string" }, "title": "Collections", "type": "array" }, "connection": { "title": "Connection", "type": "string" }, "debugger": { "title": "Debugger", "type": "string" }, "delay": { "$ref": "#/$defs/templated-integer", "title": "Delay" }, "delegate_facts": { "title": "Delegate Facts", "type": "boolean" }, "delegate_to": { "title": "Delegate To", "type": "string" }, "diff": { "$ref": "#/$defs/templated-boolean", "title": "Diff" }, "environment": { "$ref": "#/$defs/environment" }, "failed_when": { "$ref": "#/$defs/complex_conditional", "title": "Failed When" }, "ignore_errors": { "$ref": "#/$defs/ignore_errors" }, "ignore_unreachable": { "$ref": "#/$defs/templated-boolean", "title": "Ignore Unreachable" }, "include": { "$ref": "#/$defs/removed-include-module" }, "listen": { "anyOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ], "markdownDescription": "Applies only to handlers. See [listen](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html)", "title": "Listen" }, "local_action": { "title": "Local Action", "type": [ "string", "object" ] }, "loop": { "title": "Loop", "type": [ "string", "array" ] }, "loop_control": { "title": "Loop Control" }, "module_defaults": { "title": "Module Defaults" }, "name": { "title": "Name", "type": "string" }, "no_log": { "$ref": "#/$defs/no_log" }, "notify": { "anyOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ], "title": "Notify" }, "poll": { "$ref": "#/$defs/templated-integer", "title": "Poll" }, "port": { "$ref": "#/$defs/templated-integer", "title": "Port" }, "register": { "title": "Register", "type": "string" }, "remote_user": { "title": "Remote User", "type": "string" }, "retries": { "$ref": "#/$defs/templated-integer", "title": "Retries" }, "run_once": { "$ref": "#/$defs/templated-boolean", "title": "Run Once" }, "tags": { "$ref": "#/$defs/tags", "title": "Tags" }, "throttle": { "$ref": "#/$defs/templated-integer", "title": "Throttle" }, "timeout": { "$ref": "#/$defs/templated-integer", "title": "Timeout" }, "until": { "$ref": "#/$defs/complex_conditional", "title": "Until" }, "vars": { "title": "Vars", "type": "object" }, "when": { "$ref": "#/$defs/complex_conditional", "title": "When" }, "with_dict": { "title": "With Dict" }, "with_fileglob": { "title": "With Fileglob" }, "with_filetree": { "title": "With Filetree" }, "with_first_found": { "title": "With First Found" }, "with_indexed_items": { "title": "With Indexed Items" }, "with_ini": { "title": "With Ini" }, "with_inventory_hostnames": { "title": "With Inventory Hostnames" }, "with_items": { "anyOf": [ { "$ref": "#/$defs/full-jinja" }, { "type": "array" } ], "markdownDescription": "See [loops](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#loops)", "title": "With Items" }, "with_lines": { "title": "With Lines" }, "with_random_choice": { "title": "With Random Choice" }, "with_sequence": { "title": "With Sequence" }, "with_subelements": { "title": "With Subelements" }, "with_together": { "title": "With Together" } }, "title": "task", "type": "object" }, "templated-boolean": { "oneOf": [ { "type": "boolean" }, { "$ref": "#/$defs/full-jinja", "type": "string" } ] }, "templated-integer": { "oneOf": [ { "type": "integer" }, { "$ref": "#/$defs/full-jinja", "type": "string" } ] }, "templated-object": { "oneOf": [ { "type": "object" }, { "$ref": "#/$defs/full-jinja", "type": "string" } ] } }, "$id": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/tasks.json", "$schema": "http://json-schema.org/draft-07/schema", "examples": [ "tasks/*.yml", "handlers/*.yml" ], "items": { "anyOf": [ { "$ref": "#/$defs/block" }, { "$ref": "#/$defs/task" } ] }, "title": "Ansible Tasks Schema", "type": [ "array", "null" ] } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/schemas/vars.json��������������������������������������0000664�0000000�0000000�00000002661�14773473560�0024451�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "$id": "https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/vars.json", "$schema": "http://json-schema.org/draft-07/schema", "anyOf": [ { "additionalProperties": false, "patternProperties": { "^(?!(False|None|True|and|any_errors_fatal|as|assert|async|await|become|become_exe|become_flags|become_method|become_user|break|check_mode|class|collections|connection|continue|debugger|def|del|diff|elif|else|environment|except|fact_path|finally|for|force_handlers|from|gather_facts|gather_subset|gather_timeout|global|handlers|hosts|if|ignore_errors|ignore_unreachable|import|in|is|lambda|max_fail_percentage|module_defaults|name|no_log|nonlocal|not|or|order|pass|port|post_tasks|pre_tasks|raise|remote_user|return|roles|run_once|serial|strategy|tags|tasks|throttle|timeout|try|vars|vars_files|vars_prompt|while|with|yield)$)[a-zA-Z_][\\w]*$": {} }, "type": "object" }, { "pattern": "^\\$ANSIBLE_VAULT;", "type": "string" }, { "type": "null" } ], "description": "https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html", "examples": [ "playbooks/vars/*.yml", "vars/*.yml", "defaults/*.yml", "host_vars/*.yml", "group_vars/*.yml" ], "markdownDescription": "See [Using Variables](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html)", "title": "Ansible Vars Schema" } �������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/skip_utils.py������������������������������������������0000664�0000000�0000000�00000026061�14773473560�0023720�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# (c) 2019-2020, Ansible by Red Hat # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. """Utils related to inline skipping of rules.""" from __future__ import annotations import collections.abc import logging import re import warnings from collections.abc import Mapping, MutableMapping, Sequence from functools import cache from itertools import product from typing import TYPE_CHECKING, Any # Module 'ruamel.yaml' does not explicitly export attribute 'YAML'; implicit reexport disabled from ruamel.yaml import YAML from ruamel.yaml.composer import ComposerError from ruamel.yaml.scanner import ScannerError from ruamel.yaml.tokens import CommentToken from ansiblelint.config import used_old_tags from ansiblelint.constants import ( NESTED_TASK_KEYS, PLAYBOOK_TASK_KEYWORDS, RENAMED_TAGS, SKIPPED_RULES_KEY, ) from ansiblelint.errors import LintWarning, WarnSource if TYPE_CHECKING: from collections.abc import Generator from ansiblelint.file_utils import Lintable from ansiblelint.types import AnsibleBaseYAMLObject _logger = logging.getLogger(__name__) _found_deprecated_tags: set[str] = set() _noqa_comment_re = re.compile(r"^# noqa(\s|:)") # playbook: Sequence currently expects only instances of one of the two # classes below but we should consider avoiding this chimera. # ruamel.yaml.comments.CommentedSeq # ansible.parsing.yaml.objects.AnsibleSequence def get_rule_skips_from_line( line: str, lintable: Lintable, lineno: int = 1, ) -> list[str]: """Return list of rule ids skipped via comment on the line of yaml.""" _before_noqa, _noqa_marker, noqa_text = line.partition("# noqa") result = [] for v in noqa_text.lstrip(" :").split(): if v in RENAMED_TAGS: tag = RENAMED_TAGS[v] if v not in _found_deprecated_tags: msg = f"Replaced outdated tag '{v}' with '{tag}', replace it to avoid future errors" warnings.warn( message=msg, category=LintWarning, source=WarnSource( filename=lintable, lineno=lineno, tag="warning[outdated-tag]", message=msg, ), stacklevel=0, ) _found_deprecated_tags.add(v) v = tag result.append(v) return result def append_skipped_rules( pyyaml_data: AnsibleBaseYAMLObject, lintable: Lintable, ) -> AnsibleBaseYAMLObject: """Append 'skipped_rules' to individual tasks or single metadata block. For a file, uses 2nd parser (ruamel.yaml) to pull comments out of yaml subsets, check for '# noqa' skipped rules, and append any skips to the original parser (pyyaml) data relied on by remainder of ansible-lint. :param pyyaml_data: file text parsed via ansible and pyyaml. :param file_text: raw file text. :param file_type: type of file: tasks, handlers or meta. :returns: original pyyaml_data altered with a 'skipped_rules' list added \ to individual tasks, or added to the single metadata block. """ try: yaml_skip = _append_skipped_rules(pyyaml_data, lintable) except RuntimeError: # pragma: no cover # Notify user of skip error, do not stop, do not change exit code _logger.exception("Error trying to append skipped rules") return pyyaml_data if not yaml_skip: return pyyaml_data return yaml_skip @cache def load_data(file_text: str) -> Any: """Parse ``file_text`` as yaml and return parsed structure. This is the main culprit for slow performance, each rule asks for loading yaml again and again ideally the ``maxsize`` on the decorator above MUST be great or equal total number of rules :param file_text: raw text to parse :return: Parsed yaml """ yaml = YAML() # Ruamel role is not to validate the yaml file, so we ignore duplicate keys: yaml.allow_duplicate_keys = True try: return yaml.load(file_text) except ComposerError: # load fails on multi-documents with ComposerError exception return yaml.load_all(file_text) def _append_skipped_rules( pyyaml_data: AnsibleBaseYAMLObject, lintable: Lintable, ) -> AnsibleBaseYAMLObject | None: # parse file text using 2nd parser library try: ruamel_data = load_data(lintable.content) except ScannerError as exc: # pragma: no cover _logger.debug( "Ignored loading skipped rules from file %s due to: %s", lintable, exc, ) # For unparsable file types, we return empty skip lists return None skipped_rules = _get_rule_skips_from_yaml(ruamel_data, lintable) if lintable.kind in [ "yaml", "requirements", "vars", "meta", "reno", "test-meta", "galaxy", ]: # AnsibleMapping, dict if isinstance(pyyaml_data, MutableMapping): pyyaml_data[SKIPPED_RULES_KEY] = skipped_rules # AnsibleSequence, list elif ( not isinstance(pyyaml_data, str) and isinstance(pyyaml_data, collections.abc.Sequence) and skipped_rules ): pyyaml_data[0][SKIPPED_RULES_KEY] = skipped_rules return pyyaml_data # create list of blocks of tasks or nested tasks pyyaml_task_blocks: Sequence[Any] if lintable.kind in ("tasks", "handlers", "playbook"): if not isinstance(pyyaml_data, Sequence): return pyyaml_data if lintable.kind in ("tasks", "handlers"): ruamel_task_blocks = ruamel_data pyyaml_task_blocks = pyyaml_data else: try: pyyaml_task_blocks = _get_task_blocks_from_playbook(pyyaml_data) ruamel_task_blocks = _get_task_blocks_from_playbook(ruamel_data) except (AttributeError, TypeError): return pyyaml_data else: # For unsupported file types, we return empty skip lists return None # get tasks from blocks of tasks pyyaml_tasks = _get_tasks_from_blocks(pyyaml_task_blocks) ruamel_tasks = _get_tasks_from_blocks(ruamel_task_blocks) # append skipped_rules for each task for ruamel_task, pyyaml_task in zip(ruamel_tasks, pyyaml_tasks, strict=False): # ignore empty tasks if not pyyaml_task and not ruamel_task: continue # AnsibleUnicode or str if isinstance(pyyaml_task, str): continue if pyyaml_task.get("name") != ruamel_task.get("name"): # pragma: no cover msg = "Error in matching skip comment to a task" raise RuntimeError(msg) pyyaml_task[SKIPPED_RULES_KEY] = _get_rule_skips_from_yaml( ruamel_task, lintable, ) return pyyaml_data def _get_task_blocks_from_playbook(playbook: Sequence[Any]) -> list[Any]: """Return parts of playbook that contains tasks, and nested tasks. :param playbook: playbook yaml from yaml parser. :returns: list of task dictionaries. """ task_blocks = [] for play, key in product(playbook, PLAYBOOK_TASK_KEYWORDS): task_blocks.extend(play.get(key, [])) return task_blocks def _get_tasks_from_blocks(task_blocks: Sequence[Any]) -> Generator[Any, None, None]: """Get list of tasks from list made of tasks and nested tasks.""" if not task_blocks: return def get_nested_tasks(task: Any) -> Generator[Any, None, None]: if not task or not is_nested_task(task): return for k in NESTED_TASK_KEYS: if task.get(k): if hasattr(task[k], "get"): continue for subtask in task[k]: yield from get_nested_tasks(subtask) yield subtask for task in task_blocks: yield from get_nested_tasks(task) yield task def _get_rule_skips_from_yaml( yaml_input: Sequence[Any], lintable: Lintable, ) -> Sequence[Any]: """Traverse yaml for comments with rule skips and return list of rules.""" yaml_comment_obj_strings = [] if isinstance(yaml_input, str): return [] def traverse_yaml(obj: Any) -> None: for entry in obj.ca.items.values(): for v in entry: if isinstance(v, CommentToken): comment_str = v.value if _noqa_comment_re.match(comment_str): line = v.start_mark.line + 1 # ruamel line numbers start at 0 lintable.line_skips[line].update( get_rule_skips_from_line( comment_str.strip(), lintable=lintable, lineno=line, ), ) yaml_comment_obj_strings.append(str(obj.ca.items)) if isinstance(obj, dict): for val in obj.values(): if isinstance(val, dict | list): traverse_yaml(val) elif isinstance(obj, list): for element in obj: if isinstance(element, dict | list): traverse_yaml(element) if isinstance(yaml_input, dict | list): traverse_yaml(yaml_input) rule_id_list = [] for comment_obj_str in yaml_comment_obj_strings: for line in comment_obj_str.split(r"\n"): rule_id_list.extend(get_rule_skips_from_line(line, lintable=lintable)) return [normalize_tag(tag) for tag in rule_id_list] def normalize_tag(tag: str) -> str: """Return current name of tag.""" if tag in RENAMED_TAGS: # pragma: no cover used_old_tags[tag] = RENAMED_TAGS[tag] return RENAMED_TAGS[tag] return tag def is_nested_task(task: Mapping[str, Any]) -> bool: """Check if task includes block/always/rescue.""" # Cannot really trust the input if isinstance(task, str): return False # https://github.com/ansible/ansible-lint/issues/4492 if not hasattr(task, "get"): return False return any(task.get(key) for key in NESTED_TASK_KEYS) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/stats.py�����������������������������������������������0000664�0000000�0000000�00000002052�14773473560�0022662�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Module hosting functionality about reporting.""" from __future__ import annotations from dataclasses import dataclass, field @dataclass(order=True) class TagStats: """Tag statistics.""" order: int = 0 # to be computed based on rule's profile tag: str = "" # rule effective id (can be multiple tags per rule id) count: int = 0 # total number of occurrences warning: bool = False # set true if listed in warn_list profile: str = "" associated_tags: list[str] = field(default_factory=list) class SummarizedResults: """The statistics about an ansible-lint run.""" failures: int = 0 warnings: int = 0 fixed_failures: int = 0 fixed_warnings: int = 0 tag_stats: dict[str, TagStats] = {} passed_profile: str = "" @property def fixed(self) -> int: """Get total fixed count.""" return self.fixed_failures + self.fixed_warnings def sort(self) -> None: """Sort tag stats by tag name.""" self.tag_stats = dict(sorted(self.tag_stats.items(), key=lambda t: t[1])) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/testing/�����������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0022630�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/testing/__init__.py������������������������������������0000664�0000000�0000000�00000007252�14773473560�0024747�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test utils for ansible-lint.""" from __future__ import annotations import os import shutil import subprocess import sys import tempfile from pathlib import Path from typing import TYPE_CHECKING, Any from ansiblelint.app import App, get_app if TYPE_CHECKING: # https://github.com/PyCQA/pylint/issues/3240 CompletedProcess = subprocess.CompletedProcess[Any] from ansiblelint.errors import MatchError from ansiblelint.rules import RulesCollection else: CompletedProcess = subprocess.CompletedProcess # pylint: disable=wrong-import-position from ansiblelint.runner import Runner class RunFromText: """Use Runner on temp files created from testing text snippets.""" app: App | None = None def __init__(self, collection: RulesCollection) -> None: """Initialize a RunFromText instance with rules collection.""" # Emulate command line execution initialization as without it Ansible module # would be loaded with incomplete module/role/collection list. if not self.app: # pragma: no cover self.app = get_app(offline=True) self.collection = collection def _call_runner(self, path: Path) -> list[MatchError]: runner = Runner(path, rules=self.collection) return runner.run() def run(self, filename: Path) -> list[MatchError]: """Lints received filename.""" return self._call_runner(filename) def run_playbook( self, playbook_text: str, prefix: str = "playbook", ) -> list[MatchError]: """Lints received text as a playbook.""" with tempfile.NamedTemporaryFile( mode="w", suffix=".yml", prefix=prefix, encoding="utf-8" ) as fh: fh.write(playbook_text) fh.flush() results = self._call_runner(Path(fh.name)) return results def run_role_tasks_main( self, tasks_main_text: str, tmp_path: Path, ) -> list[MatchError]: """Lints received text as tasks.""" role_path = tmp_path tasks_path = role_path / "tasks" tasks_path.mkdir(parents=True, exist_ok=True) with (tasks_path / "main.yml").open("w", encoding="utf-8") as fh: fh.write(tasks_main_text) fh.flush() results = self._call_runner(role_path) shutil.rmtree(role_path) return results def run_ansible_lint( *argv: str | Path, cwd: Path | None = None, executable: str | None = None, env: dict[str, str] | None = None, offline: bool = True, ) -> CompletedProcess: """Run ansible-lint on a given path and returns its output.""" args = [str(item) for item in argv] if offline: # pragma: no cover args.insert(0, "--offline") if not executable: executable = sys.executable args = [sys.executable, "-m", "ansiblelint", *args] else: args = [executable, *args] # It is not safe to pass entire env for testing as other tests would # pollute the env, causing weird behaviors, so we pass only a safe list of # vars. safe_list = [ "COVERAGE_FILE", "COVERAGE_PROCESS_START", "HOME", "LANG", "LC_ALL", "LC_CTYPE", "NO_COLOR", "PATH", "PYTHONIOENCODING", "PYTHONPATH", "TERM", "VIRTUAL_ENV", ] env_ = {} if env is None else env for v in safe_list: if v in os.environ and v not in env_: env_[v] = os.environ[v] return subprocess.run( args, capture_output=True, shell=False, # needed when command is a list check=False, cwd=cwd, env=env_, text=True, encoding="utf-8", ) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/testing/fixtures.py������������������������������������0000664�0000000�0000000�00000003563�14773473560�0025062�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""PyTest Fixtures. They should not be imported, instead add code below to your root conftest.py file: pytest_plugins = ['ansiblelint.testing'] """ from __future__ import annotations from typing import TYPE_CHECKING import pytest from ansiblelint.config import Options from ansiblelint.constants import DEFAULT_RULESDIR from ansiblelint.rules import RulesCollection from ansiblelint.testing import RunFromText if TYPE_CHECKING: from _pytest.fixtures import SubRequest # The sessions scope does not apply to xdist, so we will still have one # session for each worker, but at least it will a limited number. @pytest.fixture(name="default_rules_collection", scope="session") def fixture_default_rules_collection() -> RulesCollection: """Return default rule collection.""" assert DEFAULT_RULESDIR.is_dir() config_options = Options() config_options.enable_list = ["no-same-owner"] # That is instantiated very often and do want to avoid ansible-galaxy # install errors due to concurrency. config_options.offline = True return RulesCollection(rulesdirs=[DEFAULT_RULESDIR], options=config_options) @pytest.fixture def default_text_runner(default_rules_collection: RulesCollection) -> RunFromText: """Return RunFromText instance for the default set of collections.""" return RunFromText(default_rules_collection) @pytest.fixture def rule_runner(request: SubRequest) -> RunFromText: """Return runner for a specific rule class.""" rule_class = request.param config_options = Options() config_options.enable_list.append(rule_class().id) collection = RulesCollection(options=config_options) collection.register(rule_class()) return RunFromText(collection) @pytest.fixture(name="config_options") def fixture_config_options() -> Options: """Return configuration options that will be restored after testrun.""" return Options() ���������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/text.py������������������������������������������������0000664�0000000�0000000�00000003753�14773473560�0022521�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Text utils.""" from __future__ import annotations import re from functools import cache RE_HAS_JINJA = re.compile(r"{[{%#].*[%#}]}", re.DOTALL) RE_HAS_GLOB = re.compile(r"[][*?]") RE_IS_FQCN_OR_NAME = re.compile(r"^\w+(\.\w+){2,100}$|^\w+$") RE_STRIP_ANSI_ESCAPE = re.compile(r"\x1b[^m]*m") RE_TO_IDENTIFIER = re.compile(r"[\s-]+") def strip_ansi_escape(data: str | bytes) -> str: """Remove all ANSI escapes from string or bytes. If bytes is passed instead of string, it will be converted to string using UTF-8. """ if isinstance(data, bytes): # pragma: no branch data = data.decode("utf-8") return RE_STRIP_ANSI_ESCAPE.sub("", data) def toidentifier(text: str) -> str: """Convert unsafe chars to ones allowed in variables.""" result = RE_TO_IDENTIFIER.sub("_", text) if not result.isidentifier(): msg = f"Unable to convert role name '{text}' to valid variable name." raise RuntimeError(msg) return result # https://www.python.org/dev/peps/pep-0616/ def removeprefix(text: str, prefix: str) -> str: """Remove prefix from string.""" if text.startswith(prefix): return text[len(prefix) :] return text[:] @cache def has_jinja(value: str) -> bool: """Return true if a string seems to contain jinja templating.""" return bool(isinstance(value, str) and RE_HAS_JINJA.search(value)) @cache def has_glob(value: str) -> bool: """Return true if a string looks like having a glob pattern.""" return bool(isinstance(value, str) and RE_HAS_GLOB.search(value)) @cache def is_fqcn_or_name(value: str) -> bool: """Return true if a string seems to be a module/filter old name or a fully qualified one.""" return bool(isinstance(value, str) and RE_IS_FQCN_OR_NAME.search(value)) @cache def is_fqcn(value: str) -> bool: """Return true if a string seems to be a fully qualified collection name.""" match = RE_IS_FQCN_OR_NAME.search(value) return bool(isinstance(value, str) and match and match.group(1)) ���������������������ansible-ansible-lint-c16f018/src/ansiblelint/transformer.py�����������������������������������������0000664�0000000�0000000�00000017754�14773473560�0024105�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# cspell:ignore classinfo """Transformer implementation.""" from __future__ import annotations import logging from typing import TYPE_CHECKING, cast from ruamel.yaml.comments import CommentedMap, CommentedSeq from ansiblelint.file_utils import Lintable from ansiblelint.rules import TransformMixin from ansiblelint.yaml_utils import FormattedYAML, get_path_to_play, get_path_to_task if TYPE_CHECKING: from ansiblelint.config import Options from ansiblelint.errors import MatchError from ansiblelint.rules import AnsibleLintRule from ansiblelint.runner import LintResult __all__ = ["Transformer"] _logger = logging.getLogger(__name__) class Transformer: """Transformer class marshals transformations. The Transformer is similar to the ``ansiblelint.runner.Runner`` which manages running each of the rules. We only expect there to be one ``Transformer`` instance which should be instantiated from the main entrypoint function. In the future, the transformer will be responsible for running transforms for each of the rule matches. For now, it just reads/writes YAML files which is a pre-requisite for the planned rule-specific transforms. """ DUMP_MSG = "Rewriting yaml file:" FIX_NA_MSG = "Rule specific fix not available for:" FIX_NE_MSG = "Rule specific fix not enabled for:" FIX_APPLY_MSG = "Applying rule specific fix for:" FIX_FAILED_MSG = "Rule specific fix failed for:" FIX_ISSUE_MSG = ( "Please file an issue for this with the task or playbook that caused the error." ) FIX_APPLIED_MSG = "Rule specific fix applied for:" FIX_NOT_APPLIED_MSG = "Rule specific fix not applied for:" def __init__(self, result: LintResult, options: Options): """Initialize a Transformer instance.""" self.write_set = self.effective_write_set(options.write_list) self.write_exclude_set = self.effective_write_set(options.write_exclude_list) self.matches: list[MatchError] = result.matches self.files: set[Lintable] = result.files lintables: dict[str, Lintable] = {file.filename: file for file in result.files} self.matches_per_file: dict[Lintable, list[MatchError]] = { file: [] for file in result.files } not_ignored = [match for match in self.matches if not match.ignored] for match in not_ignored: try: lintable = lintables[match.filename] except KeyError: # we shouldn't get here, but this is easy to recover from so do that. lintable = Lintable(match.filename) self.matches_per_file[lintable] = [] self.matches_per_file[lintable].append(match) @staticmethod def effective_write_set(write_list: list[str]) -> set[str]: """Simplify write_list based on ``"none"`` and ``"all"`` keywords. ``"none"`` resets the enabled rule transforms. This returns ``{"none"}`` or a set of everything after the last ``"none"``. If ``"all"`` is in the ``write_list`` (after ``"none"`` if present), then this will return ``{"all"}``. """ none_indexes = [i for i, value in enumerate(write_list) if value == "none"] if none_indexes: index = none_indexes[-1] if len(write_list) > index + 1: index += 1 write_list = write_list[index:] if "all" in write_list: return {"all"} return set(write_list) def run(self) -> None: """For each file, read it, execute transforms on it, then write it.""" for file, matches in self.matches_per_file.items(): # str() convinces mypy that "text/yaml" is a valid Literal. # Otherwise, it thinks base_kind is one of playbook, meta, tasks, ... file_is_yaml = str(file.base_kind) == "text/yaml" try: data: str = file.content except (UnicodeDecodeError, IsADirectoryError): # pragma: no cover # we hit a binary file (eg a jar or tar.gz) or a directory data = "" file_is_yaml = False ruamel_data: CommentedMap | CommentedSeq | None = None if file_is_yaml: # We need a fresh YAML() instance for each load because ruamel.yaml # stores intermediate state during load which could affect loading # any other files. (Based on suggestion from ruamel.yaml author) yaml = FormattedYAML( # Ansible only uses YAML 1.1, but others files should use newer 1.2 (ruamel.yaml defaults to 1.2) version=(1, 1) if file.is_owned_by_ansible() else None, ) ruamel_data = yaml.load(data) if not isinstance(ruamel_data, CommentedMap | CommentedSeq): # This is an empty vars file or similar which loads as None. # It is not safe to write this file or data-loss is likely. # Only maps and sequences can preserve comments. Skip it. _logger.debug( "Ignored reformatting %s because current implementation in ruamel.yaml would drop comments. See https://sourceforge.net/p/ruamel-yaml/tickets/460/", file, ) continue if self.write_set != {"none"}: self._do_transforms( file, ruamel_data or data, file_is_yaml, matches ) _logger.debug("%s %s, version=%s", self.DUMP_MSG, file, yaml.version) # noinspection PyUnboundLocalVariable file.content = yaml.dumps(ruamel_data) elif self.write_set != {"none"}: # pragma: no cover self._do_transforms(file, ruamel_data or data, file_is_yaml, matches) if file.updated: file.write() def _do_transforms( self, file: Lintable, data: CommentedMap | CommentedSeq | str, file_is_yaml: bool, matches: list[MatchError], ) -> None: """Do Rule-Transforms handling any last-minute MatchError inspections.""" for match in sorted(matches): match_id = f"{match.tag}/{match.match_type} {match.filename}:{match.lineno}" if not isinstance(match.rule, TransformMixin): _logger.debug("%s %s", self.FIX_NA_MSG, match_id) continue rule = cast("AnsibleLintRule", match.rule) rule_definition = set(rule.tags) rule_definition.add(rule.id) if not rule_definition.isdisjoint( self.write_exclude_set, ) or self.write_exclude_set == {"all"}: continue if rule_definition.isdisjoint(self.write_set) and self.write_set != {"all"}: _logger.debug("%s %s", self.FIX_NE_MSG, match_id) continue if file_is_yaml and not match.yaml_path: data = cast("CommentedMap | CommentedSeq", data) if match.match_type == "play": match.yaml_path = get_path_to_play(file, match.lineno, data) elif match.task or file.kind in ( "tasks", "handlers", "playbook", ): match.yaml_path = get_path_to_task(file, match.lineno, data) _logger.debug("%s %s", self.FIX_APPLY_MSG, match_id) try: match.rule.transform(match, file, data) except Exception as exc: # pylint: disable=broad-except _logger.error("%s %s", self.FIX_FAILED_MSG, match_id) # noqa: TRY400 _logger.exception(exc) # noqa: TRY401 _logger.error(self.FIX_ISSUE_MSG) # noqa: TRY400 continue if match.fixed: _logger.debug("%s %s", self.FIX_APPLIED_MSG, match_id) else: _logger.error("%s %s", self.FIX_NOT_APPLIED_MSG, match_id) ��������������������ansible-ansible-lint-c16f018/src/ansiblelint/types.py�����������������������������������������������0000664�0000000�0000000�00000004144�14773473560�0022674�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Types helper.""" from __future__ import annotations from collections.abc import Mapping, Sequence from typing import TypeAlias from ansible.parsing.yaml.objects import ( # pyright: ignore[reportMissingImports] AnsibleMapping, AnsibleSequence, AnsibleUnicode, AnsibleVaultEncryptedUnicode, ) try: from ansible.parsing.yaml.constructor import ( # pyright: ignore[reportMissingImports] AnsibleConstructor, ) from ansible.parsing.yaml.objects import ( # pyright: ignore[reportMissingImports] AnsibleBaseYAMLObject, # pyright: ignore[reportRedeclaration] ) TrustedAsTemplate = None class AnsibleTemplateSyntaxError: """Fake class introduced in 2.19.""" ansible_error_format = 1 # core 2.19 + data tagging: except ImportError: # pragma: no cover # cspell: ignore datatag from ansible._internal._datatag._tags import ( # type: ignore[import-not-found,no-redef] TrustedAsTemplate, ) from ansible._internal._yaml._constructor import ( # type: ignore[import-not-found,no-redef] # pyright: ignore[reportMissingImports] # pylint: disable=import-error,no-name-in-module AnsibleConstructor, ) from ansible.errors import ( # type: ignore[no-redef,attr-defined,unused-ignore] AnsibleTemplateSyntaxError, # pyright: ignore[reportAttributeAccessIssue] ) AnsibleBaseYAMLObject: TypeAlias = ( # type: ignore[no-redef] # pyright: ignore[reportRedeclaration] Sequence | Mapping | str | None ) ansible_error_format = 2 # temporary ignoring the type parameters for Sequence and Mapping because once # add them we can no longer use isinstance() to check for them and we will # need to implement a more complex runtime type checking. AnsibleJSON: TypeAlias = Sequence | Mapping | AnsibleUnicode | str | None # type: ignore[type-arg] __all__ = [ "AnsibleBaseYAMLObject", "AnsibleConstructor", "AnsibleJSON", "AnsibleMapping", "AnsibleSequence", "AnsibleTemplateSyntaxError", "AnsibleUnicode", "AnsibleVaultEncryptedUnicode", "TrustedAsTemplate", "ansible_error_format", ] ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/utils.py�����������������������������������������������0000664�0000000�0000000�00000140406�14773473560�0022672�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Copyright (c) 2013-2014 Will Thames <will@thames.id.au> # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # spell-checker:ignore dwim # pylint: disable=too-many-lines """Generic utility helpers.""" from __future__ import annotations import ast import collections.abc import contextlib import copy import inspect import logging import os import re from collections.abc import ( ItemsView, Iterable, Iterator, Mapping, MutableMapping, Sequence, ) from dataclasses import _MISSING_TYPE, dataclass, field from functools import cache, lru_cache from pathlib import Path from typing import TYPE_CHECKING, Any import ruamel.yaml.parser import yaml from ansible.errors import AnsibleError, AnsibleParserError from ansible.module_utils._text import to_bytes from ansible.module_utils.parsing.convert_bool import boolean from ansible.parsing.dataloader import DataLoader from ansible.parsing.mod_args import ModuleArgsParser from ansible.parsing.plugin_docs import read_docstring from ansible.parsing.splitter import split_args from ansible.parsing.vault import PromptVaultSecret from ansible.parsing.yaml.loader import AnsibleLoader from ansible.plugins.loader import ( PluginLoadContext, action_loader, add_all_plugin_dirs, module_loader, ) from ansible.template import Templar from ansible.utils.collection_loader import AnsibleCollectionConfig from yaml.composer import Composer from yaml.parser import ParserError from yaml.representer import RepresenterError from yaml.scanner import ScannerError from ansiblelint._internal.rules import ( AnsibleParserErrorRule, RuntimeErrorRule, ) from ansiblelint.app import App, get_app from ansiblelint.config import Options, options from ansiblelint.constants import ( ANNOTATION_KEYS, FILENAME_KEY, INCLUSION_ACTION_NAMES, LINE_NUMBER_KEY, NESTED_TASK_KEYS, ROLE_IMPORT_ACTION_NAMES, SKIPPED_RULES_KEY, FileType, ) from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable, discover_lintables from ansiblelint.skip_utils import is_nested_task from ansiblelint.text import has_jinja, is_fqcn, removeprefix from ansiblelint.types import ( AnsibleBaseYAMLObject, AnsibleConstructor, # pyright: ignore[reportAttributeAccessIssue] AnsibleJSON, AnsibleMapping, AnsibleSequence, TrustedAsTemplate, ) if TYPE_CHECKING: from ansiblelint.rules import RulesCollection # ansible-lint doesn't need/want to know about encrypted secrets, so we pass a # string as the password to enable such yaml files to be opened and parsed # successfully. DEFAULT_VAULT_PASSWORD = "x" # noqa: S105 PLAYBOOK_DIR = os.environ.get("ANSIBLE_PLAYBOOK_DIR", None) LINE_COLUMN_REGEX = re.compile( r".*line (?P<line>\d+), column (?P<column>\d+).*", flags=re.MULTILINE ) _logger = logging.getLogger(__name__) def parse_yaml_from_file(filepath: str) -> AnsibleJSON: """Extract a decrypted YAML object from file.""" dataloader = DataLoader() # type: ignore[no-untyped-call] if hasattr(dataloader, "set_vault_secrets"): dataloader.set_vault_secrets([ ("default", PromptVaultSecret(_bytes=to_bytes(DEFAULT_VAULT_PASSWORD))) # type: ignore[no-untyped-call] ]) result: object = dataloader.load_from_file(filepath) if result is None: return result if isinstance(result, AnsibleJSON): return result # pragma: no cover msg = "Expected a YAML object" raise TypeError(msg) def path_dwim(basedir: str, given: str) -> str: """Convert a given path do-what-I-mean style.""" dataloader = DataLoader() # type: ignore[no-untyped-call] dataloader.set_basedir(basedir) return str(dataloader.path_dwim(given)) def ansible_templar(basedir: Path, templatevars: Any) -> Templar: """Create an Ansible Templar using templatevars.""" # `basedir` is the directory containing the lintable file. # Therefore, for tasks in a role, `basedir` has the form # `roles/some_role/tasks`. On the other hand, the search path # is `roles/some_role/{files,templates}`. As a result, the # `tasks` part in the basedir should be stripped stripped. if basedir.name == "tasks": basedir = basedir.parent dataloader = DataLoader() # type: ignore[no-untyped-call] dataloader.set_basedir(str(basedir)) templar = Templar(dataloader, variables=templatevars) # type: ignore[no-untyped-call] return templar def mock_filter(left: Any, *args: Any, **kwargs: Any) -> Any: # noqa: ARG001 """Mock a filter that can take any combination of args and kwargs. This will return x when x | filter(y,z) is called e.g. {{ foo | ansible.utils.ipaddr('address') }} :param left: The left hand side of the filter :param args: The args passed to the filter :param kwargs: The kwargs passed to the filter :return: The left hand side of the filter """ # pylint: disable=unused-argument return left def ansible_template( basedir: Path, varname: Any, templatevars: Any, **kwargs: Any, ) -> Any: """Render a templated string by mocking missing filters. In the case of a missing lookup, ansible core does an early exit when disable_lookup=True but this happens after the jinja2 syntax already passed return the original string as if it had been templated. In the case of a missing filter, extract the missing filter plugin name from the ansible error, 'Could not load "filter"'. Then mock the filter and template the string again. The range allows for up to 10 unknown filters in succession :param basedir: The directory containing the lintable file :param varname: The string to be templated :param templatevars: The variables to be used in the template :param kwargs: Additional arguments to be passed to the templating engine :return: The templated string or None :raises: AnsibleError if the filter plugin cannot be extracted or the string could not be templated in 10 attempts """ # pylint: disable=too-many-locals filter_error = "template error while templating string:" lookup_error = "was found, however lookups were disabled from templating" re_filter_fqcn = re.compile(r"\w+\.\w+\.\w+") re_filter_in_err = re.compile(r"Could not load \"(\w+)\"") re_valid_filter = re.compile(r"^\w+(\.\w+\.\w+)?$") templar = ansible_templar(basedir=basedir, templatevars=templatevars) kwargs["disable_lookups"] = True for _i in range(10): try: if TrustedAsTemplate and not isinstance(varname, TrustedAsTemplate): varname = TrustedAsTemplate().tag(varname) templated = templar.template(varname, **kwargs) # type: ignore[no-untyped-call] except AnsibleError as exc: if lookup_error in exc.message: return varname if exc.message.startswith(filter_error): while True: match = re_filter_in_err.search(exc.message) if match: missing_filter = match.group(1) break match = re_filter_fqcn.search(exc.message) if match: missing_filter = match.group(0) break missing_filter = exc.message.split("'")[1] break if not re_valid_filter.match(missing_filter): err = f"Could not parse missing filter name from error message: {exc.message}" _logger.warning(err) raise v = templar.environment.filters if not hasattr(v, "_delegatee"): # pragma: no cover raise v._delegatee[missing_filter] = mock_filter # fmt: skip # noqa: SLF001 # Record the mocked filter so we can warn the user if missing_filter not in options.mock_filters: _logger.debug("Mocking missing filter %s", missing_filter) options.mock_filters.append(missing_filter) continue raise return templated return None BLOCK_NAME_TO_ACTION_TYPE_MAP = { "tasks": "task", "handlers": "handler", "pre_tasks": "task", "post_tasks": "task", "block": "meta", "rescue": "meta", "always": "meta", } def tokenize(value: str) -> tuple[list[str], dict[str, str]]: """Parse a string task invocation.""" # We do not try to tokenize something very simple because it would fail to # work for a case like: task_include: path with space.yml if value and "=" not in value: return ([value], {}) parts = split_args(value) # type: ignore[no-untyped-call] args: list[str] = [] kwargs: dict[str, str] = {} for part in parts: if "=" not in part: args.append(part) else: k, v = part.split("=", 1) kwargs[k] = v return (args, kwargs) def playbook_items(pb_data: AnsibleJSON) -> ItemsView: # type: ignore[type-arg] """Return a list of items from within the playbook.""" if isinstance(pb_data, dict): return pb_data.items() # "if play" prevents failure if the play sequence contains None, # which is weird but currently allowed by Ansible # https://github.com/ansible/ansible-lint/issues/849 if isinstance(pb_data, Sequence): return [ item for play in pb_data if isinstance(play, Mapping) for item in play.items() ] # type: ignore[return-value] return {}.items() def set_collections_basedir(basedir: Path) -> None: """Set the playbook directory as playbook_paths for the collection loader.""" # Ansible expects only absolute paths inside `playbook_paths` and will # produce weird errors if we use a relative one. # https://github.com/psf/black/issues/4519 # fmt: off AnsibleCollectionConfig.playbook_paths = ( # type: ignore[attr-defined] # pyright: ignore[reportAttributeAccessIssue] str(basedir.resolve())) # fmt: on def template( basedir: Path, value: Any, variables: Any, *, fail_on_error: bool = False, fail_on_undefined: bool = False, **kwargs: str, ) -> Any: """Attempt rendering a value with known vars.""" try: value = ansible_template( basedir.resolve(), value, variables, **dict(kwargs, fail_on_undefined=fail_on_undefined), ) # Hack to skip the following exception when using to_json filter on a variable. # noqa: FIX004 # I guess the filter doesn't like empty vars... except (AnsibleError, ValueError, RepresenterError): # templating failed, so just keep value as is. if fail_on_error: raise return value @dataclass class HandleChildren: """Parse task, roles and children.""" rules: RulesCollection = field(init=True, repr=False) app: App def include_children( self, lintable: Lintable, k: str, v: Any, parent_type: FileType, ) -> list[Lintable]: """Include children.""" basedir = str(lintable.path.parent) # handle special case include_tasks: name=filename.yml if k in INCLUSION_ACTION_NAMES and isinstance(v, dict) and "file" in v: v = v["file"] # we cannot really parse any jinja2 in includes, so we ignore them if not v or not isinstance(v, str) or "{{" in v: return [] # handle include: filename.yml tags=blah (args, kwargs) = tokenize(v) if args: file = args[0] elif "file" in kwargs: file = kwargs["file"] else: return [] result = path_dwim(basedir, file) while basedir not in ["", "/"]: if os.path.exists(result): break basedir = os.path.dirname(basedir) result = path_dwim(basedir, file) return [Lintable(result, kind=parent_type)] def taskshandlers_children( self, lintable: Lintable, k: str, v: Any | None, parent_type: FileType, ) -> list[Lintable]: """TasksHandlers Children.""" basedir = str(lintable.path.parent) results: list[Lintable] = [] if v is None or isinstance(v, int | str): raise MatchError( message="A malformed block was encountered while loading a block.", rule=RuntimeErrorRule(), lintable=lintable, ) for task_handler in v: # ignore empty tasks, `-` if not task_handler: continue with contextlib.suppress(LookupError): children = _get_task_handler_children_for_tasks_or_playbooks( task_handler, basedir, k, parent_type, ) results.append(children) continue if any(x in task_handler for x in ROLE_IMPORT_ACTION_NAMES): task_handler = normalize_task_v2( Task(task_handler, filename=str(lintable.path)), ) self._validate_task_handler_action_for_role(task_handler["action"]) name = task_handler["action"].get("name") if has_jinja(name): # we cannot deal with dynamic imports continue results.extend( self.roles_children(lintable, k, [name], parent_type), ) continue if "block" not in task_handler: continue for elem in ("block", "rescue", "always"): if elem in task_handler: results.extend( self.taskshandlers_children( lintable, k, task_handler[elem], parent_type, ), ) return results def _validate_task_handler_action_for_role(self, th_action: dict[str, Any]) -> None: """Verify that the task handler action is valid for role include.""" module = th_action["__ansible_module__"] lintable = Lintable( self.rules.options.lintables[0] if self.rules.options.lintables else ".", ) if "name" not in th_action: raise MatchError( message=f"Failed to find required 'name' key in {module!s}", rule=self.rules.rules[0], lintable=lintable, ) if not isinstance(th_action["name"], str): raise MatchError( message=f"Value assigned to 'name' key on '{module!s}' is not a string.", rule=self.rules.rules[1], lintable=lintable, ) def roles_children( self, lintable: Lintable, k: str, v: Sequence[Any], parent_type: FileType, ) -> list[Lintable]: """Roles children.""" # pylint: disable=unused-argument # parent_type) basedir = str(lintable.path.parent) results: list[Lintable] = [] if not v or not isinstance(v, Iterable): # typing does not prevent junk from being passed in return results for role in v: if isinstance(role, dict): if "role" in role or "name" in role: if "tags" not in role or "skip_ansible_lint" not in role["tags"]: role_name = role.get("role", role.get("name")) if not isinstance(role_name, str): # pragma: no cover msg = "Role name is not a string." raise TypeError(msg) results.extend( self._look_for_role_files( basedir, role_name, ), ) elif k != "dependencies": msg = f'role dict {role} does not contain a "role" or "name" key' raise SystemExit(msg) else: results.extend(self._look_for_role_files(basedir, role)) return results def import_playbook_children( self, lintable: Lintable, k: str, # pylint: disable=unused-argument v: Any, parent_type: FileType, ) -> list[Lintable]: """Include import_playbook children.""" def append_playbook_path(loc: str, playbook_path: list[str]) -> None: possible_paths.append( Path( path_dwim( os.path.expanduser(loc), os.path.join( "ansible_collections", namespace_name, collection_name, "playbooks", *playbook_path, ), ), ), ) # import_playbook only accepts a string as argument (no dict syntax) if not isinstance(v, str): return [] possible_paths = [] namespace_name, collection_name, *playbook_path = parse_fqcn(v) if namespace_name and collection_name: for loc in self.app.runtime.config.collections_paths: append_playbook_path( loc, playbook_path[:-1] + [f"{playbook_path[-1]}.yml"], ) append_playbook_path( loc, playbook_path[:-1] + [f"{playbook_path[-1]}.yaml"], ) else: possible_paths.append(lintable.path.parent / v) for possible_path in possible_paths: if not possible_path.exists(): msg = f"Failed to find {v} playbook." elif not self.app.runtime.has_playbook( str(possible_path), ): msg = f"Failed to load {v} playbook due to failing syntax check." break elif namespace_name and collection_name: # don't lint foreign playbook return [] else: return [Lintable(possible_path, kind=parent_type)] _logger.error(msg) return [] def _look_for_role_files(self, basedir: str, role: str) -> list[Lintable]: role_path = self._rolepath(basedir, role) if not role_path: # pragma: no branch return [] results = [] for kind in ["tasks", "meta", "handlers", "vars", "defaults"]: current_path = os.path.join(role_path, kind) for folder, _, files in os.walk(current_path): for file in files: file_ignorecase = file.lower() if file_ignorecase.endswith((".yml", ".yaml")): results.append(Lintable(os.path.join(folder, file))) return results def _rolepath(self, basedir: str, role: str) -> str | None: role_path = None namespace_name, collection_name, role_name = parse_fqcn(role) possible_paths = [ # if included from a playbook path_dwim(basedir, os.path.join("roles", role_name)), path_dwim(basedir, role_name), # if included from roles/[role]/meta/main.yml path_dwim(basedir, os.path.join("..", "..", "..", "roles", role_name)), path_dwim(basedir, os.path.join("..", "..", role_name)), # if checking a role in the current directory path_dwim(basedir, os.path.join("..", role_name)), ] for loc in self.app.runtime.config.default_roles_path: loc = os.path.expanduser(loc) possible_paths.append(path_dwim(loc, role_name)) if namespace_name and collection_name: for loc in get_app(cached=True).runtime.config.collections_paths: loc = os.path.expanduser(loc) possible_paths.append( path_dwim( loc, os.path.join( "ansible_collections", namespace_name, collection_name, "roles", role_name, ), ), ) possible_paths.append(path_dwim(basedir, "")) for path_option in possible_paths: # pragma: no branch if os.path.isdir(path_option): role_path = path_option break if role_path: # pragma: no branch add_all_plugin_dirs(role_path) # type: ignore[no-untyped-call] return role_path def _get_task_handler_children_for_tasks_or_playbooks( task_handler: dict[str, Any], basedir: str, k: Any, parent_type: FileType, ) -> Lintable: """Try to get children of taskhandler for include/import tasks/playbooks.""" child_type = k if parent_type == "playbook" else parent_type # Include the FQCN task names as this happens before normalize for task_handler_key in INCLUSION_ACTION_NAMES: with contextlib.suppress(KeyError): # ignore empty tasks if not task_handler or isinstance(task_handler, str): # pragma: no branch continue file_name = "" action_args = task_handler[task_handler_key] if isinstance(action_args, str): (args, kwargs) = tokenize(action_args) if len(args) == 1: file_name = args[0] elif kwargs.get("file", None): file_name = kwargs["file"] else: # ignore invalid data (syntax check will outside the scope) continue if isinstance(action_args, Mapping) and action_args.get("file", None): file_name = action_args["file"] if not file_name: # ignore invalid data (syntax check will outside the scope) continue f = path_dwim(basedir, file_name) while basedir not in ["", "/"]: if os.path.exists(f): break basedir = os.path.dirname(basedir) f = path_dwim(basedir, file_name) return Lintable(f, kind=child_type) msg = f"The node contains none of: {', '.join(sorted(INCLUSION_ACTION_NAMES))}" raise LookupError(msg) def _sanitize_task(task: MutableMapping[str, Any]) -> MutableMapping[str, Any]: """Return a stripped-off task structure compatible with new Ansible. This helper takes a copy of the incoming task and drops any internally used keys from it. """ result = copy.deepcopy(task) # task is an AnsibleMapping which inherits from OrderedDict, so we need # to use `del` to remove unwanted keys. def remove_keys(obj: MutableMapping[str, Any]) -> MutableMapping[str, Any]: """Recursively removes specified keys from a nested dictionary or list. :param obj: The input dictionary or list to process. :param forbidden_keys: List of keys to remove from dictionaries. :return: A new object with forbidden keys removed. """ if isinstance(obj, MutableMapping): for key in [SKIPPED_RULES_KEY, FILENAME_KEY, LINE_NUMBER_KEY]: if key in obj: del obj[key] for value in obj.values(): if isinstance(value, MutableMapping): remove_keys(value) return obj # Base case: return non-dict, non-list values unchanged return remove_keys(result) def _extract_ansible_parsed_keys_from_task( result: MutableMapping[str, Any], task: MutableMapping[str, Any], keys: tuple[str, ...], ) -> MutableMapping[str, Any]: """Return a dict with existing key in task.""" for k, v in list(task.items()): if k in keys: # we don't want to re-assign these values, which were # determined by the ModuleArgsParser() above continue result[k] = v return result def normalize_task_v2(task: Task) -> MutableMapping[str, Any]: """Ensure tasks have a normalized action key and strings are converted to python objects.""" raw_task = task.raw_task result: MutableMapping[str, Any] = {} ansible_parsed_keys = ("action", "local_action", "args", "delegate_to") arguments = {} if is_nested_task(raw_task): _extract_ansible_parsed_keys_from_task(result, raw_task, ansible_parsed_keys) # Add dummy action for block/always/rescue statements result["action"] = { "__ansible_module__": "block/always/rescue", "__ansible_module_original__": "block/always/rescue", } return result sanitized_task = _sanitize_task(raw_task) mod_arg_parser = ModuleArgsParser(sanitized_task) # type: ignore[no-untyped-call] try: action, arguments, result["delegate_to"] = mod_arg_parser.parse( # type: ignore[no-untyped-call] skip_action_validation=options.skip_action_validation, ) except AnsibleParserError as exc: # pragma: no cover if "get_line_column" not in globals(): from ansiblelint.yaml_utils import get_line_column # pylint: disable=possibly-used-before-assignment line, column = get_line_column(raw_task, 0) if not line: line = 0 column = 0 regex = LINE_COLUMN_REGEX.search(exc.message) if regex: line = int(regex.group("line")) column = int(regex.group("column")) if not exc.message.startswith( "Complex args containing variables cannot use bare variables" ): raise MatchError( rule=AnsibleParserErrorRule(), message=exc.message, lintable=Lintable(task.filename or ""), lineno=line or 1, column=column or None, ) from exc result = sanitized_task if "action" not in result: msg = "Unable to normalize task" raise NotImplementedError(msg) from exc action = result["action"] # denormalize shell -> command conversion if "_uses_shell" in arguments: action = "shell" del arguments["_uses_shell"] _extract_ansible_parsed_keys_from_task( result, raw_task, (*ansible_parsed_keys, action), ) if not isinstance(action, str): msg = f"Task actions can only be strings, got {action}" raise TypeError(msg) action_unnormalized = action # convert builtin fqn calls to short forms because most rules know only # about short calls but in the future we may switch the normalization to do # the opposite. Mainly we currently consider normalized the module listing # used by `ansible-doc -t module -l 2>/dev/null` action = removeprefix(action, "ansible.builtin.") result["action"] = { "__ansible_module__": action, "__ansible_module_original__": action_unnormalized, } # Inject back original line number information into the task if ( action_unnormalized in task.raw_task and isinstance(task.raw_task[action_unnormalized], Mapping) and "__line__" in task.raw_task[action_unnormalized] ): result["action"]["__line__"] = task.raw_task[action_unnormalized]["__line__"] result["action"].update(arguments) return result # pylint: disable=too-many-nested-blocks def extract_from_list( blocks: AnsibleBaseYAMLObject, candidates: list[str], *, recursive: bool = False, ) -> list[Any]: """Get action tasks from block structures.""" results: list[Any] = [] if isinstance(blocks, Iterable): for block in blocks: for candidate in candidates: if isinstance(block, dict) and candidate in block: if isinstance(block[candidate], list): subresults = add_action_type(block[candidate], candidate) if recursive: subresults.extend( extract_from_list( subresults, candidates, recursive=recursive, ), ) results.extend(subresults) elif block[candidate] is not None: msg = f"Key '{candidate}' defined, but bad value: '{block[candidate]!s}'" raise RuntimeError(msg) return results @dataclass class Task(Mapping[str, Any]): """Class that represents a task from linter point of view. raw_task: When looping through the tasks in the file, each "raw_task" is minimally processed to include these special keys: __line__, __file__, skipped_rules. normalized_task: When each raw_task is "normalized", action shorthand (strings) get parsed by ansible into python objects and the action key gets normalized. If the task should be skipped (skipped is True) or normalizing it fails (error is not None) then this is just the raw_task instead of a normalized copy. skip_tags: List of tags found to be skipped, from tags block or noqa comments error: This is normally None. It will be a MatchError when the raw_task cannot be normalized due to an AnsibleParserError. position: The position of the task in the data structure using JSONPath like notation (no $ prefix). """ raw_task: MutableMapping[str, Any] filename: str = "" _normalized_task: MutableMapping[str, Any] | _MISSING_TYPE = field( init=False, repr=False ) error: MatchError | None = None position: str = "" kind: str = "tasks" def __post_init__(self) -> None: """Ensures that the task is valid.""" # This command ensures that we can print the task, ensuring that we # fail fast if someone tries to instantiate an invalid task. str(self) def __len__(self) -> int: """Return the length of the normalized task.""" return len(self.normalized_task) @property def name(self) -> str | None: """Return the name of the task.""" name = self.raw_task.get("name", None) if name is not None and not isinstance(name, str): # pragma: no cover msg = "Task name can only be a string." raise RuntimeError(msg) return name @property def action(self) -> str: """Return the resolved action name.""" action_name = self.normalized_task["action"]["__ansible_module_original__"] if not isinstance(action_name, str): msg = "Task actions can only be strings." raise TypeError(msg) return action_name @property def args(self) -> Any: """Return the arguments passed to the task action. While we usually expect to return a dictionary, it can also return a templated string when jinja is used. """ if "args" in self.raw_task: return self.raw_task["args"] result = { k: v for k, v in self.normalized_task["action"].items() if k not in ANNOTATION_KEYS } return result @property def normalized_task(self) -> MutableMapping[str, Any]: """Return the name of the task.""" if not hasattr(self, "_normalized_task"): try: self._normalized_task = self._normalize_task() except MatchError as err: self.error = err # When we cannot normalize it, we just use the raw task instead # to avoid adding extra complexity to the rules. self._normalized_task = self.raw_task if isinstance(self._normalized_task, _MISSING_TYPE): msg = "Task was not normalized" raise TypeError(msg) return self._normalized_task def _normalize_task(self) -> MutableMapping[str, Any]: """Unify task-like object structures.""" ansible_action_type = self.raw_task.get("__ansible_action_type__", "task") if "__ansible_action_type__" in self.raw_task: del self.raw_task["__ansible_action_type__"] # pragma: no cover task = normalize_task_v2(self) task[FILENAME_KEY] = self.filename task["__ansible_action_type__"] = ansible_action_type return task @property def skip_tags(self) -> list[str]: """Return the list of tags to skip.""" skip_tags: list[str] = self.raw_task.get(SKIPPED_RULES_KEY, []) return skip_tags def is_handler(self) -> bool: """Return true for tasks that are handlers.""" return self.kind == "handlers" def __str__(self) -> str: """Return a string representation of the task.""" name = self.get("name") if name: return str(name) action = self.get("action") if isinstance(action, str) or not isinstance(action, dict): return str(action) args = [ f"{k}={v}" for (k, v) in action.items() if k not in [ "__ansible_module__", "__ansible_module_original__", "_raw_params", LINE_NUMBER_KEY, FILENAME_KEY, ] ] raw_params = action.get("_raw_params", []) if isinstance(raw_params, list): for item in raw_params: args.extend(str(item)) else: args.append(raw_params) result = f"{action['__ansible_module__']} {' '.join(args)}" return result def __repr__(self) -> str: """Return a string representation of the task.""" result = f"Task('{self.name or self.action}'" if self.position: result += f" [{self.position}])" result += ")" return result def get(self, key: str, default: Any = None) -> Any: """Get a value from the task.""" return self.normalized_task.get(key, default) def __getitem__(self, index: str) -> Any: """Allow access as task[...].""" return self.normalized_task[index] def __iter__(self) -> Iterator[str]: """Provide support for 'key in task'.""" yield from (f for f in self.normalized_task) @property def line(self) -> int: """Return the line number of the task.""" result: int = 0 if "get_line_column" not in globals(): from ansiblelint.yaml_utils import get_line_column result, _ = get_line_column(self.raw_task) # pylint: disable=possibly-used-before-assignment if not result: # pragma: no cover x = self.get("action", {}) result = int(x.get(LINE_NUMBER_KEY, 0)) return result or 1 def get_error_line(self, path: list[str | int]) -> int: """Return error line number.""" ctx: Mapping[Any, Any] = self.normalized_task line = 1 if LINE_NUMBER_KEY in self.normalized_task: line = self.normalized_task[LINE_NUMBER_KEY] for _ in path: if ( isinstance(ctx, collections.abc.Container) and _ in ctx ): # isinstance(ctx, collections.abc.Container) and value = ctx.get( # pyright: ignore[reportAttributeAccessIssue] _ # pyright: ignore[reportArgumentType] ) if isinstance(value, Mapping): ctx = value if ( isinstance(ctx, collections.abc.Container) and LINE_NUMBER_KEY in ctx ): line = ctx[LINE_NUMBER_KEY] # pyright: ignore[reportIndexIssue] if not isinstance(line, int): # pragma: no cover msg = "Line number is not an integer" raise TypeError(msg) return line def task_in_list( data: AnsibleBaseYAMLObject, file: Lintable, kind: str, position: str = ".", ) -> Iterator[Task]: """Get action tasks from block structures.""" def each_entry( data: Sequence[Any] | AnsibleMapping, file: Lintable, kind: str, position: str ) -> Iterator[Task]: if not data or not isinstance(data, Iterable): return for entry_index, entry in enumerate(data): if not entry: continue pos_ = f"{position}[{entry_index}]" if isinstance(entry, MutableMapping): yield Task( entry, filename=file.filename, kind=kind, position=pos_, ) for block in [k for k in entry if k in NESTED_TASK_KEYS]: v = entry[block] if isinstance(v, AnsibleBaseYAMLObject): yield from task_in_list( data=v, file=file, kind=kind, position=f"{pos_}.{block}", ) if not isinstance(data, Sequence): return if kind == "playbook": attributes = ["tasks", "pre_tasks", "post_tasks", "handlers"] for item_index, item in enumerate(data): for attribute in attributes: if not isinstance(item, Mapping): continue if attribute in item: if isinstance(item[attribute], Sequence): yield from each_entry( item[attribute], file=file, kind="tasks" if "tasks" in attribute else "handlers", position=f"{position}[{item_index}].{attribute}", ) elif item[attribute] is not None: # pragma: no cover msg = f"Key '{attribute}' defined, but bad value: '{item[attribute]!s}'" raise RuntimeError(msg) elif isinstance(data, Sequence): yield from each_entry(data, file=file, position=position, kind=kind) def add_action_type( actions: AnsibleBaseYAMLObject, action_type: str ) -> AnsibleSequence: """Add action markers to task objects.""" results = AnsibleSequence() if isinstance(actions, Iterable): for action in actions: # ignore empty task if not action or isinstance(action, str): # pragma: no cover continue action["__ansible_action_type__"] = BLOCK_NAME_TO_ACTION_TYPE_MAP[ action_type ] results.append(action) return results @cache def parse_yaml_linenumbers( lintable: Lintable, ) -> AnsibleBaseYAMLObject | None: """Parse yaml as ansible.utils.parse_yaml but with linenumbers. The line numbers are stored in each node's LINE_NUMBER_KEY key. """ loader: AnsibleLoader result = AnsibleSequence() # signature of Composer.compose_node def compose_node(parent: yaml.nodes.Node | None, index: int) -> yaml.nodes.Node: # the line number where the previous token has ended (plus empty lines) node = Composer.compose_node(loader, parent, index) # type: ignore[no-untyped-call,arg-type,unused-ignore] if not isinstance(node, yaml.nodes.Node): msg = "Unexpected yaml data." raise TypeError(msg) if hasattr(loader, "line"): # pragma: no cover line = loader.line node.__line__ = line + 1 # type: ignore[attr-defined] return node # signature of AnsibleConstructor.construct_mapping def construct_mapping( node: yaml.MappingNode, deep: bool = False, # noqa: FBT002 ) -> AnsibleMapping: # pyright: ignore[reportArgumentType] mapping: AnsibleMapping = AnsibleConstructor.construct_mapping( loader, node, deep=deep ) # type: ignore[no-untyped-call] if hasattr(node, LINE_NUMBER_KEY): mapping[LINE_NUMBER_KEY] = getattr(node, LINE_NUMBER_KEY) else: if hasattr(mapping, "_line_number"): mapping[LINE_NUMBER_KEY] = mapping._line_number # noqa: SLF001 mapping[FILENAME_KEY] = lintable.path return mapping try: kwargs = {} if "vault_password" in inspect.getfullargspec(AnsibleLoader.__init__).args: kwargs["vault_password"] = DEFAULT_VAULT_PASSWORD # WARNING: 'unused-ignore' is needed below in order to allow mypy to # be passing with both pre-2.19 and post-2.19 versions of Ansible core. loader = AnsibleLoader(lintable.content, **kwargs) # type: ignore[no-untyped-call] # redefine Composer.compose_node loader.compose_node = compose_node # type: ignore[attr-defined,unused-ignore] # redefine AnsibleConstructor.construct_mapping loader.construct_mapping = construct_mapping # type: ignore[method-assign] # while Ansible only accepts single documents, we also need to load # multi-documents, as we attempt to load any YAML file, not only # Ansible managed ones. while True: data = loader.get_data() # type: ignore[no-untyped-call] if data is None: break result.append(data) except ( ParserError, ScannerError, yaml.constructor.ConstructorError, ruamel.yaml.parser.ParserError, ) as exc: msg = f"Failed to load YAML file: {lintable.path}" raise RuntimeError(msg) from exc if len(result) == 0: return None # empty documents if len(result) == 1: if not isinstance(result[0], AnsibleBaseYAMLObject): # pragma: no cover msg = "Unexpected yaml data." raise TypeError(msg) return result[0] return result def get_cmd_args(task: Mapping[str, Any]) -> str: """Extract the args from a cmd task as a string.""" if "cmd" in task["action"]: args = task["action"]["cmd"] else: args = task["action"].get("_raw_params", []) if not isinstance(args, str): return " ".join(args) return args def get_first_cmd_arg(task: Task) -> Any: """Extract the first arg from a cmd task.""" try: first_cmd_arg = get_cmd_args(task).split()[0] except IndexError: return None return first_cmd_arg def get_second_cmd_arg(task: Task) -> Any: """Extract the second arg from a cmd task.""" try: second_cmd_arg = get_cmd_args(task).split()[1] except IndexError: return None return second_cmd_arg def is_playbook(filename: str) -> bool: """Check if the file is a playbook. Given a filename, it should return true if it looks like a playbook. The function is not supposed to raise exceptions. """ # we assume is a playbook if we loaded a sequence of dictionaries where # at least one of these keys is present: playbooks_keys = { "gather_facts", "hosts", "import_playbook", "post_tasks", "pre_tasks", "roles", "tasks", } # makes it work with Path objects by converting them to strings if not isinstance(filename, str): filename = str(filename) try: f = parse_yaml_from_file(filename) except Exception as exc: # pylint: disable=broad-except # noqa: BLE001 _logger.warning( "Failed to load %s with %s, assuming is not a playbook.", filename, exc, ) else: # A playbook is a sequence of dictionaries that contain at least one # of the playbooks_keys each. if isinstance(f, Sequence): for item in f: if not isinstance(item, Mapping) or not playbooks_keys.intersection( item.keys() ): return False return True return False def get_lintables( opts: Options = options, args: list[str] | None = None, ) -> list[Lintable]: """Detect files and directories that are lintable.""" lintables: list[Lintable] = [] # passing args bypass auto-detection mode if args: for arg in args: lintable = Lintable(arg) lintables.append(lintable) else: for filename in discover_lintables(opts): path = Path(filename) lintables.append(Lintable(path)) # stage 2: guess roles from current lintables, as there is no unique # file that must be present in any kind of role. _extend_with_roles(lintables) return lintables def _extend_with_roles(lintables: list[Lintable]) -> None: """Detect roles among lintables and adds them to the list.""" for lintable in lintables: parts = lintable.path.parent.parts if "roles" in parts: role = lintable.path while role.parent.name != "roles" and role.name: role = role.parent if role.exists() and not role.is_file(): lintable = Lintable(role) if lintable.kind == "role" and lintable not in lintables: _logger.debug("Added role: %s", lintable) lintables.append(lintable) def convert_to_boolean(value: Any) -> bool: """Use Ansible to convert something to a boolean.""" return bool(boolean(value)) # type: ignore[no-untyped-call] def parse_examples_from_plugin(lintable: Lintable) -> tuple[int, str]: """Parse yaml inside plugin EXAMPLES string. Store a line number offset to realign returned line numbers later """ offset = 1 parsed = ast.parse(lintable.content) for child in parsed.body: if isinstance(child, ast.Assign): label = child.targets[0] if isinstance(label, ast.Name) and label.id == "EXAMPLES": offset = child.lineno - 1 break docs = read_docstring(str(lintable.path)) # type: ignore[no-untyped-call] examples = docs["plainexamples"] # Ignore the leading newline and lack of document start # as including those in EXAMPLES would be weird. return offset, (f"---{examples}" if examples else "") @lru_cache def load_plugin(name: str) -> PluginLoadContext: """Return loaded ansible plugin/module.""" loaded_module = action_loader.find_plugin_with_context( # type: ignore[no-untyped-call] name, ignore_deprecated=True, check_aliases=True, ) if not loaded_module.resolved: loaded_module = module_loader.find_plugin_with_context( # type: ignore[no-untyped-call] name, ignore_deprecated=True, check_aliases=True, ) if not loaded_module.resolved and name.startswith( "ansible.builtin." ): # pragma: no cover # fallback to core behavior of using legacy loaded_module = module_loader.find_plugin_with_context( # type: ignore[no-untyped-call] name.replace("ansible.builtin.", "ansible.legacy."), ignore_deprecated=True, check_aliases=True, ) if not isinstance(loaded_module, PluginLoadContext): # pragma: no cover msg = f"Failed to load plugin: {name}" raise TypeError(msg) return loaded_module def parse_fqcn(name: str) -> tuple[str, ...]: """Parse name parameter into FQCN segments.""" return tuple(name.split(".")) if is_fqcn(name) else ("", "", name) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/version.py���������������������������������������������0000664�0000000�0000000�00000001340�14773473560�0023210�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Ansible-lint version information.""" # this is the fallback SemVer version picked by setuptools_scm when tag # information is not available. __version__ = "0.1.dev1" __all__ = ("__version__",) from typing import TYPE_CHECKING # as either pyright or mypy have problems with these import fallbacks, we # avoid running them when doing type checking if not TYPE_CHECKING: try: from ._version import version as __version__ except ImportError: # pragma: no cover try: import pkg_resources # pylint: disable=import-error __version__ = pkg_resources.get_distribution("ansible-lint").version except Exception: # pylint: disable=broad-except # noqa: BLE001, S110 pass ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/src/ansiblelint/yaml_utils.py������������������������������������������0000664�0000000�0000000�00000143373�14773473560�0023722�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Utility helpers to simplify working with yaml-based data.""" # pylint: disable=too-many-lines from __future__ import annotations import functools import logging import os import re from collections.abc import Mapping from io import StringIO from pathlib import Path from re import Pattern from typing import TYPE_CHECKING, Any, cast import ruamel.yaml.events from ruamel.yaml.comments import CommentedMap, CommentedSeq, Format from ruamel.yaml.composer import ComposerError from ruamel.yaml.constructor import RoundTripConstructor from ruamel.yaml.emitter import Emitter, ScalarAnalysis # Module 'ruamel.yaml' does not explicitly export attribute 'YAML'; implicit reexport disabled # To make the type checkers happy, we import from ruamel.yaml.main instead. from ruamel.yaml.main import YAML from ruamel.yaml.parser import ParserError from ruamel.yaml.scalarint import HexInt, ScalarInt from yamllint.config import YamlLintConfig from ansiblelint.constants import ( ANNOTATION_KEYS, LINE_NUMBER_KEY, NESTED_TASK_KEYS, PLAYBOOK_TASK_KEYWORDS, ) from ansiblelint.utils import Task try: # ansible 2.19 + data tagging # cspell: ignore datatag from ansible._internal._datatag._tags import ( # type: ignore[import-not-found] # pyright: ignore[reportMissingImports] Origin, ) except ImportError: # pragma: no cover Origin = None if TYPE_CHECKING: # noinspection PyProtectedMember from collections.abc import Callable, Iterator, Sequence from ruamel.yaml.comments import LineCol from ruamel.yaml.nodes import ScalarNode from ruamel.yaml.representer import RoundTripRepresenter from ruamel.yaml.tokens import CommentToken from ansiblelint.file_utils import Lintable _logger = logging.getLogger(__name__) class CustomYamlLintConfig(YamlLintConfig): """Extension of YamlLintConfig.""" def __init__( self, content: str | None = None, file: str | Path | None = None, ) -> None: """Initialize config.""" super().__init__(content=content, file=file) # type: ignore[no-untyped-call] self.incompatible = "" def deannotate(data: Any) -> Any: """Remove our annotations like __file__ and __line__ and return a JSON serializable object.""" if isinstance(data, dict): result = data.copy() for key, value in data.items(): if key in ANNOTATION_KEYS: del result[key] else: result[key] = deannotate(value) return result if isinstance(data, list): return [deannotate(item) for item in data if item not in ANNOTATION_KEYS] return data def load_yamllint_config() -> CustomYamlLintConfig: """Load our default yamllint config and any customized override file.""" config = CustomYamlLintConfig(file=Path(__file__).parent / "data" / ".yamllint") config.incompatible = "" # if we detect local yamllint config we use it but raise a warning # as this is likely to get out of sync with our internal config. for path in [ ".yamllint", ".yamllint.yaml", ".yamllint.yml", os.getenv("YAMLLINT_CONFIG_FILE", ""), os.getenv("XDG_CONFIG_HOME", "~/.config") + "/yamllint/config", ]: file = Path(path).expanduser() if file.is_file(): _logger.debug( "Loading custom %s config file, this extends our " "internal yamllint config.", file, ) custom_config = CustomYamlLintConfig(file=str(file)) custom_config.extend(config) # type: ignore[no-untyped-call] config = custom_config break # Look for settings incompatible with our reformatting checks: list[tuple[str, str | int | bool]] = [ ( "comments.min-spaces-from-content", 1, ), ( "comments-indentation", False, ), ( "braces.min-spaces-inside", 0, ), ( "braces.max-spaces-inside", 1, ), ( "octal-values.forbid-implicit-octal", True, ), ( "octal-values.forbid-explicit-octal", True, ), # ( # "key-duplicates.forbid-duplicated-merge-keys", # v1.34.0+ # True, # ), # ( # "quoted-strings.quote-type", "double", # ), # ( # "quoted-strings.required", "only-when-needed", # ), ] errors = [] for setting, expected_value in checks: v = config.rules for key in setting.split("."): if not isinstance(v, dict): # pragma: no cover break if key not in v: # pragma: no cover break v = v[key] if v != expected_value: msg = f"{setting} must be {str(expected_value).lower()}" errors.append(msg) if errors: nl = "\n" msg = f"Found incompatible custom yamllint configuration ({file}), please either remove the file or edit it to comply with:{nl} - {(nl + ' - ').join(errors)}.{nl}{nl}Read https://ansible.readthedocs.io/projects/lint/rules/yaml/ for more details regarding why we have these requirements. Fix mode will not be available." config.incompatible = msg _logger.debug("Effective yamllint rules used: %s", config.rules) return config def nested_items_path( data_collection: Mapping[Any, Any] | list[Any], ignored_keys: Sequence[str] = (), ) -> Iterator[tuple[Any, Any, list[str | int]]]: """Iterate a nested data structure, yielding key/index, value, and parent_path. This is a recursive function that calls itself for each nested layer of data. Each iteration yields: 1. the current item's dictionary key or list index, 2. the current item's value, and 3. the path to the current item from the outermost data structure. For dicts, the yielded (1) key and (2) value are what ``dict.items()`` yields. For lists, the yielded (1) index and (2) value are what ``enumerate()`` yields. The final component, the parent path, is a list of dict keys and list indexes. The parent path can be helpful in providing error messages that indicate precisely which part of a yaml file (or other data structure) needs to be fixed. For example, given this playbook: .. code-block:: yaml - name: A play tasks: - name: A task debug: msg: foobar Here's the first and last yielded items: .. code-block:: python >>> playbook=[{"name": "a play", "tasks": [{"name": "a task", "debug": {"msg": "foobar"}}]}] >>> next( nested_items_path( playbook ) ) (0, {'name': 'a play', 'tasks': [{'name': 'a task', 'debug': {'msg': 'foobar'}}]}, []) >>> list( nested_items_path( playbook ) )[-1] ('msg', 'foobar', [0, 'tasks', 0, 'debug']) Note that, for outermost data structure, the parent path is ``[]`` because you do not need to descend into any nested dicts or lists to find the indicated key and value. If a rule were designed to prohibit "foobar" debug messages, it could use the parent path to provide a path to the problematic ``msg``. It might use a jq-style path in its error message: "the error is at ``.[0].tasks[0].debug.msg``". Or if a utility could automatically fix issues, it could use the path to descend to the parent object using something like this: .. code-block:: python target = data for segment in parent_path: target = target[segment] :param data_collection: The nested data (dicts or lists). :returns: each iteration yields the key (of the parent dict) or the index (lists) """ # As typing and mypy cannot effectively ensure we are called only with # valid data, we better ignore NoneType if data_collection is None: # pragma: no cover return data: Mapping[Any, Any] | list[Any] if isinstance(data_collection, Task): data = data_collection.normalized_task else: data = data_collection yield from _nested_items_path( data_collection=data, parent_path=[], ignored_keys=ignored_keys, ) def _nested_items_path( data_collection: Mapping[Any, Any] | list[Any], parent_path: list[str | int], ignored_keys: Sequence[str] = (), ) -> Iterator[tuple[Any, Any, list[str | int]]]: """Iterate through data_collection (internal implementation of nested_items_path). This is a separate function because callers of nested_items_path should not be using the parent_path param which is used in recursive _nested_items_path calls to build up the path to the parent object of the current key/index, value. """ # we have to cast each convert_to_tuples assignment or mypy complains # that both assignments (for dict and list) do not have the same type # convert_to_tuples_type = Callable[[], Iterator[tuple[str | int, Any]]] if isinstance(data_collection, Mapping): convert_data_collection_to_tuples = cast( "Callable[[], Iterator[tuple[str | int, Any]]]", functools.partial(data_collection.items), ) elif isinstance(data_collection, list): convert_data_collection_to_tuples = cast( "Callable[[], Iterator[tuple[str | int, Any]]]", functools.partial(enumerate, data_collection), ) else: msg = f"Expected a dict or a list but got {data_collection!r} of type '{type(data_collection)}'" raise TypeError(msg) for key, value in convert_data_collection_to_tuples(): if key in (*ANNOTATION_KEYS, *ignored_keys): continue yield key, value, parent_path if isinstance(value, dict | list): yield from _nested_items_path( data_collection=value, parent_path=[*parent_path, key], ) def get_path_to_play( lintable: Lintable, lineno: int, # 1-based ruamel_data: CommentedMap | CommentedSeq, ) -> list[str | int]: """Get the path to the play in the given file at the given line number.""" if lineno < 1: msg = f"expected lineno >= 1, got {lineno}" raise ValueError(msg) if lintable.kind != "playbook" or not isinstance(ruamel_data, CommentedSeq): return [] lc: LineCol # lc uses 0-based counts # lineno is 1-based. Convert to 0-based. line_index = lineno - 1 if line_index == 0: return [] prev_play_line_index = ruamel_data.lc.line last_play_index = len(ruamel_data) play_index = None for play_index, play in enumerate(ruamel_data): next_play_index = play_index + 1 if last_play_index > next_play_index: next_play_line_index = ruamel_data[next_play_index].lc.line else: next_play_line_index = None lc = play.lc if not isinstance(lc.line, int): # pragma: no cover msg = f"expected lc.line to be an int, got {lc.line!r}" raise TypeError(msg) if lc.line == line_index: return [play_index] if play_index > 0 and prev_play_line_index < line_index < lc.line: return [play_index - 1] # The previous play check (above) can't catch the last play, # so, handle the last play separately. if ( next_play_index == last_play_index and line_index <= lc.line and (next_play_line_index is None or line_index < next_play_line_index) ): # part of this (last) play return [play_index] prev_play_line_index = play.lc.line if play_index is None: return [] return [play_index] def get_path_to_task( lintable: Lintable, lineno: int, # 1-based ruamel_data: CommentedMap | CommentedSeq, ) -> list[str | int]: """Get the path to the task in the given file at the given line number.""" if lineno < 1: msg = f"expected lineno >= 1, got {lineno}" raise ValueError(msg) if lintable.kind in ("tasks", "handlers", "playbook"): if not isinstance(ruamel_data, CommentedSeq): # pragma: no cover msg = f"expected ruamel_data to be a CommentedSeq, got {ruamel_data!r}" raise ValueError(msg) if lintable.kind in ("tasks", "handlers"): return _get_path_to_task_in_tasks_block(lineno, ruamel_data) if lintable.kind == "playbook": return _get_path_to_task_in_playbook(lineno, ruamel_data) return [] def _get_path_to_task_in_playbook( lineno: int, # 1-based ruamel_data: CommentedSeq, ) -> list[str | int]: """Get the path to the task in the given playbook data at the given line number.""" last_play_index = len(ruamel_data) for play_index, play in enumerate(ruamel_data): next_play_index = play_index + 1 if last_play_index > next_play_index: next_play_line_index = ruamel_data[next_play_index].lc.line else: next_play_line_index = None # We clearly haven't found the right spot yet if a following play starts on an earlier line. if next_play_line_index and lineno > next_play_line_index: continue play_keys = list(play.keys()) for tasks_keyword in PLAYBOOK_TASK_KEYWORDS: if not play.get(tasks_keyword): continue try: next_keyword = play_keys[play_keys.index(tasks_keyword) + 1] except IndexError: next_block_line_index = None else: next_block_line_index = play.lc.data[next_keyword][0] # last_lineno_in_block is 1-based; next_*_line_index is 0-based # next_*_line_index - 1 to get line before next_*_line_index. # Then + 1 to make it a 1-based number. if next_block_line_index is not None: last_lineno_in_block = next_block_line_index elif next_play_line_index is not None: last_lineno_in_block = next_play_line_index else: last_lineno_in_block = None task_path = _get_path_to_task_in_tasks_block( lineno, play[tasks_keyword], last_lineno_in_block, ) if task_path: # mypy gets confused without this typehint tasks_keyword_path: list[int | str] = [ play_index, tasks_keyword, ] return tasks_keyword_path + list(task_path) # lineno is before first play or no tasks keywords in any of the plays return [] def _get_path_to_task_in_tasks_block( lineno: int, # 1-based tasks_block: CommentedSeq, last_lineno: int | None = None, # 1-based ) -> list[str | int]: """Get the path to the task in the given tasks block at the given line number.""" task: CommentedMap | None # lineno and last_lineno are 1-based. Convert to 0-based. line_index = lineno - 1 last_line_index = None if last_lineno is None else last_lineno - 1 # lc (LineCol) uses 0-based counts prev_task_line_index = tasks_block.lc.line last_task_index = len(tasks_block) for task_index, task in enumerate(tasks_block): next_task_index = task_index + 1 if last_task_index > next_task_index: if tasks_block[next_task_index] is not None: next_task_line_index = tasks_block[next_task_index].lc.line else: next_task_line_index = tasks_block.lc.item(next_task_index)[0] else: next_task_line_index = None if task is None: # create a dummy task to represent the null task task = CommentedMap() task.lc.line, task.lc.col = tasks_block.lc.item(task_index) nested_task_keys = set(task.keys()).intersection(set(NESTED_TASK_KEYS)) if nested_task_keys: subtask_path = _get_path_to_task_in_nested_tasks_block( lineno, task, nested_task_keys, next_task_line_index, ) if subtask_path: # mypy gets confused without this typehint task_path: list[str | int] = [task_index] return task_path + list(subtask_path) if not isinstance(task.lc.line, int): # pragma: no cover msg = f"expected task.lc.line to be an int, got {task.lc.line!r}" raise TypeError(msg) if task.lc.line == line_index: return [task_index] if task_index > 0 and prev_task_line_index < line_index < task.lc.line: return [task_index - 1] # The previous task check can't catch the last task, # so, handle the last task separately (also after subtask checks). # pylint: disable=too-many-boolean-expressions if ( next_task_index == last_task_index and line_index > task.lc.line and (next_task_line_index is None or line_index < next_task_line_index) and (last_line_index is None or line_index <= last_line_index) ): # part of this (last) task return [task_index] prev_task_line_index = task.lc.line # line is not part of this tasks block return [] def _get_path_to_task_in_nested_tasks_block( lineno: int, # 1-based task: CommentedMap, nested_task_keys: set[str], next_task_line_index: int | None = None, # 0-based ) -> list[str | int]: """Get the path to the task in the given nested tasks block.""" # loop through the keys in line order task_keys = list(task.keys()) task_keys_by_index = dict(enumerate(task_keys)) for task_index, task_key in enumerate(task_keys): nested_task_block = task[task_key] if task_key not in nested_task_keys or not nested_task_block: continue next_task_key = task_keys_by_index.get(task_index + 1, None) if next_task_key is not None: if task.lc.data[next_task_key][2] < lineno: continue next_task_key_line_index = task.lc.data[next_task_key][0] else: next_task_key_line_index = None # last_lineno_in_block is 1-based; next_*_line_index is 0-based # next_*_line_index - 1 to get line before next_*_line_index. # Then + 1 to make it a 1-based number. last_lineno_in_block = ( next_task_key_line_index if next_task_key_line_index is not None else next_task_line_index ) subtask_path = _get_path_to_task_in_tasks_block( lineno, nested_task_block, last_lineno_in_block, # 1-based ) if subtask_path: return [task_key, *list(subtask_path)] # line is not part of this nested tasks block return [] class OctalIntYAML11(ScalarInt): """OctalInt representation for YAML 1.1.""" # tell mypy that ScalarInt has these attributes _width: Any _underscore: Any def __new__(cls, *args: Any, **kwargs: Any) -> Any: """Create a new int with ScalarInt-defined attributes.""" return ScalarInt.__new__(cls, *args, **kwargs) @staticmethod def represent_octal(representer: RoundTripRepresenter, data: OctalIntYAML11) -> Any: """Return a YAML 1.1 octal representation. Based on ruamel.yaml.representer.RoundTripRepresenter.represent_octal_int() (which only handles the YAML 1.2 octal representation). """ v = format(data, "o") anchor = data.yaml_anchor(any=True) # noinspection PyProtectedMember return representer.insert_underscore( "0", v, data._underscore, anchor=anchor, ) class CustomConstructor(RoundTripConstructor): """Custom YAML constructor that preserves Octal formatting in YAML 1.1.""" def construct_yaml_int(self, node: ScalarNode) -> Any: """Construct int while preserving Octal formatting in YAML 1.1. ruamel.yaml only preserves the octal format for YAML 1.2. For 1.1, it converts the octal to an int. So, we preserve the format. Code partially copied from ruamel.yaml (MIT licensed). """ ret = super().construct_yaml_int(node) if self.resolver.processing_version == (1, 1) and isinstance(ret, int): # Do not rewrite zero as octal. if ret == 0: return ret # see if we've got an octal we need to preserve. value_su = self.construct_scalar(node) try: v = value_su.rstrip("_") underscore = [len(v) - v.rindex("_") - 1, False, False] # type: Any except ValueError: underscore = None except IndexError: # pragma: no cover underscore = None value_s = value_su.replace("_", "") if value_s[0] in "+-": value_s = value_s[1:] if value_s[0:2] == "0x": ret = HexInt(ret, width=len(value_s) - 2) elif value_s[0] == "0": # got an octal in YAML 1.1 ret = OctalIntYAML11( ret, width=None, underscore=underscore, anchor=node.anchor, ) return ret CustomConstructor.add_constructor( "tag:yaml.org,2002:int", CustomConstructor.construct_yaml_int, ) class FormattedEmitter(Emitter): """Emitter that applies custom formatting rules when dumping YAML. Differences from ruamel.yaml defaults: - indentation of root-level sequences - prefer double-quoted scalars over single-quoted scalars This ensures that root-level sequences are never indented. All subsequent levels are indented as configured (normal ruamel.yaml behavior). Earlier implementations used dedent on ruamel.yaml's dumped output, but string magic like that had a ton of problematic edge cases. """ preferred_quote = '"' # either " or ' min_spaces_inside = 0 max_spaces_inside = 1 _sequence_indent = 2 _sequence_dash_offset = 0 # Should be _sequence_indent - 2 _root_is_sequence = False _in_empty_flow_map = False @property def _is_root_level_sequence(self) -> bool: """Return True if this is a sequence at the root level of the yaml document.""" return self.column < 2 and self._root_is_sequence def expect_document_root(self) -> None: """Expect doc root (extend to record if the root doc is a sequence).""" self._root_is_sequence = isinstance( self.event, ruamel.yaml.events.SequenceStartEvent, ) return super().expect_document_root() # NB: mypy does not support overriding attributes with properties yet: # https://github.com/python/mypy/issues/4125 # To silence we have to ignore[override] both the @property and the method. @property def best_sequence_indent(self) -> int: """Return the configured sequence_indent or 2 for root level.""" return 2 if self._is_root_level_sequence else self._sequence_indent @best_sequence_indent.setter def best_sequence_indent(self, value: int) -> None: """Configure how many columns to indent each sequence item (including the '-').""" self._sequence_indent = value @property def sequence_dash_offset(self) -> int: """Return the configured sequence_dash_offset or 0 for root level.""" return 0 if self._is_root_level_sequence else self._sequence_dash_offset @sequence_dash_offset.setter def sequence_dash_offset(self, value: int) -> None: """Configure how many spaces to put before each sequence item's '-'.""" self._sequence_dash_offset = value def choose_scalar_style(self) -> Any: """Select how to quote scalars if needed.""" style = super().choose_scalar_style() if ( style == "" # noqa: PLC1901 and self.event.value.startswith("0") and len(self.event.value) > 1 ): # We have an as-yet unquoted token that starts with "0" (but is not itself the digit 0). # It could be: # - hexadecimal like "0xF1"; comes tagged as int. Should continue unquoted to continue as an int. # - octal like "0666" or "0o755"; comes tagged as str. **Should** be quoted to be cross-YAML compatible. # - string like "0.0.0.0" and "00-header". Should not be quoted, unless it has a quote in it. if ( self.event.value.startswith("0x") and self.event.tag == "tag:yaml.org,2002:int" and self.event.implicit[0] ): # hexadecimal self.event.tag = "tag:yaml.org,2002:str" return "" try: int(self.event.value, 8) except ValueError: pass # fallthrough to string else: # octal self.event.tag = "tag:yaml.org,2002:str" self.event.implicit = (True, True, True) return '"' if style != "'": # block scalar, double quoted, etc. return style if '"' in self.event.value: return "'" return self.preferred_quote def increase_indent( self, flow: bool = False, # noqa: FBT002 sequence: bool | None = None, indentless: bool = False, # noqa: FBT002 ) -> None: super().increase_indent(flow, sequence, indentless) # If our previous node was a sequence and we are still trying to indent, don't if self.indents.last_seq(): self.indent = self.column + 1 def write_indicator( self, indicator: str, # ruamel.yaml typehint is wrong. This is a string. need_whitespace: bool, whitespace: bool = False, # noqa: FBT002 indention: bool = False, # (sic) ruamel.yaml has this typo in their API # noqa: FBT002 ) -> None: """Make sure that flow maps get whitespace by the curly braces.""" # We try to go with one whitespace by the curly braces and adjust accordingly # to what min_spaces_inside and max_spaces_inside are set to. # This assumes min_spaces_inside <= max_spaces_inside spaces_inside = min( max(1, self.min_spaces_inside), self.max_spaces_inside if self.max_spaces_inside != -1 else 1, ) # If this is the end of the flow mapping that isn't on a new line: if ( indicator == "}" and (self.column or 0) > (self.indent or 0) and not self._in_empty_flow_map ): indicator = (" " * spaces_inside) + "}" # Indicator sometimes comes with embedded spaces we need to squish if indicator == " -" and self.indents.last_seq(): indicator = "-" super().write_indicator(indicator, need_whitespace, whitespace, indention) # if it is the start of a flow mapping, and it's not time # to wrap the lines, insert a space. if indicator == "{" and self.column < self.best_width: if self.check_empty_mapping(): self._in_empty_flow_map = True else: self.column += 1 self.stream.write(" " * spaces_inside) self._in_empty_flow_map = False # "/n/n" results in one blank line (end the previous line, then newline). # So, "/n/n/n" or more is too many new lines. Clean it up. _re_repeat_blank_lines: Pattern[str] = re.compile(r"\n{3,}") @staticmethod def add_octothorpe_protection(string: str) -> str: """Modify strings to protect "#" from full-line-comment post-processing.""" try: if "#" in string: # # is \uFF03 (fullwidth number sign) # ﹟ is \uFE5F (small number sign) string = string.replace("#", "\uff03#\ufe5f") # this is safe even if this sequence is present # because it gets reversed in post-processing except (ValueError, TypeError): # pragma: no cover # probably not really a string. Whatever. pass return string @staticmethod def drop_octothorpe_protection(string: str) -> str: """Remove string protection of "#" after full-line-comment post-processing.""" try: if "\uff03#\ufe5f" in string: # # is \uFF03 (fullwidth number sign) # ﹟ is \uFE5F (small number sign) string = string.replace("\uff03#\ufe5f", "#") except (ValueError, TypeError): # probably not really a string. Whatever. pass return string def analyze_scalar(self, scalar: str) -> ScalarAnalysis: """Determine quoting and other requirements for string. And protect "#" from full-line-comment post-processing. """ analysis: ScalarAnalysis = super().analyze_scalar(scalar) if analysis.empty: return analysis analysis.scalar = self.add_octothorpe_protection(analysis.scalar) return analysis # comment is a CommentToken, not Any (Any is ruamel.yaml's lazy type hint). def write_comment( self, comment: CommentToken, pre: bool = False, # noqa: FBT002 ) -> None: """Clean up extra new lines and spaces in comments. ruamel.yaml treats new or empty lines as comments. See: https://stackoverflow.com/questions/42708668/removing-all-blank-lines-but-not-comments-in-ruamel-yaml/42712747#42712747 """ value: str = comment.value if ( pre and not value.strip() and not isinstance( self.event, ruamel.yaml.events.CollectionEndEvent | ruamel.yaml.events.DocumentEndEvent | ruamel.yaml.events.StreamEndEvent | ruamel.yaml.events.MappingStartEvent, ) ): # drop pure whitespace pre comments # does not apply to End events since they consume one of the newlines. value = "" elif ( pre and not value.strip() and isinstance(self.event, ruamel.yaml.events.MappingStartEvent) ): value = self._re_repeat_blank_lines.sub("", value) elif pre: # preserve content in pre comment with at least one newline, # but no extra blank lines. value = self._re_repeat_blank_lines.sub("\n", value) else: # single blank lines in post comments value = self._re_repeat_blank_lines.sub("\n\n", value) comment.value = value # make sure that the eol comment only has one space before it. if comment.column > self.column + 1 and not pre: comment.column = self.column + 1 return super().write_comment(comment, pre) def write_version_directive(self, version_text: Any) -> None: """Skip writing '%YAML 1.1'.""" if version_text == "1.1": return super().write_version_directive(version_text) # pylint: disable=too-many-instance-attributes class FormattedYAML(YAML): """A YAML loader/dumper that handles ansible content better by default.""" default_config = { "explicit_start": True, "explicit_end": False, "width": 160, "indent_sequences": True, "preferred_quote": '"', "min_spaces_inside": 0, "max_spaces_inside": 1, } def __init__( # pylint: disable=too-many-arguments self, *, typ: str | None = None, pure: bool = False, output: Any = None, plug_ins: list[str] | None = None, version: tuple[int, int] | None = None, config: dict[str, bool | int | str] | None = None, ): """Return a configured ``ruamel.yaml.YAML`` instance. Some config defaults get extracted from the yamllint config. ``ruamel.yaml.YAML`` uses attributes to configure how it dumps yaml files. Some of these settings can be confusing, so here are examples of how different settings will affect the dumped yaml. This example does not indent any sequences: .. code:: python yaml.explicit_start=True yaml.map_indent=2 yaml.sequence_indent=2 yaml.sequence_dash_offset=0 .. code:: yaml --- - name: A playbook tasks: - name: Task This example indents all sequences including the root-level: .. code:: python yaml.explicit_start=True yaml.map_indent=2 yaml.sequence_indent=4 yaml.sequence_dash_offset=2 # yaml.Emitter defaults to ruamel.yaml.emitter.Emitter .. code:: yaml --- - name: Playbook tasks: - name: Task This example indents all sequences except at the root-level: .. code:: python yaml.explicit_start=True yaml.map_indent=2 yaml.sequence_indent=4 yaml.sequence_dash_offset=2 yaml.Emitter = FormattedEmitter # custom Emitter prevents root-level indents .. code:: yaml --- - name: Playbook tasks: - name: Task """ if version: if isinstance(version, str): # pragma: no cover x, y = version.split(".", maxsplit=1) version = (int(x), int(y)) self._yaml_version_default: tuple[int, int] = version self._yaml_version: tuple[int, int] = self._yaml_version_default super().__init__(typ=typ, pure=pure, output=output, plug_ins=plug_ins) # NB: We ignore some mypy issues because ruamel.yaml typehints are not great. if not config: config = self._defaults_from_yamllint_config() # these settings are derived from yamllint config self.explicit_start: bool = config["explicit_start"] # type: ignore[assignment] self.explicit_end: bool = config["explicit_end"] # type: ignore[assignment] self.width: int = config["width"] # type: ignore[assignment] indent_sequences: bool = cast("bool", config["indent_sequences"]) preferred_quote: str = cast("str", config["preferred_quote"]) # either ' or " min_spaces_inside: int = cast("int", config["min_spaces_inside"]) max_spaces_inside: int = cast("int", config["max_spaces_inside"]) self.default_flow_style = False self.compact_seq_seq = True # type: ignore[assignment] # dash after dash self.compact_seq_map = True # type: ignore[assignment] # key after dash # Do not use yaml.indent() as it obscures the purpose of these vars: self.map_indent = 2 self.sequence_indent = 4 if indent_sequences else 2 self.sequence_dash_offset = self.sequence_indent - 2 # If someone doesn't want our FormattedEmitter, they can change it. self.Emitter = FormattedEmitter # ignore invalid preferred_quote setting if preferred_quote in ['"', "'"]: FormattedEmitter.preferred_quote = preferred_quote # NB: default_style affects preferred_quote as well. # self.default_style ∈ None (default), '', '"', "'", '|', '>' # spaces inside braces for flow mappings FormattedEmitter.min_spaces_inside = min_spaces_inside FormattedEmitter.max_spaces_inside = max_spaces_inside # We need a custom constructor to preserve Octal formatting in YAML 1.1 self.Constructor = CustomConstructor self.Representer.add_representer(OctalIntYAML11, OctalIntYAML11.represent_octal) # We should preserve_quotes loads all strings as a str subclass that carries # a quote attribute. Will the str subclasses cause problems in transforms? # Are there any other gotchas to this? # # This will only preserve quotes for strings read from the file. # anything modified by the transform will use no quotes, preferred_quote, # or the quote that results in the least amount of escaping. self.preserve_quotes = True # If needed, we can use this to change null representation to be explicit # (see https://stackoverflow.com/a/44314840/1134951) # self.Representer.add_representer( @staticmethod def _defaults_from_yamllint_config() -> dict[str, bool | int | str]: """Extract FormattedYAML-relevant settings from yamllint config if possible.""" config = FormattedYAML.default_config for rule, rule_config in load_yamllint_config().rules.items(): if not rule_config: # rule disabled continue # refactor this if ... elif ... elif ... else monstrosity using match/case (PEP 634) once python 3.10 is mandatory if rule == "document-start": config["explicit_start"] = rule_config["present"] elif rule == "document-end": config["explicit_end"] = rule_config["present"] elif rule == "line-length": config["width"] = rule_config["max"] elif rule == "braces": min_spaces_inside = rule_config["min-spaces-inside"] if min_spaces_inside: config["min_spaces_inside"] = int(min_spaces_inside) max_spaces_inside = rule_config["max-spaces-inside"] if max_spaces_inside: config["max_spaces_inside"] = int(max_spaces_inside) elif rule == "indentation": indent_sequences = rule_config["indent-sequences"] # one of: bool, "whatever", "consistent" # so, we use True for "whatever" and "consistent" config["indent_sequences"] = bool(indent_sequences) elif rule == "quoted-strings": # pragma: no cover quote_type = rule_config["quote-type"] # one of: single, double, any if quote_type == "single": config["preferred_quote"] = "'" elif quote_type == "double": config["preferred_quote"] = '"' return cast("dict[str, bool | int | str]", config) @property def version(self) -> tuple[int, int] | None: """Return the YAML version used to parse or dump. Ansible uses PyYAML which only supports YAML 1.1. ruamel.yaml defaults to 1.2. So, we have to make sure we dump yaml files using YAML 1.1. We can relax the version requirement once ansible uses a version of PyYAML that includes this PR: https://github.com/yaml/pyyaml/pull/555 """ if hasattr(self, "_yaml_version"): return self._yaml_version return None @version.setter def version(self, val: tuple[int, int] | None) -> None: """Ensure that yaml version uses our default value. The yaml Reader updates this value based on the ``%YAML`` directive in files. So, if a file does not include the directive, it sets this to None. But, None effectively resets the parsing version to YAML 1.2 (ruamel's default). """ if val is not None: self._yaml_version = val elif hasattr(self, "_yaml_version_default"): self._yaml_version = self._yaml_version_default # We do nothing if the object did not have a previous default version defined def load(self, stream: Path | Any) -> Any: """Load YAML content from a string while avoiding known ruamel.yaml issues.""" if not isinstance(stream, str): # pragma: no cover msg = f"expected a str but got {type(stream)}" raise NotImplementedError(msg) # As ruamel drops comments for any document that is not a mapping or sequence, # we need to avoid using it to reformat those documents. # https://sourceforge.net/p/ruamel-yaml/tickets/460/ text, preamble_comment = self._pre_process_yaml(stream) try: data = super().load(stream=text) except ComposerError: data = self.load_all(stream=text) except ParserError: data = None _logger.error( # noqa: TRY400 "Invalid yaml, verify the file contents and try again.", ) if preamble_comment is not None and isinstance( data, CommentedMap | CommentedSeq, ): data.preamble_comment = preamble_comment # type: ignore[union-attr] # Because data can validly also be None for empty documents, we cannot # really annotate the return type here, so we need to remember to # never save None or scalar data types when reformatting. return data def dumps(self, data: Any) -> str: """Dump YAML document to string (including its preamble_comment).""" preamble_comment: str | None = getattr(data, "preamble_comment", None) self._prevent_wrapping_flow_style(data) with StringIO() as stream: if preamble_comment: stream.write(preamble_comment) self.dump(data, stream) text = stream.getvalue() strip_version_directive = hasattr(self, "_yaml_version_default") return self._post_process_yaml( text, strip_version_directive=strip_version_directive, strip_explicit_start=not self.explicit_start, ) def _prevent_wrapping_flow_style(self, data: Any) -> None: if not isinstance(data, CommentedMap | CommentedSeq): return for key, value, parent_path in nested_items_path(data): if not isinstance(value, CommentedMap | CommentedSeq): continue fa: Format = value.fa if fa.flow_style(): predicted_indent = self._predict_indent_length(parent_path, key) predicted_width = len(str(value)) if predicted_indent + predicted_width > self.width: # this flow-style map will probably get line-wrapped, # so, switch it to block style to avoid the line wrap. fa.set_block_style() def _predict_indent_length(self, parent_path: list[str | int], key: Any) -> int: indent = 0 # each parent_key type tells us what the indent is for the next level. for parent_key in parent_path: if isinstance(parent_key, int) and indent == 0: # root level is a sequence indent += self.sequence_dash_offset elif isinstance(parent_key, int): # next level is a sequence indent += cast("int", self.sequence_indent) elif isinstance(parent_key, str): # next level is a map indent += cast("int", self.map_indent) if isinstance(key, int) and indent == 0: # flow map is an item in a root-level sequence indent += self.sequence_dash_offset elif isinstance(key, int) and indent > 0: # flow map is in a sequence indent += cast("int", self.sequence_indent) elif isinstance(key, str): # flow map is in a map indent += len(key + ": ") return indent # ruamel.yaml only preserves empty (no whitespace) blank lines # (ie "/n/n" becomes "/n/n" but "/n /n" becomes "/n"). # So, we need to identify whitespace-only lines to drop spaces before reading. _whitespace_only_lines_re = re.compile(r"^ +$", re.MULTILINE) def _pre_process_yaml(self, text: str) -> tuple[str, str | None]: """Handle known issues with ruamel.yaml loading. Preserve blank lines despite extra whitespace. Preserve any preamble (aka header) comments before "---". For more on preamble comments, see: https://stackoverflow.com/questions/70286108/python-ruamel-yaml-package-how-to-get-header-comment-lines/70287507#70287507 """ text = self._whitespace_only_lines_re.sub("", text) # I investigated extending ruamel.yaml to capture preamble comments. # preamble comment goes from: # DocumentStartToken.comment -> DocumentStartEvent.comment # Then, in the composer: # once in composer.current_event # discards DocumentStartEvent # move DocumentStartEvent to composer.last_event # all document nodes get composed (events get used) # discard DocumentEndEvent # move DocumentEndEvent to composer.last_event # So, there's no convenient way to extend the composer # to somehow capture the comments and pass them on. preamble_comments = [] if "\n---\n" not in text and "\n--- " not in text: # nothing is before the document start mark, # so there are no comments to preserve. return text, None for line in text.splitlines(True): # We only need to capture the preamble comments. No need to remove them. # lines might also include directives. if line.lstrip().startswith("#") or line == "\n": preamble_comments.append(line) elif line.startswith("---"): break return text, "".join(preamble_comments) or None @staticmethod def _post_process_yaml( text: str, *, strip_version_directive: bool = False, strip_explicit_start: bool = False, ) -> str: """Handle known issues with ruamel.yaml dumping. Make sure there's only one newline at the end of the file. Fix the indent of full-line comments to match the indent of the next line. See: https://stackoverflow.com/questions/71354698/how-can-i-use-the-ruamel-yaml-rtsc-mode/71355688#71355688 Also, removes "#" protection from strings that prevents them from being identified as full line comments in post-processing. Make sure null list items don't end in a space. """ # remove YAML directive if strip_version_directive and text.startswith("%YAML"): text = text.split("\n", 1)[1] # remove explicit document start if strip_explicit_start and text.startswith("---"): text = text.split("\n", 1)[1] text = text.rstrip("\n") + "\n" lines = text.splitlines(keepends=True) full_line_comments: list[tuple[int, str]] = [] for i, line in enumerate(lines): stripped = line.lstrip() if not stripped: # blank line. Move on. continue space_length = len(line) - len(stripped) if stripped.startswith("#"): # got a full line comment # allow some full line comments to match the previous indent if i > 0 and not full_line_comments and space_length: prev = lines[i - 1] prev_space_length = len(prev) - len(prev.lstrip()) if prev_space_length == space_length: # if the indent matches the previous line's indent, skip it. continue full_line_comments.append((i, stripped)) elif full_line_comments: # match ident of previous non-blank line if not lines[i - 1].lstrip(): prev = lines[i - 2] space_length = len(prev) - len(prev.lstrip()) # end of full line comments so adjust to match indent of this line spaces = " " * space_length for index, comment in full_line_comments: lines[index] = spaces + comment full_line_comments.clear() if line.rpartition(" ")[2] == "\n": # drop any trailing spaces lines[i] = line.rstrip() + "\n" cleaned = line.strip() if not cleaned.startswith("#") and cleaned.endswith("-"): # got an empty list item. drop any trailing spaces. lines[i] = line.rstrip() + "\n" text = "".join( FormattedEmitter.drop_octothorpe_protection(line) for line in lines ) return text def clean_json( obj: Any, func: Callable[[str], Any] = lambda key: ( key.startswith("__") if isinstance(key, str) else False ), ) -> Any: """Remove all keys matching the condition from a nested JSON-like object. :param obj: a JSON like object to clean, also returned for chaining. :param func: a callable that takes a key in argument and return True for each key to delete """ if isinstance(obj, dict): for key in list(obj.keys()): if func(key): del obj[key] else: clean_json(obj[key], func) elif isinstance(obj, list): for i in reversed(range(len(obj))): if func(obj[i]): del obj[i] else: clean_json(obj[i], func) else: # neither a dict nor a list, do nothing pass return obj def get_line_column(data: object, default_line: int = 1) -> tuple[int, int | None]: """Return the line and column of the given data. Args: data: Object for which to introspect line number. default_line: fallback default line number to return if no line number is found. """ line = 0 column = None if isinstance(data, Mapping) and LINE_NUMBER_KEY in data: line = int(data[LINE_NUMBER_KEY]) if not line: # ansible 2.19+ if Origin: # pragma: no cover tag = Origin.get_tag(data) line = tag.line_num column = tag.col_num else: # pre-ansible 2.19 if hasattr(data, "ansible_pos"): # AnsibleUnicode object _, line, column = data.ansible_pos # pyright: ignore[reportAttributeAccessIssue] return (line or default_line, column) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/������������������������������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0017037�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/__init__.py�������������������������������������������������������0000664�0000000�0000000�00000000072�14773473560�0021147�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Use ansiblelint.testing instead for reusable tests.""" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/bar.txt�����������������������������������������������������������0000664�0000000�0000000�00000000011�14773473560�0020334�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������Bar file �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/conftest.py�������������������������������������������������������0000664�0000000�0000000�00000006505�14773473560�0021244�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""PyTest fixtures for testing the project.""" from __future__ import annotations import shutil import subprocess from pathlib import Path from typing import TYPE_CHECKING import pytest # pylint: disable=wildcard-import,unused-wildcard-import from ansiblelint.testing.fixtures import * # noqa: F403 from ansiblelint.yaml_utils import FormattedYAML if TYPE_CHECKING: from _pytest import nodes from _pytest.config import Config from _pytest.config.argparsing import Parser def pytest_addoption(parser: Parser) -> None: """Add --regenerate-formatting-fixtures option to pytest.""" parser.addoption( "--regenerate-formatting-fixtures", action="store_true", default=False, help="Regenerate formatting fixtures with prettier and internal formatter", ) def pytest_collection_modifyitems(items: list[nodes.Item], config: Config) -> None: """Skip tests based on --regenerate-formatting-fixtures option.""" do_regenerate = config.getoption("--regenerate-formatting-fixtures") skip_other = pytest.mark.skip( reason="not a formatting_fixture test and " "--regenerate-formatting-fixtures was specified", ) skip_formatting_fixture = pytest.mark.skip( reason="specify --regenerate-formatting-fixtures to " "only run formatting_fixtures test", ) for item in items: if do_regenerate and "formatting_fixtures" not in item.keywords: item.add_marker(skip_other) elif not do_regenerate and "formatting_fixtures" in item.keywords: item.add_marker(skip_formatting_fixture) def pytest_configure(config: Config) -> None: """Register custom markers.""" if config.getoption("--regenerate-formatting-fixtures"): regenerate_formatting_fixtures() def regenerate_formatting_fixtures() -> None: """Re-generate formatting fixtures with prettier and internal formatter. Pass ``--regenerate-formatting-fixtures`` to run this and skip all other tests. This is a "test" because once fixtures are regenerated, we run prettier again to make sure it does not change files formatted with our internal formatting code. """ subprocess.check_call(["which", "prettier"]) yaml = FormattedYAML() fixtures_dir = Path("test/fixtures/") fixtures_dir_before = fixtures_dir / "formatting-before" fixtures_dir_prettier = fixtures_dir / "formatting-prettier" fixtures_dir_after = fixtures_dir / "formatting-after" fixtures_dir_prettier.mkdir(exist_ok=True) fixtures_dir_after.mkdir(exist_ok=True) # Copying before fixtures... for fixture in fixtures_dir_before.glob("fmt-[0-9].yml"): shutil.copy(str(fixture), str(fixtures_dir_prettier / fixture.name)) shutil.copy(str(fixture), str(fixtures_dir_after / fixture.name)) # Writing fixtures with prettier... subprocess.check_call(["prettier", "-w", str(fixtures_dir_prettier)]) # NB: pre-commit end-of-file-fixer can also modify files. # Writing fixtures with ansiblelint.yaml_utils.FormattedYAML() for fixture in fixtures_dir_after.glob("fmt-[0-9].yml"): data = yaml.load(fixture.read_text()) output = yaml.dumps(data) fixture.write_text(output) # Make sure prettier won't make changes in {fixtures_dir_after} subprocess.check_call(["prettier", "-c", str(fixtures_dir_after)]) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/custom_rules/�����������������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0021563�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/custom_rules/__init__.py������������������������������������������0000664�0000000�0000000�00000000031�14773473560�0023666�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Dummy test module.""" �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/custom_rules/example_com/�����������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024054�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/custom_rules/example_com/__init__.py������������������������������0000664�0000000�0000000�00000000036�14773473560�0026164�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""A dummy test module #2.""" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/custom_rules/example_com/example_com_rule.py����������������������0000664�0000000�0000000�00000002374�14773473560�0027754�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Copyright (c) 2020, Ansible Project # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. """A dummy custom rule module #2.""" from ansiblelint.rules import AnsibleLintRule class ExampleComRule(AnsibleLintRule): """A dummy custom rule class.""" id = "100002" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/custom_rules/example_inc/�����������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024047�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/custom_rules/example_inc/__init__.py������������������������������0000664�0000000�0000000�00000000031�14773473560�0026152�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Dummy test module.""" �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/custom_rules/example_inc/custom_rule.py���������������������������0000664�0000000�0000000�00000002361�14773473560�0026764�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Copyright (c) 2020, Ansible Project # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. """Dummy custom rule module.""" from ansiblelint.rules import AnsibleLintRule class CustomRule(AnsibleLintRule): """Dummy custom rule class.""" id = "100001" �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/���������������������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0020710�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/__init__.py����������������������������������������������0000664�0000000�0000000�00000000036�14773473560�0023020�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Fixtures used in tests.""" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/ansible-config-invalid.yml�������������������������������0000664�0000000�0000000�00000000064�14773473560�0025737�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- # invalid .ansible-lint config file - foo - bar ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/ansible-config.yml���������������������������������������0000664�0000000�0000000�00000000062�14773473560�0024311�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- verbosity: 1 # vim: et:sw=2:syntax=yaml:ts=2: ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/broken-ansible.cfg/��������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024341�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/broken-ansible.cfg/ansible.cfg���������������������������0000664�0000000�0000000�00000000056�14773473560�0026440�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������[defaults] fact_caching_timeout=invalid-value ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/config-with-extra-vars.yml�������������������������������0000664�0000000�0000000�00000000067�14773473560�0025746�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- extra_vars: foo: bar knights_favorite_word: NI �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/config-with-relative-path.yml����������������������������0000664�0000000�0000000�00000000130�14773473560�0026406�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- exclude_paths: - ../../examples/roles/test-role/ # vim: et:sw=2:syntax=yaml:ts=2: ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/config-with-write-all.yml��������������������������������0000664�0000000�0000000�00000000030�14773473560�0025540�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- write_list: - all ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/config-with-write-none.yml�������������������������������0000664�0000000�0000000�00000000031�14773473560�0025730�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- write_list: - none �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/config-with-write-subset.yml�����������������������������0000664�0000000�0000000�00000000051�14773473560�0026300�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- write_list: - rule-tag - rule-id ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/exclude-paths-with-expands.yml���������������������������0000664�0000000�0000000�00000000142�14773473560�0026607�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- exclude_paths: - ~/.ansible/roles - $HOME/.ansible/roles # vim: et:sw=2:syntax=yaml:ts=2: ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/exclude-paths.yml����������������������������������������0000664�0000000�0000000�00000000074�14773473560�0024202�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- exclude_paths: - ../ # vim: et:sw=2:syntax=yaml:ts=2: ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-after/����������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024161�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-after/fmt-1.yml�������������������������������0000664�0000000�0000000�00000002330�14773473560�0025626�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- # ^ too many newlines before foo: bar # This is a comment has extra spaces preceding it fruits: # unindented sequence: - apple - orange vegetables: # indented sequence: - onion - carrot quoting: - "that should have double quotes" - "that should remain in single quotes" - 'a string with " inside' # next line has some undesired trailing spaces: - "a string with ' inside" - can't be sure! # next line should be converted to use double quotes: - ["foo", "bar"] inline-dictionary: - { foo: bar } # should add some spacing between curly braces and content - { foo2: bar2 } # should reduce spacing between curly braces and content # YAML 1.1 Boolean-hell: https://yaml.org/type/bool.html booleans-true: preferred: true # YAML 1.2 compatible! answer-1.1: true canonical-1.1: true canonical-upper-1.1: true logical-1.1: true option-1.1: true booleans-false: preferred: false # YAML 1.2 compatible! answer-1.1: false canonical-1.1: false canonical-upper-1.1: false logical-1.1: false option-1.1: false # ^ double newline should be removed overly-indented-vault-value: !vault | $ANSIBLE_VAULT;1.1;AES256 123466303630313 # this file also has 3 newlines at end-of-file instead of one ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-after/fmt-2.yml�������������������������������0000664�0000000�0000000�00000000667�14773473560�0025642�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# preamble/header comment --- # initial comment - foo: bar - baz: # over indented - qwerty - foobar animals: # under indented - crow - pig - giraffe - nothing: # null - octal: - "0o123" # YAML 1.2 octal - "0123" # YAML 1.1 octal - integer: - 0 # Not an octal. See #2071 - 10 - 9999 zero: 0 # Not an octal. See #2071 - string: - 0steps - 9steps - 0.0.0.0 - "0" - "01234" �������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-after/fmt-3.yml�������������������������������0000664�0000000�0000000�00000000773�14773473560�0025641�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- dummy_map: # eol comment # full line comment not indented something: # full line comment indented # next full line comment indented - or # 1 full line comments over indented # 2 full line comments over indented - other - | # this is part of a string not a yaml comment # also not a comment # comment before top-level second_key: - {} # should drop the extra space in flow map # comment before non top-level - {} # comment before non top-level - [] �����ansible-ansible-lint-c16f018/test/fixtures/formatting-after/fmt-4.yml�������������������������������0000664�0000000�0000000�00000000723�14773473560�0025635�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Gather all legacy facts cisco.ios.ios_facts: - name: Update modification and access time of given file ansible.builtin.file: path: /etc/some_file state: file modification_time: now access_time: now - name: Disable ufw service ansible.builtin.service: name: ufw enabled: false state: stopped when: '"ufw" in services' - name: Remove file (delete file) ansible.builtin.file: path: /etc/foo.txt state: absent ���������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-after/fmt-5.yml�������������������������������0000664�0000000�0000000�00000001114�14773473560�0025631�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Test this playbook hosts: all tasks: - name: Gather all legacy facts cisco.ios.ios_facts: - name: Update modification and access time of given file ansible.builtin.file: path: /etc/some_file state: file modification_time: now access_time: now - name: Disable ufw service ansible.builtin.service: name: ufw enabled: false state: stopped when: '"ufw" in services' - name: Remove file (delete file) ansible.builtin.file: path: /etc/foo.txt state: absent ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-after/fmt-hex.yml�����������������������������0000664�0000000�0000000�00000000041�14773473560�0026247�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- d: 0x123 # <-- hex e: 0x0123 �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-before/���������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024322�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-before/fmt-1.yml������������������������������0000664�0000000�0000000�00000002325�14773473560�0025773�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- # ^ too many newlines before foo: bar # This is a comment has extra spaces preceding it fruits: # unindented sequence: - apple - orange vegetables: # indented sequence: - onion - carrot quoting: - 'that should have double quotes' - 'that should remain in single quotes' - 'a string with " inside' # next line has some undesired trailing spaces: - "a string with ' inside" - can't be sure! # next line should be converted to use double quotes: - ['foo', 'bar'] inline-dictionary: - {foo: bar} # should add some spacing between curly braces and content - { foo2: bar2 } # should reduce spacing between curly braces and content # YAML 1.1 Boolean-hell: https://yaml.org/type/bool.html booleans-true: preferred: true # YAML 1.2 compatible! answer-1.1: YES canonical-1.1: y canonical-upper-1.1: Y logical-1.1: True option-1.1: on booleans-false: preferred: false # YAML 1.2 compatible! answer-1.1: NO canonical-1.1: n canonical-upper-1.1: N logical-1.1: False option-1.1: off # ^ double newline should be removed overly-indented-vault-value: !vault | $ANSIBLE_VAULT;1.1;AES256 123466303630313 # this file also has 3 newlines at end-of-file instead of one �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-before/fmt-2.yml������������������������������0000664�0000000�0000000�00000000726�14773473560�0025777�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# preamble/header comment --- # initial comment - foo: bar - baz: # over indented - qwerty - foobar animals: # under indented - crow - pig - giraffe - nothing: null # null - octal: - 0o123 # YAML 1.2 octal - 0123 # YAML 1.1 octal - integer: - 0 # Not an octal. See #2071 - 10 - 9999 zero: 0 # Not an octal. See #2071 - string: - 0steps - 9steps - 0.0.0.0 - "0" - "01234" ������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-before/fmt-3.yml������������������������������0000664�0000000�0000000�00000001012�14773473560�0025765�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- dummy_map: # eol comment # full line comment not indented something: # full line comment indented # next full line comment indented - or # 1 full line comments over indented # 2 full line comments over indented - other - | # this is part of a string not a yaml comment # also not a comment # comment before top-level second_key: - { } # should drop the extra space in flow map # comment before non top-level - {} # comment before non top-level - [] ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-before/fmt-4.yml������������������������������0000664�0000000�0000000�00000000726�14773473560�0026001�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Gather all legacy facts cisco.ios.ios_facts: - name: Update modification and access time of given file ansible.builtin.file: path: /etc/some_file state: file modification_time: now access_time: now - name: Disable ufw service ansible.builtin.service: name: ufw enabled: false state: stopped when: '"ufw" in services' - name: Remove file (delete file) ansible.builtin.file: path: /etc/foo.txt state: absent ������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-before/fmt-5.yml������������������������������0000664�0000000�0000000�00000001117�14773473560�0025775�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Test this playbook hosts: all tasks: - name: Gather all legacy facts cisco.ios.ios_facts: - name: Update modification and access time of given file ansible.builtin.file: path: /etc/some_file state: file modification_time: now access_time: now - name: Disable ufw service ansible.builtin.service: name: ufw enabled: false state: stopped when: '"ufw" in services' - name: Remove file (delete file) ansible.builtin.file: path: /etc/foo.txt state: absent �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-before/fmt-hex.yml����������������������������0000664�0000000�0000000�00000000042�14773473560�0026411�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- d: 0x123 # <-- hex e: 0x0123 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-prettier/�������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024716�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-prettier/fmt-1.yml����������������������������0000664�0000000�0000000�00000002303�14773473560�0026363�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- # ^ too many newlines before foo: bar # This is a comment has extra spaces preceding it fruits: # unindented sequence: - apple - orange vegetables: # indented sequence: - onion - carrot quoting: - "that should have double quotes" - "that should remain in single quotes" - 'a string with " inside' # next line has some undesired trailing spaces: - "a string with ' inside" - can't be sure! # next line should be converted to use double quotes: - ["foo", "bar"] inline-dictionary: - { foo: bar } # should add some spacing between curly braces and content - { foo2: bar2 } # should reduce spacing between curly braces and content # YAML 1.1 Boolean-hell: https://yaml.org/type/bool.html booleans-true: preferred: true # YAML 1.2 compatible! answer-1.1: YES canonical-1.1: y canonical-upper-1.1: Y logical-1.1: True option-1.1: on booleans-false: preferred: false # YAML 1.2 compatible! answer-1.1: NO canonical-1.1: n canonical-upper-1.1: N logical-1.1: False option-1.1: off # ^ double newline should be removed overly-indented-vault-value: !vault | $ANSIBLE_VAULT;1.1;AES256 123466303630313 # this file also has 3 newlines at end-of-file instead of one �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-prettier/fmt-2.yml����������������������������0000664�0000000�0000000�00000000674�14773473560�0026375�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# preamble/header comment --- # initial comment - foo: bar - baz: # over indented - qwerty - foobar animals: # under indented - crow - pig - giraffe - nothing: null # null - octal: - "0o123" # YAML 1.2 octal - "0123" # YAML 1.1 octal - integer: - 0 # Not an octal. See #2071 - 10 - 9999 zero: 0 # Not an octal. See #2071 - string: - 0steps - 9steps - 0.0.0.0 - "0" - "01234" ��������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-prettier/fmt-3.yml����������������������������0000664�0000000�0000000�00000000777�14773473560�0026402�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- dummy_map: # eol comment # full line comment not indented something: # full line comment indented # next full line comment indented - or # 1 full line comments over indented # 2 full line comments over indented - other - | # this is part of a string not a yaml comment # also not a comment # comment before top-level second_key: - {} # should drop the extra space in flow map # comment before non top-level - {} # comment before non top-level - [] �ansible-ansible-lint-c16f018/test/fixtures/formatting-prettier/fmt-4.yml����������������������������0000664�0000000�0000000�00000000723�14773473560�0026372�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Gather all legacy facts cisco.ios.ios_facts: - name: Update modification and access time of given file ansible.builtin.file: path: /etc/some_file state: file modification_time: now access_time: now - name: Disable ufw service ansible.builtin.service: name: ufw enabled: false state: stopped when: '"ufw" in services' - name: Remove file (delete file) ansible.builtin.file: path: /etc/foo.txt state: absent ���������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-prettier/fmt-5.yml����������������������������0000664�0000000�0000000�00000001114�14773473560�0026366�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Test this playbook hosts: all tasks: - name: Gather all legacy facts cisco.ios.ios_facts: - name: Update modification and access time of given file ansible.builtin.file: path: /etc/some_file state: file modification_time: now access_time: now - name: Disable ufw service ansible.builtin.service: name: ufw enabled: false state: stopped when: '"ufw" in services' - name: Remove file (delete file) ansible.builtin.file: path: /etc/foo.txt state: absent ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/formatting-prettier/fmt-hex.yml��������������������������0000664�0000000�0000000�00000000041�14773473560�0027004�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- d: 0x123 # <-- hex e: 0x0123 �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/list-rules-tests/����������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024153�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/list-rules-tests/.yamllint�������������������������������0000664�0000000�0000000�00000000007�14773473560�0026002�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- {} �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/parseable.yml��������������������������������������������0000664�0000000�0000000�00000000065�14773473560�0023372�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- parseable: true # vim: et:sw=2:syntax=yaml:ts=2: ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/quiet.yml������������������������������������������������0000664�0000000�0000000�00000000061�14773473560�0022557�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- quiet: true # vim: et:sw=2:syntax=yaml:ts=2: �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/rulesdir-defaults.yml������������������������������������0000664�0000000�0000000�00000000123�14773473560�0025065�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- rulesdir: - ./rules use_default_rules: true # vim: et:sw=2:syntax=yaml:ts=2: ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/rulesdir.yml���������������������������������������������0000664�0000000�0000000�00000000073�14773473560�0023264�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- rulesdir: - ./rules # vim: et:sw=2:syntax=yaml:ts=2: ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/show-abspath.yml�����������������������������������������0000664�0000000�0000000�00000000077�14773473560�0024037�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- display_relative_path: false # vim: et:sw=2:syntax=2:ts=2: �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/show-relpath.yml�����������������������������������������0000664�0000000�0000000�00000000076�14773473560�0024053�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- display_relative_path: true # vim: et:sw=2:syntax=2:ts=2: ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/skip-tags.yml��������������������������������������������0000664�0000000�0000000�00000000074�14773473560�0023336�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- skip_list: - bad_tag # vim: et:sw=2:syntax=yaml:ts=2: ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/strict.yml�����������������������������������������������0000664�0000000�0000000�00000000062�14773473560�0022741�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- strict: true # vim: et:sw=2:syntax=yaml:ts=2: ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/tags.yml�������������������������������������������������0000664�0000000�0000000�00000000101�14773473560�0022361�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- tags: - skip_ansible_lint # vim: et:sw=2:syntax=yaml:ts=2: ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/unknown-type.yml�����������������������������������������0000664�0000000�0000000�00000000016�14773473560�0024106�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- some: map ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/verbosity-tests/�����������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024076�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/verbosity-tests/.yamllint��������������������������������0000664�0000000�0000000�00000000007�14773473560�0025725�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- {} �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/verbosity-tests/tasks/�����������������������������������0000775�0000000�0000000�00000000000�14773473560�0025223�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/verbosity-tests/tasks/main.yml���������������������������0000664�0000000�0000000�00000000000�14773473560�0026660�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/fixtures/verbosity.yml��������������������������������������������0000664�0000000�0000000�00000000062�14773473560�0023457�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- verbosity: 1 # vim: et:sw=2:syntax=yaml:ts=2: ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/foo.txt�����������������������������������������������������������0000664�0000000�0000000�00000000011�14773473560�0020353�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������Foo file �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/����������������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0021601�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/README.md�������������������������������������������0000664�0000000�0000000�00000000577�14773473560�0023071�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������The reason that every roles test gets its own directory is that while they use the same three roles, the way the tests work makes sure that when the second one runs, the roles and their local plugins from the first test are still known to Ansible. For that reason, their names reflect the directory they are in to make sure that tests don't use modules/plugins found by other tests. ���������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/collections/����������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024117�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/collections/ansible_collections/��������������������0000775�0000000�0000000�00000000000�14773473560�0030132�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/collections/ansible_collections/testns/�������������0000775�0000000�0000000�00000000000�14773473560�0031452�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������test_collection/������������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0034565�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/collections/ansible_collections/testns���������������������������������������������������������������������������������galaxy.yml������������������������������������������������������������������������������������������0000664�0000000�0000000�00000000073�14773473560�0036575�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/collections/ansible_collections/testns/test_collection�����������������������������������������������������������������--- namespace: testns name: test_collection version: 0.1.0 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������plugins/��������������������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0036246�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/collections/ansible_collections/testns/test_collection�����������������������������������������������������������������filter/���������������������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0037533�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/collections/ansible_collections/testns/test_collection/plugins���������������������������������������������������������test_filter.py��������������������������������������������������������������������������������������0000664�0000000�0000000�00000000505�14773473560�0042431�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/collections/ansible_collections/testns/test_collection/plugins/filter��������������������������������������������������"""A filter plugin.""" def a_test_filter(a, b): """Return a string containing both a and b.""" return f"{a}:{b}" # pylint: disable=too-few-public-methods class FilterModule: """Filter plugin.""" @staticmethod def filters(): """Return filters.""" return {"test_filter": a_test_filter} �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������modules/��������������������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0037716�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/collections/ansible_collections/testns/test_collection/plugins���������������������������������������������������������test_module_2.py������������������������������������������������������������������������������������0000775�0000000�0000000�00000000364�14773473560�0043043�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/collections/ansible_collections/testns/test_collection/plugins/modules�������������������������������������������������#!/usr/bin/python """A module.""" from ansible.module_utils.basic import AnsibleModule def main() -> None: """Execute module.""" module = AnsibleModule({}) module.exit_json(msg="Hello 2!") if __name__ == "__main__": main() ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-collection.yml���������������������������������0000664�0000000�0000000�00000000514�14773473560�0025434�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Use module and filter plugin from local collection hosts: localhost tasks: - name: Use module from local collection testns.test_collection.test_module_2: - name: Use filter from local collection ansible.builtin.assert: that: - 1 | testns.test_collection.test_filter(2) == '1:2' ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed-complete/�������������������������0000775�0000000�0000000�00000000000�14773473560�0026732�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed-complete/roles/�������������������0000775�0000000�0000000�00000000000�14773473560�0030056�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed-complete/roles/role1/�������������0000775�0000000�0000000�00000000000�14773473560�0031100�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed-complete/roles/role1/library/�����0000775�0000000�0000000�00000000000�14773473560�0032544�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������test_module_1_failed_complete.py��������������������������������������������������������������������0000775�0000000�0000000�00000000364�14773473560�0041005�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/test-roles-failed-complete/roles/role1/library�������������������������������������������������������������������������#!/usr/bin/python """A module.""" from ansible.module_utils.basic import AnsibleModule def main() -> None: """Execute module.""" module = AnsibleModule({}) module.exit_json(msg="Hello 1!") if __name__ == "__main__": main() ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed-complete/roles/role1/tasks/�������0000775�0000000�0000000�00000000000�14773473560�0032225�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������main.yml��������������������������������������������������������������������������������������������0000664�0000000�0000000�00000000100�14773473560�0033604�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/test-roles-failed-complete/roles/role1/tasks���������������������������������������������������������������������������--- - name: Use local module 1 test_module_1_failed_complete: ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed-complete/roles/role2/�������������0000775�0000000�0000000�00000000000�14773473560�0031101�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed-complete/roles/role2/tasks/�������0000775�0000000�0000000�00000000000�14773473560�0032226�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������main.yml��������������������������������������������������������������������������������������������0000664�0000000�0000000�00000000712�14773473560�0033616�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/test-roles-failed-complete/roles/role2/tasks���������������������������������������������������������������������������--- - name: Use local module from other role that has been included before this one # If it has not been included before, loading this role fails! test_module_1_failed_complete: - name: Use local module from other role that has been included before this one # If it has not been included before, loading this role fails! test_module_3_failed_complete: - name: Use local test plugin assert: that: - "'2' is b_test_failed_complete '12345'" ������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed-complete/roles/role2/test_plugins/0000775�0000000�0000000�00000000000�14773473560�0033621�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������b_failed_complete.py��������������������������������������������������������������������������������0000664�0000000�0000000�00000000546�14773473560�0037536�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/test-roles-failed-complete/roles/role2/test_plugins��������������������������������������������������������������������"""A test plugin.""" def compatibility_in_test(a, b): """Return True when a is contained in b.""" return a in b # pylint: disable=too-few-public-methods class TestModule: """Test plugin.""" @staticmethod def tests(): """Return tests.""" return { "b_test_failed_complete": compatibility_in_test, } ����������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed-complete/roles/role3/�������������0000775�0000000�0000000�00000000000�14773473560�0031102�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed-complete/roles/role3/library/�����0000775�0000000�0000000�00000000000�14773473560�0032546�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������test_module_3_failed_complete.py��������������������������������������������������������������������0000775�0000000�0000000�00000000364�14773473560�0041011�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/test-roles-failed-complete/roles/role3/library�������������������������������������������������������������������������#!/usr/bin/python """A module.""" from ansible.module_utils.basic import AnsibleModule def main() -> None: """Execute module.""" module = AnsibleModule({}) module.exit_json(msg="Hello 3!") if __name__ == "__main__": main() ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed-complete/roles/role3/tasks/�������0000775�0000000�0000000�00000000000�14773473560�0032227�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������main.yml��������������������������������������������������������������������������������������������0000664�0000000�0000000�00000000100�14773473560�0033606�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/test-roles-failed-complete/roles/role3/tasks���������������������������������������������������������������������������--- - name: Use local module 3 test_module_3_failed_complete: ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed/����������������������������������0000775�0000000�0000000�00000000000�14773473560�0025124�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed/roles/����������������������������0000775�0000000�0000000�00000000000�14773473560�0026250�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed/roles/role1/����������������������0000775�0000000�0000000�00000000000�14773473560�0027272�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed/roles/role1/library/��������������0000775�0000000�0000000�00000000000�14773473560�0030736�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������test_module_1_failed.py�����������������������������������������������������������������������������0000775�0000000�0000000�00000000364�14773473560�0035307�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/test-roles-failed/roles/role1/library����������������������������������������������������������������������������������#!/usr/bin/python """A module.""" from ansible.module_utils.basic import AnsibleModule def main() -> None: """Execute module.""" module = AnsibleModule({}) module.exit_json(msg="Hello 1!") if __name__ == "__main__": main() ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed/roles/role1/tasks/����������������0000775�0000000�0000000�00000000000�14773473560�0030417�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed/roles/role1/tasks/main.yml��������0000664�0000000�0000000�00000000067�14773473560�0032071�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Use local module 1 test_module_1_failed: �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed/roles/role2/����������������������0000775�0000000�0000000�00000000000�14773473560�0027273�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed/roles/role2/tasks/����������������0000775�0000000�0000000�00000000000�14773473560�0030420�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed/roles/role2/tasks/main.yml��������0000664�0000000�0000000�00000000657�14773473560�0032077�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Use local module from other role that has been included before this one # If it has not been included before, loading this role fails! test_module_1_failed: - name: Use local module from other role that has been included before this one # If it has not been included before, loading this role fails! test_module_3_failed: - name: Use local test plugin assert: that: - "'2' is b_test_failed '12345'" ���������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed/roles/role2/test_plugins/���������0000775�0000000�0000000�00000000000�14773473560�0032013�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������b_failed.py�����������������������������������������������������������������������������������������0000664�0000000�0000000�00000000607�14773473560�0034036�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/test-roles-failed/roles/role2/test_plugins�����������������������������������������������������������������������������"""A test plugin.""" def compatibility_in_test(element, container): """Return True when element is contained in container.""" return element in container # pylint: disable=too-few-public-methods class TestModule: """Test plugin.""" @staticmethod def tests(): """Return tests.""" return { "b_test_failed": compatibility_in_test, } �������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed/roles/role3/����������������������0000775�0000000�0000000�00000000000�14773473560�0027274�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed/roles/role3/library/��������������0000775�0000000�0000000�00000000000�14773473560�0030740�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������test_module_3_failed.py�����������������������������������������������������������������������������0000775�0000000�0000000�00000000364�14773473560�0035313�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/test-roles-failed/roles/role3/library����������������������������������������������������������������������������������#!/usr/bin/python """A module.""" from ansible.module_utils.basic import AnsibleModule def main() -> None: """Execute module.""" module = AnsibleModule({}) module.exit_json(msg="Hello 3!") if __name__ == "__main__": main() ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed/roles/role3/tasks/����������������0000775�0000000�0000000�00000000000�14773473560�0030421�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed/roles/role3/tasks/main.yml��������0000664�0000000�0000000�00000000067�14773473560�0032073�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Use local module 3 test_module_3_failed: �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-failed/test.yml��������������������������0000664�0000000�0000000�00000000216�14773473560�0026625�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Use roles with local module in wrong order, so that Ansible fails hosts: localhost roles: - role2 - role3 - role1 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-success/���������������������������������0000775�0000000�0000000�00000000000�14773473560�0025350�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-success/roles/���������������������������0000775�0000000�0000000�00000000000�14773473560�0026474�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-success/roles/role1/���������������������0000775�0000000�0000000�00000000000�14773473560�0027516�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-success/roles/role1/library/�������������0000775�0000000�0000000�00000000000�14773473560�0031162�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������test_module_1_success.py����������������������������������������������������������������������������0000775�0000000�0000000�00000000364�14773473560�0035757�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/test-roles-success/roles/role1/library���������������������������������������������������������������������������������#!/usr/bin/python """A module.""" from ansible.module_utils.basic import AnsibleModule def main() -> None: """Execute module.""" module = AnsibleModule({}) module.exit_json(msg="Hello 1!") if __name__ == "__main__": main() ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-success/roles/role1/tasks/���������������0000775�0000000�0000000�00000000000�14773473560�0030643�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-success/roles/role1/tasks/main.yml�������0000664�0000000�0000000�00000000070�14773473560�0032307�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Use local module 1 test_module_1_success: ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-success/roles/role2/���������������������0000775�0000000�0000000�00000000000�14773473560�0027517�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-success/roles/role2/tasks/���������������0000775�0000000�0000000�00000000000�14773473560�0030644�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-success/roles/role2/tasks/main.yml�������0000664�0000000�0000000�00000000662�14773473560�0032317�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Use local module from other role that has been included before this one # If it has not been included before, loading this role fails! test_module_1_success: - name: Use local module from other role that has been included before this one # If it has not been included before, loading this role fails! test_module_3_success: - name: Use local test plugin assert: that: - "'2' is b_test_success '12345'" ������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-success/roles/role2/test_plugins/��������0000775�0000000�0000000�00000000000�14773473560�0032237�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������b_success.py����������������������������������������������������������������������������������������0000664�0000000�0000000�00000000605�14773473560�0034504�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/test-roles-success/roles/role2/test_plugins����������������������������������������������������������������������������"""A test plugin.""" def compatibility_in_test(element, container): """Return True when element contained in container.""" return element in container # pylint: disable=too-few-public-methods class TestModule: """Test plugin.""" @staticmethod def tests(): """Return tests.""" return { "b_test_success": compatibility_in_test, } ���������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-success/roles/role3/���������������������0000775�0000000�0000000�00000000000�14773473560�0027520�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-success/roles/role3/library/�������������0000775�0000000�0000000�00000000000�14773473560�0031164�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������test_module_3_success.py����������������������������������������������������������������������������0000775�0000000�0000000�00000000364�14773473560�0035763�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/local-content/test-roles-success/roles/role3/library���������������������������������������������������������������������������������#!/usr/bin/python """A module.""" from ansible.module_utils.basic import AnsibleModule def main() -> None: """Execute module.""" module = AnsibleModule({}) module.exit_json(msg="Hello 3!") if __name__ == "__main__": main() ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-success/roles/role3/tasks/���������������0000775�0000000�0000000�00000000000�14773473560�0030645�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/local-content/test-roles-success/roles/role3/tasks/main.yml�������0000664�0000000�0000000�00000000070�14773473560�0032311�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Use local module 3 test_module_3_success: ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/rules/������������������������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0020171�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/rules/__init__.py�������������������������������������������������0000664�0000000�0000000�00000000040�14773473560�0022274�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for specific rules.""" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/rules/fixtures/���������������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0022042�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/rules/fixtures/__init__.py����������������������������������������0000664�0000000�0000000�00000000034�14773473560�0024150�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test rules resources.""" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/rules/fixtures/ematcher.py����������������������������������������0000664�0000000�0000000�00000000611�14773473560�0024202�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Custom rule used as fixture.""" from ansiblelint.rules import AnsibleLintRule class EMatcherRule(AnsibleLintRule): """BANNED string found.""" id = "TEST0001" description = ( "This is a test custom rule that looks for lines containing BANNED string" ) tags = ["fake", "dummy", "test1"] def match(self, line: str) -> bool: return "BANNED" in line �����������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/rules/fixtures/raw_task.md����������������������������������������0000664�0000000�0000000�00000000124�14773473560�0024174�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# raw-task This is a test rule that looks in a raw task to flag raw action params. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/rules/fixtures/raw_task.py����������������������������������������0000664�0000000�0000000�00000001574�14773473560�0024236�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test Rule that needs_raw_task.""" from __future__ import annotations 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 RawTaskRule(AnsibleLintRule): """Test rule that inspects the raw task.""" id = "raw-task" _shortdesc = "Test rule that inspects the raw task" tags = ["fake", "dummy", "test3"] needs_raw_task = True def matchtask( self, task: Task, file: Lintable | None = None, ) -> bool | str: """Match a task using __raw_task__ to inspect the module params type.""" raw_task = task["__raw_task__"] module = task["action"]["__ansible_module_original__"] found_raw_task_params = not isinstance(raw_task[module], dict) return found_raw_task_params ������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/rules/fixtures/unset_variable_matcher.py��������������������������0000664�0000000�0000000�00000000663�14773473560�0027127�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Custom linting rule used as test fixture.""" from ansiblelint.rules import AnsibleLintRule class UnsetVariableMatcherRule(AnsibleLintRule): """Line contains untemplated variable.""" id = "TEST0002" description = ( "This is a test rule that looks for lines post templating that still contain {{" ) tags = ["fake", "dummy", "test2"] def match(self, line: str) -> bool: return "{{" in line �����������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/rules/test_args.py������������������������������������������������0000664�0000000�0000000�00000001362�14773473560�0022540�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for args rule.""" from ansiblelint.file_utils import Lintable from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner def test_args_module_relative_import(default_rules_collection: RulesCollection) -> None: """Validate args check of a module with a relative import.""" lintable = Lintable( "examples/playbooks/module_relative_import.yml", kind="playbook", ) result = Runner(lintable, rules=default_rules_collection).run() assert len(result) == 1, result assert result[0].lineno == 5 assert result[0].filename == "examples/playbooks/module_relative_import.yml" assert result[0].tag == "args[module]" assert result[0].message == "missing required arguments: name" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/rules/test_deprecated_module.py�����������������������������������0000664�0000000�0000000�00000001555�14773473560�0025255�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for deprecated-module rule.""" from pathlib import Path from ansiblelint.rules import RulesCollection from ansiblelint.rules.deprecated_module import DeprecatedModuleRule from ansiblelint.testing import RunFromText MODULE_DEPRECATED = """ - name: Task example docker: debug: test """ def test_module_deprecated(tmp_path: Path) -> None: """Test for deprecated-module.""" collection = RulesCollection() collection.register(DeprecatedModuleRule()) runner = RunFromText(collection) results = runner.run_role_tasks_main(MODULE_DEPRECATED, tmp_path=tmp_path) assert len(results) == 1 # based on version and blend of ansible being used, we may # get a missing module, so we future proof the test assert ( "couldn't resolve module" not in results[0].message or "Deprecated module" not in results[0].message ) ���������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/rules/test_inline_env_var.py��������������������������������������0000664�0000000�0000000�00000004060�14773473560�0024600�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for inline-env-var rule.""" from ansiblelint.rules import RulesCollection from ansiblelint.rules.inline_env_var import EnvVarsInCommandRule from ansiblelint.testing import RunFromText SUCCESS_PLAY_TASKS = """ - hosts: localhost tasks: - name: Actual use of environment shell: echo $HELLO environment: HELLO: hello - name: Use some key-value pairs command: chdir=/tmp creates=/tmp/bobbins touch bobbins - name: Commands can have flags command: abc --xyz=def blah - name: Commands can have equals in them command: echo "===========" - name: Commands with cmd command: cmd: echo "-------" - name: Command with stdin (ansible > 2.4) command: /bin/cat args: stdin: "Hello, world!" - name: Use argv to send the command as a list command: argv: - /bin/echo - Hello - World - name: Another use of argv command: args: argv: - echo - testing - name: Environment variable with shell shell: HELLO=hello echo $HELLO - name: Command with stdin_add_newline (ansible > 2.8) command: /bin/cat args: stdin: "Hello, world!" stdin_add_newline: false - name: Command with strip_empty_ends (ansible > 2.8) command: echo args: strip_empty_ends: false """ FAIL_PLAY_TASKS = """ - hosts: localhost tasks: - name: Environment variable with command command: HELLO=hello echo $HELLO - name: Typo some stuff command: crates=/tmp/blah touch /tmp/blah """ def test_success() -> None: """Positive test for inline-env-var.""" collection = RulesCollection() collection.register(EnvVarsInCommandRule()) runner = RunFromText(collection) results = runner.run_playbook(SUCCESS_PLAY_TASKS) assert len(results) == 0 def test_fail() -> None: """Negative test for inline-env-var.""" collection = RulesCollection() collection.register(EnvVarsInCommandRule()) runner = RunFromText(collection) results = runner.run_playbook(FAIL_PLAY_TASKS) assert len(results) == 2 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/rules/test_no_changed_when.py�������������������������������������0000664�0000000�0000000�00000001547�14773473560�0024717�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for no-change-when rule.""" from ansiblelint.rules import RulesCollection from ansiblelint.rules.no_changed_when import CommandHasChangesCheckRule from ansiblelint.runner import Runner def test_command_changes_positive() -> None: """Positive test for no-changed-when.""" collection = RulesCollection() collection.register(CommandHasChangesCheckRule()) success = "examples/playbooks/command-check-success.yml" good_runner = Runner(success, rules=collection) assert good_runner.run() == [] def test_command_changes_negative() -> None: """Negative test for no-changed-when.""" collection = RulesCollection() collection.register(CommandHasChangesCheckRule()) failure = "examples/playbooks/command-check-failure.yml" bad_runner = Runner(failure, rules=collection) errs = bad_runner.run() assert len(errs) == 2 ���������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/rules/test_package_latest.py��������������������������������������0000664�0000000�0000000�00000001536�14773473560�0024556�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for package-latest rule.""" from ansiblelint.rules import RulesCollection from ansiblelint.rules.package_latest import PackageIsNotLatestRule from ansiblelint.runner import Runner def test_package_not_latest_positive() -> None: """Positive test for package-latest.""" collection = RulesCollection() collection.register(PackageIsNotLatestRule()) success = "examples/playbooks/package-check-success.yml" good_runner = Runner(success, rules=collection) assert good_runner.run() == [] def test_package_not_latest_negative() -> None: """Negative test for package-latest.""" collection = RulesCollection() collection.register(PackageIsNotLatestRule()) failure = "examples/playbooks/package-check-failure.yml" bad_runner = Runner(failure, rules=collection) errs = bad_runner.run() assert len(errs) == 5 ������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/rules/test_role_names.py������������������������������������������0000664�0000000�0000000�00000004750�14773473560�0023734�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test the RoleNames rule.""" from __future__ import annotations from typing import TYPE_CHECKING, Any import pytest from ansiblelint.rules import RulesCollection from ansiblelint.rules.role_name import RoleNames from ansiblelint.runner import Runner if TYPE_CHECKING: from pathlib import Path from _pytest.fixtures import SubRequest ROLE_NAME_VALID = "test_role" TASK_MINIMAL = """ - name: Some task ping: """ ROLE_MINIMAL = {"tasks": {"main.yml": TASK_MINIMAL}} ROLE_META_EMPTY = {"meta": {"main.yml": ""}} ROLE_WITH_EMPTY_META = {**ROLE_MINIMAL, **ROLE_META_EMPTY} PLAY_INCLUDE_ROLE = f""" - hosts: all roles: - {ROLE_NAME_VALID} """ @pytest.fixture(name="test_rules_collection") def fixture_test_rules_collection() -> RulesCollection: """Instantiate a roles collection for tests.""" collection = RulesCollection() collection.register(RoleNames()) return collection def dict_to_files(parent_dir: Path, file_dict: dict[str, Any]) -> None: """Write a nested dict to a file and directory structure below parent_dir.""" for file, content in file_dict.items(): if isinstance(content, dict): directory = parent_dir / file directory.mkdir() dict_to_files(directory, content) else: (parent_dir / file).write_text(content) @pytest.fixture(name="playbook_path") def fixture_playbook_path(request: SubRequest, tmp_path: Path) -> str: """Create a playbook with a role in a temporary directory.""" playbook_text = request.param[0] role_name = request.param[1] role_layout = request.param[2] role_path = tmp_path / role_name role_path.mkdir() dict_to_files(role_path, role_layout) play_path = tmp_path / "playbook.yml" play_path.write_text(playbook_text) return str(play_path) @pytest.mark.parametrize( ("playbook_path", "messages"), ( pytest.param( (PLAY_INCLUDE_ROLE, ROLE_NAME_VALID, ROLE_WITH_EMPTY_META), [], id="ROLE_EMPTY_META", ), ), indirect=("playbook_path",), ) def test_role_name( test_rules_collection: RulesCollection, playbook_path: str, messages: list[str], ) -> None: """Lint a playbook and compare the expected messages with the actual messages.""" runner = Runner(playbook_path, rules=test_rules_collection) results = runner.run() assert len(results) == len(messages) results_text = str(results) for message in messages: assert message in results_text ������������������������ansible-ansible-lint-c16f018/test/rules/test_syntax_check.py����������������������������������������0000664�0000000�0000000�00000006730�14773473560�0024273�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for syntax-check rule.""" from typing import Any import pytest from ansiblelint.file_utils import Lintable from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner @pytest.mark.parametrize( ("filename", "expected_results"), ( pytest.param( "examples/playbooks/conflicting_action.yml", [ ( "syntax-check[specific]", [4], 7, "conflicting action statements: ansible.builtin.debug, ansible.builtin.command", ), ], id="0", ), pytest.param( "examples/playbooks/conflicting_action2.yml", [ ( "syntax-check[specific]", [5, 6], 7, "'include_role' is not a valid attribute for a Block", ), ], id="1", ), ), ) def test_get_ansible_syntax_check_matches( default_rules_collection: RulesCollection, filename: str, expected_results: list[tuple[str, list[int], int, str]], ) -> None: """Validate parsing of ansible output.""" lintable = Lintable( filename, kind="playbook", ) result = sorted(Runner(lintable, rules=default_rules_collection).run()) assert len(result) == len(expected_results) for index, expected in enumerate(expected_results): assert result[index].tag == expected[0] assert result[index].lineno in expected[1] assert result[index].column == expected[2] assert str(expected[3]) in result[index].message # We internally convert absolute paths returned by ansible into paths # relative to current directory. # assert result[index].filename.endswith("/conflicting_action.yml") def test_empty_playbook(default_rules_collection: RulesCollection) -> None: """Validate detection of empty-playbook.""" lintable = Lintable("examples/playbooks/empty_playbook.yml", kind="playbook") result = Runner(lintable, rules=default_rules_collection).run() assert result[0].lineno == 1 # We internally convert absolute paths returned by ansible into paths # relative to current directory. assert result[0].filename.endswith("/empty_playbook.yml") assert result[0].tag == "syntax-check[empty-playbook]" assert result[0].message == "Empty playbook, nothing to do" assert len(result) == 1 def test_extra_vars_passed_to_command( default_rules_collection: RulesCollection, config_options: Any, ) -> None: """Validate `extra-vars` are passed to syntax check command.""" config_options.extra_vars = { "foo": "bar", "complex_variable": ":{;\t$()", } lintable = Lintable("examples/playbooks/extra_vars.yml", kind="playbook") result = Runner(lintable, rules=default_rules_collection).run() assert not result def test_syntax_check_role(default_rules_collection: RulesCollection) -> None: """Validate syntax check of a broken role.""" lintable = Lintable("examples/playbooks/roles/invalid_due_syntax", kind="role") result = Runner(lintable, rules=default_rules_collection).run() assert len(result) == 1, result assert result[0].lineno == 2 assert result[0].filename == "examples/roles/invalid_due_syntax/tasks/main.yml" assert result[0].tag == "syntax-check[specific]" assert result[0].message == "no module/action detected in task." ����������������������������������������ansible-ansible-lint-c16f018/test/schemas/����������������������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0020462�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/.mocharc.json���������������������������������������������0000664�0000000�0000000�00000000334�14773473560�0023047�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "colors": true, "extensions": ["ts"], "require": "ts-node/register", "node-option": [ "experimental-specifier-resolution=node", "loader=ts-node/esm" ], "slow": "500", "spec": "src/**/*.spec.ts" } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/f���������������������������������������������������������0000777�0000000�0000000�00000000000�14773473560�0025714�2../../src/ansiblelint/schemas�����������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/��������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0023323�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/.ansible-lint�������������������������������0000664�0000000�0000000�00000000056�14773473560�0025706�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- # .ansible-lint rules: Wrong_Rule_name: ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/.ansible-lint.md����������������������������0000664�0000000�0000000�00000006345�14773473560�0026314�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/rules", "keyword": "enum", "message": "must be equal to one of the allowed values", "params": { "allowedValues": [ "command-instead-of-module", "command-instead-of-shell", "deprecated-bare-vars", "deprecated-local-action", "deprecated-module", "empty-string-compare", "fqcn", "fqcn[action-core]", "fqcn[action]", "fqcn[canonical]", "fqcn[keyword]", "galaxy", "galaxy[no-changelog]", "galaxy[no-runtime]", "galaxy[tags]", "galaxy[version-incorrect]", "galaxy[version-missing]", "ignore-errors", "inline-env-var", "internal-error", "jinja", "jinja[invalid]", "jinja[spacing]", "key-order", "latest", "literal-compare", "load-failure", "load-failure[not-found]", "loop-var-prefix", "loop-var-prefix[missing]", "loop-var-prefix[wrong]", "meta-incorrect", "meta-no-tags", "meta-runtime", "meta-video-links", "name", "name[casing]", "name[play]", "name[prefix]", "name[template]", "no-changed-when", "no-handler", "no-jinja-when", "no-log-password", "no-prompting", "no-relative-paths", "no-same-owner", "no-tabs", "only-builtins", "package-latest", "parser-error", "partial-become", "playbook-extension", "risky-file-permissions", "risky-octal", "risky-shell-pipe", "role-name", "run-once", "run-once[play]", "run-once[task]", "sanity", "sanity[bad-ignore]", "sanity[cannot-ignore]", "schema", "syntax-check", "var-naming", "yaml" ] }, "propertyName": "Wrong_Rule_name", "schemaPath": "#/properties/rules/propertyNames/oneOf/0/enum" }, { "instancePath": "/rules", "keyword": "pattern", "message": "must match pattern \"^[a-z0-9-\\[\\]]+$\"", "params": { "pattern": "^[a-z0-9-\\[\\]]+$" }, "propertyName": "Wrong_Rule_name", "schemaPath": "#/properties/rules/propertyNames/oneOf/1/pattern" }, { "instancePath": "/rules", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "propertyName": "Wrong_Rule_name", "schemaPath": "#/properties/rules/propertyNames/oneOf" }, { "instancePath": "/rules", "keyword": "propertyNames", "message": "property name must be valid", "params": { "propertyName": "Wrong_Rule_name" }, "schemaPath": "#/properties/rules/propertyNames" }, { "instancePath": "/rules/Wrong_Rule_name", "keyword": "type", "message": "must be object", "params": { "type": "object" }, "schemaPath": "#/$defs/rule/type" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [], "parse_errors": [ { "filename": "negative_test/.ansible-lint", "message": "Failed to parse negative_test/.ansible-lint" } ] } ``` �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/.config/������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024646�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/.config/ansible-lint.yml��������������������0000664�0000000�0000000�00000000055�14773473560�0027752�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- # .ansible-lint profile: invalid_profile �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/.config/ansible-lint.yml.md�����������������0000664�0000000�0000000�00000001362�14773473560�0030353�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/profile", "keyword": "enum", "message": "must be equal to one of the allowed values", "params": { "allowedValues": [ "min", "basic", "moderate", "safety", "shared", "production", null ] }, "schemaPath": "#/properties/profile/enum" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/.config/ansible-lint.yml", "path": "$.profile", "message": "'invalid_profile' is not one of ['min', 'basic', 'moderate', 'safety', 'shared', 'production', None]", "has_sub_errors": false } ], "parse_errors": [] } ``` ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/���������������������������������0000775�0000000�0000000�00000000000�14773473560�0025435�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/invalid-date/��������������������0000775�0000000�0000000�00000000000�14773473560�0027776�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/invalid-date/changelogs/���������0000775�0000000�0000000�00000000000�14773473560�0032110�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������changelog.yaml��������������������������������������������������������������������������������������0000664�0000000�0000000�00000000136�14773473560�0034644�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/invalid-date/changelogs�����������������������������������������������������������������������������--- releases: 1.0.0: release_date: 01-01-2020 # invalid date format, must be ISO-8601 ! ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������changelog.yaml.md�����������������������������������������������������������������������������������0000664�0000000�0000000�00000001633�14773473560�0035246�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/invalid-date/changelogs�����������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/releases/1.0.0/release_date", "keyword": "pattern", "message": "must match pattern \"\\d\\d\\d\\d-\\d\\d-\\d\\d\"", "params": { "pattern": "\\d\\d\\d\\d-\\d\\d-\\d\\d" }, "schemaPath": "#/properties/release_date/pattern" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/changelogs/invalid-date/changelogs/changelog.yaml", "path": "$.releases.1.0.0.release_date", "message": "'01-01-2020' is not a 'date'", "has_sub_errors": false }, { "filename": "negative_test/changelogs/invalid-date/changelogs/changelog.yaml", "path": "$.releases.1.0.0.release_date", "message": "'01-01-2020' does not match '\\\\d\\\\d\\\\d\\\\d-\\\\d\\\\d-\\\\d\\\\d'", "has_sub_errors": false } ], "parse_errors": [] } ``` �����������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/invalid-plugin-namespace/��������0000775�0000000�0000000�00000000000�14773473560�0032311�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������changelogs/�����������������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0034344�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/invalid-plugin-namespace����������������������������������������������������������������������������changelog.yaml��������������������������������������������������������������������������������������0000664�0000000�0000000�00000000273�14773473560�0037161�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/invalid-plugin-namespace/changelogs�����������������������������������������������������������������--- releases: 1.0.0: plugins: lookup: - name: reverse description: Reverse magic namespace: "foo" # namespace must be null for plugins and objects �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������changelog.yaml.md�����������������������������������������������������������������������������������0000664�0000000�0000000�00000001220�14773473560�0037551�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/invalid-plugin-namespace/changelogs�����������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/releases/1.0.0/plugins/lookup/0/namespace", "keyword": "type", "message": "must be null", "params": { "type": "null" }, "schemaPath": "#/$defs/plugin-descriptions/items/properties/namespace/type" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/changelogs/invalid-plugin-namespace/changelogs/changelog.yaml", "path": "$.releases.1.0.0.plugins.lookup[0].namespace", "message": "'foo' is not of type 'null'", "has_sub_errors": false } ], "parse_errors": [] } ``` ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/list/����������������������������0000775�0000000�0000000�00000000000�14773473560�0026410�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/list/changelogs/�����������������0000775�0000000�0000000�00000000000�14773473560�0030522�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/list/changelogs/changelog.yaml���0000664�0000000�0000000�00000000130�14773473560�0033327�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - this is invalid - as changelog must be object (mapping) - not an array (sequence) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/list/changelogs/changelog.yaml.md0000664�0000000�0000000�00000001112�14773473560�0033727�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "", "keyword": "type", "message": "must be object", "params": { "type": "object" }, "schemaPath": "#/type" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/changelogs/list/changelogs/changelog.yaml", "path": "$", "message": "['this is invalid', 'as changelog must be object (mapping)', 'not an array (sequence)'] is not of type 'object'", "has_sub_errors": false } ], "parse_errors": [] } ``` ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/no-semver/�����������������������0000775�0000000�0000000�00000000000�14773473560�0027350�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/no-semver/changelogs/������������0000775�0000000�0000000�00000000000�14773473560�0031462�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������changelog.yaml��������������������������������������������������������������������������������������0000664�0000000�0000000�00000000045�14773473560�0034215�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/no-semver/changelogs��������������������������������������������������������������������������������--- releases: foo # <-- not a semver �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������changelog.yaml.md�����������������������������������������������������������������������������������0000664�0000000�0000000�00000001043�14773473560�0034613�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/no-semver/changelogs��������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/releases", "keyword": "type", "message": "must be object", "params": { "type": "object" }, "schemaPath": "#/properties/releases/type" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/changelogs/no-semver/changelogs/changelog.yaml", "path": "$.releases", "message": "'foo' is not of type 'object'", "has_sub_errors": false } ], "parse_errors": [] } ``` ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/unknown-keys/��������������������0000775�0000000�0000000�00000000000�14773473560�0030105�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/unknown-keys/changelogs/���������0000775�0000000�0000000�00000000000�14773473560�0032217�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������changelog.yaml��������������������������������������������������������������������������������������0000664�0000000�0000000�00000000074�14773473560�0034754�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/unknown-keys/changelogs�����������������������������������������������������������������������������--- release: {} # <- unknown key, correct would be releases ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������changelog.yaml.md�����������������������������������������������������������������������������������0000664�0000000�0000000�00000001147�14773473560�0035355�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/changelogs/unknown-keys/changelogs�����������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "release" }, "schemaPath": "#/additionalProperties" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/changelogs/unknown-keys/changelogs/changelog.yaml", "path": "$", "message": "Additional properties are not allowed ('release' was unexpected)", "has_sub_errors": false } ], "parse_errors": [] } ``` �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/galaxy_1/�����������������������������������0000775�0000000�0000000�00000000000�14773473560�0025030�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/galaxy_1/galaxy.yml�������������������������0000664�0000000�0000000�00000000376�14773473560�0027046�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������name: foo namespace: bar version: 1.2.3 authors: - John readme: ../README.md description: ... repository: https://www.github.com/my_org/my_collection manifest: directive: # <-- typo, should be "directives" - "foo" omit_default_directives: true ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/galaxy_1/galaxy.yml.md����������������������0000664�0000000�0000000�00000001163�14773473560�0027440�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/manifest", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "directive" }, "schemaPath": "#/properties/manifest/additionalProperties" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/galaxy_1/galaxy.yml", "path": "$.manifest", "message": "Additional properties are not allowed ('directive' was unexpected)", "has_sub_errors": false } ], "parse_errors": [] } ``` �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/inventory/����������������������������������0000775�0000000�0000000�00000000000�14773473560�0025360�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/inventory/broken_dev_inventory.yml����������0000664�0000000�0000000�00000000346�14773473560�0032341�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- # See https://docs.ansible.com/ansible/latest/inventory_guide/intro_inventory.html ungrouped: {} all: hosts: mail.example.com: children: foo: {} # <-- invalid based on inventory json schema vars: {} webservers: {} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/inventory/broken_dev_inventory.yml.md�������0000664�0000000�0000000�00000001154�14773473560�0032736�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/all", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "foo" }, "schemaPath": "#/$defs/special-group/additionalProperties" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/inventory/broken_dev_inventory.yml", "path": "$.all", "message": "Additional properties are not allowed ('foo' was unexpected)", "has_sub_errors": false } ], "parse_errors": [] } ``` ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/meta/���������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024251�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/meta/runtime.yml����������������������������0000664�0000000�0000000�00000000077�14773473560�0026463�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������requires_ansible: ">= 2.12" # invalid as space is not allowed! �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/meta/runtime.yml.md�������������������������0000664�0000000�0000000�00000001104�14773473560�0027052�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/requires_ansible", "keyword": "pattern", "message": "must match pattern \"^[^\\s]*$\"", "params": { "pattern": "^[^\\s]*$" }, "schemaPath": "#/properties/requires_ansible/pattern" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/meta/runtime.yml", "path": "$.requires_ansible", "message": "'>= 2.12' does not match '^[^\\\\s]*$'", "has_sub_errors": false } ], "parse_errors": [] } ``` ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/molecule/�����������������������������������0000775�0000000�0000000�00000000000�14773473560�0025130�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/molecule/platforms_children/����������������0000775�0000000�0000000�00000000000�14773473560�0031007�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/molecule/platforms_children/molecule.yml����0000664�0000000�0000000�00000000146�14773473560�0033340�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������driver: name: delegated platforms: - name: foo children: 2 # invalid, must be list of strings ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/molecule/platforms_children/molecule.yml.md�0000664�0000000�0000000�00000001057�14773473560�0033741�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/platforms/0/children", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/properties/children/type" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/molecule/platforms_children/molecule.yml", "path": "$.platforms[0].children", "message": "2 is not of type 'array'", "has_sub_errors": false } ], "parse_errors": [] } ``` ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/molecule/platforms_networks/����������������0000775�0000000�0000000�00000000000�14773473560�0031073�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/molecule/platforms_networks/molecule.yml����0000664�0000000�0000000�00000000201�14773473560�0033414�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������driver: name: docker platforms: - name: docker networks: # invalid, must be list of dictionaries - foo - bar �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/molecule/platforms_networks/molecule.yml.md�0000664�0000000�0000000�00000001743�14773473560�0034027�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/platforms/0/networks/0", "keyword": "type", "message": "must be object", "params": { "type": "object" }, "schemaPath": "#/$defs/platform-network/type" }, { "instancePath": "/platforms/0/networks/1", "keyword": "type", "message": "must be object", "params": { "type": "object" }, "schemaPath": "#/$defs/platform-network/type" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/molecule/platforms_networks/molecule.yml", "path": "$.platforms[0].networks[0]", "message": "'foo' is not of type 'object'", "has_sub_errors": false }, { "filename": "negative_test/molecule/platforms_networks/molecule.yml", "path": "$.platforms[0].networks[1]", "message": "'bar' is not of type 'object'", "has_sub_errors": false } ], "parse_errors": [] } ``` �����������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/����������������������������������0000775�0000000�0000000�00000000000�14773473560�0025326�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/environment.yml�������������������0000664�0000000�0000000�00000000175�14773473560�0030420�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - hosts: localhost environment: "{{ foo }}-123" # <- invalid only a full jinja string is allowed, or a list of strings ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/environment.yml.md����������������0000664�0000000�0000000�00000007334�14773473560�0031023�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "environment" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/environment", "keyword": "type", "message": "must be object", "params": { "type": "object" }, "schemaPath": "#/anyOf/0/type" }, { "instancePath": "/0/environment", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/environment", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/anyOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/environment.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'environment': '{{ foo }}-123'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'environment', 'hosts' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].environment", "message": "'{{ foo }}-123' is not of type 'object'" }, "num_sub_errors": 6, "sub_errors": [ { "path": "$[0]", "message": "'environment', 'hosts' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'environment': '{{ foo }}-123'} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].environment", "message": "'{{ foo }}-123' is not valid under any of the given schemas" }, { "path": "$[0].environment", "message": "'{{ foo }}-123' is not of type 'object'" }, { "path": "$[0].environment", "message": "'{{ foo }}-123' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" } ] } ], "parse_errors": [] } ``` ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/failed_when.yml�������������������0000664�0000000�0000000�00000000176�14773473560�0030322�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost tasks: - name: foo ansible.builtin.debug: msg: foo! failed_when: 123 # <- not ok ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/failed_when.yml.md����������������0000664�0000000�0000000�00000011520�14773473560�0030714�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/tasks/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/tasks/0/failed_when", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/$defs/complex_conditional/oneOf/0/type" }, { "instancePath": "/0/tasks/0/failed_when", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/complex_conditional/oneOf/1/type" }, { "instancePath": "/0/tasks/0/failed_when", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/$defs/complex_conditional/oneOf/2/type" }, { "instancePath": "/0/tasks/0/failed_when", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/$defs/complex_conditional/oneOf" }, { "instancePath": "/0/tasks/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/failed_when.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'tasks': [{'name': 'foo', 'ansible.builtin.debug': {'msg': 'foo!'}, 'failed_when': 123}]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].tasks[0].failed_when", "message": "123 is not of type 'boolean'" }, "num_sub_errors": 9, "sub_errors": [ { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'tasks': [{'name': 'foo', 'ansible.builtin.debug': {'msg': 'foo!'}, 'failed_when': 123}]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].tasks[0]", "message": "{'name': 'foo', 'ansible.builtin.debug': {'msg': 'foo!'}, 'failed_when': 123} is not valid under any of the given schemas" }, { "path": "$[0].tasks[0]", "message": "'block' is a required property" }, { "path": "$[0].tasks[0].failed_when", "message": "123 is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].failed_when", "message": "123 is not of type 'boolean'" }, { "path": "$[0].tasks[0].failed_when", "message": "123 is not of type 'string'" }, { "path": "$[0].tasks[0].failed_when", "message": "123 is not of type 'array'" } ] } ], "parse_errors": [] } ``` ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/gather_facts.yml������������������0000664�0000000�0000000�00000000142�14773473560�0030500�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - hosts: localhost gather_facts: non tasks: - ansible.builtin.debug: msg: foo ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/gather_facts.yml.md���������������0000664�0000000�0000000�00000010101�14773473560�0031073�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "gather_facts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/gather_facts", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/gather_facts", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/gather_facts", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/gather_facts.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'gather_facts': 'non', 'tasks': [{'ansible.builtin.debug': {'msg': 'foo'}}]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'gather_facts', 'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].gather_facts", "message": "'non' is not of type 'boolean'" }, "num_sub_errors": 6, "sub_errors": [ { "path": "$[0]", "message": "'gather_facts', 'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'gather_facts': 'non', 'tasks': [{'ansible.builtin.debug': {'msg': 'foo'}}]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].gather_facts", "message": "'non' is not valid under any of the given schemas" }, { "path": "$[0].gather_facts", "message": "'non' is not of type 'boolean'" }, { "path": "$[0].gather_facts", "message": "'non' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" } ] } ], "parse_errors": [] } ``` ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/gather_subset.yml�����������������0000664�0000000�0000000�00000000143�14773473560�0030706�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - hosts: localhost gather_subset: all tasks: - ansible.builtin.debug: msg: foo �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/gather_subset.yml.md��������������0000664�0000000�0000000�00000006535�14773473560�0031320�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "gather_subset" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/gather_subset", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/properties/gather_subset/type" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/gather_subset.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'gather_subset': 'all', 'tasks': [{'ansible.builtin.debug': {'msg': 'foo'}}]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'gather_subset', 'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].gather_subset", "message": "'all' is not of type 'array'" }, "num_sub_errors": 4, "sub_errors": [ { "path": "$[0]", "message": "'gather_subset', 'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'gather_subset': 'all', 'tasks': [{'ansible.builtin.debug': {'msg': 'foo'}}]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].gather_subset", "message": "'all' is not of type 'array'" } ] } ], "parse_errors": [] } ``` �������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/gather_subset2.yml����������������0000664�0000000�0000000�00000000155�14773473560�0030773�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - hosts: localhost gather_subset: - invalid tasks: - ansible.builtin.debug: msg: foo �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/gather_subset2.yml.md�������������0000664�0000000�0000000�00000024002�14773473560�0031367�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "gather_subset" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/gather_subset/0", "keyword": "enum", "message": "must be equal to one of the allowed values", "params": { "allowedValues": [ "all", "min", "all_ipv4_addresses", "all_ipv6_addresses", "apparmor", "architecture", "caps", "chroot,cmdline", "date_time", "default_ipv4", "default_ipv6", "devices", "distribution", "distribution_major_version", "distribution_release", "distribution_version", "dns", "effective_group_ids", "effective_user_id", "env", "facter", "fips", "hardware", "interfaces", "is_chroot", "iscsi", "kernel", "local", "lsb", "machine", "machine_id", "mounts", "network", "ohai", "os_family", "pkg_mgr", "platform", "processor", "processor_cores", "processor_count", "python", "python_version", "real_user_id", "selinux", "service_mgr", "ssh_host_key_dsa_public", "ssh_host_key_ecdsa_public", "ssh_host_key_ed25519_public", "ssh_host_key_rsa_public", "ssh_host_pub_keys", "ssh_pub_keys", "system", "system_capabilities", "system_capabilities_enforced", "user", "user_dir", "user_gecos", "user_gid", "user_id", "user_shell", "user_uid", "virtual", "virtualization_role", "virtualization_type" ] }, "schemaPath": "#/properties/gather_subset/items/anyOf/0/enum" }, { "instancePath": "/0/gather_subset/0", "keyword": "enum", "message": "must be equal to one of the allowed values", "params": { "allowedValues": [ "!all", "!min", "!all_ipv4_addresses", "!all_ipv6_addresses", "!apparmor", "!architecture", "!caps", "!chroot,cmdline", "!date_time", "!default_ipv4", "!default_ipv6", "!devices", "!distribution", "!distribution_major_version", "!distribution_release", "!distribution_version", "!dns", "!effective_group_ids", "!effective_user_id", "!env", "!facter", "!fips", "!hardware", "!interfaces", "!is_chroot", "!iscsi", "!kernel", "!local", "!lsb", "!machine", "!machine_id", "!mounts", "!network", "!ohai", "!os_family", "!pkg_mgr", "!platform", "!processor", "!processor_cores", "!processor_count", "!python", "!python_version", "!real_user_id", "!selinux", "!service_mgr", "!ssh_host_key_dsa_public", "!ssh_host_key_ecdsa_public", "!ssh_host_key_ed25519_public", "!ssh_host_key_rsa_public", "!ssh_host_pub_keys", "!ssh_pub_keys", "!system", "!system_capabilities", "!system_capabilities_enforced", "!user", "!user_dir", "!user_gecos", "!user_gid", "!user_id", "!user_shell", "!user_uid", "!virtual", "!virtualization_role", "!virtualization_type" ] }, "schemaPath": "#/properties/gather_subset/items/anyOf/1/enum" }, { "instancePath": "/0/gather_subset/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/properties/gather_subset/items/anyOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/gather_subset2.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'gather_subset': ['invalid'], 'tasks': [{'ansible.builtin.debug': {'msg': 'foo'}}]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'gather_subset', 'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].gather_subset[0]", "message": "'invalid' is not one of ['all', 'min', 'all_ipv4_addresses', 'all_ipv6_addresses', 'apparmor', 'architecture', 'caps', 'chroot,cmdline', 'date_time', 'default_ipv4', 'default_ipv6', 'devices', 'distribution', 'distribution_major_version', 'distribution_release', 'distribution_version', 'dns', 'effective_group_ids', 'effective_user_id', 'env', 'facter', 'fips', 'hardware', 'interfaces', 'is_chroot', 'iscsi', 'kernel', 'local', 'lsb', 'machine', 'machine_id', 'mounts', 'network', 'ohai', 'os_family', 'pkg_mgr', 'platform', 'processor', 'processor_cores', 'processor_count', 'python', 'python_version', 'real_user_id', 'selinux', 'service_mgr', 'ssh_host_key_dsa_public', 'ssh_host_key_ecdsa_public', 'ssh_host_key_ed25519_public', 'ssh_host_key_rsa_public', 'ssh_host_pub_keys', 'ssh_pub_keys', 'system', 'system_capabilities', 'system_capabilities_enforced', 'user', 'user_dir', 'user_gecos', 'user_gid', 'user_id', 'user_shell', 'user_uid', 'virtual', 'virtualization_role', 'virtualization_type']" }, "num_sub_errors": 6, "sub_errors": [ { "path": "$[0]", "message": "'gather_subset', 'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'gather_subset': ['invalid'], 'tasks': [{'ansible.builtin.debug': {'msg': 'foo'}}]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].gather_subset[0]", "message": "'invalid' is not valid under any of the given schemas" }, { "path": "$[0].gather_subset[0]", "message": "'invalid' is not one of ['all', 'min', 'all_ipv4_addresses', 'all_ipv6_addresses', 'apparmor', 'architecture', 'caps', 'chroot,cmdline', 'date_time', 'default_ipv4', 'default_ipv6', 'devices', 'distribution', 'distribution_major_version', 'distribution_release', 'distribution_version', 'dns', 'effective_group_ids', 'effective_user_id', 'env', 'facter', 'fips', 'hardware', 'interfaces', 'is_chroot', 'iscsi', 'kernel', 'local', 'lsb', 'machine', 'machine_id', 'mounts', 'network', 'ohai', 'os_family', 'pkg_mgr', 'platform', 'processor', 'processor_cores', 'processor_count', 'python', 'python_version', 'real_user_id', 'selinux', 'service_mgr', 'ssh_host_key_dsa_public', 'ssh_host_key_ecdsa_public', 'ssh_host_key_ed25519_public', 'ssh_host_key_rsa_public', 'ssh_host_pub_keys', 'ssh_pub_keys', 'system', 'system_capabilities', 'system_capabilities_enforced', 'user', 'user_dir', 'user_gecos', 'user_gid', 'user_id', 'user_shell', 'user_uid', 'virtual', 'virtualization_role', 'virtualization_type']" }, { "path": "$[0].gather_subset[0]", "message": "'invalid' is not one of ['!all', '!min', '!all_ipv4_addresses', '!all_ipv6_addresses', '!apparmor', '!architecture', '!caps', '!chroot,cmdline', '!date_time', '!default_ipv4', '!default_ipv6', '!devices', '!distribution', '!distribution_major_version', '!distribution_release', '!distribution_version', '!dns', '!effective_group_ids', '!effective_user_id', '!env', '!facter', '!fips', '!hardware', '!interfaces', '!is_chroot', '!iscsi', '!kernel', '!local', '!lsb', '!machine', '!machine_id', '!mounts', '!network', '!ohai', '!os_family', '!pkg_mgr', '!platform', '!processor', '!processor_cores', '!processor_count', '!python', '!python_version', '!real_user_id', '!selinux', '!service_mgr', '!ssh_host_key_dsa_public', '!ssh_host_key_ecdsa_public', '!ssh_host_key_ed25519_public', '!ssh_host_key_rsa_public', '!ssh_host_pub_keys', '!ssh_pub_keys', '!system', '!system_capabilities', '!system_capabilities_enforced', '!user', '!user_dir', '!user_gecos', '!user_gid', '!user_id', '!user_shell', '!user_uid', '!virtual', '!virtualization_role', '!virtualization_type']" } ] } ], "parse_errors": [] } ``` ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/gather_subset3.yml����������������0000664�0000000�0000000�00000000147�14773473560�0030775�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - hosts: localhost gather_subset: - 1 tasks: - ansible.builtin.debug: msg: foo �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/gather_subset3.yml.md�������������0000664�0000000�0000000�00000025152�14773473560�0031377�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "gather_subset" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/gather_subset/0", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/properties/gather_subset/items/anyOf/0/type" }, { "instancePath": "/0/gather_subset/0", "keyword": "enum", "message": "must be equal to one of the allowed values", "params": { "allowedValues": [ "all", "min", "all_ipv4_addresses", "all_ipv6_addresses", "apparmor", "architecture", "caps", "chroot,cmdline", "date_time", "default_ipv4", "default_ipv6", "devices", "distribution", "distribution_major_version", "distribution_release", "distribution_version", "dns", "effective_group_ids", "effective_user_id", "env", "facter", "fips", "hardware", "interfaces", "is_chroot", "iscsi", "kernel", "local", "lsb", "machine", "machine_id", "mounts", "network", "ohai", "os_family", "pkg_mgr", "platform", "processor", "processor_cores", "processor_count", "python", "python_version", "real_user_id", "selinux", "service_mgr", "ssh_host_key_dsa_public", "ssh_host_key_ecdsa_public", "ssh_host_key_ed25519_public", "ssh_host_key_rsa_public", "ssh_host_pub_keys", "ssh_pub_keys", "system", "system_capabilities", "system_capabilities_enforced", "user", "user_dir", "user_gecos", "user_gid", "user_id", "user_shell", "user_uid", "virtual", "virtualization_role", "virtualization_type" ] }, "schemaPath": "#/properties/gather_subset/items/anyOf/0/enum" }, { "instancePath": "/0/gather_subset/0", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/properties/gather_subset/items/anyOf/1/type" }, { "instancePath": "/0/gather_subset/0", "keyword": "enum", "message": "must be equal to one of the allowed values", "params": { "allowedValues": [ "!all", "!min", "!all_ipv4_addresses", "!all_ipv6_addresses", "!apparmor", "!architecture", "!caps", "!chroot,cmdline", "!date_time", "!default_ipv4", "!default_ipv6", "!devices", "!distribution", "!distribution_major_version", "!distribution_release", "!distribution_version", "!dns", "!effective_group_ids", "!effective_user_id", "!env", "!facter", "!fips", "!hardware", "!interfaces", "!is_chroot", "!iscsi", "!kernel", "!local", "!lsb", "!machine", "!machine_id", "!mounts", "!network", "!ohai", "!os_family", "!pkg_mgr", "!platform", "!processor", "!processor_cores", "!processor_count", "!python", "!python_version", "!real_user_id", "!selinux", "!service_mgr", "!ssh_host_key_dsa_public", "!ssh_host_key_ecdsa_public", "!ssh_host_key_ed25519_public", "!ssh_host_key_rsa_public", "!ssh_host_pub_keys", "!ssh_pub_keys", "!system", "!system_capabilities", "!system_capabilities_enforced", "!user", "!user_dir", "!user_gecos", "!user_gid", "!user_id", "!user_shell", "!user_uid", "!virtual", "!virtualization_role", "!virtualization_type" ] }, "schemaPath": "#/properties/gather_subset/items/anyOf/1/enum" }, { "instancePath": "/0/gather_subset/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/properties/gather_subset/items/anyOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/gather_subset3.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'gather_subset': [1], 'tasks': [{'ansible.builtin.debug': {'msg': 'foo'}}]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'gather_subset', 'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].gather_subset[0]", "message": "1 is not one of ['all', 'min', 'all_ipv4_addresses', 'all_ipv6_addresses', 'apparmor', 'architecture', 'caps', 'chroot,cmdline', 'date_time', 'default_ipv4', 'default_ipv6', 'devices', 'distribution', 'distribution_major_version', 'distribution_release', 'distribution_version', 'dns', 'effective_group_ids', 'effective_user_id', 'env', 'facter', 'fips', 'hardware', 'interfaces', 'is_chroot', 'iscsi', 'kernel', 'local', 'lsb', 'machine', 'machine_id', 'mounts', 'network', 'ohai', 'os_family', 'pkg_mgr', 'platform', 'processor', 'processor_cores', 'processor_count', 'python', 'python_version', 'real_user_id', 'selinux', 'service_mgr', 'ssh_host_key_dsa_public', 'ssh_host_key_ecdsa_public', 'ssh_host_key_ed25519_public', 'ssh_host_key_rsa_public', 'ssh_host_pub_keys', 'ssh_pub_keys', 'system', 'system_capabilities', 'system_capabilities_enforced', 'user', 'user_dir', 'user_gecos', 'user_gid', 'user_id', 'user_shell', 'user_uid', 'virtual', 'virtualization_role', 'virtualization_type']" }, "num_sub_errors": 8, "sub_errors": [ { "path": "$[0]", "message": "'gather_subset', 'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'gather_subset': [1], 'tasks': [{'ansible.builtin.debug': {'msg': 'foo'}}]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].gather_subset[0]", "message": "1 is not valid under any of the given schemas" }, { "path": "$[0].gather_subset[0]", "message": "1 is not one of ['all', 'min', 'all_ipv4_addresses', 'all_ipv6_addresses', 'apparmor', 'architecture', 'caps', 'chroot,cmdline', 'date_time', 'default_ipv4', 'default_ipv6', 'devices', 'distribution', 'distribution_major_version', 'distribution_release', 'distribution_version', 'dns', 'effective_group_ids', 'effective_user_id', 'env', 'facter', 'fips', 'hardware', 'interfaces', 'is_chroot', 'iscsi', 'kernel', 'local', 'lsb', 'machine', 'machine_id', 'mounts', 'network', 'ohai', 'os_family', 'pkg_mgr', 'platform', 'processor', 'processor_cores', 'processor_count', 'python', 'python_version', 'real_user_id', 'selinux', 'service_mgr', 'ssh_host_key_dsa_public', 'ssh_host_key_ecdsa_public', 'ssh_host_key_ed25519_public', 'ssh_host_key_rsa_public', 'ssh_host_pub_keys', 'ssh_pub_keys', 'system', 'system_capabilities', 'system_capabilities_enforced', 'user', 'user_dir', 'user_gecos', 'user_gid', 'user_id', 'user_shell', 'user_uid', 'virtual', 'virtualization_role', 'virtualization_type']" }, { "path": "$[0].gather_subset[0]", "message": "1 is not of type 'string'" }, { "path": "$[0].gather_subset[0]", "message": "1 is not one of ['!all', '!min', '!all_ipv4_addresses', '!all_ipv6_addresses', '!apparmor', '!architecture', '!caps', '!chroot,cmdline', '!date_time', '!default_ipv4', '!default_ipv6', '!devices', '!distribution', '!distribution_major_version', '!distribution_release', '!distribution_version', '!dns', '!effective_group_ids', '!effective_user_id', '!env', '!facter', '!fips', '!hardware', '!interfaces', '!is_chroot', '!iscsi', '!kernel', '!local', '!lsb', '!machine', '!machine_id', '!mounts', '!network', '!ohai', '!os_family', '!pkg_mgr', '!platform', '!processor', '!processor_cores', '!processor_count', '!python', '!python_version', '!real_user_id', '!selinux', '!service_mgr', '!ssh_host_key_dsa_public', '!ssh_host_key_ecdsa_public', '!ssh_host_key_ed25519_public', '!ssh_host_key_rsa_public', '!ssh_host_pub_keys', '!ssh_pub_keys', '!system', '!system_capabilities', '!system_capabilities_enforced', '!user', '!user_dir', '!user_gecos', '!user_gid', '!user_id', '!user_shell', '!user_uid', '!virtual', '!virtualization_role', '!virtualization_type']" }, { "path": "$[0].gather_subset[0]", "message": "1 is not of type 'string'" } ] } ], "parse_errors": [] } ``` ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/gather_subset4.yml����������������0000664�0000000�0000000�00000000141�14773473560�0030770�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - hosts: localhost gather_subset: 1 tasks: - ansible.builtin.debug: msg: foo �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/gather_subset4.yml.md�������������0000664�0000000�0000000�00000006516�14773473560�0031403�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "gather_subset" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/gather_subset", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/properties/gather_subset/type" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/gather_subset4.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'gather_subset': 1, 'tasks': [{'ansible.builtin.debug': {'msg': 'foo'}}]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'gather_subset', 'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].gather_subset", "message": "1 is not of type 'array'" }, "num_sub_errors": 4, "sub_errors": [ { "path": "$[0]", "message": "'gather_subset', 'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'gather_subset': 1, 'tasks': [{'ansible.builtin.debug': {'msg': 'foo'}}]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].gather_subset", "message": "1 is not of type 'array'" } ] } ], "parse_errors": [] } ``` ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/ignore-unreachable.yml������������0000664�0000000�0000000�00000000466�14773473560�0031611�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Test hosts: localhost tasks: - name: Debug ansible.builtin.debug: msg: ignore_unreachable should not be a string ignore_unreachable: "yes" - name: Debug ansible.builtin.debug: msg: jinja evaluation should not be a string ignore_unreachable: 123 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/ignore-unreachable.yml.md���������0000664�0000000�0000000�00000022403�14773473560�0032203�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/tasks/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/tasks/0/ignore_unreachable", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/tasks/0/ignore_unreachable", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/tasks/0/ignore_unreachable", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0/tasks/0/ignore_unreachable", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/tasks/0/ignore_unreachable", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/tasks/0/ignore_unreachable", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0/tasks/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" }, { "instancePath": "/0/tasks/1", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/tasks/1/ignore_unreachable", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/tasks/1/ignore_unreachable", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/oneOf/1/type" }, { "instancePath": "/0/tasks/1/ignore_unreachable", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/full-jinja/type" }, { "instancePath": "/0/tasks/1/ignore_unreachable", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0/tasks/1/ignore_unreachable", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/tasks/1/ignore_unreachable", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/oneOf/1/type" }, { "instancePath": "/0/tasks/1/ignore_unreachable", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/full-jinja/type" }, { "instancePath": "/0/tasks/1/ignore_unreachable", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0/tasks/1", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/ignore-unreachable.yml", "path": "$[0]", "message": "{'name': 'Test', 'hosts': 'localhost', 'tasks': [{'name': 'Debug', 'ansible.builtin.debug': {'msg': 'ignore_unreachable should not be a string'}, 'ignore_unreachable': 'yes'}, {'name': 'Debug', 'ansible.builtin.debug': {'msg': 'jinja evaluation should not be a string'}, 'ignore_unreachable': 123}]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].tasks[0].ignore_unreachable", "message": "'yes' is not of type 'boolean'" }, "num_sub_errors": 19, "sub_errors": [ { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'name': 'Test', 'hosts': 'localhost', 'tasks': [{'name': 'Debug', 'ansible.builtin.debug': {'msg': 'ignore_unreachable should not be a string'}, 'ignore_unreachable': 'yes'}, {'name': 'Debug', 'ansible.builtin.debug': {'msg': 'jinja evaluation should not be a string'}, 'ignore_unreachable': 123}]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].tasks[0]", "message": "{'name': 'Debug', 'ansible.builtin.debug': {'msg': 'ignore_unreachable should not be a string'}, 'ignore_unreachable': 'yes'} is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].ignore_unreachable", "message": "'yes' is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].ignore_unreachable", "message": "'yes' is not of type 'boolean'" }, { "path": "$[0].tasks[0].ignore_unreachable", "message": "'yes' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" }, { "path": "$[0].tasks[0]", "message": "'block' is a required property" }, { "path": "$[0].tasks[0].ignore_unreachable", "message": "'yes' is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].ignore_unreachable", "message": "'yes' is not of type 'boolean'" }, { "path": "$[0].tasks[0].ignore_unreachable", "message": "'yes' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" }, { "path": "$[0].tasks[1]", "message": "{'name': 'Debug', 'ansible.builtin.debug': {'msg': 'jinja evaluation should not be a string'}, 'ignore_unreachable': 123} is not valid under any of the given schemas" }, { "path": "$[0].tasks[1].ignore_unreachable", "message": "123 is not valid under any of the given schemas" }, { "path": "$[0].tasks[1].ignore_unreachable", "message": "123 is not of type 'boolean'" }, { "path": "$[0].tasks[1].ignore_unreachable", "message": "123 is not of type 'string'" }, { "path": "$[0].tasks[1]", "message": "'block' is a required property" }, { "path": "$[0].tasks[1].ignore_unreachable", "message": "123 is not valid under any of the given schemas" }, { "path": "$[0].tasks[1].ignore_unreachable", "message": "123 is not of type 'boolean'" }, { "path": "$[0].tasks[1].ignore_unreachable", "message": "123 is not of type 'string'" } ] } ], "parse_errors": [] } ``` �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/ignore_errors.yml�����������������0000664�0000000�0000000�00000000254�14773473560�0030731�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost tasks: - command: echo 123 vars: should_ignore_errors: true ignore_errors: should_ignore_errors # invalid due to missing {{ }} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/ignore_errors.yml.md��������������0000664�0000000�0000000�00000013547�14773473560�0031341�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/tasks/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/tasks/0/ignore_errors", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/tasks/0/ignore_errors", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/tasks/0/ignore_errors", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0/tasks/0/ignore_errors", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/tasks/0/ignore_errors", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/tasks/0/ignore_errors", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0/tasks/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/ignore_errors.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'tasks': [{'command': 'echo 123', 'vars': {'should_ignore_errors': True}, 'ignore_errors': 'should_ignore_errors'}]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].tasks[0].ignore_errors", "message": "'should_ignore_errors' is not of type 'boolean'" }, "num_sub_errors": 11, "sub_errors": [ { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'tasks': [{'command': 'echo 123', 'vars': {'should_ignore_errors': True}, 'ignore_errors': 'should_ignore_errors'}]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].tasks[0]", "message": "{'command': 'echo 123', 'vars': {'should_ignore_errors': True}, 'ignore_errors': 'should_ignore_errors'} is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].ignore_errors", "message": "'should_ignore_errors' is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].ignore_errors", "message": "'should_ignore_errors' is not of type 'boolean'" }, { "path": "$[0].tasks[0].ignore_errors", "message": "'should_ignore_errors' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" }, { "path": "$[0].tasks[0]", "message": "'block' is a required property" }, { "path": "$[0].tasks[0].ignore_errors", "message": "'should_ignore_errors' is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].ignore_errors", "message": "'should_ignore_errors' is not of type 'boolean'" }, { "path": "$[0].tasks[0].ignore_errors", "message": "'should_ignore_errors' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" } ] } ], "parse_errors": [] } ``` ���������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/import_playbook.yml���������������0000664�0000000�0000000�00000000110�14773473560�0031253�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- ansible.builtin.import_playbook: {} # only freeform/string is allowed ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/import_playbook.yml.md������������0000664�0000000�0000000�00000004563�14773473560�0031672�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0/ansible.builtin.import_playbook", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/patternProperties/%5E(ansible%5C.builtin%5C.)%3Fimport_playbook%24/type" }, { "instancePath": "/0", "keyword": "not", "message": "must NOT be valid", "params": {}, "schemaPath": "#/allOf/0/not" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'hosts'", "params": { "missingProperty": "hosts" }, "schemaPath": "#/required" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/import_playbook.yml", "path": "$[0]", "message": "{'ansible.builtin.import_playbook': {}} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "{'ansible.builtin.import_playbook': {}} should not be valid under {'required': ['ansible.builtin.import_playbook']}" }, "best_deep_match": { "path": "$[0].ansible.builtin.import_playbook", "message": "{} is not of type 'string'" }, "num_sub_errors": 3, "sub_errors": [ { "path": "$[0].ansible.builtin.import_playbook", "message": "{} is not of type 'string'" }, { "path": "$[0]", "message": "Additional properties are not allowed ('ansible.builtin.import_playbook' was unexpected)" }, { "path": "$[0]", "message": "{'ansible.builtin.import_playbook': {}} should not be valid under {'required': ['ansible.builtin.import_playbook']}" }, { "path": "$[0]", "message": "'hosts' is a required property" } ] } ], "parse_errors": [] } ``` ���������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/import_playbook_exclusive.yml�����0000664�0000000�0000000�00000000215�14773473560�0033350�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- # invalid because you cannot have both entries in the same time: - ansible.builtin.import_playbook: foo.yml import_playbook: other.yml �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/import_playbook_exclusive.yml.md��0000664�0000000�0000000�00000007571�14773473560�0033763�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "not", "message": "must NOT be valid", "params": {}, "schemaPath": "#/oneOf/0/not" }, { "instancePath": "/0", "keyword": "not", "message": "must NOT be valid", "params": {}, "schemaPath": "#/oneOf/1/not" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "not", "message": "must NOT be valid", "params": {}, "schemaPath": "#/allOf/0/not" }, { "instancePath": "/0", "keyword": "not", "message": "must NOT be valid", "params": {}, "schemaPath": "#/allOf/1/not" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'hosts'", "params": { "missingProperty": "hosts" }, "schemaPath": "#/required" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "import_playbook" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/import_playbook_exclusive.yml", "path": "$[0]", "message": "{'ansible.builtin.import_playbook': 'foo.yml', 'import_playbook': 'other.yml'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "{'ansible.builtin.import_playbook': 'foo.yml', 'import_playbook': 'other.yml'} should not be valid under {'required': ['ansible.builtin.import_playbook']}" }, "best_deep_match": { "path": "$[0]", "message": "{'ansible.builtin.import_playbook': 'foo.yml', 'import_playbook': 'other.yml'} should not be valid under {'required': ['import_playbook']}" }, "num_sub_errors": 6, "sub_errors": [ { "path": "$[0]", "message": "{'ansible.builtin.import_playbook': 'foo.yml', 'import_playbook': 'other.yml'} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "{'ansible.builtin.import_playbook': 'foo.yml', 'import_playbook': 'other.yml'} should not be valid under {'required': ['import_playbook']}" }, { "path": "$[0]", "message": "{'ansible.builtin.import_playbook': 'foo.yml', 'import_playbook': 'other.yml'} should not be valid under {'required': ['ansible.builtin.import_playbook']}" }, { "path": "$[0]", "message": "Additional properties are not allowed ('ansible.builtin.import_playbook', 'import_playbook' were unexpected)" }, { "path": "$[0]", "message": "{'ansible.builtin.import_playbook': 'foo.yml', 'import_playbook': 'other.yml'} should not be valid under {'required': ['ansible.builtin.import_playbook']}" }, { "path": "$[0]", "message": "{'ansible.builtin.import_playbook': 'foo.yml', 'import_playbook': 'other.yml'} should not be valid under {'required': ['import_playbook']}" }, { "path": "$[0]", "message": "'hosts' is a required property" } ] } ], "parse_errors": [] } ``` ���������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/include.yml�����������������������0000664�0000000�0000000�00000000121�14773473560�0027466�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost tasks: - include: foo.yml # <-- removed in Ansible 2.16 �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/include.yml.md��������������������0000664�0000000�0000000�00000007161�14773473560�0030100�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/tasks/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/tasks/0/include", "keyword": "not", "message": "must NOT be valid", "params": {}, "schemaPath": "#/$defs/removed-include-module/not" }, { "instancePath": "/0/tasks/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/include.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'tasks': [{'include': 'foo.yml'}]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].tasks[0].include", "message": "'foo.yml' should not be valid under {}" }, "num_sub_errors": 6, "sub_errors": [ { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'tasks': [{'include': 'foo.yml'}]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].tasks[0]", "message": "{'include': 'foo.yml'} is not valid under any of the given schemas" }, { "path": "$[0].tasks[0]", "message": "'block' is a required property" }, { "path": "$[0].tasks[0].include", "message": "'foo.yml' should not be valid under {}" } ] } ], "parse_errors": [] } ``` ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/invalid-failed-when.yml�����������0000664�0000000�0000000�00000000475�14773473560�0031666�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost tasks: - debug: msg: "failed_when should not accept numeric" failed_when: 123 - debug: msg: "failed_when should not accept sequence" failed_when: - foo - bar - debug: msg: "failed_when should not accept map" failed_when: {} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/invalid-failed-when.yml.md��������0000664�0000000�0000000�00000016312�14773473560�0032262�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/tasks/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/tasks/0/failed_when", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/$defs/complex_conditional/oneOf/0/type" }, { "instancePath": "/0/tasks/0/failed_when", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/complex_conditional/oneOf/1/type" }, { "instancePath": "/0/tasks/0/failed_when", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/$defs/complex_conditional/oneOf/2/type" }, { "instancePath": "/0/tasks/0/failed_when", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/$defs/complex_conditional/oneOf" }, { "instancePath": "/0/tasks/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" }, { "instancePath": "/0/tasks/2", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/tasks/2/failed_when", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/$defs/complex_conditional/oneOf/0/type" }, { "instancePath": "/0/tasks/2/failed_when", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/complex_conditional/oneOf/1/type" }, { "instancePath": "/0/tasks/2/failed_when", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/$defs/complex_conditional/oneOf/2/type" }, { "instancePath": "/0/tasks/2/failed_when", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/$defs/complex_conditional/oneOf" }, { "instancePath": "/0/tasks/2", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/invalid-failed-when.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'tasks': [{'debug': {'msg': 'failed_when should not accept numeric'}, 'failed_when': 123}, {'debug': {'msg': 'failed_when should not accept sequence'}, 'failed_when': ['foo', 'bar']}, {'debug': {'msg': 'failed_when should not accept map'}, 'failed_when': {}}]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].tasks[0].failed_when", "message": "123 is not of type 'boolean'" }, "num_sub_errors": 15, "sub_errors": [ { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'tasks': [{'debug': {'msg': 'failed_when should not accept numeric'}, 'failed_when': 123}, {'debug': {'msg': 'failed_when should not accept sequence'}, 'failed_when': ['foo', 'bar']}, {'debug': {'msg': 'failed_when should not accept map'}, 'failed_when': {}}]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].tasks[0]", "message": "{'debug': {'msg': 'failed_when should not accept numeric'}, 'failed_when': 123} is not valid under any of the given schemas" }, { "path": "$[0].tasks[0]", "message": "'block' is a required property" }, { "path": "$[0].tasks[0].failed_when", "message": "123 is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].failed_when", "message": "123 is not of type 'boolean'" }, { "path": "$[0].tasks[0].failed_when", "message": "123 is not of type 'string'" }, { "path": "$[0].tasks[0].failed_when", "message": "123 is not of type 'array'" }, { "path": "$[0].tasks[2]", "message": "{'debug': {'msg': 'failed_when should not accept map'}, 'failed_when': {}} is not valid under any of the given schemas" }, { "path": "$[0].tasks[2]", "message": "'block' is a required property" }, { "path": "$[0].tasks[2].failed_when", "message": "{} is not valid under any of the given schemas" }, { "path": "$[0].tasks[2].failed_when", "message": "{} is not of type 'boolean'" }, { "path": "$[0].tasks[2].failed_when", "message": "{} is not of type 'string'" }, { "path": "$[0].tasks[2].failed_when", "message": "{} is not of type 'array'" } ] } ], "parse_errors": [] } ``` ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/invalid-serial.yml����������������0000664�0000000�0000000�00000000044�14773473560�0030752�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost serial: 10%BAD ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/invalid-serial.yml.md�������������0000664�0000000�0000000�00000011151�14773473560�0031352�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "serial" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/serial", "keyword": "type", "message": "must be integer", "params": { "type": "integer" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/serial", "keyword": "pattern", "message": "must match pattern \"^\\d+\\.?\\d*%?$\"", "params": { "pattern": "^\\d+\\.?\\d*%?$" }, "schemaPath": "#/oneOf/1/pattern" }, { "instancePath": "/0/serial", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/serial", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0/serial", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/properties/serial/anyOf/1/type" }, { "instancePath": "/0/serial", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/properties/serial/anyOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/invalid-serial.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'serial': '10%BAD'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts', 'serial' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].serial", "message": "'10%BAD' is not of type 'integer'" }, "num_sub_errors": 9, "sub_errors": [ { "path": "$[0]", "message": "'hosts', 'serial' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'serial': '10%BAD'} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].serial", "message": "'10%BAD' is not valid under any of the given schemas" }, { "path": "$[0].serial", "message": "'10%BAD' is not valid under any of the given schemas" }, { "path": "$[0].serial", "message": "'10%BAD' is not of type 'integer'" }, { "path": "$[0].serial", "message": "'10%BAD' does not match '^\\\\d+\\\\.?\\\\d*%?$'" }, { "path": "$[0].serial", "message": "'10%BAD' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" }, { "path": "$[0].serial", "message": "'10%BAD' is not of type 'array'" } ] } ], "parse_errors": [] } ``` �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/invalid.yml�����������������������0000664�0000000�0000000�00000000146�14773473560�0027500�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- name: foo hosts: localhost # <-- not allowed with import_playbook import_playbook: included.yml ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/invalid.yml.md��������������������0000664�0000000�0000000�00000004273�14773473560�0030104�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "not", "message": "must NOT be valid", "params": {}, "schemaPath": "#/allOf/1/not" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "import_playbook" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/invalid.yml", "path": "$[0]", "message": "{'name': 'foo', 'hosts': 'localhost', 'import_playbook': 'included.yml'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "{'name': 'foo', 'hosts': 'localhost', 'import_playbook': 'included.yml'} should not be valid under {'required': ['import_playbook']}" }, "best_deep_match": { "path": "$[0]", "message": "'hosts' does not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "num_sub_errors": 2, "sub_errors": [ { "path": "$[0]", "message": "'hosts' does not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "Additional properties are not allowed ('import_playbook' was unexpected)" }, { "path": "$[0]", "message": "{'name': 'foo', 'hosts': 'localhost', 'import_playbook': 'included.yml'} should not be valid under {'required': ['import_playbook']}" } ] } ], "parse_errors": [] } ``` �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/invalid_become.yml����������������0000664�0000000�0000000�00000000107�14773473560�0031007�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - hosts: localhost become: yes # <- invalid based on json schema ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/invalid_become.yml.md�������������0000664�0000000�0000000�00000007227�14773473560�0031420�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "become" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/become", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/become", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/become", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/invalid_become.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'become': 'yes'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'become', 'hosts' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].become", "message": "'yes' is not of type 'boolean'" }, "num_sub_errors": 6, "sub_errors": [ { "path": "$[0]", "message": "'become', 'hosts' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'become': 'yes'} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].become", "message": "'yes' is not valid under any of the given schemas" }, { "path": "$[0].become", "message": "'yes' is not of type 'boolean'" }, { "path": "$[0].become", "message": "'yes' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" } ] } ], "parse_errors": [] } ``` �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/local_action.yml������������������0000664�0000000�0000000�00000000130�14773473560�0030472�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost tasks: - local_action: [] # <-- only string or dict is allowed ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/local_action.yml.md���������������0000664�0000000�0000000�00000007274�14773473560�0031111�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/tasks/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/tasks/0/local_action", "keyword": "type", "message": "must be string,object", "params": { "type": [ "string", "object" ] }, "schemaPath": "#/properties/local_action/type" }, { "instancePath": "/0/tasks/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/local_action.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'tasks': [{'local_action': []}]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].tasks[0].local_action", "message": "[] is not of type 'string', 'object'" }, "num_sub_errors": 6, "sub_errors": [ { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'tasks': [{'local_action': []}]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].tasks[0]", "message": "{'local_action': []} is not valid under any of the given schemas" }, { "path": "$[0].tasks[0]", "message": "'block' is a required property" }, { "path": "$[0].tasks[0].local_action", "message": "[] is not of type 'string', 'object'" } ] } ], "parse_errors": [] } ``` ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/loop.yml��������������������������0000664�0000000�0000000�00000000226�14773473560�0027022�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - hosts: localhost tasks: - name: that should pass ansible.builtin.debug: var: item loop: 123 # <-- number is not valid ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/loop.yml.md�����������������������0000664�0000000�0000000�00000007517�14773473560�0027433�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/tasks/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/tasks/0/loop", "keyword": "type", "message": "must be string,array", "params": { "type": [ "string", "array" ] }, "schemaPath": "#/properties/loop/type" }, { "instancePath": "/0/tasks/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/loop.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'tasks': [{'name': 'that should pass', 'ansible.builtin.debug': {'var': 'item'}, 'loop': 123}]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].tasks[0].loop", "message": "123 is not of type 'string', 'array'" }, "num_sub_errors": 6, "sub_errors": [ { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'tasks': [{'name': 'that should pass', 'ansible.builtin.debug': {'var': 'item'}, 'loop': 123}]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].tasks[0]", "message": "{'name': 'that should pass', 'ansible.builtin.debug': {'var': 'item'}, 'loop': 123} is not valid under any of the given schemas" }, { "path": "$[0].tasks[0]", "message": "'block' is a required property" }, { "path": "$[0].tasks[0].loop", "message": "123 is not of type 'string', 'array'" } ] } ], "parse_errors": [] } ``` ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/loop2.yml�������������������������0000664�0000000�0000000�00000000222�14773473560�0027100�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - hosts: localhost tasks: - name: that should pass ansible.builtin.debug: var: item loop: {} # <-- map is not valid ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/loop2.yml.md����������������������0000664�0000000�0000000�00000007513�14773473560�0027511�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/tasks/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/tasks/0/loop", "keyword": "type", "message": "must be string,array", "params": { "type": [ "string", "array" ] }, "schemaPath": "#/properties/loop/type" }, { "instancePath": "/0/tasks/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/loop2.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'tasks': [{'name': 'that should pass', 'ansible.builtin.debug': {'var': 'item'}, 'loop': {}}]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].tasks[0].loop", "message": "{} is not of type 'string', 'array'" }, "num_sub_errors": 6, "sub_errors": [ { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'tasks': [{'name': 'that should pass', 'ansible.builtin.debug': {'var': 'item'}, 'loop': {}}]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].tasks[0]", "message": "{'name': 'that should pass', 'ansible.builtin.debug': {'var': 'item'}, 'loop': {}} is not valid under any of the given schemas" }, { "path": "$[0].tasks[0]", "message": "'block' is a required property" }, { "path": "$[0].tasks[0].loop", "message": "{} is not of type 'string', 'array'" } ] } ], "parse_errors": [] } ``` �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/no_log_partial_template.yml�������0000664�0000000�0000000�00000000262�14773473560�0032735�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost vars: some_var: true tasks: - ansible.builtin.debug: msg: foo no_log: "foo-{{ some_var }}" # <-- partial templating not allowed here ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/no_log_partial_template.yml.md����0000664�0000000�0000000�00000013343�14773473560�0033340�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/tasks/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/tasks/0/no_log", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/tasks/0/no_log", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/tasks/0/no_log", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0/tasks/0/no_log", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/tasks/0/no_log", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/tasks/0/no_log", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0/tasks/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/no_log_partial_template.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'vars': {'some_var': True}, 'tasks': [{'ansible.builtin.debug': {'msg': 'foo'}, 'no_log': 'foo-{{ some_var }}'}]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].tasks[0].no_log", "message": "'foo-{{ some_var }}' is not of type 'boolean'" }, "num_sub_errors": 11, "sub_errors": [ { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'vars': {'some_var': True}, 'tasks': [{'ansible.builtin.debug': {'msg': 'foo'}, 'no_log': 'foo-{{ some_var }}'}]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].tasks[0]", "message": "{'ansible.builtin.debug': {'msg': 'foo'}, 'no_log': 'foo-{{ some_var }}'} is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].no_log", "message": "'foo-{{ some_var }}' is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].no_log", "message": "'foo-{{ some_var }}' is not of type 'boolean'" }, { "path": "$[0].tasks[0].no_log", "message": "'foo-{{ some_var }}' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" }, { "path": "$[0].tasks[0]", "message": "'block' is a required property" }, { "path": "$[0].tasks[0].no_log", "message": "'foo-{{ some_var }}' is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].no_log", "message": "'foo-{{ some_var }}' is not of type 'boolean'" }, { "path": "$[0].tasks[0].no_log", "message": "'foo-{{ some_var }}' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" } ] } ], "parse_errors": [] } ``` ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/no_log_string.yml�����������������0000664�0000000�0000000�00000000242�14773473560�0030712�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost vars: some_var: true tasks: - ansible.builtin.debug: msg: foo no_log: some_var # <-- bad, jinja use must be explicit ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/no_log_string.yml.md��������������0000664�0000000�0000000�00000013165�14773473560�0031321�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/tasks/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/tasks/0/no_log", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/tasks/0/no_log", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/tasks/0/no_log", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0/tasks/0/no_log", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/tasks/0/no_log", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/tasks/0/no_log", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0/tasks/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/no_log_string.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'vars': {'some_var': True}, 'tasks': [{'ansible.builtin.debug': {'msg': 'foo'}, 'no_log': 'some_var'}]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].tasks[0].no_log", "message": "'some_var' is not of type 'boolean'" }, "num_sub_errors": 11, "sub_errors": [ { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'vars': {'some_var': True}, 'tasks': [{'ansible.builtin.debug': {'msg': 'foo'}, 'no_log': 'some_var'}]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].tasks[0]", "message": "{'ansible.builtin.debug': {'msg': 'foo'}, 'no_log': 'some_var'} is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].no_log", "message": "'some_var' is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].no_log", "message": "'some_var' is not of type 'boolean'" }, { "path": "$[0].tasks[0].no_log", "message": "'some_var' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" }, { "path": "$[0].tasks[0]", "message": "'block' is a required property" }, { "path": "$[0].tasks[0].no_log", "message": "'some_var' is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].no_log", "message": "'some_var' is not of type 'boolean'" }, { "path": "$[0].tasks[0].no_log", "message": "'some_var' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" } ] } ], "parse_errors": [] } ``` �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/roles.yml�������������������������0000664�0000000�0000000�00000000060�14773473560�0027171�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost roles: xxx # must be array ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/roles.yml.md����������������������0000664�0000000�0000000�00000005651�14773473560�0027603�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "roles" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/roles", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/properties/roles/type" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/roles.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'roles': 'xxx'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts', 'roles' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].roles", "message": "'xxx' is not of type 'array'" }, "num_sub_errors": 4, "sub_errors": [ { "path": "$[0]", "message": "'hosts', 'roles' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'roles': 'xxx'} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].roles", "message": "'xxx' is not of type 'array'" } ] } ], "parse_errors": [] } ``` ���������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/run_once_list.yml�����������������0000664�0000000�0000000�00000000314�14773473560�0030712�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost tasks: - name: foo2 ansible.builtin.debug: msg: foo! run_once: # invalid due to schema, also ansible does not allow lists - "{{ true }}" - xxx ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/run_once_list.yml.md��������������0000664�0000000�0000000�00000013636�14773473560�0031324�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/tasks/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/tasks/0/run_once", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/tasks/0/run_once", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/oneOf/1/type" }, { "instancePath": "/0/tasks/0/run_once", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/full-jinja/type" }, { "instancePath": "/0/tasks/0/run_once", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0/tasks/0/run_once", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/tasks/0/run_once", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/oneOf/1/type" }, { "instancePath": "/0/tasks/0/run_once", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/full-jinja/type" }, { "instancePath": "/0/tasks/0/run_once", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0/tasks/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/run_once_list.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'tasks': [{'name': 'foo2', 'ansible.builtin.debug': {'msg': 'foo!'}, 'run_once': ['{{ true }}', 'xxx']}]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].tasks[0].run_once", "message": "['{{ true }}', 'xxx'] is not of type 'boolean'" }, "num_sub_errors": 11, "sub_errors": [ { "path": "$[0]", "message": "'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'tasks': [{'name': 'foo2', 'ansible.builtin.debug': {'msg': 'foo!'}, 'run_once': ['{{ true }}', 'xxx']}]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].tasks[0]", "message": "{'name': 'foo2', 'ansible.builtin.debug': {'msg': 'foo!'}, 'run_once': ['{{ true }}', 'xxx']} is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].run_once", "message": "['{{ true }}', 'xxx'] is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].run_once", "message": "['{{ true }}', 'xxx'] is not of type 'boolean'" }, { "path": "$[0].tasks[0].run_once", "message": "['{{ true }}', 'xxx'] is not of type 'string'" }, { "path": "$[0].tasks[0]", "message": "'block' is a required property" }, { "path": "$[0].tasks[0].run_once", "message": "['{{ true }}', 'xxx'] is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].run_once", "message": "['{{ true }}', 'xxx'] is not of type 'boolean'" }, { "path": "$[0].tasks[0].run_once", "message": "['{{ true }}', 'xxx'] is not of type 'string'" } ] } ], "parse_errors": [] } ``` ��������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tags-mapping.yml������������������0000664�0000000�0000000�00000000060�14773473560�0030434�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost tags: {} # <-- not allowed ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tags-mapping.yml.md���������������0000664�0000000�0000000�00000010125�14773473560�0031036�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/tags", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/tags/anyOf/0/type" }, { "instancePath": "/0/tags", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/$defs/tags/anyOf/1/type" }, { "instancePath": "/0/tags", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/$defs/tags/anyOf" }, { "instancePath": "/0/tags", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/tags/anyOf/0/type" }, { "instancePath": "/0/tags", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/$defs/tags/anyOf/1/type" }, { "instancePath": "/0/tags", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/$defs/tags/anyOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tags-mapping.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'tags': {}} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts' does not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].tags", "message": "{} is not of type 'string'" }, "num_sub_errors": 9, "sub_errors": [ { "path": "$[0]", "message": "'hosts' does not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'tags': {}} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].tags", "message": "{} is not valid under any of the given schemas" }, { "path": "$[0].tags", "message": "{} is not of type 'string'" }, { "path": "$[0].tags", "message": "{} is not of type 'array'" }, { "path": "$[0].tags", "message": "{} is not valid under any of the given schemas" }, { "path": "$[0].tags", "message": "{} is not of type 'string'" }, { "path": "$[0].tags", "message": "{} is not of type 'array'" } ] } ], "parse_errors": [] } ``` �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tags-number.yml�������������������0000664�0000000�0000000�00000000061�14773473560�0030272�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost tags: 123 # <-- not allowed �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tags-number.yml.md����������������0000664�0000000�0000000�00000010135�14773473560�0030674�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/tags", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/tags/anyOf/0/type" }, { "instancePath": "/0/tags", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/$defs/tags/anyOf/1/type" }, { "instancePath": "/0/tags", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/$defs/tags/anyOf" }, { "instancePath": "/0/tags", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/tags/anyOf/0/type" }, { "instancePath": "/0/tags", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/$defs/tags/anyOf/1/type" }, { "instancePath": "/0/tags", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/$defs/tags/anyOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tags-number.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'tags': 123} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts' does not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].tags", "message": "123 is not of type 'string'" }, "num_sub_errors": 9, "sub_errors": [ { "path": "$[0]", "message": "'hosts' does not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'tags': 123} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].tags", "message": "123 is not valid under any of the given schemas" }, { "path": "$[0].tags", "message": "123 is not of type 'string'" }, { "path": "$[0].tags", "message": "123 is not of type 'array'" }, { "path": "$[0].tags", "message": "123 is not valid under any of the given schemas" }, { "path": "$[0].tags", "message": "123 is not of type 'string'" }, { "path": "$[0].tags", "message": "123 is not of type 'array'" } ] } ], "parse_errors": [] } ``` �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks.yml�������������������������0000664�0000000�0000000�00000000240�14773473560�0027172�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost pre_tasks: foo # <-- must be array post_tasks: {} # <-- must be array tasks: 1 # <-- must be array handlers: 1.0 # <-- must be array ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks.yml.md����������������������0000664�0000000�0000000�00000011421�14773473560�0027574�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "pre_tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "post_tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "handlers" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/handlers", "keyword": "type", "message": "must be array,null", "params": { "type": [ "array", "null" ] }, "schemaPath": "#/type" }, { "instancePath": "/0/post_tasks", "keyword": "type", "message": "must be array,null", "params": { "type": [ "array", "null" ] }, "schemaPath": "#/type" }, { "instancePath": "/0/pre_tasks", "keyword": "type", "message": "must be array,null", "params": { "type": [ "array", "null" ] }, "schemaPath": "#/type" }, { "instancePath": "/0/tasks", "keyword": "type", "message": "must be array,null", "params": { "type": [ "array", "null" ] }, "schemaPath": "#/type" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tasks.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'pre_tasks': 'foo', 'post_tasks': {}, 'tasks': 1, 'handlers': 1.0} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'handlers', 'hosts', 'post_tasks', 'pre_tasks', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].handlers", "message": "1.0 is not of type 'array', 'null'" }, "num_sub_errors": 7, "sub_errors": [ { "path": "$[0]", "message": "'handlers', 'hosts', 'post_tasks', 'pre_tasks', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'pre_tasks': 'foo', 'post_tasks': {}, 'tasks': 1, 'handlers': 1.0} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].handlers", "message": "1.0 is not of type 'array', 'null'" }, { "path": "$[0].post_tasks", "message": "{} is not of type 'array', 'null'" }, { "path": "$[0].pre_tasks", "message": "'foo' is not of type 'array', 'null'" }, { "path": "$[0].tasks", "message": "1 is not of type 'array', 'null'" } ] } ], "parse_errors": [] } ``` �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/����������������������������0000775�0000000�0000000�00000000000�14773473560�0026453�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/args_integer.yml������������0000664�0000000�0000000�00000000044�14773473560�0031645�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- action: foo args: 123 # invalid ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/args_integer.yml.md���������0000664�0000000�0000000�00000004216�14773473560�0032251�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/args", "keyword": "type", "message": "must be object", "params": { "type": "object" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/args", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/oneOf/1/type" }, { "instancePath": "/0/args", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/full-jinja/type" }, { "instancePath": "/0/args", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tasks/args_integer.yml", "path": "$[0]", "message": "{'action': 'foo', 'args': 123} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'block' is a required property" }, "best_deep_match": { "path": "$[0].args", "message": "123 is not of type 'object'" }, "num_sub_errors": 3, "sub_errors": [ { "path": "$[0]", "message": "'block' is a required property" }, { "path": "$[0].args", "message": "123 is not valid under any of the given schemas" }, { "path": "$[0].args", "message": "123 is not of type 'object'" }, { "path": "$[0].args", "message": "123 is not of type 'string'" } ] } ], "parse_errors": [] } ``` ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/args_string.yml�������������0000664�0000000�0000000�00000000127�14773473560�0031520�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- action: foo args: "{{ }}123" # invalid as only full jinja2 expressions are allowed �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/args_string.yml.md����������0000664�0000000�0000000�00000004154�14773473560�0032123�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/args", "keyword": "type", "message": "must be object", "params": { "type": "object" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/args", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/args", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tasks/args_string.yml", "path": "$[0]", "message": "{'action': 'foo', 'args': '{{ }}123'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'block' is a required property" }, "best_deep_match": { "path": "$[0].args", "message": "'{{ }}123' is not of type 'object'" }, "num_sub_errors": 3, "sub_errors": [ { "path": "$[0]", "message": "'block' is a required property" }, { "path": "$[0].args", "message": "'{{ }}123' is not valid under any of the given schemas" }, { "path": "$[0].args", "message": "'{{ }}123' is not of type 'object'" }, { "path": "$[0].args", "message": "'{{ }}123' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" } ] } ], "parse_errors": [] } ``` ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/become_method_invalid.yml���0000664�0000000�0000000�00000000104�14773473560�0033471�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- command: echo 123 vars: sudo_var: doo become_method: true ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/become_method_invalid.yml.md0000664�0000000�0000000�00000013574�14773473560�0034107�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/become_method", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/anyOf/0/type" }, { "instancePath": "/0/become_method", "keyword": "enum", "message": "must be equal to one of the allowed values", "params": { "allowedValues": [ "ansible.builtin.sudo", "ansible.builtin.su", "community.general.pbrun", "community.general.pfexec", "ansible.builtin.runas", "community.general.dzdo", "community.general.ksu", "community.general.doas", "community.general.machinectl", "community.general.pmrun", "community.general.sesu", "community.general.sudosu" ] }, "schemaPath": "#/anyOf/0/enum" }, { "instancePath": "/0/become_method", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/full-jinja/type" }, { "instancePath": "/0/become_method", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/anyOf/2/type" }, { "instancePath": "/0/become_method", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/anyOf" }, { "instancePath": "/0/become_method", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/anyOf/0/type" }, { "instancePath": "/0/become_method", "keyword": "enum", "message": "must be equal to one of the allowed values", "params": { "allowedValues": [ "ansible.builtin.sudo", "ansible.builtin.su", "community.general.pbrun", "community.general.pfexec", "ansible.builtin.runas", "community.general.dzdo", "community.general.ksu", "community.general.doas", "community.general.machinectl", "community.general.pmrun", "community.general.sesu", "community.general.sudosu" ] }, "schemaPath": "#/anyOf/0/enum" }, { "instancePath": "/0/become_method", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/full-jinja/type" }, { "instancePath": "/0/become_method", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/anyOf/2/type" }, { "instancePath": "/0/become_method", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/anyOf" }, { "instancePath": "/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tasks/become_method_invalid.yml", "path": "$[0]", "message": "{'command': 'echo 123', 'vars': {'sudo_var': 'doo'}, 'become_method': True} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'block' is a required property" }, "best_deep_match": { "path": "$[0].become_method", "message": "True is not one of ['ansible.builtin.sudo', 'ansible.builtin.su', 'community.general.pbrun', 'community.general.pfexec', 'ansible.builtin.runas', 'community.general.dzdo', 'community.general.ksu', 'community.general.doas', 'community.general.machinectl', 'community.general.pmrun', 'community.general.sesu', 'community.general.sudosu']" }, "num_sub_errors": 10, "sub_errors": [ { "path": "$[0].become_method", "message": "True is not valid under any of the given schemas" }, { "path": "$[0].become_method", "message": "True is not one of ['ansible.builtin.sudo', 'ansible.builtin.su', 'community.general.pbrun', 'community.general.pfexec', 'ansible.builtin.runas', 'community.general.dzdo', 'community.general.ksu', 'community.general.doas', 'community.general.machinectl', 'community.general.pmrun', 'community.general.sesu', 'community.general.sudosu']" }, { "path": "$[0].become_method", "message": "True is not of type 'string'" }, { "path": "$[0].become_method", "message": "True is not of type 'string'" }, { "path": "$[0].become_method", "message": "True is not of type 'string'" }, { "path": "$[0]", "message": "'block' is a required property" }, { "path": "$[0].become_method", "message": "True is not valid under any of the given schemas" }, { "path": "$[0].become_method", "message": "True is not one of ['ansible.builtin.sudo', 'ansible.builtin.su', 'community.general.pbrun', 'community.general.pfexec', 'ansible.builtin.runas', 'community.general.dzdo', 'community.general.ksu', 'community.general.doas', 'community.general.machinectl', 'community.general.pmrun', 'community.general.sesu', 'community.general.sudosu']" }, { "path": "$[0].become_method", "message": "True is not of type 'string'" }, { "path": "$[0].become_method", "message": "True is not of type 'string'" }, { "path": "$[0].become_method", "message": "True is not of type 'string'" } ] } ], "parse_errors": [] } ``` ������������������������������������������������������������������������������������������������������������������������������������become_method_untemplated.yml.md��������������������������������������������������������������������0000664�0000000�0000000�00000010752�14773473560�0034717�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/become_method", "keyword": "enum", "message": "must be equal to one of the allowed values", "params": { "allowedValues": [ "sudo", "su", "pbrun", "pfexec", "runas", "dzdo", "ksu", "doas", "machinectl", "pmrun", "sesu", "sudosu" ] }, "schemaPath": "#/oneOf/0/enum" }, { "instancePath": "/0/become_method", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/become_method", "keyword": "pattern", "message": "must match pattern \"^[A-Z][a-z][0-9]._$\"", "params": { "pattern": "^[A-Z][a-z][0-9]._$" }, "schemaPath": "#/oneOf/2/pattern" }, { "instancePath": "/0/become_method", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0/become_method", "keyword": "enum", "message": "must be equal to one of the allowed values", "params": { "allowedValues": [ "sudo", "su", "pbrun", "pfexec", "runas", "dzdo", "ksu", "doas", "machinectl", "pmrun", "sesu", "sudosu" ] }, "schemaPath": "#/oneOf/0/enum" }, { "instancePath": "/0/become_method", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/become_method", "keyword": "pattern", "message": "must match pattern \"^[A-Z][a-z][0-9]._$\"", "params": { "pattern": "^[A-Z][a-z][0-9]._$" }, "schemaPath": "#/oneOf/2/pattern" }, { "instancePath": "/0/become_method", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "errors": [ { "filename": "negative_test/playbooks/tasks/become_method_untemplated.yml", "path": "$[0]", "message": "{'command': 'echo 123', 'vars': {'sudo_var': 'doo'}, 'become_method': 'sudo_var'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'block' is a required property" }, "sub_errors": [ { "path": "$[0].become_method", "message": "'sudo_var' is not valid under any of the given schemas" }, { "path": "$[0].become_method", "message": "'sudo_var' is not one of ['sudo', 'su', 'pbrun', 'pfexec', 'runas', 'dzdo', 'ksu', 'doas', 'machinectl', 'pmrun', 'sesu', 'sudosu']" }, { "path": "$[0].become_method", "message": "'sudo_var' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" }, { "path": "$[0].become_method", "message": "'sudo_var' does not match '^[A-Z][a-z][0-9]._$'" }, { "path": "$[0]", "message": "'block' is a required property" }, { "path": "$[0].become_method", "message": "'sudo_var' is not valid under any of the given schemas" }, { "path": "$[0].become_method", "message": "'sudo_var' is not one of ['sudo', 'su', 'pbrun', 'pfexec', 'runas', 'dzdo', 'ksu', 'doas', 'machinectl', 'pmrun', 'sesu', 'sudosu']" }, { "path": "$[0].become_method", "message": "'sudo_var' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" }, { "path": "$[0].become_method", "message": "'sudo_var' does not match '^[A-Z][a-z][0-9]._$'" } ] } ], "parse_errors": [] } ``` ����������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/ignore_errors.yml�����������0000664�0000000�0000000�00000000200�14773473560�0032045�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- command: echo 123 vars: should_ignore_errors: true ignore_errors: should_ignore_errors # invalid due to missing {{ }} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/ignore_errors.yml.md��������0000664�0000000�0000000�00000006600�14773473560�0032456�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/ignore_errors", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/ignore_errors", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/ignore_errors", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0/ignore_errors", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/ignore_errors", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/ignore_errors", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tasks/ignore_errors.yml", "path": "$[0]", "message": "{'command': 'echo 123', 'vars': {'should_ignore_errors': True}, 'ignore_errors': 'should_ignore_errors'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'block' is a required property" }, "best_deep_match": { "path": "$[0].ignore_errors", "message": "'should_ignore_errors' is not of type 'boolean'" }, "num_sub_errors": 6, "sub_errors": [ { "path": "$[0].ignore_errors", "message": "'should_ignore_errors' is not valid under any of the given schemas" }, { "path": "$[0].ignore_errors", "message": "'should_ignore_errors' is not of type 'boolean'" }, { "path": "$[0].ignore_errors", "message": "'should_ignore_errors' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" }, { "path": "$[0]", "message": "'block' is a required property" }, { "path": "$[0].ignore_errors", "message": "'should_ignore_errors' is not valid under any of the given schemas" }, { "path": "$[0].ignore_errors", "message": "'should_ignore_errors' is not of type 'boolean'" }, { "path": "$[0].ignore_errors", "message": "'should_ignore_errors' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" } ] } ], "parse_errors": [] } ``` ��������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/invalid_block.yml�����������0000664�0000000�0000000�00000000057�14773473560�0032000�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - block: {} # <-- invalid, should be array ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/invalid_block.yml.md��������0000664�0000000�0000000�00000002566�14773473560�0032406�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0/block", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/properties/block/type" }, { "instancePath": "/0", "keyword": "not", "message": "must NOT be valid", "params": {}, "schemaPath": "#/allOf/3/not" }, { "instancePath": "/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tasks/invalid_block.yml", "path": "$[0]", "message": "{'block': {}} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "{'block': {}} should not be valid under {'required': ['block']}" }, "best_deep_match": { "path": "$[0].block", "message": "{} is not of type 'array'" }, "num_sub_errors": 1, "sub_errors": [ { "path": "$[0].block", "message": "{} is not of type 'array'" }, { "path": "$[0]", "message": "{'block': {}} should not be valid under {'required': ['block']}" } ] } ], "parse_errors": [] } ``` ������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/local_action.yml������������0000664�0000000�0000000�00000000070�14773473560�0031622�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- local_action: [] # <-- only string or dict is allowed ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/local_action.yml.md���������0000664�0000000�0000000�00000002723�14773473560�0032230�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/local_action", "keyword": "type", "message": "must be string,object", "params": { "type": [ "string", "object" ] }, "schemaPath": "#/properties/local_action/type" }, { "instancePath": "/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tasks/local_action.yml", "path": "$[0]", "message": "{'local_action': []} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'block' is a required property" }, "best_deep_match": { "path": "$[0].local_action", "message": "[] is not of type 'string', 'object'" }, "num_sub_errors": 1, "sub_errors": [ { "path": "$[0]", "message": "'block' is a required property" }, { "path": "$[0].local_action", "message": "[] is not of type 'string', 'object'" } ] } ], "parse_errors": [] } ``` ���������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/loop.yml��������������������0000664�0000000�0000000�00000000111�14773473560�0030140�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- ansible.builtin.debug: var: item loop: {} # <-- map is not valid �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/loop.yml.md�����������������0000664�0000000�0000000�00000002711�14773473560�0030547�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/loop", "keyword": "type", "message": "must be string,array", "params": { "type": [ "string", "array" ] }, "schemaPath": "#/properties/loop/type" }, { "instancePath": "/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tasks/loop.yml", "path": "$[0]", "message": "{'ansible.builtin.debug': {'var': 'item'}, 'loop': {}} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'block' is a required property" }, "best_deep_match": { "path": "$[0].loop", "message": "{} is not of type 'string', 'array'" }, "num_sub_errors": 1, "sub_errors": [ { "path": "$[0]", "message": "'block' is a required property" }, { "path": "$[0].loop", "message": "{} is not of type 'string', 'array'" } ] } ], "parse_errors": [] } ``` �������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/loop2.yml�������������������0000664�0000000�0000000�00000000115�14773473560�0030226�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- ansible.builtin.debug: var: item loop: 123 # <-- number is not valid ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/loop2.yml.md����������������0000664�0000000�0000000�00000002715�14773473560�0030635�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/loop", "keyword": "type", "message": "must be string,array", "params": { "type": [ "string", "array" ] }, "schemaPath": "#/properties/loop/type" }, { "instancePath": "/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tasks/loop2.yml", "path": "$[0]", "message": "{'ansible.builtin.debug': {'var': 'item'}, 'loop': 123} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'block' is a required property" }, "best_deep_match": { "path": "$[0].loop", "message": "123 is not of type 'string', 'array'" }, "num_sub_errors": 1, "sub_errors": [ { "path": "$[0]", "message": "'block' is a required property" }, { "path": "$[0].loop", "message": "123 is not of type 'string', 'array'" } ] } ], "parse_errors": [] } ``` ���������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/no_log_number.yml�����������0000664�0000000�0000000�00000000076�14773473560�0032026�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- ansible.builtin.debug: msg: foo no_log: 123 # <-- bad ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/no_log_number.yml.md��������0000664�0000000�0000000�00000006374�14773473560�0032434�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/no_log", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/no_log", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/oneOf/1/type" }, { "instancePath": "/0/no_log", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/full-jinja/type" }, { "instancePath": "/0/no_log", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0/no_log", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/no_log", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/oneOf/1/type" }, { "instancePath": "/0/no_log", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/full-jinja/type" }, { "instancePath": "/0/no_log", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tasks/no_log_number.yml", "path": "$[0]", "message": "{'ansible.builtin.debug': {'msg': 'foo'}, 'no_log': 123} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'block' is a required property" }, "best_deep_match": { "path": "$[0].no_log", "message": "123 is not of type 'boolean'" }, "num_sub_errors": 6, "sub_errors": [ { "path": "$[0].no_log", "message": "123 is not valid under any of the given schemas" }, { "path": "$[0].no_log", "message": "123 is not of type 'boolean'" }, { "path": "$[0].no_log", "message": "123 is not of type 'string'" }, { "path": "$[0]", "message": "'block' is a required property" }, { "path": "$[0].no_log", "message": "123 is not valid under any of the given schemas" }, { "path": "$[0].no_log", "message": "123 is not of type 'boolean'" }, { "path": "$[0].no_log", "message": "123 is not of type 'string'" } ] } ], "parse_errors": [] } ``` ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/no_log_string.yml�����������0000664�0000000�0000000�00000000172�14773473560�0032041�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- ansible.builtin.debug: msg: foo vars: some_var: true no_log: some_var # <-- bad, jinja use must be explicit ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/no_log_string.yml.md��������0000664�0000000�0000000�00000006304�14773473560�0032443�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/no_log", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/no_log", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/no_log", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0/no_log", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/oneOf/0/type" }, { "instancePath": "/0/no_log", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/no_log", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tasks/no_log_string.yml", "path": "$[0]", "message": "{'ansible.builtin.debug': {'msg': 'foo'}, 'vars': {'some_var': True}, 'no_log': 'some_var'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'block' is a required property" }, "best_deep_match": { "path": "$[0].no_log", "message": "'some_var' is not of type 'boolean'" }, "num_sub_errors": 6, "sub_errors": [ { "path": "$[0].no_log", "message": "'some_var' is not valid under any of the given schemas" }, { "path": "$[0].no_log", "message": "'some_var' is not of type 'boolean'" }, { "path": "$[0].no_log", "message": "'some_var' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" }, { "path": "$[0]", "message": "'block' is a required property" }, { "path": "$[0].no_log", "message": "'some_var' is not valid under any of the given schemas" }, { "path": "$[0].no_log", "message": "'some_var' is not of type 'boolean'" }, { "path": "$[0].no_log", "message": "'some_var' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" } ] } ], "parse_errors": [] } ``` ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/tags-mapping.yml������������0000664�0000000�0000000�00000000103�14773473560�0031557�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- ansible.builtin.debug: msg: foo tags: {} # <-- not allowed �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/tags-mapping.yml.md���������0000664�0000000�0000000�00000005474�14773473560�0032176�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/tags", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/tags/anyOf/0/type" }, { "instancePath": "/0/tags", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/$defs/tags/anyOf/1/type" }, { "instancePath": "/0/tags", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/$defs/tags/anyOf" }, { "instancePath": "/0/tags", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/tags/anyOf/0/type" }, { "instancePath": "/0/tags", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/$defs/tags/anyOf/1/type" }, { "instancePath": "/0/tags", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/$defs/tags/anyOf" }, { "instancePath": "/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tasks/tags-mapping.yml", "path": "$[0]", "message": "{'ansible.builtin.debug': {'msg': 'foo'}, 'tags': {}} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'block' is a required property" }, "best_deep_match": { "path": "$[0].tags", "message": "{} is not of type 'string'" }, "num_sub_errors": 6, "sub_errors": [ { "path": "$[0].tags", "message": "{} is not valid under any of the given schemas" }, { "path": "$[0].tags", "message": "{} is not of type 'string'" }, { "path": "$[0].tags", "message": "{} is not of type 'array'" }, { "path": "$[0]", "message": "'block' is a required property" }, { "path": "$[0].tags", "message": "{} is not valid under any of the given schemas" }, { "path": "$[0].tags", "message": "{} is not of type 'string'" }, { "path": "$[0].tags", "message": "{} is not of type 'array'" } ] } ], "parse_errors": [] } ``` ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/tags-string.yml�������������0000664�0000000�0000000�00000000104�14773473560�0031433�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- ansible.builtin.debug: msg: foo tags: 123 # <-- not allowed ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/tags-string.yml.md����������0000664�0000000�0000000�00000005503�14773473560�0032042�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/tags", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/tags/anyOf/0/type" }, { "instancePath": "/0/tags", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/$defs/tags/anyOf/1/type" }, { "instancePath": "/0/tags", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/$defs/tags/anyOf" }, { "instancePath": "/0/tags", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/tags/anyOf/0/type" }, { "instancePath": "/0/tags", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/$defs/tags/anyOf/1/type" }, { "instancePath": "/0/tags", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/$defs/tags/anyOf" }, { "instancePath": "/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tasks/tags-string.yml", "path": "$[0]", "message": "{'ansible.builtin.debug': {'msg': 'foo'}, 'tags': 123} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'block' is a required property" }, "best_deep_match": { "path": "$[0].tags", "message": "123 is not of type 'string'" }, "num_sub_errors": 6, "sub_errors": [ { "path": "$[0].tags", "message": "123 is not valid under any of the given schemas" }, { "path": "$[0].tags", "message": "123 is not of type 'string'" }, { "path": "$[0].tags", "message": "123 is not of type 'array'" }, { "path": "$[0]", "message": "'block' is a required property" }, { "path": "$[0].tags", "message": "123 is not valid under any of the given schemas" }, { "path": "$[0].tags", "message": "123 is not of type 'string'" }, { "path": "$[0].tags", "message": "123 is not of type 'array'" } ] } ], "parse_errors": [] } ``` ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/when_integer.yml������������0000664�0000000�0000000�00000000074�14773473560�0031655�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- action: foo when: 123 # invalid, number is not accepted ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/when_integer.yml.md���������0000664�0000000�0000000�00000007111�14773473560�0032253�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/when", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/$defs/complex_conditional/oneOf/0/type" }, { "instancePath": "/0/when", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/complex_conditional/oneOf/1/type" }, { "instancePath": "/0/when", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/$defs/complex_conditional/oneOf/2/type" }, { "instancePath": "/0/when", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/$defs/complex_conditional/oneOf" }, { "instancePath": "/0/when", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/$defs/complex_conditional/oneOf/0/type" }, { "instancePath": "/0/when", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/complex_conditional/oneOf/1/type" }, { "instancePath": "/0/when", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/$defs/complex_conditional/oneOf/2/type" }, { "instancePath": "/0/when", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/$defs/complex_conditional/oneOf" }, { "instancePath": "/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tasks/when_integer.yml", "path": "$[0]", "message": "{'action': 'foo', 'when': 123} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'block' is a required property" }, "best_deep_match": { "path": "$[0].when", "message": "123 is not of type 'boolean'" }, "num_sub_errors": 8, "sub_errors": [ { "path": "$[0].when", "message": "123 is not valid under any of the given schemas" }, { "path": "$[0].when", "message": "123 is not of type 'boolean'" }, { "path": "$[0].when", "message": "123 is not of type 'string'" }, { "path": "$[0].when", "message": "123 is not of type 'array'" }, { "path": "$[0]", "message": "'block' is a required property" }, { "path": "$[0].when", "message": "123 is not valid under any of the given schemas" }, { "path": "$[0].when", "message": "123 is not of type 'boolean'" }, { "path": "$[0].when", "message": "123 is not of type 'string'" }, { "path": "$[0].when", "message": "123 is not of type 'array'" } ] } ], "parse_errors": [] } ``` �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/when_object.yml�������������0000664�0000000�0000000�00000000073�14773473560�0031465�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- action: foo when: {} # invalid, object is not accepted ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/when_object.yml.md����������0000664�0000000�0000000�00000007076�14773473560�0032076�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/when", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/$defs/complex_conditional/oneOf/0/type" }, { "instancePath": "/0/when", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/complex_conditional/oneOf/1/type" }, { "instancePath": "/0/when", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/$defs/complex_conditional/oneOf/2/type" }, { "instancePath": "/0/when", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/$defs/complex_conditional/oneOf" }, { "instancePath": "/0/when", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/$defs/complex_conditional/oneOf/0/type" }, { "instancePath": "/0/when", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/complex_conditional/oneOf/1/type" }, { "instancePath": "/0/when", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/$defs/complex_conditional/oneOf/2/type" }, { "instancePath": "/0/when", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/$defs/complex_conditional/oneOf" }, { "instancePath": "/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tasks/when_object.yml", "path": "$[0]", "message": "{'action': 'foo', 'when': {}} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'block' is a required property" }, "best_deep_match": { "path": "$[0].when", "message": "{} is not of type 'boolean'" }, "num_sub_errors": 8, "sub_errors": [ { "path": "$[0].when", "message": "{} is not valid under any of the given schemas" }, { "path": "$[0].when", "message": "{} is not of type 'boolean'" }, { "path": "$[0].when", "message": "{} is not of type 'string'" }, { "path": "$[0].when", "message": "{} is not of type 'array'" }, { "path": "$[0]", "message": "'block' is a required property" }, { "path": "$[0].when", "message": "{} is not valid under any of the given schemas" }, { "path": "$[0].when", "message": "{} is not of type 'boolean'" }, { "path": "$[0].when", "message": "{} is not of type 'string'" }, { "path": "$[0].when", "message": "{} is not of type 'array'" } ] } ], "parse_errors": [] } ``` ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/with_items_boolean.yml������0000664�0000000�0000000�00000000125�14773473560�0033047�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- command: echo 123 with_items: true # invalid, must be a list or templated string �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks/with_items_boolean.yml.md���0000664�0000000�0000000�00000004033�14773473560�0033450�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/with_items", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/full-jinja/type" }, { "instancePath": "/0/with_items", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/properties/with_items/anyOf/1/type" }, { "instancePath": "/0/with_items", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/properties/with_items/anyOf" }, { "instancePath": "/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tasks/with_items_boolean.yml", "path": "$[0]", "message": "{'command': 'echo 123', 'with_items': True} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'block' is a required property" }, "best_deep_match": { "path": "$[0].with_items", "message": "True is not of type 'string'" }, "num_sub_errors": 3, "sub_errors": [ { "path": "$[0]", "message": "'block' is a required property" }, { "path": "$[0].with_items", "message": "True is not valid under any of the given schemas" }, { "path": "$[0].with_items", "message": "True is not of type 'string'" }, { "path": "$[0].with_items", "message": "True is not of type 'array'" } ] } ], "parse_errors": [] } ``` �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������with_items_untemplated_string.yml�������������������������������������������������������������������0000664�0000000�0000000�00000000131�14773473560�0035256�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks������������������������������������������������������������������������������������������������- command: echo 123 with_items: foobar # invalid, probably user wanted "{{ foobar }}"? ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������with_items_untemplated_string.yml.md����������������������������������������������������������������0000664�0000000�0000000�00000004312�14773473560�0035662�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/tasks������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/with_items", "keyword": "pattern", "message": "must match pattern \"^\\{[\\{%](.|[\r\n])*[\\}%]\\}$\"", "params": { "pattern": "^\\{[\\{%](.|[\r\n])*[\\}%]\\}$" }, "schemaPath": "#/$defs/full-jinja/pattern" }, { "instancePath": "/0/with_items", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/properties/with_items/anyOf/1/type" }, { "instancePath": "/0/with_items", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/properties/with_items/anyOf" }, { "instancePath": "/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/tasks/with_items_untemplated_string.yml", "path": "$[0]", "message": "{'command': 'echo 123', 'with_items': 'foobar'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'block' is a required property" }, "best_deep_match": { "path": "$[0].with_items", "message": "'foobar' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" }, "num_sub_errors": 3, "sub_errors": [ { "path": "$[0]", "message": "'block' is a required property" }, { "path": "$[0].with_items", "message": "'foobar' is not valid under any of the given schemas" }, { "path": "$[0].with_items", "message": "'foobar' does not match '^\\\\{[\\\\{%](.|[\\r\\n])*[\\\\}%]\\\\}$'" }, { "path": "$[0].with_items", "message": "'foobar' is not of type 'array'" } ] } ], "parse_errors": [] } ``` ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/var_files_list_number.yml���������0000664�0000000�0000000�00000000137�14773473560�0032427�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: var_files should not accept array[number] hosts: localhost vars_files: - 0 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/var_files_list_number.yml.md������0000664�0000000�0000000�00000007475�14773473560�0033042�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/vars_files", "keyword": "type", "message": "must be object", "params": { "type": "object" }, "schemaPath": "#/patternProperties/vars/type" }, { "instancePath": "/0/vars_files/0", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/properties/vars_files/items/oneOf/0/type" }, { "instancePath": "/0/vars_files/0", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/properties/vars_files/items/oneOf/1/type" }, { "instancePath": "/0/vars_files/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/properties/vars_files/items/oneOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/var_files_list_number.yml", "path": "$[0]", "message": "{'name': 'var_files should not accept array[number]', 'hosts': 'localhost', 'vars_files': [0]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts' does not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].vars_files[0]", "message": "0 is not of type 'string'" }, "num_sub_errors": 7, "sub_errors": [ { "path": "$[0]", "message": "'hosts' does not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'name': 'var_files should not accept array[number]', 'hosts': 'localhost', 'vars_files': [0]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].vars_files", "message": "[0] is not of type 'object'" }, { "path": "$[0].vars_files[0]", "message": "0 is not valid under any of the given schemas" }, { "path": "$[0].vars_files[0]", "message": "0 is not of type 'string'" }, { "path": "$[0].vars_files[0]", "message": "0 is not of type 'array'" } ] } ], "parse_errors": [] } ``` ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/var_files_list_of_list_number.yml�0000664�0000000�0000000�00000000144�14773473560�0034144�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: var_files should not accept array[number] hosts: localhost vars_files: - [0, 1] ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������var_files_list_of_list_number.yml.md����������������������������������������������������������������0000664�0000000�0000000�00000010275�14773473560�0034472�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/vars_files", "keyword": "type", "message": "must be object", "params": { "type": "object" }, "schemaPath": "#/patternProperties/vars/type" }, { "instancePath": "/0/vars_files/0", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/properties/vars_files/items/oneOf/0/type" }, { "instancePath": "/0/vars_files/0/0", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/properties/vars_files/items/oneOf/1/items/type" }, { "instancePath": "/0/vars_files/0/1", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/properties/vars_files/items/oneOf/1/items/type" }, { "instancePath": "/0/vars_files/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/properties/vars_files/items/oneOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/var_files_list_of_list_number.yml", "path": "$[0]", "message": "{'name': 'var_files should not accept array[number]', 'hosts': 'localhost', 'vars_files': [[0, 1]]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts' does not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].vars_files[0][0]", "message": "0 is not of type 'string'" }, "num_sub_errors": 8, "sub_errors": [ { "path": "$[0]", "message": "'hosts' does not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'name': 'var_files should not accept array[number]', 'hosts': 'localhost', 'vars_files': [[0, 1]]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].vars_files", "message": "[[0, 1]] is not of type 'object'" }, { "path": "$[0].vars_files[0]", "message": "[0, 1] is not valid under any of the given schemas" }, { "path": "$[0].vars_files[0]", "message": "[0, 1] is not of type 'string'" }, { "path": "$[0].vars_files[0][0]", "message": "0 is not of type 'string'" }, { "path": "$[0].vars_files[0][1]", "message": "1 is not of type 'string'" } ] } ], "parse_errors": [] } ``` �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/var_files_number.yml��������������0000664�0000000�0000000�00000000122�14773473560�0031366�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: var_files should not accept number hosts: localhost vars_files: 0 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/var_files_number.yml.md�����������0000664�0000000�0000000�00000006256�14773473560�0032003�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/vars_files", "keyword": "type", "message": "must be object", "params": { "type": "object" }, "schemaPath": "#/patternProperties/vars/type" }, { "instancePath": "/0/vars_files", "keyword": "type", "message": "must be array,string,null", "params": { "type": [ "array", "string", "null" ] }, "schemaPath": "#/properties/vars_files/type" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/var_files_number.yml", "path": "$[0]", "message": "{'name': 'var_files should not accept number', 'hosts': 'localhost', 'vars_files': 0} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts' does not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].vars_files", "message": "0 is not of type 'object'" }, "num_sub_errors": 5, "sub_errors": [ { "path": "$[0]", "message": "'hosts' does not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'name': 'var_files should not accept number', 'hosts': 'localhost', 'vars_files': 0} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].vars_files", "message": "0 is not of type 'object'" }, { "path": "$[0].vars_files", "message": "0 is not of type 'array', 'string', 'null'" } ] } ], "parse_errors": [] } ``` ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/vars/�����������������������������0000775�0000000�0000000�00000000000�14773473560�0026301�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/vars/asterisk.yml�����������������0000664�0000000�0000000�00000000043�14773473560�0030646�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- "*foo": ... # invalid var name ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/vars/asterisk.yml.md��������������0000664�0000000�0000000�00000005645�14773473560�0031262�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "*foo" }, "schemaPath": "#/anyOf/0/additionalProperties" }, { "instancePath": "", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/anyOf/1/type" }, { "instancePath": "", "keyword": "type", "message": "must be null", "params": { "type": "null" }, "schemaPath": "#/anyOf/2/type" }, { "instancePath": "", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/vars/asterisk.yml", "path": "$", "message": "{'*foo': '...'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$", "message": "{'*foo': '...'} is not of type 'string'" }, "best_deep_match": { "path": "$", "message": "'*foo' does not match any of the regexes: '^(?!(False|None|True|and|any_errors_fatal|as|assert|async|await|become|become_exe|become_flags|become_method|become_user|break|check_mode|class|collections|connection|continue|debugger|def|del|diff|elif|else|environment|except|fact_path|finally|for|force_handlers|from|gather_facts|gather_subset|gather_timeout|global|handlers|hosts|if|ignore_errors|ignore_unreachable|import|in|is|lambda|max_fail_percentage|module_defaults|name|no_log|nonlocal|not|or|order|pass|port|post_tasks|pre_tasks|raise|remote_user|return|roles|run_once|serial|strategy|tags|tasks|throttle|timeout|try|vars|vars_files|vars_prompt|while|with|yield)$)[a-zA-Z_][\\\\w]*$'" }, "num_sub_errors": 2, "sub_errors": [ { "path": "$", "message": "'*foo' does not match any of the regexes: '^(?!(False|None|True|and|any_errors_fatal|as|assert|async|await|become|become_exe|become_flags|become_method|become_user|break|check_mode|class|collections|connection|continue|debugger|def|del|diff|elif|else|environment|except|fact_path|finally|for|force_handlers|from|gather_facts|gather_subset|gather_timeout|global|handlers|hosts|if|ignore_errors|ignore_unreachable|import|in|is|lambda|max_fail_percentage|module_defaults|name|no_log|nonlocal|not|or|order|pass|port|post_tasks|pre_tasks|raise|remote_user|return|roles|run_once|serial|strategy|tags|tasks|throttle|timeout|try|vars|vars_files|vars_prompt|while|with|yield)$)[a-zA-Z_][\\\\w]*$'" }, { "path": "$", "message": "{'*foo': '...'} is not of type 'string'" }, { "path": "$", "message": "{'*foo': '...'} is not of type 'null'" } ] } ], "parse_errors": [] } ``` �������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/vars/dash-in-var-name.yml���������0000664�0000000�0000000�00000000044�14773473560�0032051�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- foo-bar: ... # invalid var name ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/vars/dash-in-var-name.yml.md������0000664�0000000�0000000�00000005702�14773473560�0032456�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "foo-bar" }, "schemaPath": "#/anyOf/0/additionalProperties" }, { "instancePath": "", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/anyOf/1/type" }, { "instancePath": "", "keyword": "type", "message": "must be null", "params": { "type": "null" }, "schemaPath": "#/anyOf/2/type" }, { "instancePath": "", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/vars/dash-in-var-name.yml", "path": "$", "message": "{'foo-bar': '...'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$", "message": "{'foo-bar': '...'} is not of type 'string'" }, "best_deep_match": { "path": "$", "message": "'foo-bar' does not match any of the regexes: '^(?!(False|None|True|and|any_errors_fatal|as|assert|async|await|become|become_exe|become_flags|become_method|become_user|break|check_mode|class|collections|connection|continue|debugger|def|del|diff|elif|else|environment|except|fact_path|finally|for|force_handlers|from|gather_facts|gather_subset|gather_timeout|global|handlers|hosts|if|ignore_errors|ignore_unreachable|import|in|is|lambda|max_fail_percentage|module_defaults|name|no_log|nonlocal|not|or|order|pass|port|post_tasks|pre_tasks|raise|remote_user|return|roles|run_once|serial|strategy|tags|tasks|throttle|timeout|try|vars|vars_files|vars_prompt|while|with|yield)$)[a-zA-Z_][\\\\w]*$'" }, "num_sub_errors": 2, "sub_errors": [ { "path": "$", "message": "'foo-bar' does not match any of the regexes: '^(?!(False|None|True|and|any_errors_fatal|as|assert|async|await|become|become_exe|become_flags|become_method|become_user|break|check_mode|class|collections|connection|continue|debugger|def|del|diff|elif|else|environment|except|fact_path|finally|for|force_handlers|from|gather_facts|gather_subset|gather_timeout|global|handlers|hosts|if|ignore_errors|ignore_unreachable|import|in|is|lambda|max_fail_percentage|module_defaults|name|no_log|nonlocal|not|or|order|pass|port|post_tasks|pre_tasks|raise|remote_user|return|roles|run_once|serial|strategy|tags|tasks|throttle|timeout|try|vars|vars_files|vars_prompt|while|with|yield)$)[a-zA-Z_][\\\\w]*$'" }, { "path": "$", "message": "{'foo-bar': '...'} is not of type 'string'" }, { "path": "$", "message": "{'foo-bar': '...'} is not of type 'null'" } ] } ], "parse_errors": [] } ``` ��������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/vars/list.yml���������������������0000664�0000000�0000000�00000000074�14773473560�0030000�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# invalid vars file, as sequence is not allowed - foo - bar ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/vars/list.yml.md������������������0000664�0000000�0000000�00000003112�14773473560�0030373�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "", "keyword": "type", "message": "must be object", "params": { "type": "object" }, "schemaPath": "#/anyOf/0/type" }, { "instancePath": "", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/anyOf/1/type" }, { "instancePath": "", "keyword": "type", "message": "must be null", "params": { "type": "null" }, "schemaPath": "#/anyOf/2/type" }, { "instancePath": "", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/vars/list.yml", "path": "$", "message": "['foo', 'bar'] is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$", "message": "['foo', 'bar'] is not of type 'object'" }, "best_deep_match": { "path": "$", "message": "['foo', 'bar'] is not of type 'object'" }, "num_sub_errors": 2, "sub_errors": [ { "path": "$", "message": "['foo', 'bar'] is not of type 'object'" }, { "path": "$", "message": "['foo', 'bar'] is not of type 'string'" }, { "path": "$", "message": "['foo', 'bar'] is not of type 'null'" } ] } ], "parse_errors": [] } ``` ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/vars/numeric-var-name.yml���������0000664�0000000�0000000�00000000037�14773473560�0032172�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- 12: ... # invalid var name �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/vars/numeric-var-name.yml.md������0000664�0000000�0000000�00000005637�14773473560�0032604�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "12" }, "schemaPath": "#/anyOf/0/additionalProperties" }, { "instancePath": "", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/anyOf/1/type" }, { "instancePath": "", "keyword": "type", "message": "must be null", "params": { "type": "null" }, "schemaPath": "#/anyOf/2/type" }, { "instancePath": "", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/vars/numeric-var-name.yml", "path": "$", "message": "{'12': '...'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$", "message": "{'12': '...'} is not of type 'string'" }, "best_deep_match": { "path": "$", "message": "'12' does not match any of the regexes: '^(?!(False|None|True|and|any_errors_fatal|as|assert|async|await|become|become_exe|become_flags|become_method|become_user|break|check_mode|class|collections|connection|continue|debugger|def|del|diff|elif|else|environment|except|fact_path|finally|for|force_handlers|from|gather_facts|gather_subset|gather_timeout|global|handlers|hosts|if|ignore_errors|ignore_unreachable|import|in|is|lambda|max_fail_percentage|module_defaults|name|no_log|nonlocal|not|or|order|pass|port|post_tasks|pre_tasks|raise|remote_user|return|roles|run_once|serial|strategy|tags|tasks|throttle|timeout|try|vars|vars_files|vars_prompt|while|with|yield)$)[a-zA-Z_][\\\\w]*$'" }, "num_sub_errors": 2, "sub_errors": [ { "path": "$", "message": "'12' does not match any of the regexes: '^(?!(False|None|True|and|any_errors_fatal|as|assert|async|await|become|become_exe|become_flags|become_method|become_user|break|check_mode|class|collections|connection|continue|debugger|def|del|diff|elif|else|environment|except|fact_path|finally|for|force_handlers|from|gather_facts|gather_subset|gather_timeout|global|handlers|hosts|if|ignore_errors|ignore_unreachable|import|in|is|lambda|max_fail_percentage|module_defaults|name|no_log|nonlocal|not|or|order|pass|port|post_tasks|pre_tasks|raise|remote_user|return|roles|run_once|serial|strategy|tags|tasks|throttle|timeout|try|vars|vars_files|vars_prompt|while|with|yield)$)[a-zA-Z_][\\\\w]*$'" }, { "path": "$", "message": "{'12': '...'} is not of type 'string'" }, { "path": "$", "message": "{'12': '...'} is not of type 'null'" } ] } ], "parse_errors": [] } ``` �������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/vars/play-keyword.yml�������������0000664�0000000�0000000�00000000050�14773473560�0031446�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- environment: ... # invalid var name ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/vars/play-keyword.yml.md����������0000664�0000000�0000000�00000005732�14773473560�0032061�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "environment" }, "schemaPath": "#/anyOf/0/additionalProperties" }, { "instancePath": "", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/anyOf/1/type" }, { "instancePath": "", "keyword": "type", "message": "must be null", "params": { "type": "null" }, "schemaPath": "#/anyOf/2/type" }, { "instancePath": "", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/vars/play-keyword.yml", "path": "$", "message": "{'environment': '...'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$", "message": "{'environment': '...'} is not of type 'string'" }, "best_deep_match": { "path": "$", "message": "'environment' does not match any of the regexes: '^(?!(False|None|True|and|any_errors_fatal|as|assert|async|await|become|become_exe|become_flags|become_method|become_user|break|check_mode|class|collections|connection|continue|debugger|def|del|diff|elif|else|environment|except|fact_path|finally|for|force_handlers|from|gather_facts|gather_subset|gather_timeout|global|handlers|hosts|if|ignore_errors|ignore_unreachable|import|in|is|lambda|max_fail_percentage|module_defaults|name|no_log|nonlocal|not|or|order|pass|port|post_tasks|pre_tasks|raise|remote_user|return|roles|run_once|serial|strategy|tags|tasks|throttle|timeout|try|vars|vars_files|vars_prompt|while|with|yield)$)[a-zA-Z_][\\\\w]*$'" }, "num_sub_errors": 2, "sub_errors": [ { "path": "$", "message": "'environment' does not match any of the regexes: '^(?!(False|None|True|and|any_errors_fatal|as|assert|async|await|become|become_exe|become_flags|become_method|become_user|break|check_mode|class|collections|connection|continue|debugger|def|del|diff|elif|else|environment|except|fact_path|finally|for|force_handlers|from|gather_facts|gather_subset|gather_timeout|global|handlers|hosts|if|ignore_errors|ignore_unreachable|import|in|is|lambda|max_fail_percentage|module_defaults|name|no_log|nonlocal|not|or|order|pass|port|post_tasks|pre_tasks|raise|remote_user|return|roles|run_once|serial|strategy|tags|tasks|throttle|timeout|try|vars|vars_files|vars_prompt|while|with|yield)$)[a-zA-Z_][\\\\w]*$'" }, { "path": "$", "message": "{'environment': '...'} is not of type 'string'" }, { "path": "$", "message": "{'environment': '...'} is not of type 'null'" } ] } ], "parse_errors": [] } ``` ��������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/vars/python-keyword.yml�����������0000664�0000000�0000000�00000000101�14773473560�0032017�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- async: ... # invalid var name lambda: ... # invalid var name ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/vars/python-keyword.yml.md��������0000664�0000000�0000000�00000006363�14773473560�0032436�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "async" }, "schemaPath": "#/anyOf/0/additionalProperties" }, { "instancePath": "", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "lambda" }, "schemaPath": "#/anyOf/0/additionalProperties" }, { "instancePath": "", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/anyOf/1/type" }, { "instancePath": "", "keyword": "type", "message": "must be null", "params": { "type": "null" }, "schemaPath": "#/anyOf/2/type" }, { "instancePath": "", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/vars/python-keyword.yml", "path": "$", "message": "{'async': '...', 'lambda': '...'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$", "message": "{'async': '...', 'lambda': '...'} is not of type 'string'" }, "best_deep_match": { "path": "$", "message": "'async', 'lambda' do not match any of the regexes: '^(?!(False|None|True|and|any_errors_fatal|as|assert|async|await|become|become_exe|become_flags|become_method|become_user|break|check_mode|class|collections|connection|continue|debugger|def|del|diff|elif|else|environment|except|fact_path|finally|for|force_handlers|from|gather_facts|gather_subset|gather_timeout|global|handlers|hosts|if|ignore_errors|ignore_unreachable|import|in|is|lambda|max_fail_percentage|module_defaults|name|no_log|nonlocal|not|or|order|pass|port|post_tasks|pre_tasks|raise|remote_user|return|roles|run_once|serial|strategy|tags|tasks|throttle|timeout|try|vars|vars_files|vars_prompt|while|with|yield)$)[a-zA-Z_][\\\\w]*$'" }, "num_sub_errors": 2, "sub_errors": [ { "path": "$", "message": "'async', 'lambda' do not match any of the regexes: '^(?!(False|None|True|and|any_errors_fatal|as|assert|async|await|become|become_exe|become_flags|become_method|become_user|break|check_mode|class|collections|connection|continue|debugger|def|del|diff|elif|else|environment|except|fact_path|finally|for|force_handlers|from|gather_facts|gather_subset|gather_timeout|global|handlers|hosts|if|ignore_errors|ignore_unreachable|import|in|is|lambda|max_fail_percentage|module_defaults|name|no_log|nonlocal|not|or|order|pass|port|post_tasks|pre_tasks|raise|remote_user|return|roles|run_once|serial|strategy|tags|tasks|throttle|timeout|try|vars|vars_files|vars_prompt|while|with|yield)$)[a-zA-Z_][\\\\w]*$'" }, { "path": "$", "message": "{'async': '...', 'lambda': '...'} is not of type 'string'" }, { "path": "$", "message": "{'async': '...', 'lambda': '...'} is not of type 'null'" } ] } ], "parse_errors": [] } ``` �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/vars/varname-numeric-prefix.yml���0000664�0000000�0000000�00000000041�14773473560�0033403�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- 5foo: ... # invalid var name �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/vars/varname-numeric-prefix.yml.md0000664�0000000�0000000�00000005663�14773473560�0034021�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "5foo" }, "schemaPath": "#/anyOf/0/additionalProperties" }, { "instancePath": "", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/anyOf/1/type" }, { "instancePath": "", "keyword": "type", "message": "must be null", "params": { "type": "null" }, "schemaPath": "#/anyOf/2/type" }, { "instancePath": "", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/vars/varname-numeric-prefix.yml", "path": "$", "message": "{'5foo': '...'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$", "message": "{'5foo': '...'} is not of type 'string'" }, "best_deep_match": { "path": "$", "message": "'5foo' does not match any of the regexes: '^(?!(False|None|True|and|any_errors_fatal|as|assert|async|await|become|become_exe|become_flags|become_method|become_user|break|check_mode|class|collections|connection|continue|debugger|def|del|diff|elif|else|environment|except|fact_path|finally|for|force_handlers|from|gather_facts|gather_subset|gather_timeout|global|handlers|hosts|if|ignore_errors|ignore_unreachable|import|in|is|lambda|max_fail_percentage|module_defaults|name|no_log|nonlocal|not|or|order|pass|port|post_tasks|pre_tasks|raise|remote_user|return|roles|run_once|serial|strategy|tags|tasks|throttle|timeout|try|vars|vars_files|vars_prompt|while|with|yield)$)[a-zA-Z_][\\\\w]*$'" }, "num_sub_errors": 2, "sub_errors": [ { "path": "$", "message": "'5foo' does not match any of the regexes: '^(?!(False|None|True|and|any_errors_fatal|as|assert|async|await|become|become_exe|become_flags|become_method|become_user|break|check_mode|class|collections|connection|continue|debugger|def|del|diff|elif|else|environment|except|fact_path|finally|for|force_handlers|from|gather_facts|gather_subset|gather_timeout|global|handlers|hosts|if|ignore_errors|ignore_unreachable|import|in|is|lambda|max_fail_percentage|module_defaults|name|no_log|nonlocal|not|or|order|pass|port|post_tasks|pre_tasks|raise|remote_user|return|roles|run_once|serial|strategy|tags|tasks|throttle|timeout|try|vars|vars_files|vars_prompt|while|with|yield)$)[a-zA-Z_][\\\\w]*$'" }, { "path": "$", "message": "{'5foo': '...'} is not of type 'string'" }, { "path": "$", "message": "{'5foo': '...'} is not of type 'null'" } ] } ], "parse_errors": [] } ``` �����������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/vas_prompt.yml��������������������0000664�0000000�0000000�00000000327�14773473560�0030245�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost vars_prompt: - name: username prompt: What is your username? private: false tags: # tags were never supported, https://github.com/ansible/ansible/issues/1780 - foo ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/vas_prompt.yml.md�����������������0000664�0000000�0000000�00000006645�14773473560�0030655�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/vars_prompt", "keyword": "type", "message": "must be object", "params": { "type": "object" }, "schemaPath": "#/patternProperties/vars/type" }, { "instancePath": "/0/vars_prompt/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tags" }, "schemaPath": "#/$defs/vars_prompt/additionalProperties" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/vas_prompt.yml", "path": "$[0]", "message": "{'hosts': 'localhost', 'vars_prompt': [{'name': 'username', 'prompt': 'What is your username?', 'private': False, 'tags': ['foo']}]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'hosts' does not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].vars_prompt[0]", "message": "Additional properties are not allowed ('tags' was unexpected)" }, "num_sub_errors": 5, "sub_errors": [ { "path": "$[0]", "message": "'hosts' does not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'hosts': 'localhost', 'vars_prompt': [{'name': 'username', 'prompt': 'What is your username?', 'private': False, 'tags': ['foo']}]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].vars_prompt", "message": "[{'name': 'username', 'prompt': 'What is your username?', 'private': False, 'tags': ['foo']}] is not of type 'object'" }, { "path": "$[0].vars_prompt[0]", "message": "Additional properties are not allowed ('tags' was unexpected)" } ] } ], "parse_errors": [] } ``` �������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/when.yml��������������������������0000664�0000000�0000000�00000000344�14773473560�0027013�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Test for when (failure) hosts: localhost gather_facts: false tasks: - name: Testing for when is passed a list ansible.builtin.debug: msg: "this is ok" when: - true - 123 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/playbooks/when.yml.md�����������������������0000664�0000000�0000000�00000017760�14773473560�0027424�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/0", "keyword": "required", "message": "must have required property 'ansible.builtin.import_playbook'", "params": { "missingProperty": "ansible.builtin.import_playbook" }, "schemaPath": "#/oneOf/0/required" }, { "instancePath": "/0", "keyword": "required", "message": "must have required property 'import_playbook'", "params": { "missingProperty": "import_playbook" }, "schemaPath": "#/oneOf/1/required" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/oneOf" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "hosts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "gather_facts" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "tasks" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "/0/tasks/0", "keyword": "required", "message": "must have required property 'block'", "params": { "missingProperty": "block" }, "schemaPath": "#/required" }, { "instancePath": "/0/tasks/0/when", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/$defs/complex_conditional/oneOf/0/type" }, { "instancePath": "/0/tasks/0/when", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/complex_conditional/oneOf/1/type" }, { "instancePath": "/0/tasks/0/when/1", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/$defs/complex_conditional/oneOf/2/items/anyOf/0/type" }, { "instancePath": "/0/tasks/0/when/1", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/complex_conditional/oneOf/2/items/anyOf/1/type" }, { "instancePath": "/0/tasks/0/when/1", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/$defs/complex_conditional/oneOf/2/items/anyOf" }, { "instancePath": "/0/tasks/0/when", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/$defs/complex_conditional/oneOf" }, { "instancePath": "/0/tasks/0/when", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/$defs/complex_conditional/oneOf/0/type" }, { "instancePath": "/0/tasks/0/when", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/complex_conditional/oneOf/1/type" }, { "instancePath": "/0/tasks/0/when/1", "keyword": "type", "message": "must be boolean", "params": { "type": "boolean" }, "schemaPath": "#/$defs/complex_conditional/oneOf/2/items/anyOf/0/type" }, { "instancePath": "/0/tasks/0/when/1", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/$defs/complex_conditional/oneOf/2/items/anyOf/1/type" }, { "instancePath": "/0/tasks/0/when/1", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/$defs/complex_conditional/oneOf/2/items/anyOf" }, { "instancePath": "/0/tasks/0/when", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/$defs/complex_conditional/oneOf" }, { "instancePath": "/0/tasks/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/items/anyOf" }, { "instancePath": "/0", "keyword": "oneOf", "message": "must match exactly one schema in oneOf", "params": { "passingSchemas": null }, "schemaPath": "#/items/oneOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/playbooks/when.yml", "path": "$[0]", "message": "{'name': 'Test for when (failure)', 'hosts': 'localhost', 'gather_facts': False, 'tasks': [{'name': 'Testing for when is passed a list', 'ansible.builtin.debug': {'msg': 'this is ok'}, 'when': [True, 123]}]} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$[0]", "message": "'gather_facts', 'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, "best_deep_match": { "path": "$[0].tasks[0].when[1]", "message": "123 is not of type 'boolean'" }, "num_sub_errors": 17, "sub_errors": [ { "path": "$[0]", "message": "'gather_facts', 'hosts', 'tasks' do not match any of the regexes: '^(ansible\\\\.builtin\\\\.)?import_playbook$', 'name', 'tags', 'vars', 'when'" }, { "path": "$[0]", "message": "{'name': 'Test for when (failure)', 'hosts': 'localhost', 'gather_facts': False, 'tasks': [{'name': 'Testing for when is passed a list', 'ansible.builtin.debug': {'msg': 'this is ok'}, 'when': [True, 123]}]} is not valid under any of the given schemas" }, { "path": "$[0]", "message": "'ansible.builtin.import_playbook' is a required property" }, { "path": "$[0]", "message": "'import_playbook' is a required property" }, { "path": "$[0].tasks[0]", "message": "{'name': 'Testing for when is passed a list', 'ansible.builtin.debug': {'msg': 'this is ok'}, 'when': [True, 123]} is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].when", "message": "[True, 123] is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].when", "message": "[True, 123] is not of type 'boolean'" }, { "path": "$[0].tasks[0].when", "message": "[True, 123] is not of type 'string'" }, { "path": "$[0].tasks[0].when[1]", "message": "123 is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].when[1]", "message": "123 is not of type 'boolean'" }, { "path": "$[0].tasks[0].when[1]", "message": "123 is not of type 'string'" }, { "path": "$[0].tasks[0]", "message": "'block' is a required property" }, { "path": "$[0].tasks[0].when", "message": "[True, 123] is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].when", "message": "[True, 123] is not of type 'boolean'" }, { "path": "$[0].tasks[0].when", "message": "[True, 123] is not of type 'string'" }, { "path": "$[0].tasks[0].when[1]", "message": "123 is not valid under any of the given schemas" }, { "path": "$[0].tasks[0].when[1]", "message": "123 is not of type 'boolean'" }, { "path": "$[0].tasks[0].when[1]", "message": "123 is not of type 'string'" } ] } ], "parse_errors": [] } ``` ����������������ansible-ansible-lint-c16f018/test/schemas/negative_test/reqs3/��������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024360�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/reqs3/meta/���������������������������������0000775�0000000�0000000�00000000000�14773473560�0025306�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/reqs3/meta/requirements.yml�����������������0000664�0000000�0000000�00000000047�14773473560�0030555�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# this should fail validation foo: bar �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/reqs3/meta/requirements.yml.md��������������0000664�0000000�0000000�00000004425�14773473560�0031160�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/anyOf/0/type" }, { "instancePath": "", "keyword": "required", "message": "must have required property 'collections'", "params": { "missingProperty": "collections" }, "schemaPath": "#/anyOf/0/required" }, { "instancePath": "", "keyword": "required", "message": "must have required property 'roles'", "params": { "missingProperty": "roles" }, "schemaPath": "#/anyOf/1/required" }, { "instancePath": "", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/anyOf" }, { "instancePath": "", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "foo" }, "schemaPath": "#/additionalProperties" }, { "instancePath": "", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/anyOf" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/reqs3/meta/requirements.yml", "path": "$", "message": "{'foo': 'bar'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$", "message": "{'foo': 'bar'} is not of type 'array'" }, "best_deep_match": { "path": "$", "message": "{'foo': 'bar'} is not of type 'array'" }, "num_sub_errors": 4, "sub_errors": [ { "path": "$", "message": "{'foo': 'bar'} is not of type 'array'" }, { "path": "$", "message": "Additional properties are not allowed ('foo' was unexpected)" }, { "path": "$", "message": "{'foo': 'bar'} is not valid under any of the given schemas" }, { "path": "$", "message": "'collections' is a required property" }, { "path": "$", "message": "'roles' is a required property" } ] } ], "parse_errors": [] } ``` �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/��������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024447�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/meta/���������������������������������0000775�0000000�0000000�00000000000�14773473560�0025375�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/meta/argument_specs.yml���������������0000664�0000000�0000000�00000000134�14773473560�0031135�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- argument_specs: main: foo: bar # <-- invalid based on json schema options: {} ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/meta/argument_specs.yml.md������������0000664�0000000�0000000�00000001163�14773473560�0031537�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/argument_specs/main", "keyword": "additionalProperties", "message": "must NOT have additional properties", "params": { "additionalProperty": "foo" }, "schemaPath": "#/additionalProperties" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/roles/meta/argument_specs.yml", "path": "$.argument_specs.main", "message": "Additional properties are not allowed ('foo' was unexpected)", "has_sub_errors": false } ], "parse_errors": [] } ``` �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/meta/main.yml�������������������������0000664�0000000�0000000�00000000332�14773473560�0027042�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������galaxy_info: description: bar min_ansible_version: "2.9" company: foo license: MIT galaxy_tags: database # <-- invalid, must be a list of strings platforms: - name: Alpine versions: - all ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/meta/main.yml.md����������������������0000664�0000000�0000000�00000002212�14773473560�0027440�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/galaxy_info", "keyword": "required", "message": "must have required property 'author'", "params": { "missingProperty": "author" }, "schemaPath": "#/allOf/0/then/required" }, { "instancePath": "/galaxy_info", "keyword": "if", "message": "must match \"then\" schema", "params": { "failingKeyword": "then" }, "schemaPath": "#/allOf/0/if" }, { "instancePath": "/galaxy_info/galaxy_tags", "keyword": "type", "message": "must be array", "params": { "type": "array" }, "schemaPath": "#/properties/galaxy_tags/type" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/roles/meta/main.yml", "path": "$.galaxy_info", "message": "'author' is a required property", "has_sub_errors": false }, { "filename": "negative_test/roles/meta/main.yml", "path": "$.galaxy_info.galaxy_tags", "message": "'database' is not of type 'array'", "has_sub_errors": false } ], "parse_errors": [] } ``` ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/meta_invalid_collection/��������������0000775�0000000�0000000�00000000000�14773473560�0031316�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/meta_invalid_collection/meta/���������0000775�0000000�0000000�00000000000�14773473560�0032244�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/meta_invalid_collection/meta/main.yml�0000664�0000000�0000000�00000000303�14773473560�0033707�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������collections: - foo # invalid pattern galaxy_info: standalone: false # role inside a collection description: foo license: bar platforms: - name: Fedora versions: - all �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������main.yml.md�����������������������������������������������������������������������������������������0000664�0000000�0000000�00000001160�14773473560�0034231�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/meta_invalid_collection/meta�����������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/collections/0", "keyword": "pattern", "message": "must match pattern \"^[a-z_]+\\.[a-z_]+$\"", "params": { "pattern": "^[a-z_]+\\.[a-z_]+$" }, "schemaPath": "#/$defs/collections/items/pattern" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/roles/meta_invalid_collection/meta/main.yml", "path": "$.collections[0]", "message": "'foo' does not match '^[a-z_]+\\\\.[a-z_]+$'", "has_sub_errors": false } ], "parse_errors": [] } ``` ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/meta_invalid_collections/�������������0000775�0000000�0000000�00000000000�14773473560�0031501�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/meta_invalid_collections/meta/��������0000775�0000000�0000000�00000000000�14773473560�0032427�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/meta_invalid_collections/meta/main.yml0000664�0000000�0000000�00000000336�14773473560�0034100�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# role inside a collection collections: - FOO.BAR # invalid pattern, need to use lowercase galaxy_info: standalone: false description: foo license: bar platforms: - name: Fedora versions: - all ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������main.yml.md�����������������������������������������������������������������������������������������0000664�0000000�0000000�00000001165�14773473560�0034421�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/meta_invalid_collections/meta����������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/collections/0", "keyword": "pattern", "message": "must match pattern \"^[a-z_]+\\.[a-z_]+$\"", "params": { "pattern": "^[a-z_]+\\.[a-z_]+$" }, "schemaPath": "#/$defs/collections/items/pattern" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/roles/meta_invalid_collections/meta/main.yml", "path": "$.collections[0]", "message": "'FOO.BAR' does not match '^[a-z_]+\\\\.[a-z_]+$'", "has_sub_errors": false } ], "parse_errors": [] } ``` �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/meta_invalid_role_namespace/����������0000775�0000000�0000000�00000000000�14773473560�0032140�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/meta_invalid_role_namespace/meta/�����0000775�0000000�0000000�00000000000�14773473560�0033066�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������main.yml��������������������������������������������������������������������������������������������0000664�0000000�0000000�00000000310�14773473560�0034450�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/meta_invalid_role_namespace/meta�������������������������������������������������������������������������--- # old standalone role galaxy_info: description: foo min_ansible_version: "2.9" namespace: foo-bar company: foo license: MIT platforms: - name: Alpine versions: - all ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������main.yml.md�����������������������������������������������������������������������������������������0000664�0000000�0000000�00000001424�14773473560�0035056�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/meta_invalid_role_namespace/meta�������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/galaxy_info", "keyword": "required", "message": "must have required property 'author'", "params": { "missingProperty": "author" }, "schemaPath": "#/allOf/0/then/required" }, { "instancePath": "/galaxy_info", "keyword": "if", "message": "must match \"then\" schema", "params": { "failingKeyword": "then" }, "schemaPath": "#/allOf/0/if" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/roles/meta_invalid_role_namespace/meta/main.yml", "path": "$.galaxy_info", "message": "'author' is a required property", "has_sub_errors": false } ], "parse_errors": [] } ``` ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/role_with_bad_deps_in_meta/�����������0000775�0000000�0000000�00000000000�14773473560�0031760�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/role_with_bad_deps_in_meta/meta/������0000775�0000000�0000000�00000000000�14773473560�0032706�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������main.yml��������������������������������������������������������������������������������������������0000664�0000000�0000000�00000000465�14773473560�0034303�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/role_with_bad_deps_in_meta/meta��������������������������������������������������������������������������# old standalone role galaxy_info: description: bar min_ansible_version: "2.9" company: foo license: MIT platforms: - name: Alpine versions: - all dependencies: - version: foo # invalid, should have at least name, role or src properties - 1234 # invalid, needs to be a string �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������main.yml.md�����������������������������������������������������������������������������������������0000664�0000000�0000000�00000010675�14773473560�0034706�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000�ansible-ansible-lint-c16f018/test/schemas/negative_test/roles/role_with_bad_deps_in_meta/meta��������������������������������������������������������������������������# ajv errors ```json [ { "instancePath": "/dependencies/0", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/properties/dependencies/items/anyOf/0/type" }, { "instancePath": "/dependencies/0", "keyword": "required", "message": "must have required property 'role'", "params": { "missingProperty": "role" }, "schemaPath": "#/anyOf/0/required" }, { "instancePath": "/dependencies/0", "keyword": "required", "message": "must have required property 'src'", "params": { "missingProperty": "src" }, "schemaPath": "#/anyOf/1/required" }, { "instancePath": "/dependencies/0", "keyword": "required", "message": "must have required property 'name'", "params": { "missingProperty": "name" }, "schemaPath": "#/anyOf/2/required" }, { "instancePath": "/dependencies/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/anyOf" }, { "instancePath": "/dependencies/0", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/properties/dependencies/items/anyOf" }, { "instancePath": "/dependencies/1", "keyword": "type", "message": "must be string", "params": { "type": "string" }, "schemaPath": "#/properties/dependencies/items/anyOf/0/type" }, { "instancePath": "/dependencies/1", "keyword": "type", "message": "must be object", "params": { "type": "object" }, "schemaPath": "#/type" }, { "instancePath": "/dependencies/1", "keyword": "anyOf", "message": "must match a schema in anyOf", "params": {}, "schemaPath": "#/properties/dependencies/items/anyOf" }, { "instancePath": "/galaxy_info", "keyword": "required", "message": "must have required property 'author'", "params": { "missingProperty": "author" }, "schemaPath": "#/allOf/0/then/required" }, { "instancePath": "/galaxy_info", "keyword": "if", "message": "must match \"then\" schema", "params": { "failingKeyword": "then" }, "schemaPath": "#/allOf/0/if" } ] ``` # check-jsonschema stdout: ```json { "status": "fail", "successes": [], "errors": [ { "filename": "negative_test/roles/role_with_bad_deps_in_meta/meta/main.yml", "path": "$.dependencies[0]", "message": "{'version': 'foo'} is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$.dependencies[0]", "message": "{'version': 'foo'} is not of type 'string'" }, "best_deep_match": { "path": "$.dependencies[0]", "message": "{'version': 'foo'} is not of type 'string'" }, "num_sub_errors": 4, "sub_errors": [ { "path": "$.dependencies[0]", "message": "{'version': 'foo'} is not of type 'string'" }, { "path": "$.dependencies[0]", "message": "{'version': 'foo'} is not valid under any of the given schemas" }, { "path": "$.dependencies[0]", "message": "'role' is a required property" }, { "path": "$.dependencies[0]", "message": "'src' is a required property" }, { "path": "$.dependencies[0]", "message": "'name' is a required property" } ] }, { "filename": "negative_test/roles/role_with_bad_deps_in_meta/meta/main.yml", "path": "$.dependencies[1]", "message": "1234 is not valid under any of the given schemas", "has_sub_errors": true, "best_match": { "path": "$.dependencies[1]", "message": "1234 is not of type 'string'" }, "best_deep_match": { "path": "$.dependencies[1]", "message": "1234 is not of type 'string'" }, "num_sub_errors": 1, "sub_errors": [ { "path": "$.dependencies[1]", "message": "1234 is not of type 'string'" }, { "path": "$.dependencies[1]", "message": "1234 is not of type 'object'" } ] }, { "filename": "negative_test/roles/role_with_bad_deps_in_meta/meta/main.yml", "path": "$.galaxy_info", "message": "'author' is a required property", "has_sub_errors": false } ], "parse_errors": [] } ``` �������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/package-lock.json�����������������������������������������0000664�0000000�0000000�00000312232�14773473560�0023701�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "name": "schemas", "lockfileVersion": 2, "requires": true, "packages": { "": { "dependencies": { "ajv-formats": "^3.0.1", "js-yaml": "^4.1.0", "safe-stable-stringify": "^2.5.0", "ts-node": "^10.9.2", "vscode-json-languageservice": "^5.4.3" }, "devDependencies": { "@types/chai": "^5.2.0", "@types/js-yaml": "^4.0.9", "@types/minimatch": "^5.1.2", "@types/mocha": "^10.0.10", "@types/node": "^22.13.10", "chai": "^5.2.0", "minimatch": "^10.0.1", "mocha": "^11.1.0", "typescript": "^5.8.2" } }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, "engines": { "node": ">=12" } }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { "node": ">=12" } }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", "engines": { "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/@isaacs/cliui/node_modules/ansi-styles": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, "license": "MIT", "engines": { "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true, "license": "MIT" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" }, "engines": { "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@isaacs/cliui/node_modules/strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, "engines": { "node": ">=12" }, "funding": { "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" }, "engines": { "node": ">=12" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/@jridgewell/resolve-uri": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.13", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, "license": "MIT", "optional": true, "engines": { "node": ">=14" } }, "node_modules/@tsconfig/node10": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==" }, "node_modules/@tsconfig/node12": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==" }, "node_modules/@tsconfig/node14": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==" }, "node_modules/@tsconfig/node16": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==" }, "node_modules/@types/chai": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.0.tgz", "integrity": "sha512-FWnQYdrG9FAC8KgPVhDFfrPL1FBsL3NtIt2WsxKvwu/61K6HiuDF3xAb7c7w/k9ML2QOUHcwTgU7dKLFPK6sBg==", "dev": true, "license": "MIT", "dependencies": { "@types/deep-eql": "*" } }, "node_modules/@types/deep-eql": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", "dev": true, "license": "MIT" }, "node_modules/@types/js-yaml": { "version": "4.0.9", "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", "dev": true }, "node_modules/@types/minimatch": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", "dev": true }, "node_modules/@types/mocha": { "version": "10.0.10", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", "dev": true, "license": "MIT" }, "node_modules/@types/node": { "version": "22.13.10", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz", "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==", "license": "MIT", "dependencies": { "undici-types": "~6.20.0" } }, "node_modules/@vscode/l10n": { "version": "0.0.18", "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.18.tgz", "integrity": "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==" }, "node_modules/acorn": { "version": "8.6.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", "bin": { "acorn": "bin/acorn" }, "engines": { "node": ">=0.4.0" } }, "node_modules/acorn-walk": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "engines": { "node": ">=0.4.0" } }, "node_modules/ajv": { "version": "8.10.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.2.2" }, "funding": { "type": "github", "url": "https://github.com/sponsors/epoberezkin" } }, "node_modules/ajv-formats": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "dependencies": { "ajv": "^8.0.0" }, "peerDependencies": { "ajv": "^8.0.0" }, "peerDependenciesMeta": { "ajv": { "optional": true } } }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, "engines": { "node": ">=6" } }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { "color-convert": "^2.0.1" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/anymatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" }, "engines": { "node": ">= 8" } }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, "engines": { "node": ">=12" } }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/braces": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, "node_modules/camelcase": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", "dev": true, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/chai": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", "dev": true, "license": "MIT", "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" }, "engines": { "node": ">=12" } }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/chalk/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, "node_modules/check-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true, "engines": { "node": ">= 16" } }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, "funding": [ { "type": "individual", "url": "https://paulmillr.com/funding/" } ], "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "engines": { "node": ">= 8.10.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" }, "engines": { "node": ">=12" } }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { "color-name": "~1.1.4" }, "engines": { "node": ">=7.0.0" } }, "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" }, "engines": { "node": ">= 8" } }, "node_modules/debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, "dependencies": { "ms": "2.1.2" }, "engines": { "node": ">=6.0" }, "peerDependenciesMeta": { "supports-color": { "optional": true } } }, "node_modules/debug/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "node_modules/decamelize": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/deep-eql": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.1.tgz", "integrity": "sha512-nwQCf6ne2gez3o1MxWifqkciwt0zhl0LO1/UwVu4uMBuPmflWM4oQ70XMqHqnBJA+nhzncaqL9HVL6KkHJ28lw==", "dev": true, "engines": { "node": ">=6" } }, "node_modules/diff": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, "engines": { "node": ">=0.3.1" } }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true, "license": "MIT" }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "engines": { "node": ">=6" } }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, "engines": { "node": ">=8" } }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/flat": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, "bin": { "flat": "cli.js" } }, "node_modules/foreground-child": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" }, "engines": { "node": ">=14" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "hasInstallScript": true, "optional": true, "os": [ "darwin" ], "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-func-name": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, "engines": { "node": "*" } }, "node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "dependencies": { "is-glob": "^4.0.1" }, "engines": { "node": ">= 6" } }, "node_modules/glob/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, "bin": { "he": "bin/he" } }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "dependencies": { "binary-extensions": "^2.0.0" }, "engines": { "node": ">=8" } }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, "engines": { "node": ">=0.10.0" } }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, "engines": { "node": ">=0.12.0" } }, "node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true, "license": "ISC" }, "node_modules/jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, "funding": { "url": "https://github.com/sponsors/isaacs" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "node_modules/jsonc-parser": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==" }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "dependencies": { "p-locate": "^5.0.0" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/loupe": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.0.tgz", "integrity": "sha512-qKl+FrLXUhFuHUoDJG7f8P8gEMHq9NFS0c6ghXG1J0rldmZFQZoNVv/vyirE9qwCIhWZDsvEFd1sbFu3GvRQFg==", "dev": true, "dependencies": { "get-func-name": "^2.0.1" } }, "node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, "license": "ISC" }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" }, "node_modules/minimatch": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/mocha": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz", "integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==", "dev": true, "dependencies": { "ansi-colors": "^4.1.3", "browser-stdout": "^1.3.1", "chokidar": "^3.5.3", "debug": "^4.3.5", "diff": "^5.2.0", "escape-string-regexp": "^4.0.0", "find-up": "^5.0.0", "glob": "^10.4.5", "he": "^1.2.0", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", "minimatch": "^5.1.6", "ms": "^2.1.3", "serialize-javascript": "^6.0.2", "strip-json-comments": "^3.1.1", "supports-color": "^8.1.1", "workerpool": "^6.5.1", "yargs": "^17.7.2", "yargs-parser": "^21.1.1", "yargs-unparser": "^2.0.0" }, "bin": { "_mocha": "bin/_mocha", "mocha": "bin/mocha.js" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/mocha/node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { "node": ">=10" } }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "dependencies": { "yocto-queue": "^0.1.0" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "dependencies": { "p-limit": "^3.0.2" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true, "license": "BlueOak-1.0.0" }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { "node": ">=16 || 14 >=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/pathval": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true, "engines": { "node": ">= 14.16" } }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "engines": { "node": ">=8.6" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "engines": { "node": ">=6" } }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "dependencies": { "safe-buffer": "^5.1.0" } }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "dependencies": { "picomatch": "^2.2.1" }, "engines": { "node": ">=8.10.0" } }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "engines": { "node": ">=0.10.0" } }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/feross" }, { "type": "patreon", "url": "https://www.patreon.com/feross" }, { "type": "consulting", "url": "https://feross.org/support" } ] }, "node_modules/safe-stable-stringify": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", "license": "MIT", "engines": { "node": ">=10" } }, "node_modules/serialize-javascript": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "dependencies": { "randombytes": "^2.1.0" } }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, "engines": { "node": ">=8" } }, "node_modules/shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, "license": "ISC", "engines": { "node": ">=14" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" } }, "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" } }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" } }, "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" } }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "dependencies": { "has-flag": "^4.0.0" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "dependencies": { "is-number": "^7.0.0" }, "engines": { "node": ">=8.0" } }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", "@tsconfig/node16": "^1.0.2", "acorn": "^8.4.1", "acorn-walk": "^8.1.1", "arg": "^4.1.0", "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" }, "bin": { "ts-node": "dist/bin.js", "ts-node-cwd": "dist/bin-cwd.js", "ts-node-esm": "dist/bin-esm.js", "ts-node-script": "dist/bin-script.js", "ts-node-transpile-only": "dist/bin-transpile.js", "ts-script": "dist/bin-script-deprecated.js" }, "peerDependencies": { "@swc/core": ">=1.2.50", "@swc/wasm": ">=1.2.50", "@types/node": "*", "typescript": ">=2.7" }, "peerDependenciesMeta": { "@swc/core": { "optional": true }, "@swc/wasm": { "optional": true } } }, "node_modules/ts-node/node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "engines": { "node": ">=0.3.1" } }, "node_modules/typescript": { "version": "5.8.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { "node": ">=14.17" } }, "node_modules/undici-types": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "license": "MIT" }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dependencies": { "punycode": "^2.1.0" } }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" }, "node_modules/vscode-json-languageservice": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-5.4.3.tgz", "integrity": "sha512-NVSEQDloP9NYccuqKg4eI46kutZpwucBY4csBB6FCxbM7AZVoBt0oxTItPVA+ZwhnG1bg/fmiBRAwcGJyNQoPA==", "dependencies": { "@vscode/l10n": "^0.0.18", "jsonc-parser": "^3.3.1", "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "^3.17.5", "vscode-uri": "^3.0.8" } }, "node_modules/vscode-languageserver-textdocument": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", "license": "MIT" }, "node_modules/vscode-languageserver-types": { "version": "3.17.5", "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==" }, "node_modules/vscode-uri": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==" }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" }, "engines": { "node": ">= 8" } }, "node_modules/workerpool": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", "dev": true }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, "engines": { "node": ">=10" } }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" }, "engines": { "node": ">=12" } }, "node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, "engines": { "node": ">=12" } }, "node_modules/yargs-unparser": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", "dev": true, "dependencies": { "camelcase": "^6.0.0", "decamelize": "^4.0.0", "flat": "^5.0.2", "is-plain-obj": "^2.1.0" }, "engines": { "node": ">=10" } }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "engines": { "node": ">=6" } }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } } }, "dependencies": { "@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "requires": { "@jridgewell/trace-mapping": "0.3.9" } }, "@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, "requires": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "dependencies": { "ansi-regex": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true }, "ansi-styles": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true }, "emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, "string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "requires": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "requires": { "ansi-regex": "^6.0.1" } }, "wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "requires": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } } } }, "@jridgewell/resolve-uri": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==" }, "@jridgewell/sourcemap-codec": { "version": "1.4.13", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==" }, "@jridgewell/trace-mapping": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "requires": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, "optional": true }, "@tsconfig/node10": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==" }, "@tsconfig/node12": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==" }, "@tsconfig/node14": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==" }, "@tsconfig/node16": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==" }, "@types/chai": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.0.tgz", "integrity": "sha512-FWnQYdrG9FAC8KgPVhDFfrPL1FBsL3NtIt2WsxKvwu/61K6HiuDF3xAb7c7w/k9ML2QOUHcwTgU7dKLFPK6sBg==", "dev": true, "requires": { "@types/deep-eql": "*" } }, "@types/deep-eql": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", "dev": true }, "@types/js-yaml": { "version": "4.0.9", "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", "dev": true }, "@types/minimatch": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", "dev": true }, "@types/mocha": { "version": "10.0.10", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", "dev": true }, "@types/node": { "version": "22.13.10", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz", "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==", "requires": { "undici-types": "~6.20.0" } }, "@vscode/l10n": { "version": "0.0.18", "resolved": "https://registry.npmjs.org/@vscode/l10n/-/l10n-0.0.18.tgz", "integrity": "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==" }, "acorn": { "version": "8.6.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==" }, "acorn-walk": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" }, "ajv": { "version": "8.10.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, "ajv-formats": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "requires": { "ajv": "^8.0.0" } }, "ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { "color-convert": "^2.0.1" } }, "anymatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, "brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "requires": { "balanced-match": "^1.0.0" } }, "braces": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "requires": { "fill-range": "^7.1.1" } }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, "camelcase": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", "dev": true }, "chai": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", "dev": true, "requires": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" }, "dependencies": { "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { "has-flag": "^4.0.0" } } } }, "check-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true }, "chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, "requires": { "anymatch": "~3.1.2", "braces": "~3.0.2", "fsevents": "~2.3.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" } }, "cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "requires": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { "color-name": "~1.1.4" } }, "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" }, "cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, "requires": { "ms": "2.1.2" }, "dependencies": { "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } }, "decamelize": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true }, "deep-eql": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.1.tgz", "integrity": "sha512-nwQCf6ne2gez3o1MxWifqkciwt0zhl0LO1/UwVu4uMBuPmflWM4oQ70XMqHqnBJA+nhzncaqL9HVL6KkHJ28lw==", "dev": true }, "diff": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true }, "eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "requires": { "to-regex-range": "^5.0.1" } }, "find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "requires": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "flat": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true }, "foreground-child": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, "requires": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" } }, "fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "optional": true }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, "get-func-name": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true }, "glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "requires": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "dependencies": { "minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "requires": { "brace-expansion": "^2.0.1" } } } }, "glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { "is-glob": "^4.0.1" } }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "requires": { "binary-extensions": "^2.0.0" } }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { "is-extglob": "^2.1.1" } }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true }, "is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "requires": { "@isaacs/cliui": "^8.0.2", "@pkgjs/parseargs": "^0.11.0" } }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "requires": { "argparse": "^2.0.1" } }, "json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "jsonc-parser": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==" }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "requires": { "p-locate": "^5.0.0" } }, "log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, "requires": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" } }, "loupe": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.0.tgz", "integrity": "sha512-qKl+FrLXUhFuHUoDJG7f8P8gEMHq9NFS0c6ghXG1J0rldmZFQZoNVv/vyirE9qwCIhWZDsvEFd1sbFu3GvRQFg==", "dev": true, "requires": { "get-func-name": "^2.0.1" } }, "lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true }, "make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" }, "minimatch": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", "dev": true, "requires": { "brace-expansion": "^2.0.1" } }, "minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true }, "mocha": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz", "integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==", "dev": true, "requires": { "ansi-colors": "^4.1.3", "browser-stdout": "^1.3.1", "chokidar": "^3.5.3", "debug": "^4.3.5", "diff": "^5.2.0", "escape-string-regexp": "^4.0.0", "find-up": "^5.0.0", "glob": "^10.4.5", "he": "^1.2.0", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", "minimatch": "^5.1.6", "ms": "^2.1.3", "serialize-javascript": "^6.0.2", "strip-json-comments": "^3.1.1", "supports-color": "^8.1.1", "workerpool": "^6.5.1", "yargs": "^17.7.2", "yargs-parser": "^21.1.1", "yargs-unparser": "^2.0.0" }, "dependencies": { "minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "requires": { "brace-expansion": "^2.0.1" } } } }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "requires": { "yocto-queue": "^0.1.0" } }, "p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "requires": { "p-limit": "^3.0.2" } }, "package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, "requires": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "pathval": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true }, "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "requires": { "safe-buffer": "^5.1.0" } }, "readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "requires": { "picomatch": "^2.2.1" } }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true }, "require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, "safe-stable-stringify": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==" }, "serialize-javascript": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "requires": { "randombytes": "^2.1.0" } }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { "shebang-regex": "^3.0.0" } }, "shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "string-width-cjs": { "version": "npm:string-width@4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { "ansi-regex": "^5.0.1" } }, "strip-ansi-cjs": { "version": "npm:strip-ansi@6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { "ansi-regex": "^5.0.1" } }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, "supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { "has-flag": "^4.0.0" } }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" } }, "ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "requires": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", "@tsconfig/node16": "^1.0.2", "acorn": "^8.4.1", "acorn-walk": "^8.1.1", "arg": "^4.1.0", "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" }, "dependencies": { "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" } } }, "typescript": { "version": "5.8.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==" }, "undici-types": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "requires": { "punycode": "^2.1.0" } }, "v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" }, "vscode-json-languageservice": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-5.4.3.tgz", "integrity": "sha512-NVSEQDloP9NYccuqKg4eI46kutZpwucBY4csBB6FCxbM7AZVoBt0oxTItPVA+ZwhnG1bg/fmiBRAwcGJyNQoPA==", "requires": { "@vscode/l10n": "^0.0.18", "jsonc-parser": "^3.3.1", "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "^3.17.5", "vscode-uri": "^3.0.8" } }, "vscode-languageserver-textdocument": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==" }, "vscode-languageserver-types": { "version": "3.17.5", "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==" }, "vscode-uri": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==" }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" } }, "workerpool": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", "dev": true }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "requires": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "wrap-ansi-cjs": { "version": "npm:wrap-ansi@7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "requires": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, "yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "requires": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true }, "yargs-unparser": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", "dev": true, "requires": { "camelcase": "^6.0.0", "decamelize": "^4.0.0", "flat": "^5.0.2", "is-plain-obj": "^2.1.0" } }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true } } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/package.json����������������������������������������������0000664�0000000�0000000�00000001305�14773473560�0022747�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "dependencies": { "ajv-formats": "^3.0.1", "js-yaml": "^4.1.0", "safe-stable-stringify": "^2.5.0", "ts-node": "^10.9.2", "vscode-json-languageservice": "^5.4.3" }, "scripts": { "compile": "tsc", "deps": "npx --yes npm-check-updates -u && npm install --ignore-scripts", "test": "python3 src/rebuild.py && mocha" }, "devDependencies": { "@types/chai": "^5.2.0", "@types/js-yaml": "^4.0.9", "@types/minimatch": "^5.1.2", "@types/mocha": "^10.0.10", "@types/node": "^22.13.10", "chai": "^5.2.0", "minimatch": "^10.0.1", "mocha": "^11.1.0", "typescript": "^5.8.2" }, "directories": { "test": "./src" }, "type": "module" } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/src/������������������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0021251�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/src/rebuild.py��������������������������������������������0000664�0000000�0000000�00000010070�14773473560�0023247�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Utility to generate some complex patterns.""" import copy import json import keyword import sys from pathlib import Path from typing import Any play_keywords = list( filter( None, [ "any_errors_fatal", "become", "become_exe", "become_flags", "become_method", "become_user", "check_mode", "collections", "connection", "debugger", "diff", "environment", "fact_path", "force_handlers", "gather_facts", "gather_subset", "gather_timeout", "handlers", "hosts", "ignore_errors", "ignore_unreachable", "max_fail_percentage", "module_defaults", "name", "no_log", "order", "port", "post_tasks", "pre_tasks", "remote_user", "roles", "run_once", "serial", "strategy", "tags", "tasks", "throttle", "timeout", "vars", "vars_files", "vars_prompt", ], ), ) def is_ref_used(obj: Any, ref: str) -> bool: """Return a reference use from a schema.""" ref_use = f"#/$defs/{ref}" if isinstance(obj, dict): if obj.get("$ref", None) == ref_use: return True for _ in obj.values(): if isinstance(_, dict | list) and is_ref_used(_, ref): return True elif isinstance(obj, list): for _ in obj: if isinstance(_, dict | list) and is_ref_used(_, ref): return True return False if __name__ == "__main__": invalid_var_names = sorted(list(keyword.kwlist) + play_keywords) if "__peg_parser__" in invalid_var_names: invalid_var_names.remove("__peg_parser__") print("Updating invalid var names") # noqa: T201 with Path("f/vars.json").open("r+", encoding="utf-8") as f: vars_schema = json.load(f) vars_schema["anyOf"][0]["patternProperties"] = { f"^(?!({'|'.join(invalid_var_names)})$)[a-zA-Z_][\\w]*$": {}, } f.seek(0) json.dump(vars_schema, f, indent=2) f.write("\n") f.truncate() print("Compiling subschemas...") # noqa: T201 with Path("f/ansible.json").open(encoding="utf-8") as f: combined_json = json.load(f) for subschema in ["tasks", "playbook"]: sub_json = copy.deepcopy(combined_json) # remove unsafe keys from root for key in [ "$id", "id", "title", "description", "type", "default", "items", "properties", "additionalProperties", "examples", ]: if key in sub_json: del sub_json[key] for key in sub_json: if key not in ["$schema", "$defs"]: print( # noqa: T201 f"Unexpected key found at combined schema root: ${key}", ) sys.exit(2) # Copy keys from subschema to root for key, value in combined_json["$defs"][subschema].items(): sub_json[key] = value sub_json["$comment"] = "Generated from ansible.json, do not edit." sub_json["$id"] = ( f"https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/{subschema}.json" ) # Remove all unreferenced ($ref) definitions ($defs) recursively while True: spare = [k for k in sub_json["$defs"] if not is_ref_used(sub_json, k)] for k in spare: print(f"{subschema}: deleting unused '{k}' definition") # noqa: T201 del sub_json["$defs"][k] if not spare: break with Path(f"f/{subschema}.json").open("w", encoding="utf-8") as f: json.dump(sub_json, f, indent=2, sort_keys=True) f.write("\n") ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/src/schema.spec.ts����������������������������������������0000664�0000000�0000000�00000014746�14773473560�0024026�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������import * as path from "path"; import Ajv from "ajv"; import fs from "fs"; import { minimatch } from "minimatch"; import yaml from "js-yaml"; import { assert } from "chai"; import stringify from "safe-stable-stringify"; import { spawnSync } from "child_process"; function ansiRegex({ onlyFirst = false } = {}) { const pattern = [ "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))", ].join("|"); return new RegExp(pattern, onlyFirst ? undefined : "g"); } function stripAnsi(data: string) { if (typeof data !== "string") { throw new TypeError( `Expected a \`string\`, got \`${typeof data}\ = ${data}`, ); } return data.replace(ansiRegex(), ""); } const ajv = new Ajv({ strictTypes: false, strict: false, inlineRefs: true, // https://github.com/ajv-validator/ajv/issues/1581#issuecomment-832211568 allErrors: true, // https://github.com/ajv-validator/ajv/issues/1581#issuecomment-832211568 }); // load whitelist of all test file subjects schemas can reference const test_files = getAllFiles("./test"); const negative_test_files = getAllFiles("./negative_test"); // load all schemas const schema_files = fs .readdirSync("f/") .filter((el) => path.extname(el) === ".json"); console.log(`Schemas: ${schema_files}`); describe("schemas under f/", function () { schema_files.forEach((schema_file) => { if ( schema_file.startsWith("_") || ["ansible-navigator-config.json", "rulebook.json"].includes(schema_file) ) { return; } const schema_json = JSON.parse(fs.readFileSync(`f/${schema_file}`, "utf8")); ajv.addSchema(schema_json); const validator = ajv.compile(schema_json); if (schema_json.examples == undefined) { console.error( `Schema file ${schema_file} is missing an examples key that we need for documenting file matching patterns.`, ); return process.exit(1); } describe(schema_file, function () { getTestFiles(schema_json.examples).forEach( ({ file: test_file, expect_fail }) => { it(`linting ${test_file} using ${schema_file}`, function () { var errors_md = ""; const result = validator( yaml.load(fs.readFileSync(test_file, "utf8")), ); if (validator.errors) { errors_md += "# ajv errors\n\n```json\n"; errors_md += stringify(validator.errors, null, 2); errors_md += "\n```\n\n"; } // validate using check-jsonschema (python-jsonschema): // const py = exec(); // Do not use python3 -m ... calling notation because for some // reason, nodejs environment lacks some env variables needed // and breaks usage from inside virtualenvs. const proc = spawnSync( `${process.env.VIRTUAL_ENV}/bin/check-jsonschema -v -o json --schemafile f/${schema_file} ${test_file}`, { shell: true, encoding: "utf-8", stdio: "pipe" }, ); if (proc.status != 0) { // real errors are sent to stderr due to https://github.com/python-jsonschema/check-jsonschema/issues/88 errors_md += "# check-jsonschema\n\nstdout:\n\n```json\n"; errors_md += stripAnsi(proc.output[1] || ""); errors_md += "```\n"; if (proc.output[2]) { errors_md += "\nstderr:\n\n```\n"; errors_md += stripAnsi(proc.output[2]); errors_md += "```\n"; } } // dump errors to markdown file for manual inspection const md_filename = `${test_file}.md`; if (errors_md) { fs.writeFileSync(md_filename, errors_md); } else { // if no error occurs, we should ensure there is no md file present fs.unlink(md_filename, function (err) { if (err && err.code != "ENOENT") { console.error(`Failed to remove ${md_filename}.`); } }); } assert.equal( result, !expect_fail, `${JSON.stringify(validator.errors)}`, ); }); }, ); // All /$defs/ that have examples property are assumed to be // subschemas, "tasks" being the primary such case, which is also used // for validating separated files. for (var definition in schema_json["$defs"]) { if (schema_json["$defs"][definition].examples) { const subschema_uri = `${schema_json["$id"]}#/$defs/${definition}`; const subschema_validator = ajv.getSchema(subschema_uri); if (!subschema_validator) { console.error(`Failed to load subschema ${subschema_uri}`); return process.exit(1); } getTestFiles(schema_json["$defs"][definition].examples).forEach( ({ file: test_file, expect_fail }) => { it(`linting ${test_file} using ${subschema_uri}`, function () { const result = subschema_validator( yaml.load(fs.readFileSync(test_file, "utf8")), ); assert.equal( result, !expect_fail, `${JSON.stringify(validator.errors)}`, ); }); }, ); } } }); }); }); // find all tests for each schema file function getTestFiles( globs: string[], ): { file: string; expect_fail: boolean }[] { const files = Array.from( new Set( globs .map((glob: any) => minimatch.match(test_files, path.join("**", glob))) .flat(), ), ); const negative_files = Array.from( new Set( globs .map((glob: any) => minimatch.match(negative_test_files, path.join("**", glob)), ) .flat(), ), ); // All fails ending with fail, like `foo.fail.yml` are expected to fail validation let result = files.map((f) => ({ file: f, expect_fail: false })); result = result.concat( negative_files.map((f) => ({ file: f, expect_fail: true })), ); return result; } function getAllFiles(dir: string): string[] { return fs.readdirSync(dir).reduce((files: string[], file: string) => { const name = path.join(dir, file); const isDirectory = fs.statSync(name).isDirectory(); return isDirectory ? [...files, ...getAllFiles(name)] : [...files, name]; }, []); } ��������������������������ansible-ansible-lint-c16f018/test/schemas/test/�����������������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0021441�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/.config/���������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0022764�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/.config/ansible-lint.yml�����������������������������0000664�0000000�0000000�00000000215�14773473560�0026066�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- # .ansible-lint profile: basic rules: name[missing]: exclude_paths: [] custom-inc-rule: exclude_paths: - "tests/*.yml" �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/ansible-navigator.yml��������������������������������0000664�0000000�0000000�00000002605�14773473560�0025574�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- ansible-navigator: ansible: config: /tmp/ansible.cfg cmdline: "--forks 15" inventories: - /tmp/test_inventory.yml playbook: /tmp/test_playbook.yml ansible-builder: workdir: /tmp/ ansible-runner: artifact-dir: /tmp/test1 rotate-artifacts-count: 10 timeout: 300 app: run collection-doc-cache-path: /tmp/cache.db color: enable: False osc4: False documentation: plugin: name: shell type: become editor: command: vim_from_setting console: False exec: shell: False command: /bin/foo execution-environment: container-engine: podman enabled: False environment-variables: pass: - ONE - TWO - THREE set: KEY1: VALUE1 KEY2: VALUE2 KEY3: VALUE3 image: test_image:latest pull-policy: never volume-mounts: - src: "/test1" dest: "/test1" label: "Z" container-options: - "--net=host" help-builder: False help-config: True help-doc: True help-inventory: True help-playbook: False inventory-columns: - ansible_network_os - ansible_network_cli_ssh_type - ansible_connection logging: level: critical append: False file: /tmp/log.txt mode: stdout playbook-artifact: enable: True replay: /tmp/test_artifact.json save-as: /tmp/test_artifact.json ���������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/changelog.yml����������������������������������������0000664�0000000�0000000�00000003070�14773473560�0024113�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ancestor: 0.5.4 releases: 1.0.0-alpha: release_date: "2020-01-01" codename: "The first public one" changes: release_summary: A bit o markdown text major_changes: - Free form text mentioning a major change minor_changes: - Free form text mentioning a minor change breaking_changes: - Free form text mentioning a breaking change deprecated_features: - A list of strings describing features deprecated in this release removed_features: - A list of strings describing features removed in this release security_fixes: - A list of strings describing security-relevant bugfixes bugfixes: - Fixed bug `#1 <https://example.com>` known_issues: - A list of strings describing known issues that are currently not fixed or will not be fixed trivial: - A list of strings describing changes that are too trivial to show in the changelog modules: - name: short_module_name description: foo namespace: foo plugins: lookup: - name: reverse description: Reverse magic namespace: null inventory: - name: docker description: Inventory plugin for docker containers namespace: null objects: role: - name: install_reqs description: Install all requirements of this collection namespace: null playbook: - name: wipe_personal_data description: Wipes all personal data from the database namespace: null ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/changelogs/������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0023553�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/changelogs/maximal/����������������������������������0000775�0000000�0000000�00000000000�14773473560�0025203�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/changelogs/maximal/changelog.yaml��������������������0000664�0000000�0000000�00000004371�14773473560�0030023�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- # Example of minimal changelogs/changelog.yaml that is considered valid ancestor: null releases: 1.0.0-alpha: release_date: "1980-01-01" codename: foo fragments: [] changes: release_summary: This is the initial White Rabbit release. Enjoy! major_changes: - The authentication method handling has been rewritten. minor_changes: - foo - Module can now reformat hard disks without asking. - bob lookup - Makes sure Bob isn't there multiple times. breaking_changes: - Due to the security bug in the post module, the module no longer accepts the password option. Please stop using the option and change any password you ever supplied to the module. deprecated_features: - foo - The bar option has been deprecated. Use the username option instead. - send_request - The quick option has been deprecated. Use the protocol option instead. removed_features: - foo - The baz option has been removed. It has never been used anyway. security_fixes: - post - The module accidentally sent your password in plaintext to all servers it could find. bugfixes: - post - The module made PUT requests instead of POST requests. - get - The module will no longer crash if it received invalid JSON data trivial: - something that is not included in release notes known_issues: - som other xxx: - we should ignore unknown keys because user can define custom section in changelogs/config.yaml file modules: - name: head description: Make a HEAD request namespace: "net_tools.rest" - name: echo description: Echo params namespace: "" plugins: lookup: - name: reverse description: Reverse magic namespace: null inventory: - name: docker description: Inventory plugin for docker containers namespace: null objects: role: - name: install_reqs description: Install all requirements of this collection namespace: null playbook: - name: wipe_personal_data description: Wipes all personal data from the database namespace: null �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/changelogs/minimal/����������������������������������0000775�0000000�0000000�00000000000�14773473560�0025201�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/changelogs/minimal/changelog.yaml��������������������0000664�0000000�0000000�00000000131�14773473560�0030007�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- # Example of minimal changelogs/changelog.yaml that is considered valid releases: {} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/execution-environment-v3.yml�������������������������0000664�0000000�0000000�00000000740�14773473560�0027060�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- version: 3 images: base_image: name: "quay.io/ansible/ansible-runner:stable-2.10-devel" dependencies: galaxy: requirements.yml python: requirements.txt system: bindep.txt additional_build_steps: prepend_base: | RUN whoami RUN cat /etc/os-release append_base: - RUN echo This is a post-install command! - RUN ls -la /etc options: package_manager_path: /usr/bin/dnf tags: - automation-hub.my.company.com/ee-supported-rhel9_foo:latest ��������������������������������ansible-ansible-lint-c16f018/test/schemas/test/execution-environment.yml����������������������������0000664�0000000�0000000�00000000747�14773473560�0026541�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- # Example from https://docs.ansible.com/automation-controller/latest/html/userguide/ee_reference.html version: 1 build_arg_defaults: EE_BASE_IMAGE: "quay.io/ansible/ansible-runner:stable-2.10-devel" ansible_config: "ansible.cfg" dependencies: galaxy: requirements.yml python: requirements.txt system: bindep.txt additional_build_steps: prepend: | RUN whoami RUN cat /etc/os-release append: - RUN echo This is a post-install command! - RUN ls -la /etc �������������������������ansible-ansible-lint-c16f018/test/schemas/test/galaxy.yml�������������������������������������������0000664�0000000�0000000�00000000733�14773473560�0023454�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������name: foo namespace: bar version: 1.2.3 authors: - John readme: ../README.md description: ... dependencies: "other_namespace.collection1": ">=1.0.0" "other_namespace.collection2": ">=2.0.0,<3.0.0" "anderson55.my_collection": "*" # note: "*" selects the highest version available # upload to galaxy will fail if a repository key is not present repository: https://www.github.com/my_org/my_collection manifest: directives: - "foo" omit_default_directives: true �������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/inventory.yml����������������������������������������0000664�0000000�0000000�00000000361�14773473560�0024221�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������all: hosts: mail.example.com: children: webservers: hosts: foo.example.com: bar[01:50:2].example.com: dbservers: hosts: one.example.com: two.example.com: three.example.com: �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/inventory/�������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0023476�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/inventory/inventory.yml������������������������������0000664�0000000�0000000�00000001114�14773473560�0026253�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- # https://docs.ansible.com/ansible/latest/inventory_guide/intro_inventory.html ungrouped: {} all: hosts: mail.example.com: children: webservers: hosts: foo.example.com: bar.example.com: dbservers: hosts: one.example.com: two.example.com: three.example.com: east: hosts: foo.example.com: one.example.com: two.example.com: west: hosts: bar.example.com: three.example.com: prod: children: east: {} test: children: west: {} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/inventory/production.yml�����������������������������0000664�0000000�0000000�00000001324�14773473560�0026407�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������all: hosts: mail.example.com: children: webservers: hosts: foo.example.com: bar.example.com: # ranges are supported: www[01:50].example.com: www[01:50:2].example.com: # these are variables: var_1: value_1 another_var: 200 dbservers: hosts: one.example.com: two.example.com: three.example.com: east: hosts: foo.example.com: one.example.com: two.example.com: west: hosts: bar.example.com: three.example.com: prod: children: east: test: children: west: # add variables for all hosts vars: my_var: 123 ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/meta/������������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0022367�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/meta/requirements.yml��������������������������������0000664�0000000�0000000�00000000054�14773473560�0025634�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# requirements v2 collections: [] roles: [] ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/meta/runtime.yml�������������������������������������0000664�0000000�0000000�00000000041�14773473560�0024570�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������requires_ansible: ">=2.12,<2.14" �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/molecule/��������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0023246�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/molecule/cluster/������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024727�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/molecule/cluster/base.yml����������������������������0000664�0000000�0000000�00000000000�14773473560�0026352�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/molecule/cluster/converge.yml������������������������0000664�0000000�0000000�00000000000�14773473560�0027250�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/molecule/cluster/foobar.yml��������������������������0000664�0000000�0000000�00000000000�14773473560�0026710�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/molecule/cluster/molecule.yml������������������������0000664�0000000�0000000�00000002700�14773473560�0027256�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- dependency: name: galaxy driver: name: docker lint: | set -e yamllint -c molecule/yaml-lint.yml . ansible-lint platforms: - name: instance-1 image: "geerlingguy/docker-${MOLECULE_DISTRO:-centos7}-ansible:latest" command: ${MOLECULE_DOCKER_COMMAND:-""} volumes: - /sys/fs/cgroup:/sys/fs/cgroup:ro privileged: true pre_build_image: true groups: - zookeeper env: - Hello: world! - name: instance-2 image: "geerlingguy/docker-${MOLECULE_DISTRO:-centos7}-ansible:latest" command: ${MOLECULE_DOCKER_COMMAND:-""} volumes: - /sys/fs/cgroup:/sys/fs/cgroup:ro privileged: true pre_build_image: true groups: - zookeeper env: - Hello: world! - name: instance-3 image: "geerlingguy/docker-${MOLECULE_DISTRO:-centos7}-ansible:latest" command: ${MOLECULE_DOCKER_COMMAND:-""} volumes: - /sys/fs/cgroup:/sys/fs/cgroup:ro privileged: true pre_build_image: true groups: - zookeeper env: - Hello: world! provisioner: name: ansible log: false playbooks: converge: ${MOLECULE_PLAYBOOK:-converge.yml} inventory: host_vars: instance-1: zookeeper_id: 0 instance-2: zookeeper_id: 1 instance-3: zookeeper_id: 2 scenario: name: cluster test_sequence: - destroy - create - prepare - converge - check - verify - destroy verifier: name: ansible ����������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/molecule/default/������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024672�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/molecule/default/molecule.yml������������������������0000664�0000000�0000000�00000004556�14773473560�0027234�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- dependency: name: shell enabled: true command: path/to/command --flag1 subcommand --flag2 options: ignore-certs: true ignore-errors: true env: FOO: bar lint: | set -e yamllint . ansible-lint driver: name: podman options: managed: false login_cmd_template: ... ansible_connection_options: ansible_connection: ssh # vagrant options: provider: name: virtualbox log: true platforms: - name: ubi8 hostname: ubi8 children: [] # list of strings unknown_property_foo: bar # unknown properties should be allowed for drivers groups: - ubi8 image: ubi8/ubi-init pre_build_image: true registry: url: registry.access.redhat.com dockerfile: Dockerfile pkg_extras: python*setuptools volumes: - /etc/ci/mirror_info.sh:/etc/ci/mirror_info.sh:ro - /etc/pki/rpm-gpg:/etc/pki/rpm-gpg privileged: true environment: &env http_proxy: "{{ lookup('env', 'http_proxy') }}" https_proxy: "{{ lookup('env', 'https_proxy') }}" ulimits: &ulimit - host # vagrant ones box: foo/bar memory: 1024 cpus: 2 provider_raw_config_args: [] networks: # used by docker/podman - name: foo - name: ubi7 hostname: ubi7 children: ["ubi8"] groups: - ubi7 image: ubi7/ubi-init registry: url: registry.access.redhat.com command: /sbin/init tmpfs: - /run - /tmp volumes: - /etc/ci/mirror_info.sh:/etc/ci/mirror_info.sh:ro - /etc/pki/rpm-gpg:/etc/pki/rpm-gpg - /sys/fs/cgroup:/sys/fs/cgroup:ro network_mode: service:vpn privileged: true environment: &env http_proxy: "{{ lookup('env', 'http_proxy') }}" https_proxy: "{{ lookup('env', 'https_proxy') }}" ulimits: &ulimit - host provisioner: playbooks: prepare: prepare.yml inventory: hosts: all: hosts: ubi8: ansible_python_interpreter: /usr/bin/python3 ubi7: selinux: permissive ubi8: selinux: enforced name: ansible log: true env: ANSIBLE_STDOUT_CALLBACK: yaml config_options: defaults: fact_caching: jsonfile fact_caching_connection: /tmp/molecule/facts scenario: test_sequence: - destroy - create - prepare - converge - check - verify - destroy verifier: name: testinfra ��������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/molecule/vagrant/������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024710�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/molecule/vagrant/molecule.yml������������������������0000664�0000000�0000000�00000001651�14773473560�0027243�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- dependency: name: shell enabled: false lint: | set -e yamllint . ansible-lint driver: name: vagrant provider: name: libvirt provision: false cachier: machine parallel: true default_box: "generic/alpine310" platforms: - name: instance hostname: foo.bar.com interfaces: - auto_config: true network_name: private_network type: dhcp instance_raw_config_args: - 'vm.synced_folder ".", "/vagrant", type: "rsync"' - 'vm.provision :shell, inline: "uname"' config_options: ssh.keep_alive: true ssh.remote_user: "vagrant" synced_folder: true box: fedora/32-cloud-base box_version: 32.20200422.0 box_url: "http://127.0.0.1/box.img" memory: 512 cpus: 1 provider_options: video_type: "vga" provider_raw_config_args: - cpuset = '1-4,^3,6' - name: instance2 hostname: false provisioner: name: ansible ���������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/�������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0023444�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/block.yml����������������������������������0000664�0000000�0000000�00000000361�14773473560�0025261�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost tasks: - debug: msg: task under no block - block: - debug: msg: task under one level of block - block: - debug: msg: task under two levels of block �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/defaults/����������������������������������0000775�0000000�0000000�00000000000�14773473560�0025253�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/defaults/foo.yml���������������������������0000664�0000000�0000000�00000000077�14773473560�0026565�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# defaults have same format as vars in_is_reserved: ... ss: ss �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/environment.yml����������������������������0000664�0000000�0000000�00000000170�14773473560�0026531�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - hosts: localhost environment: # <- valid FOO: BAR - hosts: localhost environment: "{{ foo }}" # <- valid ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/failed_when.yml����������������������������0000664�0000000�0000000�00000000573�14773473560�0026441�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost tasks: - name: foo ansible.builtin.debug: msg: foo! failed_when: false # <- valid - name: foo ansible.builtin.debug: msg: foo! failed_when: "string is valid too" # <- valid - name: foo ansible.builtin.debug: msg: foo! failed_when: # <- lists are valid too - foo - bar �������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/full-jinja.yml�����������������������������0000664�0000000�0000000�00000000636�14773473560�0026227�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Test that schema allows multiline-jinja hosts: localhost # https://github.com/ansible/ansible-lint/issues/2772 become: >- {{ true }} tasks: - name: Test more complex jinja is also allowed ansible.builtin.debug: msg: "{{ item }}" # that below is valid and show be allowed: with_items: >- {%- set ns = [1, 1, 2] -%} {{- ns | unique -}} ��������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/gather_facts.yml���������������������������0000664�0000000�0000000�00000000347�14773473560�0026625�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - hosts: localhost gather_facts: false tasks: - ansible.builtin.debug: msg: foo - hosts: localhost gather_facts: "{{ facts_var_bool | default(false) }}" tasks: - ansible.builtin.debug: msg: bar �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/gather_subset.yml��������������������������0000664�0000000�0000000�00000000340�14773473560�0027023�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - hosts: localhost gather_subset: - all - "!network" tasks: - ansible.builtin.debug: msg: foo - hosts: localhost gather_subset: - all tasks: - ansible.builtin.debug: msg: bar ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/ignore-unreachable.yml���������������������0000664�0000000�0000000�00000000441�14773473560�0027720�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Test hosts: localhost tasks: - name: Debug ansible.builtin.debug: msg: ignore_unreachable should be a boolean ignore_unreachable: true - name: Debug ansible.builtin.debug: msg: "foo" ignore_unreachable: '{{ "yes" | bool }}' �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/ignore_errors..yml�������������������������0000664�0000000�0000000�00000000310�14773473560�0027116�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost tasks: - command: echo 123 ignore_errors: true - command: echo 123 vars: should_ignore_errors: true ignore_errors: "{{ should_ignore_errors }}" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/import_playbook.yml������������������������0000664�0000000�0000000�00000000225�14773473560�0027400�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- ansible.builtin.import_playbook: other.yml - import_playbook: other.yml tags: - foo - import_playbook: other.yml when: - foo is true ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/included.yml�������������������������������0000664�0000000�0000000�00000000023�14773473560�0025751�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/integers.yml�������������������������������0000664�0000000�0000000�00000000666�14773473560�0026017�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - hosts: localhost vars: some: 0 gather_timeout: "{{ some }}" tasks: - ansible.builtin.debug: msg: "{{ item }}" async: 0 poll: 0 delay: 0 timeout: 0 port: 0 - ansible.builtin.debug: msg: "{{ item }}" async: "{{ some }}" poll: "{{ some }}" delay: "{{ some }}" timeout: "{{ some }}" port: "{{ some }}" - hosts: localhost gather_timeout: 0 ��������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/local_action_dict.yml����������������������0000664�0000000�0000000�00000000151�14773473560�0027616�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost tasks: - local_action: module: ansible.builtin.debug msg: hello �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/local_action_string.yml��������������������0000664�0000000�0000000�00000000122�14773473560�0030177�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost tasks: - local_action: "ansible.builtin.debug msg=hello" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/loop.yml�����������������������������������0000664�0000000�0000000�00000000224�14773473560�0025136�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - hosts: localhost tasks: - name: that should pass ansible.builtin.debug: var: item loop: - foo - bar ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/no_log.yml���������������������������������0000664�0000000�0000000�00000000306�14773473560�0025443�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost vars: some_var: true tasks: - ansible.builtin.debug: msg: foo no_log: true - ansible.builtin.debug: msg: foo no_log: "{{ some_var }}" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/order.yml����������������������������������0000664�0000000�0000000�00000000431�14773473560�0025300�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Test hosts: localhost order: "{{ host_order | default('shuffle') }}" gather_facts: false serial: 1 tasks: - name: ABC ansible.builtin.debug: msg: "hello" - name: Test 2 hosts: localhost order: inventory gather_facts: false tasks: [] ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/roles.yml����������������������������������0000664�0000000�0000000�00000000277�14773473560�0025321�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost roles: [] - hosts: localhost roles: - foo - role: "path/to/role" vars: FOO: bar tags: - foo - role: bar tags: string_tag ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/run.yml������������������������������������0000664�0000000�0000000�00000001737�14773473560�0025003�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- name: foo ansible.builtin.import_playbook: included.yml - hosts: # to check if lists are allowed: - localhost - webservers # validate serial allows strings like percentage value serial: 10% handlers: - name: handler 1 ansible.builtin.debug: msg: "I am handler 1" listen: "always handler" - name: handler 2 ansible.builtin.debug: msg: "I am handler 2" listen: # to check if lists are allowed: - "list listening handler" - "other listening topic" - hosts: localhost serial: 1 # validate serial allows integer - hosts: localhost serial: "{{ 1 }}" # jinja also ok - hosts: localhost serial: # validate serial allows these too: - 123 - 10% - "{{ some }}" # jinja also ok - hosts: localhost tasks: - debug: msg: "failed_when should accept booleans" failed_when: false - debug: msg: "failed_when should allow strings" failed_when: "'foo' in 'foobar'" ���������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/run_once.yml�������������������������������0000664�0000000�0000000�00000000201�14773473560�0025770�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost tasks: - name: foo2 ansible.builtin.debug: msg: foo! run_once: "{{ true }}" # valid �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tags.yml�����������������������������������0000664�0000000�0000000�00000000656�14773473560�0025134�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost roles: - role: foo tags: foo # <-- allowed - role: foo tags: # <-- allowed - foo - bar tags: # <-- allowed - foo - bar tasks: - ansible.builtin.debug: msg: "..." tags: # <-- allowed - foo - bar - ansible.builtin.debug: msg: "..." tags: # <-- allowed - foo - hosts: localhost tags: foo # <-- allowed ����������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks.yml����������������������������������0000664�0000000�0000000�00000000117�14773473560�0025313�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost pre_tasks: [] post_tasks: [] tasks: [] handlers: [] �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/�������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024571�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/args.yml�����������������������������0000664�0000000�0000000�00000000072�14773473560�0026247�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- action: foo args: {} - action: foo args: "{{ {} }}" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/become_method.yml��������������������0000664�0000000�0000000�00000000216�14773473560�0030105�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- command: echo 123 become_method: sudo - command: echo 123 vars: sudo_var: doo become_method: "{{ sudo_var }}" # templating is ok ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/changed_when.yml���������������������0000664�0000000�0000000�00000000362�14773473560�0027727�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- command: echo 123 changed_when: false - command: echo 123 changed_when: '"1" in ["1", "2", "3"]' - command: echo 123 changed_when: # valid, all items must evaluate as true (AND) - "foo is defined" - '"1" in ["1", "2", "3"]' ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/diff.yml�����������������������������0000664�0000000�0000000�00000000076�14773473560�0026227�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- action: foo diff: true - action: foo diff: "{{ true }}" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/empty_tasks.yml����������������������0000664�0000000�0000000�00000000075�14773473560�0027661�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- # this is a valid tasks file, loaded as 'null' document. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/ignore_errors.yml��������������������0000664�0000000�0000000�00000000224�14773473560�0030171�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- command: echo 123 ignore_errors: true - command: echo 123 vars: should_ignore_errors: true ignore_errors: "{{ should_ignore_errors }}" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/local_action_dict.yml����������������0000664�0000000�0000000�00000000101�14773473560�0030736�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- local_action: module: ansible.builtin.debug msg: hello ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/local_action_string.yml��������������0000664�0000000�0000000�00000000062�14773473560�0031327�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- local_action: "ansible.builtin.debug msg=hello" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/loop.yml�����������������������������0000664�0000000�0000000�00000000134�14773473560�0026263�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- name: that should pass ansible.builtin.debug: var: item loop: - foo - bar ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/no_log.yml���������������������������0000664�0000000�0000000�00000000315�14773473560�0026570�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- ansible.builtin.debug: msg: foo no_log: true # valid vars: some_var: true - ansible.builtin.debug: msg: foo no_log: "{{ some_var }}" # valid too vars: some_var: true �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/notify.yml���������������������������0000664�0000000�0000000�00000000364�14773473560�0026627�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- name: notify single handler ansible.builtin.debug: msg: task with single handler notify: handler1 - name: notify multiple handlers ansible.builtin.debug: msg: task with multiple handlers notify: - handler1 - handler2 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/run_once.yml�������������������������0000664�0000000�0000000�00000000242�14773473560�0027122�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- name: foo ansible.builtin.debug: msg: foo! run_once: true # valid - name: foo2 ansible.builtin.debug: msg: foo! run_once: "{{ true }}" # valid ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/some_tasks.yml�����������������������0000664�0000000�0000000�00000000176�14773473560�0027470�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- name: foo debug: msg: bar delegate_facts: true - block: - debug: msg: "block under one level of block" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/tags.yml�����������������������������0000664�0000000�0000000�00000000537�14773473560�0026257�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- command: echo 123 tags: - foo - bar - command: echo 123 tags: foo - block: - command: echo 123 tags: - foo - bar - command: echo 123 tags: foo tags: - foo - bar - block: - command: echo 123 tags: - foo - bar - command: echo 123 tags: foo tags: foo �����������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/templated_become.yml�����������������0000664�0000000�0000000�00000000434�14773473560�0030606�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- name: foo ansible.builtin.debug: msg: foo! become: "{{ firewalld_become }}" # <- valid - name: foo block become: "{{ firewalld_become }}" # <- valid block: - name: foo ansible.builtin.debug: msg: foo! become: "{{ firewalld_become }}" # <- valid ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/templated_integers.yml���������������0000664�0000000�0000000�00000000164�14773473560�0031174�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- debug: msg: foo retries: "{{ 2 }}" # <-- valid port: "{{ 80 }}" # <-- valid poll: "{{ 2 }}" # <-- valid ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/throttled.yml������������������������0000664�0000000�0000000�00000000121�14773473560�0027317�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- action: foo throttle: 1 # valid - action: foo throttle: "{{ 1 }}" # valid �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/until.yml����������������������������0000664�0000000�0000000�00000000361�14773473560�0026447�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- ansible.builtin.debug: msg: "valid" until: true - ansible.builtin.debug: msg: "valid" until: - "foo not in bar" - ansible.builtin.debug: msg: "valid" until: - "'1' in ['1', '2', '3']" - "foo is not defined" �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/when.yml�����������������������������0000664�0000000�0000000�00000000257�14773473560�0026261�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- action: debug when: true # valid - action: debug msg="foo" when: foo in bar # valid - action: debug msg="foo 3" when: # valid - foo in bar - apple is orange �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/tasks/with_items.yml�����������������������0000664�0000000�0000000�00000000310�14773473560�0027462�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- command: echo 123 with_items: [] - command: echo 123 with_items: - 1 - foo - {} - [] - command: echo 123 vars: my_list: - 1 - 2 with_items: "{{ my_list }}" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/templated_become.yml�����������������������0000664�0000000�0000000�00000000626�14773473560�0027464�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - hosts: localhost become: "{{ firewalld_become }}" # <- valid tasks: - name: foo ansible.builtin.debug: msg: foo! become: "{{ firewalld_become }}" # <- valid - name: foo block become: "{{ firewalld_become }}" # <- valid block: - name: foo ansible.builtin.debug: msg: foo! become: "{{ firewalld_become }}" # <- valid ����������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/user_valid.yml�����������������������������0000664�0000000�0000000�00000000117�14773473560�0026323�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- hosts: localhost user: foo # <-- allowed, alias to remote_user tasks: [] �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/var_files.yml������������������������������0000664�0000000�0000000�00000000557�14773473560�0026150�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: var_files should accept null hosts: localhost vars_files: null - name: var_files should accept string hosts: localhost vars_files: /dev/null - name: var_files should accept array[string] hosts: localhost vars_files: - /dev/null - name: var_files should accept array of array[string] hosts: localhost vars_files: - ["/dev/null"] �������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/vars/��������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024417�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/vars/empty_vars.yml������������������������0000664�0000000�0000000�00000000101�14773473560�0027323�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- # Ensure we allow empty var files, matching Ansible behavior ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/vars/encrypted.yml�������������������������0000664�0000000�0000000�00000000547�14773473560�0027145�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������$ANSIBLE_VAULT;1.2;AES256;dev 66373266323161346330626137613862653935343634366636353266323966363665636266363739 6436363237626633653139636232663131613832336266310a323766643264306436306266663930 66666238346132373766623932356530333165613835623863653837306130383065323138333034 6265313861613761620a393663616265633637343534346533366437653839623239396366366330 3165 ���������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/vars/myvars.yml����������������������������0000664�0000000�0000000�00000000215�14773473560�0026461�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������foo: bar _foo: bar foo_var_xxx: "{{ sss }}" in_job: ... nested: pear: fruit apple: fruit sso_force_handlers: ... force_handlers_foo: ... �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/vars_prompt.yml����������������������������0000664�0000000�0000000�00000000350�14773473560�0026541�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������- name: Fixture hosts: localhost vars_prompt: - name: username prompt: What is your username? private: false unsafe: false - name: password prompt: What is your password? default: "secret" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/when.yml�����������������������������������0000664�0000000�0000000�00000000346�14773473560�0025133�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- - name: Test for when (passing) hosts: localhost gather_facts: false tasks: - name: Testing for when is passed a list ansible.builtin.debug: msg: "this is ok" when: - true - "foo" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/playbooks/with_.yml����������������������������������0000664�0000000�0000000�00000001647�14773473560�0025311�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- # https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#with-flattened - hosts: localhost tasks: - ansible.builtin.debug: msg: "{{ item }}" with_list: [] # <-- valid - ansible.builtin.debug: msg: "{{ item }}" with_items: [] # <-- valid - ansible.builtin.debug: msg: "{{ item }}" with_indexed_items: [] - ansible.builtin.debug: msg: "{{ item }}" with_together: [] - ansible.builtin.debug: msg: "{{ item }}" with_dict: {} - ansible.builtin.debug: msg: "{{ item }}" with_sequence: [] - ansible.builtin.debug: msg: "{{ item }}" with_subelements: [] - ansible.builtin.debug: msg: "{{ item }}" with_nested: [] - ansible.builtin.debug: msg: "{{ item }}" with_random_choice: [] - ansible.builtin.debug: msg: "{{ item }}" with_fileglob: [] �����������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/reqs2/�����������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0022475�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/reqs2/meta/������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0023423�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/reqs2/meta/requirements.yml��������������������������0000664�0000000�0000000�00000000276�14773473560�0026676�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# https://docs.ansible.com/ansible/latest/galaxy/user_guide.html collections: - doo.bar - name: geerlingguy.php_roles version: 0.9.3 source: https://galaxy.ansible.com roles: [] ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/reqs4/�����������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0022477�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/reqs4/meta/������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0023425�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/reqs4/meta/requirements.yml��������������������������0000664�0000000�0000000�00000000256�14773473560�0026676�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# requirements v1 format - src: https://github.com/bennojoy/nginx - src: git+http://bitbucket.org/willthames/git-ansible-galaxy version: v1.4 scm: git - include: foo.yml ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/reqs5/�����������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0022500�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/reqs5/meta/������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0023426�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/reqs5/meta/requirements.yml��������������������������0000664�0000000�0000000�00000000102�14773473560�0026665�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Collection without roles collections: - name: kubernetes.core ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/�����������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0022565�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/description-only/������������������������������0000775�0000000�0000000�00000000000�14773473560�0026067�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/description-only/meta/�������������������������0000775�0000000�0000000�00000000000�14773473560�0027015�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/description-only/meta/main.yml�����������������0000664�0000000�0000000�00000000161�14773473560�0030462�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- argument_specs: main: short_description: A role with only documentation and no options should be valid ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/empty-meta/������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024647�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/empty-meta/meta/�������������������������������0000775�0000000�0000000�00000000000�14773473560�0025575�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/empty-meta/meta/main.yml�����������������������0000664�0000000�0000000�00000000076�14773473560�0027247�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# this is meta file without any data, ansible-core accepts it ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/foo/�������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0023350�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/foo/meta/��������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024276�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/foo/meta/argument_specs.yml��������������������0000664�0000000�0000000�00000006270�14773473560�0030045�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- # https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#role-argument-validation argument_specs: main: short_description: The main entry point for the role. description: "a longer description" version_added: 1.2.3 author: Foobar Baz options: my_app_int: type: "int" required: false default: 42 description: "The integer value, defaulting to 42." no_log: false version_added: 1.0.0 my_app_str: type: "str" required: true description: - The string value. - Has some more text. choices: - foo - bar - baz top_level: type: dict description: Contains more content. options: sub_option: type: list elements: int description: A list of special integers. choices: - 1 - 2 - 3 - 123 complex_required_options: type: dict description: Contains sub-options with interacting requirements options: foo: type: str bar: type: str baz: type: str mutually_exclusive: - ["foo", "bar"] required_together: - ["bar", "baz"] required_one_of: - ["foo", "bar", "baz"] required_if: - ["foo", "must_have_bar_and_baz_default", ["bar", "baz"]] - ["foo", "must_have_bar_and_baz_explicit", ["bar", "baz"], false] - ["foo", "must_have_one_of_bar_or_baz", ["bar", "baz"], true] required_by: foo: "bar" bar: ["foo", "baz"] seealso: - module: community.foo.bar - module: community.foo.baz description: Baz bam! - plugin: community.foo.bam plugin_type: lookup - plugin: community.foo.bar plugin_type: lookup description: A lookup plugin. - ref: developer_guide description: A link into the Ansible documentation. - link: https://docs.ansible.com/ name: The Ansible documentation. description: A link to the Ansible documentation. examples: |- - name: Use role include_role: foo.bar.baz alternate: short_description: The alternate entry point for the my_app role. author: - Foobar Baz - Bert Foo attributes: idempotent: description: Whether the role is idempotent. support: full check_mode: description: - Whether the role supports check mode. support: partial details: - Does not work if O(my_app_int=5). version_added: 1.2.0 action_group: description: - Use C(group/foo.bar.baz) in C(module_defaults) to set authentication options for the C(foo.bar) modules used by this role. support: full membership: foo.bar.baz options: my_app_int: type: "int" required: false default: 1024 description: "The integer value, defaulting to 1024." third: description: - First paragraph. - Second paragraph. options: {} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/foo/meta/main.yml������������������������������0000664�0000000�0000000�00000002212�14773473560�0025742�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������collections: - foo.bar dependencies: - name: ansible-role-foo version: "1.0" - name: ansible-role-bar version: "1.0" - ansible-role-baz # from Bitbucket - src: git+http://bitbucket.org/willthames/git-ansible-galaxy version: v1.4 # from Bitbucket, alternative syntax and caveats - src: http://bitbucket.org/willthames/hg-ansible-galaxy scm: hg # from galaxy - src: community.molecule # from GitHub - src: https://github.com/bennojoy/nginx # from GitHub, overriding the name and specifying a specific tag - src: https://github.com/bennojoy/nginx version: master name: nginx_role # from GitLab or other git-based scm - src: git@gitlab.company.com:my-group/my-repo.git scm: git version: "0.1" # quoted, so YAML doesn't parse this as a floating-point value # from a web server, where the role is packaged in a tar.gz - src: https://some.webserver.example.com/files/master.tar.gz name: http-role galaxy_info: author: John Doe company: foo description: foo license: MIT min_ansible_version: "2.9" # standalone: true platforms: - name: Alpine versions: - all ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/foo/meta/runtime.yml���������������������������0000664�0000000�0000000�00000002442�14773473560�0026506�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Based on https://docs.ansible.com/ansible/devel/dev_guide/developing_collections_structure.html#meta-directory requires_ansible: ">=2.10,<2.11" plugin_routing: inventory: kubevirt: redirect: community.general.kubevirt my_inventory: tombstone: removal_version: "2.0.0" warning_text: my_inventory has been removed. Please use other_inventory instead. modules: my_module: deprecation: removal_date: "2021-11-30" warning_text: my_module will be removed in a future release of this collection. Use another.collection.new_module instead. redirect: another.collection.new_module podman_image: redirect: containers.podman.podman_image module_utils: ec2: redirect: amazon.aws.ec2 util_dir.subdir.my_util: redirect: namespace.name.my_util import_redirection: ansible.module_utils.old_utility: redirect: ansible_collections.namespace_name.collection_name.plugins.module_utils.new_location action_groups: groupname: # The special metadata dictionary. All action/module names should be strings. - metadata: extend_group: - another.collection.groupname - another_group - my_action another_group: - my_module - another.collection.another_module ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/maximum/���������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024242�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/maximum/meta/����������������������������������0000775�0000000�0000000�00000000000�14773473560�0025170�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/maximum/meta/main.yml��������������������������0000664�0000000�0000000�00000000577�14773473560�0026650�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������allow_duplicates: true galaxy_info: author: John Doe standalone: true # v1 role meta (standalone) description: maximum min_ansible_version: "2.9" company: foo license: MIT galaxy_tags: # ensure galaxy_tags is allowed - database platforms: - name: Alpine versions: - all dependencies: - role: foo vars: {} when: - foo - bar ���������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/meta-tags/�������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024447�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/meta-tags/meta/��������������������������������0000775�0000000�0000000�00000000000�14773473560�0025375�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/meta-tags/meta/main.yml������������������������0000664�0000000�0000000�00000001302�14773473560�0027040�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- # https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html#role-dependencies dependencies: - role: foo tags: fruit # simple string allowed - role: bar tags: # array of strings allowed - apple - orange - role: requires_sudo become: true - role: role_with_condition when: inventory_hostname == "foo" - role: another_role # https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#passing-different-parameters something_that_counts_as_role_parameter: ... vars: "foo": bar galaxy_info: author: John Doe standalone: true description: foo license: MIT min_ansible_version: "2.10" platforms: [] ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/ns/��������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0023205�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/ns/meta/���������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024133�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/ns/meta/main.yml�������������������������������0000664�0000000�0000000�00000000330�14773473560�0025576�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- galaxy_info: author: John Doe standalone: true description: foo min_ansible_version: "2.9" namespace: foo_bar company: foo license: MIT platforms: - name: Alpine versions: - all ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/v1_role/���������������������������������������0000775�0000000�0000000�00000000000�14773473560�0024134�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/v1_role/meta/����������������������������������0000775�0000000�0000000�00000000000�14773473560�0025062�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/roles/v1_role/meta/main.yml��������������������������0000664�0000000�0000000�00000000407�14773473560�0026532�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- galaxy_info: standalone: true author: foo-bar # <-- that is a valid author name because is a valid github username description: foo min_ansible_version: "2.9" company: foo license: MIT platforms: - name: Alpine versions: - all ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/tests/�����������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0022603�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/tests/integration/�����������������������������������0000775�0000000�0000000�00000000000�14773473560�0025126�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/tests/integration/rom_role/��������������������������0000775�0000000�0000000�00000000000�14773473560�0026744�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/tests/integration/rom_role/meta/���������������������0000775�0000000�0000000�00000000000�14773473560�0027672�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/test/tests/integration/rom_role/meta/main.yml�������������0000664�0000000�0000000�00000000111�14773473560�0031332�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������--- dependencies: [] galaxy_info: standalone: false description: foo �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/schemas/tsconfig.json���������������������������������������������0000664�0000000�0000000�00000000574�14773473560�0023177�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ "compilerOptions": { "declaration": true, "esModuleInterop": true, "lib": ["ESNext"], "module": "esnext", "moduleResolution": "node", "outDir": "../../.tox/out", "resolveJsonModule": true, "sourceMap": true, "strict": true, "stripInternal": true, "target": "ESNext", }, "exclude": ["node_modules"], "include": ["src/**/*"], } ������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_adjacent_plugins.py������������������������������������������0000664�0000000�0000000�00000001332�14773473560�0023761�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test ability to recognize adjacent modules/plugins.""" import logging import pytest from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner def test_adj_action( default_rules_collection: RulesCollection, caplog: pytest.LogCaptureFixture, ) -> None: """Assures local collections are found.""" playbook_path = "examples/playbooks/adj_action.yml" with caplog.at_level(logging.DEBUG): runner = Runner(playbook_path, rules=default_rules_collection, verbosity=1) results = runner.run() assert "Unable to load module" not in caplog.text assert "Unable to resolve FQCN" not in caplog.text assert len(runner.lintables) == 1 assert len(results) == 0 ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_ansiblelintrule.py�������������������������������������������0000664�0000000�0000000�00000002100�14773473560�0023635�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Generic tests for AnsibleLintRule class.""" from __future__ import annotations from typing import Any import pytest from ansiblelint.rules import AnsibleLintRule, RulesCollection from ansiblelint.rules.complexity import ComplexityRule def test_unjinja() -> None: """Verify that unjinja understands nested mustache.""" text = "{{ a }} {% b %} {# try to confuse parsing inside a comment { {{}} } #}" output = "JINJA_EXPRESSION JINJA_STATEMENT JINJA_COMMENT" assert AnsibleLintRule.unjinja(text) == output @pytest.mark.parametrize( ("rule_name", "rule_config"), ( pytest.param("load-failure", {}, id="load-failure"), pytest.param("complexity", {}, id="complexity"), ), ) def test_rule_config( rule_name: str, rule_config: dict[str, Any], ) -> None: """Check that a rule config can be accessed.""" rules = RulesCollection() rules.register(ComplexityRule()) for rule in rules: if rule.id == rule_name: assert rule._collection # noqa: SLF001 assert rule.rule_config == rule_config ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_ansiblesyntax.py���������������������������������������������0000664�0000000�0000000�00000001004�14773473560�0023327�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test Ansible Syntax. This module contains tests that validate that linter does not produce errors when encountering what counts as valid Ansible syntax. """ from ansiblelint.testing import RunFromText PB_WITH_NULL_TASKS = """\ --- - name: Fixture for test_null_tasks hosts: all tasks: """ def test_null_tasks(default_text_runner: RunFromText) -> None: """Assure we do not fail when encountering null tasks.""" results = default_text_runner.run_playbook(PB_WITH_NULL_TASKS) assert not results ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_app.py�������������������������������������������������������0000664�0000000�0000000�00000004531�14773473560�0021233�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test for app module.""" from pathlib import Path from ansiblelint.constants import RC from ansiblelint.file_utils import Lintable from ansiblelint.testing import run_ansible_lint def test_generate_ignore(tmp_path: Path) -> None: """Validate that --generate-ignore dumps expected ignore to the file.""" lintable = Lintable(tmp_path / "vars.yaml") lintable.content = "foo: 1\nbar: baz\n" lintable.write(force=True) ignore_file = tmp_path / ".ansible-lint-ignore" assert not ignore_file.exists() result = run_ansible_lint(lintable.filename, "--generate-ignore", cwd=tmp_path) assert result.returncode == 2 assert ignore_file.exists() with ignore_file.open(encoding="utf-8") as f: assert "vars.yaml yaml[colons]\n" in f.readlines() # Run again and now we expect to succeed as we have an ignore file. result = run_ansible_lint(lintable.filename, cwd=tmp_path) assert result.returncode == 0 def test_app_no_matches(tmp_path: Path) -> None: """Validate that linter returns special exit code if no files are analyzed.""" result = run_ansible_lint(cwd=tmp_path) assert result.returncode == RC.NO_FILES_MATCHED def test_with_inventory_concurrent_syntax_checks(tmp_path: Path) -> None: """Validate using inventory file with concurrent syntax checks aren't faulty.""" (tmp_path / "ansible.cfg").write_text("[defaults]\ninventory = foo\n") (tmp_path / "foo").write_text("[group_name]\nhost1\nhost2\n") lintable1 = Lintable(tmp_path / "playbook1.yml") lintable2 = Lintable(tmp_path / "playbook2.yml") lintable1.content = "---\n- name: Test\n hosts:\n - group_name\n serial: \"{{ batch | default(groups['group_name'] | length) }}\"\n" lintable2.content = "---\n- name: Test\n hosts:\n - group_name\n serial: \"{{ batch | default(groups['group_name'] | length) }}\"\n" lintable1.kind = "playbook" lintable2.kind = "playbook" lintable1.write(force=True) lintable2.write(force=True) counter = 0 while counter < 3: result = run_ansible_lint(lintable1.filename, lintable2.filename, cwd=tmp_path) assert result.returncode == RC.SUCCESS # AttributeError err is expected to look like what's reported here, # https://github.com/ansible/ansible-lint/issues/4446. assert "AttributeError" not in result.stderr counter += 1 �����������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_cli.py�������������������������������������������������������0000664�0000000�0000000�00000020016�14773473560�0021216�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test cli arguments and config.""" from __future__ import annotations import os from pathlib import Path from typing import TYPE_CHECKING import pytest from ansiblelint import cli if TYPE_CHECKING: from _pytest.monkeypatch import MonkeyPatch @pytest.fixture(name="base_arguments") def fixture_base_arguments() -> list[str]: """Define reusable base arguments for tests in current module.""" return ["../test/skiptasks.yml"] @pytest.mark.parametrize( ("args", "config_path"), ( pytest.param(["-p"], "test/fixtures/parseable.yml", id="1"), pytest.param(["-q"], "test/fixtures/quiet.yml", id="2"), pytest.param( ["-r", "test/fixtures/rules/"], "test/fixtures/rulesdir.yml", id="3", ), pytest.param( ["-R", "-r", "test/fixtures/rules/"], "test/fixtures/rulesdir-defaults.yml", id="4", ), pytest.param(["-s"], "test/fixtures/strict.yml", id="5"), pytest.param(["-t", "skip_ansible_lint"], "test/fixtures/tags.yml", id="6"), pytest.param(["-v"], "test/fixtures/verbosity.yml", id="7"), pytest.param(["-x", "bad_tag"], "test/fixtures/skip-tags.yml", id="8"), pytest.param(["--exclude", "../"], "test/fixtures/exclude-paths.yml", id="9"), pytest.param(["--show-relpath"], "test/fixtures/show-abspath.yml", id="10"), pytest.param([], "test/fixtures/show-relpath.yml", id="11"), ), ) def test_ensure_config_are_equal( base_arguments: list[str], args: list[str], config_path: str, ) -> None: """Check equality of the CLI options to config files.""" command = base_arguments + args cli_parser = cli.get_cli_parser() options = cli_parser.parse_args(command) file_config = cli.load_config(config_path)[0] for key, val in file_config.items(): # config_file does not make sense in file_config if key == "config_file": continue if key == "rulesdir": # this is list of Paths val = [Path(p) for p in val] assert val == getattr(options, key), f"Mismatch for {key}" @pytest.mark.parametrize( ("with_base", "args", "config", "expected"), ( pytest.param( True, ["--fix"], "test/fixtures/config-with-write-all.yml", ["all"], id="1", ), pytest.param( True, ["--fix=all"], "test/fixtures/config-with-write-all.yml", ["all"], id="2", ), pytest.param( True, ["--fix", "all"], "test/fixtures/config-with-write-all.yml", ["all"], id="3", ), pytest.param( True, ["--fix=none"], "test/fixtures/config-with-write-none.yml", [], id="4", ), pytest.param( True, ["--fix", "none"], "test/fixtures/config-with-write-none.yml", [], id="5", ), pytest.param( True, ["--fix=rule-tag,rule-id"], "test/fixtures/config-with-write-subset.yml", ["rule-tag", "rule-id"], id="6", ), pytest.param( True, ["--fix", "rule-tag,rule-id"], "test/fixtures/config-with-write-subset.yml", ["rule-tag", "rule-id"], id="7", ), pytest.param( True, ["--fix", "rule-tag", "--fix", "rule-id"], "test/fixtures/config-with-write-subset.yml", ["rule-tag", "rule-id"], id="8", ), pytest.param( False, ["--fix", "examples/playbooks/example.yml"], "test/fixtures/config-with-write-all.yml", ["all"], id="9", ), pytest.param( False, ["--fix", "examples/playbooks/example.yml", "non-existent.yml"], "test/fixtures/config-with-write-all.yml", ["all"], id="10", ), ), ) def test_ensure_write_cli_does_not_consume_lintables( base_arguments: list[str], with_base: bool, args: list[str], config: str, expected: list[str], ) -> None: """Check equality of the CLI --fix options to config files.""" cli_parser = cli.get_cli_parser() command = base_arguments + args if with_base else args options = cli_parser.parse_args(command) file_config = cli.load_config(config)[0] file_config.get("write_list") orig_cli_value = options.write_list cli_value = cli.WriteArgAction.merge_fix_list_config( from_file=[], from_cli=orig_cli_value, ) assert cli_value == expected def test_config_can_be_overridden(base_arguments: list[str]) -> None: """Check that config can be overridden from CLI.""" no_override = cli.get_config([*base_arguments, "-t", "bad_tag"]) overridden = cli.get_config( [*base_arguments, "-t", "bad_tag", "-c", "test/fixtures/tags.yml"], ) assert [*no_override.tags, "skip_ansible_lint"] == overridden.tags def test_different_config_file(base_arguments: list[str]) -> None: """Ensures an alternate config_file can be used.""" diff_config = cli.get_config( [*base_arguments, "-c", "test/fixtures/ansible-config.yml"], ) no_config = cli.get_config([*base_arguments, "-v"]) assert diff_config.verbosity == no_config.verbosity def test_expand_path_user_and_vars_config_file(base_arguments: list[str]) -> None: """Ensure user and vars are expanded when specified as exclude_paths.""" config1 = cli.get_config( [*base_arguments, "-c", "test/fixtures/exclude-paths-with-expands.yml"], ) config2 = cli.get_config( [ *base_arguments, "--exclude", "~/.ansible/roles", "--exclude", "$HOME/.ansible/roles", ], ) assert str(config1.exclude_paths[0]) == os.path.expanduser( # noqa: PTH111 "~/.ansible/roles", ) assert str(config1.exclude_paths[1]) == os.path.expandvars("$HOME/.ansible/roles") # exclude-paths coming in via cli are PosixPath objects; which hold the (canonical) real path (without symlinks) assert str(config2.exclude_paths[0]) == os.path.realpath( os.path.expanduser("~/.ansible/roles"), # noqa: PTH111 ) assert str(config2.exclude_paths[1]) == os.path.realpath( os.path.expandvars("$HOME/.ansible/roles"), ) def test_path_from_config_do_not_depend_on_cwd( monkeypatch: MonkeyPatch, ) -> None: # Issue 572 """Check that config-provided paths are decoupled from CWD.""" config1 = cli.load_config("test/fixtures/config-with-relative-path.yml")[0] monkeypatch.chdir("test") config2 = cli.load_config("fixtures/config-with-relative-path.yml")[0] assert config1["exclude_paths"].sort() == config2["exclude_paths"].sort() @pytest.mark.parametrize( "config_file", ( pytest.param("test/fixtures/ansible-config-invalid.yml", id="invalid"), pytest.param("/dev/null/ansible-config-missing.yml", id="missing"), ), ) def test_config_failure(base_arguments: list[str], config_file: str) -> None: """Ensures specific config files produce error code 3.""" with pytest.raises(SystemExit, match=r"^3$"): cli.get_config([*base_arguments, "-c", config_file]) def test_extra_vars_loaded(base_arguments: list[str]) -> None: """Ensure ``extra_vars`` option is loaded from file config.""" config = cli.get_config( [*base_arguments, "-c", "test/fixtures/config-with-extra-vars.yml"], ) assert config.extra_vars == {"foo": "bar", "knights_favorite_word": "NI"} @pytest.mark.parametrize( "config_file", (pytest.param("/dev/null", id="dev-null"),), ) def test_config_dev_null(base_arguments: list[str], config_file: str) -> None: """Ensures specific config files produce error code 3.""" cfg = cli.get_config([*base_arguments, "-c", config_file]) assert cfg.config_file == "/dev/null" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_cli_role_paths.py��������������������������������������������0000664�0000000�0000000�00000017506�14773473560�0023450�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests related to role paths.""" from __future__ import annotations import os from pathlib import Path import pytest from ansiblelint.constants import RC from ansiblelint.testing import run_ansible_lint from ansiblelint.text import strip_ansi_escape @pytest.fixture(name="local_test_dir") def fixture_local_test_dir() -> Path: """Fixture to return local test directory.""" return Path(__file__).resolve().parent.parent / "examples" def test_run_single_role_path_no_trailing_slash_module(local_test_dir: Path) -> None: """Test that a role path without a trailing slash is accepted.""" cwd = local_test_dir role_path = "roles/test-role" result = run_ansible_lint(role_path, cwd=cwd) assert "Use shell only when shell functionality is required" in result.stdout def test_run_single_role_path_no_trailing_slash_script(local_test_dir: Path) -> None: """Test that a role path without a trailing slash is accepted.""" cwd = local_test_dir role_path = "roles/test-role" result = run_ansible_lint(role_path, cwd=cwd, executable="ansible-lint") assert "Use shell only when shell functionality is required" in result.stdout def test_run_single_role_path_with_trailing_slash(local_test_dir: Path) -> None: """Test that a role path with a trailing slash is accepted.""" cwd = local_test_dir role_path = "roles/test-role/" result = run_ansible_lint(role_path, cwd=cwd) assert "Use shell only when shell functionality is required" in result.stdout def test_run_multiple_role_path_no_trailing_slash(local_test_dir: Path) -> None: """Test that multiple roles paths without a trailing slash are accepted.""" cwd = local_test_dir role_path = "roles/test-role" result = run_ansible_lint(role_path, cwd=cwd) assert "Use shell only when shell functionality is required" in result.stdout def test_run_multiple_role_path_with_trailing_slash(local_test_dir: Path) -> None: """Test that multiple roles paths without a trailing slash are accepted.""" cwd = local_test_dir role_path = "roles/test-role/" result = run_ansible_lint(role_path, cwd=cwd) assert "Use shell only when shell functionality is required" in result.stdout def test_run_inside_role_dir(local_test_dir: Path) -> None: """Tests execution from inside a role.""" cwd = local_test_dir / "roles" / "test-role" role_path = "." result = run_ansible_lint(role_path, cwd=cwd) assert "Use shell only when shell functionality is required" in result.stdout def test_run_role_three_dir_deep(local_test_dir: Path) -> None: """Tests execution from deep inside a role.""" cwd = local_test_dir role_path = "testproject/roles/test-role" result = run_ansible_lint(role_path, cwd=cwd) assert "Use shell only when shell functionality is required" in result.stdout def test_run_playbook(local_test_dir: Path) -> None: """Call ansible-lint the way molecule does.""" cwd = local_test_dir / "roles" / "test-role" lintable = "molecule/default/include-import-role.yml" role_path = str(Path(cwd).parent.resolve()) env = os.environ.copy() env["ANSIBLE_ROLES_PATH"] = role_path env["NO_COLOR"] = "1" result = run_ansible_lint("-f", "pep8", lintable, cwd=cwd, env=env) # All 4 failures are expected to be found inside the included role and not # from the playbook given as argument. assert result.returncode == RC.VIOLATIONS_FOUND assert "tasks/main.yml:2: command-instead-of-shell" in result.stdout assert "tasks/world.yml:2: name[missing]" in result.stdout @pytest.mark.parametrize( ("args", "expected_msg"), ( pytest.param( [], "role-name: Role name invalid-name does not match", id="normal", ), pytest.param(["--nocolor", "--skip-list", "role-name"], "", id="skipped"), ), ) def test_run_role_name_invalid( local_test_dir: Path, args: list[str], expected_msg: str, ) -> None: """Test run with a role with invalid name.""" cwd = local_test_dir role_path = "roles/invalid-name" env = {"NO_COLOR": "1"} result = run_ansible_lint(*args, role_path, cwd=cwd, env=env) assert result.returncode == (2 if expected_msg else 0), result if expected_msg: assert expected_msg in result.stdout def test_run_role_name_with_prefix(local_test_dir: Path) -> None: """Test run where role path has a prefix.""" cwd = local_test_dir role_path = "roles/ansible-role-foo" result = run_ansible_lint("-v", role_path, cwd=cwd) assert len(result.stdout) == 0 assert result.returncode == 0 def test_run_role_name_from_meta(local_test_dir: Path) -> None: """Test running from inside meta folder.""" cwd = local_test_dir role_path = "roles/valid-due-to-meta" result = run_ansible_lint("-v", role_path, cwd=cwd) assert len(result.stdout) == 0 assert result.returncode == 0 def test_run_invalid_role_name_from_meta(local_test_dir: Path) -> None: """Test invalid role from inside meta folder.""" cwd = local_test_dir role_path = "roles/invalid_due_to_meta" result = run_ansible_lint(role_path, cwd=cwd, env={"NO_COLOR": "1"}) assert ( "role-name: Role name invalid-due-to-meta does not match" in strip_ansi_escape(result.stdout) ) def test_run_single_role_path_with_roles_path_env(local_test_dir: Path) -> None: """Test for role name collision with ANSIBLE_ROLES_PATH. Test if ansible-lint chooses the role in the current directory when the role specified as parameter exists in the current directory and the ANSIBLE_ROLES_PATH. """ cwd = local_test_dir role_path = "roles/test-role" env = os.environ.copy() env["ANSIBLE_ROLES_PATH"] = os.path.realpath((cwd / "../examples/roles").resolve()) result = run_ansible_lint(role_path, cwd=cwd, env=env) assert "Use shell only when shell functionality is required" in result.stdout @pytest.mark.parametrize( ("result", "env"), ( (True, {"GITHUB_ACTIONS": "true", "GITHUB_WORKFLOW": "foo", "NO_COLOR": "1"}), (False, None), ), ids=("on", "off"), ) def test_run_playbook_github(result: bool, env: dict[str, str]) -> None: """Call ansible-lint simulating GitHub Actions environment.""" cwd = Path(__file__).parent.parent.resolve() role_path = "examples/playbooks/example.yml" if env is None: env = {} env["PATH"] = os.environ["PATH"] result_gh = run_ansible_lint(role_path, cwd=cwd, env=env) expected = ( "::error file=examples/playbooks/example.yml,line=44,severity=VERY_LOW,title=package-latest::" "Package installs should not use latest" ) assert (expected in result_gh.stderr) is result def test_run_role_identified(local_test_dir: Path) -> None: """Test that role name is identified correctly.""" cwd = local_test_dir env = os.environ.copy() env["ANSIBLE_ROLES_PATH"] = os.path.realpath( (cwd / "../examples/roles/role_detection").resolve(), ) result = run_ansible_lint( Path("roles/role_detection/foo/defaults/main.yml"), cwd=cwd, env=env, ) assert result.returncode == RC.SUCCESS def test_run_role_identified_prefix_missing(local_test_dir: Path) -> None: """Test that role name is identified correctly, with prefix violations.""" cwd = local_test_dir env = os.environ.copy() env["ANSIBLE_ROLES_PATH"] = os.path.realpath( (cwd / "../examples/roles/role_detection/base").resolve(), ) result = run_ansible_lint( Path("roles/role_detection/base/bar/defaults/main.yml"), cwd=cwd, env=env, ) assert result.returncode == RC.VIOLATIONS_FOUND assert ( "Variables names from within roles should use bar_ as a prefix" in result.stdout ) assert ( "Variables names from within roles should use bar_ as a prefix" in result.stdout ) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_config.py����������������������������������������������������0000664�0000000�0000000�00000001367�14773473560�0021724�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for config module.""" from ansiblelint.config import PROFILES from ansiblelint.rules import RulesCollection def test_profiles(default_rules_collection: RulesCollection) -> None: """Test the rules included in profiles are valid.""" profile_banned_tags = {"opt-in", "experimental"} for name, data in PROFILES.items(): for profile_rule_id in data["rules"]: for rule in default_rules_collection.rules: if profile_rule_id == rule.id: forbidden_tags = profile_banned_tags & set(rule.tags) assert ( not forbidden_tags ), f"Rule {profile_rule_id} from {name} profile cannot use {profile_banned_tags & set(rule.tags)} tag." �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_constants.py�������������������������������������������������0000664�0000000�0000000�00000000453�14773473560�0022466�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for constants module.""" from ansiblelint.constants import States def test_states() -> None: """Test that states are evaluated as boolean false.""" assert bool(States.NOT_LOADED) is False assert bool(States.LOAD_FAILED) is False assert bool(States.UNKNOWN_DATA) is False ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_dependencies_in_meta.py��������������������������������������0000664�0000000�0000000�00000000712�14773473560�0024572�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests about dependencies in meta.""" from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner def test_external_dependency_is_ok(default_rules_collection: RulesCollection) -> None: """Check that external dep in role meta is not a violation.""" playbook_path = "examples/roles/dependency_in_meta/meta/main.yml" good_runner = Runner(playbook_path, rules=default_rules_collection) assert good_runner.run() == [] ������������������������������������������������������ansible-ansible-lint-c16f018/test/test_errors.py����������������������������������������������������0000664�0000000�0000000�00000001021�14773473560�0021756�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test ansiblelint.errors.""" import pytest from ansiblelint.errors import MatchError def test_matcherror() -> None: """.""" match = MatchError("foo", lineno=1, column=2) with pytest.raises(TypeError): assert match <= 0 assert match != 0 assert match.position == "1:2" match2 = MatchError("foo", lineno=1) assert match2.position == "1" # str and repr are for the moment the same assert str(match) == repr(match) # tests implicit level assert match.level == "warning" ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_examples.py��������������������������������������������������0000664�0000000�0000000�00000007434�14773473560�0022276�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Assure samples produced desire outcomes.""" import pytest from ansiblelint.app import get_app from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner from ansiblelint.testing import run_ansible_lint def test_example(default_rules_collection: RulesCollection) -> None: """example.yml is expected to have exact number of errors inside.""" result = Runner( "examples/playbooks/example.yml", rules=default_rules_collection, ).run() assert len(result) == 22 @pytest.mark.parametrize( ("filename", "expected_results"), ( pytest.param( "examples/playbooks/syntax-error-string.yml", [("syntax-check[unknown-module]", 6, 7)], id="0", ), pytest.param( "examples/playbooks/syntax-error.yml", [("syntax-check[specific]", 2, 3)], id="1", ), ), ) def test_example_syntax_error( default_rules_collection: RulesCollection, filename: str, expected_results: list[tuple[str, int | None, int | None]], ) -> None: """Validates that loading valid YAML string produce error.""" result = Runner(filename, rules=default_rules_collection).run() assert len(result) == len(expected_results) for i, expected in enumerate(expected_results): if expected[0] is not None: assert result[i].tag == expected[0] # This also ensures that line and column numbers start at 1, so they # match what editors will show (or output from other linters) if expected[1] is not None: assert result[i].lineno == expected[1] if expected[2] is not None: assert result[i].column == expected[2] def test_example_custom_module(default_rules_collection: RulesCollection) -> None: """custom_module.yml is expected to pass.""" app = get_app(offline=True) result = Runner( "examples/playbooks/custom_module.yml", rules=default_rules_collection, ).run() assert len(result) == 0, f"{app.runtime.cache_dir}" def test_vault_full(default_rules_collection: RulesCollection) -> None: """Check ability to process fully vaulted files.""" result = Runner( "examples/playbooks/vars/vault_full.yml", rules=default_rules_collection, ).run() assert len(result) == 0 def test_vault_partial( default_rules_collection: RulesCollection, caplog: pytest.LogCaptureFixture, ) -> None: """Check ability to process files that container !vault inside.""" result = Runner( "examples/playbooks/vars/vault_partial.yml", rules=default_rules_collection, ).run() assert len(result) == 0 # Ensure that we do not have side-effect extra logging even if the vault # content cannot be decrypted. assert caplog.record_tuples == [] def test_custom_kinds() -> None: """Check if user defined kinds are used.""" result = run_ansible_lint("-vv", "--offline", "examples/other/") assert result.returncode == 0 # .yaml-too is not a recognized extension and unless is manually defined # in our ansible-lint config, the test would not identify it as yaml file. assert "Examining examples/other/some.yaml-too of type yaml" in result.stderr assert "Examining examples/other/some.j2.yaml of type jinja2" in result.stderr def test_bug_3216(capsys: pytest.CaptureFixture[str]) -> None: """Check that we hide ansible-core originating warning about fallback on unique filter.""" result = run_ansible_lint( "-vv", "--offline", "examples/playbooks/bug-core-warning-unique-filter-fallback.yml", ) captured = capsys.readouterr() assert result.returncode == 0 warn_msg = "Falling back to Ansible unique filter" assert warn_msg not in captured.err assert warn_msg not in captured.out ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_file_path_evaluation.py��������������������������������������0000664�0000000�0000000�00000007152�14773473560�0024637�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Testing file path evaluation when using import_tasks / include_tasks.""" from __future__ import annotations import textwrap from typing import TYPE_CHECKING import pytest from ansiblelint.runner import Runner if TYPE_CHECKING: from pathlib import Path from ansiblelint.rules import RulesCollection LAYOUT_IMPORTS: dict[str, str] = { "main.yml": textwrap.dedent( """\ --- - name: Fixture hosts: target gather_facts: false tasks: - name: From main import task 1 ansible.builtin.import_tasks: tasks/task_1.yml """, ), "tasks/task_1.yml": textwrap.dedent( """\ --- - name: task_1 | From task 1 import task 2 ansible.builtin.import_tasks: tasks/task_2.yml """, ), "tasks/task_2.yml": textwrap.dedent( """\ --- - name: task_2 | From task 2 import subtask 1 ansible.builtin.import_tasks: tasks/subtasks/subtask_1.yml """, ), "tasks/subtasks/subtask_1.yml": textwrap.dedent( """\ --- - name: subtasks | subtask_1 | From subtask 1 import subtask 2 ansible.builtin.import_tasks: tasks/subtasks/subtask_2.yml """, ), "tasks/subtasks/subtask_2.yml": textwrap.dedent( """\ --- - name: subtasks | subtask_2 | From subtask 2 do something debug: # <-- expected to raise fqcn[action-core] msg: | Something... """, ), } LAYOUT_INCLUDES: dict[str, str] = { "main.yml": textwrap.dedent( """\ --- - name: Fixture hosts: target gather_facts: false tasks: - name: From main import task 1 ansible.builtin.include_tasks: tasks/task_1.yml """, ), "tasks/task_1.yml": textwrap.dedent( """\ --- - name: task_1 | From task 1 import task 2 ansible.builtin.include_tasks: tasks/task_2.yml """, ), "tasks/task_2.yml": textwrap.dedent( """\ --- - name: task_2 | From task 2 import subtask 1 ansible.builtin.include_tasks: tasks/subtasks/subtask_1.yml """, ), "tasks/subtasks/subtask_1.yml": textwrap.dedent( """\ --- - name: subtasks | subtask_1 | From subtask 1 import subtask 2 ansible.builtin.include_tasks: tasks/subtasks/subtask_2.yml """, ), "tasks/subtasks/subtask_2.yml": textwrap.dedent( """\ --- - name: subtasks | subtask_2 | From subtask 2 do something debug: # <-- expected to raise fqcn[action-core] msg: | Something... """, ), } @pytest.mark.parametrize( "ansible_project_layout", ( pytest.param(LAYOUT_IMPORTS, id="using-only-import_tasks"), pytest.param(LAYOUT_INCLUDES, id="using-only-include_tasks"), ), ) def test_file_path_evaluation( tmp_path: Path, default_rules_collection: RulesCollection, ansible_project_layout: dict[str, str], ) -> None: """Test file path evaluation when using import_tasks / include_tasks in the project. The goal of this test is to verify our ability to find errors from within nested includes. """ for file_path, file_content in ansible_project_layout.items(): full_path = tmp_path / file_path full_path.parent.mkdir(parents=True, exist_ok=True) full_path.write_text(file_content) result = Runner(str(tmp_path), rules=default_rules_collection).run() assert len(result) == 1 assert result[0].rule.id == "fqcn" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_file_utils.py������������������������������������������������0000664�0000000�0000000�00000041414�14773473560�0022613�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for file utility functions.""" from __future__ import annotations import copy import logging import os import time from pathlib import Path from typing import TYPE_CHECKING, Any import pytest from ansiblelint import cli, file_utils from ansiblelint.file_utils import ( Lintable, cwd, expand_path_vars, expand_paths_vars, find_project_root, normpath, normpath_path, ) from ansiblelint.runner import Runner if TYPE_CHECKING: from _pytest.capture import CaptureFixture from _pytest.logging import LogCaptureFixture from _pytest.monkeypatch import MonkeyPatch from ansiblelint.constants import FileType from ansiblelint.rules import RulesCollection @pytest.mark.parametrize( ("path", "expected"), ( pytest.param(Path("a/b/../"), "a", id="pathlib.Path"), pytest.param("a/b/../", "a", id="str"), pytest.param("", ".", id="empty"), pytest.param(".", ".", id="empty"), ), ) def test_normpath(path: str, expected: str) -> None: """Ensure that relative parent dirs are normalized in paths.""" assert normpath(path) == expected def test_expand_path_vars(monkeypatch: MonkeyPatch) -> None: """Ensure that tilde and env vars are expanded in paths.""" test_path = "/test/path" monkeypatch.setenv("TEST_PATH", test_path) assert expand_path_vars("~") == os.path.expanduser("~") # noqa: PTH111 assert expand_path_vars("$TEST_PATH") == test_path @pytest.mark.parametrize( ("test_path", "expected"), ( pytest.param(Path("$TEST_PATH"), "/test/path", id="pathlib.Path"), pytest.param("$TEST_PATH", "/test/path", id="str"), pytest.param(" $TEST_PATH ", "/test/path", id="stripped-str"), pytest.param("~", os.path.expanduser("~"), id="home"), # noqa: PTH111 ), ) def test_expand_paths_vars( test_path: str | Path, expected: str, monkeypatch: MonkeyPatch, ) -> None: """Ensure that tilde and env vars are expanded in paths lists.""" monkeypatch.setenv("TEST_PATH", "/test/path") assert expand_paths_vars([test_path]) == [expected] # type: ignore[list-item] def test_discover_lintables_silent( monkeypatch: MonkeyPatch, capsys: CaptureFixture[str], caplog: LogCaptureFixture, ) -> None: """Verify that no stderr output is displayed while discovering yaml files. (when the verbosity is off, regardless of the Git or Git-repo presence) Also checks expected number of files are detected. """ caplog.set_level(logging.FATAL) options = cli.get_config([]) test_dir = Path(__file__).resolve().parent lint_path = (test_dir / ".." / "examples" / "roles" / "test-role").resolve() yaml_count = len(list(lint_path.glob("**/*.yml"))) + len( list(lint_path.glob("**/*.yaml")), ) monkeypatch.chdir(str(lint_path)) my_options = copy.deepcopy(options) my_options.lintables = [str(lint_path)] files = file_utils.discover_lintables(my_options) stderr = capsys.readouterr().err assert ( not stderr ), f"No stderr output is expected when the verbosity is off, got: {stderr}" assert ( len(files) == yaml_count ), "Expected to find {yaml_count} yaml files in {lint_path}".format_map( locals(), ) def test_discover_lintables_umlaut(monkeypatch: MonkeyPatch) -> None: """Verify that filenames containing German umlauts are not garbled by the discover_lintables.""" options = cli.get_config([]) test_dir = Path(__file__).resolve().parent lint_path = (test_dir / ".." / "examples" / "playbooks").resolve() monkeypatch.chdir(str(lint_path)) files = file_utils.discover_lintables(options) assert '"with-umlaut-\\303\\244.yml"' not in files assert "with-umlaut-ä.yml" in files @pytest.mark.parametrize( ("path", "kind"), ( pytest.param("tasks/run_test_playbook.yml", "tasks", id="0"), pytest.param("foo/playbook.yml", "playbook", id="1"), pytest.param("playbooks/foo.yml", "playbook", id="2"), pytest.param("examples/roles/foo.yml", "yaml", id="3"), # the only yml file that is not a playbook inside molecule/ folders pytest.param( "examples/.config/molecule/config.yml", "yaml", id="4", ), # molecule shared config pytest.param( "test/schemas/test/molecule/cluster/base.yml", "yaml", id="5", ), # molecule scenario base config pytest.param( "test/schemas/test/molecule/cluster/molecule.yml", "yaml", id="6", ), # molecule scenario config pytest.param( "test/schemas/test/molecule/cluster/foobar.yml", "playbook", id="7", ), # custom playbook name pytest.param( "test/schemas/test/molecule/cluster/converge.yml", "playbook", id="8", ), # common playbook name pytest.param( "roles/foo/molecule/scenario3/requirements.yml", "requirements", id="9", ), # requirements pytest.param( "roles/foo/molecule/scenario3/collections.yml", "requirements", id="10", ), # requirements pytest.param( "roles/foo/meta/argument_specs.yml", "role-arg-spec", id="11", ), # role argument specs # tasks files: pytest.param("tasks/directory with spaces/main.yml", "tasks", id="12"), # tasks pytest.param("tasks/requirements.yml", "tasks", id="13"), # tasks # requirements (we do not support includes yet) pytest.param( "requirements.yml", "requirements", id="14", ), # collection requirements pytest.param( "roles/foo/meta/requirements.yml", "requirements", id="15", ), # inside role requirements # Undeterminable files: pytest.param("test/fixtures/unknown-type.yml", "yaml", id="16"), pytest.param( "releasenotes/notes/run-playbooks-refactor.yaml", "reno", id="17", ), # reno pytest.param("examples/host_vars/localhost.yml", "vars", id="18"), pytest.param("examples/group_vars/all.yml", "vars", id="19"), pytest.param("examples/playbooks/vars/other.yml", "vars", id="20"), pytest.param( "examples/playbooks/vars/subfolder/settings.yml", "vars", id="21", ), # deep vars pytest.param( "molecule/scenario/collections.yml", "requirements", id="22", ), # deprecated 2.8 format pytest.param( "../roles/geerlingguy.mysql/tasks/configure.yml", "tasks", id="23", ), # relative path involved pytest.param("galaxy.yml", "galaxy", id="24"), pytest.param("foo.j2.yml", "jinja2", id="25"), pytest.param("foo.yml.j2", "jinja2", id="26"), pytest.param("foo.j2.yaml", "jinja2", id="27"), pytest.param("foo.yaml.j2", "jinja2", id="28"), pytest.param( "examples/playbooks/rulebook.yml", "playbook", id="29", ), # playbooks folder should determine kind pytest.param( "examples/rulebooks/rulebook-pass.yml", "rulebook", id="30", ), # content should determine it as a rulebook pytest.param( "examples/yamllint/valid.yml", "yaml", id="31", ), # empty yaml is valid yaml, not assuming anything else pytest.param( "examples/other/guess-1.yml", "playbook", id="32", ), # content should determine is as a play pytest.param( "examples/playbooks/tasks/passing_task.yml", "tasks", id="33", ), # content should determine is tasks pytest.param("examples/.collection/galaxy.yml", "galaxy", id="34"), pytest.param("examples/meta/runtime.yml", "meta-runtime", id="35"), pytest.param("examples/meta/changelogs/changelog.yaml", "changelog", id="36"), pytest.param("examples/inventory/inventory.yml", "inventory", id="37"), pytest.param("examples/inventory/production.yml", "inventory", id="38"), pytest.param("examples/playbooks/vars/empty_vars.yml", "vars", id="39"), pytest.param( "examples/playbooks/vars/subfolder/settings.yaml", "vars", id="40", ), pytest.param( "examples/sanity_ignores/tests/sanity/ignore-2.14.txt", "sanity-ignore-file", id="41", ), pytest.param("examples/playbooks/tasks/vars/bug-3289.yml", "vars", id="42"), pytest.param( "examples/site.yml", "playbook", id="43", ), # content should determine it as a play pytest.param( "plugins/modules/fake_module.py", "plugin", id="44", ), pytest.param("examples/meta/changelogs/changelog.yml", "changelog", id="45"), ), ) def test_kinds(path: str, kind: FileType) -> None: """Verify auto-detection logic based on DEFAULT_KINDS.""" # assert Lintable is able to determine file type lintable_detected = Lintable(path) lintable_expected = Lintable(path, kind=kind) assert lintable_detected == lintable_expected def test_find_project_root_1(tmp_path: Path) -> None: """Verify find_project_root().""" # this matches black behavior in absence of any config files or .git/.hg folders. with cwd(tmp_path): path, method = find_project_root([]) assert str(path) == "/" assert method == "file system root" def test_find_project_root_dotconfig() -> None: """Verify find_project_root().""" # this expects to return examples folder as project root because this # folder already has an .config/ansible-lint.yml file inside, which should # be enough. with cwd(Path("examples")): assert Path( ".config/ansible-lint.yml", ).exists(), "Test requires config file inside .config folder." path, method = find_project_root([]) assert str(path) == str(Path.cwd()) assert ".config/ansible-lint.yml" in method BASIC_PLAYBOOK = """ - name: "playbook" tasks: - name: Hello debug: msg: 'world' """ @pytest.fixture(name="tmp_updated_lintable") def fixture_tmp_updated_lintable( tmp_path: Path, path: str, content: str, updated_content: str, ) -> Lintable: """Create a temp file Lintable with a content update that is not on disk.""" lintable = Lintable(tmp_path / path, content) with lintable.path.open("w", encoding="utf-8") as f: f.write(content) # move mtime to a time in the past to avoid race conditions in the test mtime = time.time() - 60 * 60 # 1hr ago os.utime(str(lintable.path), (mtime, mtime)) lintable.content = updated_content return lintable @pytest.mark.parametrize( ("path", "content", "updated_content", "updated"), ( pytest.param( "no_change.yaml", BASIC_PLAYBOOK, BASIC_PLAYBOOK, False, id="no_change", ), pytest.param( "quotes.yaml", BASIC_PLAYBOOK, BASIC_PLAYBOOK.replace('"', "'"), True, id="updated_quotes", ), pytest.param( "shorten.yaml", BASIC_PLAYBOOK, "# short file\n", True, id="shorten_file", ), ), ) def test_lintable_updated( path: str, content: str, updated_content: str, updated: bool, ) -> None: """Validate ``Lintable.updated`` when setting ``Lintable.content``.""" lintable = Lintable(path, content) assert lintable.content == content lintable.content = updated_content assert lintable.content == updated_content assert lintable.updated is updated @pytest.mark.parametrize( "updated_content", ((None,), (b"bytes",)), ids=("none", "bytes"), ) def test_lintable_content_setter_with_bad_types(updated_content: Any) -> None: """Validate ``Lintable.updated`` when setting ``Lintable.content``.""" lintable = Lintable("bad_type.yaml", BASIC_PLAYBOOK) assert lintable.content == BASIC_PLAYBOOK with pytest.raises(TypeError): lintable.content = updated_content assert not lintable.updated def test_lintable_with_new_file(tmp_path: Path) -> None: """Validate ``Lintable.updated`` for a new file.""" lintable = Lintable(tmp_path / "new.yaml") lintable.content = BASIC_PLAYBOOK lintable.content = BASIC_PLAYBOOK assert lintable.content == BASIC_PLAYBOOK assert lintable.updated assert not lintable.path.exists() lintable.write() assert lintable.path.exists() assert lintable.path.read_text(encoding="utf-8") == BASIC_PLAYBOOK @pytest.mark.parametrize( ("path", "force", "content", "updated_content", "updated"), ( pytest.param( "no_change.yaml", False, BASIC_PLAYBOOK, BASIC_PLAYBOOK, False, id="no_change", ), pytest.param( "forced.yaml", True, BASIC_PLAYBOOK, BASIC_PLAYBOOK, False, id="forced_rewrite", ), pytest.param( "quotes.yaml", False, BASIC_PLAYBOOK, BASIC_PLAYBOOK.replace('"', "'"), True, id="updated_quotes", ), pytest.param( "shorten.yaml", False, BASIC_PLAYBOOK, "# short file\n", True, id="shorten_file", ), pytest.param( "forced.yaml", True, BASIC_PLAYBOOK, BASIC_PLAYBOOK.replace('"', "'"), True, id="forced_and_updated", ), ), ) def test_lintable_write( tmp_updated_lintable: Lintable, force: bool, content: str, updated_content: str, updated: bool, ) -> None: """Validate ``Lintable.write`` writes when it should.""" pre_updated = tmp_updated_lintable.updated pre_stat = tmp_updated_lintable.path.stat() tmp_updated_lintable.write(force=force) post_stat = tmp_updated_lintable.path.stat() post_updated = tmp_updated_lintable.updated # write() should not hide that an update happened assert pre_updated == post_updated == updated if force or updated: assert pre_stat.st_mtime < post_stat.st_mtime else: assert pre_stat.st_mtime == post_stat.st_mtime with tmp_updated_lintable.path.open("r", encoding="utf-8") as f: post_content = f.read() if updated: assert content != post_content else: assert content == post_content assert post_content == updated_content @pytest.mark.parametrize( ("path", "content", "updated_content"), ( pytest.param( "quotes.yaml", BASIC_PLAYBOOK, BASIC_PLAYBOOK.replace('"', "'"), id="updated_quotes", ), ), ) def test_lintable_content_deleter( tmp_updated_lintable: Lintable, content: str, updated_content: str, ) -> None: """Ensure that resetting content cache triggers re-reading file.""" assert content != updated_content assert tmp_updated_lintable.content == updated_content del tmp_updated_lintable.content assert tmp_updated_lintable.content == content @pytest.mark.parametrize( ("path", "result"), ( pytest.param("foo", "foo", id="rel"), pytest.param( os.path.expanduser("~/xxx"), # noqa: PTH111 "~/xxx", id="rel-to-home", ), pytest.param("/a/b/c", "/a/b/c", id="absolute"), pytest.param( "examples/playbooks/roles", "examples/roles", id="resolve-symlink", ), ), ) def test_normpath_path(path: str, result: str) -> None: """Tests behavior of normpath.""" assert normpath_path(path) == Path(result) def test_bug_2513( tmp_path: Path, default_rules_collection: RulesCollection, ) -> None: """Regression test for bug 2513. Test that when CWD is outside ~, and argument is like ~/playbook.yml we will still be able to process the files. See: https://github.com/ansible/ansible-lint/issues/2513 """ filename = Path("~/.cache/ansible-lint/playbook.yml").expanduser() filename.parent.mkdir(parents=True, exist_ok=True) lintable = Lintable(filename, content="---\n- hosts: all\n") lintable.write(force=True) with cwd(tmp_path): results = Runner(filename, rules=default_rules_collection).run() assert len(results) == 1 assert results[0].rule.id == "name" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_formatter.py�������������������������������������������������0000664�0000000�0000000�00000005022�14773473560�0022452�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test for output formatter.""" # Copyright (c) 2016 Will Thames <will@thames.id.au> # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import pathlib from ansiblelint.app import get_app from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.formatters import Formatter from ansiblelint.rules import AnsibleLintRule, RulesCollection collection = RulesCollection(app=get_app(offline=True)) rule = AnsibleLintRule() rule.id = "TCF0001" collection.register(rule) formatter = Formatter(pathlib.Path.cwd(), display_relative_path=True) # These details would generate a rich rendering error if not escaped: DETAILS = "Some [/tmp/foo] details." def test_format_coloured_string() -> None: """Test formetting colored.""" match = MatchError( message="message", lineno=1, details=DETAILS, lintable=Lintable("filename.yml", content=""), rule=rule, ) formatter.apply(match) def test_unicode_format_string() -> None: """Test formatting unicode.""" match = MatchError( message="\U0001f427", lineno=1, details=DETAILS, lintable=Lintable("filename.yml", content=""), rule=rule, ) formatter.apply(match) def test_dict_format_line() -> None: """Test formatting dictionary details.""" match = MatchError( message="xyz", lineno=1, details={"hello": "world"}, # type: ignore[arg-type] lintable=Lintable("filename.yml", content=""), rule=rule, ) formatter.apply(match) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_formatter_base.py��������������������������������������������0000664�0000000�0000000�00000003770�14773473560�0023454�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests related to base formatter.""" from __future__ import annotations from pathlib import Path from typing import Any import pytest from ansiblelint.formatters import BaseFormatter @pytest.mark.parametrize( ("base_dir", "relative_path"), ( pytest.param(None, True, id="0"), pytest.param("/whatever", False, id="1"), pytest.param(Path("/whatever"), False, id="2"), ), ) @pytest.mark.parametrize( "path", ( pytest.param("/whatever/string", id="a"), pytest.param(Path("/whatever/string"), id="b"), ), ) def test_base_formatter_when_base_dir( base_dir: Any, relative_path: bool, path: str, ) -> None: """Check that base formatter accepts relative pathlib and str.""" # Given base_formatter = BaseFormatter(base_dir, relative_path) # type: ignore[var-annotated] # When output_path = base_formatter._format_path( # noqa: SLF001 path, ) # Then assert isinstance(output_path, str | Path) assert base_formatter.base_dir is None or isinstance( base_formatter.base_dir, str | Path, ) assert output_path == path @pytest.mark.parametrize( "base_dir", ( pytest.param(Path("/whatever"), id="0"), pytest.param("/whatever", id="1"), ), ) @pytest.mark.parametrize( "path", ( pytest.param("/whatever/string", id="a"), pytest.param(Path("/whatever/string"), id="b"), ), ) def test_base_formatter_when_base_dir_is_given_and_relative_is_true( path: str | Path, base_dir: str | Path, ) -> None: """Check that the base formatter equally accepts pathlib and str.""" # Given base_formatter = BaseFormatter(base_dir, True) # type: ignore[var-annotated] # When output_path = base_formatter._format_path(path) # noqa: SLF001 # Then assert isinstance(output_path, str | Path) assert isinstance(base_formatter.base_dir, str | Path) assert output_path == Path(path).name # vim: et:sw=4:syntax=python:ts=4: ��������ansible-ansible-lint-c16f018/test/test_formatter_json.py��������������������������������������������0000664�0000000�0000000�00000012530�14773473560�0023505�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test the codeclimate JSON formatter.""" from __future__ import annotations import json import pathlib import subprocess import sys import pytest from ansiblelint.app import get_app from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.formatters import CodeclimateJSONFormatter from ansiblelint.rules import AnsibleLintRule, RulesCollection class TestCodeclimateJSONFormatter: """Unit test for CodeclimateJSONFormatter.""" rule = AnsibleLintRule() matches: list[MatchError] = [] formatter: CodeclimateJSONFormatter | None = None collection = RulesCollection(app=get_app(offline=True)) def setup_class(self) -> None: """Set up few MatchError objects.""" self.rule = AnsibleLintRule() self.rule.id = "TCF0001" self.rule.severity = "VERY_HIGH" self.collection.register(self.rule) self.matches = [] self.matches.append( MatchError( message="message", lineno=1, details="hello", lintable=Lintable("filename.yml", content=""), rule=self.rule, ), ) self.matches.append( MatchError( message="message", lineno=2, details="hello", lintable=Lintable("filename.yml", content=""), rule=self.rule, ignored=True, ), ) self.formatter = CodeclimateJSONFormatter( pathlib.Path.cwd(), display_relative_path=True, ) def test_json_format_list(self) -> None: """Test if the return value is a string.""" assert isinstance(self.formatter, CodeclimateJSONFormatter) assert isinstance(self.formatter.format_result(self.matches), str) def test_result_is_json(self) -> None: """Test if returned string value is a JSON.""" assert isinstance(self.formatter, CodeclimateJSONFormatter) output = self.formatter.format_result(self.matches) json.loads(output) # https://github.com/ansible/ansible-navigator/issues/1490 assert "\n" not in output def test_json_single_match(self) -> None: """Test negative case. Only lists are allowed. Otherwise a RuntimeError will be raised.""" assert isinstance(self.formatter, CodeclimateJSONFormatter) with pytest.raises(TypeError): self.formatter.format_result(self.matches[0]) # type: ignore[arg-type] def test_result_is_list(self) -> None: """Test if the return JSON contains a list with a length of 2.""" assert isinstance(self.formatter, CodeclimateJSONFormatter) result = json.loads(self.formatter.format_result(self.matches)) assert len(result) == 2 def test_validate_codeclimate_schema(self) -> None: """Test if the returned JSON is a valid codeclimate report.""" assert isinstance(self.formatter, CodeclimateJSONFormatter) result = json.loads(self.formatter.format_result(self.matches)) single_match = result[0] assert "type" in single_match assert single_match["type"] == "issue" assert "check_name" in single_match assert "categories" in single_match assert isinstance(single_match["categories"], list) assert "severity" in single_match assert single_match["severity"] == "major" assert "description" in single_match assert "fingerprint" in single_match assert "location" in single_match assert "path" in single_match["location"] assert single_match["location"]["path"] == self.matches[0].filename assert "lines" in single_match["location"] assert single_match["location"]["lines"]["begin"] == self.matches[0].lineno assert "positions" not in single_match["location"] # check that the 2nd match is marked as 'minor' because it was created with ignored=True assert result[1]["severity"] == "minor" def test_validate_codeclimate_schema_with_positions(self) -> None: """Test if the returned JSON is a valid codeclimate report (containing 'positions' instead of 'lines').""" assert isinstance(self.formatter, CodeclimateJSONFormatter) result = json.loads( self.formatter.format_result( [ MatchError( message="message", lineno=1, column=42, details="hello", lintable=Lintable("filename.yml", content=""), rule=self.rule, ), ], ), ) assert result[0]["location"]["positions"]["begin"]["line"] == 1 assert result[0]["location"]["positions"]["begin"]["column"] == 42 assert "lines" not in result[0]["location"] def test_code_climate_parsable_ignored() -> None: """Test that -p option does not alter codeclimate format.""" cmd = [ sys.executable, "-m", "ansiblelint", "-v", "-p", ] file = "examples/playbooks/empty_playbook.yml" result = subprocess.run([*cmd, file], check=False) result2 = subprocess.run([*cmd, "-p", file], check=False) assert result.returncode == result2.returncode assert result.stdout == result2.stdout ������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_formatter_sarif.py�������������������������������������������0000664�0000000�0000000�00000020760�14773473560�0023644�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test the codeclimate JSON formatter.""" from __future__ import annotations import json import os import pathlib import subprocess import sys from tempfile import NamedTemporaryFile import pytest from ansiblelint.app import get_app from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.formatters import SarifFormatter from ansiblelint.rules import AnsibleLintRule, RulesCollection class TestSarifFormatter: """Unit test for SarifFormatter.""" rule1 = AnsibleLintRule() rule2 = AnsibleLintRule() matches: list[MatchError] = [] formatter: SarifFormatter | None = None collection = RulesCollection(app=get_app(offline=True)) collection.register(rule1) collection.register(rule2) def setup_class(self) -> None: """Set up few MatchError objects.""" self.rule1.id = "TCF0001" self.rule1.severity = "VERY_HIGH" self.rule1.description = "This is the rule description." self.rule1.link = "https://rules/help#TCF0001" self.rule1.tags = ["tag1", "tag2"] self.rule2.id = "TCF0002" self.rule2.severity = "MEDIUM" self.rule2.link = "https://rules/help#TCF0002" self.rule2.tags = ["tag3", "tag4"] self.matches.extend( [ MatchError( message="message1", lineno=1, column=10, details="details1", lintable=Lintable("filename1.yml", content=""), rule=self.rule1, tag="yaml[test1]", ignored=False, ), MatchError( message="message2", lineno=2, details="", lintable=Lintable("filename2.yml", content=""), rule=self.rule1, tag="yaml[test2]", ignored=True, ), MatchError( message="message3", lineno=666, column=667, details="details3", lintable=Lintable("filename3.yml", content=""), rule=self.rule2, tag="yaml[test3]", ignored=False, ), ], ) self.formatter = SarifFormatter(pathlib.Path.cwd(), display_relative_path=True) def test_sarif_format_list(self) -> None: """Test if the return value is a string.""" assert isinstance(self.formatter, SarifFormatter) assert isinstance(self.formatter.format_result(self.matches), str) def test_sarif_result_is_json(self) -> None: """Test if returned string value is a JSON.""" assert isinstance(self.formatter, SarifFormatter) output = self.formatter.format_result(self.matches) json.loads(output) # https://github.com/ansible/ansible-navigator/issues/1490 assert "\n" not in output def test_sarif_single_match(self) -> None: """Test negative case. Only lists are allowed. Otherwise, a RuntimeError will be raised.""" assert isinstance(self.formatter, SarifFormatter) with pytest.raises(TypeError): self.formatter.format_result(self.matches[0]) # type: ignore[arg-type] def test_sarif_format(self) -> None: """Test if the return SARIF object contains the expected results.""" assert isinstance(self.formatter, SarifFormatter) sarif = json.loads(self.formatter.format_result(self.matches)) assert len(sarif["runs"][0]["results"]) == 3 for result in sarif["runs"][0]["results"]: # Ensure all reported entries have a level assert "level" in result # Ensure reported levels are either error or warning assert result["level"] in ("error", "warning") def test_validate_sarif_schema(self) -> None: """Test if the returned JSON is a valid SARIF report.""" assert isinstance(self.formatter, SarifFormatter) sarif = json.loads(self.formatter.format_result(self.matches)) assert sarif["$schema"] == SarifFormatter.SARIF_SCHEMA assert sarif["version"] == SarifFormatter.SARIF_SCHEMA_VERSION driver = sarif["runs"][0]["tool"]["driver"] assert driver["name"] == SarifFormatter.TOOL_NAME assert driver["informationUri"] == SarifFormatter.TOOL_URL rules = driver["rules"] assert len(rules) == 3 assert rules[0]["id"] == self.matches[0].tag assert rules[0]["name"] == self.matches[0].tag assert rules[0]["shortDescription"]["text"] == self.matches[0].message assert rules[0]["defaultConfiguration"][ "level" ] == SarifFormatter.get_sarif_rule_severity_level(self.matches[0].rule) assert rules[0]["help"]["text"] == self.matches[0].rule.description assert rules[0]["properties"]["tags"] == self.matches[0].rule.tags assert rules[0]["helpUri"] == self.matches[0].rule.url results = sarif["runs"][0]["results"] assert len(results) == 3 for i, result in enumerate(results): assert result["ruleId"] == self.matches[i].tag assert ( result["locations"][0]["physicalLocation"]["artifactLocation"]["uri"] == self.matches[i].filename ) assert ( result["locations"][0]["physicalLocation"]["artifactLocation"][ "uriBaseId" ] == SarifFormatter.BASE_URI_ID ) assert ( result["locations"][0]["physicalLocation"]["region"]["startLine"] == self.matches[i].lineno ) if self.matches[i].column: assert ( result["locations"][0]["physicalLocation"]["region"]["startColumn"] == self.matches[i].column ) else: assert ( "startColumn" not in result["locations"][0]["physicalLocation"]["region"] ) assert result["level"] == SarifFormatter.get_sarif_result_severity_level( self.matches[i], ) assert sarif["runs"][0]["originalUriBaseIds"][SarifFormatter.BASE_URI_ID]["uri"] assert results[0]["message"]["text"] == self.matches[0].details assert results[1]["message"]["text"] == self.matches[1].message def test_sarif_parsable_ignored() -> None: """Test that -p option does not alter SARIF format.""" cmd = [ sys.executable, "-m", "ansiblelint", "-v", "-p", ] file = "examples/playbooks/empty_playbook.yml" result = subprocess.run([*cmd, file], check=False) result2 = subprocess.run([*cmd, "-p", file], check=False) assert result.returncode == result2.returncode assert result.stdout == result2.stdout @pytest.mark.parametrize( ("file", "return_code"), ( pytest.param("examples/playbooks/valid.yml", 0, id="0"), pytest.param("playbook.yml", 2, id="1"), ), ) def test_sarif_file(file: str, return_code: int) -> None: """Test ability to dump sarif file (--sarif-file).""" with NamedTemporaryFile( mode="w", suffix=".sarif", prefix="output", encoding="utf-8" ) as output_file: cmd = [ sys.executable, "-m", "ansiblelint", "--sarif-file", str(output_file.name), ] result = subprocess.run([*cmd, file], check=False, capture_output=True) assert result.returncode == return_code assert os.path.exists(output_file.name) # noqa: PTH110 assert pathlib.Path(output_file.name).stat().st_size > 0 @pytest.mark.parametrize( ("file", "return_code"), (pytest.param("examples/playbooks/valid.yml", 0, id="0"),), ) def test_sarif_file_creates_it_if_none_exists(file: str, return_code: int) -> None: """Test ability to create sarif file if none exists and dump output to it (--sarif-file).""" sarif_file_name = "test_output.sarif" cmd = [ sys.executable, "-m", "ansiblelint", "--sarif-file", sarif_file_name, ] result = subprocess.run([*cmd, file], check=False, capture_output=True) assert result.returncode == return_code assert os.path.exists(sarif_file_name) # noqa: PTH110 assert pathlib.Path(sarif_file_name).stat().st_size > 0 pathlib.Path.unlink(pathlib.Path(sarif_file_name)) ����������������ansible-ansible-lint-c16f018/test/test_import_include_role.py���������������������������������������0000664�0000000�0000000�00000007414�14773473560�0024514�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests related to role imports.""" from __future__ import annotations from typing import TYPE_CHECKING import pytest from ansiblelint.runner import Runner if TYPE_CHECKING: from pathlib import Path from _pytest.fixtures import SubRequest from ansiblelint.rules import RulesCollection ROLE_TASKS_MAIN = """\ --- - name: Shell instead of command shell: echo hello world # noqa: fqcn no-free-form changed_when: false """ ROLE_TASKS_WORLD = """\ --- - ansible.builtin.debug: msg: "this is a task without a name" """ PLAY_IMPORT_ROLE = """\ --- - name: Test fixture hosts: all tasks: - name: Some import # noqa: fqcn import_role: name: test-role """ PLAY_IMPORT_ROLE_FQCN = """\ --- - name: Test fixture hosts: all tasks: - name: Some import ansible.builtin.import_role: name: test-role """ PLAY_IMPORT_ROLE_INLINE = """\ --- - name: Fixture hosts: all tasks: - name: Some import import_role: name=test-role # noqa: no-free-form fqcn """ PLAY_INCLUDE_ROLE = """\ --- - name: Fixture hosts: all tasks: - name: Some import include_role: name: test-role tasks_from: world """ PLAY_INCLUDE_ROLE_FQCN = """\ --- - name: Fixture hosts: all tasks: - name: Some import ansible.builtin.include_role: name: test-role tasks_from: world """ PLAY_INCLUDE_ROLE_INLINE = """\ --- - name: Fixture hosts: all tasks: - name: Some import include_role: name=test-role tasks_from=world # noqa: no-free-form """ @pytest.fixture(name="playbook_path") def fixture_playbook_path(request: SubRequest, tmp_path: Path) -> str: """Create a reusable per-test role skeleton.""" playbook_text = request.param role_tasks_dir = tmp_path / "test-role" / "tasks" role_tasks_dir.mkdir(parents=True) (role_tasks_dir / "main.yml").write_text(ROLE_TASKS_MAIN) (role_tasks_dir / "world.yml").write_text(ROLE_TASKS_WORLD) play_path = tmp_path / "playbook.yml" play_path.write_text(playbook_text) return str(play_path) @pytest.mark.parametrize( ("playbook_path", "messages"), ( pytest.param( PLAY_IMPORT_ROLE, ["only when shell functionality is required", "All tasks should be named"], id="IMPORT_ROLE", ), pytest.param( PLAY_IMPORT_ROLE_FQCN, ["only when shell functionality is required", "All tasks should be named"], id="IMPORT_ROLE_FQCN", ), pytest.param( PLAY_IMPORT_ROLE_INLINE, ["only when shell functionality is require", "All tasks should be named"], id="IMPORT_ROLE_INLINE", ), pytest.param( PLAY_INCLUDE_ROLE, ["only when shell functionality is require", "All tasks should be named"], id="INCLUDE_ROLE", ), pytest.param( PLAY_INCLUDE_ROLE_FQCN, ["only when shell functionality is require", "All tasks should be named"], id="INCLUDE_ROLE_FQCN", ), pytest.param( PLAY_INCLUDE_ROLE_INLINE, ["only when shell functionality is require", "All tasks should be named"], id="INCLUDE_ROLE_INLINE", ), ), indirect=("playbook_path",), ) def test_import_role2( default_rules_collection: RulesCollection, playbook_path: str, messages: list[str], ) -> None: """Test that include_role digs deeper than import_role.""" runner = Runner( playbook_path, rules=default_rules_collection, skip_list=["fqcn[action-core]"], ) results = runner.run() for message in messages: assert message in str(results) # Ensure no other unexpected messages are present assert len(messages) == len(results), results ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_import_playbook.py�������������������������������������������0000664�0000000�0000000�00000003070�14773473560�0023662�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test ability to import playbooks.""" from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner def test_task_hook_import_playbook(default_rules_collection: RulesCollection) -> None: """Assures import_playbook includes are recognized.""" playbook_path = "examples/playbooks/playbook-parent.yml" runner = Runner(playbook_path, rules=default_rules_collection) results = runner.run() results_text = str(results) assert len(runner.lintables) == 2 assert len(results) == 2 # Assures we detected the issues from imported playbook assert "Commands should not change things" in results_text assert "[name]" in results_text assert "All tasks should be named" in results_text def test_import_playbook_from_collection( default_rules_collection: RulesCollection, ) -> None: """Assures import_playbook from collection.""" playbook_path = "examples/playbooks/test_import_playbook.yml" runner = Runner(playbook_path, rules=default_rules_collection) results = runner.run() assert len(runner.lintables) == 1 assert len(results) == 0 def test_import_playbook_invalid( default_rules_collection: RulesCollection, ) -> None: """Assures import_playbook from collection.""" playbook_path = "examples/playbooks/test_import_playbook_invalid.yml" runner = Runner(playbook_path, rules=default_rules_collection) results = runner.run() assert len(runner.lintables) == 1 assert len(results) == 1 assert results[0].tag == "syntax-check[specific]" assert results[0].lineno == 2 ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_import_tasks.py����������������������������������������������0000664�0000000�0000000�00000001775�14773473560�0023201�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test related to import of invalid files.""" import pytest from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner @pytest.mark.parametrize( ("playbook_path", "lintable_count", "match_count"), ( pytest.param( "examples/playbooks/test_import_with_conflicting_action_statements.yml", 2, 4, id="0", ), pytest.param("examples/playbooks/test_import_with_malformed.yml", 2, 1, id="1"), ), ) def test_import_tasks( default_rules_collection: RulesCollection, playbook_path: str, lintable_count: int, match_count: int, ) -> None: """Assures import_playbook includes are recognized.""" runner = Runner(playbook_path, rules=default_rules_collection) results = runner.run() assert len(runner.lintables) == lintable_count assert len(results) == match_count # Assures we detected the issues from imported file assert results[0].rule.id in ("syntax-check", "load-failure") ���ansible-ansible-lint-c16f018/test/test_include_miss_file_with_role.py�������������������������������0000664�0000000�0000000�00000002632�14773473560�0026204�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests related to inclusions.""" import pytest from _pytest.logging import LogCaptureFixture from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner def test_cases_warning_message(default_rules_collection: RulesCollection) -> None: """Test that including a non-existing file produces an error.""" playbook_path = "examples/playbooks/play_miss_include.yml" runner = Runner(playbook_path, rules=default_rules_collection) results = runner.run() assert len(runner.lintables) == 3 assert len(results) == 1 assert "No such file or directory" in results[0].message @pytest.mark.parametrize( "playbook_path", ( pytest.param("examples/playbooks/test_include_inplace.yml", id="inplace"), pytest.param("examples/playbooks/test_include_relative.yml", id="relative"), ), ) def test_cases_that_do_not_report( playbook_path: str, default_rules_collection: RulesCollection, caplog: LogCaptureFixture, ) -> None: """Test that relative inclusions are properly followed.""" runner = Runner(playbook_path, rules=default_rules_collection) result = runner.run() noexist_message_count = 0 for record in caplog.records: for msg in ("No such file or directory", "Couldn't open"): if msg in str(record): noexist_message_count += 1 assert noexist_message_count == 0 assert len(result) == 0 ������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_internal_rules.py��������������������������������������������0000664�0000000�0000000�00000001766�14773473560�0023510�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for internal rules.""" import pytest from ansiblelint._internal.rules import BaseRule from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner def test_base_rule_url() -> None: """Test that rule URL is set to expected value.""" rule = BaseRule() assert rule.url == "https://ansible.readthedocs.io/projects/lint/rules/" @pytest.mark.parametrize( ("path"), ( pytest.param( "examples/playbooks/incorrect_module_args.yml", id="playbook", ), ), ) def test_incorrect_module_args( path: str, default_rules_collection: RulesCollection, ) -> None: """Check that we fail when file encoding is wrong.""" runner = Runner(path, rules=default_rules_collection) matches = runner.run() assert len(matches) == 1, matches assert matches[0].rule.id == "load-failure" assert "Failed to find required 'name' key in include_role" in matches[0].message assert matches[0].tag == "internal-error" ����������ansible-ansible-lint-c16f018/test/test_lint_rule.py�������������������������������������������������0000664�0000000�0000000�00000003527�14773473560�0022454�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for lintable.""" # Copyright (c) 2013-2014 Will Thames <will@thames.id.au> # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import pytest from ansiblelint.file_utils import Lintable from .rules.fixtures import ematcher, raw_task @pytest.fixture(name="lintable") def fixture_lintable() -> Lintable: """Return a playbook Lintable for use in this file's tests.""" return Lintable("examples/playbooks/ematcher-rule.yml", kind="playbook") def test_rule_matching(lintable: Lintable) -> None: """Test rule.matchlines() on a playbook.""" rule = ematcher.EMatcherRule() matches = rule.matchlines(lintable) assert len(matches) == 3 def test_raw_rule_matching(lintable: Lintable) -> None: """Test rule.matchlines() on a playbook.""" rule = raw_task.RawTaskRule() matches = rule.matchtasks(lintable) assert len(matches) == 1 �������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_list_rules.py������������������������������������������������0000664�0000000�0000000�00000004777�14773473560�0022654�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests related to our logging/verbosity setup.""" from pathlib import Path import pytest from ansiblelint.testing import run_ansible_lint def test_list_rules_includes_opt_in_rules(project_path: Path) -> None: """Checks that listing rules also includes the opt-in rules.""" # Piggyback off the .yamllint in the root of the repo, just for testing. # We'll "override" it with the one in the fixture. fakerole = Path("test") / "fixtures" / "list-rules-tests" result_list_rules = run_ansible_lint("-L", fakerole, cwd=project_path) assert ("opt-in" in result_list_rules.stdout) is True def test_list_rules_includes_autofix() -> None: """Checks that listing rules also includes the autofix label for applicable rules.""" result_list_rules = run_ansible_lint("--list-rules") assert ("autofix" in result_list_rules.stdout) is True @pytest.mark.parametrize( ("result", "returncode", "format_string"), ( (False, 0, "brief"), (False, 0, "full"), (False, 0, "md"), (True, 2, "json"), (True, 2, "codeclimate"), (True, 2, "quiet"), (True, 2, "pep8"), (True, 2, "foo"), ), ids=( "plain", "full", "md", "json", "codeclimate", "quiet", "pep8", "foo", ), ) def test_list_rules_with_format_option( result: bool, returncode: int, format_string: str, project_path: Path, ) -> None: """Checks that listing rules with format options works.""" # Piggyback off the .yamllint in the root of the repo, just for testing. # We'll "override" it with the one in the fixture. fakerole = Path("test") / "fixtures" / "list-rules-tests" result_list_rules = run_ansible_lint( "-f", format_string, "-L", fakerole, cwd=project_path, ) assert (f"invalid choice: '{format_string}'" in result_list_rules.stderr) is result assert ("syntax-check" in result_list_rules.stdout) is not result assert result_list_rules.returncode is returncode def test_list_tags_includes_opt_in_rules(project_path: Path) -> None: """Checks that listing tags also includes the opt-in rules.""" # Piggyback off the .yamllint in the root of the repo, just for testing. # We'll "override" it with the one in the fixture. fakerole = Path("test") / "fixtures" / "list-rules-tests" result_list_tags = run_ansible_lint("-L", str(fakerole), cwd=project_path) assert ("opt-in" in result_list_tags.stdout) is True �ansible-ansible-lint-c16f018/test/test_load_failure.py����������������������������������������������0000664�0000000�0000000�00000001420�14773473560�0023073�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for LoadFailureRule.""" import pytest from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner @pytest.mark.parametrize( "path", ( pytest.param("examples/broken/encoding.j2", id="jinja2"), pytest.param("examples/broken/encoding.yml", id="yaml"), ), ) def test_load_failure_encoding( path: str, default_rules_collection: RulesCollection, ) -> None: """Check that we fail when file encoding is wrong.""" runner = Runner(path, rules=default_rules_collection) matches = runner.run() assert len(matches) == 1, matches assert matches[0].rule.id == "load-failure" assert "'utf-8' codec can't decode byte" in matches[0].message assert matches[0].tag == "load-failure[unicodedecodeerror]" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_loaders.py���������������������������������������������������0000664�0000000�0000000�00000007313�14773473560�0022105�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for loaders submodule.""" import os import tempfile import uuid from pathlib import Path from textwrap import dedent from ansiblelint.loaders import IGNORE_FILE, load_ignore_txt def test_load_ignore_txt_default_empty() -> None: """Test load_ignore_txt when no ignore-file is present.""" with tempfile.TemporaryDirectory() as temporary_directory: cwd = Path.cwd() try: os.chdir(temporary_directory) result = load_ignore_txt() finally: os.chdir(cwd) assert not result def test_load_ignore_txt_default_success() -> None: """Test load_ignore_txt with an existing ignore-file in the default location.""" with tempfile.TemporaryDirectory() as temporary_directory: ignore_file = Path(temporary_directory) / IGNORE_FILE.default with ignore_file.open("w", encoding="utf-8") as _ignore_file: _ignore_file.write( dedent( """ # See https://ansible.readthedocs.io/projects/lint/configuring/#ignoring-rules-for-entire-files playbook2.yml package-latest # comment playbook2.yml foo-bar """, ), ) cwd = Path.cwd() try: os.chdir(temporary_directory) result = load_ignore_txt() finally: os.chdir(cwd) assert result == {"playbook2.yml": {"package-latest", "foo-bar"}} def test_load_ignore_txt_default_success_alternative() -> None: """Test load_ignore_txt with an ignore-file in the alternative location ('.config' subdirectory).""" with tempfile.TemporaryDirectory() as temporary_directory: ignore_file = Path(temporary_directory) / IGNORE_FILE.alternative ignore_file.parent.mkdir(parents=True) with ignore_file.open("w", encoding="utf-8") as _ignore_file: _ignore_file.write( dedent( """ playbook.yml foo-bar playbook.yml more-foo # what-the-foo? tasks/main.yml more-bar """, ), ) cwd = Path.cwd() try: os.chdir(temporary_directory) result = load_ignore_txt() finally: os.chdir(cwd) assert result == { "playbook.yml": {"more-foo", "foo-bar"}, "tasks/main.yml": {"more-bar"}, } def test_load_ignore_txt_custom_success() -> None: """Test load_ignore_txt with an ignore-file in a user defined location.""" with tempfile.TemporaryDirectory() as temporary_directory: ignore_file = Path(temporary_directory) / "subdir" / "my_ignores.txt" ignore_file.parent.mkdir(parents=True, exist_ok=True) with ignore_file.open("w", encoding="utf-8") as _ignore_file: _ignore_file.write( dedent( """ playbook.yml hector vars/main.yml tuco roles/guzman/tasks/main.yml lalo roles/eduardo/tasks/main.yml lalo """, ), ) cwd = Path.cwd() try: os.chdir(temporary_directory) result = load_ignore_txt(Path(ignore_file)) finally: os.chdir(cwd) assert result == { "playbook.yml": {"hector"}, "roles/eduardo/tasks/main.yml": {"lalo"}, "roles/guzman/tasks/main.yml": {"lalo"}, "vars/main.yml": {"tuco"}, } def test_load_ignore_txt_custom_fail() -> None: """Test load_ignore_txt with a user defined but invalid ignore-file location.""" result = load_ignore_txt(Path(str(uuid.uuid4()))) assert not result ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_local_content.py���������������������������������������������0000664�0000000�0000000�00000000734�14773473560�0023300�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test playbooks with local content.""" from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner def test_local_collection(default_rules_collection: RulesCollection) -> None: """Assures local collections are found.""" playbook_path = "test/local-content/test-collection.yml" runner = Runner(playbook_path, rules=default_rules_collection) results = runner.run() assert len(runner.lintables) == 1 assert len(results) == 0 ������������������������������������ansible-ansible-lint-c16f018/test/test_main.py������������������������������������������������������0000664�0000000�0000000�00000013525�14773473560�0021402�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests related to ansiblelint.__main__ module.""" import os import shutil import subprocess import sys import tempfile import time from collections.abc import Mapping from http.client import RemoteDisconnected from pathlib import Path import pytest from pytest_mock import MockerFixture from ansiblelint.config import get_version_warning, options from ansiblelint.constants import RC from ansiblelint.loaders import yaml_load_safe @pytest.mark.parametrize( ("in_path"), (False, True), ids=("in", "missing"), ) def test_call_from_outside_venv(in_path: bool) -> None: """Asserts ability to be called w/ or w/o venv activation.""" git_location = shutil.which("git") if not git_location: pytest.fail("git not found") git_path = Path(git_location).parent py_path = Path(sys.executable).parent.resolve().as_posix() env = os.environ.copy() env["VIRTUAL_ENV"] = "" env["NO_COLOR"] = "1" if in_path: # VIRTUAL_ENV obliterated here to emulate call from outside a virtual environment env["HOME"] = Path.home().as_posix() env["PATH"] = git_path.as_posix() else: if py_path not in env["PATH"]: env["PATH"] = f"{py_path}:{env['PATH']}" for v in ("COVERAGE_FILE", "COVERAGE_PROCESS_START"): if v in os.environ: env[v] = os.environ[v] # Passing custom env prevents the process from inheriting PATH or other # environment variables from the current process, so we emulate being # called from outside the venv. proc = subprocess.run( [f"{py_path}/ansible-lint", "--version"], check=False, capture_output=True, text=True, env=env, ) assert proc.returncode == 0, proc warning_found = "PATH altered to include" in proc.stderr assert warning_found is in_path @pytest.mark.parametrize( ("ver_diff", "found", "check", "outlen"), ( pytest.param("v1.2.2", True, "pre-release", 1, id="0"), pytest.param("v1.2.3", False, "", 1, id="1"), pytest.param("v1.2.4", True, "new release", 2, id="2"), ), ) def test_get_version_warning( mocker: MockerFixture, ver_diff: str, found: bool, check: str, outlen: int, ) -> None: """Assert get_version_warning working as expected.""" data = f'{{"html_url": "https://127.0.0.1", "tag_name": "{ver_diff}"}}' # simulate cache file mocker.patch("os.path.exists", return_value=True) mocker.patch("os.path.getmtime", return_value=time.time()) mocker.patch("builtins.open", mocker.mock_open(read_data=data)) # overwrite ansible-lint version mocker.patch("ansiblelint.config.__version__", "1.2.3") # overwrite install method to custom one. This one will increase msg line count # to easily detect unwanted call to it. mocker.patch("ansiblelint.config.guess_install_method", return_value="\n") msg = get_version_warning() if not found: assert msg == check else: assert check in msg assert len(msg.split("\n")) == outlen def test_get_version_warning_no_pip(mocker: MockerFixture) -> None: """Test that we do not display any message if install method is not pip.""" mocker.patch("ansiblelint.config.guess_install_method", return_value="") assert get_version_warning() == "" # noqa: PLC1901 def test_get_version_warning_remote_disconnect(mocker: MockerFixture) -> None: """Test that we can handle remote disconnect when fetching release url.""" mocker.patch("urllib.request.urlopen", side_effect=RemoteDisconnected) try: get_version_warning() except RemoteDisconnected: pytest.fail("Failed to handle a remote disconnect") def test_get_version_warning_offline(mocker: MockerFixture) -> None: """Test that offline mode does not display any message.""" with tempfile.TemporaryDirectory() as temporary_directory: # ensures a real cache_file is not loaded mocker.patch("ansiblelint.config.CACHE_DIR", Path(temporary_directory)) options.offline = True assert get_version_warning() == "" # noqa: PLC1901 @pytest.mark.parametrize( ("lintable"), ( pytest.param("examples/playbooks/nodeps.yml", id="1"), pytest.param("examples/playbooks/nodeps2.yml", id="2"), ), ) def test_nodeps(lintable: str) -> None: """Asserts ability to be called w/ or w/o venv activation.""" env = os.environ.copy() env["ANSIBLE_LINT_NODEPS"] = "1" py_path = Path(sys.executable).parent proc = subprocess.run( [str(py_path / "ansible-lint"), lintable], check=False, capture_output=True, text=True, env=env, ) assert proc.returncode == 0, proc def test_broken_ansible_cfg() -> None: """Asserts behavior when encountering broken ansible.cfg files.""" py_path = Path(sys.executable).parent proc = subprocess.run( [str(py_path / "ansible-lint"), "--version"], check=False, capture_output=True, text=True, cwd="test/fixtures/broken-ansible.cfg", ) assert proc.returncode == RC.INVALID_CONFIG, proc # 2.19 had different errors assert any( x in proc.stderr for x in ( "Invalid type for configuration option setting: CACHE_PLUGIN_TIMEOUT", "has an invalid value: Invalid type provided for 'int': 'invalid-value'", ) ) def test_list_tags() -> None: """Asserts that we can list tags and that the output is parseable yaml.""" result = subprocess.run( ["ansible-lint", "--list-tags"], check=True, capture_output=True, text=True, ) assert result.returncode == 0 data = yaml_load_safe(result.stdout) assert isinstance(data, Mapping) for key, value in data.items(): assert isinstance(key, str) assert isinstance(value, list) for item in value: assert isinstance(item, str) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_matcherrror.py�����������������������������������������������0000664�0000000�0000000�00000015407�14773473560�0023007�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for MatchError.""" import operator from collections.abc import Callable from typing import Any import pytest from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.rules.no_changed_when import CommandHasChangesCheckRule from ansiblelint.rules.partial_become import BecomeUserWithoutBecomeRule class DummyTestObject: """A dummy object for equality tests.""" def __repr__(self) -> str: """Return a dummy object representation for parametrize.""" return f"{self.__class__.__name__}()" def __eq__(self, other: object) -> bool: """Report the equality check failure with any object.""" return False def __ne__(self, other: object) -> bool: """Report the confirmation of inequality with any object.""" return True class DummySentinelTestObject: """A dummy object for equality protocol tests with sentinel.""" def __eq__(self, other: object) -> bool: """Return sentinel as result of equality check w/ anything.""" return "EQ_SENTINEL" # type: ignore[return-value] def __ne__(self, other: object) -> bool: """Return sentinel as result of inequality check w/ anything.""" return "NE_SENTINEL" # type: ignore[return-value] def __lt__(self, other: object) -> bool: """Return sentinel as result of less than check w/ anything.""" return "LT_SENTINEL" # type: ignore[return-value] def __gt__(self, other: object) -> bool: """Return sentinel as result of greater than chk w/ anything.""" return "GT_SENTINEL" # type: ignore[return-value] @pytest.mark.parametrize( ("left_match_error", "right_match_error"), ( (MatchError("foo"), MatchError("foo")), (MatchError("a", details="foo"), MatchError("a", details="foo")), ), ) def test_matcherror_compare( left_match_error: MatchError, right_match_error: MatchError, ) -> None: """Check that MatchError instances with similar attrs are equivalent.""" assert left_match_error == right_match_error def test_matcherror_invalid() -> None: """Ensure that MatchError requires message or rule.""" with pytest.raises(TypeError): MatchError() # pylint: disable=pointless-exception-statement @pytest.mark.parametrize( ("left_match_error", "right_match_error"), ( # sorting by message (MatchError("z"), MatchError("a")), # filenames takes priority in sorting ( MatchError("a", lintable=Lintable("b", content="")), MatchError("a", lintable=Lintable("a", content="")), ), # rule id partial-become > rule id no-changed-when ( MatchError(rule=BecomeUserWithoutBecomeRule()), MatchError(rule=CommandHasChangesCheckRule()), ), # details are taken into account (MatchError("a", details="foo"), MatchError("a", details="bar")), # columns are taken into account (MatchError("a", column=3), MatchError("a", column=1)), (MatchError("a", column=3), MatchError("a")), ), ) class TestMatchErrorCompare: """Test the comparison of MatchError instances.""" @staticmethod def test_match_error_less_than( left_match_error: MatchError, right_match_error: MatchError, ) -> None: """Check 'less than' protocol implementation in MatchError.""" assert right_match_error < left_match_error @staticmethod def test_match_error_greater_than( left_match_error: MatchError, right_match_error: MatchError, ) -> None: """Check 'greater than' protocol implementation in MatchError.""" assert left_match_error > right_match_error @staticmethod def test_match_error_not_equal( left_match_error: MatchError, right_match_error: MatchError, ) -> None: """Check 'not equals' protocol implementation in MatchError.""" assert left_match_error != right_match_error @pytest.mark.parametrize( "other", ( pytest.param(None, id="none"), pytest.param("foo", id="str"), pytest.param(42, id="int"), pytest.param(Exception("foo"), id="exc"), ), ids=repr, ) @pytest.mark.parametrize( ("operation", "operator_char"), ( pytest.param(operator.le, "<=", id="le"), pytest.param(operator.gt, ">", id="gt"), ), ) def test_matcherror_compare_no_other_fallback( other: Any, operation: Callable[..., bool], operator_char: str, ) -> None: """Check that MatchError comparison with other types causes TypeError.""" expected_error = ( r"^(" rf"unsupported operand type\(s\) for {operator_char!s}:|" rf"'{operator_char!s}' not supported between instances of" rf") 'MatchError' and '{type(other).__name__!s}'$" ) with pytest.raises(TypeError, match=expected_error): operation(MatchError("foo"), other) @pytest.mark.parametrize( "other", ( pytest.param(None, id="none"), pytest.param("foo", id="str"), pytest.param(42, id="int"), pytest.param(Exception("foo"), id="exception"), pytest.param(DummyTestObject(), id="obj"), ), ids=repr, ) @pytest.mark.parametrize( ("operation", "expected_value"), ( pytest.param(operator.eq, False, id="eq"), pytest.param(operator.ne, True, id="ne"), ), ) def test_matcherror_compare_with_other_fallback( other: object, operation: Callable[..., bool], expected_value: bool, ) -> None: """Check that MatchError comparison runs other types fallbacks.""" assert operation(MatchError(message="foo"), other) is expected_value @pytest.mark.parametrize( ("operation", "expected_value"), ( pytest.param(operator.eq, "EQ_SENTINEL", id="eq"), pytest.param(operator.ne, "NE_SENTINEL", id="ne"), # NOTE: these are swapped because when we do `x < y`, and `x.__lt__(y)` # NOTE: returns `NotImplemented`, Python will reverse the check into # NOTE: `y > x`, and so `y.__gt__(x) is called. # Ref: https://docs.python.org/3/reference/datamodel.html#object.__lt__ pytest.param(operator.lt, "GT_SENTINEL", id="gt"), pytest.param(operator.gt, "LT_SENTINEL", id="lt"), ), ) def test_matcherror_compare_with_dummy_sentinel( operation: Callable[..., bool], expected_value: str, ) -> None: """Check that MatchError comparison runs other types fallbacks.""" dummy_obj = DummySentinelTestObject() # NOTE: This assertion abuses the CPython property to cache short string # NOTE: objects because the identity check is more precise and we don't # NOTE: want extra operator protocol methods to influence the test. assert operation(MatchError("foo"), dummy_obj) is expected_value # type: ignore[comparison-overlap] ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_mockings.py��������������������������������������������������0000664�0000000�0000000�00000001036�14773473560�0022262�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test mockings module.""" from pathlib import Path import pytest from ansiblelint._mockings import _make_module_stub from ansiblelint.config import Options from ansiblelint.constants import RC def test_make_module_stub(config_options: Options) -> None: """Test make module stub.""" config_options.cache_dir = Path() # current directory with pytest.raises(SystemExit) as exc: _make_module_stub(module_name="", options=config_options) assert exc.type is SystemExit assert exc.value.code == RC.INVALID_CONFIG ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_profiles.py��������������������������������������������������0000664�0000000�0000000�00000004234�14773473560�0022276�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for the --profile feature.""" import platform import subprocess import sys from _pytest.capture import CaptureFixture from ansiblelint.rules import RulesCollection, filter_rules_with_profile from ansiblelint.rules.risky_shell_pipe import ShellWithoutPipefail from ansiblelint.text import strip_ansi_escape def test_profile_min() -> None: """Asserts our ability to unload rules based on profile.""" collection = RulesCollection() assert len(collection.rules) == 4, "Unexpected number of implicit rules." # register one extra rule that we know not to be part of "min" profile collection.register(ShellWithoutPipefail()) assert len(collection.rules) == 5, "Failed to register new rule." filter_rules_with_profile(collection.rules, "min") assert ( len(collection.rules) == 4 ), "Failed to unload rule that is not part of 'min' profile." def test_profile_listing(capfd: CaptureFixture[str]) -> None: """Test that run without arguments it will detect and lint the entire repository.""" cmd = [ sys.executable, "-m", "ansiblelint", "-P", ] result = subprocess.run(cmd, check=False).returncode assert result == 0 out, err = capfd.readouterr() # Confirmation that it runs in auto-detect mode assert "command-instead-of-module" in out # On WSL we might see this warning on stderr: # [WARNING]: Ansible is being run in a world writable directory # WSL2 has "WSL2" in platform name but WSL1 has "microsoft": platform_name = platform.platform().lower() err_lines = [] for line in strip_ansi_escape(err).splitlines(): if "SyntaxWarning:" in line: continue if "No know markdown renderer found" in line: continue if ( "Skipped installing collection dependencies due to running in offline mode." in line ): continue err_lines.append(line) if all(word not in platform_name for word in ["wsl", "microsoft"]) and err_lines: assert ( not err_lines ), f"Unexpected stderr output found while running on {platform_name} platform:\n{err_lines}" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_requirements.py����������������������������������������������0000664�0000000�0000000�00000001147�14773473560�0023176�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests requirements module.""" from ansible_compat.runtime import Runtime from ansiblelint.requirements import Reqs def test_reqs() -> None: """Performs basic testing of Reqs class.""" reqs = Reqs() runtime = Runtime() assert "ansible-core" in reqs # checks that this ansible core version is not supported: assert reqs.matches("ansible-core", "0.0") is False # assert that invalid package name assert reqs.matches("this-package-does-not-exist", "0.0") is False # check the current ansible core version is supported: assert reqs.matches("ansible-core", runtime.version) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_rule_properties.py�������������������������������������������0000664�0000000�0000000�00000000732�14773473560�0023675�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests related to rule properties.""" from ansiblelint.rules import RulesCollection def test_severity_valid(default_rules_collection: RulesCollection) -> None: """Test that rules collection only has allow-listed severities.""" valid_severity_values = [ "VERY_HIGH", "HIGH", "MEDIUM", "LOW", "VERY_LOW", "INFO", ] for rule in default_rules_collection: assert rule.severity in valid_severity_values ��������������������������������������ansible-ansible-lint-c16f018/test/test_rules_collection.py������������������������������������������0000664�0000000�0000000�00000015077�14773473560�0024027�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for rule collection class.""" # Copyright (c) 2013-2014 Will Thames <will@thames.id.au> # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from __future__ import annotations import collections import re from pathlib import Path from typing import TYPE_CHECKING import pytest from ansiblelint.file_utils import Lintable from ansiblelint.rules import RulesCollection from ansiblelint.testing import run_ansible_lint if TYPE_CHECKING: from ansiblelint.config import Options @pytest.fixture(name="test_rules_collection") def fixture_test_rules_collection() -> RulesCollection: """Create a shared rules collection test instance.""" return RulesCollection([Path("./test/rules/fixtures").resolve()]) @pytest.fixture(name="ematchtestfile") def fixture_ematchtestfile() -> Lintable: """Produce a test lintable with an id violation.""" return Lintable("examples/playbooks/ematcher-rule.yml", kind="playbook") @pytest.fixture(name="bracketsmatchtestfile") def fixture_bracketsmatchtestfile() -> Lintable: """Produce a test lintable with matching brackets.""" return Lintable("examples/playbooks/bracketsmatchtest.yml", kind="playbook") def test_load_collection_from_directory(test_rules_collection: RulesCollection) -> None: """Test that custom rules extend the default ones.""" # two detected rules plus the internal ones assert len(test_rules_collection) == 7 def test_run_collection( test_rules_collection: RulesCollection, ematchtestfile: Lintable, ) -> None: """Test that default rules match pre-meditated violations.""" matches = test_rules_collection.run(ematchtestfile) assert len(matches) == 4 # 3 occurrences of BANNED using TEST0001 + 1 for raw-task assert matches[0].lineno == 3 def test_tags( test_rules_collection: RulesCollection, ematchtestfile: Lintable, bracketsmatchtestfile: Lintable, ) -> None: """Test that tags are treated as skip markers.""" matches = test_rules_collection.run(ematchtestfile, tags={"test1"}) assert len(matches) == 3 matches = test_rules_collection.run(ematchtestfile, tags={"test2"}) assert len(matches) == 0 matches = test_rules_collection.run(bracketsmatchtestfile, tags={"test1"}) assert len(matches) == 0 matches = test_rules_collection.run(bracketsmatchtestfile, tags={"test2"}) assert len(matches) == 2 def test_skip_tags( test_rules_collection: RulesCollection, ematchtestfile: Lintable, bracketsmatchtestfile: Lintable, ) -> None: """Test that tags can be skipped.""" matches = test_rules_collection.run(ematchtestfile, skip_list=["test1", "test3"]) assert len(matches) == 0 matches = test_rules_collection.run(ematchtestfile, skip_list=["test2", "test3"]) assert len(matches) == 3 matches = test_rules_collection.run(bracketsmatchtestfile, skip_list=["test1"]) assert len(matches) == 2 matches = test_rules_collection.run(bracketsmatchtestfile, skip_list=["test2"]) assert len(matches) == 0 def test_skip_id( test_rules_collection: RulesCollection, ematchtestfile: Lintable, bracketsmatchtestfile: Lintable, ) -> None: """Check that skipping valid IDs excludes their violations.""" matches = test_rules_collection.run( ematchtestfile, skip_list=["TEST0001", "raw-task"], ) assert len(matches) == 0 matches = test_rules_collection.run( ematchtestfile, skip_list=["TEST0002", "raw-task"], ) assert len(matches) == 3 matches = test_rules_collection.run(bracketsmatchtestfile, skip_list=["TEST0001"]) assert len(matches) == 2 matches = test_rules_collection.run(bracketsmatchtestfile, skip_list=["TEST0002"]) assert len(matches) == 0 def test_skip_non_existent_id( test_rules_collection: RulesCollection, ematchtestfile: Lintable, ) -> None: """Check that skipping invalid IDs changes nothing.""" matches = test_rules_collection.run(ematchtestfile, skip_list=["DOESNOTEXIST"]) assert len(matches) == 4 def test_no_duplicate_rule_ids() -> None: """Check that rules of the collection don't have duplicate IDs.""" real_rules = RulesCollection([Path("./src/ansiblelint/rules").resolve()]) rule_ids = [rule.id for rule in real_rules] assert not any(y > 1 for y in collections.Counter(rule_ids).values()) def test_rule_listing() -> None: """Test that rich list format output is rendered as a table. This check also offers the contract of having rule id, short and long descriptions in the console output. """ rules_path = Path("./test/rules/fixtures").resolve() result = run_ansible_lint("-r", str(rules_path), "-L") assert result.returncode == 0 for rule in RulesCollection([rules_path]): assert rule.id in result.stdout assert rule.shortdesc in result.stdout def test_rules_id_format(config_options: Options) -> None: """Assure all our rules have consistent format.""" rule_id_re = re.compile(r"^[a-z-]{4,30}$") rules = RulesCollection( [Path("./src/ansiblelint/rules").resolve()], options=config_options, conditional=False, ) keys: set[str] = set() for rule in rules: assert rule_id_re.match( rule.id, ), f"Rule id {rule.id} did not match our required format." keys.add(rule.id) assert ( rule.help or rule.description or rule.__doc__ ), f"Rule {rule.id} must have at least one of: .help, .description, .__doc__" assert "yaml" in keys, "yaml rule is missing" assert len(rules) == 51 # update this number when adding new rules! assert len(keys) == len(rules), "Duplicate rule ids?" �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_runner.py����������������������������������������������������0000664�0000000�0000000�00000020327�14773473560�0021765�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for runner submodule.""" # Copyright (c) 2013-2014 Will Thames <will@thames.id.au> # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from __future__ import annotations from pathlib import Path from typing import TYPE_CHECKING, Any import pytest from ansiblelint import formatters from ansiblelint.file_utils import Lintable from ansiblelint.runner import Runner if TYPE_CHECKING: from ansiblelint.rules import RulesCollection LOTS_OF_WARNINGS_PLAYBOOK = Path("examples/playbooks/lots_of_warnings.yml").resolve() @pytest.mark.parametrize( ("playbook", "exclude", "length"), ( pytest.param( Path("examples/playbooks/nomatchestest.yml"), [], 0, id="nomatchestest", ), pytest.param(Path("examples/playbooks/unicode.yml"), [], 1, id="unicode"), pytest.param( LOTS_OF_WARNINGS_PLAYBOOK, [LOTS_OF_WARNINGS_PLAYBOOK], 993, id="lots_of_warnings", ), pytest.param(Path("examples/playbooks/become.yml"), [], 0, id="become"), pytest.param( Path("examples/playbooks/contains_secrets.yml"), [], 0, id="contains_secrets", ), ), ) def test_runner( default_rules_collection: RulesCollection, playbook: Path, exclude: list[str], length: int, ) -> None: """Test that runner can go through any corner cases.""" runner = Runner(playbook, rules=default_rules_collection, exclude_paths=exclude) matches = runner.run() assert len(matches) == length def test_runner_exclude_paths(default_rules_collection: RulesCollection) -> None: """Test that exclude paths do work.""" runner = Runner( "examples/playbooks/deep/", rules=default_rules_collection, exclude_paths=["examples/playbooks/deep/empty.yml"], ) matches = runner.run() assert len(matches) == 0 @pytest.mark.parametrize( ("exclude_path"), (pytest.param("**/playbooks_globs/*b.yml", id="1"),), ) def test_runner_exclude_globs( default_rules_collection: RulesCollection, exclude_path: str, ) -> None: """Test that globs work.""" runner = Runner( "examples/playbooks_globs", rules=default_rules_collection, exclude_paths=[exclude_path], ) matches = runner.run() assert len(matches) == 0 @pytest.mark.parametrize( ("formatter_cls"), ( pytest.param(formatters.Formatter, id="Formatter-plain"), pytest.param(formatters.ParseableFormatter, id="ParseableFormatter-colored"), pytest.param(formatters.QuietFormatter, id="QuietFormatter-colored"), pytest.param(formatters.Formatter, id="Formatter-colored"), ), ) def test_runner_unicode_format( default_rules_collection: RulesCollection, formatter_cls: type[formatters.BaseFormatter[Any]], ) -> None: """Check that all formatters are unicode-friendly.""" formatter = formatter_cls(Path.cwd(), display_relative_path=True) runner = Runner( Lintable("examples/playbooks/unicode.yml", kind="playbook"), rules=default_rules_collection, ) matches = runner.run() formatter.apply(matches[0]) @pytest.mark.parametrize( "directory_name", ( pytest.param(Path("test/fixtures/verbosity-tests"), id="rel"), pytest.param(Path("test/fixtures/verbosity-tests").resolve(), id="abs"), ), ) def test_runner_with_directory( default_rules_collection: RulesCollection, directory_name: Path, ) -> None: """Check that runner detects a directory as role.""" runner = Runner(directory_name, rules=default_rules_collection) expected = Lintable(name=directory_name, kind="role") assert expected in runner.lintables def test_files_not_scanned_twice(default_rules_collection: RulesCollection) -> None: """Ensure that lintables aren't double-checked.""" checked_files: set[Lintable] = set() filename = Path("examples/playbooks/common-include-1.yml").resolve() runner = Runner( filename, rules=default_rules_collection, verbosity=0, checked_files=checked_files, ) run1 = runner.run() assert len(runner.checked_files) == 2 assert len(run1) == 1 filename = Path("examples/playbooks/common-include-2.yml").resolve() runner = Runner( str(filename), rules=default_rules_collection, verbosity=0, checked_files=checked_files, ) run2 = runner.run() assert len(runner.checked_files) == 3 # this second run should return 0 because the included filed was already # processed and added to checked_files, which acts like a bypass list. assert len(run2) == 0 @pytest.mark.parametrize( ("filename", "failures", "checked_files_no"), ( pytest.param( "examples/playbooks/common-include-wrong-syntax.yml", 1, 1, id="1", ), pytest.param( "examples/playbooks/common-include-wrong-syntax2.yml", 1, 1, id="2", ), pytest.param( "examples/playbooks/common-include-wrong-syntax3.yml", 0, 2, id="3", ), ), ) def test_include_wrong_syntax( filename: str, failures: int, checked_files_no: int, default_rules_collection: RulesCollection, ) -> None: """Ensure that lintables aren't double-checked.""" checked_files: set[Lintable] = set() path = Path(filename).resolve() runner = Runner( path, rules=default_rules_collection, verbosity=0, checked_files=checked_files, ) result = runner.run() assert len(runner.checked_files) == checked_files_no assert len(result) == failures, result for item in result: assert item.tag == "syntax-check[no-file]" def test_runner_not_found(default_rules_collection: RulesCollection) -> None: """Ensure that lintables aren't double-checked.""" checked_files: set[Lintable] = set() filename = Path("this/folder/does/not/exist").resolve() runner = Runner( filename, rules=default_rules_collection, verbosity=0, checked_files=checked_files, ) result = runner.run() assert len(runner.checked_files) == 1 assert len(result) == 1 assert result[0].tag == "load-failure[not-found]" def test_runner_tmp_file( tmp_path: Path, default_rules_collection: RulesCollection, ) -> None: """Ensure we do not ignore an explicit temporary file from linting.""" # https://github.com/ansible/ansible-lint/issues/2628 filename = tmp_path / "playbook.yml" filename.write_text("---\n") runner = Runner( filename, rules=default_rules_collection, verbosity=0, ) result = runner.run() assert len(result) == 1 assert result[0].tag == "syntax-check[empty-playbook]" def test_with_full_path(default_rules_collection: RulesCollection) -> None: """Ensure that lintables include file path starting from home directory.""" filename = Path("examples/playbooks/deep").absolute() runner = Runner( filename, rules=default_rules_collection, verbosity=0, ) result = runner.run() assert len(result) == 1 assert result[0].tag == "name[casing]" ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_schemas.py���������������������������������������������������0000664�0000000�0000000�00000007354�14773473560�0022104�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test schemas modules.""" import json import logging import os import subprocess import sys import urllib import warnings from pathlib import Path from typing import Any from unittest.mock import DEFAULT, MagicMock, patch import license_expression import pytest from ansiblelint.file_utils import Lintable from ansiblelint.schemas import __file__ as schema_module from ansiblelint.schemas.__main__ import refresh_schemas from ansiblelint.schemas.main import validate_file_schema schema_path = Path(schema_module).parent spdx_config_path = ( Path(license_expression.__file__).parent / "data" / "scancode-licensedb-index.json" ) def urlopen_side_effect(*_args: Any, **kwargs: Any) -> Any: """Actual test that timeout parameter is defined.""" assert "timeout" in kwargs assert kwargs["timeout"] > 0 return DEFAULT @patch("urllib.request") def test_requests_uses_timeout(mock_request: MagicMock) -> None: """Test that schema refresh uses timeout.""" mock_request.urlopen.side_effect = urlopen_side_effect refresh_schemas(min_age_seconds=0) mock_request.urlopen.assert_called() @patch("urllib.request") def test_request_timeouterror_handling( mock_request: MagicMock, caplog: pytest.LogCaptureFixture, ) -> None: """Test that schema refresh can handle time out errors.""" error_msg = "Simulating handshake operation time out." mock_request.urlopen.side_effect = ( urllib.error.URLError( # pyright: ignore[reportAttributeAccessIssue] TimeoutError(error_msg) ) ) with caplog.at_level(logging.DEBUG): assert refresh_schemas(min_age_seconds=0) == 0 mock_request.urlopen.assert_called() assert "Skipped schema refresh due to unexpected exception: " in caplog.text assert error_msg in caplog.text def test_schema_refresh_cli() -> None: """Ensure that we test the cli schema refresh command.""" proc = subprocess.run( [sys.executable, "-m", "ansiblelint.schemas"], check=False, capture_output=True, text=True, ) assert proc.returncode == 0, proc def test_validate_file_schema() -> None: """Test file schema validation failure on unknown file kind.""" lintable = Lintable("foo.bar", kind="") result = validate_file_schema(lintable) assert len(result) == 1, result assert "Unable to find JSON Schema" in result[0] def test_spdx() -> None: """Test that SPDX license identifiers are in sync.""" license_ids = set() with spdx_config_path.open(encoding="utf-8") as license_fh: licenses = json.load(license_fh) for lic in licenses: if lic.get("is_deprecated"): continue lic_id = lic["spdx_license_key"] if lic_id.startswith("LicenseRef"): continue license_ids.add(lic_id) galaxy_json = schema_path / "galaxy.json" with galaxy_json.open(encoding="utf-8") as f: schema = json.load(f) spx_enum = schema["$defs"]["SPDXLicenseEnum"]["enum"] if set(spx_enum) != license_ids: constraints = os.environ.get("PIP_CONSTRAINT", "/dev/null") if constraints.endswith(".config/constraints.txt"): with galaxy_json.open("w", encoding="utf-8") as f: schema["$defs"]["SPDXLicenseEnum"]["enum"] = sorted(license_ids) json.dump(schema, f, indent=2) pytest.fail( f"SPDX license list inside galaxy.json JSON Schema file was updated. {constraints}", ) else: warnings.warn( f"test_spdx failure was ignored because constraints were not pinned (PIP_CONSTRAINT={constraints}). This is expected for py310 and py-devel, lower jobs.", category=pytest.PytestWarning, stacklevel=1, ) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_skip_import_playbook.py��������������������������������������0000664�0000000�0000000�00000002043�14773473560�0024707�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test related to skipping import_playbook.""" from pathlib import Path from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner IMPORTED_PLAYBOOK = """\ --- - name: Fixture hosts: all tasks: - name: Success # noqa: no-free-form ansible.builtin.fail: msg="fail" when: false """ MAIN_PLAYBOOK = """\ --- - name: Fixture hosts: all tasks: - name: Should be shell # noqa: command-instead-of-shell no-changed-when no-free-form ansible.builtin.shell: echo lol - name: Should not be imported import_playbook: imported_playbook.yml """ def test_skip_import_playbook( default_rules_collection: RulesCollection, tmp_path: Path ) -> None: """Verify that a playbook import is skipped after a failure.""" playbook_path = tmp_path / "playbook.yml" playbook_path.write_text(MAIN_PLAYBOOK) (tmp_path / "imported_playbook.yml").write_text(IMPORTED_PLAYBOOK) runner = Runner(playbook_path, rules=default_rules_collection) results = runner.run() assert len(results) == 0 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_skip_inside_yaml.py������������������������������������������0000664�0000000�0000000�00000002277�14773473560�0024003�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests related to use of inline noqa.""" import pytest from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner from ansiblelint.testing import run_ansible_lint def test_role_tasks_with_block(default_rules_collection: RulesCollection) -> None: """Check that blocks in role tasks can contain skips.""" results = Runner( "examples/playbooks/roles/fixture_1", rules=default_rules_collection, ).run() assert len(results) == 4 for result in results: assert result.tag == "latest[git]" @pytest.mark.parametrize( ("lintable", "expected"), (pytest.param("examples/playbooks/test_skip_inside_yaml.yml", 4, id="yaml"),), ) def test_inline_skips( default_rules_collection: RulesCollection, lintable: str, expected: int, ) -> None: """Check that playbooks can contain skips.""" results = Runner(lintable, rules=default_rules_collection).run() assert len(results) == expected def test_role_meta() -> None: """Test running from inside meta folder.""" role_path = "examples/roles/meta_noqa" result = run_ansible_lint("-v", role_path) assert len(result.stdout) == 0 assert result.returncode == 0 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_skip_playbook_items.py���������������������������������������0000664�0000000�0000000�00000006122�14773473560�0024520�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests related to use of noqa inside playbooks.""" import pytest from ansiblelint.testing import RunFromText PLAYBOOK_PRE_TASKS = """\ --- - name: Fixture hosts: all tasks: - name: Bad git 1 # noqa: latest[git] action: ansible.builtin.git a=b c=d - name: Bad git 2 action: ansible.builtin.git a=b c=d pre_tasks: - name: Bad git 3 # noqa: latest[git] action: ansible.builtin.git a=b c=d - name: Bad git 4 action: ansible.builtin.git a=b c=d """ PLAYBOOK_POST_TASKS = """\ --- - name: Fixture hosts: all tasks: - name: Bad git 1 # noqa: latest[git] action: ansible.builtin.git a=b c=d - name: Bad git 2 action: ansible.builtin.git a=b c=d post_tasks: - name: Bad git 3 # noqa: latest[git] action: ansible.builtin.git a=b c=d - name: Bad git 4 action: ansible.builtin.git a=b c=d """ PLAYBOOK_HANDLERS = """\ --- - name: Fixture hosts: all tasks: - name: Bad git 1 # noqa: latest[git] action: ansible.builtin.git a=b c=d - name: Bad git 2 action: ansible.builtin.git a=b c=d handlers: - name: Bad git 3 # noqa: latest[git] action: ansible.builtin.git a=b c=d - name: Bad git 4 action: ansible.builtin.git a=b c=d """ PLAYBOOK_TWO_PLAYS = """\ --- - name: Fixture hosts: all tasks: - name: Bad git 1 # noqa: latest[git] action: ansible.builtin.git a=b c=d - name: Bad git 2 action: ansible.builtin.git a=b c=d - name: Fixture 2 hosts: all tasks: - name: Bad git 3 # noqa: latest[git] action: ansible.builtin.git a=b c=d - name: Bad git 4 action: ansible.builtin.git a=b c=d """ PLAYBOOK_WITH_BLOCK = """\ --- - name: Fixture hosts: all tasks: - name: Bad git 1 # noqa: latest[git] action: ansible.builtin.git a=b c=d - name: Bad git 2 action: ansible.builtin.git a=b c=d - name: Block with rescue and always section block: - name: Bad git 3 # noqa: latest[git] action: ansible.builtin.git a=b c=d - name: Bad git 4 action: ansible.builtin.git a=b c=d rescue: - name: Bad git 5 # noqa: latest[git] action: ansible.builtin.git a=b c=d - name: Bad git 6 action: ansible.builtin.git a=b c=d always: - name: Bad git 7 # noqa: latest[git] action: ansible.builtin.git a=b c=d - name: Bad git 8 action: ansible.builtin.git a=b c=d """ @pytest.mark.parametrize( ("playbook", "length"), ( pytest.param(PLAYBOOK_PRE_TASKS, 6, id="PRE_TASKS"), pytest.param(PLAYBOOK_POST_TASKS, 6, id="POST_TASKS"), pytest.param(PLAYBOOK_HANDLERS, 6, id="HANDLERS"), pytest.param(PLAYBOOK_TWO_PLAYS, 6, id="TWO_PLAYS"), pytest.param(PLAYBOOK_WITH_BLOCK, 12, id="WITH_BLOCK"), ), ) def test_pre_tasks( default_text_runner: RunFromText, playbook: str, length: int, ) -> None: """Check that skipping is possible in different playbook parts.""" # When results = default_text_runner.run_playbook(playbook) # Then assert len(results) == length ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_skiputils.py�������������������������������������������������0000664�0000000�0000000�00000022320�14773473560�0022476�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Validate ansiblelint.skip_utils.""" from __future__ import annotations from pathlib import Path from typing import TYPE_CHECKING, Any import pytest from ansiblelint.constants import SKIPPED_RULES_KEY from ansiblelint.file_utils import Lintable from ansiblelint.runner import Runner from ansiblelint.skip_utils import ( append_skipped_rules, get_rule_skips_from_line, is_nested_task, ) from ansiblelint.utils import Task if TYPE_CHECKING: from ansiblelint.rules import RulesCollection from ansiblelint.testing import RunFromText from ansiblelint.types import AnsibleBaseYAMLObject PLAYBOOK_WITH_NOQA = """\ --- - name: Fixture hosts: all vars: SOME_VAR_NOQA: "Foo" # noqa: var-naming SOME_VAR: "Bar" tasks: - name: "Set the SOME_OTHER_VAR" ansible.builtin.set_fact: SOME_OTHER_VAR_NOQA: "Baz" # noqa: var-naming SOME_OTHER_VAR: "Bat" """ @pytest.mark.parametrize( ("line", "expected"), ( pytest.param("foo # noqa: bar", "bar", id="0"), pytest.param("foo # noqa bar", "bar", id="1"), ), ) def test_get_rule_skips_from_line(line: str, expected: str) -> None: """Validate get_rule_skips_from_line.""" v = get_rule_skips_from_line(line, lintable=Lintable("")) assert v == [expected] def test_playbook_noqa(default_text_runner: RunFromText) -> None: """Check that noqa is properly taken into account on vars and tasks.""" results = default_text_runner.run_playbook(PLAYBOOK_WITH_NOQA) # Should raise error at "SOME_VAR". assert len(results) == 1 def test_playbook_noqa2(default_text_runner: RunFromText) -> None: """Check that noqa is properly taken into account on vars and tasks.""" results = default_text_runner.run_playbook(PLAYBOOK_WITH_NOQA, "test") # Should raise error at "SOME_VAR". assert len(results) == 1 @pytest.mark.parametrize( ("lintable", "yaml", "expected_form"), ( pytest.param( Lintable("examples/playbooks/noqa.yml", kind="playbook"), [ { "hosts": "localhost", "tasks": [ { "name": "This would typically fire latest[git] and partial-become", "become_user": "alice", "git": "src=/path/to/git/repo dest=checkout", "__line__": 4, "__file__": Path("examples/playbooks/noqa.yml"), }, ], "__line__": 2, "__file__": Path("examples/playbooks/noqa.yml"), }, ], [ { "hosts": "localhost", "tasks": [ { "name": "This would typically fire latest[git] and partial-become", "become_user": "alice", "git": "src=/path/to/git/repo dest=checkout", "__line__": 4, "__file__": Path("examples/playbooks/noqa.yml"), SKIPPED_RULES_KEY: ["latest[git]", "partial-become"], }, ], "__line__": 2, "__file__": Path("examples/playbooks/noqa.yml"), }, ], ), pytest.param( Lintable("examples/playbooks/noqa-nested.yml", kind="playbook"), [ { "hosts": "localhost", "tasks": [ { "name": "Example of multi-level block", "block": [ { "name": "2nd level", "block": [ { "ansible.builtin.debug": { "msg": "Test unnamed task in block", "__line__": 9, "__file__": Path( "examples/playbooks/noqa-nested.yml", ), }, "__line__": 8, "__file__": Path( "examples/playbooks/noqa-nested.yml", ), }, ], "__line__": 6, "__file__": Path( "examples/playbooks/noqa-nested.yml", ), }, ], "__line__": 4, "__file__": Path("examples/playbooks/noqa-nested.yml"), }, ], "__line__": 2, "__file__": Path("examples/playbooks/noqa-nested.yml"), }, ], [ { "hosts": "localhost", "tasks": [ { "name": "Example of multi-level block", "block": [ { "name": "2nd level", "block": [ { "ansible.builtin.debug": { "msg": "Test unnamed task in block", "__line__": 9, "__file__": Path( "examples/playbooks/noqa-nested.yml", ), }, "__line__": 8, "__file__": Path( "examples/playbooks/noqa-nested.yml", ), SKIPPED_RULES_KEY: ["name[missing]"], }, ], "__line__": 6, "__file__": Path( "examples/playbooks/noqa-nested.yml", ), SKIPPED_RULES_KEY: ["name[missing]"], }, ], "__line__": 4, "__file__": Path("examples/playbooks/noqa-nested.yml"), SKIPPED_RULES_KEY: ["name[missing]"], }, ], "__line__": 2, "__file__": Path("examples/playbooks/noqa-nested.yml"), }, ], ), ), ) def test_append_skipped_rules( lintable: Lintable, yaml: AnsibleBaseYAMLObject, expected_form: AnsibleBaseYAMLObject, ) -> None: """Check that it appends skipped_rules properly.""" assert append_skipped_rules(yaml, lintable) == expected_form @pytest.mark.parametrize( ("task", "expected"), ( pytest.param( { "name": "ensure apache is at the latest version", "yum": {"name": "httpd", "state": "latest"}, }, False, ), pytest.param( { "name": "Attempt and graceful roll back", "block": [ { "name": "Force a failure", "ansible.builtin.command": "/bin/false", }, ], "rescue": [ { "name": "Force a failure in middle of recovery!", "ansible.builtin.command": "/bin/false", }, ], "always": [ { "name": "Always do this", "ansible.builtin.debug": {"msg": "This always executes"}, }, ], }, True, ), ), ) def test_is_nested_task(task: dict[str, Any], expected: bool) -> None: """Test is_nested_task() returns expected bool.""" assert is_nested_task(Task(task)) == expected def test_capture_warning_outdated_tag( default_rules_collection: RulesCollection, ) -> None: """Test that exclude paths do work.""" runner = Runner( "examples/playbooks/capture-warning.yml", rules=default_rules_collection, ) matches = runner.run() assert len(matches) == 1 assert matches[0].rule.id == "warning" assert matches[0].tag == "warning[outdated-tag]" assert matches[0].lineno == 8 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_strict.py����������������������������������������������������0000664�0000000�0000000�00000001565�14773473560�0021767�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Test strict mode.""" import os import pytest from ansiblelint.testing import run_ansible_lint @pytest.mark.parametrize( ("strict", "returncode", "message"), ( pytest.param(True, 2, "Failed", id="on"), pytest.param(False, 0, "Passed", id="off"), ), ) def test_strict(strict: bool, returncode: int, message: str) -> None: """Test running from inside meta folder.""" args = ["examples/playbooks/strict-mode.yml"] env = os.environ.copy() env["NO_COLOR"] = "1" if strict: args.insert(0, "--strict") result = run_ansible_lint(*args, env=env) assert result.returncode == returncode assert "args[module]" in result.stdout for summary_line in result.stderr.splitlines(): if summary_line.startswith(message): break else: pytest.fail(f"Failed to find {message} inside stderr output") �������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_task_includes.py���������������������������������������������0000664�0000000�0000000�00000003005�14773473560�0023276�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests related to task inclusions.""" import pytest from ansiblelint.file_utils import Lintable from ansiblelint.rules import RulesCollection from ansiblelint.runner import Runner @pytest.mark.parametrize( ("filename", "file_count", "match_count"), ( pytest.param( "examples/playbooks/blockincludes.yml", 4, 3, id="blockincludes", ), pytest.param( "examples/playbooks/blockincludes2.yml", 4, 3, id="blockincludes2", ), pytest.param("examples/playbooks/taskincludes.yml", 3, 6, id="taskincludes"), pytest.param("examples/playbooks/taskimports.yml", 5, 3, id="taskimports"), pytest.param( "examples/playbooks/include-in-block.yml", 3, 1, id="include-in-block", ), pytest.param( "examples/playbooks/include-import-tasks-in-role.yml", 4, 2, id="role_with_task_inclusions", ), ), ) def test_included_tasks( default_rules_collection: RulesCollection, filename: str, file_count: int, match_count: int, ) -> None: """Check if number of loaded files is correct.""" lintable = Lintable(filename) default_rules_collection.options.enable_list = ["name[prefix]"] runner = Runner(lintable, rules=default_rules_collection) result = runner.run() assert len(runner.lintables) == file_count assert len(result) == match_count ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_text.py������������������������������������������������������0000664�0000000�0000000�00000004247�14773473560�0021443�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for text module.""" from typing import Any import pytest from ansiblelint.text import has_glob, has_jinja, strip_ansi_escape, toidentifier @pytest.mark.parametrize( ("value", "expected"), ( pytest.param("\x1b[1;31mHello", "Hello", id="0"), pytest.param("\x1b[2;37;41mExample_file.zip", "Example_file.zip", id="1"), pytest.param(b"ansible-lint", "ansible-lint", id="2"), ), ) def test_strip_ansi_escape(value: Any, expected: str) -> None: """Tests for strip_ansi_escape().""" assert strip_ansi_escape(value) == expected @pytest.mark.parametrize( ("value", "expected"), ( pytest.param("foo-bar", "foo_bar", id="0"), pytest.param("foo--bar", "foo_bar", id="1"), ), ) def test_toidentifier(value: Any, expected: str) -> None: """Tests for toidentifier().""" assert toidentifier(value) == expected @pytest.mark.parametrize( ("value", "expected"), (pytest.param("example_test.zip", "Unable to convert role name", id="0"),), ) def test_toidentifier_fail(value: Any, expected: str) -> None: """Tests for toidentifier().""" with pytest.raises(RuntimeError) as err: toidentifier(value) assert str(err.value).find(expected) > -1 @pytest.mark.parametrize( ("value", "expected"), ( pytest.param("", False, id="0"), pytest.param("{{ }}", True, id="1"), pytest.param("foo {# #} bar", True, id="2"), pytest.param("foo \n{% %} bar", True, id="3"), pytest.param(None, False, id="4"), pytest.param(42, False, id="5"), pytest.param(True, False, id="6"), ), ) def test_has_jinja(value: Any, expected: bool) -> None: """Tests for has_jinja().""" assert has_jinja(value) == expected @pytest.mark.parametrize( ("value", "expected"), ( pytest.param("", False, id="0"), pytest.param("*", True, id="1"), pytest.param("foo.*", True, id="2"), pytest.param(None, False, id="4"), pytest.param(42, False, id="5"), pytest.param(True, False, id="6"), ), ) def test_has_glob(value: Any, expected: bool) -> None: """Tests for has_jinja().""" assert has_glob(value) == expected ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_transform_mixin.py�������������������������������������������0000664�0000000�0000000�00000012657�14773473560�0023702�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for TransformMixin.""" from __future__ import annotations from typing import TYPE_CHECKING import pytest from ansiblelint.rules import TransformMixin if TYPE_CHECKING: from collections.abc import MutableMapping, MutableSequence from typing import Any DUMMY_MAP: dict[str, Any] = { "foo": "text", "bar": {"some": "text2"}, "fruits": ["apple", "orange"], "answer": [{"forty-two": ["life", "universe", "everything"]}], } DUMMY_LIST: list[dict[str, Any]] = [ {"foo": "text"}, {"bar": {"some": "text2"}, "fruits": ["apple", "orange"]}, {"answer": [{"forty-two": ["life", "universe", "everything"]}]}, ] @pytest.mark.parametrize( ("yaml_path", "data", "expected_error"), ( ([0], DUMMY_MAP, KeyError), (["bar", 0], DUMMY_MAP, KeyError), (["fruits", 100], DUMMY_MAP, IndexError), (["answer", 1], DUMMY_MAP, IndexError), (["answer", 0, 42], DUMMY_MAP, KeyError), (["answer", 0, "42"], DUMMY_MAP, KeyError), ([100], DUMMY_LIST, IndexError), ([0, 0], DUMMY_LIST, KeyError), ([0, "wrong key"], DUMMY_LIST, KeyError), ([1, "bar", "wrong key"], DUMMY_LIST, KeyError), ([1, "fruits", "index should be int"], DUMMY_LIST, TypeError), ([1, "fruits", 100], DUMMY_LIST, IndexError), ), ) def test_seek_with_bad_path( yaml_path: list[int | str], data: MutableMapping[str, Any] | MutableSequence[Any] | str, expected_error: type[Exception], ) -> None: """Verify that TransformMixin.seek() propagates errors.""" with pytest.raises(expected_error): TransformMixin.seek(yaml_path, data) @pytest.mark.parametrize( ("yaml_path", "data", "expected"), ( pytest.param([], DUMMY_MAP, DUMMY_MAP, id="0"), pytest.param(["foo"], DUMMY_MAP, DUMMY_MAP["foo"], id="1"), pytest.param(["bar"], DUMMY_MAP, DUMMY_MAP["bar"], id="2"), pytest.param(["bar", "some"], DUMMY_MAP, DUMMY_MAP["bar"]["some"], id="3"), pytest.param(["fruits"], DUMMY_MAP, DUMMY_MAP["fruits"], id="4"), pytest.param(["fruits", 0], DUMMY_MAP, DUMMY_MAP["fruits"][0], id="5"), pytest.param(["fruits", 1], DUMMY_MAP, DUMMY_MAP["fruits"][1], id="6"), pytest.param(["answer"], DUMMY_MAP, DUMMY_MAP["answer"], id="7"), pytest.param(["answer", 0], DUMMY_MAP, DUMMY_MAP["answer"][0], id="8"), pytest.param( ["answer", 0, "forty-two"], DUMMY_MAP, DUMMY_MAP["answer"][0]["forty-two"], id="9", ), pytest.param( ["answer", 0, "forty-two", 0], DUMMY_MAP, DUMMY_MAP["answer"][0]["forty-two"][0], id="10", ), pytest.param( ["answer", 0, "forty-two", 1], DUMMY_MAP, DUMMY_MAP["answer"][0]["forty-two"][1], id="11", ), pytest.param( ["answer", 0, "forty-two", 2], DUMMY_MAP, DUMMY_MAP["answer"][0]["forty-two"][2], id="12", ), pytest.param([], DUMMY_LIST, DUMMY_LIST, id="13"), pytest.param([0], DUMMY_LIST, DUMMY_LIST[0], id="14"), pytest.param([0, "foo"], DUMMY_LIST, DUMMY_LIST[0]["foo"], id="15"), pytest.param([1], DUMMY_LIST, DUMMY_LIST[1], id="16"), pytest.param([1, "bar"], DUMMY_LIST, DUMMY_LIST[1]["bar"], id="17"), pytest.param( [1, "bar", "some"], DUMMY_LIST, DUMMY_LIST[1]["bar"]["some"], id="18", ), pytest.param([1, "fruits"], DUMMY_LIST, DUMMY_LIST[1]["fruits"], id="19"), pytest.param([1, "fruits", 0], DUMMY_LIST, DUMMY_LIST[1]["fruits"][0], id="20"), pytest.param([1, "fruits", 1], DUMMY_LIST, DUMMY_LIST[1]["fruits"][1], id="21"), pytest.param([2], DUMMY_LIST, DUMMY_LIST[2], id="22"), pytest.param([2, "answer"], DUMMY_LIST, DUMMY_LIST[2]["answer"], id="23"), pytest.param([2, "answer", 0], DUMMY_LIST, DUMMY_LIST[2]["answer"][0], id="24"), pytest.param( [2, "answer", 0, "forty-two"], DUMMY_LIST, DUMMY_LIST[2]["answer"][0]["forty-two"], id="25", ), pytest.param( [2, "answer", 0, "forty-two", 0], DUMMY_LIST, DUMMY_LIST[2]["answer"][0]["forty-two"][0], id="26", ), pytest.param( [2, "answer", 0, "forty-two", 1], DUMMY_LIST, DUMMY_LIST[2]["answer"][0]["forty-two"][1], id="27", ), pytest.param( [2, "answer", 0, "forty-two", 2], DUMMY_LIST, DUMMY_LIST[2]["answer"][0]["forty-two"][2], id="28", ), pytest.param( [], "this is a string that should be returned as is, ignoring path.", "this is a string that should be returned as is, ignoring path.", id="29", ), pytest.param( [2, "answer", 0, "forty-two", 2], "this is a string that should be returned as is, ignoring path.", "this is a string that should be returned as is, ignoring path.", id="30", ), ), ) def test_seek( yaml_path: list[int | str], data: MutableMapping[str, Any] | MutableSequence[Any] | str, expected: Any, ) -> None: """Ensure TransformMixin.seek() retrieves the correct data.""" actual = TransformMixin.seek(yaml_path, data) assert actual == expected ���������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_transformer.py�����������������������������������������������0000664�0000000�0000000�00000052714�14773473560�0023023�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# cspell:ignore classinfo """Tests for Transformer.""" from __future__ import annotations import builtins import os import shutil from pathlib import Path from typing import TYPE_CHECKING, Any from unittest import mock from unittest.mock import Mock import pytest import ansiblelint.__main__ as main from ansiblelint.app import App from ansiblelint.config import Options from ansiblelint.errors import MatchError from ansiblelint.file_utils import Lintable from ansiblelint.rules import AnsibleLintRule, TransformMixin # noinspection PyProtectedMember from ansiblelint.runner import LintResult, get_matches from ansiblelint.transformer import Transformer if TYPE_CHECKING: from ansiblelint.rules import RulesCollection @pytest.fixture(name="runner_result") def fixture_runner_result( config_options: Options, default_rules_collection: RulesCollection, playbook_str: str, monkeypatch: pytest.MonkeyPatch, ) -> LintResult: """Fixture that runs the Runner to populate a LintResult for a given file.""" # needed for testing transformer when roles/modules are missing: monkeypatch.setenv("ANSIBLE_LINT_NODEPS", "1") config_options.lintables = [playbook_str] result = get_matches(rules=default_rules_collection, options=config_options) return result @pytest.mark.parametrize( ("playbook_str", "matches_count", "transformed", "is_owned_by_ansible"), ( # reuse TestRunner::test_runner test cases to ensure transformer does not mangle matches pytest.param( "examples/playbooks/nomatchestest.yml", 0, False, True, id="nomatchestest", ), pytest.param("examples/playbooks/unicode.yml", 1, False, True, id="unicode"), pytest.param( "examples/playbooks/lots_of_warnings.yml", 993, False, True, id="lots_of_warnings", ), pytest.param("examples/playbooks/become.yml", 0, False, True, id="become"), pytest.param( "examples/playbooks/contains_secrets.yml", 0, False, True, id="contains_secrets", ), pytest.param( "examples/playbooks/vars/empty_vars.yml", 0, False, True, id="empty_vars", ), pytest.param( "examples/playbooks/vars/strings.yml", 0, True, True, id="strings", ), pytest.param("examples/playbooks/vars/empty.yml", 1, False, True, id="empty"), pytest.param("examples/playbooks/fqcn.yml", 3, True, True, id="fqcn"), pytest.param( "examples/playbooks/multi_yaml_doc.yml", 1, False, True, id="multi_yaml_doc", ), pytest.param( "examples/playbooks/transform_command_instead_of_shell.yml", 3, True, True, id="cmd_instead_of_shell", ), pytest.param( "examples/playbooks/transform-deprecated-local-action.yml", 1, True, True, id="dep_local_action", ), pytest.param( "examples/playbooks/transform-block-indentation-indicator.yml", 0, True, True, id="multiline_msg_with_indent_indicator", ), pytest.param( "examples/playbooks/transform-jinja.yml", 7, True, True, id="jinja_spacing", ), pytest.param( "examples/playbooks/transform-no-jinja-when.yml", 3, True, True, id="no_jinja_when", ), pytest.param( "examples/playbooks/vars/transform_nested_data.yml", 3, True, True, id="nested", ), pytest.param( "examples/playbooks/transform-key-order.yml", 6, True, True, id="key_order_transform", ), pytest.param( "examples/playbooks/transform-no-free-form.yml", 5, True, True, id="no_free_form_transform", ), pytest.param( "examples/playbooks/transform-partial-become.yml", 4, True, True, id="partial_become", ), pytest.param( "examples/playbooks/transform-key-order-play.yml", 1, True, True, id="key_order_play_transform", ), pytest.param( "examples/playbooks/transform-key-order-block.yml", 1, True, True, id="key_order_block_transform", ), pytest.param( "examples/.github/workflows/sample.yml", 0, False, False, id="github-workflow", ), pytest.param( "examples/playbooks/invalid-transform.yml", 1, False, True, id="invalid_transform", ), pytest.param( "examples/roles/name_prefix/tasks/test.yml", 1, True, True, id="name_casing_prefix", ), pytest.param( "examples/roles/name_casing/tasks/main.yml", 2, True, True, id="name_case_roles", ), pytest.param( "examples/playbooks/4114/transform-with-missing-role-and-modules.yml", 1, True, True, id="4114", ), pytest.param( "examples/playbooks/transform-name.yml", 3, True, True, id="name-capitalize", ), ), ) @mock.patch.dict(os.environ, {"ANSIBLE_LINT_WRITE_TMP": "1"}, clear=True) def test_transformer( # pylint: disable=too-many-arguments,too-many-positional-arguments config_options: Options, playbook_str: str, runner_result: LintResult, transformed: bool, is_owned_by_ansible: bool, matches_count: int, ) -> None: """Test that transformer can go through any corner cases. Based on TestRunner::test_runner """ # test ability to detect is_owned_by_ansible assert Lintable(playbook_str).is_owned_by_ansible() == is_owned_by_ansible playbook = Path(playbook_str) config_options.write_list = ["all"] matches = runner_result.matches assert len(matches) == matches_count transformer = Transformer(result=runner_result, options=config_options) transformer.run() orig_content = playbook.read_text(encoding="utf-8") if transformed: expected_content = playbook.with_suffix( f".transformed{playbook.suffix}", ).read_text(encoding="utf-8") transformed_content = playbook.with_suffix(f".tmp{playbook.suffix}").read_text( encoding="utf-8", ) assert orig_content != transformed_content assert expected_content == transformed_content playbook.with_suffix(f".tmp{playbook.suffix}").unlink() @pytest.mark.parametrize( ("write_list", "expected"), ( # 1 item (["all"], {"all"}), (["none"], {"none"}), (["rule-id"], {"rule-id"}), # 2 items (["all", "all"], {"all"}), (["all", "none"], {"none"}), (["all", "rule-id"], {"all"}), (["none", "all"], {"all"}), (["none", "none"], {"none"}), (["none", "rule-id"], {"rule-id"}), (["rule-id", "all"], {"all"}), (["rule-id", "none"], {"none"}), (["rule-id", "rule-id"], {"rule-id"}), # 3 items (["all", "all", "all"], {"all"}), (["all", "all", "none"], {"none"}), (["all", "all", "rule-id"], {"all"}), (["all", "none", "all"], {"all"}), (["all", "none", "none"], {"none"}), (["all", "none", "rule-id"], {"rule-id"}), (["all", "rule-id", "all"], {"all"}), (["all", "rule-id", "none"], {"none"}), (["all", "rule-id", "rule-id"], {"all"}), (["none", "all", "all"], {"all"}), (["none", "all", "none"], {"none"}), (["none", "all", "rule-id"], {"all"}), (["none", "none", "all"], {"all"}), (["none", "none", "none"], {"none"}), (["none", "none", "rule-id"], {"rule-id"}), (["none", "rule-id", "all"], {"all"}), (["none", "rule-id", "none"], {"none"}), (["none", "rule-id", "rule-id"], {"rule-id"}), (["rule-id", "all", "all"], {"all"}), (["rule-id", "all", "none"], {"none"}), (["rule-id", "all", "rule-id"], {"all"}), (["rule-id", "none", "all"], {"all"}), (["rule-id", "none", "none"], {"none"}), (["rule-id", "none", "rule-id"], {"rule-id"}), (["rule-id", "rule-id", "all"], {"all"}), (["rule-id", "rule-id", "none"], {"none"}), (["rule-id", "rule-id", "rule-id"], {"rule-id"}), ), ) def test_effective_write_set(write_list: list[str], expected: set[str]) -> None: """Make sure effective_write_set handles all/none keywords correctly.""" actual = Transformer.effective_write_set(write_list) assert actual == expected @pytest.mark.parametrize( ("write_list", "write_exclude_list", "rules"), ( ( ["all"], ["none"], [("rule-id", True), ("rule1", True), ("rule-03", True)], ), ( ["all"], ["all"], [("rule-id", False), ("rule1", False), ("rule-03", False)], ), ( ["none"], ["none"], [("rule-id", False), ("rule1", False), ("rule-03", False)], ), ( ["none"], ["all"], [("rule-id", False), ("rule1", False), ("rule-03", False)], ), ( ["rule-id"], ["none"], [("rule-id", True), ("rule1", False), ("rule-03", False)], ), ( ["rule-id"], ["all"], [("rule-id", False), ("rule1", False), ("rule-03", False)], ), ), ) def test_write_exclude_list( write_list: list[str], write_exclude_list: list[str], rules: list[tuple[str, bool]], ) -> None: """Test item matching write_exclude_list are excluded correctly.""" matches: list[MatchError] = [] class TestRule(AnsibleLintRule, TransformMixin): """Dummy class for transformable rules.""" for rule_id, transform_expected in rules: rule = Mock(spec=TestRule) rule.id = rule_id rule.tags = [] rule.transform_expected = transform_expected match = MatchError(rule=rule) matches.append(match) transformer = Transformer( LintResult(matches, set()), Options(write_list=write_list, write_exclude_list=write_exclude_list), ) # noinspection PyTypeChecker Transformer._do_transforms(transformer, Mock(), "", False, matches) # noqa: SLF001 for match in matches: if match.rule.transform_expected: # type: ignore[attr-defined] match.rule.transform.assert_called() # type: ignore[attr-defined] else: match.rule.transform.assert_not_called() # type: ignore[attr-defined] def test_pruned_err_after_fix(monkeypatch: pytest.MonkeyPatch, tmpdir: Path) -> None: """Test that pruned errors are not reported after fixing. :param monkeypatch: Monkeypatch :param tmpdir: Temporary directory """ file = Path("examples/playbooks/transform-jinja.yml") source = Path.cwd() / file dest = tmpdir / source.name shutil.copyfile(source, dest) monkeypatch.setattr("sys.argv", ["ansible-lint", str(dest), "--fix=all"]) fix_called = False orig_fix = main.fix def test_fix( runtime_options: Options, result: LintResult, rules: RulesCollection, ) -> None: """Wrap main.fix to check if it was called and match count is correct. :param runtime_options: Runtime options :param result: Lint result :param rules: Rules collection """ nonlocal fix_called fix_called = True assert len(result.matches) == 7 orig_fix(runtime_options, result, rules) report_called = False class TestApp(App): """Wrap App to check if it was called and match count is correct.""" def report_outcome( self: TestApp, result: LintResult, *, mark_as_success: bool = False, ) -> int: """Wrap App.report_outcome to check if it was called and match count is correct. :param result: Lint result :param mark_as_success: Mark as success :returns: Exit code """ nonlocal report_called report_called = True assert len(result.matches) == 1 return super().report_outcome(result, mark_as_success=mark_as_success) monkeypatch.setattr("ansiblelint.__main__.fix", test_fix) monkeypatch.setattr("ansiblelint.app.App", TestApp) # disable the App() caching because we cannot prevent the initial initialization from happening monkeypatch.setattr("ansiblelint.app._CACHED_APP", None) main.main() assert fix_called assert report_called class TransformTests: """A carrier for some common test constants.""" FILE_NAME = "examples/playbooks/transform-no-free-form.yml" FILE_TYPE = "playbook" LINENO = 5 ID = "no-free-form" MATCH_TYPE = "task" VERSION_PART = "version=(1, 1)" @classmethod def match_id(cls) -> str: """Generate a match id. :returns: Match id string """ return f"{cls.ID}/{cls.MATCH_TYPE} {cls.FILE_NAME}:{cls.LINENO}" @classmethod def rewrite_part(cls) -> str: """Generate a rewrite part. :returns: Rewrite part string """ return f"{cls.FILE_NAME} ({cls.FILE_TYPE}), {cls.VERSION_PART}" @pytest.fixture(name="test_result") def fixture_test_result( config_options: Options, default_rules_collection: RulesCollection, ) -> tuple[LintResult, Options]: """Fixture that runs the Runner to populate a LintResult for a given file. The results are confirmed and a limited to a single match. :param config_options: Configuration options :param default_rules_collection: Default rules collection :returns: Tuple of LintResult and Options """ config_options.write_list = [TransformTests.ID] config_options.lintables = [TransformTests.FILE_NAME] result = get_matches(rules=default_rules_collection, options=config_options) match = result.matches[0] def write(*_args: Any, **_kwargs: Any) -> None: """Don't rewrite the test fixture. :param _args: Arguments :param _kwargs: Keyword arguments """ setattr(match.lintable, "write", write) # noqa: B010 assert match.rule.id == TransformTests.ID assert match.filename == TransformTests.FILE_NAME assert match.lineno == TransformTests.LINENO assert match.match_type == TransformTests.MATCH_TYPE result.matches = [match] return result, config_options def test_transform_na( caplog: pytest.LogCaptureFixture, monkeypatch: pytest.MonkeyPatch, test_result: tuple[LintResult, Options], ) -> None: """Test the transformer is not available. :param caplog: Log capture fixture :param monkeypatch: Monkeypatch :param test_result: Test result fixture """ result = test_result[0] options = test_result[1] isinstance_ = builtins.isinstance called = False def mp_isinstance(t_object: Any, classinfo: type) -> bool: if classinfo is TransformMixin: nonlocal called called = True return False return isinstance_(t_object, classinfo) monkeypatch.setattr(builtins, "isinstance", mp_isinstance) transformer = Transformer(result=result, options=options) with caplog.at_level(10): transformer.run() assert called logs = [record for record in caplog.records if record.module == "transformer"] assert len(logs) == 2 log_0 = f"{transformer.FIX_NA_MSG} {TransformTests.match_id()}" assert logs[0].message == log_0 assert logs[0].levelname == "DEBUG" log_1 = f"{transformer.DUMP_MSG} {TransformTests.rewrite_part()}" assert logs[1].message == log_1 assert logs[1].levelname == "DEBUG" def test_transform_no_tb( caplog: pytest.LogCaptureFixture, test_result: tuple[LintResult, Options], ) -> None: """Test the transformer does not traceback. :param caplog: Log capture fixture :param test_result: Test result fixture :raises RuntimeError: If the rule is not a TransformMixin """ result = test_result[0] options = test_result[1] exception_msg = "FixFailure" def transform(*_args: Any, **_kwargs: Any) -> None: """Raise an exception for the transform call. :raises RuntimeError: Always """ raise RuntimeError(exception_msg) if isinstance(result.matches[0].rule, TransformMixin): setattr(result.matches[0].rule, "transform", transform) # noqa: B010 else: err = "Rule is not a TransformMixin" raise TypeError(err) transformer = Transformer(result=result, options=options) with caplog.at_level(10): transformer.run() logs = [record for record in caplog.records if record.module == "transformer"] assert len(logs) == 5 log_0 = f"{transformer.FIX_APPLY_MSG} {TransformTests.match_id()}" assert logs[0].message == log_0 assert logs[0].levelname == "DEBUG" log_1 = f"{transformer.FIX_FAILED_MSG} {TransformTests.match_id()}" assert logs[1].message == log_1 assert logs[1].levelname == "ERROR" log_2 = exception_msg assert logs[2].message == log_2 assert logs[2].levelname == "ERROR" log_3 = f"{transformer.FIX_ISSUE_MSG}" assert logs[3].message == log_3 assert logs[3].levelname == "ERROR" log_4 = f"{transformer.DUMP_MSG} {TransformTests.rewrite_part()}" assert logs[4].message == log_4 assert logs[4].levelname == "DEBUG" def test_transform_applied( caplog: pytest.LogCaptureFixture, test_result: tuple[LintResult, Options], ) -> None: """Test the transformer is applied. :param caplog: Log capture fixture :param test_result: Test result fixture """ result = test_result[0] options = test_result[1] transformer = Transformer(result=result, options=options) with caplog.at_level(10): transformer.run() logs = [record for record in caplog.records if record.module == "transformer"] assert len(logs) == 3 log_0 = f"{transformer.FIX_APPLY_MSG} {TransformTests.match_id()}" assert logs[0].message == log_0 assert logs[0].levelname == "DEBUG" log_1 = f"{transformer.FIX_APPLIED_MSG} {TransformTests.match_id()}" assert logs[1].message == log_1 assert logs[1].levelname == "DEBUG" log_2 = f"{transformer.DUMP_MSG} {TransformTests.rewrite_part()}" assert logs[2].message == log_2 assert logs[2].levelname == "DEBUG" def test_transform_not_enabled( caplog: pytest.LogCaptureFixture, test_result: tuple[LintResult, Options], ) -> None: """Test the transformer is not enabled. :param caplog: Log capture fixture :param test_result: Test result fixture """ result = test_result[0] options = test_result[1] options.write_list = [] transformer = Transformer(result=result, options=options) with caplog.at_level(10): transformer.run() logs = [record for record in caplog.records if record.module == "transformer"] assert len(logs) == 2 log_0 = f"{transformer.FIX_NE_MSG} {TransformTests.match_id()}" assert logs[0].message == log_0 assert logs[0].levelname == "DEBUG" log_1 = f"{transformer.DUMP_MSG} {TransformTests.rewrite_part()}" assert logs[1].message == log_1 assert logs[1].levelname == "DEBUG" def test_transform_not_applied( caplog: pytest.LogCaptureFixture, test_result: tuple[LintResult, Options], ) -> None: """Test the transformer is not applied. :param caplog: Log capture fixture :param test_result: Test result fixture :raises RuntimeError: If the rule is not a TransformMixin """ result = test_result[0] options = test_result[1] called = False def transform(match: MatchError, *_args: Any, **_kwargs: Any) -> None: """Do not apply the transform. :param match: Match object :param _args: Arguments :param _kwargs: Keyword arguments """ nonlocal called called = True match.fixed = False if isinstance(result.matches[0].rule, TransformMixin): setattr(result.matches[0].rule, "transform", transform) # noqa: B010 else: err = "Rule is not a TransformMixin" raise TypeError(err) transformer = Transformer(result=result, options=options) with caplog.at_level(10): transformer.run() assert called logs = [record for record in caplog.records if record.module == "transformer"] assert len(logs) == 3 log_0 = f"{transformer.FIX_APPLY_MSG} {TransformTests.match_id()}" assert logs[0].message == log_0 assert logs[0].levelname == "DEBUG" log_1 = f"{transformer.FIX_NOT_APPLIED_MSG} {TransformTests.match_id()}" assert logs[1].message == log_1 assert logs[1].levelname == "ERROR" log_2 = f"{transformer.DUMP_MSG} {TransformTests.rewrite_part()}" assert logs[2].message == log_2 assert logs[2].levelname == "DEBUG" ����������������������������������������������������ansible-ansible-lint-c16f018/test/test_utils.py�����������������������������������������������������0000664�0000000�0000000�00000043521�14773473560�0021615�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Copyright (c) 2013-2014 Will Thames <will@thames.id.au> # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. """Tests for generic utility functions.""" from __future__ import annotations import logging import subprocess import sys from pathlib import Path from typing import TYPE_CHECKING, Any import pytest from ansible.utils.sentinel import Sentinel from ansible_compat.runtime import Runtime from ansiblelint import cli, constants, utils from ansiblelint.__main__ import initialize_logger from ansiblelint.cli import get_rules_dirs from ansiblelint.constants import RC from ansiblelint.file_utils import Lintable, cwd from ansiblelint.runner import Runner from ansiblelint.testing import run_ansible_lint from ansiblelint.types import AnsibleMapping, AnsibleSequence if TYPE_CHECKING: from collections.abc import Sequence from _pytest.capture import CaptureFixture from _pytest.logging import LogCaptureFixture from _pytest.monkeypatch import MonkeyPatch from ansiblelint.rules import RulesCollection runtime = Runtime(require_module=True) @pytest.mark.parametrize( ("string", "expected_args", "expected_kwargs"), ( pytest.param("", [], {}, id="a"), pytest.param("a=1", [], {"a": "1"}, id="b"), pytest.param("hello a=1", ["hello"], {"a": "1"}, id="c"), pytest.param( "whatever bobbins x=y z=x c=3", ["whatever", "bobbins"], {"x": "y", "z": "x", "c": "3"}, id="more_than_one_arg", ), pytest.param( "command chdir=wxy creates=zyx tar xzf zyx.tgz", ["command", "tar", "xzf", "zyx.tgz"], {"chdir": "wxy", "creates": "zyx"}, id="command_with_args", ), pytest.param( "{{ varset }}.yml", ["{{ varset }}.yml"], {}, id="x", ), pytest.param( "foo bar.yml", ["foo bar.yml"], {}, id="path-with-spaces", ), ), ) def test_tokenize( string: str, expected_args: Sequence[str], expected_kwargs: dict[str, Any], ) -> None: """Test that tokenize works for different input types.""" (args, kwargs) = utils.tokenize(string) assert args == expected_args assert kwargs == expected_kwargs @pytest.mark.parametrize( ("reference_form", "alternate_forms"), ( pytest.param( {"name": "hello", "action": "command chdir=abc echo hello world"}, ({"name": "hello", "command": "chdir=abc echo hello world"},), id="simple_command", ), pytest.param( {"git": {"version": "abc"}, "args": {"repo": "blah", "dest": "xyz"}}, ( {"git": {"version": "abc", "repo": "blah", "dest": "xyz"}}, {"git": "version=abc repo=blah dest=xyz"}, { "git": None, "args": {"repo": "blah", "dest": "xyz", "version": "abc"}, }, ), id="args", ), ), ) def test_normalize( reference_form: dict[str, Any], alternate_forms: tuple[dict[str, Any]], ) -> None: """Test that tasks specified differently are normalized same way.""" task = utils.Task(reference_form, filename="tasks.yml") normal_form = task._normalize_task() # noqa: SLF001 for form in alternate_forms: task2 = utils.Task(form, filename="tasks.yml") assert normal_form == task2._normalize_task() # noqa: SLF001 def test_normalize_complex_command() -> None: """Test that tasks specified differently are normalized same way.""" task1 = utils.Task( { "name": "hello", "action": {"module": "pip", "name": "df", "editable": "false"}, }, filename="tasks.yml", ) task2 = utils.Task( {"name": "hello", "pip": {"name": "df", "editable": "false"}}, filename="tasks.yml", ) task3 = utils.Task( {"name": "hello", "pip": "name=df editable=false"}, filename="tasks.yml", ) task4 = utils.Task( {"name": "hello", "action": "pip name=df editable=false"}, filename="tasks.yml", ) assert task1._normalize_task() == task2._normalize_task() # noqa: SLF001 assert task2._normalize_task() == task3._normalize_task() # noqa: SLF001 assert task3._normalize_task() == task4._normalize_task() # noqa: SLF001 @pytest.mark.parametrize( ("task_raw", "expected_form"), ( pytest.param( { "name": "ensure apache is at the latest version", "yum": {"name": "httpd", "state": "latest"}, }, { "delegate_to": Sentinel, "name": "ensure apache is at the latest version", "action": { "__ansible_module__": "yum", "__ansible_module_original__": "yum", "name": "httpd", "state": "latest", }, }, id="0", ), pytest.param( { "name": "Attempt and graceful roll back", "block": [ { "name": "Install httpd and memcached", "ansible.builtin.yum": ["httpd", "memcached"], "state": "present", }, ], }, { "name": "Attempt and graceful roll back", "block": [ { "name": "Install httpd and memcached", "ansible.builtin.yum": ["httpd", "memcached"], "state": "present", }, ], "action": { "__ansible_module__": "block/always/rescue", "__ansible_module_original__": "block/always/rescue", }, }, id="1", ), ), ) def test_normalize_task_v2( task_raw: dict[str, Any], expected_form: dict[str, Any], ) -> None: """Check that it normalizes task and returns the expected form.""" task = utils.Task(task_raw) assert utils.normalize_task_v2(task) == expected_form def test_extract_from_list() -> None: """Check that tasks get extracted from blocks if present.""" block = { "block": [{"tasks": {"name": "hello", "command": "whoami"}}], "test_none": None, "test_string": "foo", } blocks = AnsibleSequence([block]) test_list = utils.extract_from_list(blocks, ["block"]) test_none = utils.extract_from_list(blocks, ["test_none"]) assert list(block["block"]) == test_list # type: ignore[arg-type] assert not test_none with pytest.raises(RuntimeError): utils.extract_from_list(blocks, ["test_string"]) def test_extract_from_list_recursive() -> None: """Check that tasks get extracted from blocks if present.""" block = AnsibleMapping({ "block": [{"block": [{"name": "hello", "command": "whoami"}]}], }) blocks = AnsibleSequence([block]) test_list = utils.extract_from_list(blocks, ["block"]) assert list(block["block"]) == test_list test_list_recursive = utils.extract_from_list(blocks, ["block"], recursive=True) assert block["block"] + block["block"][0]["block"] == test_list_recursive @pytest.mark.parametrize( ("template", "output"), ( pytest.param("{{ playbook_dir }}", "/a/b/c", id="simple"), # Does not work the same with ansible 2.19 with data tagging # pytest.param( # "{{ 'hello' | doesnotexist }}", # "hello", # newer implementation ignores unknown filters # id="unknown_filter", # ), pytest.param( "{{ hello | to_json }}", "{{ hello | to_json }}", id="to_json_filter_on_undefined_variable", ), pytest.param( "{{ hello | to_nice_yaml }}", "{{ hello | to_nice_yaml }}", id="to_nice_yaml_filter_on_undefined_variable", ), ), ) def test_template(template: str, output: str) -> None: """Verify that resolvable template vars and filters get rendered.""" result = utils.template( basedir=Path("/base/dir"), value=template, variables={"playbook_dir": "/a/b/c"}, fail_on_error=False, ) assert result == output def test_task_to_str_unicode() -> None: """Ensure that extracting messages from tasks preserves Unicode.""" task = utils.Task({"fail": {"msg": "unicode é ô à"}}, filename="filename.yml") assert str(task) == "fail msg=unicode é ô à" def test_logger_debug(caplog: LogCaptureFixture) -> None: """Test that the double verbosity arg causes logger to be DEBUG.""" options = cli.get_config(["-vv"]) initialize_logger(options.verbosity) expected_info = ( "ansiblelint.__main__", logging.DEBUG, "Logging initialized to level 10", ) assert expected_info in caplog.record_tuples def test_cli_auto_detect(capfd: CaptureFixture[str]) -> None: """Test that run without arguments it will detect and lint the entire repository.""" cmd = [ sys.executable, "-m", "ansiblelint", "-x", "schema", # exclude schema as our test file would fail it "-v", "-p", "--nocolor", "--offline", "--exclude=examples", "--exclude=test", "--exclude=src", "--exclude=collections", "--exclude=.github", ] result = subprocess.run(cmd, check=False).returncode # We de expect to fail on our own repo due to test examples we have assert result == RC.VIOLATIONS_FOUND out, err = capfd.readouterr() # An expected rule match from our examples assert any( x in out for x in ("playbook.yml:6: name[casing]", "playbook.yml:6:13: name[casing]") ) # assures that our ansible-lint config exclude was effective in excluding github files assert "Identified: .github/" not in out # assures that we can parse playbooks as playbooks assert "Identified: test/test/always-run-success.yml" not in err assert "Executing syntax check on playbook playbook.yml" in err def test_is_playbook() -> None: """Verify that we can detect a playbook as a playbook.""" assert utils.is_playbook("examples/playbooks/always-run-success.yml") @pytest.mark.parametrize( "exclude", (pytest.param("foo", id="1"), pytest.param("foo/", id="2")), ) def test_auto_detect_exclude(tmp_path: Path, exclude: str) -> None: """Verify that exclude option can be used to narrow down detection.""" with cwd(tmp_path): subprocess.check_output( "git init", stderr=subprocess.STDOUT, text=True, shell=True, cwd=tmp_path, ) (tmp_path / "foo").mkdir() (tmp_path / "bar").mkdir() (tmp_path / "foo" / "playbook.yml").touch() (tmp_path / "bar" / "playbook.yml").touch() options = cli.get_config(["--exclude", exclude]) options.cwd = tmp_path result = utils.get_lintables(options) assert result == [Lintable("bar/playbook.yml", kind="playbook")] # now we also test with .gitignore exclude approach (tmp_path / ".gitignore").write_text(f".gitignore\n{exclude}\n") options = cli.get_config([]) options.cwd = tmp_path result = utils.get_lintables(options) assert result == [Lintable("bar/playbook.yml", kind="playbook")] _DEFAULT_RULEDIRS = [constants.DEFAULT_RULESDIR] _CUSTOM_RULESDIR = Path(__file__).parent / "custom_rules" _CUSTOM_RULEDIRS = [ _CUSTOM_RULESDIR / "example_inc", _CUSTOM_RULESDIR / "example_com", ] @pytest.mark.parametrize( ("user_ruledirs", "use_default", "expected"), ( ([], True, _DEFAULT_RULEDIRS), ([], False, _DEFAULT_RULEDIRS), (_CUSTOM_RULEDIRS, True, _CUSTOM_RULEDIRS + _DEFAULT_RULEDIRS), (_CUSTOM_RULEDIRS, False, _CUSTOM_RULEDIRS), ), ) def test_get_rules_dirs( user_ruledirs: list[Path], use_default: bool, expected: list[Path], ) -> None: """Test it returns expected dir lists.""" assert get_rules_dirs(user_ruledirs, use_default=use_default) == expected @pytest.mark.parametrize( ("user_ruledirs", "use_default", "expected"), ( ([], True, sorted(_CUSTOM_RULEDIRS) + _DEFAULT_RULEDIRS), ([], False, sorted(_CUSTOM_RULEDIRS) + _DEFAULT_RULEDIRS), ( _CUSTOM_RULEDIRS, True, _CUSTOM_RULEDIRS + sorted(_CUSTOM_RULEDIRS) + _DEFAULT_RULEDIRS, ), (_CUSTOM_RULEDIRS, False, _CUSTOM_RULEDIRS), ), ) def test_get_rules_dirs_with_custom_rules( user_ruledirs: list[Path], use_default: bool, expected: list[Path], monkeypatch: MonkeyPatch, ) -> None: """Test it returns expected dir lists when custom rules exist.""" monkeypatch.setenv(constants.CUSTOM_RULESDIR_ENVVAR, str(_CUSTOM_RULESDIR)) assert get_rules_dirs(user_ruledirs, use_default=use_default) == expected def test_find_children(default_rules_collection: RulesCollection) -> None: """Verify correct function of find_children().""" Runner( rules=default_rules_collection, ).find_children(Lintable("examples/playbooks/find_children.yml")) def test_find_children_in_task(default_rules_collection: RulesCollection) -> None: """Verify correct function of find_children() in tasks.""" Runner( Lintable("examples/playbooks/tasks/bug-2875.yml"), rules=default_rules_collection, ).run() @pytest.mark.parametrize( ("file", "names", "positions"), ( pytest.param( "examples/playbooks/task_in_list-0.yml", ["A", "B", "C", "D", "E", "F", "G"], [ ".[0].tasks[0]", ".[0].tasks[1]", ".[0].pre_tasks[0]", ".[0].post_tasks[0]", ".[0].post_tasks[0].block[0]", ".[0].post_tasks[0].rescue[0]", ".[0].post_tasks[0].always[0]", ], id="0", ), ), ) def test_task_in_list(file: str, names: list[str], positions: list[str]) -> None: """Check that tasks get extracted from blocks if present.""" lintable = Lintable(file) assert lintable.kind tasks = list( utils.task_in_list(data=lintable.data, file=lintable, kind=lintable.kind), ) assert len(tasks) == len(names) for index, task in enumerate(tasks): assert task.name == names[index] assert task.position == positions[index] def test_find_children_in_module(default_rules_collection: RulesCollection) -> None: """Verify correct function of find_children() in tasks.""" lintable = Lintable("plugins/modules/fake_module.py") children = Runner( rules=default_rules_collection, ).find_children(lintable) assert len(children) == 1 child = children[0] # Parent is a python file assert lintable.base_kind == "text/python" # Child correctly looks like a YAML file assert child.base_kind == "text/yaml" assert child.content.startswith("---") def test_find_children_in_playbook(default_rules_collection: RulesCollection) -> None: """Verify correct function of find_children() in playbooks.""" lintable = Lintable("examples/playbooks/bug-4095.yml") children = Runner( rules=default_rules_collection, ).find_children(lintable) assert len(children) == 1 assert children[0].role == "bug4095" def test_include_children_load_playbook_failed_syntax_check() -> None: """Verify include_children() logs playbook failed to load due to syntax-check.""" result = run_ansible_lint( Path("playbooks/import-failed-syntax-check.yml"), cwd=Path(__file__).resolve().parent.parent / "examples", ) assert ( "Failed to load syntax-error.yml playbook due to failing syntax check." in result.stderr ) def test_import_playbook_children() -> None: """Verify import_playbook_children().""" result = run_ansible_lint( Path("playbooks/import_playbook_fqcn.yml"), cwd=Path(__file__).resolve().parent.parent / "examples", env={ "ANSIBLE_COLLECTIONS_PATH": "../collections", }, ) assert "Failed to find local.testcollection.foo playbook." not in result.stderr assert ( "Failed to load local.testcollection.foo playbook due to failing syntax check." not in result.stderr ) def test_import_playbook_children_subdirs() -> None: """Verify import_playbook_children() when playbook is in a subdirectory.""" result = run_ansible_lint( Path("playbooks/import_playbook_fqcn.yml"), cwd=Path(__file__).resolve().parent.parent / "examples", env={ "ANSIBLE_COLLECTIONS_PATH": "../collections", }, ) assert ( "Failed to find local.testcollection.test.bar.foo playbook." not in result.stderr ) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_verbosity.py�������������������������������������������������0000664�0000000�0000000�00000005313�14773473560�0022500�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests related to our logging/verbosity setup.""" from __future__ import annotations from pathlib import Path import pytest from ansiblelint.testing import run_ansible_lint from ansiblelint.text import strip_ansi_escape # substrs is a list of tuples, where: # component 1 is the substring in question # component 2 is whether or not to invert ("NOT") the match @pytest.mark.parametrize( ("verbosity", "substrs"), ( pytest.param( "", [ ("WARNING Listing 1 violation(s) that are fatal", False), ("DEBUG ", True), ("INFO ", True), ], id="default", ), pytest.param( "-q", [ ("WARNING ", True), ("DEBUG ", True), ("INFO ", True), ], id="q", ), pytest.param( "-qq", [ ("WARNING ", True), ("DEBUG ", True), ("INFO ", True), ], id="qq", ), pytest.param( "-v", [ ("WARNING Listing 1 violation(s) that are fatal", False), ("INFO Set ANSIBLE_LIBRARY=", False), ("DEBUG ", True), ], id="v", ), pytest.param( "-vv", [ ("WARNING Listing 1 violation(s) that are fatal", False), ("INFO Set ANSIBLE_LIBRARY=", False), ], id="really-loquacious", ), pytest.param( "-vv", [ ("WARNING Listing 1 violation(s) that are fatal", False), ("INFO Set ANSIBLE_LIBRARY=", False), ], id="vv", ), ), ) def test_verbosity( verbosity: str, substrs: list[tuple[str, bool]], project_path: Path, ) -> None: """Checks that our default verbosity displays (only) warnings.""" # Piggyback off the .yamllint in the root of the repo, just for testing. # We'll "override" it with the one in the fixture, to produce a warning. fakerole = Path() / "test" / "fixtures" / "verbosity-tests" if verbosity: result = run_ansible_lint(verbosity, str(fakerole), cwd=project_path) else: result = run_ansible_lint(str(fakerole), cwd=project_path) result.stderr = strip_ansi_escape(result.stderr) result.stdout = strip_ansi_escape(result.stdout) assert result.returncode == 2, result for substr, invert in substrs: if invert: assert substr not in result.stderr, result.stderr else: assert substr in result.stderr, result.stderr ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_vulture.py���������������������������������������������������0000664�0000000�0000000�00000002703�14773473560�0022160�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Used only by vulture to determine reachable code.""" # ExampleComRule from ansiblelint.rules.args import ArgsRule from ansiblelint.rules.deprecated_local_action import TaskNoLocalActionRule from ansiblelint.rules.key_order import KeyOrderRule from ansiblelint.rules.latest import LatestRule from ansiblelint.rules.literal_compare import ComparisonToLiteralBoolRule from ansiblelint.rules.meta_incorrect import MetaChangeFromDefaultRule from ansiblelint.rules.meta_video_links import MetaVideoLinksRule from ansiblelint.rules.no_handler import UseHandlerRatherThanWhenChangedRule from ansiblelint.rules.no_relative_paths import RoleRelativePath from ansiblelint.rules.no_tabs import NoTabsRule from ansiblelint.rules.risky_file_permissions import MissingFilePermissionsRule from ansiblelint.rules.syntax_check import AnsibleSyntaxCheckRule from test.custom_rules.example_com.example_com_rule import ExampleComRule from test.custom_rules.example_inc.custom_rule import CustomRule from test.rules.fixtures.unset_variable_matcher import UnsetVariableMatcherRule __all__ = [ "AnsibleSyntaxCheckRule", "ArgsRule", "ComparisonToLiteralBoolRule", "CustomRule", "ExampleComRule", "KeyOrderRule", "LatestRule", "MetaChangeFromDefaultRule", "MetaVideoLinksRule", "MissingFilePermissionsRule", "NoTabsRule", "RoleRelativePath", "TaskNoLocalActionRule", "UnsetVariableMatcherRule", "UseHandlerRatherThanWhenChangedRule", ] �������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_with_skip_tagid.py�������������������������������������������0000664�0000000�0000000�00000003574�14773473560�0023632�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests related to skip tag id.""" from ansiblelint.rules import RulesCollection from ansiblelint.rules.yaml_rule import YamllintRule from ansiblelint.runner import Runner from ansiblelint.testing import run_ansible_lint FILE = "examples/playbooks/with-skip-tag-id.yml" collection = RulesCollection() collection.register(YamllintRule()) def test_negative_no_param() -> None: """Negative test no param.""" bad_runner = Runner(FILE, rules=collection) errs = bad_runner.run() assert len(errs) > 0 def test_negative_with_id() -> None: """Negative test with_id.""" with_id = "yaml" bad_runner = Runner(FILE, rules=collection, tags=frozenset([with_id])) errs = bad_runner.run() assert len(errs) == 1 def test_negative_with_tag() -> None: """Negative test with_tag.""" with_tag = "yaml[trailing-spaces]" bad_runner = Runner(FILE, rules=collection, tags=frozenset([with_tag])) errs = bad_runner.run() assert len(errs) == 1 def test_positive_skip_id() -> None: """Positive test skip_id.""" skip_id = "yaml" good_runner = Runner(FILE, rules=collection, skip_list=[skip_id]) assert good_runner.run() == [] def test_positive_skip_id_2() -> None: """Positive test skip_id.""" skip_id = "key-order" good_runner = Runner(FILE, rules=collection, tags=frozenset([skip_id])) assert good_runner.run() == [] def test_positive_skip_tag() -> None: """Positive test skip_tag.""" skip_tag = "yaml[trailing-spaces]" good_runner = Runner(FILE, rules=collection, skip_list=[skip_tag]) assert good_runner.run() == [] def test_run_skip_rule() -> None: """Test that we can skip a rule with -x.""" result = run_ansible_lint( "-x", "name[casing]", "examples/playbooks/rule-name-casing.yml", executable="ansible-lint", ) assert result.returncode == 0 assert not result.stdout ������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/test/test_yaml_utils.py������������������������������������������������0000664�0000000�0000000�00000101337�14773473560�0022637�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������"""Tests for yaml-related utility functions.""" # pylint: disable=too-many-lines from __future__ import annotations from io import StringIO from pathlib import Path from typing import TYPE_CHECKING, Any, cast import pytest from ruamel.yaml.main import YAML from yamllint.linter import run as run_yamllint import ansiblelint.yaml_utils from ansiblelint.file_utils import Lintable, cwd from ansiblelint.utils import task_in_list if TYPE_CHECKING: from ruamel.yaml.comments import CommentedMap, CommentedSeq from ruamel.yaml.emitter import Emitter fixtures_dir = Path(__file__).parent / "fixtures" formatting_before_fixtures_dir = fixtures_dir / "formatting-before" formatting_prettier_fixtures_dir = fixtures_dir / "formatting-prettier" formatting_after_fixtures_dir = fixtures_dir / "formatting-after" @pytest.fixture(name="empty_lintable") def fixture_empty_lintable() -> Lintable: """Return a Lintable with no contents.""" lintable = Lintable("__empty_file__.yaml", content="") return lintable def test_tasks_in_list_empty_file(empty_lintable: Lintable) -> None: """Make sure that task_in_list returns early when files are empty.""" assert empty_lintable.kind assert empty_lintable.path res = list( task_in_list( data=empty_lintable.data, file=empty_lintable, kind=empty_lintable.kind, ), ) assert not res def test_nested_items_path() -> None: """Verify correct function of nested_items_path().""" data = { "foo": "text", "bar": {"some": "text2"}, "fruits": ["apple", "orange"], "answer": [{"forty-two": ["life", "universe", "everything"]}], } items = [ ("foo", "text", []), ("bar", {"some": "text2"}, []), ("some", "text2", ["bar"]), ("fruits", ["apple", "orange"], []), (0, "apple", ["fruits"]), (1, "orange", ["fruits"]), ("answer", [{"forty-two": ["life", "universe", "everything"]}], []), (0, {"forty-two": ["life", "universe", "everything"]}, ["answer"]), ("forty-two", ["life", "universe", "everything"], ["answer", 0]), (0, "life", ["answer", 0, "forty-two"]), (1, "universe", ["answer", 0, "forty-two"]), (2, "everything", ["answer", 0, "forty-two"]), ] assert list(ansiblelint.yaml_utils.nested_items_path(data)) == items @pytest.mark.parametrize( "invalid_data_input", ( "string", 42, 1.234, ("tuple",), {"set"}, # NoneType is no longer include, as we assume we have to ignore it ), ) def test_nested_items_path_raises_typeerror(invalid_data_input: Any) -> None: """Verify non-dict/non-list types make nested_items_path() raises TypeError.""" with pytest.raises(TypeError, match=r"Expected a dict or a list.*"): list(ansiblelint.yaml_utils.nested_items_path(invalid_data_input)) _input_playbook = [ { "name": "It's a playbook", # unambiguous; no quotes needed "tasks": [ { "name": '"fun" task', # should be a single-quoted string "debug": { # ruamel.yaml default to single-quotes # our Emitter defaults to double-quotes "msg": "{{ msg }}", }, }, ], }, ] _SINGLE_QUOTE_WITHOUT_INDENTS = """\ --- - name: It's a playbook tasks: - name: '"fun" task' debug: msg: '{{ msg }}' """ _SINGLE_QUOTE_WITH_INDENTS = """\ --- - name: It's a playbook tasks: - name: '"fun" task' debug: msg: '{{ msg }}' """ _DOUBLE_QUOTE_WITHOUT_INDENTS = """\ --- - name: It's a playbook tasks: - name: '"fun" task' debug: msg: "{{ msg }}" """ _DOUBLE_QUOTE_WITH_INDENTS_EXCEPT_ROOT_LEVEL = """\ --- - name: It's a playbook tasks: - name: '"fun" task' debug: msg: "{{ msg }}" """ @pytest.mark.parametrize( ( "map_indent", "sequence_indent", "sequence_dash_offset", "alternate_emitter", "expected_output", ), ( pytest.param( 2, 2, 0, None, _SINGLE_QUOTE_WITHOUT_INDENTS, id="single_quote_without_indents", ), pytest.param( 2, 4, 2, None, _SINGLE_QUOTE_WITH_INDENTS, id="single_quote_with_indents", ), pytest.param( 2, 2, 0, ansiblelint.yaml_utils.FormattedEmitter, _DOUBLE_QUOTE_WITHOUT_INDENTS, id="double_quote_without_indents", ), pytest.param( 2, 4, 2, ansiblelint.yaml_utils.FormattedEmitter, _DOUBLE_QUOTE_WITH_INDENTS_EXCEPT_ROOT_LEVEL, id="double_quote_with_indents_except_root_level", ), ), ) def test_custom_ruamel_yaml_emitter( map_indent: int, sequence_indent: int, sequence_dash_offset: int, alternate_emitter: Emitter | None, expected_output: str, ) -> None: """Test ``ruamel.yaml.YAML.dump()`` sequence formatting and quotes.""" yaml = YAML(typ="rt") # NB: ruamel.yaml does not have typehints, so mypy complains about everything here. yaml.explicit_start = True yaml.map_indent = map_indent yaml.sequence_indent = sequence_indent yaml.sequence_dash_offset = sequence_dash_offset if alternate_emitter is not None: yaml.Emitter = alternate_emitter # ruamel.yaml only writes to a stream (there is no `dumps` function) with StringIO() as output_stream: yaml.dump(_input_playbook, output_stream) output = output_stream.getvalue() assert output == expected_output def load_yaml_formatting_fixtures(fixture_filename: str) -> tuple[str, str, str]: """Get the contents for the formatting fixture files. To regenerate these fixtures, please run ``pytest --regenerate-formatting-fixtures``. Ideally, prettier should not have to change any ``formatting-after`` fixtures. """ before_path = formatting_before_fixtures_dir / fixture_filename prettier_path = formatting_prettier_fixtures_dir / fixture_filename after_path = formatting_after_fixtures_dir / fixture_filename before_content = before_path.read_text() prettier_content = prettier_path.read_text() formatted_content = after_path.read_text() return before_content, prettier_content, formatted_content @pytest.mark.parametrize( ("before", "after", "version"), ( pytest.param("---\nfoo: bar\n", "---\nfoo: bar\n", None, id="1"), # verify that 'on' is not translated to bool (1.2 behavior) pytest.param("---\nfoo: on\n", "---\nfoo: on\n", None, id="2"), # When version is manually mentioned by us, we expect to output without version directive pytest.param("---\nfoo: on\n", "---\nfoo: on\n", (1, 2), id="3"), pytest.param("---\nfoo: on\n", "---\nfoo: true\n", (1, 1), id="4"), pytest.param("%YAML 1.1\n---\nfoo: on\n", "---\nfoo: true\n", (1, 1), id="5"), # verify that in-line directive takes precedence but dumping strips if we mention a specific version pytest.param("%YAML 1.1\n---\nfoo: on\n", "---\nfoo: true\n", (1, 2), id="6"), # verify that version directive are kept if present pytest.param("%YAML 1.1\n---\nfoo: on\n", "---\nfoo: true\n", None, id="7"), pytest.param( "%YAML 1.2\n---\nfoo: on\n", "%YAML 1.2\n---\nfoo: on\n", None, id="8", ), pytest.param("---\nfoo: YES\n", "---\nfoo: true\n", (1, 1), id="9"), pytest.param("---\nfoo: YES\n", "---\nfoo: YES\n", (1, 2), id="10"), pytest.param("---\nfoo: YES\n", "---\nfoo: YES\n", None, id="11"), pytest.param( "---\n # quoted-strings:\n # quote-type: double\n # required: only-when-needed\n\nignore:\n - secrets.yml\n", "---\n # quoted-strings:\n # quote-type: double\n # required: only-when-needed\n\nignore:\n - secrets.yml\n", None, id="12", ), pytest.param( "---\nWSLENV: HOSTNAME:CI:FORCE_COLOR:GITHUB_ACTION:GITHUB_ACTION_PATH/p:GITHUB_ACTION_REPOSITORY:GITHUB_WORKFLOW:GITHUB_WORKSPACE/p:GITHUB_PATH/p:GITHUB_ENV/p:VIRTUAL_ENV/p:SKIP_PODMAN:SKIP_DOCKER\n", "---\nWSLENV:\n HOSTNAME:CI:FORCE_COLOR:GITHUB_ACTION:GITHUB_ACTION_PATH/p:GITHUB_ACTION_REPOSITORY:GITHUB_WORKFLOW:GITHUB_WORKSPACE/p:GITHUB_PATH/p:GITHUB_ENV/p:VIRTUAL_ENV/p:SKIP_PODMAN:SKIP_DOCKER\n", None, id="13", ), ), ) def test_fmt(before: str, after: str, version: tuple[int, int] | None) -> None: """Tests behavior of formatter in regards to different YAML versions, specified or not.""" yaml = ansiblelint.yaml_utils.FormattedYAML(version=version) data = yaml.load(before) result = yaml.dumps(data) assert result == after @pytest.mark.parametrize( ("fixture_filename", "version"), ( pytest.param("fmt-1.yml", (1, 1), id="1"), pytest.param("fmt-2.yml", (1, 1), id="2"), pytest.param("fmt-3.yml", (1, 1), id="3"), pytest.param("fmt-4.yml", (1, 1), id="4"), pytest.param("fmt-5.yml", (1, 1), id="5"), pytest.param("fmt-hex.yml", (1, 1), id="hex"), ), ) def test_formatted_yaml_loader_dumper( fixture_filename: str, version: tuple[int, int], ) -> None: """Ensure that FormattedYAML loads/dumps formatting fixtures consistently.""" before_content, prettier_content, after_content = load_yaml_formatting_fixtures( fixture_filename, ) assert before_content != prettier_content assert before_content != after_content yaml = ansiblelint.yaml_utils.FormattedYAML(version=version) data_before = yaml.load(before_content) dump_from_before = yaml.dumps(data_before) data_prettier = yaml.load(prettier_content) dump_from_prettier = yaml.dumps(data_prettier) data_after = yaml.load(after_content) dump_from_after = yaml.dumps(data_after) # comparing data does not work because the Comment objects # have different IDs even if contents do not match. assert dump_from_before == after_content assert dump_from_prettier == after_content assert dump_from_after == after_content # We can't do this because FormattedYAML is stricter in some cases: # # Instead, `pytest --regenerate-formatting-fixtures` will fail if prettier would # change any files in test/fixtures/formatting-after # Running our files through yamllint, after we reformatted them, # should not yield any problems. config = ansiblelint.yaml_utils.load_yamllint_config() assert not list(run_yamllint(after_content, config)) # type: ignore[no-untyped-call] @pytest.fixture(name="lintable") def fixture_lintable(file_path: str) -> Lintable: """Return a playbook Lintable for use in ``get_path_to_*`` tests.""" return Lintable(file_path) @pytest.fixture(name="ruamel_data") def fixture_ruamel_data(lintable: Lintable) -> CommentedMap | CommentedSeq: """Return the loaded YAML data for the Lintable.""" yaml = ansiblelint.yaml_utils.FormattedYAML() data: CommentedMap | CommentedSeq = yaml.load(lintable.content) return data @pytest.mark.parametrize( ("file_path", "lineno", "expected_path"), ( # ignored lintables pytest.param( "examples/playbooks/tasks/passing_task.yml", 2, [], id="ignore_tasks_file", ), pytest.param( "examples/roles/more_complex/handlers/main.yml", 2, [], id="ignore_handlers_file", ), pytest.param("examples/playbooks/vars/other.yml", 2, [], id="ignore_vars_file"), pytest.param( "examples/host_vars/localhost.yml", 2, [], id="ignore_host_vars_file", ), pytest.param("examples/group_vars/all.yml", 2, [], id="ignore_group_vars_file"), pytest.param( "examples/inventory/inventory.yml", 2, [], id="ignore_inventory_file", ), pytest.param( "examples/roles/dependency_in_meta/meta/main.yml", 2, [], id="ignore_meta_file", ), pytest.param( "examples/reqs_v1/requirements.yml", 2, [], id="ignore_requirements_v1_file", ), pytest.param( "examples/reqs_v2/requirements.yml", 2, [], id="ignore_requirements_v2_file", ), # we don't have any release notes examples. Oh well. pytest.param( ".pre-commit-config.yaml", 2, [], id="ignore_unrecognized_yaml_file", ), # playbook lintables pytest.param( "examples/playbooks/become.yml", 1, [], id="1_play_playbook-line_before_play", ), pytest.param( "examples/playbooks/become.yml", 2, [0], id="1_play_playbook-first_line_in_play", ), pytest.param( "examples/playbooks/become.yml", 10, [0], id="1_play_playbook-middle_line_in_play", ), pytest.param( "examples/playbooks/become.yml", 100, [0], id="1_play_playbook-line_after_eof", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 1, [], id="4_play_playbook-line_before_play_1", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 2, [0], id="4_play_playbook-first_line_in_play_1", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 5, [0], id="4_play_playbook-middle_line_in_play_1", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 9, [0], id="4_play_playbook-last_line_in_play_1", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 12, [1], id="4_play_playbook-first_line_in_play_2", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 14, [1], id="4_play_playbook-middle_line_in_play_2", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 18, [1], id="4_play_playbook-last_line_in_play_2", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 21, [2], id="4_play_playbook-first_line_in_play_3", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 23, [2], id="4_play_playbook-middle_line_in_play_3", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 27, [2], id="4_play_playbook-last_line_in_play_3", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 31, [3], id="4_play_playbook-first_line_in_play_4", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 31, [3], id="4_play_playbook-middle_line_in_play_4", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 35, [3], id="4_play_playbook-last_line_in_play_4", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 100, [3], id="4_play_playbook-line_after_eof", ), pytest.param( "examples/playbooks/playbook-parent.yml", 1, [], id="import_playbook-line_before_play_1", ), pytest.param( "examples/playbooks/playbook-parent.yml", 2, [0], id="import_playbook-first_line_in_play_1", ), pytest.param( "examples/playbooks/playbook-parent.yml", 3, [0], id="import_playbook-middle_line_in_play_1", ), pytest.param( "examples/playbooks/playbook-parent.yml", 4, [0], id="import_playbook-last_line_in_play_1", ), pytest.param( "examples/playbooks/playbook-parent.yml", 5, [1], id="import_playbook-first_line_in_play_2", ), pytest.param( "examples/playbooks/playbook-parent.yml", 6, [1], id="import_playbook-middle_line_in_play_2", ), pytest.param( "examples/playbooks/playbook-parent.yml", 7, [1], id="import_playbook-last_line_in_play_2", ), pytest.param( "examples/playbooks/playbook-parent.yml", 8, [2], id="import_playbook-first_line_in_play_3", ), pytest.param( "examples/playbooks/playbook-parent.yml", 9, [2], id="import_playbook-last_line_in_play_3", ), pytest.param( "examples/playbooks/playbook-parent.yml", 15, [2], id="import_playbook-line_after_eof", ), ), ) def test_get_path_to_play( lintable: Lintable, lineno: int, ruamel_data: CommentedMap | CommentedSeq, expected_path: list[int | str], ) -> None: """Ensure ``get_path_to_play`` returns the expected path given a file + line.""" path_to_play = ansiblelint.yaml_utils.get_path_to_play( lintable, lineno, ruamel_data, ) assert path_to_play == expected_path @pytest.mark.parametrize( ("file_path", "lineno", "expected_path"), ( # ignored lintables pytest.param("examples/playbooks/vars/other.yml", 2, [], id="ignore_vars_file"), pytest.param( "examples/host_vars/localhost.yml", 2, [], id="ignore_host_vars_file", ), pytest.param("examples/group_vars/all.yml", 2, [], id="ignore_group_vars_file"), pytest.param( "examples/inventory/inventory.yml", 2, [], id="ignore_inventory_file", ), pytest.param( "examples/roles/dependency_in_meta/meta/main.yml", 2, [], id="ignore_meta_file", ), pytest.param( "examples/reqs_v1/requirements.yml", 2, [], id="ignore_requirements_v1_file", ), pytest.param( "examples/reqs_v2/requirements.yml", 2, [], id="ignore_requirements_v2_file", ), # we don't have any release notes examples. Oh well. pytest.param( ".pre-commit-config.yaml", 2, [], id="ignore_unrecognized_yaml_file", ), # tasks-containing lintables pytest.param( "examples/playbooks/become.yml", 4, [], id="1_task_playbook-line_before_tasks", ), pytest.param( "examples/playbooks/become.yml", 5, [0, "tasks", 0], id="1_task_playbook-first_line_in_task_1", ), pytest.param( "examples/playbooks/become.yml", 10, [0, "tasks", 0], id="1_task_playbook-middle_line_in_task_1", ), pytest.param( "examples/playbooks/become.yml", 15, [0, "tasks", 0], id="1_task_playbook-last_line_in_task_1", ), pytest.param( "examples/playbooks/become.yml", 100, [0, "tasks", 0], id="1_task_playbook-line_after_eof_without_anything_after_task", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 1, [], id="4_play_playbook-play_1_line_before_tasks", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 8, [0, "tasks", 0], id="4_play_playbook-play_1_first_line_task_1", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 9, [0, "tasks", 0], id="4_play_playbook-play_1_last_line_task_1", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 13, [], id="4_play_playbook-play_2_line_before_tasks", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 12, [], id="4_play_playbook-play_2_line_before_tasks", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 15, [1, "tasks", 0], id="4_play_playbook-play_2_first_line_task_1", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 18, [1, "tasks", 0], id="4_play_playbook-play_2_middle_line_task_1", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 18, [1, "tasks", 0], id="4_play_playbook-play_2_last_line_task_1", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 23, [], id="4_play_playbook-play_3_line_before_tasks", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 22, [], id="4_play_playbook-play_3_line_before_tasks", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 25, [2, "tasks", 0], id="4_play_playbook-play_3_first_line_task_1", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 25, [2, "tasks", 0], id="4_play_playbook-play_3_middle_line_task_1", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 27, [2, "tasks", 0], id="4_play_playbook-play_3_last_line_task_1", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 33, [], id="4_play_playbook-play_4_line_before_tasks", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 31, [], id="4_play_playbook-play_4_line_before_tasks", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 35, [3, "tasks", 0], id="4_play_playbook-play_4_first_line_task_1", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 39, [3, "tasks", 0], id="4_play_playbook-play_4_middle_line_task_1", ), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 35, [3, "tasks", 0], id="4_play_playbook-play_4_last_line_task_1", ), # playbook with multiple tasks + tasks blocks in a play pytest.param( # must have at least one key after one of the tasks blocks "examples/playbooks/include.yml", 6, [0, "pre_tasks", 0], id="playbook-multi_tasks_blocks-pre_tasks_last_task_before_roles", ), pytest.param( "examples/playbooks/include.yml", 7, [], id="playbook-multi_tasks_blocks-roles_after_pre_tasks", ), pytest.param( "examples/playbooks/include.yml", 10, [], id="playbook-multi_tasks_blocks-roles_before_tasks", ), pytest.param( "examples/playbooks/include.yml", 12, [0, "tasks", 0], id="playbook-multi_tasks_blocks-tasks_first_task", ), pytest.param( "examples/playbooks/include.yml", 14, [0, "tasks", 2], id="playbook-multi_tasks_blocks-tasks_last_task_before_handlers", ), pytest.param( "examples/playbooks/include.yml", 17, [0, "handlers", 0], id="playbook-multi_tasks_blocks-handlers_task", ), # playbook with subtasks blocks pytest.param( "examples/playbooks/blockincludes.yml", 14, [0, "tasks", 0, "block", 1, "block", 0], id="playbook-deeply_nested_task", ), pytest.param( "examples/playbooks/block.yml", 12, [0, "tasks", 0, "block", 1], id="playbook-subtasks-block_task_2", ), pytest.param( "examples/playbooks/block.yml", 22, [0, "tasks", 0, "rescue", 2], id="playbook-subtasks-rescue_task_3", ), pytest.param( "examples/playbooks/block.yml", 25, [0, "tasks", 0, "always", 0], id="playbook-subtasks-always_task_3", ), # tasks files pytest.param("examples/playbooks/tasks/x.yml", 2, [0], id="tasks-null_task"), pytest.param( "examples/playbooks/tasks/x.yml", 6, [1], id="tasks-null_task_next", ), pytest.param( "examples/playbooks/tasks/empty_blocks.yml", 7, [0], # this IS part of the first task and "rescue" does not have subtasks. id="tasks-null_rescue", ), pytest.param( "examples/playbooks/tasks/empty_blocks.yml", 8, [0], # this IS part of the first task and "always" does not have subtasks. id="tasks-empty_always", ), pytest.param( "examples/playbooks/tasks/empty_blocks.yml", 16, [1, "always", 0], id="tasks-task_beyond_empty_blocks", ), pytest.param( "examples/roles/more_complex/tasks/main.yml", 1, [], id="tasks-line_before_tasks", ), pytest.param( "examples/roles/more_complex/tasks/main.yml", 2, [0], id="tasks-first_line_in_task_1", ), pytest.param( "examples/roles/more_complex/tasks/main.yml", 3, [0], id="tasks-middle_line_in_task_1", ), pytest.param( "examples/roles/more_complex/tasks/main.yml", 4, [0], id="tasks-last_line_in_task_1", ), pytest.param( "examples/roles/more_complex/tasks/main.yml", 5, [1], id="tasks-first_line_in_task_2", ), pytest.param( "examples/roles/more_complex/tasks/main.yml", 6, [1], id="tasks-middle_line_in_task_2", ), pytest.param( "examples/roles/more_complex/tasks/main.yml", 7, [1], id="tasks-last_line_in_task_2", ), pytest.param( "examples/roles/more_complex/tasks/main.yml", 8, [2], id="tasks-first_line_in_task_3", ), pytest.param( "examples/roles/more_complex/tasks/main.yml", 9, [2], id="tasks-last_line_in_task_3", ), pytest.param( "examples/roles/more_complex/tasks/main.yml", 100, [2], id="tasks-line_after_eof", ), # handlers pytest.param( "examples/roles/more_complex/handlers/main.yml", 1, [], id="handlers-line_before_tasks", ), pytest.param( "examples/roles/more_complex/handlers/main.yml", 2, [0], id="handlers-first_line_in_task_1", ), pytest.param( "examples/roles/more_complex/handlers/main.yml", 3, [0], id="handlers-last_line_in_task_1", ), pytest.param( "examples/roles/more_complex/handlers/main.yml", 100, [0], id="handlers-line_after_eof", ), ), ) def test_get_path_to_task( lintable: Lintable, lineno: int, ruamel_data: CommentedMap | CommentedSeq, expected_path: list[int | str], ) -> None: """Ensure ``get_task_to_play`` returns the expected path given a file + line.""" path_to_task = ansiblelint.yaml_utils.get_path_to_task( lintable, lineno, ruamel_data, ) assert path_to_task == expected_path @pytest.mark.parametrize( ("file_path", "lineno"), ( pytest.param("examples/playbooks/become.yml", 0, id="1_play_playbook"), pytest.param( "examples/playbooks/rule-partial-become-without-become-pass.yml", 0, id="4_play_playbook", ), pytest.param("examples/playbooks/playbook-parent.yml", 0, id="import_playbook"), pytest.param("examples/playbooks/become.yml", 0, id="1_task_playbook"), ), ) def test_get_path_to_play_raises_value_error_for_bad_lineno( lintable: Lintable, lineno: int, ruamel_data: CommentedMap | CommentedSeq, ) -> None: """Ensure ``get_path_to_play`` raises ValueError for lineno < 1.""" with pytest.raises( ValueError, match=f"expected lineno >= 1, got {lineno}", ): ansiblelint.yaml_utils.get_path_to_play(lintable, lineno, ruamel_data) @pytest.mark.parametrize( ("file_path", "lineno"), (pytest.param("examples/roles/more_complex/tasks/main.yml", 0, id="tasks"),), ) def test_get_path_to_task_raises_value_error_for_bad_lineno( lintable: Lintable, lineno: int, ruamel_data: CommentedMap | CommentedSeq, ) -> None: """Ensure ``get_task_to_play`` raises ValueError for lineno < 1.""" with pytest.raises( ValueError, match=f"expected lineno >= 1, got {lineno}", ): ansiblelint.yaml_utils.get_path_to_task(lintable, lineno, ruamel_data) @pytest.mark.parametrize( ("before", "after"), ( pytest.param(None, None, id="1"), pytest.param(1, 1, id="2"), pytest.param({}, {}, id="3"), pytest.param({"__file__": 1}, {}, id="simple"), pytest.param({"foo": {"__file__": 1}}, {"foo": {}}, id="nested"), pytest.param([{"foo": {"__file__": 1}}], [{"foo": {}}], id="nested-in-lint"), pytest.param({"foo": [{"__file__": 1}]}, {"foo": [{}]}, id="nested-in-lint"), ), ) def test_deannotate( before: Any, after: Any, ) -> None: """Ensure deannotate works as intended.""" assert ansiblelint.yaml_utils.deannotate(before) == after def test_yamllint_incompatible_config() -> None: """Ensure we can detect incompatible yamllint settings.""" with cwd(Path("examples/yamllint/incompatible-config")): config = ansiblelint.yaml_utils.load_yamllint_config() assert config.incompatible @pytest.mark.parametrize( ("yaml_version", "explicit_start"), ( pytest.param((1, 1), True), pytest.param((1, 1), False), ), ) def test_document_start( yaml_version: tuple[int, int] | None, explicit_start: bool, ) -> None: """Ensure the explicit_start config option from .yamllint is applied correctly.""" config = ansiblelint.yaml_utils.FormattedYAML.default_config config["explicit_start"] = explicit_start yaml = ansiblelint.yaml_utils.FormattedYAML( version=yaml_version, config=cast("dict[str, bool | int | str]", config), ) assert ( yaml.dumps(yaml.load(_SINGLE_QUOTE_WITHOUT_INDENTS)).startswith("---") == explicit_start ) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/tools/�����������������������������������������������������������������0000775�0000000�0000000�00000000000�14773473560�0017220�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/tools/generate_docs.py�������������������������������������������������0000775�0000000�0000000�00000001754�14773473560�0022406�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!python3 """Script that tests rule markdown documentation.""" from __future__ import annotations import subprocess from pathlib import Path from ansiblelint.cli import get_rules_dirs from ansiblelint.config import Options from ansiblelint.rules import RulesCollection, TransformMixin if __name__ == "__main__": subprocess.run( # noqa: S603 ["ansible-lint", "--list-rules"], # noqa: S607 check=True, stdout=subprocess.DEVNULL, ) file = Path("docs/_autofix_rules.md") options = Options() options.rulesdirs = get_rules_dirs([]) options.list_rules = True rules = RulesCollection( options.rulesdirs, options=options, ) contents: list[str] = [ f"- [{rule.id}](rules/{rule.id}.md)\n" for rule in rules.alphabetical() if issubclass(rule.__class__, TransformMixin) ] # Write the injected contents to the file. with file.open(encoding="utf-8", mode="w") as fh: fh.writelines(contents) ��������������������ansible-ansible-lint-c16f018/tools/get-version.sh���������������������������������������������������0000775�0000000�0000000�00000000370�14773473560�0022021�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/bash set -e { python3 -c "import setuptools_scm" || python3 -m pip install --user setuptools-scm } 1>&2 # redirect stdout to stderr to avoid polluting the output python3 -m setuptools_scm | \ sed 's/Guessed Version\([^+]\+\).*/\1/' ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/tools/install-reqs.sh��������������������������������������������������0000775�0000000�0000000�00000000232�14773473560�0022172�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/bash set -euo pipefail echo "Install requirements.yml ..." ansible-galaxy collection install -r requirements.yml -p examples/playbooks/collections ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/tools/test-eco.sh������������������������������������������������������0000775�0000000�0000000�00000001554�14773473560�0021307�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env bash set -eu SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) if [[ -d "${SCRIPT_DIR}/../.cache/eco/.git" ]]; then git -C "${SCRIPT_DIR}/../.cache/eco" pull else mkdir -p "${SCRIPT_DIR}/../.cache" git clone --recursive https://github.com/ansible-community/ansible-lint-eco "${SCRIPT_DIR}/../.cache/eco" fi pushd "${SCRIPT_DIR}/../.cache/eco/projects" > /dev/null for i in $(ls -d */); do DIR=${i%%/} RC=0 pushd $DIR > /dev/null # Calling ansible lint without any positional arguments inside repository root SECONDS=0 ANSIBLE_LINT_IGNORE_FILE=../$DIR.ignore.txt ansible-lint -qq --generate-ignore -f codeclimate | python3 -m json.tool > ../$DIR.json || RC=$? echo "Got $RC RC on $DIR in $SECONDS seconds" popd > /dev/null done popd > /dev/null # Fail if git reports dirty at the end git diff --exit-code ����������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/tools/test-hook.sh�����������������������������������������������������0000775�0000000�0000000�00000001367�14773473560�0021503�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/bash # This scripts checks if ansible-lint works as a hook as expected. SOURCE=${BASH_SOURCE[0]} while [ -L "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink DIR=$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd ) SOURCE=$(readlink "$SOURCE") [[ $SOURCE != /* ]] && SOURCE=$DIR/$SOURCE # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located done DIR=$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd ) set -euo pipefail rm -rf .tox/x mkdir -p .tox/x cd .tox/x git init --initial-branch=main # we add a file to the repo to avoid error due to no file to to lint touch foo.yml git add foo.yml python3 -m pre_commit try-repo -v "${DIR}/.." ansible-lint �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/tools/test-setup.sh����������������������������������������������������0000775�0000000�0000000�00000001771�14773473560�0021702�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/bash # This tool is used to setup the environment for running the tests. Its name # name and location is based on Zuul CI, which can automatically run it. set -euo pipefail # User specific environment # shellcheck disable=SC2076 if ! [[ "$PATH" =~ "$HOME/.local/bin" ]] then PATH="$HOME/.local/bin:$PATH" fi if [ -f "/usr/bin/apt-get" ]; then if [ ! -f "/var/cache/apt/pkgcache.bin" ]; then sudo apt-get update # mandatory or other apt-get commands fail fi # avoid outdated ansible and pipx sudo apt-get remove -y ansible pipx || true # cspell:disable-next-line sudo apt-get install -y --no-install-recommends -o=Dpkg::Use-Pty=0 \ curl gcc git python3-venv python3-pip python3-dev libyaml-dev # Some of these might be needed for compiling packages that do not yet # a binary for current platform, like pyyaml on py311 # pip3 install -v --no-binary :all: --user pyyaml fi # Log some useful info in case of unexpected failures: uname python3 --version �������ansible-ansible-lint-c16f018/tools/update-version.sh������������������������������������������������0000775�0000000�0000000�00000000336�14773473560�0022526�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/bash DIR=$(dirname "$0") VERSION=$(./tools/get-version.sh) mkdir -p "${DIR}/../dist" sed -e "s/VERSION_PLACEHOLDER/${VERSION}/" \ "${DIR}/../.config/ansible-lint.spec" \ > "${DIR}/../dist/ansible-lint.spec" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ansible-ansible-lint-c16f018/tox.ini����������������������������������������������������������������0000664�0000000�0000000�00000013172�14773473560�0017377�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������[tox] requires = setuptools>=65.3 tox>=4.24.2 tox-extra>=2.1 tox-uv>=1.25 env_list = py py-devel lint pkg hook docs schemas lower pre eco skip_missing_interpreters = true [testenv] description = Run the tests under {base_python} devel: and ansible devel branch pre: and enable --pre when installing dependencies, testing prereleases package = editable deps = devel: ansible-compat @ git+https://github.com/ansible/ansible-compat.git # GPLv3+ devel: ansible-core @ git+https://github.com/ansible/ansible.git # GPLv3+ extras = test pass_env = CI CURL_CA_BUNDLE FORCE_COLOR HOME LANG LC_* NO_COLOR PYTEST_* PYTEST_REQPASS PYTHON* PYTHONBREAKPOINT PYTHONIOENCODING PYTHONPYCACHEPREFIX PY_COLORS REQUESTS_CA_BUNDLE RTD_TOKEN SETUPTOOLS_SCM_DEBUG SSH_AUTH_SOCK SSL_CERT_FILE UV_* set_env = COVERAGE_FILE = {env:COVERAGE_FILE:{env_dir}/.coverage.{env_name}} COVERAGE_PROCESS_START = {tox_root}/pyproject.toml FORCE_COLOR = 1 PIP_CONSTRAINT = {tox_root}/.config/constraints.txt PIP_DISABLE_PIP_VERSION_CHECK = 1 PRE_COMMIT_COLOR = always PYTEST_REQPASS = 908 UV_CONSTRAINT = {tox_root}/.config/constraints.txt deps, devel, hook, lint, pkg, pre, py310, schemas: PIP_CONSTRAINT = /dev/null deps, devel, hook, lint, pkg, pre, py310, schemas: UV_CONSTRAINT = /dev/null devel: ANSIBLE_DEVEL_WARNING = false lower: PIP_CONSTRAINT = {tox_root}/.github/lower-constraints.txt lower: UV_CONSTRAINT = {tox_root}/.github/lower-constraints.txt pre: PIP_PRE = 1 commands_pre = sh -c "rm -f {env_dir}/.coverage.* 2>/dev/null || true" {env_python} -m pip check bash ./tools/install-reqs.sh ansible --version commands = sh -c "{env_python} -m pip freeze > {env_dir}/log/requirements.txt" coverage run -m pytest {posargs: \ -n auto \ -ra \ --showlocals \ --doctest-modules \ --durations=10 \ } {py,py310,py311,py312,py313}: sh -c "coverage combine -a -q --data-file={env_dir}/.coverage {work_dir}/*/.coverage.* && coverage xml --data-file={env_dir}/.coverage -o {env_dir}/coverage.xml --fail-under=0 && coverage report --data-file={env_dir}/.coverage" allowlist_externals = ./tools/test-hook.sh bash find git pwd rm sh tox {work_dir}/.pipx/bin/ansible-lint [testenv:lint] description = Run all linters skip_install = true deps = pre-commit>=4.1 pre-commit-uv>=4.1.4 pytest>=7.2.2 # to updated schemas setuptools>=51.1.1 pass_env = {[testenv]pass_env} PRE_COMMIT_HOME commands_pre = commands = {env_python} -m pre_commit run --all-files --show-diff-on-failure {posargs:} [testenv:pkg] description = Build package, verify metadata, install package and assert behavior when ansible is missing. skip_install = true deps = build>=0.9 pip pipx twine>=4.0.1 commands_pre = commands = bash -c "PIPX_BIN_DIR={work_dir}/.pipx/bin PIPX_HOME={work_dir}/.pipx pipx install --force -e ." bash -c "if stderr=$({work_dir}/.pipx/bin/ansible-lint --version >/dev/null) && test -z \"$stderr\"; then echo "ok"; fi" {env_python} -c 'import os.path, shutil, sys; \ dist_dir = os.path.join("{tox_root}", "dist"); \ os.path.isdir(dist_dir) or sys.exit(0); \ print("Removing \{!s\} contents...".format(dist_dir), file=sys.stderr); \ shutil.rmtree(dist_dir)' {env_python} -m build --outdir {tox_root}/dist/ {tox_root} python3 -m twine check --strict {tox_root}/dist/* sh -c 'python3 -m pip install "ansible-lint @ file://$(echo {tox_root}/dist/*.whl)"' python3 -m pip uninstall -y ansible-lint [testenv:hook] description = Validate pre-commit hook definition deps = pre-commit commands = ./tools/test-hook.sh [testenv:docs] description = Builds docs package = editable skip_install = false extras = docs set_env = DYLD_FALLBACK_LIBRARY_PATH = /opt/homebrew/lib:{env:LD_LIBRARY_PATH} NO_COLOR = 1 TERM = dump commands_pre = ansible-lint --version commands = mkdocs {posargs:build --strict --site-dir=_readthedocs/html/} [testenv:schemas] description = Rebuild and test JSON Schemas skip_install = true deps = check-jsonschema>=0.26.3 change_dir = test/schemas commands_pre = npm install commands = npm test allowlist_externals = npm [testenv:lower] description = Install using lower-constraints.txt file for testing oldest versions. [testenv:eco] description = Perform ecosystem impact (downstream testing) https://github.com/ansible/ansible-lint/discussions/1403 deps = {[testenv]deps} extras = test set_env = PYTEST_REQPASS = 7 commands = sh -c tools/test-eco.sh allowlist_externals = {[testenv]allowlist_externals} [testenv:deps] description = Bump all test dependencies skip_install = true deps = {[testenv:lint]deps} commands_pre = commands = pre-commit run --all-files --show-diff-on-failure --hook-stage manual lock pre-commit run --all-files --show-diff-on-failure --hook-stage manual deps pre-commit autoupdate sh -c "cd test/schemas && npm run deps" tox -e lint env_dir = {work_dir}/lint [testenv:redirects] description = Update documentation redirections for readthedocs deps = readthedocs-cli commands = rtd projects ansible-lint redirects sync -f docs/redirects.yml --wet-run [testenv:clean] description = Remove temporary files skip_install = true deps = commands_pre = commands = find . -type d \( -name __pycache__ -o -name .mypy_cache \) -delete find . -type f \( -name '*.py[co]' -o -name ".coverage*" -o -name coverage.xml \) -delete commands_post = ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������