mirror of
https://github.com/ansible/ansible.git
synced 2026-08-03 08:03:05 +02:00
Encryptedstring redact fixes (#85390)
* misc DTFIX/docstring cleanup
* fix EncryptedString redaction, add tests
Co-authored-by: Matt Clay <matt@mystile.com>
* Fix test failures
---------
Co-authored-by: Matt Clay <matt@mystile.com>
(cherry picked from commit 649c9ec443)
This commit is contained in:
@@ -10,8 +10,6 @@ from ansible.plugins.callback import CallbackBase
|
||||
|
||||
|
||||
class CallbackModule(CallbackBase):
|
||||
# DTFIX1: validate VaultedValue redaction behavior
|
||||
|
||||
CALLBACK_NEEDS_ENABLED = True
|
||||
seen_tr = [] # track taskresult instances to ensure every call sees a unique instance
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import typing as t
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible._internal._json import AnsibleVariableVisitor, EncryptedStringBehavior
|
||||
from ansible.errors import AnsibleVariableTypeError
|
||||
from ansible.parsing.vault import EncryptedString, AnsibleVaultError
|
||||
from units.mock.vault_helper import VaultTestHelper
|
||||
|
||||
|
||||
@pytest.mark.parametrize("behavior, decryptable, expected", (
|
||||
(EncryptedStringBehavior.PRESERVE, True, None),
|
||||
(EncryptedStringBehavior.PRESERVE, False, None),
|
||||
(EncryptedStringBehavior.DECRYPT, True, "plaintext"),
|
||||
(EncryptedStringBehavior.DECRYPT, False, AnsibleVaultError("no vault secrets")),
|
||||
(EncryptedStringBehavior.REDACT, True, "<redacted>"),
|
||||
(EncryptedStringBehavior.REDACT, False, "<redacted>"),
|
||||
(EncryptedStringBehavior.FAIL, True, AnsibleVariableTypeError("unsupported for variable storage")),
|
||||
(EncryptedStringBehavior.FAIL, False, AnsibleVariableTypeError("unsupported for variable storage")),
|
||||
), ids=str)
|
||||
def test_encrypted_string_behavior(
|
||||
behavior: EncryptedStringBehavior,
|
||||
decryptable: bool,
|
||||
expected: t.Any,
|
||||
_vault_secrets_context: None,
|
||||
) -> None:
|
||||
if decryptable:
|
||||
value = VaultTestHelper.make_encrypted_string('plaintext')
|
||||
else:
|
||||
# valid ciphertext with intentionally unavailable secret
|
||||
value = EncryptedString(ciphertext=(
|
||||
'$ANSIBLE_VAULT;1.1;AES256\n'
|
||||
'333665623864636331356364306535613231613833616662656130613665336561316435393736366636663864396636326330626530643238653462333562350a396162623230643'
|
||||
'037396430383335386663363534353733386430643764303062633738613533336135653563313139373038333964316264633265376435370a326137363231646261303036356636'
|
||||
'37346430303361316436306130663461393832656134346639326365633830373361376236343961386164323538353962'
|
||||
))
|
||||
|
||||
avv = AnsibleVariableVisitor(encrypted_string_behavior=behavior)
|
||||
|
||||
if isinstance(expected, Exception):
|
||||
with pytest.raises(type(expected), match=expected.args[0]):
|
||||
avv.visit(value)
|
||||
else:
|
||||
result = avv.visit(value)
|
||||
|
||||
if expected is None:
|
||||
assert result is value
|
||||
else:
|
||||
assert result == expected
|
||||
@@ -26,7 +26,9 @@ import unittest
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible._internal._datatag._tags import Origin
|
||||
from ansible.parsing.vault import EncryptedString
|
||||
from ansible.utils.vars import combine_vars, merge_hash, transform_to_native_types
|
||||
from units.mock.vault_helper import VaultTestHelper
|
||||
|
||||
|
||||
class TestVariableUtils(unittest.TestCase):
|
||||
@@ -279,12 +281,27 @@ class TestVariableUtils(unittest.TestCase):
|
||||
|
||||
|
||||
def test_transform_to_native_types() -> None:
|
||||
"""Verify that transform_to_native_types results in native types for both keys and values."""
|
||||
value = {Origin(description="blah").tag("tagged_key"): Origin(description="blah").tag("value with tagged key")}
|
||||
"""Verify that transform_to_native_types results in native types for both keys and values, with default redaction."""
|
||||
value = {
|
||||
Origin(description="blah").tag("tagged_key"): Origin(description="blah").tag("value with tagged key"),
|
||||
# use a bogus EncryptedString instance with no VaultSecretsContext active; ensures that transform with redaction does not attempt decryption
|
||||
"redact_this": EncryptedString(ciphertext="bogus")
|
||||
}
|
||||
|
||||
result = transform_to_native_types(value)
|
||||
|
||||
assert result == dict(tagged_key="value with tagged key")
|
||||
assert result == dict(tagged_key="value with tagged key", redact_this='<redacted>')
|
||||
|
||||
assert all(type(key) is str for key in result.keys()) # pylint: disable=unidiomatic-typecheck
|
||||
assert all(type(value) is str for value in result.values()) # pylint: disable=unidiomatic-typecheck
|
||||
|
||||
|
||||
def test_transform_to_native_types_unredacted(_vault_secrets_context: None) -> None:
|
||||
"""Verify that transform with redaction disabled returns a plain string decrypted value."""
|
||||
plaintext = "hello"
|
||||
value = dict(enc=VaultTestHelper.make_encrypted_string(plaintext))
|
||||
result = transform_to_native_types(value, redact=False)
|
||||
|
||||
assert result == dict(enc=plaintext)
|
||||
assert all(type(key) is str for key in result.keys()) # pylint: disable=unidiomatic-typecheck
|
||||
assert all(type(value) is str for value in result.values()) # pylint: disable=unidiomatic-typecheck
|
||||
|
||||
Reference in New Issue
Block a user