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.
Files changed (709) hide show
  1. ansible/_internal/__init__.py +53 -0
  2. ansible/_internal/_ansiballz.py +265 -0
  3. ansible/_internal/_datatag/__init__.py +0 -0
  4. ansible/_internal/_datatag/_tags.py +130 -0
  5. ansible/_internal/_datatag/_utils.py +19 -0
  6. ansible/_internal/_datatag/_wrappers.py +33 -0
  7. ansible/_internal/_errors/__init__.py +0 -0
  8. ansible/_internal/_errors/_captured.py +128 -0
  9. ansible/_internal/_errors/_handler.py +91 -0
  10. ansible/_internal/_errors/_utils.py +310 -0
  11. ansible/_internal/_json/__init__.py +160 -0
  12. ansible/_internal/_json/_legacy_encoder.py +34 -0
  13. ansible/_internal/_json/_profiles/__init__.py +0 -0
  14. ansible/_internal/_json/_profiles/_cache_persistence.py +55 -0
  15. ansible/_internal/_json/_profiles/_inventory_legacy.py +40 -0
  16. ansible/_internal/_json/_profiles/_legacy.py +198 -0
  17. ansible/_internal/_locking.py +21 -0
  18. ansible/_internal/_plugins/__init__.py +0 -0
  19. ansible/_internal/_plugins/_cache.py +57 -0
  20. ansible/_internal/_task.py +78 -0
  21. ansible/_internal/_templating/__init__.py +10 -0
  22. ansible/_internal/_templating/_access.py +86 -0
  23. ansible/_internal/_templating/_chain_templar.py +63 -0
  24. ansible/_internal/_templating/_datatag.py +95 -0
  25. ansible/_internal/_templating/_engine.py +588 -0
  26. ansible/_internal/_templating/_errors.py +28 -0
  27. ansible/_internal/_templating/_jinja_bits.py +1066 -0
  28. ansible/_internal/_templating/_jinja_common.py +332 -0
  29. ansible/_internal/_templating/_jinja_patches.py +44 -0
  30. ansible/_internal/_templating/_jinja_plugins.py +351 -0
  31. ansible/_internal/_templating/_lazy_containers.py +633 -0
  32. ansible/_internal/_templating/_marker_behaviors.py +103 -0
  33. ansible/_internal/_templating/_transform.py +63 -0
  34. ansible/_internal/_templating/_utils.py +107 -0
  35. ansible/_internal/_wrapt.py +1052 -0
  36. ansible/_internal/_yaml/__init__.py +0 -0
  37. ansible/_internal/_yaml/_constructor.py +240 -0
  38. ansible/_internal/_yaml/_dumper.py +62 -0
  39. ansible/_internal/_yaml/_errors.py +166 -0
  40. ansible/_internal/_yaml/_loader.py +66 -0
  41. ansible/_internal/ansible_collections/ansible/_protomatter/README.md +11 -0
  42. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/action/debug.py +36 -0
  43. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/apply_trust.py +19 -0
  44. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/dump_object.py +18 -0
  45. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/finalize.py +16 -0
  46. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/origin.py +18 -0
  47. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.py +24 -0
  48. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/python_literal_eval.yml +33 -0
  49. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/tag_names.py +16 -0
  50. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/true_type.py +17 -0
  51. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/filter/unmask.py +49 -0
  52. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.py +21 -0
  53. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/lookup/config.yml +2 -0
  54. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.py +15 -0
  55. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged.yml +19 -0
  56. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.py +18 -0
  57. ansible/_internal/ansible_collections/ansible/_protomatter/plugins/test/tagged_with.yml +19 -0
  58. ansible/cli/__init__.py +153 -89
  59. ansible/cli/_ssh_askpass.py +47 -0
  60. ansible/cli/adhoc.py +14 -7
  61. ansible/cli/arguments/option_helpers.py +154 -7
  62. ansible/cli/config.py +43 -68
  63. ansible/cli/console.py +10 -8
  64. ansible/cli/doc.py +48 -46
  65. ansible/cli/galaxy.py +27 -20
  66. ansible/cli/inventory.py +28 -26
  67. ansible/cli/playbook.py +4 -12
  68. ansible/cli/pull.py +51 -11
  69. ansible/cli/scripts/ansible_connection_cli_stub.py +7 -7
  70. ansible/cli/vault.py +12 -11
  71. ansible/compat/__init__.py +2 -2
  72. ansible/config/base.yml +165 -108
  73. ansible/config/manager.py +52 -49
  74. ansible/constants.py +3 -4
  75. ansible/errors/__init__.py +277 -235
  76. ansible/executor/interpreter_discovery.py +28 -149
  77. ansible/executor/module_common.py +426 -493
  78. ansible/executor/play_iterator.py +22 -27
  79. ansible/executor/playbook_executor.py +11 -11
  80. ansible/executor/powershell/async_watchdog.ps1 +97 -102
  81. ansible/executor/powershell/async_wrapper.ps1 +202 -151
  82. ansible/executor/powershell/become_wrapper.ps1 +89 -144
  83. ansible/executor/powershell/bootstrap_wrapper.ps1 +24 -9
  84. ansible/executor/powershell/coverage_wrapper.ps1 +82 -135
  85. ansible/executor/powershell/exec_wrapper.ps1 +462 -196
  86. ansible/executor/powershell/module_manifest.py +417 -265
  87. ansible/executor/powershell/module_wrapper.ps1 +169 -186
  88. ansible/executor/powershell/psrp_fetch_file.ps1 +41 -0
  89. ansible/executor/powershell/psrp_put_file.ps1 +122 -0
  90. ansible/executor/powershell/winrm_fetch_file.ps1 +46 -0
  91. ansible/executor/powershell/winrm_put_file.ps1 +36 -0
  92. ansible/executor/process/worker.py +136 -76
  93. ansible/executor/stats.py +5 -5
  94. ansible/executor/task_executor.py +237 -236
  95. ansible/executor/task_queue_manager.py +62 -38
  96. ansible/executor/task_result.py +21 -12
  97. ansible/galaxy/__init__.py +2 -2
  98. ansible/galaxy/api.py +22 -18
  99. ansible/galaxy/collection/__init__.py +1 -1
  100. ansible/galaxy/collection/concrete_artifact_manager.py +8 -11
  101. ansible/galaxy/dependency_resolution/dataclasses.py +14 -4
  102. ansible/galaxy/dependency_resolution/providers.py +1 -1
  103. ansible/galaxy/dependency_resolution/reporters.py +81 -0
  104. ansible/galaxy/role.py +4 -8
  105. ansible/galaxy/token.py +28 -21
  106. ansible/inventory/data.py +47 -57
  107. ansible/inventory/group.py +44 -72
  108. ansible/inventory/helpers.py +9 -0
  109. ansible/inventory/host.py +32 -54
  110. ansible/inventory/manager.py +77 -34
  111. ansible/keyword_desc.yml +1 -1
  112. ansible/module_utils/_internal/__init__.py +55 -0
  113. ansible/module_utils/_internal/_ambient_context.py +58 -0
  114. ansible/module_utils/_internal/_ansiballz.py +133 -0
  115. ansible/module_utils/_internal/_concurrent/_daemon_threading.py +1 -0
  116. ansible/module_utils/_internal/_dataclass_annotation_patch.py +64 -0
  117. ansible/module_utils/_internal/_dataclass_validation.py +217 -0
  118. ansible/module_utils/_internal/_datatag/__init__.py +928 -0
  119. ansible/module_utils/_internal/_datatag/_tags.py +38 -0
  120. ansible/module_utils/_internal/_debugging.py +31 -0
  121. ansible/module_utils/_internal/_errors.py +30 -0
  122. ansible/module_utils/_internal/_json/__init__.py +63 -0
  123. ansible/module_utils/_internal/_json/_legacy_encoder.py +26 -0
  124. ansible/module_utils/_internal/_json/_profiles/__init__.py +410 -0
  125. ansible/module_utils/_internal/_json/_profiles/_fallback_to_str.py +73 -0
  126. ansible/module_utils/_internal/_json/_profiles/_module_legacy_c2m.py +31 -0
  127. ansible/module_utils/_internal/_json/_profiles/_module_legacy_m2c.py +35 -0
  128. ansible/module_utils/_internal/_json/_profiles/_module_modern_c2m.py +35 -0
  129. ansible/module_utils/_internal/_json/_profiles/_module_modern_m2c.py +33 -0
  130. ansible/module_utils/_internal/_json/_profiles/_tagless.py +50 -0
  131. ansible/module_utils/_internal/_patches/__init__.py +66 -0
  132. ansible/module_utils/_internal/_patches/_dataclass_annotation_patch.py +55 -0
  133. ansible/module_utils/_internal/_patches/_socket_patch.py +34 -0
  134. ansible/module_utils/_internal/_patches/_sys_intern_patch.py +34 -0
  135. ansible/module_utils/_internal/_plugin_exec_context.py +49 -0
  136. ansible/module_utils/_internal/_testing.py +0 -0
  137. ansible/module_utils/_internal/_traceback.py +89 -0
  138. ansible/module_utils/ansible_release.py +2 -2
  139. ansible/module_utils/api.py +1 -2
  140. ansible/module_utils/basic.py +154 -120
  141. ansible/module_utils/common/_utils.py +24 -28
  142. ansible/module_utils/common/collections.py +1 -2
  143. ansible/module_utils/common/dict_transformations.py +2 -2
  144. ansible/module_utils/common/file.py +2 -2
  145. ansible/module_utils/common/json.py +90 -84
  146. ansible/module_utils/common/locale.py +2 -2
  147. ansible/module_utils/common/messages.py +108 -0
  148. ansible/module_utils/common/parameters.py +27 -24
  149. ansible/module_utils/common/process.py +2 -2
  150. ansible/module_utils/common/respawn.py +41 -19
  151. ansible/module_utils/common/sentinel.py +66 -0
  152. ansible/module_utils/common/sys_info.py +8 -8
  153. ansible/module_utils/common/text/converters.py +16 -37
  154. ansible/module_utils/common/validation.py +35 -24
  155. ansible/module_utils/common/warnings.py +86 -25
  156. ansible/module_utils/common/yaml.py +29 -3
  157. ansible/module_utils/compat/datetime.py +33 -21
  158. ansible/module_utils/compat/paramiko.py +21 -10
  159. ansible/module_utils/compat/typing.py +6 -5
  160. ansible/module_utils/connection.py +2 -2
  161. ansible/module_utils/csharp/Ansible.Basic.cs +14 -11
  162. ansible/module_utils/csharp/Ansible.Become.cs +1 -0
  163. ansible/module_utils/csharp/Ansible._Async.cs +517 -0
  164. ansible/module_utils/datatag.py +46 -0
  165. ansible/module_utils/distro/__init__.py +2 -2
  166. ansible/module_utils/facts/ansible_collector.py +4 -5
  167. ansible/module_utils/facts/collector.py +13 -14
  168. ansible/module_utils/facts/compat.py +4 -4
  169. ansible/module_utils/facts/default_collectors.py +1 -1
  170. ansible/module_utils/facts/hardware/aix.py +34 -0
  171. ansible/module_utils/facts/hardware/base.py +1 -1
  172. ansible/module_utils/facts/hardware/darwin.py +1 -3
  173. ansible/module_utils/facts/hardware/freebsd.py +2 -2
  174. ansible/module_utils/facts/hardware/linux.py +4 -4
  175. ansible/module_utils/facts/namespace.py +1 -1
  176. ansible/module_utils/facts/network/base.py +1 -1
  177. ansible/module_utils/facts/network/fc_wwn.py +1 -2
  178. ansible/module_utils/facts/network/iscsi.py +1 -2
  179. ansible/module_utils/facts/network/nvme.py +1 -2
  180. ansible/module_utils/facts/other/facter.py +1 -2
  181. ansible/module_utils/facts/other/ohai.py +2 -3
  182. ansible/module_utils/facts/system/apparmor.py +1 -2
  183. ansible/module_utils/facts/system/caps.py +1 -1
  184. ansible/module_utils/facts/system/chroot.py +1 -2
  185. ansible/module_utils/facts/system/cmdline.py +1 -2
  186. ansible/module_utils/facts/system/date_time.py +5 -3
  187. ansible/module_utils/facts/system/distribution.py +9 -8
  188. ansible/module_utils/facts/system/dns.py +1 -1
  189. ansible/module_utils/facts/system/env.py +1 -2
  190. ansible/module_utils/facts/system/fips.py +7 -20
  191. ansible/module_utils/facts/system/loadavg.py +1 -2
  192. ansible/module_utils/facts/system/local.py +1 -2
  193. ansible/module_utils/facts/system/lsb.py +1 -2
  194. ansible/module_utils/facts/system/pkg_mgr.py +1 -2
  195. ansible/module_utils/facts/system/platform.py +1 -2
  196. ansible/module_utils/facts/system/python.py +1 -2
  197. ansible/module_utils/facts/system/selinux.py +1 -1
  198. ansible/module_utils/facts/system/service_mgr.py +1 -2
  199. ansible/module_utils/facts/system/ssh_pub_keys.py +1 -1
  200. ansible/module_utils/facts/system/systemd.py +1 -1
  201. ansible/module_utils/facts/system/user.py +1 -2
  202. ansible/module_utils/facts/utils.py +3 -3
  203. ansible/module_utils/facts/virtual/base.py +1 -1
  204. ansible/module_utils/facts/virtual/sunos.py +3 -15
  205. ansible/module_utils/facts/virtual/sysctl.py +3 -16
  206. ansible/module_utils/json_utils.py +2 -2
  207. ansible/module_utils/parsing/convert_bool.py +1 -1
  208. ansible/module_utils/service.py +18 -21
  209. ansible/module_utils/splitter.py +7 -7
  210. ansible/module_utils/testing.py +31 -0
  211. ansible/module_utils/urls.py +60 -31
  212. ansible/modules/add_host.py +4 -4
  213. ansible/modules/apt.py +60 -46
  214. ansible/modules/apt_key.py +19 -12
  215. ansible/modules/apt_repository.py +19 -16
  216. ansible/modules/assemble.py +6 -6
  217. ansible/modules/assert.py +4 -4
  218. ansible/modules/async_status.py +10 -12
  219. ansible/modules/async_wrapper.py +8 -3
  220. ansible/modules/blockinfile.py +6 -7
  221. ansible/modules/command.py +10 -17
  222. ansible/modules/copy.py +57 -144
  223. ansible/modules/cron.py +20 -15
  224. ansible/modules/deb822_repository.py +8 -9
  225. ansible/modules/debconf.py +5 -5
  226. ansible/modules/debug.py +4 -4
  227. ansible/modules/dnf.py +8 -8
  228. ansible/modules/dnf5.py +52 -17
  229. ansible/modules/dpkg_selections.py +4 -4
  230. ansible/modules/expect.py +8 -10
  231. ansible/modules/fail.py +4 -4
  232. ansible/modules/fetch.py +4 -4
  233. ansible/modules/file.py +174 -133
  234. ansible/modules/find.py +20 -18
  235. ansible/modules/gather_facts.py +3 -3
  236. ansible/modules/get_url.py +59 -53
  237. ansible/modules/getent.py +7 -9
  238. ansible/modules/git.py +28 -25
  239. ansible/modules/group.py +6 -6
  240. ansible/modules/group_by.py +4 -4
  241. ansible/modules/hostname.py +13 -29
  242. ansible/modules/import_playbook.py +6 -6
  243. ansible/modules/import_role.py +7 -7
  244. ansible/modules/import_tasks.py +6 -6
  245. ansible/modules/include_role.py +6 -6
  246. ansible/modules/include_tasks.py +6 -6
  247. ansible/modules/include_vars.py +6 -6
  248. ansible/modules/iptables.py +86 -73
  249. ansible/modules/known_hosts.py +10 -10
  250. ansible/modules/lineinfile.py +5 -5
  251. ansible/modules/meta.py +4 -4
  252. ansible/modules/mount_facts.py +2 -2
  253. ansible/modules/package.py +4 -4
  254. ansible/modules/package_facts.py +22 -10
  255. ansible/modules/pause.py +6 -6
  256. ansible/modules/ping.py +6 -6
  257. ansible/modules/pip.py +10 -11
  258. ansible/modules/raw.py +4 -4
  259. ansible/modules/reboot.py +6 -6
  260. ansible/modules/replace.py +9 -13
  261. ansible/modules/rpm_key.py +7 -8
  262. ansible/modules/script.py +4 -4
  263. ansible/modules/service.py +7 -8
  264. ansible/modules/service_facts.py +87 -10
  265. ansible/modules/set_fact.py +5 -5
  266. ansible/modules/set_stats.py +4 -4
  267. ansible/modules/setup.py +2 -2
  268. ansible/modules/shell.py +6 -6
  269. ansible/modules/slurp.py +6 -6
  270. ansible/modules/stat.py +9 -23
  271. ansible/modules/subversion.py +15 -15
  272. ansible/modules/systemd.py +6 -6
  273. ansible/modules/systemd_service.py +6 -6
  274. ansible/modules/sysvinit.py +6 -6
  275. ansible/modules/tempfile.py +5 -6
  276. ansible/modules/template.py +6 -6
  277. ansible/modules/unarchive.py +32 -11
  278. ansible/modules/uri.py +35 -49
  279. ansible/modules/user.py +53 -34
  280. ansible/modules/validate_argument_spec.py +10 -7
  281. ansible/modules/wait_for.py +39 -32
  282. ansible/modules/wait_for_connection.py +6 -6
  283. ansible/modules/yum_repository.py +6 -6
  284. ansible/parsing/ajson.py +14 -32
  285. ansible/parsing/dataloader.py +99 -54
  286. ansible/parsing/mod_args.py +28 -44
  287. ansible/parsing/plugin_docs.py +21 -86
  288. ansible/parsing/quoting.py +1 -1
  289. ansible/parsing/splitter.py +27 -12
  290. ansible/parsing/utils/addresses.py +24 -24
  291. ansible/parsing/utils/yaml.py +32 -61
  292. ansible/parsing/vault/__init__.py +319 -87
  293. ansible/parsing/yaml/__init__.py +0 -18
  294. ansible/parsing/yaml/dumper.py +6 -120
  295. ansible/parsing/yaml/loader.py +6 -39
  296. ansible/parsing/yaml/objects.py +36 -339
  297. ansible/playbook/__init__.py +1 -1
  298. ansible/playbook/attribute.py +8 -3
  299. ansible/playbook/base.py +182 -132
  300. ansible/playbook/block.py +26 -24
  301. ansible/playbook/collectionsearch.py +1 -15
  302. ansible/playbook/conditional.py +3 -77
  303. ansible/playbook/handler.py +8 -2
  304. ansible/playbook/helpers.py +41 -53
  305. ansible/playbook/included_file.py +6 -15
  306. ansible/playbook/loop_control.py +2 -2
  307. ansible/playbook/play.py +85 -44
  308. ansible/playbook/play_context.py +12 -17
  309. ansible/playbook/playbook_include.py +14 -15
  310. ansible/playbook/role/__init__.py +24 -26
  311. ansible/playbook/role/definition.py +15 -17
  312. ansible/playbook/role/include.py +2 -4
  313. ansible/playbook/role/metadata.py +10 -11
  314. ansible/playbook/role_include.py +3 -3
  315. ansible/playbook/taggable.py +13 -8
  316. ansible/playbook/task.py +188 -118
  317. ansible/playbook/task_include.py +5 -5
  318. ansible/plugins/__init__.py +68 -21
  319. ansible/plugins/action/__init__.py +209 -176
  320. ansible/plugins/action/add_host.py +1 -1
  321. ansible/plugins/action/assemble.py +1 -1
  322. ansible/plugins/action/assert.py +54 -66
  323. ansible/plugins/action/copy.py +7 -11
  324. ansible/plugins/action/debug.py +37 -31
  325. ansible/plugins/action/dnf.py +3 -4
  326. ansible/plugins/action/fail.py +1 -1
  327. ansible/plugins/action/fetch.py +4 -5
  328. ansible/plugins/action/gather_facts.py +8 -7
  329. ansible/plugins/action/group_by.py +1 -1
  330. ansible/plugins/action/include_vars.py +10 -11
  331. ansible/plugins/action/package.py +3 -6
  332. ansible/plugins/action/pause.py +2 -2
  333. ansible/plugins/action/script.py +15 -8
  334. ansible/plugins/action/service.py +6 -11
  335. ansible/plugins/action/set_fact.py +3 -12
  336. ansible/plugins/action/set_stats.py +3 -8
  337. ansible/plugins/action/template.py +35 -59
  338. ansible/plugins/action/unarchive.py +1 -1
  339. ansible/plugins/action/validate_argument_spec.py +5 -5
  340. ansible/plugins/action/wait_for_connection.py +1 -1
  341. ansible/plugins/become/__init__.py +31 -8
  342. ansible/plugins/become/runas.py +71 -0
  343. ansible/plugins/become/su.py +13 -8
  344. ansible/plugins/become/sudo.py +19 -0
  345. ansible/plugins/cache/__init__.py +35 -44
  346. ansible/plugins/cache/base.py +8 -0
  347. ansible/plugins/cache/jsonfile.py +10 -16
  348. ansible/plugins/cache/memory.py +6 -12
  349. ansible/plugins/callback/__init__.py +141 -123
  350. ansible/plugins/callback/default.py +30 -23
  351. ansible/plugins/callback/junit.py +28 -24
  352. ansible/plugins/callback/minimal.py +17 -14
  353. ansible/plugins/callback/oneline.py +13 -7
  354. ansible/plugins/callback/tree.py +10 -6
  355. ansible/plugins/connection/__init__.py +47 -34
  356. ansible/plugins/connection/local.py +150 -54
  357. ansible/plugins/connection/paramiko_ssh.py +21 -18
  358. ansible/plugins/connection/psrp.py +76 -165
  359. ansible/plugins/connection/ssh.py +301 -78
  360. ansible/plugins/connection/winrm.py +58 -140
  361. ansible/plugins/doc_fragments/action_common_attributes.py +14 -14
  362. ansible/plugins/doc_fragments/action_core.py +6 -6
  363. ansible/plugins/doc_fragments/backup.py +2 -2
  364. ansible/plugins/doc_fragments/checksum_common.py +27 -0
  365. ansible/plugins/doc_fragments/constructed.py +6 -2
  366. ansible/plugins/doc_fragments/decrypt.py +2 -2
  367. ansible/plugins/doc_fragments/default_callback.py +2 -2
  368. ansible/plugins/doc_fragments/files.py +2 -2
  369. ansible/plugins/doc_fragments/inventory_cache.py +2 -2
  370. ansible/plugins/doc_fragments/result_format_callback.py +2 -2
  371. ansible/plugins/doc_fragments/return_common.py +2 -2
  372. ansible/plugins/doc_fragments/template_common.py +4 -4
  373. ansible/plugins/doc_fragments/url.py +17 -1
  374. ansible/plugins/doc_fragments/url_windows.py +2 -2
  375. ansible/plugins/doc_fragments/validate.py +2 -2
  376. ansible/plugins/doc_fragments/vars_plugin_staging.py +2 -2
  377. ansible/plugins/filter/__init__.py +6 -2
  378. ansible/plugins/filter/b64decode.yml +22 -0
  379. ansible/plugins/filter/b64encode.yml +22 -0
  380. ansible/plugins/filter/bool.yml +11 -4
  381. ansible/plugins/filter/core.py +218 -108
  382. ansible/plugins/filter/encryption.py +32 -32
  383. ansible/plugins/filter/flatten.yml +3 -2
  384. ansible/plugins/filter/human_to_bytes.yml +2 -2
  385. ansible/plugins/filter/mathstuff.py +30 -37
  386. ansible/plugins/filter/password_hash.yml +8 -0
  387. ansible/plugins/filter/regex_search.yml +1 -4
  388. ansible/plugins/filter/split.yml +1 -1
  389. ansible/plugins/filter/to_nice_yaml.yml +0 -4
  390. ansible/plugins/filter/to_yaml.yml +0 -4
  391. ansible/plugins/filter/unvault.yml +1 -1
  392. ansible/plugins/filter/urls.py +1 -1
  393. ansible/plugins/filter/urlsplit.py +8 -9
  394. ansible/plugins/filter/vault.yml +14 -9
  395. ansible/plugins/filter/win_basename.yml +6 -1
  396. ansible/plugins/filter/win_dirname.yml +5 -0
  397. ansible/plugins/inventory/__init__.py +97 -77
  398. ansible/plugins/inventory/advanced_host_list.py +7 -5
  399. ansible/plugins/inventory/auto.py +11 -4
  400. ansible/plugins/inventory/constructed.py +21 -24
  401. ansible/plugins/inventory/generator.py +16 -11
  402. ansible/plugins/inventory/host_list.py +7 -5
  403. ansible/plugins/inventory/ini.py +78 -44
  404. ansible/plugins/inventory/script.py +189 -119
  405. ansible/plugins/inventory/toml.py +16 -126
  406. ansible/plugins/inventory/yaml.py +10 -8
  407. ansible/plugins/list.py +3 -3
  408. ansible/plugins/loader.py +197 -82
  409. ansible/plugins/lookup/__init__.py +21 -4
  410. ansible/plugins/lookup/config.py +21 -35
  411. ansible/plugins/lookup/csvfile.py +3 -2
  412. ansible/plugins/lookup/dict.py +1 -6
  413. ansible/plugins/lookup/env.py +12 -9
  414. ansible/plugins/lookup/file.py +5 -8
  415. ansible/plugins/lookup/first_found.py +86 -55
  416. ansible/plugins/lookup/indexed_items.py +1 -10
  417. ansible/plugins/lookup/ini.py +14 -13
  418. ansible/plugins/lookup/items.py +1 -1
  419. ansible/plugins/lookup/lines.py +8 -1
  420. ansible/plugins/lookup/list.py +1 -1
  421. ansible/plugins/lookup/nested.py +2 -18
  422. ansible/plugins/lookup/password.py +5 -5
  423. ansible/plugins/lookup/pipe.py +5 -7
  424. ansible/plugins/lookup/sequence.py +18 -8
  425. ansible/plugins/lookup/subelements.py +1 -4
  426. ansible/plugins/lookup/template.py +42 -36
  427. ansible/plugins/lookup/together.py +0 -12
  428. ansible/plugins/lookup/unvault.py +1 -5
  429. ansible/plugins/lookup/url.py +2 -8
  430. ansible/plugins/lookup/vars.py +16 -24
  431. ansible/plugins/shell/__init__.py +2 -2
  432. ansible/plugins/shell/cmd.py +2 -2
  433. ansible/plugins/shell/powershell.py +39 -22
  434. ansible/plugins/shell/sh.py +3 -2
  435. ansible/plugins/strategy/__init__.py +94 -113
  436. ansible/plugins/strategy/debug.py +2 -2
  437. ansible/plugins/strategy/free.py +13 -28
  438. ansible/plugins/strategy/host_pinned.py +2 -2
  439. ansible/plugins/strategy/linear.py +31 -33
  440. ansible/plugins/terminal/__init__.py +4 -4
  441. ansible/plugins/test/__init__.py +7 -2
  442. ansible/plugins/test/core.py +54 -20
  443. ansible/plugins/test/files.py +1 -1
  444. ansible/plugins/test/mathstuff.py +3 -3
  445. ansible/plugins/test/uri.py +3 -3
  446. ansible/plugins/vars/host_group_vars.py +7 -14
  447. ansible/release.py +2 -2
  448. ansible/template/__init__.py +368 -944
  449. ansible/utils/__init__.py +0 -18
  450. ansible/utils/_ssh_agent.py +657 -0
  451. ansible/utils/collection_loader/__init__.py +52 -5
  452. ansible/utils/collection_loader/_collection_config.py +5 -6
  453. ansible/utils/collection_loader/_collection_finder.py +79 -93
  454. ansible/utils/collection_loader/_collection_meta.py +13 -8
  455. ansible/utils/display.py +428 -58
  456. ansible/utils/encrypt.py +27 -19
  457. ansible/utils/fqcn.py +2 -2
  458. ansible/utils/hashing.py +2 -2
  459. ansible/utils/helpers.py +2 -2
  460. ansible/utils/listify.py +8 -8
  461. ansible/utils/lock.py +2 -2
  462. ansible/utils/path.py +4 -4
  463. ansible/utils/plugin_docs.py +14 -13
  464. ansible/utils/sentinel.py +4 -62
  465. ansible/utils/singleton.py +2 -0
  466. ansible/utils/ssh_functions.py +1 -1
  467. ansible/utils/unsafe_proxy.py +23 -332
  468. ansible/utils/vars.py +28 -8
  469. ansible/utils/version.py +2 -2
  470. ansible/vars/clean.py +4 -4
  471. ansible/vars/hostvars.py +60 -90
  472. ansible/vars/manager.py +205 -264
  473. ansible/vars/reserved.py +8 -9
  474. ansible_core-2.19.0b1.dist-info/BSD-3-Clause.txt +28 -0
  475. {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/METADATA +5 -4
  476. ansible_core-2.19.0b1.dist-info/RECORD +1070 -0
  477. {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/WHEEL +1 -1
  478. ansible_test/_data/completion/docker.txt +7 -7
  479. ansible_test/_data/completion/remote.txt +6 -6
  480. ansible_test/_data/completion/windows.txt +1 -0
  481. ansible_test/_data/requirements/ansible.txt +2 -2
  482. ansible_test/_data/requirements/sanity.ansible-doc.txt +3 -3
  483. ansible_test/_data/requirements/sanity.changelog.txt +1 -1
  484. ansible_test/_data/requirements/sanity.import.plugin.txt +2 -2
  485. ansible_test/_data/requirements/sanity.pylint.txt +4 -4
  486. ansible_test/_data/requirements/sanity.validate-modules.txt +2 -2
  487. ansible_test/_data/requirements/sanity.yamllint.txt +1 -1
  488. ansible_test/_data/requirements/units.txt +1 -0
  489. ansible_test/_internal/__init__.py +1 -0
  490. ansible_test/_internal/ansible_util.py +2 -0
  491. ansible_test/_internal/become.py +1 -0
  492. ansible_test/_internal/bootstrap.py +1 -0
  493. ansible_test/_internal/cache.py +1 -0
  494. ansible_test/_internal/cgroup.py +1 -0
  495. ansible_test/_internal/ci/__init__.py +1 -0
  496. ansible_test/_internal/ci/azp.py +1 -0
  497. ansible_test/_internal/ci/local.py +1 -0
  498. ansible_test/_internal/classification/__init__.py +1 -0
  499. ansible_test/_internal/classification/common.py +1 -0
  500. ansible_test/_internal/classification/csharp.py +1 -0
  501. ansible_test/_internal/classification/powershell.py +1 -0
  502. ansible_test/_internal/classification/python.py +1 -0
  503. ansible_test/_internal/cli/__init__.py +1 -0
  504. ansible_test/_internal/cli/actions.py +1 -0
  505. ansible_test/_internal/cli/argparsing/__init__.py +1 -0
  506. ansible_test/_internal/cli/argparsing/actions.py +1 -0
  507. ansible_test/_internal/cli/argparsing/argcompletion.py +1 -0
  508. ansible_test/_internal/cli/argparsing/parsers.py +1 -0
  509. ansible_test/_internal/cli/commands/__init__.py +11 -0
  510. ansible_test/_internal/cli/commands/coverage/__init__.py +1 -0
  511. ansible_test/_internal/cli/commands/coverage/analyze/__init__.py +1 -0
  512. ansible_test/_internal/cli/commands/coverage/analyze/targets/__init__.py +1 -0
  513. ansible_test/_internal/cli/commands/coverage/analyze/targets/combine.py +1 -0
  514. ansible_test/_internal/cli/commands/coverage/analyze/targets/expand.py +1 -0
  515. ansible_test/_internal/cli/commands/coverage/analyze/targets/filter.py +1 -0
  516. ansible_test/_internal/cli/commands/coverage/analyze/targets/generate.py +1 -0
  517. ansible_test/_internal/cli/commands/coverage/analyze/targets/missing.py +1 -0
  518. ansible_test/_internal/cli/commands/coverage/combine.py +1 -0
  519. ansible_test/_internal/cli/commands/coverage/erase.py +1 -0
  520. ansible_test/_internal/cli/commands/coverage/html.py +1 -0
  521. ansible_test/_internal/cli/commands/coverage/report.py +1 -0
  522. ansible_test/_internal/cli/commands/coverage/xml.py +1 -0
  523. ansible_test/_internal/cli/commands/env.py +1 -0
  524. ansible_test/_internal/cli/commands/integration/__init__.py +1 -0
  525. ansible_test/_internal/cli/commands/integration/network.py +1 -0
  526. ansible_test/_internal/cli/commands/integration/posix.py +1 -0
  527. ansible_test/_internal/cli/commands/integration/windows.py +1 -0
  528. ansible_test/_internal/cli/commands/sanity.py +9 -0
  529. ansible_test/_internal/cli/commands/shell.py +1 -0
  530. ansible_test/_internal/cli/commands/units.py +1 -0
  531. ansible_test/_internal/cli/compat.py +1 -0
  532. ansible_test/_internal/cli/completers.py +1 -0
  533. ansible_test/_internal/cli/converters.py +1 -0
  534. ansible_test/_internal/cli/environments.py +1 -0
  535. ansible_test/_internal/cli/epilog.py +1 -0
  536. ansible_test/_internal/cli/parsers/__init__.py +1 -0
  537. ansible_test/_internal/cli/parsers/base_argument_parsers.py +1 -0
  538. ansible_test/_internal/cli/parsers/helpers.py +1 -0
  539. ansible_test/_internal/cli/parsers/host_config_parsers.py +1 -0
  540. ansible_test/_internal/cli/parsers/key_value_parsers.py +1 -0
  541. ansible_test/_internal/cli/parsers/value_parsers.py +1 -0
  542. ansible_test/_internal/commands/__init__.py +1 -0
  543. ansible_test/_internal/commands/coverage/__init__.py +2 -1
  544. ansible_test/_internal/commands/coverage/analyze/__init__.py +1 -0
  545. ansible_test/_internal/commands/coverage/analyze/targets/__init__.py +1 -0
  546. ansible_test/_internal/commands/coverage/analyze/targets/combine.py +1 -0
  547. ansible_test/_internal/commands/coverage/analyze/targets/expand.py +1 -0
  548. ansible_test/_internal/commands/coverage/analyze/targets/filter.py +1 -0
  549. ansible_test/_internal/commands/coverage/analyze/targets/generate.py +1 -0
  550. ansible_test/_internal/commands/coverage/analyze/targets/missing.py +1 -0
  551. ansible_test/_internal/commands/coverage/combine.py +2 -1
  552. ansible_test/_internal/commands/coverage/erase.py +1 -0
  553. ansible_test/_internal/commands/coverage/html.py +1 -0
  554. ansible_test/_internal/commands/coverage/report.py +1 -0
  555. ansible_test/_internal/commands/coverage/xml.py +1 -0
  556. ansible_test/_internal/commands/env/__init__.py +2 -0
  557. ansible_test/_internal/commands/integration/__init__.py +4 -0
  558. ansible_test/_internal/commands/integration/cloud/__init__.py +1 -0
  559. ansible_test/_internal/commands/integration/cloud/acme.py +2 -1
  560. ansible_test/_internal/commands/integration/cloud/aws.py +1 -0
  561. ansible_test/_internal/commands/integration/cloud/azure.py +1 -0
  562. ansible_test/_internal/commands/integration/cloud/cs.py +1 -0
  563. ansible_test/_internal/commands/integration/cloud/digitalocean.py +1 -0
  564. ansible_test/_internal/commands/integration/cloud/galaxy.py +3 -2
  565. ansible_test/_internal/commands/integration/cloud/hcloud.py +1 -0
  566. ansible_test/_internal/commands/integration/cloud/httptester.py +2 -1
  567. ansible_test/_internal/commands/integration/cloud/nios.py +2 -1
  568. ansible_test/_internal/commands/integration/cloud/opennebula.py +1 -0
  569. ansible_test/_internal/commands/integration/cloud/openshift.py +1 -0
  570. ansible_test/_internal/commands/integration/cloud/scaleway.py +1 -0
  571. ansible_test/_internal/commands/integration/cloud/vcenter.py +1 -0
  572. ansible_test/_internal/commands/integration/cloud/vultr.py +1 -0
  573. ansible_test/_internal/commands/integration/coverage.py +1 -0
  574. ansible_test/_internal/commands/integration/filters.py +1 -0
  575. ansible_test/_internal/commands/integration/network.py +1 -0
  576. ansible_test/_internal/commands/integration/posix.py +1 -0
  577. ansible_test/_internal/commands/integration/windows.py +1 -0
  578. ansible_test/_internal/commands/sanity/__init__.py +16 -1
  579. ansible_test/_internal/commands/sanity/ansible_doc.py +1 -0
  580. ansible_test/_internal/commands/sanity/bin_symlinks.py +1 -0
  581. ansible_test/_internal/commands/sanity/compile.py +1 -0
  582. ansible_test/_internal/commands/sanity/ignores.py +1 -0
  583. ansible_test/_internal/commands/sanity/import.py +1 -0
  584. ansible_test/_internal/commands/sanity/integration_aliases.py +1 -0
  585. ansible_test/_internal/commands/sanity/pep8.py +1 -0
  586. ansible_test/_internal/commands/sanity/pslint.py +1 -0
  587. ansible_test/_internal/commands/sanity/pylint.py +24 -26
  588. ansible_test/_internal/commands/sanity/shellcheck.py +1 -0
  589. ansible_test/_internal/commands/sanity/validate_modules.py +1 -0
  590. ansible_test/_internal/commands/sanity/yamllint.py +1 -0
  591. ansible_test/_internal/commands/shell/__init__.py +1 -0
  592. ansible_test/_internal/commands/units/__init__.py +1 -0
  593. ansible_test/_internal/compat/__init__.py +1 -0
  594. ansible_test/_internal/compat/packaging.py +1 -0
  595. ansible_test/_internal/compat/yaml.py +1 -0
  596. ansible_test/_internal/completion.py +1 -0
  597. ansible_test/_internal/config.py +2 -0
  598. ansible_test/_internal/connections.py +1 -0
  599. ansible_test/_internal/constants.py +1 -0
  600. ansible_test/_internal/containers.py +1 -0
  601. ansible_test/_internal/content_config.py +1 -0
  602. ansible_test/_internal/core_ci.py +1 -0
  603. ansible_test/_internal/coverage_util.py +11 -10
  604. ansible_test/_internal/data.py +1 -0
  605. ansible_test/_internal/delegation.py +1 -0
  606. ansible_test/_internal/dev/__init__.py +1 -0
  607. ansible_test/_internal/dev/container_probe.py +1 -0
  608. ansible_test/_internal/diff.py +3 -2
  609. ansible_test/_internal/docker_util.py +2 -1
  610. ansible_test/_internal/encoding.py +1 -0
  611. ansible_test/_internal/executor.py +1 -0
  612. ansible_test/_internal/git.py +1 -0
  613. ansible_test/_internal/host_configs.py +1 -0
  614. ansible_test/_internal/host_profiles.py +1 -0
  615. ansible_test/_internal/http.py +1 -0
  616. ansible_test/_internal/init.py +1 -0
  617. ansible_test/_internal/inventory.py +35 -3
  618. ansible_test/_internal/io.py +1 -0
  619. ansible_test/_internal/metadata.py +1 -0
  620. ansible_test/_internal/payload.py +1 -0
  621. ansible_test/_internal/provider/__init__.py +1 -0
  622. ansible_test/_internal/provider/layout/__init__.py +1 -0
  623. ansible_test/_internal/provider/layout/ansible.py +1 -0
  624. ansible_test/_internal/provider/layout/collection.py +1 -0
  625. ansible_test/_internal/provider/layout/unsupported.py +1 -0
  626. ansible_test/_internal/provider/source/__init__.py +1 -0
  627. ansible_test/_internal/provider/source/git.py +1 -0
  628. ansible_test/_internal/provider/source/installed.py +1 -0
  629. ansible_test/_internal/provider/source/unsupported.py +1 -0
  630. ansible_test/_internal/provider/source/unversioned.py +1 -0
  631. ansible_test/_internal/provisioning.py +1 -0
  632. ansible_test/_internal/pypi_proxy.py +6 -5
  633. ansible_test/_internal/python_requirements.py +1 -0
  634. ansible_test/_internal/ssh.py +1 -0
  635. ansible_test/_internal/target.py +1 -0
  636. ansible_test/_internal/test.py +3 -2
  637. ansible_test/_internal/thread.py +1 -0
  638. ansible_test/_internal/timeout.py +1 -0
  639. ansible_test/_internal/util.py +1 -0
  640. ansible_test/_internal/util_common.py +5 -2
  641. ansible_test/_internal/venv.py +1 -0
  642. ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py +1 -0
  643. ansible_test/_util/controller/sanity/code-smell/changelog/sphinx.py +1 -0
  644. ansible_test/_util/controller/sanity/code-smell/changelog.py +1 -0
  645. ansible_test/_util/controller/sanity/code-smell/empty-init.py +1 -0
  646. ansible_test/_util/controller/sanity/code-smell/line-endings.py +1 -0
  647. ansible_test/_util/controller/sanity/code-smell/no-assert.py +1 -0
  648. ansible_test/_util/controller/sanity/code-smell/no-get-exception.py +1 -0
  649. ansible_test/_util/controller/sanity/code-smell/no-illegal-filenames.py +1 -0
  650. ansible_test/_util/controller/sanity/code-smell/no-smart-quotes.py +1 -0
  651. ansible_test/_util/controller/sanity/code-smell/replace-urlopen.py +1 -0
  652. ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +28 -1
  653. ansible_test/_util/controller/sanity/code-smell/shebang.py +1 -0
  654. ansible_test/_util/controller/sanity/code-smell/symlinks.py +1 -0
  655. ansible_test/_util/controller/sanity/code-smell/use-argspec-type-path.py +1 -0
  656. ansible_test/_util/controller/sanity/code-smell/use-compat-six.py +1 -0
  657. ansible_test/_util/controller/sanity/integration-aliases/yaml_to_json.py +2 -1
  658. ansible_test/_util/controller/sanity/pep8/current-ignore.txt +4 -0
  659. ansible_test/_util/controller/sanity/pylint/config/ansible-test-target.cfg +7 -5
  660. ansible_test/_util/controller/sanity/pylint/config/ansible-test.cfg +7 -5
  661. ansible_test/_util/controller/sanity/pylint/config/code-smell.cfg +7 -5
  662. ansible_test/_util/controller/sanity/pylint/config/collection.cfg +3 -5
  663. ansible_test/_util/controller/sanity/pylint/config/default.cfg +7 -7
  664. ansible_test/_util/controller/sanity/pylint/plugins/deprecated.py +1 -13
  665. ansible_test/_util/controller/sanity/pylint/plugins/hide_unraisable.py +1 -0
  666. ansible_test/_util/controller/sanity/pylint/plugins/string_format.py +1 -8
  667. ansible_test/_util/controller/sanity/pylint/plugins/unwanted.py +1 -8
  668. ansible_test/_util/controller/sanity/validate-modules/validate_modules/main.py +55 -28
  669. ansible_test/_util/controller/sanity/validate-modules/validate_modules/module_args.py +12 -5
  670. ansible_test/_util/controller/sanity/validate-modules/validate_modules/schema.py +13 -2
  671. ansible_test/_util/controller/sanity/validate-modules/validate_modules/utils.py +1 -0
  672. ansible_test/_util/controller/sanity/yamllint/yamllinter.py +35 -17
  673. ansible_test/_util/controller/tools/collection_detail.py +1 -0
  674. ansible_test/_util/controller/tools/yaml_to_json.py +2 -1
  675. ansible_test/_util/target/pytest/plugins/ansible_forked.py +6 -1
  676. ansible_test/_util/target/pytest/plugins/ansible_pytest_collections.py +2 -1
  677. ansible_test/_util/target/pytest/plugins/ansible_pytest_coverage.py +1 -0
  678. ansible_test/_util/target/sanity/compile/compile.py +1 -0
  679. ansible_test/_util/target/sanity/import/importer.py +15 -16
  680. ansible_test/_util/target/setup/bootstrap.sh +9 -20
  681. ansible_test/_util/target/setup/probe_cgroups.py +1 -0
  682. ansible_test/_util/target/setup/quiet_pip.py +1 -0
  683. ansible_test/_util/target/setup/requirements.py +35 -27
  684. ansible_test/_util/target/tools/virtualenvcheck.py +2 -1
  685. ansible_test/_util/target/tools/yamlcheck.py +2 -1
  686. ansible/compat/selectors.py +0 -32
  687. ansible/errors/yaml_strings.py +0 -138
  688. ansible/executor/action_write_locks.py +0 -44
  689. ansible/executor/discovery/python_target.py +0 -47
  690. ansible/executor/powershell/module_powershell_wrapper.ps1 +0 -86
  691. ansible/executor/powershell/module_script_wrapper.ps1 +0 -22
  692. ansible/module_utils/compat/importlib.py +0 -26
  693. ansible/module_utils/compat/selectors.py +0 -32
  694. ansible/module_utils/pycompat24.py +0 -73
  695. ansible/parsing/utils/jsonify.py +0 -36
  696. ansible/parsing/yaml/constructor.py +0 -178
  697. ansible/template/native_helpers.py +0 -251
  698. ansible/template/template.py +0 -43
  699. ansible/template/vars.py +0 -77
  700. ansible/utils/native_jinja.py +0 -11
  701. ansible/vars/fact_cache.py +0 -71
  702. ansible_core-2.18.4rc1.dist-info/RECORD +0 -992
  703. {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/Apache-License.txt +0 -0
  704. {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/COPYING +0 -0
  705. {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/MIT-license.txt +0 -0
  706. {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/PSF-license.txt +0 -0
  707. {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/entry_points.txt +0 -0
  708. {ansible_core-2.18.4rc1.dist-info → ansible_core-2.19.0b1.dist-info}/simplified_bsd.txt +0 -0
  709. {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, filename=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 b_vaulttext: byte str containing the data from a save file
157
- :kwarg default_vault_id: The vault_id name to use if the vaulttext does not provide one.
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 exc:
172
- msg = "Vault envelope format error"
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
- return unhexlify(b_data)
223
- except (BinasciiError, TypeError) as exc:
224
- raise AnsibleVaultFormatError('Vault format unhexlify error: %s' % exc)
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 exc:
251
- msg = "Vault vaulttext format error: %s" % exc
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
- '''Check the secret against minimal requirements.
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
- '''Opaque/abstract objects for a single vault secret. ie, a password or a key.'''
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
- '''The secret as a bytestring.
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
- '''Determine if a vault secret script is a client script that can be given --vault-id args'''
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
- ''' Get secret from file content or execute file and get secret from stdout '''
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, filename)
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
- '''Find all VaultSecret objects that are mapped to any of the target_vault_ids in secrets'''
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
- '''Find the best secret from secrets that matches target_vault_ids
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
- '''Find the best/first/only secret in secrets to use for encrypting'''
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, filename=None, obj=None):
637
- '''Decrypt a piece of vault encrypted data.
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
- :kwarg filename: a filename that the data came from. This is only
642
- used to make better error messages in case the data cannot be
643
- decrypted.
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, filename=None, obj=None):
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
- b_vaulttext = to_bytes(vaulttext, errors='strict', encoding='utf-8')
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
- msg = "A vault password must be specified to decrypt data"
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
- msg = "input is not vault encrypted data. "
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, filename=filename)
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 AnsibleError("{0} cipher could not be found".format(cipher_name))
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(filename)))
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(filename)))
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 filename:
733
- file_slug = ' of "%s"' % filename
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 as exc:
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(filename), e))
731
+ (to_text(vault_secret_id), to_text(origin), e))
749
732
  continue
750
733
  else:
751
- msg = "Decryption failed (no vault secrets were found that could decrypt)"
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, filename=filename)
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, filename=filename)
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, filename=filename)
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
@@ -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