diff --git a/changelogs/fragments/71609-is_string-vault.yml b/changelogs/fragments/71609-is_string-vault.yml new file mode 100644 index 00000000000..89ddd91913e --- /dev/null +++ b/changelogs/fragments/71609-is_string-vault.yml @@ -0,0 +1,3 @@ +bugfixes: +- is_string/vault - Ensure the is_string helper properly identifies AnsibleVaultEncryptedUnicode + as a string (https://github.com/ansible/ansible/pull/71609) diff --git a/lib/ansible/module_utils/common/collections.py b/lib/ansible/module_utils/common/collections.py index 78f8bf3a296..1b120b8d544 100644 --- a/lib/ansible/module_utils/common/collections.py +++ b/lib/ansible/module_utils/common/collections.py @@ -67,7 +67,8 @@ class ImmutableDict(Hashable, Mapping): def is_string(seq): """Identify whether the input has a string-like type (inclding bytes).""" - return isinstance(seq, (text_type, binary_type)) + # AnsibleVaultEncryptedUnicode inherits from Sequence, but is expected to be a string like object + return isinstance(seq, (text_type, binary_type)) or getattr(seq, '__ENCRYPTED__', False) def is_iterable(seq, include_strings=False): diff --git a/lib/ansible/module_utils/common/json.py b/lib/ansible/module_utils/common/json.py index 3ac9eecf2b4..866a89663b0 100644 --- a/lib/ansible/module_utils/common/json.py +++ b/lib/ansible/module_utils/common/json.py @@ -31,7 +31,7 @@ def _preprocess_unsafe_encode(value): """ if _is_unsafe(value): value = {'__ansible_unsafe': to_text(value, errors='surrogate_or_strict', nonstring='strict')} - elif is_sequence(value) and not _is_vault(value): + elif is_sequence(value): value = [_preprocess_unsafe_encode(v) for v in value] elif isinstance(value, Mapping): value = dict((k, _preprocess_unsafe_encode(v)) for k, v in value.items()) diff --git a/test/units/module_utils/common/test_collections.py b/test/units/module_utils/common/test_collections.py index eb6e376a2cd..95b2a402f29 100644 --- a/test/units/module_utils/common/test_collections.py +++ b/test/units/module_utils/common/test_collections.py @@ -35,8 +35,21 @@ class IterableStub: return IteratorStub() +class FakeAnsibleVaultEncryptedUnicode(Sequence): + __ENCRYPTED__ = True + + def __init__(self, data): + self.data = data + + def __getitem__(self, index): + return self.data[index] + + def __len__(self): + return len(self.data) + + TEST_STRINGS = u'he', u'Україна', u'Česká republika' -TEST_STRINGS = TEST_STRINGS + tuple(s.encode('utf-8') for s in TEST_STRINGS) +TEST_STRINGS = TEST_STRINGS + tuple(s.encode('utf-8') for s in TEST_STRINGS) + (FakeAnsibleVaultEncryptedUnicode(u'foo'),) TEST_ITEMS_NON_SEQUENCES = ( {}, object(), frozenset(),