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
ansible/utils/__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
@@ -0,0 +1,657 @@
1
+ # Copyright: Contributors to the Ansible project
2
+ # BSD 3 Clause License (see licenses/BSD-3-Clause.txt or https://opensource.org/license/bsd-3-clause/)
3
+
4
+ from __future__ import annotations
5
+
6
+ import binascii
7
+ import copy
8
+ import dataclasses
9
+ import enum
10
+ import functools
11
+ import hashlib
12
+ import socket
13
+ import types
14
+ import typing as t
15
+
16
+ try:
17
+ from cryptography.hazmat.primitives import serialization
18
+ from cryptography.hazmat.primitives.asymmetric.dsa import (
19
+ DSAParameterNumbers,
20
+ DSAPrivateKey,
21
+ DSAPublicKey,
22
+ DSAPublicNumbers,
23
+ )
24
+ from cryptography.hazmat.primitives.asymmetric.ec import (
25
+ EllipticCurve,
26
+ EllipticCurvePrivateKey,
27
+ EllipticCurvePublicKey,
28
+ SECP256R1,
29
+ SECP384R1,
30
+ SECP521R1,
31
+ )
32
+ from cryptography.hazmat.primitives.asymmetric.ed25519 import (
33
+ Ed25519PrivateKey,
34
+ Ed25519PublicKey,
35
+ )
36
+ from cryptography.hazmat.primitives.asymmetric.rsa import (
37
+ RSAPrivateKey,
38
+ RSAPublicKey,
39
+ RSAPublicNumbers,
40
+ )
41
+ except ImportError:
42
+ HAS_CRYPTOGRAPHY = False
43
+ else:
44
+ HAS_CRYPTOGRAPHY = True
45
+
46
+ CryptoPublicKey = t.Union[
47
+ DSAPublicKey,
48
+ EllipticCurvePublicKey,
49
+ Ed25519PublicKey,
50
+ RSAPublicKey,
51
+ ]
52
+
53
+ CryptoPrivateKey = t.Union[
54
+ DSAPrivateKey,
55
+ EllipticCurvePrivateKey,
56
+ Ed25519PrivateKey,
57
+ RSAPrivateKey,
58
+ ]
59
+
60
+
61
+ if t.TYPE_CHECKING:
62
+ from cryptography.hazmat.primitives.asymmetric.dsa import DSAPrivateNumbers
63
+ from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateNumbers
64
+ from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateNumbers
65
+
66
+
67
+ _SSH_AGENT_CLIENT_SOCKET_TIMEOUT = 10
68
+
69
+
70
+ class ProtocolMsgNumbers(enum.IntEnum):
71
+ # Responses
72
+ SSH_AGENT_FAILURE = 5
73
+ SSH_AGENT_SUCCESS = 6
74
+ SSH_AGENT_IDENTITIES_ANSWER = 12
75
+ SSH_AGENT_SIGN_RESPONSE = 14
76
+ SSH_AGENT_EXTENSION_FAILURE = 28
77
+ SSH_AGENT_EXTENSION_RESPONSE = 29
78
+
79
+ # Constraints
80
+ SSH_AGENT_CONSTRAIN_LIFETIME = 1
81
+ SSH_AGENT_CONSTRAIN_CONFIRM = 2
82
+ SSH_AGENT_CONSTRAIN_EXTENSION = 255
83
+
84
+ # Requests
85
+ SSH_AGENTC_REQUEST_IDENTITIES = 11
86
+ SSH_AGENTC_SIGN_REQUEST = 13
87
+ SSH_AGENTC_ADD_IDENTITY = 17
88
+ SSH_AGENTC_REMOVE_IDENTITY = 18
89
+ SSH_AGENTC_REMOVE_ALL_IDENTITIES = 19
90
+ SSH_AGENTC_ADD_SMARTCARD_KEY = 20
91
+ SSH_AGENTC_REMOVE_SMARTCARD_KEY = 21
92
+ SSH_AGENTC_LOCK = 22
93
+ SSH_AGENTC_UNLOCK = 23
94
+ SSH_AGENTC_ADD_ID_CONSTRAINED = 25
95
+ SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED = 26
96
+ SSH_AGENTC_EXTENSION = 27
97
+
98
+ def to_blob(self) -> bytes:
99
+ return bytes([self])
100
+
101
+
102
+ class SshAgentFailure(RuntimeError):
103
+ """Server failure or unexpected response."""
104
+
105
+
106
+ # NOTE: Classes below somewhat represent "Data Type Representations Used in the SSH Protocols"
107
+ # as specified by RFC4251
108
+
109
+ @t.runtime_checkable
110
+ class SupportsToBlob(t.Protocol):
111
+ def to_blob(self) -> bytes:
112
+ ...
113
+
114
+
115
+ @t.runtime_checkable
116
+ class SupportsFromBlob(t.Protocol):
117
+ @classmethod
118
+ def from_blob(cls, blob: memoryview | bytes) -> t.Self:
119
+ ...
120
+
121
+ @classmethod
122
+ def consume_from_blob(cls, blob: memoryview | bytes) -> tuple[t.Self, memoryview | bytes]:
123
+ ...
124
+
125
+
126
+ def _split_blob(blob: memoryview | bytes, length: int) -> tuple[memoryview | bytes, memoryview | bytes]:
127
+ if len(blob) < length:
128
+ raise ValueError("_split_blob: unexpected data length")
129
+ return blob[:length], blob[length:]
130
+
131
+
132
+ class VariableSized:
133
+ @classmethod
134
+ def from_blob(cls, blob: memoryview | bytes) -> t.Self:
135
+ raise NotImplementedError
136
+
137
+ @classmethod
138
+ def consume_from_blob(cls, blob: memoryview | bytes) -> tuple[t.Self, memoryview | bytes]:
139
+ length = uint32.from_blob(blob[:4])
140
+ blob = blob[4:]
141
+ data, rest = _split_blob(blob, length)
142
+ return cls.from_blob(data), rest
143
+
144
+
145
+ class uint32(int):
146
+ def to_blob(self) -> bytes:
147
+ return self.to_bytes(length=4, byteorder='big')
148
+
149
+ @classmethod
150
+ def from_blob(cls, blob: memoryview | bytes) -> t.Self:
151
+ return cls.from_bytes(blob, byteorder='big')
152
+
153
+ @classmethod
154
+ def consume_from_blob(cls, blob: memoryview | bytes) -> tuple[t.Self, memoryview | bytes]:
155
+ length = uint32(4)
156
+ data, rest = _split_blob(blob, length)
157
+ return cls.from_blob(data), rest
158
+
159
+
160
+ class mpint(int, VariableSized):
161
+ def to_blob(self) -> bytes:
162
+ if self < 0:
163
+ raise ValueError("negative mpint not allowed")
164
+ if not self:
165
+ return b""
166
+ nbytes = (self.bit_length() + 8) // 8
167
+ ret = bytearray(self.to_bytes(length=nbytes, byteorder='big'))
168
+ ret[:0] = uint32(len(ret)).to_blob()
169
+ return ret
170
+
171
+ @classmethod
172
+ def from_blob(cls, blob: memoryview | bytes) -> t.Self:
173
+ if blob and blob[0] > 127:
174
+ raise ValueError("Invalid data")
175
+ return cls.from_bytes(blob, byteorder='big')
176
+
177
+
178
+ class constraints(bytes):
179
+ def to_blob(self) -> bytes:
180
+ return self
181
+
182
+
183
+ class binary_string(bytes, VariableSized):
184
+ def to_blob(self) -> bytes:
185
+ if length := len(self):
186
+ return uint32(length).to_blob() + self
187
+ else:
188
+ return b""
189
+
190
+ @classmethod
191
+ def from_blob(cls, blob: memoryview | bytes) -> t.Self:
192
+ return cls(blob)
193
+
194
+
195
+ class unicode_string(str, VariableSized):
196
+ def to_blob(self) -> bytes:
197
+ val = self.encode('utf-8')
198
+ if length := len(val):
199
+ return uint32(length).to_blob() + val
200
+ else:
201
+ return b""
202
+
203
+ @classmethod
204
+ def from_blob(cls, blob: memoryview | bytes) -> t.Self:
205
+ return cls(bytes(blob).decode('utf-8'))
206
+
207
+
208
+ class KeyAlgo(str, VariableSized, enum.Enum):
209
+ RSA = "ssh-rsa"
210
+ DSA = "ssh-dss"
211
+ ECDSA256 = "ecdsa-sha2-nistp256"
212
+ SKECDSA256 = "sk-ecdsa-sha2-nistp256@openssh.com"
213
+ ECDSA384 = "ecdsa-sha2-nistp384"
214
+ ECDSA521 = "ecdsa-sha2-nistp521"
215
+ ED25519 = "ssh-ed25519"
216
+ SKED25519 = "sk-ssh-ed25519@openssh.com"
217
+ RSASHA256 = "rsa-sha2-256"
218
+ RSASHA512 = "rsa-sha2-512"
219
+
220
+ @property
221
+ def main_type(self) -> str:
222
+ match self:
223
+ case self.RSA:
224
+ return 'RSA'
225
+ case self.DSA:
226
+ return 'DSA'
227
+ case self.ECDSA256 | self.ECDSA384 | self.ECDSA521:
228
+ return 'ECDSA'
229
+ case self.ED25519:
230
+ return 'ED25519'
231
+ case _:
232
+ raise NotImplementedError(self.name)
233
+
234
+ def to_blob(self) -> bytes:
235
+ b_self = self.encode('utf-8')
236
+ return uint32(len(b_self)).to_blob() + b_self
237
+
238
+ @classmethod
239
+ def from_blob(cls, blob: memoryview | bytes) -> t.Self:
240
+ return cls(bytes(blob).decode('utf-8'))
241
+
242
+
243
+ if HAS_CRYPTOGRAPHY:
244
+ _ECDSA_KEY_TYPE: dict[KeyAlgo, type[EllipticCurve]] = {
245
+ KeyAlgo.ECDSA256: SECP256R1,
246
+ KeyAlgo.ECDSA384: SECP384R1,
247
+ KeyAlgo.ECDSA521: SECP521R1,
248
+ }
249
+
250
+
251
+ @dataclasses.dataclass
252
+ class Msg:
253
+ def to_blob(self) -> bytes:
254
+ rv = bytearray()
255
+ for field in dataclasses.fields(self):
256
+ fv = getattr(self, field.name)
257
+ if isinstance(fv, SupportsToBlob):
258
+ rv.extend(fv.to_blob())
259
+ else:
260
+ raise NotImplementedError(field.type)
261
+ return rv
262
+
263
+ @classmethod
264
+ def from_blob(cls, blob: memoryview | bytes) -> t.Self:
265
+ args: list[t.Any] = []
266
+ for _field_name, field_type in t.get_type_hints(cls).items():
267
+ if isinstance(field_type, SupportsFromBlob):
268
+ fv, blob = field_type.consume_from_blob(blob)
269
+ args.append(fv)
270
+ else:
271
+ raise NotImplementedError(str(field_type))
272
+ return cls(*args)
273
+
274
+
275
+ @dataclasses.dataclass
276
+ class PrivateKeyMsg(Msg):
277
+ @staticmethod
278
+ def from_private_key(private_key: CryptoPrivateKey) -> PrivateKeyMsg:
279
+ match private_key:
280
+ case RSAPrivateKey():
281
+ rsa_pn: RSAPrivateNumbers = private_key.private_numbers()
282
+ return RSAPrivateKeyMsg(
283
+ KeyAlgo.RSA,
284
+ mpint(rsa_pn.public_numbers.n),
285
+ mpint(rsa_pn.public_numbers.e),
286
+ mpint(rsa_pn.d),
287
+ mpint(rsa_pn.iqmp),
288
+ mpint(rsa_pn.p),
289
+ mpint(rsa_pn.q),
290
+ )
291
+ case DSAPrivateKey():
292
+ dsa_pn: DSAPrivateNumbers = private_key.private_numbers()
293
+ return DSAPrivateKeyMsg(
294
+ KeyAlgo.DSA,
295
+ mpint(dsa_pn.public_numbers.parameter_numbers.p),
296
+ mpint(dsa_pn.public_numbers.parameter_numbers.q),
297
+ mpint(dsa_pn.public_numbers.parameter_numbers.g),
298
+ mpint(dsa_pn.public_numbers.y),
299
+ mpint(dsa_pn.x),
300
+ )
301
+ case EllipticCurvePrivateKey():
302
+ ecdsa_pn: EllipticCurvePrivateNumbers = private_key.private_numbers()
303
+ key_size = private_key.key_size
304
+ return EcdsaPrivateKeyMsg(
305
+ getattr(KeyAlgo, f'ECDSA{key_size}'),
306
+ unicode_string(f'nistp{key_size}'),
307
+ binary_string(private_key.public_key().public_bytes(
308
+ encoding=serialization.Encoding.X962,
309
+ format=serialization.PublicFormat.UncompressedPoint
310
+ )),
311
+ mpint(ecdsa_pn.private_value),
312
+ )
313
+ case Ed25519PrivateKey():
314
+ public_bytes = private_key.public_key().public_bytes(
315
+ encoding=serialization.Encoding.Raw,
316
+ format=serialization.PublicFormat.Raw,
317
+ )
318
+ private_bytes = private_key.private_bytes(
319
+ encoding=serialization.Encoding.Raw,
320
+ format=serialization.PrivateFormat.Raw,
321
+ encryption_algorithm=serialization.NoEncryption()
322
+ )
323
+ return Ed25519PrivateKeyMsg(
324
+ KeyAlgo.ED25519,
325
+ binary_string(public_bytes),
326
+ binary_string(private_bytes + public_bytes),
327
+ )
328
+ case _:
329
+ raise NotImplementedError(private_key)
330
+
331
+
332
+ @dataclasses.dataclass(order=True, slots=True)
333
+ class RSAPrivateKeyMsg(PrivateKeyMsg):
334
+ type: KeyAlgo
335
+ n: mpint
336
+ e: mpint
337
+ d: mpint
338
+ iqmp: mpint
339
+ p: mpint
340
+ q: mpint
341
+ comments: unicode_string = dataclasses.field(default=unicode_string(''), compare=False)
342
+ constraints: constraints = dataclasses.field(default=constraints(b''))
343
+
344
+
345
+ @dataclasses.dataclass(order=True, slots=True)
346
+ class DSAPrivateKeyMsg(PrivateKeyMsg):
347
+ type: KeyAlgo
348
+ p: mpint
349
+ q: mpint
350
+ g: mpint
351
+ y: mpint
352
+ x: mpint
353
+ comments: unicode_string = dataclasses.field(default=unicode_string(''), compare=False)
354
+ constraints: constraints = dataclasses.field(default=constraints(b''))
355
+
356
+
357
+ @dataclasses.dataclass(order=True, slots=True)
358
+ class EcdsaPrivateKeyMsg(PrivateKeyMsg):
359
+ type: KeyAlgo
360
+ ecdsa_curve_name: unicode_string
361
+ Q: binary_string
362
+ d: mpint
363
+ comments: unicode_string = dataclasses.field(default=unicode_string(''), compare=False)
364
+ constraints: constraints = dataclasses.field(default=constraints(b''))
365
+
366
+
367
+ @dataclasses.dataclass(order=True, slots=True)
368
+ class Ed25519PrivateKeyMsg(PrivateKeyMsg):
369
+ type: KeyAlgo
370
+ enc_a: binary_string
371
+ k_env_a: binary_string
372
+ comments: unicode_string = dataclasses.field(default=unicode_string(''), compare=False)
373
+ constraints: constraints = dataclasses.field(default=constraints(b''))
374
+
375
+
376
+ @dataclasses.dataclass
377
+ class PublicKeyMsg(Msg):
378
+ @staticmethod
379
+ def get_dataclass(
380
+ type: KeyAlgo
381
+ ) -> type[t.Union[
382
+ RSAPublicKeyMsg,
383
+ EcdsaPublicKeyMsg,
384
+ Ed25519PublicKeyMsg,
385
+ DSAPublicKeyMsg
386
+ ]]:
387
+ match type:
388
+ case KeyAlgo.RSA:
389
+ return RSAPublicKeyMsg
390
+ case KeyAlgo.ECDSA256 | KeyAlgo.ECDSA384 | KeyAlgo.ECDSA521:
391
+ return EcdsaPublicKeyMsg
392
+ case KeyAlgo.ED25519:
393
+ return Ed25519PublicKeyMsg
394
+ case KeyAlgo.DSA:
395
+ return DSAPublicKeyMsg
396
+ case _:
397
+ raise NotImplementedError(type)
398
+
399
+ @functools.cached_property
400
+ def public_key(self) -> CryptoPublicKey:
401
+ type: KeyAlgo = self.type
402
+ match type:
403
+ case KeyAlgo.RSA:
404
+ return RSAPublicNumbers(
405
+ self.e,
406
+ self.n
407
+ ).public_key()
408
+ case KeyAlgo.ECDSA256 | KeyAlgo.ECDSA384 | KeyAlgo.ECDSA521:
409
+ curve = _ECDSA_KEY_TYPE[KeyAlgo(type)]
410
+ return EllipticCurvePublicKey.from_encoded_point(
411
+ curve(),
412
+ self.Q
413
+ )
414
+ case KeyAlgo.ED25519:
415
+ return Ed25519PublicKey.from_public_bytes(
416
+ self.enc_a
417
+ )
418
+ case KeyAlgo.DSA:
419
+ return DSAPublicNumbers(
420
+ self.y,
421
+ DSAParameterNumbers(
422
+ self.p,
423
+ self.q,
424
+ self.g
425
+ )
426
+ ).public_key()
427
+ case _:
428
+ raise NotImplementedError(type)
429
+
430
+ @staticmethod
431
+ def from_public_key(public_key: CryptoPublicKey) -> PublicKeyMsg:
432
+ match public_key:
433
+ case DSAPublicKey():
434
+ dsa_pn: DSAPublicNumbers = public_key.public_numbers()
435
+ return DSAPublicKeyMsg(
436
+ KeyAlgo.DSA,
437
+ mpint(dsa_pn.parameter_numbers.p),
438
+ mpint(dsa_pn.parameter_numbers.q),
439
+ mpint(dsa_pn.parameter_numbers.g),
440
+ mpint(dsa_pn.y)
441
+ )
442
+ case EllipticCurvePublicKey():
443
+ return EcdsaPublicKeyMsg(
444
+ getattr(KeyAlgo, f'ECDSA{public_key.curve.key_size}'),
445
+ unicode_string(f'nistp{public_key.curve.key_size}'),
446
+ binary_string(public_key.public_bytes(
447
+ encoding=serialization.Encoding.X962,
448
+ format=serialization.PublicFormat.UncompressedPoint
449
+ ))
450
+ )
451
+ case Ed25519PublicKey():
452
+ return Ed25519PublicKeyMsg(
453
+ KeyAlgo.ED25519,
454
+ binary_string(public_key.public_bytes(
455
+ encoding=serialization.Encoding.Raw,
456
+ format=serialization.PublicFormat.Raw,
457
+ ))
458
+ )
459
+ case RSAPublicKey():
460
+ rsa_pn: RSAPublicNumbers = public_key.public_numbers()
461
+ return RSAPublicKeyMsg(
462
+ KeyAlgo.RSA,
463
+ mpint(rsa_pn.e),
464
+ mpint(rsa_pn.n)
465
+ )
466
+ case _:
467
+ raise NotImplementedError(public_key)
468
+
469
+ @functools.cached_property
470
+ def fingerprint(self) -> str:
471
+ digest = hashlib.sha256()
472
+ msg = copy.copy(self)
473
+ msg.comments = unicode_string('')
474
+ k = msg.to_blob()
475
+ digest.update(k)
476
+ return binascii.b2a_base64(
477
+ digest.digest(),
478
+ newline=False
479
+ ).rstrip(b'=').decode('utf-8')
480
+
481
+
482
+ @dataclasses.dataclass(order=True, slots=True)
483
+ class RSAPublicKeyMsg(PublicKeyMsg):
484
+ type: KeyAlgo
485
+ e: mpint
486
+ n: mpint
487
+ comments: unicode_string = dataclasses.field(default=unicode_string(''), compare=False)
488
+
489
+
490
+ @dataclasses.dataclass(order=True, slots=True)
491
+ class DSAPublicKeyMsg(PublicKeyMsg):
492
+ type: KeyAlgo
493
+ p: mpint
494
+ q: mpint
495
+ g: mpint
496
+ y: mpint
497
+ comments: unicode_string = dataclasses.field(default=unicode_string(''), compare=False)
498
+
499
+
500
+ @dataclasses.dataclass(order=True, slots=True)
501
+ class EcdsaPublicKeyMsg(PublicKeyMsg):
502
+ type: KeyAlgo
503
+ ecdsa_curve_name: unicode_string
504
+ Q: binary_string
505
+ comments: unicode_string = dataclasses.field(default=unicode_string(''), compare=False)
506
+
507
+
508
+ @dataclasses.dataclass(order=True, slots=True)
509
+ class Ed25519PublicKeyMsg(PublicKeyMsg):
510
+ type: KeyAlgo
511
+ enc_a: binary_string
512
+ comments: unicode_string = dataclasses.field(default=unicode_string(''), compare=False)
513
+
514
+
515
+ @dataclasses.dataclass(order=True, slots=True)
516
+ class KeyList(Msg):
517
+ nkeys: uint32
518
+ keys: PublicKeyMsgList
519
+
520
+ def __post_init__(self) -> None:
521
+ if self.nkeys != len(self.keys):
522
+ raise SshAgentFailure(
523
+ "agent: invalid number of keys received for identities list"
524
+ )
525
+
526
+
527
+ @dataclasses.dataclass(order=True, slots=True)
528
+ class PublicKeyMsgList(Msg):
529
+ keys: list[PublicKeyMsg]
530
+
531
+ def __iter__(self) -> t.Iterator[PublicKeyMsg]:
532
+ yield from self.keys
533
+
534
+ def __len__(self) -> int:
535
+ return len(self.keys)
536
+
537
+ @classmethod
538
+ def from_blob(cls, blob: memoryview | bytes) -> t.Self:
539
+ ...
540
+
541
+ @classmethod
542
+ def consume_from_blob(cls, blob: memoryview | bytes) -> tuple[t.Self, memoryview | bytes]:
543
+ args: list[PublicKeyMsg] = []
544
+ while blob:
545
+ prev_blob = blob
546
+ key_blob, key_blob_length, comment_blob = cls._consume_field(blob)
547
+
548
+ peek_key_algo, _length, _blob = cls._consume_field(key_blob)
549
+ pub_key_msg_cls = PublicKeyMsg.get_dataclass(
550
+ KeyAlgo(bytes(peek_key_algo).decode('utf-8'))
551
+ )
552
+
553
+ _fv, comment_blob_length, blob = cls._consume_field(comment_blob)
554
+ key_plus_comment = (
555
+ prev_blob[4: (4 + key_blob_length) + (4 + comment_blob_length)]
556
+ )
557
+
558
+ args.append(pub_key_msg_cls.from_blob(key_plus_comment))
559
+ return cls(args), b""
560
+
561
+ @staticmethod
562
+ def _consume_field(
563
+ blob: memoryview | bytes
564
+ ) -> tuple[memoryview | bytes, uint32, memoryview | bytes]:
565
+ length = uint32.from_blob(blob[:4])
566
+ blob = blob[4:]
567
+ data, rest = _split_blob(blob, length)
568
+ return data, length, rest
569
+
570
+
571
+ class SshAgentClient:
572
+ def __init__(self, auth_sock: str) -> None:
573
+ self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
574
+ self._sock.settimeout(_SSH_AGENT_CLIENT_SOCKET_TIMEOUT)
575
+ self._sock.connect(auth_sock)
576
+
577
+ def close(self) -> None:
578
+ self._sock.close()
579
+
580
+ def __enter__(self) -> t.Self:
581
+ return self
582
+
583
+ def __exit__(
584
+ self,
585
+ exc_type: type[BaseException] | None,
586
+ exc_value: BaseException | None,
587
+ traceback: types.TracebackType | None
588
+ ) -> None:
589
+ self.close()
590
+
591
+ def send(self, msg: bytes) -> bytes:
592
+ length = uint32(len(msg)).to_blob()
593
+ self._sock.sendall(length + msg)
594
+ bufsize = uint32.from_blob(self._sock.recv(4))
595
+ resp = self._sock.recv(bufsize)
596
+ if resp[0] == ProtocolMsgNumbers.SSH_AGENT_FAILURE:
597
+ raise SshAgentFailure('agent: failure')
598
+ return resp
599
+
600
+ def remove_all(self) -> None:
601
+ self.send(
602
+ ProtocolMsgNumbers.SSH_AGENTC_REMOVE_ALL_IDENTITIES.to_blob()
603
+ )
604
+
605
+ def remove(self, public_key: CryptoPublicKey) -> None:
606
+ key_blob = PublicKeyMsg.from_public_key(public_key).to_blob()
607
+ self.send(
608
+ ProtocolMsgNumbers.SSH_AGENTC_REMOVE_IDENTITY.to_blob() +
609
+ uint32(len(key_blob)).to_blob() + key_blob
610
+ )
611
+
612
+ def add(
613
+ self,
614
+ private_key: CryptoPrivateKey,
615
+ comments: str | None = None,
616
+ lifetime: int | None = None,
617
+ confirm: bool | None = None,
618
+ ) -> None:
619
+ key_msg = PrivateKeyMsg.from_private_key(private_key)
620
+ key_msg.comments = unicode_string(comments or '')
621
+ if lifetime:
622
+ key_msg.constraints += constraints(
623
+ [ProtocolMsgNumbers.SSH_AGENT_CONSTRAIN_LIFETIME]
624
+ ).to_blob() + uint32(lifetime).to_blob()
625
+ if confirm:
626
+ key_msg.constraints += constraints(
627
+ [ProtocolMsgNumbers.SSH_AGENT_CONSTRAIN_CONFIRM]
628
+ ).to_blob()
629
+
630
+ if key_msg.constraints:
631
+ msg = ProtocolMsgNumbers.SSH_AGENTC_ADD_ID_CONSTRAINED.to_blob()
632
+ else:
633
+ msg = ProtocolMsgNumbers.SSH_AGENTC_ADD_IDENTITY.to_blob()
634
+ msg += key_msg.to_blob()
635
+ self.send(msg)
636
+
637
+ def list(self) -> KeyList:
638
+ req = ProtocolMsgNumbers.SSH_AGENTC_REQUEST_IDENTITIES.to_blob()
639
+ r = memoryview(bytearray(self.send(req)))
640
+ if r[0] != ProtocolMsgNumbers.SSH_AGENT_IDENTITIES_ANSWER:
641
+ raise SshAgentFailure(
642
+ 'agent: non-identities answer received for identities list'
643
+ )
644
+ return KeyList.from_blob(r[1:])
645
+
646
+ def __contains__(self, public_key: CryptoPublicKey) -> bool:
647
+ msg = PublicKeyMsg.from_public_key(public_key)
648
+ return msg in self.list().keys
649
+
650
+
651
+ @functools.cache
652
+ def _key_data_into_crypto_objects(key_data: bytes, passphrase: bytes | None) -> tuple[CryptoPrivateKey, CryptoPublicKey, str]:
653
+ private_key = serialization.ssh.load_ssh_private_key(key_data, passphrase)
654
+ public_key = private_key.public_key()
655
+ fingerprint = PublicKeyMsg.from_public_key(public_key).fingerprint
656
+
657
+ return private_key, public_key, fingerprint