update ansible collections sops, docker and debops
All checks were successful
/ build (pull_request) Successful in 28s
/ Ansible Lint (push) Successful in 2m36s
/ Ansible Lint (pull_request) Successful in 2m41s

This commit is contained in:
chris 2026-09-21 22:26:20 +02:00
commit e31ee5e39c
Signed by: c6ristian
SSH key fingerprint: SHA256:B3m+yzpaxGXSEcDBpPHfvza/DNC0wuX+CKMeGq8wgak
910 changed files with 27667 additions and 19786 deletions

View file

@ -4,6 +4,7 @@
from __future__ import annotations
import typing as t
from collections.abc import Sequence, Mapping
from ansible.module_utils.common.text.converters import to_native
@ -19,10 +20,19 @@ try:
except ImportError:
HAS_DATATAGGING = False
try:
from ansible.plugins.action import VariableLayer # type: ignore[attr-defined]
HAS_REGISTER_HOST_VARIABLES = True
except ImportError:
HAS_REGISTER_HOST_VARIABLES = False
if t.TYPE_CHECKING:
from ansible_collections.community.sops.plugins.plugin_utils.action_module import AnsibleActionModule
display = Display()
def _make_safe(value):
def _make_safe(value: t.Any) -> t.Any:
if HAS_DATATAGGING and isinstance(value, str):
return _trust_as_template(value)
return value
@ -30,7 +40,7 @@ def _make_safe(value):
class ActionModule(ActionModuleBase):
def _load(self, filename, module):
def _load(self, filename: str, module: AnsibleActionModule) -> dict:
def get_option_value(argument_name):
return module.params.get(argument_name)
@ -71,6 +81,7 @@ class ActionModule(ActionModuleBase):
file=dict(type='path', required=True),
name=dict(type='str'),
expressions=dict(type='str', default='ignore', choices=['ignore', 'evaluate-on-load', 'lazy-evaluation']),
return_method=dict(type='str', default='auto', choices=['auto', 'facts-only', 'vars-only']),
),
)
argument_spec.argument_spec.update(get_sops_argument_spec())
@ -81,7 +92,15 @@ class ActionModule(ActionModuleBase):
if expressions == 'lazy-evaluation' and not HAS_DATATAGGING:
module.fail_json(msg='expressions=lazy-evaluation requires ansible-core 2.19+ with Data Tagging support.')
data = dict()
return_method_str = module.params['return_method']
if return_method_str == 'auto':
return_as_facts = not HAS_REGISTER_HOST_VARIABLES
else:
return_as_facts = return_method_str == 'facts-only'
if not HAS_REGISTER_HOST_VARIABLES and not return_as_facts:
module.fail_json(msg='return_method=vars-only requires ansible-core 2.21+')
data = {}
files = []
try:
filename = self._find_needle('vars', module.params['file'])
@ -94,8 +113,7 @@ class ActionModule(ActionModuleBase):
if name is None:
value = data
else:
value = dict()
value[name] = data
value = {name: data}
if expressions == 'evaluate-on-load':
value = self._evaluate(value)
@ -103,8 +121,14 @@ class ActionModule(ActionModuleBase):
if expressions == 'lazy-evaluation':
value = self._make_safe(value)
module.exit_json(
ansible_included_var_files=files,
ansible_facts=value,
_ansible_no_log=True,
)
result = {
'ansible_included_var_files': files,
'_ansible_no_log': True,
}
if return_as_facts:
result['ansible_facts'] = value
else:
self.register_host_variables(variables=value, layer=VariableLayer.INCLUDE_VARS)
module.exit_json(**result)

View file

