ansible-core 2.18.4rc1__py3-none-any.whl → 2.19.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ansible/_internal/__init__.py +53 -0
- ansible/_internal/_ansiballz.py +265 -0
- ansible/_internal/_datatag/__init__.py +0 -0
- ansible/_internal/_datatag/_tags.py +130 -0
- ansible/_internal/_datatag/_utils.py +19 -0
- ansible/_internal/_datatag/_wrappers.py +33 -0
- ansible/_internal/_errors/__init__.py +0 -0
- ansible/_internal/_errors/_captured.py +128 -0
- ansible/_internal/_errors/_handler.py +91 -0
- ansible/_internal/_errors/_utils.py +310 -0
- ansible/_internal/_json/__init__.py +160 -0
- ansible/_internal/_json/_legacy_encoder.py +34 -0
- ansible/_internal/_json/_profiles/__init__.py +0 -0
- ansible/_internal/_json/_profiles/_cache_persistence.py +55 -0
- ansible/_internal/_json/_profiles/_inventory_legacy.py +40 -0
- ansible/_internal/_json/_profiles/_legacy.py +198 -0
- ansible/_internal/_locking.py +21 -0
- ansible/_internal/_plugins/__init__.py +0 -0
- ansible/_internal/_plugins/_cache.py +57 -0
- ansible/_internal/_task.py +78 -0
- ansible/_internal/_templating/__init__.py +10 -0
- ansible/_internal/_templating/_access.py +86 -0
- ansible/_internal/_templating/_chain_templar.py +63 -0
- ansible/_internal/_templating/_datatag.py +95 -0
- ansible/_internal/_templating/_engine.py +588 -0
- ansible/_internal/_templating/_errors.py +28 -0
- ansible/_internal/_templating/_jinja_bits.py +1066 -0
- ansible/_internal/_templating/_jinja_common.py +332 -0
- ansible/_internal/_templating/_jinja_patches.py +44 -0
- ansible/_internal/_templating/_jinja_plugins.py +351 -0
- ansible/_internal/_templating/_lazy_containers.py +633 -0
- ansible/_internal/_templating/_marker_behaviors.py +103 -0
- ansible/_internal/_templating/_transform.py +63 -0
- ansible/_internal/_templating/_utils.py +107 -0
- ansible/_internal/_wrapt.py +1052 -0
- ansible/_internal/_yaml/__init__.py +0 -0
- ansible/_internal/_yaml/_constructor.py +240 -0
- ansible/_internal/_yaml/_dumper.py +62 -0
- ansible/_internal/_yaml/_errors.py +166 -0
- ansible/_internal/_yaml/_loader.py +66 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/README.md +11 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/debug.py +36 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/apply_trust.py +19 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py +18 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/finalize.py +16 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/origin.py +18 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.py +24 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.yml +33 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/tag_names.py +16 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +17 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +49 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.py +21 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.yml +2 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.py +15 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.yml +19 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.py +18 -0
- ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.yml +19 -0
- ansible/cli/__init__.py +153 -89
- ansible/cli/_ssh_askpass.py +47 -0
- ansible/cli/adhoc.py +14 -7
- ansible/cli/arguments/option_helpers.py +154 -7
- ansible/cli/config.py +43 -68
- ansible/cli/console.py +10 -8
- ansible/cli/doc.py +48 -46
- ansible/cli/galaxy.py +27 -20
- ansible/cli/inventory.py +28 -26
- ansible/cli/playbook.py +4 -12
- ansible/cli/pull.py +51 -11
- ansible/cli/scripts/ansible_connection_cli_stub.py +7 -7
- ansible/cli/vault.py +12 -11
- ansible/compat/__init__.py +2 -2
- ansible/config/base.yml +165 -108
- ansible/config/manager.py +52 -49
- ansible/constants.py +3 -4
- ansible/errors/__init__.py +277 -235
- ansible/executor/interpreter_discovery.py +28 -149
- ansible/executor/module_common.py +426 -493
- ansible/executor/play_iterator.py +22 -27
- ansible/executor/playbook_executor.py +11 -11
- ansible/executor/powershell/async_watchdog.ps1 +97 -102
- ansible/executor/powershell/async_wrapper.ps1 +202 -151
- ansible/executor/powershell/become_wrapper.ps1 +89 -144
- ansible/executor/powershell/bootstrap_wrapper.ps1 +24 -9
- ansible/executor/powershell/coverage_wrapper.ps1 +82 -135
- ansible/executor/powershell/exec_wrapper.ps1 +462 -196
- ansible/executor/powershell/module_manifest.py +417 -265
- ansible/executor/powershell/module_wrapper.ps1 +169 -186
- ansible/executor/powershell/psrp_fetch_file.ps1 +41 -0
- ansible/executor/powershell/psrp_put_file.ps1 +122 -0
- ansible/executor/powershell/winrm_fetch_file.ps1 +46 -0
- ansible/executor/powershell/winrm_put_file.ps1 +36 -0
- ansible/executor/process/worker.py +136 -76
- ansible/executor/stats.py +5 -5
- ansible/executor/task_executor.py +237 -236
- ansible/executor/task_queue_manager.py +62 -38
- ansible/executor/task_result.py +21 -12
- ansible/galaxy/__init__.py +2 -2
- ansible/galaxy/api.py +22 -18
- ansible/galaxy/collection/__init__.py +1 -1
- ansible/galaxy/collection/concrete_artifact_manager.py +8 -11
- ansible/galaxy/dependency_resolution/dataclasses.py +14 -4
- ansible/galaxy/dependency_resolution/providers.py +1 -1
- ansible/galaxy/dependency_resolution/reporters.py +81 -0
- ansible/galaxy/role.py +4 -8
- ansible/galaxy/token.py +28 -21
- ansible/inventory/data.py +47 -57
- ansible/inventory/group.py +44 -72
- ansible/inventory/helpers.py +9 -0
- ansible/inventory/host.py +32 -54
- ansible/inventory/manager.py +77 -34
- ansible/keyword_desc.yml +1 -1
- ansible/module_utils/_internal/__init__.py +55 -0
- ansible/module_utils/_internal/_ambient_context.py +58 -0
- ansible/module_utils/_internal/_ansiballz.py +133 -0
- ansible/module_utils/_internal/_concurrent/_daemon_threading.py +1 -0
- ansible/module_utils/_internal/_dataclass_annotation_patch.py +64 -0
- ansible/module_utils/_internal/_dataclass_validation.py +217 -0
- ansible/module_utils/_internal/_datatag/__init__.py +928 -0
- ansible/module_utils/_internal/_datatag/_tags.py +38 -0
- ansible/module_utils/_internal/_debugging.py +31 -0
- ansible/module_utils/_internal/_errors.py +30 -0
- ansible/module_utils/_internal/_json/__init__.py +63 -0
- ansible/module_utils/_internal/_json/_legacy_encoder.py +26 -0
- ansible/module_utils/_internal/_json/_profiles/__init__.py +410 -0
- ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py +73 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +31 -0
- ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +35 -0
- ansible/module_utils/_internal/_json/_profiles/_module_modern_c2m.py +35 -0
- ansible/module_utils/_internal/_json/_profiles/_module_modern_m2c.py +33 -0
- ansible/module_utils/_internal/_json/_profiles/_tagless.py +50 -0
- ansible/module_utils/_internal/_patches/__init__.py +66 -0
- ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +55 -0
- ansible/module_utils/_internal/_patches/_socket_patch.py +34 -0
- ansible/module_utils/_internal/_patches/_sys_intern_patch.py +34 -0
- ansible/module_utils/_internal/_plugin_exec_context.py +49 -0
- ansible/module_utils/_internal/_testing.py +0 -0
- ansible/module_utils/_internal/_traceback.py +89 -0
- ansible/module_utils/ansible_release.py +2 -2
- ansible/module_utils/api.py +1 -2
- ansible/module_utils/basic.py +154 -120
- ansible/module_utils/common/_utils.py +24 -28
- ansible/module_utils/common/collections.py +1 -2
- ansible/module_utils/common/dict_transformations.py +2 -2
- ansible/module_utils/common/file.py +2 -2
- ansible/module_utils/common/json.py +90 -84
- ansible/module_utils/common/locale.py +2 -2
- ansible/module_utils/common/messages.py +108 -0
- ansible/module_utils/common/parameters.py +27 -24
- ansible/module_utils/common/process.py +2 -2
- ansible/module_utils/common/respawn.py +41 -19
- ansible/module_utils/common/sentinel.py +66 -0
- ansible/module_utils/common/sys_info.py +8 -8
- ansible/module_utils/common/text/converters.py +16 -37
- ansible/module_utils/common/validation.py +35 -24
- ansible/module_utils/common/warnings.py +86 -25
- ansible/module_utils/common/yaml.py +29 -3
- ansible/module_utils/compat/datetime.py +33 -21
- ansible/module_utils/compat/paramiko.py +21 -10
- ansible/module_utils/compat/typing.py +6 -5
- ansible/module_utils/connection.py +2 -2
- ansible/module_utils/csharp/Ansible.Basic.cs +14 -11
- ansible/module_utils/csharp/Ansible.Become.cs +1 -0
- ansible/module_utils/csharp/Ansible._Async.cs +517 -0
- ansible/module_utils/datatag.py +46 -0
- ansible/module_utils/distro/__init__.py +2 -2
- ansible/module_utils/facts/ansible_collector.py +4 -5
- ansible/module_utils/facts/collector.py +13 -14
- ansible/module_utils/facts/compat.py +4 -4
- ansible/module_utils/facts/default_collectors.py +1 -1
- ansible/module_utils/facts/hardware/aix.py +34 -0
- ansible/module_utils/facts/hardware/base.py +1 -1
- ansible/module_utils/facts/hardware/darwin.py +1 -3
- ansible/module_utils/facts/hardware/freebsd.py +2 -2
- ansible/module_utils/facts/hardware/linux.py +4 -4
- ansible/module_utils/facts/namespace.py +1 -1
- ansible/module_utils/facts/network/base.py +1 -1
- ansible/module_utils/facts/network/fc_wwn.py +1 -2
- ansible/module_utils/facts/network/iscsi.py +1 -2
- ansible/module_utils/facts/network/nvme.py +1 -2
- ansible/module_utils/facts/other/facter.py +1 -2
- ansible/module_utils/facts/other/ohai.py +2 -3
- ansible/module_utils/facts/system/apparmor.py +1 -2
- ansible/module_utils/facts/system/caps.py +1 -1
- ansible/module_utils/facts/system/chroot.py +1 -2
- ansible/module_utils/facts/system/cmdline.py +1 -2
- ansible/module_utils/facts/system/date_time.py +5 -3
- ansible/module_utils/facts/system/distribution.py +9 -8
- ansible/module_utils/facts/system/dns.py +1 -1
- ansible/module_utils/facts/system/env.py +1 -2
- ansible/module_utils/facts/system/fips.py +7 -20
- ansible/module_utils/facts/system/loadavg.py +1 -2
- ansible/module_utils/facts/system/local.py +1 -2
- ansible/module_utils/facts/system/lsb.py +1 -2
- ansible/module_utils/facts/system/pkg_mgr.py +1 -2
- ansible/module_utils/facts/system/platform.py +1 -2
- ansible/module_utils/facts/system/python.py +1 -2
- ansible/module_utils/facts/system/selinux.py +1 -1
- ansible/module_utils/facts/system/service_mgr.py +1 -2
- ansible/module_utils/facts/system/ssh_pub_keys.py +1 -1
- ansible/module_utils/facts/system/systemd.py +1 -1
- ansible/module_utils/facts/system/user.py +1 -2
- ansible/module_utils/facts/utils.py +3 -3
- ansible/module_utils/facts/virtual/base.py +1 -1
- ansible/module_utils/facts/virtual/sunos.py +3 -15
- ansible/module_utils/facts/virtual/sysctl.py +3 -16
- ansible/module_utils/json_utils.py +2 -2
- ansible/module_utils/parsing/convert_bool.py +1 -1
- ansible/module_utils/service.py +18 -21
- ansible/module_utils/splitter.py +7 -7
- ansible/module_utils/testing.py +31 -0
- ansible/module_utils/urls.py +60 -31
- ansible/modules/add_host.py +4 -4
- ansible/modules/apt.py +60 -46
- ansible/modules/apt_key.py +19 -12
- ansible/modules/apt_repository.py +19 -16
- ansible/modules/assemble.py +6 -6
- ansible/modules/assert.py +4 -4
- ansible/modules/async_status.py +10 -12
- ansible/modules/async_wrapper.py +8 -3
- ansible/modules/blockinfile.py +6 -7
- ansible/modules/command.py +10 -17
- ansible/modules/copy.py +57 -144
- ansible/modules/cron.py +20 -15
- ansible/modules/deb822_repository.py +8 -9
- ansible/modules/debconf.py +5 -5
- ansible/modules/debug.py +4 -4
- ansible/modules/dnf.py +8 -8
- ansible/modules/dnf5.py +52 -17
- ansible/modules/dpkg_selections.py +4 -4
- ansible/modules/expect.py +8 -10
- ansible/modules/fail.py +4 -4
- ansible/modules/fetch.py +4 -4
- ansible/modules/file.py +174 -133
- ansible/modules/find.py +20 -18
- ansible/modules/gather_facts.py +3 -3
- ansible/modules/get_url.py +59 -53
- ansible/modules/getent.py +7 -9
- ansible/modules/git.py +28 -25
- ansible/modules/group.py +6 -6
- ansible/modules/group_by.py +4 -4
- ansible/modules/hostname.py +13 -29
- ansible/modules/import_playbook.py +6 -6
- ansible/modules/import_role.py +7 -7
- ansible/modules/import_tasks.py +6 -6
- ansible/modules/include_role.py +6 -6
- ansible/modules/include_tasks.py +6 -6
- ansible/modules/include_vars.py +6 -6
- ansible/modules/iptables.py +86 -73
- ansible/modules/known_hosts.py +10 -10
- ansible/modules/lineinfile.py +5 -5
- ansible/modules/meta.py +4 -4
- ansible/modules/mount_facts.py +2 -2
- ansible/modules/package.py +4 -4
- ansible/modules/package_facts.py +22 -10
- ansible/modules/pause.py +6 -6
- ansible/modules/ping.py +6 -6
- ansible/modules/pip.py +10 -11
- ansible/modules/raw.py +4 -4
- ansible/modules/reboot.py +6 -6
- ansible/modules/replace.py +9 -13
- ansible/modules/rpm_key.py +7 -8
- ansible/modules/script.py +4 -4
- ansible/modules/service.py +7 -8
- ansible/modules/service_facts.py +87 -10
- ansible/modules/set_fact.py +5 -5
- ansible/modules/set_stats.py +4 -4
- ansible/modules/setup.py +2 -2
- ansible/modules/shell.py +6 -6
- ansible/modules/slurp.py +6 -6
- ansible/modules/stat.py +9 -23
- ansible/modules/subversion.py +15 -15
- ansible/modules/systemd.py +6 -6
- ansible/modules/systemd_service.py +6 -6
- ansible/modules/sysvinit.py +6 -6
- ansible/modules/tempfile.py +5 -6
- ansible/modules/template.py +6 -6
- ansible/modules/unarchive.py +32 -11
- ansible/modules/uri.py +35 -49
- ansible/modules/user.py +53 -34
- ansible/modules/validate_argument_spec.py +10 -7
- ansible/modules/wait_for.py +39 -32
- ansible/modules/wait_for_connection.py +6 -6
- ansible/modules/yum_repository.py +6 -6
- ansible/parsing/ajson.py +14 -32
- ansible/parsing/dataloader.py +99 -54
- ansible/parsing/mod_args.py +28 -44
- ansible/parsing/plugin_docs.py +21 -86
- ansible/parsing/quoting.py +1 -1
- ansible/parsing/splitter.py +27 -12
- ansible/parsing/utils/addresses.py +24 -24
- ansible/parsing/utils/yaml.py +32 -61
- ansible/parsing/vault/__init__.py +319 -87
- ansible/parsing/yaml/__init__.py +0 -18
- ansible/parsing/yaml/dumper.py +6 -120
- ansible/parsing/yaml/loader.py +6 -39
- ansible/parsing/yaml/objects.py +36 -339
- ansible/playbook/__init__.py +1 -1
- ansible/playbook/attribute.py +8 -3
- ansible/playbook/base.py +182 -132
- ansible/playbook/block.py +26 -24
- ansible/playbook/collectionsearch.py +1 -15
- ansible/playbook/conditional.py +3 -77
- ansible/playbook/handler.py +8 -2
- ansible/playbook/helpers.py +41 -53
- ansible/playbook/included_file.py +6 -15
- ansible/playbook/loop_control.py +2 -2
- ansible/playbook/play.py +85 -44
- ansible/playbook/play_context.py +12 -17
- ansible/playbook/playbook_include.py +14 -15
- ansible/playbook/role/__init__.py +24 -26
- ansible/playbook/role/definition.py +15 -17
- ansible/playbook/role/include.py +2 -4
- ansible/playbook/role/metadata.py +10 -11
- ansible/playbook/role_include.py +3 -3
- ansible/playbook/taggable.py +13 -8
- ansible/playbook/task.py +188 -118
- ansible/playbook/task_include.py +5 -5
- ansible/plugins/__init__.py +68 -21
- ansible/plugins/action/__init__.py +209 -176
- ansible/plugins/action/add_host.py +1 -1
- ansible/plugins/action/assemble.py +1 -1
- ansible/plugins/action/assert.py +54 -66
- ansible/plugins/action/copy.py +7 -11
- ansible/plugins/action/debug.py +37 -31
- ansible/plugins/action/dnf.py +3 -4
- ansible/plugins/action/fail.py +1 -1
- ansible/plugins/action/fetch.py +4 -5
- ansible/plugins/action/gather_facts.py +8 -7
- ansible/plugins/action/group_by.py +1 -1
- ansible/plugins/action/include_vars.py +10 -11
- ansible/plugins/action/package.py +3 -6
- ansible/plugins/action/pause.py +2 -2
- ansible/plugins/action/script.py +15 -8
- ansible/plugins/action/service.py +6 -11
- ansible/plugins/action/set_fact.py +3 -12
- ansible/plugins/action/set_stats.py +3 -8
- ansible/plugins/action/template.py +35 -59
- ansible/plugins/action/unarchive.py +1 -1
- ansible/plugins/action/validate_argument_spec.py +5 -5
- ansible/plugins/action/wait_for_connection.py +1 -1
- ansible/plugins/become/__init__.py +31 -8
- ansible/plugins/become/runas.py +71 -0
- ansible/plugins/become/su.py +13 -8
- ansible/plugins/become/sudo.py +19 -0
- ansible/plugins/cache/__init__.py +35 -44
- ansible/plugins/cache/base.py +8 -0
- ansible/plugins/cache/jsonfile.py +10 -16
- ansible/plugins/cache/memory.py +6 -12
- ansible/plugins/callback/__init__.py +141 -123
- ansible/plugins/callback/default.py +30 -23
- ansible/plugins/callback/junit.py +28 -24
- ansible/plugins/callback/minimal.py +17 -14
- ansible/plugins/callback/oneline.py +13 -7
- ansible/plugins/callback/tree.py +10 -6
- ansible/plugins/connection/__init__.py +47 -34
- ansible/plugins/connection/local.py +150 -54
- ansible/plugins/connection/paramiko_ssh.py +21 -18
- ansible/plugins/connection/psrp.py +76 -165
- ansible/plugins/connection/ssh.py +301 -78
- ansible/plugins/connection/winrm.py +58 -140
- ansible/plugins/doc_fragments/action_common_attributes.py +14 -14
- ansible/plugins/doc_fragments/action_core.py +6 -6
- ansible/plugins/doc_fragments/backup.py +2 -2
- ansible/plugins/doc_fragments/checksum_common.py +27 -0
- ansible/plugins/doc_fragments/constructed.py +6 -2
- ansible/plugins/doc_fragments/decrypt.py +2 -2
- ansible/plugins/doc_fragments/default_callback.py +2 -2
- ansible/plugins/doc_fragments/files.py +2 -2
- ansible/plugins/doc_fragments/inventory_cache.py +2 -2
- ansible/plugins/doc_fragments/result_format_callback.py +2 -2
- ansible/plugins/doc_fragments/return_common.py +2 -2
- ansible/plugins/doc_fragments/template_common.py +4 -4
- ansible/plugins/doc_fragments/url.py +17 -1
- ansible/plugins/doc_fragments/url_windows.py +2 -2
- ansible/plugins/doc_fragments/validate.py +2 -2
- ansible/plugins/doc_fragments/vars_plugin_staging.py +2 -2
- ansible/plugins/filter/__init__.py +6 -2
- ansible/plugins/filter/b64decode.yml +22 -0
- ansible/plugins/filter/b64encode.yml +22 -0
- ansible/plugins/filter/bool.yml +11 -4
- ansible/plugins/filter/core.py +218 -108
- ansible/plugins/filter/encryption.py +32 -32
- ansible/plugins/filter/flatten.yml +3 -2
- ansible/plugins/filter/human_to_bytes.yml +2 -2
- ansible/plugins/filter/mathstuff.py +30 -37
- ansible/plugins/filter/password_hash.yml +8 -0
- ansible/plugins/filter/regex_search.yml +1 -4
- ansible/plugins/filter/split.yml +1 -1
- ansible/plugins/filter/to_nice_yaml.yml +0 -4
- ansible/plugins/filter/to_yaml.yml +0 -4
- ansible/plugins/filter/unvault.yml +1 -1
- ansible/plugins/filter/urls.py +1 -1
- ansible/plugins/filter/urlsplit.py +8 -9
- ansible/plugins/filter/vault.yml +14 -9
- ansible/plugins/filter/win_basename.yml +6 -1
- ansible/plugins/filter/win_dirname.yml +5 -0
- ansible/plugins/inventory/__init__.py +97 -77
- ansible/plugins/inventory/advanced_host_list.py +7 -5
- ansible/plugins/inventory/auto.py +11 -4
- ansible/plugins/inventory/constructed.py +21 -24
- ansible/plugins/inventory/generator.py +16 -11
- ansible/plugins/inventory/host_list.py +7 -5
- ansible/plugins/inventory/ini.py +78 -44
- ansible/plugins/inventory/script.py +189 -119
- ansible/plugins/inventory/toml.py +16 -126
- ansible/plugins/inventory/yaml.py +10 -8
- ansible/plugins/list.py +3 -3
- ansible/plugins/loader.py +197 -82
- ansible/plugins/lookup/__init__.py +21 -4
- ansible/plugins/lookup/config.py +21 -35
- ansible/plugins/lookup/csvfile.py +3 -2
- ansible/plugins/lookup/dict.py +1 -6
- ansible/plugins/lookup/env.py +12 -9
- ansible/plugins/lookup/file.py +5 -8
- ansible/plugins/lookup/first_found.py +86 -55
- ansible/plugins/lookup/indexed_items.py +1 -10
- ansible/plugins/lookup/ini.py +14 -13
- ansible/plugins/lookup/items.py +1 -1
- ansible/plugins/lookup/lines.py +8 -1
- ansible/plugins/lookup/list.py +1 -1
- ansible/plugins/lookup/nested.py +2 -18
- ansible/plugins/lookup/password.py +5 -5
- ansible/plugins/lookup/pipe.py +5 -7
- ansible/plugins/lookup/sequence.py +18 -8
- ansible/plugins/lookup/subelements.py +1 -4
- ansible/plugins/lookup/template.py +42 -36
- ansible/plugins/lookup/together.py +0 -12
- ansible/plugins/lookup/unvault.py +1 -5
- ansible/plugins/lookup/url.py +2 -8
- ansible/plugins/lookup/vars.py +16 -24
- ansible/plugins/shell/__init__.py +2 -2
- ansible/plugins/shell/cmd.py +2 -2
- ansible/plugins/shell/powershell.py +39 -22
- ansible/plugins/shell/sh.py +3 -2
- ansible/plugins/strategy/__init__.py +94 -113
- ansible/plugins/strategy/debug.py +2 -2
- ansible/plugins/strategy/free.py +13 -28
- ansible/plugins/strategy/host_pinned.py +2 -2
- ansible/plugins/strategy/linear.py +31 -33
- ansible/plugins/terminal/__init__.py +4 -4
- ansible/plugins/test/__init__.py +7 -2
- ansible/plugins/test/core.py +54 -20
- ansible/plugins/test/files.py +1 -1
- ansible/plugins/test/mathstuff.py +3 -3
- ansible/plugins/test/uri.py +3 -3
- ansible/plugins/vars/host_group_vars.py +7 -14
- ansible/release.py +2 -2
- ansible/template/__init__.py +368 -944
- ansible/utils/__init__.py +0 -18
- ansible/utils/_ssh_agent.py +657 -0
- ansible/utils/collection_loader/__init__.py +52 -5
- ansible/utils/collection_loader/_collection_config.py +5 -6
- ansible/utils/collection_loader/_collection_finder.py +79 -93
- ansible/utils/collection_loader/_collection_meta.py +13 -8
- ansible/utils/display.py +428 -58
- ansible/utils/encrypt.py +27 -19
- ansible/utils/fqcn.py +2 -2
- ansible/utils/hashing.py +2 -2
- ansible/utils/helpers.py +2 -2
- ansible/utils/listify.py +8 -8
- ansible/utils/lock.py +2 -2
- ansible/utils/path.py +4 -4
- ansible/utils/plugin_docs.py +14 -13
- ansible/utils/sentinel.py +4 -62
- ansible/utils/singleton.py +2 -0
- ansible/utils/ssh_functions.py +1 -1
- ansible/utils/unsafe_proxy.py +23 -332
- ansible/utils/vars.py +28 -8
- ansible/utils/version.py +2 -2
- ansible/vars/clean.py +4 -4
- ansible/vars/hostvars.py +60 -90
- ansible/vars/manager.py +205 -264
- ansible/vars/reserved.py +8 -9
- ansible_core-2.19.0b1.dist-info/BSD-3-Clause.txt +28 -0
- {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/METADATA +5 -4
- ansible_core-2.19.0b1.dist-info/RECORD +1070 -0
- {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/WHEEL +1 -1
- ansible_test/_data/completion/docker.txt +7 -7
- ansible_test/_data/completion/remote.txt +6 -6
- ansible_test/_data/completion/windows.txt +1 -0
- ansible_test/_data/requirements/ansible.txt +2 -2
- ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
- ansible_test/_data/requirements/sanity.changelog.txt +1 -1
- ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
- ansible_test/_data/requirements/sanity.pylint.txt +4 -4
- ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
- ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
- ansible_test/_data/requirements/units.txt +1 -0
- ansible_test/_internal/__init__.py +1 -0
- ansible_test/_internal/ansible_util.py +2 -0
- ansible_test/_internal/become.py +1 -0
- ansible_test/_internal/bootstrap.py +1 -0
- ansible_test/_internal/cache.py +1 -0
- ansible_test/_internal/cgroup.py +1 -0
- ansible_test/_internal/ci/__init__.py +1 -0
- ansible_test/_internal/ci/azp.py +1 -0
- ansible_test/_internal/ci/local.py +1 -0
- ansible_test/_internal/classification/__init__.py +1 -0
- ansible_test/_internal/classification/common.py +1 -0
- ansible_test/_internal/classification/csharp.py +1 -0
- ansible_test/_internal/classification/powershell.py +1 -0
- ansible_test/_internal/classification/python.py +1 -0
- ansible_test/_internal/cli/__init__.py +1 -0
- ansible_test/_internal/cli/actions.py +1 -0
- ansible_test/_internal/cli/argparsing/__init__.py +1 -0
- ansible_test/_internal/cli/argparsing/actions.py +1 -0
- ansible_test/_internal/cli/argparsing/argcompletion.py +1 -0
- ansible_test/_internal/cli/argparsing/parsers.py +1 -0
- ansible_test/_internal/cli/commands/__init__.py +11 -0
- ansible_test/_internal/cli/commands/coverage/__init__.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/__init__.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/__init__.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/combine.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/expand.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/filter.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/generate.py +1 -0
- ansible_test/_internal/cli/commands/coverage/analyze/targets/missing.py +1 -0
- ansible_test/_internal/cli/commands/coverage/combine.py +1 -0
- ansible_test/_internal/cli/commands/coverage/erase.py +1 -0
- ansible_test/_internal/cli/commands/coverage/html.py +1 -0
- ansible_test/_internal/cli/commands/coverage/report.py +1 -0
- ansible_test/_internal/cli/commands/coverage/xml.py +1 -0
- ansible_test/_internal/cli/commands/env.py +1 -0
- ansible_test/_internal/cli/commands/integration/__init__.py +1 -0
- ansible_test/_internal/cli/commands/integration/network.py +1 -0
- ansible_test/_internal/cli/commands/integration/posix.py +1 -0
- ansible_test/_internal/cli/commands/integration/windows.py +1 -0
- ansible_test/_internal/cli/commands/sanity.py +9 -0
- ansible_test/_internal/cli/commands/shell.py +1 -0
- ansible_test/_internal/cli/commands/units.py +1 -0
- ansible_test/_internal/cli/compat.py +1 -0
- ansible_test/_internal/cli/completers.py +1 -0
- ansible_test/_internal/cli/converters.py +1 -0
- ansible_test/_internal/cli/environments.py +1 -0
- ansible_test/_internal/cli/epilog.py +1 -0
- ansible_test/_internal/cli/parsers/__init__.py +1 -0
- ansible_test/_internal/cli/parsers/base_argument_parsers.py +1 -0
- ansible_test/_internal/cli/parsers/helpers.py +1 -0
- ansible_test/_internal/cli/parsers/host_config_parsers.py +1 -0
- ansible_test/_internal/cli/parsers/key_value_parsers.py +1 -0
- ansible_test/_internal/cli/parsers/value_parsers.py +1 -0
- ansible_test/_internal/commands/__init__.py +1 -0
- ansible_test/_internal/commands/coverage/__init__.py +2 -1
- ansible_test/_internal/commands/coverage/analyze/__init__.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/__init__.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/combine.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/expand.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/filter.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/generate.py +1 -0
- ansible_test/_internal/commands/coverage/analyze/targets/missing.py +1 -0
- ansible_test/_internal/commands/coverage/combine.py +2 -1
- ansible_test/_internal/commands/coverage/erase.py +1 -0
- ansible_test/_internal/commands/coverage/html.py +1 -0
- ansible_test/_internal/commands/coverage/report.py +1 -0
- ansible_test/_internal/commands/coverage/xml.py +1 -0
- ansible_test/_internal/commands/env/__init__.py +2 -0
- ansible_test/_internal/commands/integration/__init__.py +4 -0
- ansible_test/_internal/commands/integration/cloud/__init__.py +1 -0
- ansible_test/_internal/commands/integration/cloud/acme.py +2 -1
- ansible_test/_internal/commands/integration/cloud/aws.py +1 -0
- ansible_test/_internal/commands/integration/cloud/azure.py +1 -0
- ansible_test/_internal/commands/integration/cloud/cs.py +1 -0
- ansible_test/_internal/commands/integration/cloud/digitalocean.py +1 -0
- ansible_test/_internal/commands/integration/cloud/galaxy.py +3 -2
- ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -0
- ansible_test/_internal/commands/integration/cloud/httptester.py +2 -1
- ansible_test/_internal/commands/integration/cloud/nios.py +2 -1
- ansible_test/_internal/commands/integration/cloud/opennebula.py +1 -0
- ansible_test/_internal/commands/integration/cloud/openshift.py +1 -0
- ansible_test/_internal/commands/integration/cloud/scaleway.py +1 -0
- ansible_test/_internal/commands/integration/cloud/vcenter.py +1 -0
- ansible_test/_internal/commands/integration/cloud/vultr.py +1 -0
- ansible_test/_internal/commands/integration/coverage.py +1 -0
- ansible_test/_internal/commands/integration/filters.py +1 -0
- ansible_test/_internal/commands/integration/network.py +1 -0
- ansible_test/_internal/commands/integration/posix.py +1 -0
- ansible_test/_internal/commands/integration/windows.py +1 -0
- ansible_test/_internal/commands/sanity/__init__.py +16 -1
- ansible_test/_internal/commands/sanity/ansible_doc.py +1 -0
- ansible_test/_internal/commands/sanity/bin_symlinks.py +1 -0
- ansible_test/_internal/commands/sanity/compile.py +1 -0
- ansible_test/_internal/commands/sanity/ignores.py +1 -0
- ansible_test/_internal/commands/sanity/import.py +1 -0
- ansible_test/_internal/commands/sanity/integration_aliases.py +1 -0
- ansible_test/_internal/commands/sanity/pep8.py +1 -0
- ansible_test/_internal/commands/sanity/pslint.py +1 -0
- ansible_test/_internal/commands/sanity/pylint.py +24 -26
- ansible_test/_internal/commands/sanity/shellcheck.py +1 -0
- ansible_test/_internal/commands/sanity/validate_modules.py +1 -0
- ansible_test/_internal/commands/sanity/yamllint.py +1 -0
- ansible_test/_internal/commands/shell/__init__.py +1 -0
- ansible_test/_internal/commands/units/__init__.py +1 -0
- ansible_test/_internal/compat/__init__.py +1 -0
- ansible_test/_internal/compat/packaging.py +1 -0
- ansible_test/_internal/compat/yaml.py +1 -0
- ansible_test/_internal/completion.py +1 -0
- ansible_test/_internal/config.py +2 -0
- ansible_test/_internal/connections.py +1 -0
- ansible_test/_internal/constants.py +1 -0
- ansible_test/_internal/containers.py +1 -0
- ansible_test/_internal/content_config.py +1 -0
- ansible_test/_internal/core_ci.py +1 -0
- ansible_test/_internal/coverage_util.py +11 -10
- ansible_test/_internal/data.py +1 -0
- ansible_test/_internal/delegation.py +1 -0
- ansible_test/_internal/dev/__init__.py +1 -0
- ansible_test/_internal/dev/container_probe.py +1 -0
- ansible_test/_internal/diff.py +3 -2
- ansible_test/_internal/docker_util.py +2 -1
- ansible_test/_internal/encoding.py +1 -0
- ansible_test/_internal/executor.py +1 -0
- ansible_test/_internal/git.py +1 -0
- ansible_test/_internal/host_configs.py +1 -0
- ansible_test/_internal/host_profiles.py +1 -0
- ansible_test/_internal/http.py +1 -0
- ansible_test/_internal/init.py +1 -0
- ansible_test/_internal/inventory.py +35 -3
- ansible_test/_internal/io.py +1 -0
- ansible_test/_internal/metadata.py +1 -0
- ansible_test/_internal/payload.py +1 -0
- ansible_test/_internal/provider/__init__.py +1 -0
- ansible_test/_internal/provider/layout/__init__.py +1 -0
- ansible_test/_internal/provider/layout/ansible.py +1 -0
- ansible_test/_internal/provider/layout/collection.py +1 -0
- ansible_test/_internal/provider/layout/unsupported.py +1 -0
- ansible_test/_internal/provider/source/__init__.py +1 -0
- ansible_test/_internal/provider/source/git.py +1 -0
- ansible_test/_internal/provider/source/installed.py +1 -0
- ansible_test/_internal/provider/source/unsupported.py +1 -0
- ansible_test/_internal/provider/source/unversioned.py +1 -0
- ansible_test/_internal/provisioning.py +1 -0
- ansible_test/_internal/pypi_proxy.py +6 -5
- ansible_test/_internal/python_requirements.py +1 -0
- ansible_test/_internal/ssh.py +1 -0
- ansible_test/_internal/target.py +1 -0
- ansible_test/_internal/test.py +3 -2
- ansible_test/_internal/thread.py +1 -0
- ansible_test/_internal/timeout.py +1 -0
- ansible_test/_internal/util.py +1 -0
- ansible_test/_internal/util_common.py +5 -2
- ansible_test/_internal/venv.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/changelog/sphinx.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/changelog.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/empty-init.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/line-endings.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-assert.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-get-exception.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-illegal-filenames.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/no-smart-quotes.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/replace-urlopen.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +28 -1
- ansible_test/_util/controller/sanity/code-smell/shebang.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/symlinks.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/use-argspec-type-path.py +1 -0
- ansible_test/_util/controller/sanity/code-smell/use-compat-six.py +1 -0
- ansible_test/_util/controller/sanity/integration-aliases/yaml_to_json.py +2 -1
- ansible_test/_util/controller/sanity/pep8/current-ignore.txt +4 -0
- ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +7 -5
- ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +7 -5
- ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +7 -5
- ansible_test/_util/controller/sanity/pylint/config/collection.cfg +3 -5
- ansible_test/_util/controller/sanity/pylint/config/default.cfg +7 -7
- ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -13
- ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +1 -0
- ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +1 -8
- ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +1 -8
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +55 -28
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +12 -5
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +13 -2
- ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -0
- ansible_test/_util/controller/sanity/yamllint/yamllinter.py +35 -17
- ansible_test/_util/controller/tools/collection_detail.py +1 -0
- ansible_test/_util/controller/tools/yaml_to_json.py +2 -1
- ansible_test/_util/target/pytest/plugins/ansible_forked.py +6 -1
- ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py +2 -1
- ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +1 -0
- ansible_test/_util/target/sanity/compile/compile.py +1 -0
- ansible_test/_util/target/sanity/import/importer.py +15 -16
- ansible_test/_util/target/setup/bootstrap.sh +9 -20
- ansible_test/_util/target/setup/probe_cgroups.py +1 -0
- ansible_test/_util/target/setup/quiet_pip.py +1 -0
- ansible_test/_util/target/setup/requirements.py +35 -27
- ansible_test/_util/target/tools/virtualenvcheck.py +2 -1
- ansible_test/_util/target/tools/yamlcheck.py +2 -1
- ansible/compat/selectors.py +0 -32
- ansible/errors/yaml_strings.py +0 -138
- ansible/executor/action_write_locks.py +0 -44
- ansible/executor/discovery/python_target.py +0 -47
- ansible/executor/powershell/module_powershell_wrapper.ps1 +0 -86
- ansible/executor/powershell/module_script_wrapper.ps1 +0 -22
- ansible/module_utils/compat/importlib.py +0 -26
- ansible/module_utils/compat/selectors.py +0 -32
- ansible/module_utils/pycompat24.py +0 -73
- ansible/parsing/utils/jsonify.py +0 -36
- ansible/parsing/yaml/constructor.py +0 -178
- ansible/template/native_helpers.py +0 -251
- ansible/template/template.py +0 -43
- ansible/template/vars.py +0 -77
- ansible/utils/native_jinja.py +0 -11
- ansible/vars/fact_cache.py +0 -71
- ansible_core-2.18.4rc1.dist-info/RECORD +0 -992
- {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/Apache-License.txt +0 -0
- {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/COPYING +0 -0
- {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/MIT-license.txt +0 -0
- {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/PSF-license.txt +0 -0
- {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/entry_points.txt +0 -0
- {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/simplified_bsd.txt +0 -0
- {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/top_level.txt +0 -0
@@ -19,6 +19,7 @@ from __future__ import annotations
|
|
19
19
|
|
20
20
|
import errno
|
21
21
|
import fcntl
|
22
|
+
import functools
|
22
23
|
import os
|
23
24
|
import random
|
24
25
|
import shlex
|
@@ -27,11 +28,18 @@ import subprocess
|
|
27
28
|
import sys
|
28
29
|
import tempfile
|
29
30
|
import warnings
|
31
|
+
import typing as t
|
30
32
|
|
31
33
|
from binascii import hexlify
|
32
34
|
from binascii import unhexlify
|
33
35
|
from binascii import Error as BinasciiError
|
34
36
|
|
37
|
+
from ansible.module_utils._internal._datatag import (
|
38
|
+
AnsibleTagHelper, AnsibleTaggedObject, _AnsibleTagsMapping, _EmptyROInternalTagsMapping, _EMPTY_INTERNAL_TAGS_MAPPING,
|
39
|
+
)
|
40
|
+
from ansible._internal._templating import _jinja_common
|
41
|
+
from ansible._internal._datatag._tags import Origin, VaultedValue, TrustedAsTemplate
|
42
|
+
|
35
43
|
HAS_CRYPTOGRAPHY = False
|
36
44
|
CRYPTOGRAPHY_BACKEND = None
|
37
45
|
try:
|
@@ -141,11 +149,13 @@ def _parse_vaulttext_envelope(b_vaulttext_envelope, default_vault_id=None):
|
|
141
149
|
vault_id = to_text(b_tmpheader[3].strip())
|
142
150
|
|
143
151
|
b_ciphertext = b''.join(b_tmpdata[1:])
|
152
|
+
# DTFIX-RELEASE: possible candidate for propagate_origin
|
153
|
+
b_ciphertext = AnsibleTagHelper.tag_copy(b_vaulttext_envelope, b_ciphertext)
|
144
154
|
|
145
155
|
return b_ciphertext, b_version, cipher_name, vault_id
|
146
156
|
|
147
157
|
|
148
|
-
def parse_vaulttext_envelope(b_vaulttext_envelope, default_vault_id=None
|
158
|
+
def parse_vaulttext_envelope(b_vaulttext_envelope, default_vault_id=None):
|
149
159
|
"""Parse the vaulttext envelope
|
150
160
|
|
151
161
|
When data is saved, it has a header prepended and is formatted into 80
|
@@ -153,11 +163,8 @@ def parse_vaulttext_envelope(b_vaulttext_envelope, default_vault_id=None, filena
|
|
153
163
|
and then removes the header and the inserted newlines. The string returned
|
154
164
|
is suitable for processing by the Cipher classes.
|
155
165
|
|
156
|
-
:arg
|
157
|
-
:
|
158
|
-
:kwarg filename: The filename that the data came from. This is only
|
159
|
-
used to make better error messages in case the data cannot be
|
160
|
-
decrypted. This is optional.
|
166
|
+
:arg b_vaulttext_envelope: byte str containing the data from a save file
|
167
|
+
:arg default_vault_id: The vault_id name to use if the vaulttext does not provide one.
|
161
168
|
:returns: A tuple of byte str of the vaulttext suitable to pass to parse_vaultext,
|
162
169
|
a byte str of the vault format version,
|
163
170
|
the name of the cipher used, and the vault_id.
|
@@ -168,12 +175,8 @@ def parse_vaulttext_envelope(b_vaulttext_envelope, default_vault_id=None, filena
|
|
168
175
|
|
169
176
|
try:
|
170
177
|
return _parse_vaulttext_envelope(b_vaulttext_envelope, default_vault_id)
|
171
|
-
except Exception as
|
172
|
-
|
173
|
-
if filename:
|
174
|
-
msg += ' in %s' % (filename)
|
175
|
-
msg += ': %s' % exc
|
176
|
-
raise AnsibleVaultFormatError(msg)
|
178
|
+
except Exception as ex:
|
179
|
+
raise AnsibleVaultFormatError("Vault envelope format error.", obj=b_vaulttext_envelope) from ex
|
177
180
|
|
178
181
|
|
179
182
|
def format_vaulttext_envelope(b_ciphertext, cipher_name, version=None, vault_id=None):
|
@@ -219,9 +222,10 @@ def format_vaulttext_envelope(b_ciphertext, cipher_name, version=None, vault_id=
|
|
219
222
|
|
220
223
|
def _unhexlify(b_data):
|
221
224
|
try:
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
+
# DTFIX-RELEASE: possible candidate for propagate_origin
|
226
|
+
return AnsibleTagHelper.tag_copy(b_data, unhexlify(b_data))
|
227
|
+
except (BinasciiError, TypeError) as ex:
|
228
|
+
raise AnsibleVaultFormatError('Vault format unhexlify error.', obj=b_data) from ex
|
225
229
|
|
226
230
|
|
227
231
|
def _parse_vaulttext(b_vaulttext):
|
@@ -247,25 +251,24 @@ def parse_vaulttext(b_vaulttext):
|
|
247
251
|
return _parse_vaulttext(b_vaulttext)
|
248
252
|
except AnsibleVaultFormatError:
|
249
253
|
raise
|
250
|
-
except Exception as
|
251
|
-
|
252
|
-
raise AnsibleVaultFormatError(msg)
|
254
|
+
except Exception as ex:
|
255
|
+
raise AnsibleVaultFormatError("Vault vaulttext format error.", obj=b_vaulttext) from ex
|
253
256
|
|
254
257
|
|
255
258
|
def verify_secret_is_not_empty(secret, msg=None):
|
256
|
-
|
259
|
+
"""Check the secret against minimal requirements.
|
257
260
|
|
258
261
|
Raises: AnsibleVaultPasswordError if the password does not meet requirements.
|
259
262
|
|
260
263
|
Currently, only requirement is that the password is not None or an empty string.
|
261
|
-
|
264
|
+
"""
|
262
265
|
msg = msg or 'Invalid vault password was provided'
|
263
266
|
if not secret:
|
264
267
|
raise AnsibleVaultPasswordError(msg)
|
265
268
|
|
266
269
|
|
267
270
|
class VaultSecret:
|
268
|
-
|
271
|
+
"""Opaque/abstract objects for a single vault secret. ie, a password or a key."""
|
269
272
|
|
270
273
|
def __init__(self, _bytes=None):
|
271
274
|
# FIXME: ? that seems wrong... Unset etc?
|
@@ -273,10 +276,10 @@ class VaultSecret:
|
|
273
276
|
|
274
277
|
@property
|
275
278
|
def bytes(self):
|
276
|
-
|
279
|
+
"""The secret as a bytestring.
|
277
280
|
|
278
281
|
Sub classes that store text types will need to override to encode the text to bytes.
|
279
|
-
|
282
|
+
"""
|
280
283
|
return self._bytes
|
281
284
|
|
282
285
|
def load(self):
|
@@ -335,7 +338,7 @@ class PromptVaultSecret(VaultSecret):
|
|
335
338
|
|
336
339
|
|
337
340
|
def script_is_client(filename):
|
338
|
-
|
341
|
+
"""Determine if a vault secret script is a client script that can be given --vault-id args"""
|
339
342
|
|
340
343
|
# if password script is 'something-client' or 'something-client.[sh|py|rb|etc]'
|
341
344
|
# script_name can still have '.' or could be entire filename if there is no ext
|
@@ -349,7 +352,7 @@ def script_is_client(filename):
|
|
349
352
|
|
350
353
|
|
351
354
|
def get_file_vault_secret(filename=None, vault_id=None, encoding=None, loader=None):
|
352
|
-
|
355
|
+
""" Get secret from file content or execute file and get secret from stdout """
|
353
356
|
|
354
357
|
# we unfrack but not follow the full path/context to possible vault script
|
355
358
|
# so when the script uses 'adjacent' file for configuration or similar
|
@@ -414,7 +417,7 @@ class FileVaultSecret(VaultSecret):
|
|
414
417
|
except (OSError, IOError) as e:
|
415
418
|
raise AnsibleError("Could not read vault password file %s: %s" % (filename, e))
|
416
419
|
|
417
|
-
b_vault_data, dummy = self.loader._decrypt_if_vault_data(vault_pass
|
420
|
+
b_vault_data, dummy = self.loader._decrypt_if_vault_data(vault_pass)
|
418
421
|
|
419
422
|
vault_pass = b_vault_data.strip(b'\r\n')
|
420
423
|
|
@@ -519,7 +522,7 @@ class ClientScriptVaultSecret(ScriptVaultSecret):
|
|
519
522
|
|
520
523
|
|
521
524
|
def match_secrets(secrets, target_vault_ids):
|
522
|
-
|
525
|
+
"""Find all VaultSecret objects that are mapped to any of the target_vault_ids in secrets"""
|
523
526
|
if not secrets:
|
524
527
|
return []
|
525
528
|
|
@@ -528,10 +531,10 @@ def match_secrets(secrets, target_vault_ids):
|
|
528
531
|
|
529
532
|
|
530
533
|
def match_best_secret(secrets, target_vault_ids):
|
531
|
-
|
534
|
+
"""Find the best secret from secrets that matches target_vault_ids
|
532
535
|
|
533
536
|
Since secrets should be ordered so the early secrets are 'better' than later ones, this
|
534
|
-
just finds all the matches, then returns the first secret
|
537
|
+
just finds all the matches, then returns the first secret"""
|
535
538
|
matches = match_secrets(secrets, target_vault_ids)
|
536
539
|
if matches:
|
537
540
|
return matches[0]
|
@@ -560,7 +563,7 @@ def match_encrypt_vault_id_secret(secrets, encrypt_vault_id=None):
|
|
560
563
|
|
561
564
|
|
562
565
|
def match_encrypt_secret(secrets, encrypt_vault_id=None):
|
563
|
-
|
566
|
+
"""Find the best/first/only secret in secrets to use for encrypting"""
|
564
567
|
|
565
568
|
display.vvvv(u'encrypt_vault_id=%s' % to_text(encrypt_vault_id))
|
566
569
|
# See if the --encrypt-vault-id matches a vault-id
|
@@ -633,58 +636,44 @@ class VaultLib:
|
|
633
636
|
vault_id=vault_id)
|
634
637
|
return b_vaulttext
|
635
638
|
|
636
|
-
def decrypt(self, vaulttext
|
637
|
-
|
639
|
+
def decrypt(self, vaulttext):
|
640
|
+
"""Decrypt a piece of vault encrypted data.
|
638
641
|
|
639
642
|
:arg vaulttext: a string to decrypt. Since vault encrypted data is an
|
640
643
|
ascii text format this can be either a byte str or unicode string.
|
641
|
-
:
|
642
|
-
|
643
|
-
|
644
|
-
:returns: a byte string containing the decrypted data and the vault-id that was used
|
645
|
-
|
646
|
-
'''
|
647
|
-
plaintext, vault_id, vault_secret = self.decrypt_and_get_vault_id(vaulttext, filename=filename, obj=obj)
|
644
|
+
:returns: a byte string containing the decrypted data
|
645
|
+
"""
|
646
|
+
plaintext, vault_id, vault_secret = self.decrypt_and_get_vault_id(vaulttext)
|
648
647
|
return plaintext
|
649
648
|
|
650
|
-
def decrypt_and_get_vault_id(self, vaulttext
|
649
|
+
def decrypt_and_get_vault_id(self, vaulttext):
|
651
650
|
"""Decrypt a piece of vault encrypted data.
|
652
651
|
|
653
652
|
:arg vaulttext: a string to decrypt. Since vault encrypted data is an
|
654
653
|
ascii text format this can be either a byte str or unicode string.
|
655
|
-
:kwarg filename: a filename that the data came from. This is only
|
656
|
-
used to make better error messages in case the data cannot be
|
657
|
-
decrypted.
|
658
654
|
:returns: a byte string containing the decrypted data and the vault-id vault-secret that was used
|
659
|
-
|
660
655
|
"""
|
661
|
-
|
656
|
+
origin = Origin.get_tag(vaulttext)
|
657
|
+
|
658
|
+
b_vaulttext = to_bytes(vaulttext, nonstring='error') # enforce vaulttext is str/bytes, keep type check if removing type conversion
|
662
659
|
|
663
660
|
if self.secrets is None:
|
664
|
-
|
665
|
-
if filename:
|
666
|
-
msg += " in file %s" % to_native(filename)
|
667
|
-
raise AnsibleVaultError(msg)
|
661
|
+
raise AnsibleVaultError("A vault password must be specified to decrypt data.", obj=vaulttext)
|
668
662
|
|
669
663
|
if not is_encrypted(b_vaulttext):
|
670
|
-
|
671
|
-
if filename:
|
672
|
-
msg += "%s is not a vault encrypted file" % to_native(filename)
|
673
|
-
raise AnsibleError(msg)
|
664
|
+
raise AnsibleVaultError("Input is not vault encrypted data.", obj=vaulttext)
|
674
665
|
|
675
|
-
b_vaulttext, dummy, cipher_name, vault_id = parse_vaulttext_envelope(b_vaulttext
|
666
|
+
b_vaulttext, dummy, cipher_name, vault_id = parse_vaulttext_envelope(b_vaulttext)
|
676
667
|
|
677
668
|
# create the cipher object, note that the cipher used for decrypt can
|
678
669
|
# be different than the cipher used for encrypt
|
679
670
|
if cipher_name in CIPHER_ALLOWLIST:
|
680
671
|
this_cipher = CIPHER_MAPPING[cipher_name]()
|
681
672
|
else:
|
682
|
-
raise
|
683
|
-
|
684
|
-
b_plaintext = None
|
673
|
+
raise AnsibleVaultError(f"Cipher {cipher_name!r} could not be found.", obj=vaulttext)
|
685
674
|
|
686
675
|
if not self.secrets:
|
687
|
-
raise AnsibleVaultError('Attempting to decrypt but no vault secrets found')
|
676
|
+
raise AnsibleVaultError('Attempting to decrypt but no vault secrets found.', obj=vaulttext)
|
688
677
|
|
689
678
|
# WARNING: Currently, the vault id is not required to match the vault id in the vault blob to
|
690
679
|
# decrypt a vault properly. The vault id in the vault blob is not part of the encrypted
|
@@ -697,15 +686,13 @@ class VaultLib:
|
|
697
686
|
# we check it first.
|
698
687
|
|
699
688
|
vault_id_matchers = []
|
700
|
-
vault_id_used = None
|
701
|
-
vault_secret_used = None
|
702
689
|
|
703
690
|
if vault_id:
|
704
691
|
display.vvvvv(u'Found a vault_id (%s) in the vaulttext' % to_text(vault_id))
|
705
692
|
vault_id_matchers.append(vault_id)
|
706
693
|
_matches = match_secrets(self.secrets, vault_id_matchers)
|
707
694
|
if _matches:
|
708
|
-
display.vvvvv(u'We have a secret associated with vault id (%s), will try to use to decrypt %s' % (to_text(vault_id), to_text(
|
695
|
+
display.vvvvv(u'We have a secret associated with vault id (%s), will try to use to decrypt %s' % (to_text(vault_id), to_text(origin)))
|
709
696
|
else:
|
710
697
|
display.vvvvv(u'Found a vault_id (%s) in the vault text, but we do not have a associated secret (--vault-id)' % to_text(vault_id))
|
711
698
|
|
@@ -719,45 +706,32 @@ class VaultLib:
|
|
719
706
|
|
720
707
|
# for vault_secret_id in vault_secret_ids:
|
721
708
|
for vault_secret_id, vault_secret in matched_secrets:
|
722
|
-
display.vvvvv(u'Trying to use vault secret=(%s) id=%s to decrypt %s' % (to_text(vault_secret), to_text(vault_secret_id), to_text(
|
709
|
+
display.vvvvv(u'Trying to use vault secret=(%s) id=%s to decrypt %s' % (to_text(vault_secret), to_text(vault_secret_id), to_text(origin)))
|
723
710
|
|
724
711
|
try:
|
725
712
|
# secret = self.secrets[vault_secret_id]
|
726
713
|
display.vvvv(u'Trying secret %s for vault_id=%s' % (to_text(vault_secret), to_text(vault_secret_id)))
|
727
714
|
b_plaintext = this_cipher.decrypt(b_vaulttext, vault_secret)
|
715
|
+
# DTFIX-RELEASE: possible candidate for propagate_origin
|
716
|
+
b_plaintext = AnsibleTagHelper.tag_copy(vaulttext, b_plaintext)
|
728
717
|
if b_plaintext is not None:
|
729
718
|
vault_id_used = vault_secret_id
|
730
719
|
vault_secret_used = vault_secret
|
731
720
|
file_slug = ''
|
732
|
-
if
|
733
|
-
file_slug = ' of "%s"' %
|
721
|
+
if origin:
|
722
|
+
file_slug = ' of "%s"' % origin
|
734
723
|
display.vvvvv(
|
735
724
|
u'Decrypt%s successful with secret=%s and vault_id=%s' % (to_text(file_slug), to_text(vault_secret), to_text(vault_secret_id))
|
736
725
|
)
|
737
726
|
break
|
738
|
-
except AnsibleVaultFormatError
|
739
|
-
exc.obj = obj
|
740
|
-
msg = u"There was a vault format error"
|
741
|
-
if filename:
|
742
|
-
msg += u' in %s' % (to_text(filename))
|
743
|
-
msg += u': %s' % to_text(exc)
|
744
|
-
display.warning(msg, formatted=True)
|
727
|
+
except AnsibleVaultFormatError:
|
745
728
|
raise
|
746
729
|
except AnsibleError as e:
|
747
730
|
display.vvvv(u'Tried to use the vault secret (%s) to decrypt (%s) but it failed. Error: %s' %
|
748
|
-
(to_text(vault_secret_id), to_text(
|
731
|
+
(to_text(vault_secret_id), to_text(origin), e))
|
749
732
|
continue
|
750
733
|
else:
|
751
|
-
|
752
|
-
if filename:
|
753
|
-
msg += " on %s" % to_native(filename)
|
754
|
-
raise AnsibleVaultError(msg)
|
755
|
-
|
756
|
-
if b_plaintext is None:
|
757
|
-
msg = "Decryption failed"
|
758
|
-
if filename:
|
759
|
-
msg += " on %s" % to_native(filename)
|
760
|
-
raise AnsibleError(msg)
|
734
|
+
raise AnsibleVaultError("Decryption failed (no vault secrets were found that could decrypt).", obj=vaulttext)
|
761
735
|
|
762
736
|
return b_plaintext, vault_id_used, vault_secret_used
|
763
737
|
|
@@ -916,7 +890,7 @@ class VaultEditor:
|
|
916
890
|
ciphertext = self.read_data(filename)
|
917
891
|
|
918
892
|
try:
|
919
|
-
plaintext = self.vault.decrypt(ciphertext
|
893
|
+
plaintext = self.vault.decrypt(ciphertext)
|
920
894
|
except AnsibleError as e:
|
921
895
|
raise AnsibleError("%s for %s" % (to_native(e), to_native(filename)))
|
922
896
|
self.write_data(plaintext, output_file or filename, shred=False)
|
@@ -956,7 +930,7 @@ class VaultEditor:
|
|
956
930
|
|
957
931
|
# Figure out the vault id from the file, to select the right secret to re-encrypt it
|
958
932
|
# (duplicates parts of decrypt, but alas...)
|
959
|
-
dummy, dummy, cipher_name, vault_id = parse_vaulttext_envelope(b_vaulttext
|
933
|
+
dummy, dummy, cipher_name, vault_id = parse_vaulttext_envelope(b_vaulttext)
|
960
934
|
|
961
935
|
# vault id here may not be the vault id actually used for decrypting
|
962
936
|
# as when the edited file has no vault-id but is decrypted by non-default id in secrets
|
@@ -974,7 +948,7 @@ class VaultEditor:
|
|
974
948
|
vaulttext = to_text(b_vaulttext)
|
975
949
|
|
976
950
|
try:
|
977
|
-
plaintext = self.vault.decrypt(vaulttext
|
951
|
+
plaintext = self.vault.decrypt(vaulttext)
|
978
952
|
return plaintext
|
979
953
|
except AnsibleError as e:
|
980
954
|
raise AnsibleVaultError("%s for %s" % (to_native(e), to_native(filename)))
|
@@ -1024,10 +998,12 @@ class VaultEditor:
|
|
1024
998
|
|
1025
999
|
try:
|
1026
1000
|
if filename == '-':
|
1027
|
-
data = sys.stdin.buffer.read()
|
1001
|
+
data = Origin(description='<stdin>').tag(sys.stdin.buffer.read())
|
1028
1002
|
else:
|
1003
|
+
filename = os.path.abspath(filename)
|
1004
|
+
|
1029
1005
|
with open(filename, "rb") as fh:
|
1030
|
-
data = fh.read()
|
1006
|
+
data = Origin(path=filename).tag(fh.read())
|
1031
1007
|
except Exception as e:
|
1032
1008
|
msg = to_native(e)
|
1033
1009
|
if not msg:
|
@@ -1170,6 +1146,7 @@ class VaultAES256:
|
|
1170
1146
|
return b_derivedkey
|
1171
1147
|
|
1172
1148
|
@classmethod
|
1149
|
+
@functools.cache # Concurrent first-use by multiple threads will all execute the method body.
|
1173
1150
|
def _gen_key_initctr(cls, b_password, b_salt):
|
1174
1151
|
# 16 for AES 128, 32 for AES256
|
1175
1152
|
key_length = 32
|
@@ -1302,3 +1279,258 @@ class VaultAES256:
|
|
1302
1279
|
CIPHER_MAPPING = {
|
1303
1280
|
u'AES256': VaultAES256,
|
1304
1281
|
}
|
1282
|
+
|
1283
|
+
|
1284
|
+
class VaultSecretsContext:
|
1285
|
+
"""Provides context-style access to vault secrets."""
|
1286
|
+
_current: t.ClassVar[t.Self | None] = None
|
1287
|
+
|
1288
|
+
def __init__(self, secrets: list[tuple[str, VaultSecret]]) -> None:
|
1289
|
+
self.secrets = secrets
|
1290
|
+
|
1291
|
+
@classmethod
|
1292
|
+
def initialize(cls, value: t.Self) -> None:
|
1293
|
+
"""
|
1294
|
+
Initialize VaultSecretsContext with the specified instance and secrets (since it's not a lazy or per-thread context).
|
1295
|
+
This method will fail if called more than once.
|
1296
|
+
"""
|
1297
|
+
if cls._current:
|
1298
|
+
raise RuntimeError(f"The {cls.__name__} context is already initialized.")
|
1299
|
+
|
1300
|
+
cls._current = value
|
1301
|
+
|
1302
|
+
@classmethod
|
1303
|
+
def current(cls, optional: bool = False) -> t.Self:
|
1304
|
+
"""Access vault secrets, if initialized, ala `AmbientContextBase.current()`."""
|
1305
|
+
if not cls._current and not optional:
|
1306
|
+
raise ReferenceError(f"A required {cls.__name__} context is not active.")
|
1307
|
+
|
1308
|
+
return cls._current
|
1309
|
+
|
1310
|
+
|
1311
|
+
@t.final
|
1312
|
+
class EncryptedString(AnsibleTaggedObject):
|
1313
|
+
"""
|
1314
|
+
An encrypted string which supports tagging and on-demand decryption.
|
1315
|
+
All methods provided by Python's built-in `str` are supported, all of which operate on the decrypted value.
|
1316
|
+
Any attempt to use this value when it cannot be decrypted will raise an exception.
|
1317
|
+
Despite supporting `str` methods, access to an instance of this type through templating is recommended over direct access.
|
1318
|
+
"""
|
1319
|
+
|
1320
|
+
__slots__ = ('_ciphertext', '_plaintext', '_ansible_tags_mapping')
|
1321
|
+
|
1322
|
+
_subclasses_native_type: t.ClassVar[bool] = False
|
1323
|
+
_empty_tags_as_native: t.ClassVar[bool] = False
|
1324
|
+
|
1325
|
+
_ciphertext: str
|
1326
|
+
_plaintext: str | None
|
1327
|
+
_ansible_tags_mapping: _AnsibleTagsMapping | _EmptyROInternalTagsMapping
|
1328
|
+
|
1329
|
+
def __init__(self, *, ciphertext: str) -> None:
|
1330
|
+
if type(ciphertext) is not str: # pylint: disable=unidiomatic-typecheck
|
1331
|
+
raise TypeError(f'ciphertext must be {str} instead of {type(ciphertext)}')
|
1332
|
+
|
1333
|
+
object.__setattr__(self, '_ciphertext', ciphertext)
|
1334
|
+
object.__setattr__(self, '_plaintext', None)
|
1335
|
+
object.__setattr__(self, '_ansible_tags_mapping', _EMPTY_INTERNAL_TAGS_MAPPING)
|
1336
|
+
|
1337
|
+
@classmethod
|
1338
|
+
def _instance_factory(cls, value: t.Any, tags_mapping: _AnsibleTagsMapping) -> EncryptedString:
|
1339
|
+
instance = EncryptedString.__new__(EncryptedString)
|
1340
|
+
|
1341
|
+
# In 2.18 and earlier, vaulted values were not trusted.
|
1342
|
+
# This maintains backwards compatibility with that.
|
1343
|
+
# Additionally, supporting templating on vaulted values could be problematic for a few cases:
|
1344
|
+
# 1) There's no way to compose YAML tags, so you can't use `!unsafe` and `!vault` together.
|
1345
|
+
# 2) It would make composing `EncryptedString` with a possible future `TemplateString` more difficult.
|
1346
|
+
tags_mapping.pop(TrustedAsTemplate, None)
|
1347
|
+
|
1348
|
+
object.__setattr__(instance, '_ciphertext', value._ciphertext)
|
1349
|
+
object.__setattr__(instance, '_plaintext', value._plaintext)
|
1350
|
+
object.__setattr__(instance, '_ansible_tags_mapping', tags_mapping)
|
1351
|
+
|
1352
|
+
return instance
|
1353
|
+
|
1354
|
+
def __setstate__(self, state: tuple[None, dict[str, t.Any]]) -> None:
|
1355
|
+
for key, value in state[1].items():
|
1356
|
+
object.__setattr__(self, key, value)
|
1357
|
+
|
1358
|
+
def __delattr__(self, item: str) -> t.NoReturn:
|
1359
|
+
raise AttributeError(f'{self.__class__.__name__!r} object is read-only')
|
1360
|
+
|
1361
|
+
def __setattr__(self, key: str, value: object) -> t.NoReturn:
|
1362
|
+
raise AttributeError(f'{self.__class__.__name__!r} object is read-only')
|
1363
|
+
|
1364
|
+
@classmethod
|
1365
|
+
def _init_class(cls) -> None:
|
1366
|
+
"""
|
1367
|
+
Add proxies for the specified `str` methods.
|
1368
|
+
These proxies operate on the plaintext, which is decrypted on-demand.
|
1369
|
+
"""
|
1370
|
+
cls._native_type = cls
|
1371
|
+
|
1372
|
+
operator_method_names = (
|
1373
|
+
'__eq__',
|
1374
|
+
'__ge__',
|
1375
|
+
'__gt__',
|
1376
|
+
'__le__',
|
1377
|
+
'__lt__',
|
1378
|
+
'__ne__',
|
1379
|
+
)
|
1380
|
+
|
1381
|
+
method_names = (
|
1382
|
+
'__add__',
|
1383
|
+
'__contains__',
|
1384
|
+
'__format__',
|
1385
|
+
'__getitem__',
|
1386
|
+
'__hash__',
|
1387
|
+
'__iter__',
|
1388
|
+
'__len__',
|
1389
|
+
'__mod__',
|
1390
|
+
'__mul__',
|
1391
|
+
'__rmod__',
|
1392
|
+
'__rmul__',
|
1393
|
+
'capitalize',
|
1394
|
+
'casefold',
|
1395
|
+
'center',
|
1396
|
+
'count',
|
1397
|
+
'encode',
|
1398
|
+
'endswith',
|
1399
|
+
'expandtabs',
|
1400
|
+
'find',
|
1401
|
+
'format',
|
1402
|
+
'format_map',
|
1403
|
+
'index',
|
1404
|
+
'isalnum',
|
1405
|
+
'isalpha',
|
1406
|
+
'isascii',
|
1407
|
+
'isdecimal',
|
1408
|
+
'isdigit',
|
1409
|
+
'isidentifier',
|
1410
|
+
'islower',
|
1411
|
+
'isnumeric',
|
1412
|
+
'isprintable',
|
1413
|
+
'isspace',
|
1414
|
+
'istitle',
|
1415
|
+
'isupper',
|
1416
|
+
'join',
|
1417
|
+
'ljust',
|
1418
|
+
'lower',
|
1419
|
+
'lstrip',
|
1420
|
+
'maketrans', # static, but implemented for simplicty/consistency
|
1421
|
+
'partition',
|
1422
|
+
'removeprefix',
|
1423
|
+
'removesuffix',
|
1424
|
+
'replace',
|
1425
|
+
'rfind',
|
1426
|
+
'rindex',
|
1427
|
+
'rjust',
|
1428
|
+
'rpartition',
|
1429
|
+
'rsplit',
|
1430
|
+
'rstrip',
|
1431
|
+
'split',
|
1432
|
+
'splitlines',
|
1433
|
+
'startswith',
|
1434
|
+
'strip',
|
1435
|
+
'swapcase',
|
1436
|
+
'title',
|
1437
|
+
'translate',
|
1438
|
+
'upper',
|
1439
|
+
'zfill',
|
1440
|
+
)
|
1441
|
+
|
1442
|
+
for method_name in operator_method_names:
|
1443
|
+
setattr(cls, method_name, functools.partialmethod(cls._proxy_str_operator_method, getattr(str, method_name)))
|
1444
|
+
|
1445
|
+
for method_name in method_names:
|
1446
|
+
setattr(cls, method_name, functools.partialmethod(cls._proxy_str_method, getattr(str, method_name)))
|
1447
|
+
|
1448
|
+
def _decrypt(self) -> str:
|
1449
|
+
"""
|
1450
|
+
Attempt to decrypt the ciphertext and return the plaintext, which will be cached.
|
1451
|
+
If decryption fails an exception will be raised and no result will be cached.
|
1452
|
+
"""
|
1453
|
+
if self._plaintext is None:
|
1454
|
+
vault = VaultLib(secrets=VaultSecretsContext.current().secrets)
|
1455
|
+
# use the utility method to ensure that origin tags are available
|
1456
|
+
plaintext = to_text(vault.decrypt(VaultHelper.get_ciphertext(self, with_tags=True))) # raises if the ciphertext cannot be decrypted
|
1457
|
+
|
1458
|
+
# propagate source value tags plus VaultedValue for round-tripping ciphertext
|
1459
|
+
plaintext = AnsibleTagHelper.tag(plaintext, AnsibleTagHelper.tags(self) | {VaultedValue(ciphertext=self._ciphertext)})
|
1460
|
+
|
1461
|
+
object.__setattr__(self, '_plaintext', plaintext)
|
1462
|
+
|
1463
|
+
return self._plaintext
|
1464
|
+
|
1465
|
+
def _as_dict(self) -> t.Dict[str, t.Any]:
|
1466
|
+
return dict(
|
1467
|
+
value=self._ciphertext,
|
1468
|
+
tags=list(self._ansible_tags_mapping.values()),
|
1469
|
+
)
|
1470
|
+
|
1471
|
+
def _native_copy(self) -> str:
|
1472
|
+
return AnsibleTagHelper.untag(self._decrypt())
|
1473
|
+
|
1474
|
+
def _proxy_str_operator_method(self, method: t.Callable, other) -> t.Any:
|
1475
|
+
obj = self._decrypt()
|
1476
|
+
|
1477
|
+
if type(other) is EncryptedString: # pylint: disable=unidiomatic-typecheck
|
1478
|
+
other = other._decrypt()
|
1479
|
+
|
1480
|
+
return method(obj, other)
|
1481
|
+
|
1482
|
+
def _proxy_str_method(self, method: t.Callable, *args, **kwargs) -> t.Any:
|
1483
|
+
obj = self._decrypt()
|
1484
|
+
return method(obj, *args, **kwargs)
|
1485
|
+
|
1486
|
+
def __repr__(self) -> str:
|
1487
|
+
return f'{self.__class__.__name__}(ciphertext={self._ciphertext!r})'
|
1488
|
+
|
1489
|
+
def __str__(self) -> str:
|
1490
|
+
return self._decrypt()
|
1491
|
+
|
1492
|
+
def __float__(self) -> float:
|
1493
|
+
return float(self._decrypt())
|
1494
|
+
|
1495
|
+
def __int__(self) -> int:
|
1496
|
+
return int(self._decrypt())
|
1497
|
+
|
1498
|
+
def __radd__(self, other: t.Any) -> str:
|
1499
|
+
return other + self._decrypt()
|
1500
|
+
|
1501
|
+
def __fspath__(self) -> str:
|
1502
|
+
return self._decrypt()
|
1503
|
+
|
1504
|
+
|
1505
|
+
class VaultHelper:
|
1506
|
+
"""Vault specific utility methods."""
|
1507
|
+
|
1508
|
+
@staticmethod
|
1509
|
+
def get_ciphertext(value: t.Any, *, with_tags: bool) -> str | None:
|
1510
|
+
"""
|
1511
|
+
If the given value is an `EncryptedString`, `VaultExceptionMarker` or tagged with `VaultedValue`, return the ciphertext, otherwise return `None`.
|
1512
|
+
Tags on the value other than `VaultedValue` will be included on the ciphertext if `with_tags` is `True`, otherwise it will be tagless.
|
1513
|
+
"""
|
1514
|
+
value_type = type(value)
|
1515
|
+
ciphertext: str | None
|
1516
|
+
tags = AnsibleTagHelper.tags(value)
|
1517
|
+
|
1518
|
+
if value_type is _jinja_common.VaultExceptionMarker:
|
1519
|
+
ciphertext = value._marker_undecryptable_ciphertext
|
1520
|
+
tags = AnsibleTagHelper.tags(ciphertext) # ciphertext has tags but value does not
|
1521
|
+
elif value_type is EncryptedString:
|
1522
|
+
ciphertext = value._ciphertext
|
1523
|
+
elif value_type in _jinja_common.Marker.concrete_subclasses: # avoid wasteful raise/except of Marker when calling get_tag below
|
1524
|
+
ciphertext = None
|
1525
|
+
elif vaulted_value := VaultedValue.get_tag(value):
|
1526
|
+
ciphertext = vaulted_value.ciphertext
|
1527
|
+
else:
|
1528
|
+
ciphertext = None
|
1529
|
+
|
1530
|
+
if ciphertext:
|
1531
|
+
if with_tags:
|
1532
|
+
ciphertext = VaultedValue.untag(AnsibleTagHelper.tag(ciphertext, tags))
|
1533
|
+
else:
|
1534
|
+
ciphertext = AnsibleTagHelper.untag(ciphertext)
|
1535
|
+
|
1536
|
+
return ciphertext
|
ansible/parsing/yaml/__init__.py
CHANGED
@@ -1,18 +0,0 @@
|
|
1
|
-
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
|
2
|
-
#
|
3
|
-
# This file is part of Ansible
|
4
|
-
#
|
5
|
-
# Ansible is free software: you can redistribute it and/or modify
|
6
|
-
# it under the terms of the GNU General Public License as published by
|
7
|
-
# the Free Software Foundation, either version 3 of the License, or
|
8
|
-
# (at your option) any later version.
|
9
|
-
#
|
10
|
-
# Ansible is distributed in the hope that it will be useful,
|
11
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
-
# GNU General Public License for more details.
|
14
|
-
#
|
15
|
-
# You should have received a copy of the GNU General Public License
|
16
|
-
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
17
|
-
|
18
|
-
from __future__ import annotations
|