diff --git a/changelogs/fragments/preserve_config_origin.yml b/changelogs/fragments/preserve_config_origin.yml new file mode 100644 index 00000000000..14d87e1c4ae --- /dev/null +++ b/changelogs/fragments/preserve_config_origin.yml @@ -0,0 +1,2 @@ +bugfixes: + - config - Preserve or apply Origin tag to values returned by config. diff --git a/lib/ansible/cli/arguments/option_helpers.py b/lib/ansible/cli/arguments/option_helpers.py index 131ec8caeb2..c5bfdff903b 100644 --- a/lib/ansible/cli/arguments/option_helpers.py +++ b/lib/ansible/cli/arguments/option_helpers.py @@ -535,13 +535,17 @@ def _tagged_type_factory(name: str, func: t.Callable[[str], object], /) -> t.Cal def tag_value(value: str) -> object: result = func(value) - if result is value: + if result is value or func is str: # Values which are not mutated are automatically trusted for templating. # The `is` reference equality is critically important, as other types may only alter the tags, so object equality is # not sufficient to prevent them being tagged as trusted when they should not. + # Explicitly include all usages using the `str` type factory since it strips tags. result = TrustedAsTemplate().tag(result) - return Origin(description=f'').tag(result) + if not (origin := Origin.get_tag(value)): + origin = Origin(description=f'') + + return origin.tag(result) tag_value._name = name # simplify debugging by attaching the argument name to the function diff --git a/lib/ansible/config/manager.py b/lib/ansible/config/manager.py index fb6b8f3dc2e..e255f2dc9f0 100644 --- a/lib/ansible/config/manager.py +++ b/lib/ansible/config/manager.py @@ -16,6 +16,7 @@ import typing as t from collections.abc import Mapping, Sequence from jinja2.nativetypes import NativeEnvironment +from ansible._internal._datatag import _tags from ansible.errors import AnsibleOptionsError, AnsibleError, AnsibleUndefinedConfigEntry, AnsibleRequiredOptionError from ansible.module_utils._internal._datatag import AnsibleTagHelper from ansible.module_utils.common.sentinel import Sentinel @@ -700,6 +701,9 @@ class ConfigManager: else: raise AnsibleUndefinedConfigEntry(f'No config definition exists for {_get_config_label(plugin_type, plugin_name, config)}.') + if not _tags.Origin.is_tagged_on(value): + value = _tags.Origin(description=f'').tag(value) + return value, origin def initialize_plugin_configuration_definitions(self, plugin_type, name, defs):