From e7c423964005a5bf867ecedebc5c3d953475c664 Mon Sep 17 00:00:00 2001 From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> Date: Sat, 20 Apr 2024 10:08:29 +0200 Subject: [PATCH] [PR #8225/7fd37ea2 backport][stable-6] inventory plugins: make wrapping variables as unsafe smarter to avoid triggering an AWX bug (#8244) inventory plugins: make wrapping variables as unsafe smarter to avoid triggering an AWX bug (#8225) Make wrapping variables as unsafe smarter to avoid triggering an AWX bug. (cherry picked from commit 7fd37ea247ba351b541d472cbedefc60fb98473f) Co-authored-by: Felix Fontein --- .github/BOTMETA.yml | 5 ++-- changelogs/fragments/8225-unsafe.yml | 2 ++ plugins/inventory/cobbler.py | 3 +- plugins/inventory/gitlab_runners.py | 3 +- plugins/inventory/icinga2.py | 3 +- plugins/inventory/linode.py | 3 +- plugins/inventory/lxd.py | 2 +- plugins/inventory/nmap.py | 3 +- plugins/inventory/online.py | 3 +- plugins/inventory/opennebula.py | 3 +- plugins/inventory/proxmox.py | 2 +- plugins/inventory/scaleway.py | 2 +- plugins/inventory/stackpath_compute.py | 3 +- plugins/inventory/virtualbox.py | 3 +- plugins/inventory/xen_orchestra.py | 2 +- plugins/plugin_utils/unsafe.py | 41 ++++++++++++++++++++++++++ 16 files changed, 68 insertions(+), 15 deletions(-) create mode 100644 changelogs/fragments/8225-unsafe.yml create mode 100644 plugins/plugin_utils/unsafe.py diff --git a/.github/BOTMETA.yml b/.github/BOTMETA.yml index 8761ec59be..3cb9ef7e21 100644 --- a/.github/BOTMETA.yml +++ b/.github/BOTMETA.yml @@ -1360,6 +1360,8 @@ files: ignore: matze labels: zypper maintainers: $team_suse + $plugin_utils/unsafe.py: + maintainers: felixfontein $tests/a_module.py: maintainers: felixfontein ######################### @@ -1379,7 +1381,6 @@ macros: becomes: plugins/become caches: plugins/cache callbacks: plugins/callback - cliconfs: plugins/cliconf connections: plugins/connection doc_fragments: plugins/doc_fragments filters: plugins/filter @@ -1387,7 +1388,7 @@ macros: lookups: plugins/lookup module_utils: plugins/module_utils modules: plugins/modules - terminals: plugins/terminal + plugin_utils: plugins/plugin_utils tests: plugins/test team_ansible_core: team_aix: MorrisA bcoca d-little flynn1973 gforster kairoaraujo marvin-sinister mator molekuul ramooncamacho wtcross diff --git a/changelogs/fragments/8225-unsafe.yml b/changelogs/fragments/8225-unsafe.yml new file mode 100644 index 0000000000..496797ef74 --- /dev/null +++ b/changelogs/fragments/8225-unsafe.yml @@ -0,0 +1,2 @@ +bugfixes: + - "inventory plugins - add unsafe wrapper to avoid marking strings that do not contain ``{`` or ``}`` as unsafe, to work around a bug in AWX ((https://github.com/ansible-collections/community.general/issues/8212, https://github.com/ansible-collections/community.general/pull/8225)." diff --git a/plugins/inventory/cobbler.py b/plugins/inventory/cobbler.py index cfa77eaead..7b45381239 100644 --- a/plugins/inventory/cobbler.py +++ b/plugins/inventory/cobbler.py @@ -88,7 +88,8 @@ from ansible.module_utils.common.text.converters import to_text from ansible.module_utils.six import iteritems from ansible.plugins.inventory import BaseInventoryPlugin, Cacheable, to_safe_group_name from ansible.module_utils.six import text_type -from ansible.utils.unsafe_proxy import wrap_var as make_unsafe + +from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe # xmlrpc try: diff --git a/plugins/inventory/gitlab_runners.py b/plugins/inventory/gitlab_runners.py index e6fcdbc5a1..e27606767f 100644 --- a/plugins/inventory/gitlab_runners.py +++ b/plugins/inventory/gitlab_runners.py @@ -84,7 +84,8 @@ keyed_groups: from ansible.errors import AnsibleError, AnsibleParserError from ansible.module_utils.common.text.converters import to_native from ansible.plugins.inventory import BaseInventoryPlugin, Constructable -from ansible.utils.unsafe_proxy import wrap_var as make_unsafe + +from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe try: import gitlab diff --git a/plugins/inventory/icinga2.py b/plugins/inventory/icinga2.py index 29bee907b2..4915594258 100644 --- a/plugins/inventory/icinga2.py +++ b/plugins/inventory/icinga2.py @@ -96,7 +96,8 @@ from ansible.errors import AnsibleParserError from ansible.plugins.inventory import BaseInventoryPlugin, Constructable from ansible.module_utils.urls import open_url from ansible.module_utils.six.moves.urllib.error import HTTPError -from ansible.utils.unsafe_proxy import wrap_var as make_unsafe + +from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe class InventoryModule(BaseInventoryPlugin, Constructable): diff --git a/plugins/inventory/linode.py b/plugins/inventory/linode.py index 46c9ddc761..8f171bd31d 100644 --- a/plugins/inventory/linode.py +++ b/plugins/inventory/linode.py @@ -123,7 +123,8 @@ compose: from ansible.errors import AnsibleError from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable -from ansible.utils.unsafe_proxy import wrap_var as make_unsafe + +from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe try: diff --git a/plugins/inventory/lxd.py b/plugins/inventory/lxd.py index 3ad2fb01d2..e4bb38941c 100644 --- a/plugins/inventory/lxd.py +++ b/plugins/inventory/lxd.py @@ -161,7 +161,7 @@ from ansible.module_utils.six import raise_from from ansible.errors import AnsibleError, AnsibleParserError from ansible.module_utils.six.moves.urllib.parse import urlencode from ansible_collections.community.general.plugins.module_utils.lxd import LXDClient, LXDClientException -from ansible.utils.unsafe_proxy import wrap_var as make_unsafe +from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe try: import ipaddress diff --git a/plugins/inventory/nmap.py b/plugins/inventory/nmap.py index 10ae7631b3..649081fa07 100644 --- a/plugins/inventory/nmap.py +++ b/plugins/inventory/nmap.py @@ -121,7 +121,8 @@ from ansible.errors import AnsibleParserError from ansible.module_utils.common.text.converters import to_native, to_text from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable from ansible.module_utils.common.process import get_bin_path -from ansible.utils.unsafe_proxy import wrap_var as make_unsafe + +from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable): diff --git a/plugins/inventory/online.py b/plugins/inventory/online.py index b3a9ecd379..9355d9d414 100644 --- a/plugins/inventory/online.py +++ b/plugins/inventory/online.py @@ -68,7 +68,8 @@ from ansible.plugins.inventory import BaseInventoryPlugin from ansible.module_utils.common.text.converters import to_text from ansible.module_utils.ansible_release import __version__ as ansible_version from ansible.module_utils.six.moves.urllib.parse import urljoin -from ansible.utils.unsafe_proxy import wrap_var as make_unsafe + +from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe class InventoryModule(BaseInventoryPlugin): diff --git a/plugins/inventory/opennebula.py b/plugins/inventory/opennebula.py index 83fd759f96..c19c6a16b4 100644 --- a/plugins/inventory/opennebula.py +++ b/plugins/inventory/opennebula.py @@ -97,7 +97,8 @@ except ImportError: from ansible.errors import AnsibleError from ansible.plugins.inventory import BaseInventoryPlugin, Constructable from ansible.module_utils.common.text.converters import to_native -from ansible.utils.unsafe_proxy import wrap_var as make_unsafe + +from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe from collections import namedtuple import os diff --git a/plugins/inventory/proxmox.py b/plugins/inventory/proxmox.py index 39ace24764..1668034b76 100644 --- a/plugins/inventory/proxmox.py +++ b/plugins/inventory/proxmox.py @@ -222,9 +222,9 @@ from ansible.module_utils.common.text.converters import to_native from ansible.module_utils.six import string_types from ansible.module_utils.six.moves.urllib.parse import urlencode from ansible.utils.display import Display -from ansible.utils.unsafe_proxy import wrap_var as make_unsafe from ansible_collections.community.general.plugins.module_utils.version import LooseVersion +from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe # 3rd party imports try: diff --git a/plugins/inventory/scaleway.py b/plugins/inventory/scaleway.py index ea4fb26ca7..eeb7875c61 100644 --- a/plugins/inventory/scaleway.py +++ b/plugins/inventory/scaleway.py @@ -121,10 +121,10 @@ else: from ansible.errors import AnsibleError from ansible.plugins.inventory import BaseInventoryPlugin, Constructable from ansible_collections.community.general.plugins.module_utils.scaleway import SCALEWAY_LOCATION, parse_pagination_link +from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe from ansible.module_utils.urls import open_url from ansible.module_utils.common.text.converters import to_native, to_text from ansible.module_utils.six import raise_from -from ansible.utils.unsafe_proxy import wrap_var as make_unsafe import ansible.module_utils.six.moves.urllib.parse as urllib_parse diff --git a/plugins/inventory/stackpath_compute.py b/plugins/inventory/stackpath_compute.py index 9a556d39e0..6b48a49f12 100644 --- a/plugins/inventory/stackpath_compute.py +++ b/plugins/inventory/stackpath_compute.py @@ -72,7 +72,8 @@ from ansible.plugins.inventory import ( Cacheable ) from ansible.utils.display import Display -from ansible.utils.unsafe_proxy import wrap_var as make_unsafe + +from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe display = Display() diff --git a/plugins/inventory/virtualbox.py b/plugins/inventory/virtualbox.py index 8604808e15..79b04ec722 100644 --- a/plugins/inventory/virtualbox.py +++ b/plugins/inventory/virtualbox.py @@ -62,7 +62,8 @@ from ansible.module_utils.common.text.converters import to_bytes, to_native, to_ from ansible.module_utils.common._collections_compat import MutableMapping from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable from ansible.module_utils.common.process import get_bin_path -from ansible.utils.unsafe_proxy import wrap_var as make_unsafe + +from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable): diff --git a/plugins/inventory/xen_orchestra.py b/plugins/inventory/xen_orchestra.py index 48750e1769..9740b7af69 100644 --- a/plugins/inventory/xen_orchestra.py +++ b/plugins/inventory/xen_orchestra.py @@ -82,9 +82,9 @@ from time import sleep from ansible.errors import AnsibleError from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable -from ansible.utils.unsafe_proxy import wrap_var as make_unsafe from ansible_collections.community.general.plugins.module_utils.version import LooseVersion +from ansible_collections.community.general.plugins.plugin_utils.unsafe import make_unsafe # 3rd party imports try: diff --git a/plugins/plugin_utils/unsafe.py b/plugins/plugin_utils/unsafe.py new file mode 100644 index 0000000000..1eb61bea0f --- /dev/null +++ b/plugins/plugin_utils/unsafe.py @@ -0,0 +1,41 @@ +# 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 re + +from ansible.module_utils.six import binary_type, text_type +from ansible.module_utils.common._collections_compat import Mapping, Set +from ansible.module_utils.common.collections import is_sequence +from ansible.utils.unsafe_proxy import ( + AnsibleUnsafe, + wrap_var as _make_unsafe, +) + +_RE_TEMPLATE_CHARS = re.compile(u'[{}]') +_RE_TEMPLATE_CHARS_BYTES = re.compile(b'[{}]') + + +def make_unsafe(value): + if value is None or isinstance(value, AnsibleUnsafe): + return value + + if isinstance(value, Mapping): + return dict((make_unsafe(key), make_unsafe(val)) for key, val in value.items()) + elif isinstance(value, Set): + return set(make_unsafe(elt) for elt in value) + elif is_sequence(value): + return type(value)(make_unsafe(elt) for elt in value) + elif isinstance(value, binary_type): + if _RE_TEMPLATE_CHARS_BYTES.search(value): + value = _make_unsafe(value) + return value + elif isinstance(value, text_type): + if _RE_TEMPLATE_CHARS.search(value): + value = _make_unsafe(value) + return value + + return value