diff --git a/plugins/filter/gpg_fingerprint.py b/plugins/filter/gpg_fingerprint.py new file mode 100644 index 000000000..bd9d21ecb --- /dev/null +++ b/plugins/filter/gpg_fingerprint.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2023, Felix Fontein +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = """ +name: gpg_fingerprint +short_description: Retrieve a GPG fingerprint from a GPG public or private key +author: Felix Fontein (@felixfontein) +version_added: 2.15.0 +description: + - "Takes the content of a private or public GPG key as input and returns its fingerprint." +options: + _input: + description: + - The content of a GPG public or private key. + type: string + required: true +requirements: + - GnuPG (C(gpg) executable) +seealso: + - plugin: community.crypto.gpg_fingerprint + plugin_type: lookup +""" + +EXAMPLES = """ +- name: Show fingerprint of GPG public key + ansible.builtin.debug: + msg: "{{ lookup('file', '/path/to/public_key.gpg') | community.crypto.gpg_fingerprint }}" +""" + +RETURN = """ + _value: + description: + - The fingerprint of the provided public or private GPG key. + type: string +""" + +from ansible.errors import AnsibleFilterError +from ansible.module_utils.common.text.converters import to_bytes, to_native +from ansible.module_utils.six import string_types + +from ansible_collections.community.crypto.plugins.module_utils.gnupg.cli import GPGError, get_fingerprint_from_bytes +from ansible_collections.community.crypto.plugins.plugin_utils.gnupg import PluginGPGRunner + + +def gpg_fingerprint(input): + if not isinstance(input, string_types): + raise AnsibleFilterError( + 'The input for the community.crypto.gpg_fingerprint filter must be a string; got {type} instead'.format(type=type(input)) + ) + try: + gpg = PluginGPGRunner() + return get_fingerprint_from_bytes(gpg, to_bytes(input)) + except GPGError as exc: + raise AnsibleFilterError(to_native(exc)) + + +class FilterModule(object): + '''Ansible jinja2 filters''' + + def filters(self): + return { + 'gpg_fingerprint': gpg_fingerprint, + } diff --git a/plugins/lookup/gpg_fingerprint.py b/plugins/lookup/gpg_fingerprint.py new file mode 100644 index 000000000..c562faed8 --- /dev/null +++ b/plugins/lookup/gpg_fingerprint.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2023, Felix Fontein +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = """ +name: gpg_fingerprint +short_description: Retrieve a GPG fingerprint from a GPG public or private key file +author: Felix Fontein (@felixfontein) +version_added: 2.15.0 +description: + - "Takes a list of filenames pointing to GPG public or private key files. Returns the fingerprints for each of these keys." +options: + _terms: + description: + - A path to a GPG public or private key. + type: list + elements: path + required: true +requirements: + - GnuPG (C(gpg) executable) +seealso: + - plugin: community.crypto.gpg_fingerprint + plugin_type: filter +""" + +EXAMPLES = """ +- name: Show fingerprint of GPG public key + ansible.builtin.debug: + msg: "{{ lookup('community.crypto.gpg_fingerprint', '/path/to/public_key.gpg') }}" +""" + +RETURN = """ + _value: + description: + - The fingerprints of the provided public or private GPG keys. + - The list has one entry for every path provided. + type: list + elements: string +""" + +from ansible.plugins.lookup import LookupBase +from ansible.errors import AnsibleLookupError +from ansible.module_utils.common.text.converters import to_native + +from ansible_collections.community.crypto.plugins.module_utils.gnupg.cli import GPGError, get_fingerprint_from_file +from ansible_collections.community.crypto.plugins.plugin_utils.gnupg import PluginGPGRunner + + +class LookupModule(LookupBase): + def run(self, terms, variables=None, **kwargs): + self.set_options(direct=kwargs) + + try: + gpg = PluginGPGRunner(cwd=self._loader.get_basedir()) + result = [] + for path in terms: + result.append(get_fingerprint_from_file(gpg, path)) + return result + except GPGError as exc: + raise AnsibleLookupError(to_native(exc)) diff --git a/plugins/module_utils/gnupg/cli.py b/plugins/module_utils/gnupg/cli.py new file mode 100644 index 000000000..caf0de25f --- /dev/null +++ b/plugins/module_utils/gnupg/cli.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2023, Felix Fontein +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import abc +import os + +from ansible.module_utils import six + + +class GPGError(Exception): + pass + + +@six.add_metaclass(abc.ABCMeta) +class GPGRunner(object): + @abc.abstractmethod + def run_command(self, command, check_rc=True, data=None): + """ + Run ``[gpg] + command`` and return ``(rc, stdout, stderr)``. + + If ``data`` is not ``None``, it will be provided as stdin. + The code assumes it is a bytes string. + + Returned stdout and stderr are native Python strings. + Pass ``check_rc=False`` to allow return codes != 0. + + Raises a ``GPGError`` in case of errors. + """ + pass + + +def get_fingerprint_from_stdout(stdout): + lines = stdout.splitlines(False) + for line in lines: + if line.startswith('fpr:'): + parts = line.split(':') + if len(parts) <= 9 or not parts[9]: + raise GPGError('Result line "{line}" does not have fingerprint as 10th component'.format(line=line)) + return parts[9] + raise GPGError('Cannot extract fingerprint from stdout "{stdout}"'.format(stdout=stdout)) + + +def get_fingerprint_from_file(gpg_runner, path): + if not os.path.exists(path): + raise GPGError('{path} does not exist'.format(path=path)) + stdout = gpg_runner.run_command( + ['--no-keyring', '--with-colons', '--import-options', 'show-only', '--import', path], + check_rc=True, + )[1] + return get_fingerprint_from_stdout(stdout) + + +def get_fingerprint_from_bytes(gpg_runner, content): + stdout = gpg_runner.run_command( + ['--no-keyring', '--with-colons', '--import-options', 'show-only', '--import', '/dev/stdin'], + data=content, + check_rc=True, + )[1] + return get_fingerprint_from_stdout(stdout) diff --git a/plugins/plugin_utils/gnupg.py b/plugins/plugin_utils/gnupg.py new file mode 100644 index 000000000..0cd715bf0 --- /dev/null +++ b/plugins/plugin_utils/gnupg.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2023, Felix Fontein +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from subprocess import Popen, PIPE + +from ansible.module_utils.common.process import get_bin_path +from ansible.module_utils.common.text.converters import to_native + +from ansible_collections.community.crypto.plugins.module_utils.gnupg.cli import GPGError, GPGRunner + + +class PluginGPGRunner(GPGRunner): + def __init__(self, executable=None, cwd=None): + if executable is None: + try: + executable = get_bin_path('gpg') + except ValueError as e: + raise GPGError('Cannot find the `gpg` executable on the controller') + self.executable = executable + self.cwd = cwd + + def run_command(self, command, check_rc=True, data=None): + """ + Run ``[gpg] + command`` and return ``(rc, stdout, stderr)``. + + If ``data`` is not ``None``, it will be provided as stdin. + The code assumes it is a bytes string. + + Returned stdout and stderr are native Python strings. + Pass ``check_rc=False`` to allow return codes != 0. + + Raises a ``GPGError`` in case of errors. + """ + command = [self.executable] + command + p = Popen(command, shell=False, cwd=self.cwd, stdin=PIPE, stdout=PIPE, stderr=PIPE) + stdout, stderr = p.communicate(input=data) + stdout = to_native(stdout, errors='surrogate_or_replace') + stderr = to_native(stderr, errors='surrogate_or_replace') + if check_rc and p.returncode != 0: + raise GPGError('Running {cmd} yielded return code {rc} with stdout: "{stdout}" and stderr: "{stderr}")'.format( + cmd=' '.join(command), + rc=p.returncode, + stdout=to_native(stdout, errors='surrogate_or_replace'), + stderr=to_native(stderr, errors='surrogate_or_replace'), + )) + return p.returncode, stdout, stderr diff --git a/tests/integration/targets/filter_gpg_fingerprint/aliases b/tests/integration/targets/filter_gpg_fingerprint/aliases new file mode 100644 index 000000000..326a499c3 --- /dev/null +++ b/tests/integration/targets/filter_gpg_fingerprint/aliases @@ -0,0 +1,6 @@ +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +azp/posix/2 +destructive diff --git a/tests/integration/targets/filter_gpg_fingerprint/meta/main.yml b/tests/integration/targets/filter_gpg_fingerprint/meta/main.yml new file mode 100644 index 000000000..398d0cf6c --- /dev/null +++ b/tests/integration/targets/filter_gpg_fingerprint/meta/main.yml @@ -0,0 +1,9 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +dependencies: + - prepare_jinja2_compat + - setup_remote_tmp_dir + - setup_gnupg diff --git a/tests/integration/targets/filter_gpg_fingerprint/tasks/main.yml b/tests/integration/targets/filter_gpg_fingerprint/tasks/main.yml new file mode 100644 index 000000000..071b490fd --- /dev/null +++ b/tests/integration/targets/filter_gpg_fingerprint/tasks/main.yml @@ -0,0 +1,80 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +- name: Run tests if GPG is available + when: has_gnupg + block: + - name: Create GPG key + ansible.builtin.command: + cmd: gpg --homedir "{{ remote_tmp_dir }}" --batch --generate-key + stdin: | + %echo Generating a basic OpenPGP key + %no-ask-passphrase + %no-protection + Key-Type: RSA + Key-Length: 4096 + Name-Real: Foo Bar + Name-Email: foo@bar.com + Expire-Date: 0 + %commit + %echo done + register: result + + - name: Extract fingerprint + ansible.builtin.shell: gpg --homedir "{{ remote_tmp_dir }}" --with-colons --fingerprint foo@bar.com | grep '^fpr:' + register: fingerprints + + - name: Show fingerprints + ansible.builtin.debug: + msg: "{{ fingerprints.stdout_lines | map('split', ':') | list }}" + + - name: Export public key + ansible.builtin.command: gpg --homedir "{{ remote_tmp_dir }}" --export --armor foo@bar.com + register: public_key + + - name: Export private key + ansible.builtin.command: gpg --homedir "{{ remote_tmp_dir }}" --export-secret-key --armor foo@bar.com + register: private_key + + - name: Gather fingerprints + ansible.builtin.set_fact: + public_key_fingerprint: "{{ public_key.stdout | community.crypto.gpg_fingerprint }}" + private_key_fingerprint: "{{ private_key.stdout | community.crypto.gpg_fingerprint }}" + + - name: Check whether fingerprints match + ansible.builtin.assert: + that: + - public_key_fingerprint == (fingerprints.stdout_lines[0] | split(':'))[9] + - private_key_fingerprint == (fingerprints.stdout_lines[0] | split(':'))[9] + + - name: Error scenario - wrong input type + ansible.builtin.set_fact: + failing_result: "{{ 42 | community.crypto.gpg_fingerprint }}" + register: result + ignore_errors: true + + - name: Check result + ansible.builtin.assert: + that: + - result is failed + - >- + 'The input for the community.crypto.gpg_fingerprint filter must be a string; got ' in result.msg + - >- + 'int' in result.msg + + - name: Error scenario - garbage input + ansible.builtin.set_fact: + failing_result: "{{ 'garbage' | community.crypto.gpg_fingerprint }}" + register: result + ignore_errors: true + + - name: Check result + ansible.builtin.assert: + that: + - result is failed + - >- + 'Running ' in result.msg + - >- + ('/gpg --no-keyring --with-colons --import-options show-only --import /dev/stdin yielded return code ') in result.msg diff --git a/tests/integration/targets/lookup_gpg_fingerprint/aliases b/tests/integration/targets/lookup_gpg_fingerprint/aliases new file mode 100644 index 000000000..326a499c3 --- /dev/null +++ b/tests/integration/targets/lookup_gpg_fingerprint/aliases @@ -0,0 +1,6 @@ +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +azp/posix/2 +destructive diff --git a/tests/integration/targets/lookup_gpg_fingerprint/meta/main.yml b/tests/integration/targets/lookup_gpg_fingerprint/meta/main.yml new file mode 100644 index 000000000..398d0cf6c --- /dev/null +++ b/tests/integration/targets/lookup_gpg_fingerprint/meta/main.yml @@ -0,0 +1,9 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +dependencies: + - prepare_jinja2_compat + - setup_remote_tmp_dir + - setup_gnupg diff --git a/tests/integration/targets/lookup_gpg_fingerprint/tasks/main.yml b/tests/integration/targets/lookup_gpg_fingerprint/tasks/main.yml new file mode 100644 index 000000000..860cbce97 --- /dev/null +++ b/tests/integration/targets/lookup_gpg_fingerprint/tasks/main.yml @@ -0,0 +1,93 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +- name: Run tests if GPG is available + when: has_gnupg + block: + - name: Create GPG key + ansible.builtin.command: + cmd: gpg --homedir "{{ remote_tmp_dir }}" --batch --generate-key + stdin: | + %echo Generating a basic OpenPGP key + %no-ask-passphrase + %no-protection + Key-Type: RSA + Key-Length: 4096 + Name-Real: Foo Bar + Name-Email: foo@bar.com + Expire-Date: 0 + %commit + %echo done + register: result + + - name: Extract fingerprint + ansible.builtin.shell: gpg --homedir "{{ remote_tmp_dir }}" --with-colons --fingerprint foo@bar.com | grep '^fpr:' + register: fingerprints + + - name: Show fingerprints + ansible.builtin.debug: + msg: "{{ fingerprints.stdout_lines | map('split', ':') | list }}" + + - name: Export public key + ansible.builtin.command: gpg --homedir "{{ remote_tmp_dir }}" --export --armor foo@bar.com + register: public_key + + - name: Export private key + ansible.builtin.command: gpg --homedir "{{ remote_tmp_dir }}" --export-secret-key --armor foo@bar.com + register: private_key + + - name: Write public key to disk + ansible.builtin.copy: + dest: "{{ remote_tmp_dir }}/public-key" + content: "{{ public_key.stdout }}" + + - name: Write private key to disk + ansible.builtin.copy: + dest: "{{ remote_tmp_dir }}/private-key" + content: "{{ private_key.stdout }}" + + - name: Gather fingerprints + ansible.builtin.set_fact: + public_key_fingerprint: "{{ lookup('community.crypto.gpg_fingerprint', remote_tmp_dir ~ '/public-key') }}" + private_key_fingerprint: "{{ lookup('community.crypto.gpg_fingerprint', remote_tmp_dir ~ '/private-key') }}" + + - name: Check whether fingerprints match + ansible.builtin.assert: + that: + - public_key_fingerprint == (fingerprints.stdout_lines[0] | split(':'))[9] + - private_key_fingerprint == (fingerprints.stdout_lines[0] | split(':'))[9] + + - name: Error scenario - file does not exist + ansible.builtin.set_fact: + failing_result: "{{ lookup('community.crypto.gpg_fingerprint', remote_tmp_dir ~ '/does-not-exist') }}" + register: result + ignore_errors: true + + - name: Check result + ansible.builtin.assert: + that: + - result is failed + - >- + (remote_tmp_dir ~ '/does-not-exist does not exist') in result.msg + + - name: Write garbage to disk + ansible.builtin.copy: + dest: "{{ remote_tmp_dir }}/garbage" + content: gargabe + + - name: Error scenario - file contains garbage + ansible.builtin.set_fact: + failing_result: "{{ lookup('community.crypto.gpg_fingerprint', remote_tmp_dir ~ '/garbage') }}" + register: result + ignore_errors: true + + - name: Check result + ansible.builtin.assert: + that: + - result is failed + - >- + 'Running ' in result.msg + - >- + ('/gpg --no-keyring --with-colons --import-options show-only --import ' ~ remote_tmp_dir ~ '/garbage yielded return code ') in result.msg diff --git a/tests/integration/targets/prepare_jinja2_compat/filter_plugins/ansible_compatibility.py b/tests/integration/targets/prepare_jinja2_compat/filter_plugins/ansible_compatibility.py new file mode 100644 index 000000000..c14af4ccb --- /dev/null +++ b/tests/integration/targets/prepare_jinja2_compat/filter_plugins/ansible_compatibility.py @@ -0,0 +1,20 @@ +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +# Added in ansible-core 2.11 +def compatibility_split_filter(text, by_what): + return text.split(by_what) + + +class FilterModule: + ''' Jinja2 compat filters ''' + + def filters(self): + return { + 'split': compatibility_split_filter, + } diff --git a/tests/integration/targets/setup_gnupg/meta/main.yml b/tests/integration/targets/setup_gnupg/meta/main.yml new file mode 100644 index 000000000..2fcd152f9 --- /dev/null +++ b/tests/integration/targets/setup_gnupg/meta/main.yml @@ -0,0 +1,7 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +dependencies: + - setup_pkg_mgr diff --git a/tests/integration/targets/setup_gnupg/tasks/main.yml b/tests/integration/targets/setup_gnupg/tasks/main.yml new file mode 100644 index 000000000..9e02356fc --- /dev/null +++ b/tests/integration/targets/setup_gnupg/tasks/main.yml @@ -0,0 +1,30 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +- name: Print distribution specific data + ansible.builtin.debug: + msg: | + Distribution: {{ ansible_facts.distribution }} + Distribution version: {{ ansible_facts.distribution_version }} + Distribution major version: {{ ansible_facts.distribution_major_version }} + OS family: {{ ansible_facts.os_family }} + +- name: Include distribution specific variables + ansible.builtin.include_vars: '{{ lookup("ansible.builtin.first_found", params) }}' + vars: + params: + files: + - '{{ ansible_facts.distribution }}-{{ ansible_facts.distribution_version }}.yml' + - '{{ ansible_facts.distribution }}-{{ ansible_facts.distribution_major_version }}.yml' + - '{{ ansible_facts.distribution }}.yml' + - '{{ ansible_facts.os_family }}.yml' + - default.yml + paths: + - '{{ role_path }}/vars' + +- name: Install GnuPG + ansible.builtin.package: + name: '{{ gnupg_package_name }}' + when: has_gnupg diff --git a/tests/integration/targets/setup_gnupg/vars/Alpine.yml b/tests/integration/targets/setup_gnupg/vars/Alpine.yml new file mode 100644 index 000000000..99bd64412 --- /dev/null +++ b/tests/integration/targets/setup_gnupg/vars/Alpine.yml @@ -0,0 +1,8 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +# Alpine 3.12 should have GnuPG, but for some reason installing it fails... +has_gnupg: "{{ ansible_facts.distribution_version is version('3.13', '>=') }}" +gnupg_package_name: gpg diff --git a/tests/integration/targets/setup_gnupg/vars/CentOS-6.yml b/tests/integration/targets/setup_gnupg/vars/CentOS-6.yml new file mode 100644 index 000000000..fd09e9142 --- /dev/null +++ b/tests/integration/targets/setup_gnupg/vars/CentOS-6.yml @@ -0,0 +1,7 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +has_gnupg: false +# The GnuPG version included with CentOS 6 is too old, it doesn't understand --generate-key diff --git a/tests/integration/targets/setup_gnupg/vars/Darwin.yml b/tests/integration/targets/setup_gnupg/vars/Darwin.yml new file mode 100644 index 000000000..a7d999db8 --- /dev/null +++ b/tests/integration/targets/setup_gnupg/vars/Darwin.yml @@ -0,0 +1,7 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +# TODO Homebrew currently isn't happy when running as root, so assume we don't have GnuPG +has_gnupg: false diff --git a/tests/integration/targets/setup_gnupg/vars/RedHat.yml b/tests/integration/targets/setup_gnupg/vars/RedHat.yml new file mode 100644 index 000000000..3e82c4f98 --- /dev/null +++ b/tests/integration/targets/setup_gnupg/vars/RedHat.yml @@ -0,0 +1,7 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +has_gnupg: true +gnupg_package_name: gnupg2 diff --git a/tests/integration/targets/setup_gnupg/vars/default.yml b/tests/integration/targets/setup_gnupg/vars/default.yml new file mode 100644 index 000000000..6059ed80e --- /dev/null +++ b/tests/integration/targets/setup_gnupg/vars/default.yml @@ -0,0 +1,7 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +has_gnupg: true +gnupg_package_name: gnupg diff --git a/tests/sanity/ignore-2.13.txt b/tests/sanity/ignore-2.13.txt index 71c1a17d3..aefcd3071 100644 --- a/tests/sanity/ignore-2.13.txt +++ b/tests/sanity/ignore-2.13.txt @@ -1,4 +1,5 @@ .azure-pipelines/scripts/publish-codecov.py replace-urlopen +plugins/lookup/gpg_fingerprint.py validate-modules:invalid-documentation plugins/modules/openssl_csr_info.py validate-modules:invalid-documentation plugins/modules/openssl_privatekey_info.py validate-modules:invalid-documentation plugins/modules/openssl_publickey_info.py validate-modules:invalid-documentation diff --git a/tests/sanity/ignore-2.14.txt b/tests/sanity/ignore-2.14.txt index 71c1a17d3..aefcd3071 100644 --- a/tests/sanity/ignore-2.14.txt +++ b/tests/sanity/ignore-2.14.txt @@ -1,4 +1,5 @@ .azure-pipelines/scripts/publish-codecov.py replace-urlopen +plugins/lookup/gpg_fingerprint.py validate-modules:invalid-documentation plugins/modules/openssl_csr_info.py validate-modules:invalid-documentation plugins/modules/openssl_privatekey_info.py validate-modules:invalid-documentation plugins/modules/openssl_publickey_info.py validate-modules:invalid-documentation