Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package ansible-core for openSUSE:Factory 
checked in at 2026-07-14 13:51:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ansible-core (Old)
 and      /work/SRC/openSUSE:Factory/.ansible-core.new.1991 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ansible-core"

Tue Jul 14 13:51:32 2026 rev:62 rq:1365472 version:2.21.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/ansible-core/ansible-core.changes        
2026-06-19 17:12:22.691488324 +0200
+++ /work/SRC/openSUSE:Factory/.ansible-core.new.1991/ansible-core.changes      
2026-07-14 13:51:53.823034133 +0200
@@ -1,0 +2,18 @@
+Tue Jul 14 05:15:55 UTC 2026 - Johannes Kastl 
<[email protected]>
+
+- update to 2.21.2:
+  * Minor Changes
+    - ansible-test - Added a timeout callback that dumps thread
+      stacks when the test execution deadline defined by
+      ansible-test env --timeout is approaching.
+    - parallel fact gathering - the async wrapper now considers the
+      timeout when determining whether to kill the process running
+      the module. Previously, a 5 second sleep occurred twice
+      before checking if the job had remaining time.
+  * Bugfixes
+    - encrypt - fix bcrypt salt string formatting on musl libc by
+      ensuring it is always zero-padded to 2 digits (#87180).
+    - parallel fact gathering - fix hang caused by corrupt async
+      job files.
+
+-------------------------------------------------------------------

Old:
----
  ansible_core-2.21.1.tar.gz
  ansible_core-2.21.1.tar.gz.sha256

New:
----
  ansible_core-2.21.2.tar.gz
  ansible_core-2.21.2.tar.gz.sha256

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ ansible-core.spec ++++++
--- /var/tmp/diff_new_pack.5alxEK/_old  2026-07-14 13:51:55.827103426 +0200
+++ /var/tmp/diff_new_pack.5alxEK/_new  2026-07-14 13:51:55.831103564 +0200
@@ -43,7 +43,7 @@
 %endif
 
 Name:           ansible-core
-Version:        2.21.1
+Version:        2.21.2
 Release:        0
 Summary:        Radically simple IT automation
 License:        GPL-3.0-or-later

++++++ ansible_core-2.21.1.tar.gz -> ansible_core-2.21.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.21.1/PKG-INFO 
new/ansible_core-2.21.2/PKG-INFO
--- old/ansible_core-2.21.1/PKG-INFO    2026-06-18 21:33:01.000000000 +0200
+++ new/ansible_core-2.21.2/PKG-INFO    2026-07-13 21:37:14.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: ansible-core
-Version: 2.21.1
+Version: 2.21.2
 Summary: Radically simple IT automation
 Author: Ansible Project
 License-Expression: GPL-3.0-or-later
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.21.1/ansible_core.egg-info/PKG-INFO 
new/ansible_core-2.21.2/ansible_core.egg-info/PKG-INFO
--- old/ansible_core-2.21.1/ansible_core.egg-info/PKG-INFO      2026-06-18 
21:33:01.000000000 +0200
+++ new/ansible_core-2.21.2/ansible_core.egg-info/PKG-INFO      2026-07-13 
21:37:14.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: ansible-core
-Version: 2.21.1
+Version: 2.21.2
 Summary: Radically simple IT automation
 Author: Ansible Project
 License-Expression: GPL-3.0-or-later
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/ansible_core.egg-info/SOURCES.txt 
new/ansible_core-2.21.2/ansible_core.egg-info/SOURCES.txt
--- old/ansible_core-2.21.1/ansible_core.egg-info/SOURCES.txt   2026-06-18 
21:33:01.000000000 +0200
+++ new/ansible_core-2.21.2/ansible_core.egg-info/SOURCES.txt   2026-07-13 
21:37:14.000000000 +0200
@@ -1366,6 +1366,14 @@
 test/integration/targets/ansible-test-shell/expected-stdout.txt
 test/integration/targets/ansible-test-shell/runme.sh
 test/integration/targets/ansible-test-shell/ansible_collections/ns/col/.keep
+test/integration/targets/ansible-test-timeout/aliases
+test/integration/targets/ansible-test-timeout/runme.sh
+test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/noop/aliases
+test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/noop/runme.sh
+test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/pause/aliases
+test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/pause/tasks/main.yml
+test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/sleep/aliases
+test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/sleep/runme.sh
 test/integration/targets/ansible-test-units/aliases
 test/integration/targets/ansible-test-units/runme.sh
 test/integration/targets/ansible-test-units-assertions/aliases
@@ -4760,6 +4768,7 @@
 test/lib/ansible_test/_internal/provider/source/unsupported.py
 test/lib/ansible_test/_internal/provider/source/unversioned.py
 test/lib/ansible_test/_util/__init__.py
+test/lib/ansible_test/_util/controller/ansible_collections/ansible_test/_internal/plugins/callback/timeout.py
 
test/lib/ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.json
 test/lib/ansible_test/_util/controller/sanity/code-smell/action-plugin-docs.py
 test/lib/ansible_test/_util/controller/sanity/code-smell/changelog.json
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.21.1/changelogs/CHANGELOG-v2.21.rst 
new/ansible_core-2.21.2/changelogs/CHANGELOG-v2.21.rst
--- old/ansible_core-2.21.1/changelogs/CHANGELOG-v2.21.rst      2026-06-18 
21:33:01.000000000 +0200
+++ new/ansible_core-2.21.2/changelogs/CHANGELOG-v2.21.rst      2026-07-13 
21:37:14.000000000 +0200
@@ -4,6 +4,27 @@
 
 .. contents:: Topics
 
+v2.21.2
+=======
+
+Release Summary
+---------------
+
+| Release Date: 2026-07-13
+| `Porting Guide 
<https://docs.ansible.com/ansible-core/2.21/porting_guides/porting_guide_core_2.21.html>`__
+
+Minor Changes
+-------------
+
+- ansible-test - Added a timeout callback that dumps thread stacks when the 
test execution deadline defined by ``ansible-test env --timeout`` is 
approaching.
+- parallel fact gathering - the async wrapper now considers the timeout when 
determining whether to kill the process running the module. Previously, a 5 
second sleep occurred twice before checking if the job had remaining time.
+
+Bugfixes
+--------
+
+- encrypt - fix bcrypt salt string formatting on musl libc by ensuring it is 
always zero-padded to 2 digits 
(https://github.com/ansible/ansible/issues/87180).
+- parallel fact gathering - fix hang caused by corrupt async job files.
+
 v2.21.1
 =======
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.21.1/changelogs/changelog.yaml 
new/ansible_core-2.21.2/changelogs/changelog.yaml
--- old/ansible_core-2.21.1/changelogs/changelog.yaml   2026-06-18 
21:33:01.000000000 +0200
+++ new/ansible_core-2.21.2/changelogs/changelog.yaml   2026-07-13 
21:37:14.000000000 +0200
@@ -692,3 +692,38 @@
     - sort_obfuscation.yml
     - winrm-psrp-nolog.yml
     release_date: '2026-06-11'
+  2.21.2:
+    changes:
+      release_summary: '| Release Date: 2026-07-13
+
+        | `Porting Guide 
<https://docs.ansible.com/ansible-core/2.21/porting_guides/porting_guide_core_2.21.html>`__
+
+        '
+    codename: The Rain Song
+    fragments:
+    - 2.21.2_summary.yaml
+    release_date: '2026-07-13'
+  2.21.2rc1:
+    changes:
+      bugfixes:
+      - encrypt - fix bcrypt salt string formatting on musl libc by ensuring 
it is
+        always zero-padded to 2 digits 
(https://github.com/ansible/ansible/issues/87180).
+      - parallel fact gathering - fix hang caused by corrupt async job files.
+      minor_changes:
+      - ansible-test - Added a timeout callback that dumps thread stacks when 
the
+        test execution deadline defined by ``ansible-test env --timeout`` is 
approaching.
+      - parallel fact gathering - the async wrapper now considers the timeout 
when
+        determining whether to kill the process running the module. 
Previously, a
+        5 second sleep occurred twice before checking if the job had remaining 
time.
+      release_summary: '| Release Date: 2026-07-06
+
+        | `Porting Guide 
<https://docs.ansible.com/ansible-core/2.21/porting_guides/porting_guide_core_2.21.html>`__
+
+        '
+    codename: The Rain Song
+    fragments:
+    - 2.21.2rc1_summary.yaml
+    - 87180-crypt-fixes.yml
+    - ansible-test-timeout-callback.yml
+    - fix-short-timeout-async-wrapper.yml
+    release_date: '2026-07-06'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/lib/ansible/_internal/_encryption/_crypt.py 
new/ansible_core-2.21.2/lib/ansible/_internal/_encryption/_crypt.py
--- old/ansible_core-2.21.1/lib/ansible/_internal/_encryption/_crypt.py 
2026-06-18 21:33:01.000000000 +0200
+++ new/ansible_core-2.21.2/lib/ansible/_internal/_encryption/_crypt.py 
2026-07-13 21:37:14.000000000 +0200
@@ -12,7 +12,7 @@
 
 __all__ = ['CryptFacade']
 
-_FAILURE_TOKENS = frozenset({b'*0', b'*1'})
+_FAILURE_TOKENS = frozenset({b'*', b'*0', b'*1'})
 
 
 @dataclass(frozen=True)
@@ -93,10 +93,9 @@
 
             if self._use_crypt_r:
                 self._crypt_impl.argtypes = [ctypes.c_char_p, ctypes.c_char_p, 
ctypes.POINTER(self._CryptData)]
-                self._crypt_impl.restype = ctypes.c_char_p
             else:
                 self._crypt_impl.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
-                self._crypt_impl.restype = ctypes.c_char_p
+            self._crypt_impl.restype = ctypes.c_char_p
 
             # Try to load crypt_gensalt (available in libxcrypt)
             try:
@@ -133,10 +132,7 @@
             error_msg = os.strerror(errno)
             raise OSError(errno, f'crypt failed: {error_msg}')
 
-        if result is None:
-            raise ValueError('crypt failed: invalid salt or unsupported 
algorithm')
-
-        if result in _FAILURE_TOKENS:
+        if result is None or result in _FAILURE_TOKENS:
             raise ValueError('crypt failed: invalid salt or unsupported 
algorithm')
 
         return result
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/lib/ansible/module_utils/ansible_release.py 
new/ansible_core-2.21.2/lib/ansible/module_utils/ansible_release.py
--- old/ansible_core-2.21.1/lib/ansible/module_utils/ansible_release.py 
2026-06-18 21:33:01.000000000 +0200
+++ new/ansible_core-2.21.2/lib/ansible/module_utils/ansible_release.py 
2026-07-13 21:37:14.000000000 +0200
@@ -17,6 +17,6 @@
 
 from __future__ import annotations
 
-__version__ = '2.21.1'
+__version__ = '2.21.2'
 __author__ = 'Ansible, Inc.'
 __codename__ = "The Rain Song"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/lib/ansible/modules/async_wrapper.py 
new/ansible_core-2.21.2/lib/ansible/modules/async_wrapper.py
--- old/ansible_core-2.21.1/lib/ansible/modules/async_wrapper.py        
2026-06-18 21:33:01.000000000 +0200
+++ new/ansible_core-2.21.2/lib/ansible/modules/async_wrapper.py        
2026-07-13 21:37:14.000000000 +0200
@@ -291,24 +291,31 @@
                 os.setpgid(sub_pid, sub_pid)
 
                 notice("Start watching %s (%s)" % (sub_pid, remaining))
+
+                if remaining != 0 and step >= remaining:
+                    step = remaining / 2
+
                 time.sleep(step)
+
                 while os.waitpid(sub_pid, os.WNOHANG) == (0, 0):
-                    notice("%s still running (%s)" % (sub_pid, remaining))
-                    time.sleep(step)
                     remaining = remaining - step
+                    notice("%s still running (%s)" % (sub_pid, remaining))
                     if remaining <= 0:
-                        # ensure we leave response in poll location
-                        res = {'msg': 'Timeout exceeded', 'failed': True, 
'child_pid': sub_pid}
-                        jwrite(res)
-
                         # actually kill it
                         notice("Timeout reached, now killing %s" % (sub_pid))
                         os.killpg(sub_pid, signal.SIGKILL)
                         notice("Sent kill to group %s " % sub_pid)
                         time.sleep(1)
+
+                        # ensure we leave response in poll location
+                        res = {'msg': 'Timeout exceeded', 'failed': True, 
'child_pid': sub_pid}
+                        jwrite(res)
+
                         if not preserve_tmp:
                             shutil.rmtree(os.path.dirname(wrapped_module), 
True)
                         end(res)
+
+                    time.sleep(step)
                 notice("Done in kid B.")
                 if not preserve_tmp:
                     shutil.rmtree(os.path.dirname(wrapped_module), True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.21.1/lib/ansible/release.py 
new/ansible_core-2.21.2/lib/ansible/release.py
--- old/ansible_core-2.21.1/lib/ansible/release.py      2026-06-18 
21:33:01.000000000 +0200
+++ new/ansible_core-2.21.2/lib/ansible/release.py      2026-07-13 
21:37:14.000000000 +0200
@@ -17,6 +17,6 @@
 
 from __future__ import annotations
 
-__version__ = '2.21.1'
+__version__ = '2.21.2'
 __author__ = 'Ansible, Inc.'
 __codename__ = "The Rain Song"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.21.1/lib/ansible/utils/encrypt.py 
new/ansible_core-2.21.2/lib/ansible/utils/encrypt.py
--- old/ansible_core-2.21.1/lib/ansible/utils/encrypt.py        2026-06-18 
21:33:01.000000000 +0200
+++ new/ansible_core-2.21.2/lib/ansible/utils/encrypt.py        2026-07-13 
21:37:14.000000000 +0200
@@ -186,7 +186,8 @@
         saltstring = f'${ident}' if ident else ''
         if rounds:
             if self.algo_data.rounds_format == 'cost':
-                saltstring += f'${rounds}'
+                # musl libc requires a 2-digit bcrypt cost ($2b$05$, not 
$2b$5$).
+                saltstring += f'${rounds:02d}'
             else:
                 saltstring += f'$rounds={rounds}'
         saltstring += f'${salt}'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.21.1/pyproject.toml 
new/ansible_core-2.21.2/pyproject.toml
--- old/ansible_core-2.21.1/pyproject.toml      2026-06-18 21:33:01.000000000 
+0200
+++ new/ansible_core-2.21.2/pyproject.toml      2026-07-13 21:37:14.000000000 
+0200
@@ -1,5 +1,5 @@
 [build-system]
-requires = ["setuptools >= 77.0.3, <= 82.0.1"]  # lower bound to support 
license/license-files (PEP 639), upper bound for latest version tested at 
release
+requires = ["setuptools >= 77.0.3, <= 83.0.0"]  # lower bound to support 
license/license-files (PEP 639), upper bound for latest version tested at 
release
 build-backend = "setuptools.build_meta"
 
 [project]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/test/integration/targets/ansible-test-container/runme.py
 
new/ansible_core-2.21.2/test/integration/targets/ansible-test-container/runme.py
--- 
old/ansible_core-2.21.1/test/integration/targets/ansible-test-container/runme.py
    2026-06-18 21:33:01.000000000 +0200
+++ 
new/ansible_core-2.21.2/test/integration/targets/ansible-test-container/runme.py
    2026-07-13 21:37:14.000000000 +0200
@@ -1007,6 +1007,9 @@
         if cls.install_docker():
             packages.append('moby-engine')
 
+        if cls.install_docker() and os_release.id == 'fedora':
+            packages.append('runc')
+
         if os_release.id == 'rhel':
             # As of the release of RHEL 9.1, installing podman on RHEL 9.0 
results in a non-fatal error at install time:
             #
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/test/integration/targets/ansible-test-timeout/aliases 
new/ansible_core-2.21.2/test/integration/targets/ansible-test-timeout/aliases
--- 
old/ansible_core-2.21.1/test/integration/targets/ansible-test-timeout/aliases   
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible_core-2.21.2/test/integration/targets/ansible-test-timeout/aliases   
    2026-07-13 21:37:14.000000000 +0200
@@ -0,0 +1,4 @@
+shippable/posix/group3  # runs in the distro test containers
+shippable/generic/group1  # runs in the default test container
+context/controller
+needs/target/collection
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/noop/aliases
 
new/ansible_core-2.21.2/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/noop/aliases
--- 
old/ansible_core-2.21.1/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/noop/aliases
     1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible_core-2.21.2/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/noop/aliases
     2026-07-13 21:37:14.000000000 +0200
@@ -0,0 +1 @@
+context/controller
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/noop/runme.sh
 
new/ansible_core-2.21.2/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/noop/runme.sh
--- 
old/ansible_core-2.21.1/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/noop/runme.sh
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible_core-2.21.2/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/noop/runme.sh
    2026-07-13 21:37:14.000000000 +0200
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+
+set -eux
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/pause/aliases
 
new/ansible_core-2.21.2/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/pause/aliases
--- 
old/ansible_core-2.21.1/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/pause/aliases
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible_core-2.21.2/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/pause/aliases
    2026-07-13 21:37:14.000000000 +0200
@@ -0,0 +1,2 @@
+context/controller
+gather_facts/no
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/pause/tasks/main.yml
 
new/ansible_core-2.21.2/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/pause/tasks/main.yml
--- 
old/ansible_core-2.21.1/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/pause/tasks/main.yml
     1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible_core-2.21.2/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/pause/tasks/main.yml
     2026-07-13 21:37:14.000000000 +0200
@@ -0,0 +1,3 @@
+- name: Wait long enough for the timeout callback to fire
+  wait_for:
+    timeout: 30
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/sleep/aliases
 
new/ansible_core-2.21.2/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/sleep/aliases
--- 
old/ansible_core-2.21.1/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/sleep/aliases
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible_core-2.21.2/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/sleep/aliases
    2026-07-13 21:37:14.000000000 +0200
@@ -0,0 +1 @@
+context/controller
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/sleep/runme.sh
 
new/ansible_core-2.21.2/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/sleep/runme.sh
--- 
old/ansible_core-2.21.1/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/sleep/runme.sh
   1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible_core-2.21.2/test/integration/targets/ansible-test-timeout/ansible_collections/ns/col/tests/integration/targets/sleep/runme.sh
   2026-07-13 21:37:14.000000000 +0200
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+set -eux
+
+sleep 30
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/test/integration/targets/ansible-test-timeout/runme.sh 
new/ansible_core-2.21.2/test/integration/targets/ansible-test-timeout/runme.sh
--- 
old/ansible_core-2.21.1/test/integration/targets/ansible-test-timeout/runme.sh  
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible_core-2.21.2/test/integration/targets/ansible-test-timeout/runme.sh  
    2026-07-13 21:37:14.000000000 +0200
@@ -0,0 +1,64 @@
+#!/usr/bin/env bash
+# Test ansible-test timeout functionality and the timeout callback.
+
+source ../collection/setup.sh
+
+set -eux -o pipefail
+
+# Prime the venv so timeouts don't risk leaving a broken venv.
+ansible-test integration noop --venv --color --truncate 0
+
+echo "=== Test 1: ansible-test timeout already expired ==="
+ansible-test env --timeout 0.0001 2>&1 | tee test1-env.txt
+
+if ansible-test integration sleep --venv --color --truncate 0 2>&1 | tee 
test1.txt; then
+    echo "FAIL: expected ansible-test to fail due to expired timeout, but it 
passed."
+    exit 1
+fi
+
+grep -q "test timeout expired" test1.txt
+grep -q "timeout may be too short" test1-env.txt
+
+echo "=== Test 2: ansible-test timeout fires during a test ==="
+# Use the sleep target (a shell script) so ansible-playbook doesn't run
+# and the timeout callback doesn't intercept.
+ansible-test env --timeout 0.1
+
+if ansible-test integration sleep --venv --color --truncate 0 2>&1 | tee 
test2.txt; then
+    echo "FAIL: expected ansible-test to fail due to timeout, but it passed."
+    exit 1
+fi
+
+grep -q "time limit" test2.txt
+
+echo "=== Test 3: timeout callback with deadline already passed ==="
+# The timeout margin equals the timeout duration, so the callback
+# deadline is guaranteed to be in the past by the time it loads.
+# ansible-test's own timeout check passes since the deadline itself hasn't
+# expired yet at startup.
+ansible-test env --timeout 0.167 2>&1 | tee test3-env.txt
+
+if ansible-test integration pause --venv --color --truncate 0 2>&1 | tee 
test3.txt; then
+    echo "FAIL: expected ansible-test to fail due to timeout traceback, but it 
passed."
+    exit 1
+fi
+
+grep -q "Tests aborted by the timeout callback" test3.txt
+grep -q "deadline exceeded by" test3.txt
+grep -q "timeout may be too short" test3-env.txt && exit 1
+
+echo "=== Test 4: timeout callback fires while process is hung ==="
+# Use a longer timeout so the callback deadline is in the future when it
+# loads. The pause target keeps ansible-playbook alive long enough for the
+# timeout callback to fire.
+ansible-test env --timeout 0.25
+
+if ansible-test integration pause --venv --color --truncate 0 2>&1 | tee 
test4.txt; then
+    echo "FAIL: expected ansible-test to fail due to timeout traceback, but it 
passed."
+    exit 1
+fi
+
+grep -q "Tests aborted by the timeout callback" test4.txt
+grep -q "remaining" test4.txt
+
+echo PASS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/test/integration/targets/collection/setup.sh 
new/ansible_core-2.21.2/test/integration/targets/collection/setup.sh
--- old/ansible_core-2.21.1/test/integration/targets/collection/setup.sh        
2026-06-18 21:33:01.000000000 +0200
+++ new/ansible_core-2.21.2/test/integration/targets/collection/setup.sh        
2026-07-13 21:37:14.000000000 +0200
@@ -16,9 +16,6 @@
 # 4) Windows tests need access to the ansible.windows vendored collection.
 #    This script copies any of the existing collections in 
ANSIBLE_COLLECTIONS_PATH to the temporary directory.
 #
-# NOTE: This script is *NOT* compatible ansible-test's built-in collection 
injection feature,
-#       since it assumes that ANSIBLE_COLLECTIONS_PATH contains only a single 
path.
-
 set -eu -o pipefail
 
 export TEST_DIR
@@ -33,7 +30,13 @@
 cd "${WORK_DIR}/ansible_collections/ns/${COLLECTION_NAME:-col}"
 
 if [ "${ANSIBLE_COLLECTIONS_PATH:+set}" = "set" ]; then
-    cp -aL "${ANSIBLE_COLLECTIONS_PATH}"/ansible_collections/* 
"${WORK_DIR}/ansible_collections"
+    IFS=':' read -ra collections_paths <<< "${ANSIBLE_COLLECTIONS_PATH}"
+
+    for collections_path in "${collections_paths[@]}"; do
+        if [ -d "${collections_path}/ansible_collections" ]; then
+            cp -aL "${collections_path}"/ansible_collections/* 
"${WORK_DIR}/ansible_collections"
+        fi
+    done
 fi
 
 "${TEST_DIR}/../collection/update-ignore.py"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/test/integration/targets/gathering_facts/library/slow 
new/ansible_core-2.21.2/test/integration/targets/gathering_facts/library/slow
--- 
old/ansible_core-2.21.1/test/integration/targets/gathering_facts/library/slow   
    2026-06-18 21:33:01.000000000 +0200
+++ 
new/ansible_core-2.21.2/test/integration/targets/gathering_facts/library/slow   
    2026-07-13 21:37:14.000000000 +0200
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-sleep 10
+sleep 3
 
 echo '{
     "changed": false,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/test/integration/targets/gathering_facts/runme.sh 
new/ansible_core-2.21.2/test/integration/targets/gathering_facts/runme.sh
--- old/ansible_core-2.21.1/test/integration/targets/gathering_facts/runme.sh   
2026-06-18 21:33:01.000000000 +0200
+++ new/ansible_core-2.21.2/test/integration/targets/gathering_facts/runme.sh   
2026-07-13 21:37:14.000000000 +0200
@@ -15,7 +15,7 @@
 ansible-playbook test_prevent_injection.yml -i inventory -v "$@"
 
 # ensure fact merging is working properly
-ansible-playbook verify_merge_facts.yml -v "$@" -e 'ansible_facts_parallel: 
False'
+ansible-playbook verify_merge_facts.yml -v "$@" -e 
'ansible_facts_parallel=False'
 
 # ensure we dont clobber facts in loop
 ansible-playbook prevent_clobbering.yml -v "$@"
@@ -36,10 +36,10 @@
 ANSIBLE_FACTS_MODULES='ansible.legacy.slow' ansible -m gather_facts localhost 
--playbook-dir ./ "$@"
 
 # test that gather_facts will timeout parallel modules that dont support 
gather_timeout when using gather_Timeout
-ANSIBLE_FACTS_MODULES='ansible.legacy.slow' ansible -m gather_facts localhost 
--playbook-dir ./ -a 'gather_timeout=1 parallel=true' "$@" 2>&1 |grep 'Timeout 
exceeded'
+ANSIBLE_FACTS_MODULES='ansible.legacy.slow' ANSIBLE_TASK_TIMEOUT=5 ansible -m 
gather_facts localhost --playbook-dir ./ -a 'gather_timeout=1 parallel=true' 
"$@" 2>&1 |grep 'Timeout exceeded'
 
 # test that gather_facts parallel w/o timing out
-ANSIBLE_FACTS_MODULES='ansible.legacy.slow' ansible -m gather_facts localhost 
--playbook-dir ./ -a 'gather_timeout=30 parallel=true' "$@" 2>&1 |grep -v 
'Timeout exceeded'
+ANSIBLE_FACTS_MODULES='ansible.legacy.slow' ansible -m gather_facts localhost 
--playbook-dir ./ -a 'gather_timeout=10 parallel=true' "$@" 2>&1 |grep 'Timeout 
exceeded' && exit 1
 
 
 # test parallelism
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/test/lib/ansible_test/_internal/commands/env/__init__.py
 
new/ansible_core-2.21.2/test/lib/ansible_test/_internal/commands/env/__init__.py
--- 
old/ansible_core-2.21.1/test/lib/ansible_test/_internal/commands/env/__init__.py
    2026-06-18 21:33:01.000000000 +0200
+++ 
new/ansible_core-2.21.2/test/lib/ansible_test/_internal/commands/env/__init__.py
    2026-07-13 21:37:14.000000000 +0200
@@ -36,6 +36,7 @@
 )
 
 from ...constants import (
+    TIMEOUT_MARGIN_SECONDS,
     TIMEOUT_PATH,
 )
 
@@ -137,6 +138,9 @@
 
     if timeout:
         display.info(f'Setting a {timeout.duration} minute test timeout which 
will end at: {timeout.deadline}', verbosity=1)
+
+        if timeout.duration * 60 <= TIMEOUT_MARGIN_SECONDS:
+            display.warning(f'The {timeout.duration} minute timeout may be too 
short for the faulthandler callback to provide useful diagnostics.')
     else:
         display.info('Clearing existing test timeout.', verbosity=1)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/test/lib/ansible_test/_internal/commands/integration/__init__.py
 
new/ansible_core-2.21.2/test/lib/ansible_test/_internal/commands/integration/__init__.py
--- 
old/ansible_core-2.21.1/test/lib/ansible_test/_internal/commands/integration/__init__.py
    2026-06-18 21:33:01.000000000 +0200
+++ 
new/ansible_core-2.21.2/test/lib/ansible_test/_internal/commands/integration/__init__.py
    2026-07-13 21:37:14.000000000 +0200
@@ -8,6 +8,7 @@
 import datetime
 import json
 import os
+import pathlib
 import re
 import shutil
 import tempfile
@@ -57,7 +58,12 @@
     read_text_file,
 )
 
+from ...constants import (
+    TIMEOUT_MARGIN_SECONDS,
+)
+
 from ...util import (
+    ANSIBLE_TEST_CONTROLLER_ROOT,
     ApplicationError,
     display,
     get_ansible_version,
@@ -133,6 +139,10 @@
     CoverageManager,
 )
 
+from ...timeout import (
+    get_timeout,
+)
+
 
 def generate_dependency_map(integration_targets: list[IntegrationTarget]) -> 
dict[str, set[IntegrationTarget]]:
     """Analyze the given list of integration test targets and return a 
dictionary expressing target names and the targets on which they depend."""
@@ -306,7 +316,11 @@
         ansible_config = ansible_config_src
         vars_file = os.path.join(data_context().content.root, 
data_context().content.integration_vars_path)
 
-        yield IntegrationEnvironment(data_context().content.root, 
integration_dir, targets_dir, inventory_path, ansible_config, vars_file)
+        test_env = IntegrationEnvironment(data_context().content.root, 
integration_dir, targets_dir, inventory_path, ansible_config, vars_file)
+
+        with test_env.run():
+            yield test_env
+
         return
 
     # When testing a collection, the temporary directory must reside within 
the collection.
@@ -385,7 +399,10 @@
                 make_dirs(os.path.dirname(file_dst))
                 shutil.copy2(file_src, file_dst)
 
-        yield IntegrationEnvironment(temp_dir, integration_dir, targets_dir, 
inventory_path, ansible_config, vars_file, collection_roots)
+        test_env = IntegrationEnvironment(temp_dir, integration_dir, 
targets_dir, inventory_path, ansible_config, vars_file, collection_roots)
+
+        with test_env.run():
+            yield test_env
     finally:
         if not args.explain:
             remove_tree(temp_dir)
@@ -850,6 +867,11 @@
 
     callback_plugins = ['junit'] + (env_config.callback_plugins or [] if 
env_config else [])
 
+    timeout = get_timeout()
+
+    if timeout:
+        callback_plugins.append('ansible_test._internal.timeout')
+
     integration = dict(
         JUNIT_OUTPUT_DIR=ResultType.JUNIT.path,
         JUNIT_TASK_RELATIVE_PATH=test_env.test_dir,
@@ -862,6 +884,16 @@
         INVENTORY_PATH=os.path.abspath(inventory_path),
     )
 
+    if timeout:
+        collections_path = env.get('ANSIBLE_COLLECTIONS_PATH', '')
+        collections_path = 
f'{ANSIBLE_TEST_CONTROLLER_ROOT}:{collections_path}' if collections_path else 
ANSIBLE_TEST_CONTROLLER_ROOT
+
+        integration.update(
+            ANSIBLE_COLLECTIONS_PATH=collections_path,
+            ANSIBLE_TEST_TIMEOUT_DEADLINE=str(timeout.deadline.timestamp() - 
TIMEOUT_MARGIN_SECONDS),
+            ANSIBLE_TEST_TIMEOUT_DIR=str(test_env.timeout_dir),
+        )
+
     if args.debug_strategy:
         env.update(ANSIBLE_STRATEGY='debug')
 
@@ -892,6 +924,44 @@
     vars_file: str
     collection_roots: list[str] = dataclasses.field(default_factory=list)
 
+    @property
+    def timeout_dir(self) -> pathlib.Path:
+        """Return the path for timeout dump files."""
+        return pathlib.Path(self.test_dir) / 'timeout'
+
+    @contextlib.contextmanager
+    def run(self) -> c.Iterator[None]:
+        """Context manager that checks for timeout dumps after the test 
runs."""
+        try:
+            yield
+        finally:
+            self.check_timeout_dumps()
+
+    def check_timeout_dumps(self) -> None:
+        """Check for timeout dump files and raise an error if any contain 
tracebacks."""
+        if not (timeout := get_timeout()):
+            return
+
+        if not self.timeout_dir.is_dir():
+            return
+
+        found = False
+
+        for dump_file in sorted(self.timeout_dir.iterdir()):
+            lines = dump_file.read_text().splitlines()
+
+            if len(lines) <= 2:  # first line is the command, second is the 
timeout status, traceback, if any, follows
+                continue
+
+            found = True
+            display.error(f'Timeout traceback detected ({dump_file.name}):\n' 
+ '\n'.join(lines))
+
+        if found:
+            raise ApplicationError(
+                f'Tests aborted by the timeout callback after approaching the 
{timeout.duration} minute time limit.'
+                ' See traceback(s) above for process state.'
+            )
+
     def update_environment(self, env: dict[str, str]) -> None:
         """Update the given environment dictionary with the variables 
necessary for this integration environment."""
         collections_path = value.split(':') if (value := 
env.get('ANSIBLE_COLLECTIONS_PATH')) else []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/test/lib/ansible_test/_internal/constants.py 
new/ansible_core-2.21.2/test/lib/ansible_test/_internal/constants.py
--- old/ansible_core-2.21.1/test/lib/ansible_test/_internal/constants.py        
2026-06-18 21:33:01.000000000 +0200
+++ new/ansible_core-2.21.2/test/lib/ansible_test/_internal/constants.py        
2026-07-13 21:37:14.000000000 +0200
@@ -15,6 +15,7 @@
 
 # File used to track the ansible-test test execution timeout.
 TIMEOUT_PATH = '.ansible-test-timeout.json'
+TIMEOUT_MARGIN_SECONDS = 10
 
 CONTROLLER_MIN_PYTHON_VERSION = CONTROLLER_PYTHON_VERSIONS[0]
 SUPPORTED_PYTHON_VERSIONS = REMOTE_ONLY_PYTHON_VERSIONS + 
CONTROLLER_PYTHON_VERSIONS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/test/lib/ansible_test/_internal/timeout.py 
new/ansible_core-2.21.2/test/lib/ansible_test/_internal/timeout.py
--- old/ansible_core-2.21.1/test/lib/ansible_test/_internal/timeout.py  
2026-06-18 21:33:01.000000000 +0200
+++ new/ansible_core-2.21.2/test/lib/ansible_test/_internal/timeout.py  
2026-07-13 21:37:14.000000000 +0200
@@ -20,6 +20,7 @@
 )
 
 from .util import (
+    cache,
     display,
     TimeoutExpiredError,
 )
@@ -81,6 +82,7 @@
         )
 
 
+@cache
 def get_timeout() -> TimeoutDetail | None:
     """Return details about the currently set timeout, if any, otherwise 
return None."""
     try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/test/lib/ansible_test/_util/controller/ansible_collections/ansible_test/_internal/plugins/callback/timeout.py
 
new/ansible_core-2.21.2/test/lib/ansible_test/_util/controller/ansible_collections/ansible_test/_internal/plugins/callback/timeout.py
--- 
old/ansible_core-2.21.1/test/lib/ansible_test/_util/controller/ansible_collections/ansible_test/_internal/plugins/callback/timeout.py
       1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible_core-2.21.2/test/lib/ansible_test/_util/controller/ansible_collections/ansible_test/_internal/plugins/callback/timeout.py
       2026-07-13 21:37:14.000000000 +0200
@@ -0,0 +1,73 @@
+"""Ansible callback plugin to enforce an execution deadline using 
faulthandler."""
+# GNU General Public License v3.0+ (see COPYING or 
https://www.gnu.org/licenses/gpl-3.0.txt)
+
+from __future__ import annotations
+
+import datetime
+import faulthandler
+import os
+import pathlib
+import shlex
+import sys
+
+from ansible.plugins.callback import CallbackBase
+
+DOCUMENTATION = """
+    name: timeout
+    type: aggregate
+    short_description: Dump thread stacks when an execution deadline is 
reached.
+    description:
+      - Enforces an execution deadline by dumping all thread stacks to a file
+        and terminating the process when the deadline expires.
+      - Intended for use by ansible-test only. Do not enable manually.
+    options:
+      deadline:
+        description: Execution deadline as a UTC epoch timestamp.
+        env:
+          - name: ANSIBLE_TEST_TIMEOUT_DEADLINE
+      dump_dir:
+        description: Directory for timeout dump files.
+        env:
+          - name: ANSIBLE_TEST_TIMEOUT_DIR
+"""
+
+
+class CallbackModule(CallbackBase):
+    """Dump thread stacks and exit when an execution deadline is reached."""
+
+    CALLBACK_VERSION = 2.0
+    CALLBACK_TYPE = 'aggregate'
+    CALLBACK_NAME = 'timeout'
+    CALLBACK_NEEDS_ENABLED = True
+
+    def __init__(self):
+        super().__init__()
+
+        deadline_str = os.environ.get('ANSIBLE_TEST_TIMEOUT_DEADLINE')
+        dump_dir = os.environ.get('ANSIBLE_TEST_TIMEOUT_DIR')
+
+        if not deadline_str or not dump_dir:
+            return
+
+        deadline = datetime.datetime.fromtimestamp(float(deadline_str), 
tz=datetime.timezone.utc)
+        now = datetime.datetime.now(datetime.timezone.utc)
+        remaining = deadline - now
+
+        dump_dir_path = pathlib.Path(dump_dir)
+        dump_dir_path.mkdir(parents=True, exist_ok=True)
+
+        dump_path = dump_dir_path / 
f'timeout-{now.isoformat()}-{os.getpid()}.txt'
+
+        self._dump_file = dump_path.open('w')
+        self._dump_file.write(f'Command: {shlex.join(sys.argv).replace("\n", " 
")}\n')
+        self._dump_file.flush()
+
+        if remaining > datetime.timedelta():
+            self._dump_file.write(f'Timeout: {remaining} remaining\n')
+            self._dump_file.flush()
+            faulthandler.dump_traceback_later(remaining.total_seconds(), 
file=self._dump_file, exit=True)
+        else:
+            self._dump_file.write(f'Timeout: deadline exceeded by 
{-remaining}\n')
+            self._dump_file.flush()
+            faulthandler.dump_traceback(file=self._dump_file)
+            sys.exit(1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.21.1/test/units/_internal/_encryption/test_crypt.py 
new/ansible_core-2.21.2/test/units/_internal/_encryption/test_crypt.py
--- old/ansible_core-2.21.1/test/units/_internal/_encryption/test_crypt.py      
2026-06-18 21:33:01.000000000 +0200
+++ new/ansible_core-2.21.2/test/units/_internal/_encryption/test_crypt.py      
2026-07-13 21:37:14.000000000 +0200
@@ -82,7 +82,7 @@
 
     def test_crypt_fail_errno(self, mocker: MockerFixture) -> None:
         """Test crypt() setting failure errno raises OSError."""
-        mocker.patch('ctypes.get_errno', return_value=errno.EBADFD)
+        mocker.patch('ctypes.get_errno', return_value=errno.EBADF)
         crypt_facade = CryptFacade()
 
         with pytest.raises(OSError, match=r'crypt failed:'):
@@ -96,10 +96,11 @@
         with pytest.raises(ValueError, match=r'crypt failed: invalid salt or 
unsupported algorithm'):
             crypt_facade.crypt(b"test", b"123")
 
-    def test_crypt_result_failure(self, mocker: MockerFixture) -> None:
+    @pytest.mark.parametrize('failure_token', sorted(list(_FAILURE_TOKENS)))
+    def test_crypt_result_failure(self, mocker: MockerFixture, failure_token: 
bytes) -> None:
         """Test crypt() implementation returning failure token raises 
ValueError."""
         crypt_facade = CryptFacade()
-        mocker.patch.object(crypt_facade, '_crypt_impl', 
return_value=list(_FAILURE_TOKENS)[0])
+        mocker.patch.object(crypt_facade, '_crypt_impl', 
return_value=failure_token)
 
         with pytest.raises(ValueError, match=r'crypt failed: invalid salt or 
unsupported algorithm'):
             crypt_facade.crypt(b"test", b"123")
@@ -124,7 +125,7 @@
 
     def test_crypt_gensalt_fail_errno(self, mocker: MockerFixture) -> None:
         """Test crypt_gensalt() setting failure errno raises OSError."""
-        mocker.patch('ctypes.get_errno', return_value=errno.EBADFD)
+        mocker.patch('ctypes.get_errno', return_value=errno.EBADF)
         crypt_facade = CryptFacade()
 
         with pytest.raises(OSError, match=r'crypt_gensalt failed:'):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.21.1/test/units/utils/test_encrypt.py 
new/ansible_core-2.21.2/test/units/utils/test_encrypt.py
--- old/ansible_core-2.21.1/test/units/utils/test_encrypt.py    2026-06-18 
21:33:01.000000000 +0200
+++ new/ansible_core-2.21.2/test/units/utils/test_encrypt.py    2026-07-13 
21:37:14.000000000 +0200
@@ -294,6 +294,16 @@
         with pytest.raises(AnsibleError, match=r"crypt does not support 
'sha256_crypt' algorithm"):
             crypt_hash.hash("123", salt="12345678")
 
+    def test_build_saltstring_bcrypt_cost_padding(self, mocker: MockerFixture) 
-> None:
+        """musl libc requires a 2-digit bcrypt cost in the salt string."""
+        mocker.patch('ansible.utils.encrypt.HAS_CRYPT', True)
+        
mocker.patch('ansible._internal._encryption._crypt.CryptFacade.has_crypt_gensalt',
 False)
+
+        crypt_hash = encrypt.CryptHash("bcrypt")
+        saltstring = crypt_hash._build_saltstring('2b', 5, 
'1234567890123456789012', None)
+
+        assert saltstring == '$2b$05$1234567890123456789012'
+
 
 class TestPasslibHash:
     """

++++++ ansible_core-2.21.1.tar.gz.sha256 -> ansible_core-2.21.2.tar.gz.sha256 
++++++
--- /work/SRC/openSUSE:Factory/ansible-core/ansible_core-2.21.1.tar.gz.sha256   
2026-06-19 17:12:22.795491874 +0200
+++ 
/work/SRC/openSUSE:Factory/.ansible-core.new.1991/ansible_core-2.21.2.tar.gz.sha256
 2026-07-14 13:51:54.043041740 +0200
@@ -1 +1 @@
-a5536ece95be84de15212b3644cdbbe9cbd9efd62e4e8a544cd6b0b27a083039  
ansible_core-2.21.1.tar.gz
+c6139e662eda1bfb5af16029f12afa5edfc7f95f8cd44281b1bdb434a6d9dc70  
ansible_core-2.21.2.tar.gz

Reply via email to