From b7ef2c1589180f274876d5618c451e8a2b40066d Mon Sep 17 00:00:00 2001 From: Miklos Sagi Date: Mon, 20 Feb 2023 16:58:21 +0000 Subject: [PATCH] ansible-playbook -K breaks when passwords have quotes (#79837) Now only 'unquote' when ini config file is the source --- .../79837-unquoting-only-when-origin-is-ini.yml | 2 ++ lib/ansible/config/manager.py | 8 ++++++-- test/units/config/test_manager.py | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/79837-unquoting-only-when-origin-is-ini.yml diff --git a/changelogs/fragments/79837-unquoting-only-when-origin-is-ini.yml b/changelogs/fragments/79837-unquoting-only-when-origin-is-ini.yml new file mode 100644 index 00000000000..4017af36f2d --- /dev/null +++ b/changelogs/fragments/79837-unquoting-only-when-origin-is-ini.yml @@ -0,0 +1,2 @@ +bugfixes: + - ansible-playbook -K breaks when passwords have quotes (https://github.com/ansible/ansible/issues/79836). diff --git a/lib/ansible/config/manager.py b/lib/ansible/config/manager.py index 203f7180fd8..bcb98047d46 100644 --- a/lib/ansible/config/manager.py +++ b/lib/ansible/config/manager.py @@ -143,13 +143,17 @@ def ensure_type(value, value_type, origin=None): elif value_type in ('str', 'string'): if isinstance(value, (string_types, AnsibleVaultEncryptedUnicode, bool, int, float, complex)): - value = unquote(to_text(value, errors='surrogate_or_strict')) + value = to_text(value, errors='surrogate_or_strict') + if origin == 'ini': + value = unquote(value) else: errmsg = 'string' # defaults to string type elif isinstance(value, (string_types, AnsibleVaultEncryptedUnicode)): - value = unquote(to_text(value, errors='surrogate_or_strict')) + value = to_text(value, errors='surrogate_or_strict') + if origin == 'ini': + value = unquote(value) if errmsg: raise ValueError('Invalid type provided for "%s": %s' % (errmsg, to_native(value))) diff --git a/test/units/config/test_manager.py b/test/units/config/test_manager.py index 9e6b6696540..3f3347f1cd3 100644 --- a/test/units/config/test_manager.py +++ b/test/units/config/test_manager.py @@ -65,6 +65,15 @@ ensure_test_data = [ ('None', 'none', type(None)) ] +ensure_unquoting_test_data = [ + ('"value"', '"value"', 'str', 'env'), + ('"value"', '"value"', 'str', 'yaml'), + ('"value"', 'value', 'str', 'ini'), + ('\'value\'', 'value', 'str', 'ini'), + ('\'\'value\'\'', '\'value\'', 'str', 'ini'), + ('""value""', '"value"', 'str', 'ini') +] + class TestConfigManager: @classmethod @@ -79,6 +88,11 @@ class TestConfigManager: def test_ensure_type(self, value, expected_type, python_type): assert isinstance(ensure_type(value, expected_type), python_type) + @pytest.mark.parametrize("value, expected_value, value_type, origin", ensure_unquoting_test_data) + def test_ensure_type_unquoting(self, value, expected_value, value_type, origin): + actual_value = ensure_type(value, value_type, origin) + assert actual_value == expected_value + def test_resolve_path(self): assert os.path.join(curdir, 'test.yml') == resolve_path('./test.yml', cfg_file)