@ -34,6 +34,15 @@ options:
- Requires SOPS 3.7.0+.
type: path
version_added: 1.4.0
age_key_cmd:
description:
- A command that SOPS will execute to obtain an age private key that SOPS can use to decrypt encrypted files.
- Will be set as the E(SOPS_AGE_KEY_CMD) environment variable when calling SOPS.
- Requires SOPS 3.10.0+.
- When running this command and when SOPS 3.12.0+ is used, SOPS will set the E(SOPS_AGE_RECIPIENT) variable
to the identity of the key it wants to use to decrypt.
type: str
version_added: 2.3.0
age_ssh_private_keyfile:
description:
- The file containing the SSH private key that SOPS can use to decrypt encrypted files.
@ -42,6 +51,15 @@ options:
- Requires SOPS 3.10.0+.
type: path
version_added: 1.4.0
age_ssh_private_key_cmd:
description:
- A command that SOPS will execute to obtain an SSH private key that SOPS can use to decrypt encrypted files.
- Will be set as the E(SOPS_AGE_SSH_PRIVATE_KEY_CMD) environment variable when calling SOPS.
- When running this command, SOPS will set the E(SOPS_AGE_RECIPIENT) variable to the identity of the key
it wants to use to decrypt.
- Requires SOPS 3.12.0+.
type: str
version_added: 2.3.0
aws_profile:
description:
- The AWS profile to use for requests to AWS.
@ -66,6 +84,23 @@ options:
- Sets the environment variable E(AWS_SESSION_TOKEN) for the SOPS call.
type: str
version_added: 1.0.0
gcp_oauth_access_token:
description:
- Provide a Google Cloud OAauth token.
- Will be set as the E(GOOGLE_OAUTH_ACCESS_TOKEN) environment variable when calling SOPS.
- Requires SOPS 3.10.0+.
type: str
version_added: 3.2.0
gcp_kms_client_type:
description:
- Determine which client to use to communicate with Google Cloud Services.
- Will be set as the E(SOPS_GCP_KMS_CLIENT_TYPE) environment variable when calling SOPS.
- Requires SOPS 3.12.0+.
type: str
choices:
rest: Use REST client
grpc: Use gRPC client
version_added: 3.2.0
config_path:
description:
- Path to the SOPS configuration file.
@ -90,6 +125,12 @@ options:
version_added: 1.0.0
"""
ANSIBLE_PLUGIN = r'''
options:
sops_binary:
type: str
'''
ANSIBLE_VARIABLES = r'''
options:
sops_binary:
@ -101,9 +142,15 @@ options:
age_keyfile:
vars:
- name: sops_age_keyfile
age_key_cmd:
vars:
- name: sops_age_key_cmd
age_ssh_private_keyfile:
vars:
- name: sops_age_ssh_private_keyfile
age_ssh_private_key_cmd:
vars:
- name: sops_age_ssh_private_key_cmd
aws_profile:
vars:
- name: sops_aws_profile
@ -118,6 +165,12 @@ options:
- name: sops_session_token
- name: sops_aws_session_token
version_added: 1.2.0
gcp_oauth_access_token:
vars:
- name: sops_gcp_oauth_access_token
gcp_kms_client_type:
vars:
- name: sops_gcp_kms_client_type
config_path:
vars:
- name: sops_config_path
@ -141,9 +194,15 @@ options:
age_keyfile:
env:
- name: ANSIBLE_SOPS_AGE_KEYFILE
age_key_cmd:
env:
- name: ANSIBLE_SOPS_AGE_KEY_CMD
age_ssh_private_keyfile:
env:
- name: ANSIBLE_SOPS_AGE_SSH_PRIVATE_KEYFILE
age_ssh_private_key_cmd:
env:
- name: ANSIBLE_SOPS_AGE_SSH_PRIVATE_KEY_CMD
aws_profile:
env:
- name: ANSIBLE_SOPS_AWS_PROFILE
@ -160,6 +219,12 @@ options:
env:
- name: ANSIBLE_SOPS_AWS_SESSION_TOKEN
version_added: 1.2.0
gcp_oauth_access_token:
env:
- name: ANSIBLE_SOPS_GCP_OAUTH_ACCESS_TOKEN
gcp_kms_client_type:
env:
- name: ANSIBLE_SOPS_GCP_KMS_CLIENT_TYPE
config_path:
env:
- name: ANSIBLE_SOPS_CONFIG_PATH
@ -188,10 +253,18 @@ options:
ini:
- section: community.sops
key: age_keyfile
age_key_cmd:
ini:
- section: community.sops
key: age_key_cmd
age_ssh_private_keyfile:
ini:
- section: community.sops
key: age_ssh_private_keyfile
age_ssh_private_key_cmd:
ini:
- section: community.sops
key: age_ssh_private_key_cmd
aws_profile:
ini:
- section: community.sops
@ -210,6 +283,13 @@ options:
- section: community.sops
key: aws_session_token
version_added: 1.2.0
# We do not provide an INI key for
# gcp_oauth_access_token
# to make sure that secrets cannot be provided in ansible.ini. Use environment variables or another mechanism for that.
gcp_kms_client_type:
ini:
- section: community.sops
key: gcp_kms_client_type
config_path:
ini:
- section: community.sops
@ -272,6 +352,14 @@ options:
type: list
elements: str
version_added: 1.0.0
huawei_cloud_kms:
description:
- HuaweiCloud KMS key IDs to use.
- This corresponds to the SOPS C(--hckms) option.
- Requires SOPS 3.12.0+.
type: list
elements: str
version_added: 3.2.0
unencrypted_suffix:
description:
- Override the unencrypted key suffix.

View file

@ -52,7 +52,7 @@ def pick_latest_version(version_list):
version_list = [v for v in version_list if '-' not in v and '+' not in v]
if not version_list:
return ''
return sorted(version_list, key=LooseVersion, reverse=True)[0]
return max(version_list, key=LooseVersion)
class FilterModule:

View file

@ -108,6 +108,7 @@ from ansible.module_utils.common.text.converters import to_bytes, to_native
from ansible.utils.display import Display
from ansible_collections.community.sops.plugins.module_utils.sops import Sops, SopsError
from ansible_collections.community.sops.plugins.plugin_utils._args import wrap_get_option_value_check_types
_VALID_TYPES = set(['binary', 'json', 'yaml', 'dotenv', 'ini'])
@ -115,7 +116,8 @@ _VALID_TYPES = set(['binary', 'json', 'yaml', 'dotenv', 'ini'])
def decrypt_filter(data, input_type='yaml', output_type='yaml', sops_binary='sops', rstrip=True, decode_output=True,
aws_profile=None, aws_access_key_id=None, aws_secret_access_key=None, aws_session_token=None,
config_path=None, enable_local_keyservice=True, keyservice=None, age_key=None, age_keyfile=None, age_ssh_private_keyfile=None):
config_path=None, enable_local_keyservice=True, keyservice=None, age_key=None, age_keyfile=None, age_ssh_private_keyfile=None,
age_key_cmd=None, age_ssh_private_key_cmd=None, gcp_oauth_access_token=None, gcp_kms_client_type=None):
'''Decrypt sops-encrypted data.'''
# Check parameters
@ -150,16 +152,33 @@ def decrypt_filter(data, input_type='yaml', output_type='yaml', sops_binary='sop
return enable_local_keyservice
if argument_name == 'keyservice':
return keyservice
raise AssertionError('internal error: should not be reached')
if argument_name == 'age_key_cmd':
return age_key_cmd
if argument_name == 'age_ssh_private_key_cmd':
return age_ssh_private_key_cmd
if argument_name == 'gcp_oauth_access_token':
return gcp_oauth_access_token
if argument_name == 'gcp_kms_client_type':
return gcp_kms_client_type
raise AssertionError('internal error: should not be reached') # pragma: no cover
# Decode
data = to_bytes(data)
try:
output = Sops.decrypt(
None, content=data, display=Display(), rstrip=rstrip, decode_output=decode_output,
input_type=input_type, output_type=output_type, get_option_value=get_option_value)
None,
content=data,
display=Display(),
rstrip=rstrip,
decode_output=decode_output,
input_type=input_type,
output_type=output_type,
get_option_value=wrap_get_option_value_check_types(get_option_value, add_encrypt_specific=False),
)
except SopsError as e:
raise AnsibleFilterError(to_native(e))
except ValueError as e:
raise AnsibleFilterError(f"Error in community.sops.decrypt filter: {e}")
return output

View file

@ -67,6 +67,7 @@ options:
type: str
version_added: 1.9.0
extends_documentation_fragment:
- community.sops.sops.ansible_plugin # must come before community.sops.sops!
- community.sops.sops
- community.sops.sops.ansible_variables
- community.sops.sops.ansible_env
@ -116,9 +117,12 @@ _raw:
import base64
from ansible.errors import AnsibleLookupError
from ansible.plugins.lookup import LookupBase
from ansible.module_utils.common.text.converters import to_native
from ansible.module_utils.compat.version import LooseVersion
from ansible.plugins.lookup import LookupBase
from ansible.release import __version__ as ansible_version
from ansible_collections.community.sops.plugins.module_utils.sops import Sops, SopsError
from ansible_collections.community.sops.plugins.plugin_utils._args import wrap_get_option_value_plugin_path
from ansible.utils.display import Display
display = Display()
@ -137,8 +141,25 @@ class LookupModule(LookupBase):
ret = []
def get_option_value(argument_name):
return self.get_option(argument_name)
try:
sops_binary, sops_binary_origin = self.get_option_and_origin("sops_binary")
if sops_binary is None and (
LooseVersion(ansible_version) < LooseVersion("2.18.8")
or
LooseVersion(ansible_version) == LooseVersion("2.19.0")
):
# Ansible-core < 2.18.8 and 2.19.0 are broken: https://github.com/ansible/ansible/issues/85480
sops_binary = self.get_option("sops_binary")
sops_binary_origin = "Direct"
except AttributeError:
# Ansible-core 2.15 has no get_option_and_origin()!
sops_binary = self.get_option("sops_binary")
sops_binary_origin = "Direct"
get_option_value = wrap_get_option_value_plugin_path(
self.get_option,
sops_binary=sops_binary,
sops_binary_origin=sops_binary_origin,
)
for term in terms:
display.debug("Sops lookup term: %s" % term)

View file

@ -96,11 +96,15 @@ def _create_env_variable(argument_name):
GENERAL_OPTIONS = {
'age_key': _create_env_variable('SOPS_AGE_KEY'),
'age_keyfile': _create_env_variable('SOPS_AGE_KEY_FILE'),
'age_key_cmd': _create_env_variable('SOPS_AGE_KEY_CMD'),
'age_ssh_private_keyfile': _create_env_variable('SOPS_AGE_SSH_PRIVATE_KEY_FILE'),
'age_ssh_private_key_cmd': _create_env_variable('SOPS_AGE_SSH_PRIVATE_KEY_CMD'),
'aws_profile': _create_single_arg('--aws-profile'),
'aws_access_key_id': _create_env_variable('AWS_ACCESS_KEY_ID'),
'aws_secret_access_key': _create_env_variable('AWS_SECRET_ACCESS_KEY'),
'aws_session_token': _create_env_variable('AWS_SESSION_TOKEN'),
'gcp_oauth_access_token': _create_env_variable('GOOGLE_OAUTH_ACCESS_TOKEN'),
'gcp_kms_client_type': _create_env_variable('SOPS_GCP_KMS_CLIENT_TYPE'),
'config_path': _create_single_arg('--config', pre=True),
'enable_local_keyservice': _create_boolean('--enable-local-keyservice=false', invert=True),
'keyservice': _create_repeated('--keyservice'),
@ -114,6 +118,7 @@ ENCRYPT_OPTIONS = {
'azure_kv': _create_comma_separated('--azure-kv'),
'hc_vault_transit': _create_comma_separated('--hc-vault-transit'),
'pgp': _create_comma_separated('--pgp'),
'huawei_cloud_kms': _create_comma_separated('--hckms'),
'unencrypted_suffix': _create_single_arg('--unencrypted-suffix'),
'encrypted_suffix': _create_single_arg('--encrypted-suffix'),
'unencrypted_regex': _create_single_arg('--unencrypted-regex'),
@ -289,7 +294,7 @@ class SopsRunner(object):
raise SopsError(path, 0, 'Cannot decode filestatus result: %s' % exc, operation='inspect')
_SOPS_RUNNER_CACHE = dict()
_SOPS_RUNNER_CACHE = dict() # type: dict[str, SopsRunner]
class Sops():
@ -357,9 +362,17 @@ def get_sops_argument_spec(add_encrypt_specific=False):
'age_keyfile': {
'type': 'path',
},
'age_key_cmd': {
'type': 'str',
'no_log': False,
},
'age_ssh_private_keyfile': {
'type': 'path',
},
'age_ssh_private_key_cmd': {
'type': 'str',
'no_log': False,
},
'aws_profile': {
'type': 'str',
},
@ -374,6 +387,14 @@ def get_sops_argument_spec(add_encrypt_specific=False):
'type': 'str',
'no_log': True,
},
'gcp_oauth_access_token': {
'type': 'str',
'no_log': True,
},
'gcp_kms_client_type': {
'type': 'str',
'choices': ['rest', 'grpc'],
},
'config_path': {
'type': 'path',
},
@ -412,6 +433,10 @@ def get_sops_argument_spec(add_encrypt_specific=False):
'type': 'list',
'elements': 'str',
},
'huawei_cloud_kms': {
'type': 'list',
'elements': 'str',
},
'unencrypted_suffix': {
'type': 'str',
},

View file

@ -42,6 +42,23 @@ options:
- ignore
- evaluate-on-load
- lazy-evaluation
return_method:
description:
- Determine how to return the results.
- Because of limitations of ansible-core < 2.21, the results were returned as Ansible facts.
Since ansible-core 2.21, it is possible to actually set variables, similar to how M(ansible.builtin.include_vars)
is working.
type: str
default: auto
choices:
auto:
- Return the results as facts for ansible-core < 2.21, and as variables for ansible-core >= 2.21.
facts-only:
- Return the results always as facts.
vars-only:
- Return the results always as variables.
- Fails for ansible-core < 2.21.
version_added: 2.3.0
extends_documentation_fragment:
- community.sops.sops
- community.sops.attributes
@ -61,7 +78,9 @@ attributes:
details:
- This action does not modify state.
facts:
support: full
support: partial
details:
- Only returns facts if O(return_method=facts-only), or O(return_method=auto) for ansible-core < 2.21.
idempotent:
support: N/A
details:
@ -105,7 +124,7 @@ EXAMPLES = r"""
RETURN = r"""
ansible_facts:
description: Variables that were included and their values.
returned: success
returned: success, and O(return_method=facts-only), or O(return_method=auto) for ansible-core < 2.21
type: dict
sample: {'variable': 'value'}
ansible_included_var_files:

View file

@ -110,7 +110,7 @@ try:
except ImportError:
YAML_IMP_ERR = traceback.format_exc()
HAS_YAML = False
yaml = None
yaml = None # type: ignore[assignment] # use better type later...
def get_data_type(module):
@ -122,7 +122,7 @@ def get_data_type(module):
return 'json'
if module.params['content_yaml'] is not None:
return 'yaml'
module.fail_json(msg='Internal error: unknown content type')
module.fail_json(msg='Internal error: unknown content type') # pragma: no cover
def compare_encoded_content(module, binary_data, content):
@ -144,7 +144,7 @@ def compare_encoded_content(module, binary_data, content):
except Exception:
# Treat parsing errors as content not equal
return False
module.fail_json(msg='Internal error: unknown content type')
module.fail_json(msg='Internal error: unknown content type') # pragma: no cover
def get_encoded_type_content(module, binary_data):
@ -156,7 +156,7 @@ def get_encoded_type_content(module, binary_data):
return 'json', json.dumps(module.params['content_json']).encode('utf-8')
if module.params['content_yaml'] is not None:
return 'yaml', yaml.safe_dump(module.params['content_yaml']).encode('utf-8')
module.fail_json(msg='Internal error: unknown content type')
module.fail_json(msg='Internal error: unknown content type') # pragma: no cover
def main():

View file

@ -0,0 +1,110 @@
# Copyright (c) 2026 Felix Fontein <felix@fontein.de>
# 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
# Note that this module util is **PRIVATE** to the collection. It can have breaking changes at any time.
# Do not use this from other collections or standalone plugins/modules!
from __future__ import annotations
import os
import typing as t
from ansible.module_utils.common.text.converters import to_bytes as _to_bytes
from ansible.module_utils.common.validation import check_type_bool as _check_type_bool
from ansible.module_utils.common.validation import check_type_dict as _check_type_dict
from ansible.module_utils.common.validation import check_type_int as _check_type_int
from ansible.module_utils.common.validation import check_type_float as _check_type_float
from ansible.module_utils.common.validation import check_type_list as _check_type_list
from ansible.module_utils.common.validation import check_type_path as _check_type_path
from ansible.module_utils.common.validation import check_type_str as _check_type_str
from ansible.utils.path import unfrackpath as _unfrackpath
from ansible_collections.community.sops.plugins.module_utils.sops import get_sops_argument_spec as _get_sops_argument_spec
if t.TYPE_CHECKING:
from collections.abc import Callable, Mapping # pragma: no cover
def wrap_get_option_value(
get_option_value: Callable[[str], t.Any],
*,
overrides: Mapping[str, t.Any],
) -> Callable[[str], t.Any]:
def new_get_option_value(option: str) -> t.Any:
if option in overrides:
return overrides[option]
return get_option_value(option)
return new_get_option_value
def wrap_get_option_value_plugin_path(
get_option_value: Callable[[str], t.Any],
*,
sops_binary: t.Any,
sops_binary_origin: str | None = "Direct",
) -> Callable[[str], t.Any]:
if isinstance(sops_binary, str):
candidate = sops_binary
# ansible.config.manager.resolve_path() handles {{CWD}}:
if "{{CWD}}" in candidate:
candidate = candidate.replace("{{CWD}}", os.getcwd())
basedir = sops_binary_origin if sops_binary_origin and os.path.isabs(sops_binary_origin) and os.path.exists(_to_bytes(sops_binary_origin)) else None
candidate = _unfrackpath(candidate, follow=False, basedir=basedir)
# Check whether the candidate is a file:
if os.path.isfile(candidate):
sops_binary = candidate
else:
# If not, fall back to what a module would do with the path
sops_binary = os.path.expanduser(os.path.expandvars(sops_binary))
overrides = {"sops_binary": sops_binary}
return wrap_get_option_value(get_option_value, overrides=overrides)
_TYPE_CHECKS = {
"dict": _check_type_dict,
"bool": _check_type_bool,
"int": _check_type_int,
"float": _check_type_float,
"str": lambda value: _check_type_str(value, allow_conversion=False),
"path": lambda value: _check_type_path(_check_type_str(value, allow_conversion=False)),
}
def _ensure_type_impl(value: t.Any, *, option_type: str) -> t.Any:
return _TYPE_CHECKS[option_type](value)
def _ensure_type(value: t.Any, *, option_type: str, elements_type: str | None, sensitive: bool) -> t.Any:
if value is None:
return None
if option_type != "list":
return _ensure_type_impl(value, option_type=option_type)
value = _check_type_list(value)
if elements_type is None:
# Our options do not have a list without 'elements', so this is unreachable.
# We still want to keep this code though...
return value # pragma: no cover
return [_ensure_type_impl(v, option_type=elements_type) for v in value]
def wrap_get_option_value_check_types(
get_option_value: Callable[[str], t.Any],
*,
add_encrypt_specific: bool,
) -> Callable[[str], t.Any]:
overrides: dict[str, t.Any] = {}
for option, data in _get_sops_argument_spec(add_encrypt_specific=add_encrypt_specific).items():
value = get_option_value(option)
try:
value = _ensure_type(
value,
option_type=data.get("type", "str"),
elements_type=data.get("elements"),
sensitive=data.get("no_log", False),
)
except TypeError as exc:
raise ValueError(f"option {option} has invalid value: {exc}")
overrides[option] = value
return wrap_get_option_value(get_option_value, overrides=overrides)

View file

@ -16,6 +16,7 @@ from __future__ import annotations
import abc
import copy
import traceback
import typing as t
from ansible.errors import AnsibleError
from ansible.module_utils.basic import SEQUENCETYPE, remove_values
@ -25,8 +26,14 @@ from ansible.plugins.action import ActionBase
from ansible.module_utils.common.arg_spec import ArgumentSpecValidator
from ansible.module_utils.errors import UnsupportedError
if t.TYPE_CHECKING:
from collections.abc import Callable
safe_eval: Callable[[t.Any, t.Any, t.Any], t.Any] | None
try:
from ansible.module_utils.common.validation import (
from ansible.module_utils.common.validation import ( # type: ignore[no-redef]
safe_eval,
)
except ImportError:
@ -207,7 +214,7 @@ class ActionModuleBase(ActionBase, metaclass=abc.ABCMeta):
argument_spec, kwargs = self.setup_module()
module = argument_spec.create_ansible_module_helper(AnsibleActionModule, (self, ), **kwargs)
self.run_module(module)
raise AnsibleError('Internal error: action module did not call module.exit_json()')
raise AnsibleError('Internal error: action module did not call module.exit_json()') # pragma: no cover
except _ModuleExitException as mee:
result.update(mee.result)
return result

View file

@ -87,6 +87,7 @@ options:
- name: ANSIBLE_VARS_SOPS_PLUGIN_HANDLE_UNENCRYPTED_FILES
extends_documentation_fragment:
- ansible.builtin.vars_plugin_staging
- community.sops.sops.ansible_plugin # must come before community.sops.sops!
- community.sops.sops
- community.sops.sops.ansible_env
- community.sops.sops.ansible_ini
@ -101,6 +102,7 @@ seealso:
"""
import os
import typing as t
from collections.abc import Sequence, Mapping
from ansible.errors import AnsibleParserError
@ -111,6 +113,7 @@ from ansible.plugins.vars import BaseVarsPlugin
from ansible.utils.display import Display
from ansible.utils.vars import combine_vars
from ansible_collections.community.sops.plugins.module_utils.sops import Sops, SopsError
from ansible_collections.community.sops.plugins.plugin_utils._args import wrap_get_option_value_plugin_path
try:
from ansible.template import trust_as_template as _trust_as_template
@ -121,11 +124,11 @@ except ImportError:
display = Display()
FOUND = {}
DECRYPTED = {}
FOUND: dict[str, list[str]] = {}
DECRYPTED: dict[str, bytes] = {}
def _make_safe(value):
def _make_safe(value: t.Any) -> t.Any:
if isinstance(value, str):
# must come *before* Sequence, as strings are also instances of Sequence
if HAS_DATATAGGING and isinstance(value, str):
@ -148,8 +151,17 @@ class VarsModule(BaseVarsPlugin):
super().get_vars(loader, path, entities)
def get_option_value(argument_name):
return self.get_option(argument_name)
try:
sops_binary, sops_binary_origin = self.get_option_and_origin("sops_binary")
except AttributeError:
# Ansible-core 2.15 has no get_option_and_origin()!
sops_binary = self.get_option("sops_binary")
sops_binary_origin = "Direct"
get_option_value = wrap_get_option_value_plugin_path(
self.get_option,
sops_binary=sops_binary,
sops_binary_origin=sops_binary_origin,
)
if cache is None:
cache = self.get_option('cache')