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 2024-12-05 17:08:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ansible-core (Old)
 and      /work/SRC/openSUSE:Factory/.ansible-core.new.28523 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ansible-core"

Thu Dec  5 17:08:32 2024 rev:37 rq:1228282 version:2.18.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/ansible-core/ansible-core.changes        
2024-12-02 16:58:56.708724839 +0100
+++ /work/SRC/openSUSE:Factory/.ansible-core.new.28523/ansible-core.changes     
2024-12-05 17:10:06.049261770 +0100
@@ -1,0 +2,27 @@
+Tue Dec  3 05:53:19 UTC 2024 - Johannes Kastl 
<opensuse_buildserv...@ojkastl.de>
+
+- update to 2.18.1:
+  * Minor Changes
+    - ansible-test - When detection of the current container
+      network fails, a warning is now issued and execution
+      continues. This simplifies usage in cases where the current
+      container cannot be inspected, such as when running in GitHub
+      Codespaces.
+  * Security Fixes
+    - Templating will not prefer AnsibleUnsafe when a variable is
+      referenced via hostvars - CVE-2024-11079
+  * Bugfixes
+    - Fix returning 'unreachable' for the overall task result. This
+      prevents false positives when a looped task has unignored
+      unreachable items (#84019).
+    - ansible-test - Fix traceback that occurs after an interactive
+      command fails.
+    - dnf5 - fix installing a package using state=latest when a
+      binary of the same name as the package is already installed
+      (#84259)
+    - dnf5 - matching on a binary can be achieved only by
+      specifying a full path (#84334)
+    - runas become - Fix up become logic to still get the SYSTEM
+      token with the most privileges when running as SYSTEM.
+
+-------------------------------------------------------------------

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

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

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

Other differences:
------------------
++++++ ansible-core.spec ++++++
--- /var/tmp/diff_new_pack.4zM3mT/_old  2024-12-05 17:10:06.925298456 +0100
+++ /var/tmp/diff_new_pack.4zM3mT/_new  2024-12-05 17:10:06.925298456 +0100
@@ -43,7 +43,7 @@
 %endif
 
 Name:           ansible-core
-Version:        2.18.0
+Version:        2.18.1
 Release:        0
 Summary:        Radically simple IT automation
 License:        GPL-3.0-or-later

++++++ ansible_core-2.18.0.tar.gz -> ansible_core-2.18.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.18.0/PKG-INFO 
new/ansible_core-2.18.1/PKG-INFO
--- old/ansible_core-2.18.0/PKG-INFO    2024-11-04 19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/PKG-INFO    2024-12-02 18:46:46.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: ansible-core
-Version: 2.18.0
+Version: 2.18.1
 Summary: Radically simple IT automation
 Author: Ansible Project
 Project-URL: Homepage, https://ansible.com/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.18.0/ansible_core.egg-info/PKG-INFO 
new/ansible_core-2.18.1/ansible_core.egg-info/PKG-INFO
--- old/ansible_core-2.18.0/ansible_core.egg-info/PKG-INFO      2024-11-04 
19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/ansible_core.egg-info/PKG-INFO      2024-12-02 
18:46:46.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: ansible-core
-Version: 2.18.0
+Version: 2.18.1
 Summary: Radically simple IT automation
 Author: Ansible Project
 Project-URL: Homepage, https://ansible.com/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.18.0/ansible_core.egg-info/SOURCES.txt 
new/ansible_core-2.18.1/ansible_core.egg-info/SOURCES.txt
--- old/ansible_core-2.18.0/ansible_core.egg-info/SOURCES.txt   2024-11-04 
19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/ansible_core.egg-info/SOURCES.txt   2024-12-02 
18:46:46.000000000 +0100
@@ -2216,6 +2216,7 @@
 test/integration/targets/ignore_unreachable/inventory
 test/integration/targets/ignore_unreachable/runme.sh
 test/integration/targets/ignore_unreachable/test_base_cannot_connect.yml
+test/integration/targets/ignore_unreachable/test_base_loop_cannot_connect.yml
 test/integration/targets/ignore_unreachable/test_cannot_connect.yml
 test/integration/targets/ignore_unreachable/test_with_bad_plugins.yml
 test/integration/targets/ignore_unreachable/fake_connectors/bad_exec.py
@@ -3594,6 +3595,7 @@
 test/integration/targets/template/badnull3.cfg
 test/integration/targets/template/corner_cases.yml
 test/integration/targets/template/custom_template.yml
+test/integration/targets/template/cve-2024-11079.yml
 test/integration/targets/template/filter_plugins.yml
 test/integration/targets/template/in_template_overrides.j2
 test/integration/targets/template/lazy_eval.yml
@@ -4442,6 +4444,8 @@
 test/units/ansible_test/__init__.py
 test/units/ansible_test/conftest.py
 test/units/ansible_test/test_diff.py
+test/units/ansible_test/_internal/__init__.py
+test/units/ansible_test/_internal/test_util.py
 test/units/ansible_test/ci/__init__.py
 test/units/ansible_test/ci/test_azp.py
 test/units/ansible_test/ci/util.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.18.0/changelogs/CHANGELOG-v2.18.rst 
new/ansible_core-2.18.1/changelogs/CHANGELOG-v2.18.rst
--- old/ansible_core-2.18.0/changelogs/CHANGELOG-v2.18.rst      2024-11-04 
19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/changelogs/CHANGELOG-v2.18.rst      2024-12-02 
18:46:46.000000000 +0100
@@ -4,6 +4,34 @@
 
 .. contents:: Topics
 
+v2.18.1
+=======
+
+Release Summary
+---------------
+
+| Release Date: 2024-12-02
+| `Porting Guide 
<https://docs.ansible.com/ansible-core/2.18/porting_guides/porting_guide_core_2.18.html>`__
+
+Minor Changes
+-------------
+
+- ansible-test - When detection of the current container network fails, a 
warning is now issued and execution continues. This simplifies usage in cases 
where the current container cannot be inspected, such as when running in GitHub 
Codespaces.
+
+Security Fixes
+--------------
+
+- Templating will not prefer AnsibleUnsafe when a variable is referenced via 
hostvars - CVE-2024-11079
+
+Bugfixes
+--------
+
+- Fix returning 'unreachable' for the overall task result. This prevents false 
positives when a looped task has unignored unreachable items 
(https://github.com/ansible/ansible/issues/84019).
+- ansible-test - Fix traceback that occurs after an interactive command fails.
+- dnf5 - fix installing a package using ``state=latest`` when a binary of the 
same name as the package is already installed 
(https://github.com/ansible/ansible/issues/84259)
+- dnf5 - matching on a binary can be achieved only by specifying a full path 
(https://github.com/ansible/ansible/issues/84334)
+- runas become - Fix up become logic to still get the SYSTEM token with the 
most privileges when running as SYSTEM.
+
 v2.18.0
 =======
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.18.0/changelogs/changelog.yaml 
new/ansible_core-2.18.1/changelogs/changelog.yaml
--- old/ansible_core-2.18.0/changelogs/changelog.yaml   2024-11-04 
19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/changelogs/changelog.yaml   2024-12-02 
18:46:46.000000000 +0100
@@ -612,3 +612,50 @@
     - cve-2024-8775.yml
     - user_ssh_fix.yml
     release_date: '2024-10-29'
+  2.18.1:
+    changes:
+      release_summary: '| Release Date: 2024-12-02
+
+        | `Porting Guide 
<https://docs.ansible.com/ansible-core/2.18/porting_guides/porting_guide_core_2.18.html>`__
+
+        '
+    codename: Fool in the Rain
+    fragments:
+    - 2.18.1_summary.yaml
+    release_date: '2024-12-02'
+  2.18.1rc1:
+    changes:
+      bugfixes:
+      - Fix returning 'unreachable' for the overall task result. This prevents 
false
+        positives when a looped task has unignored unreachable items 
(https://github.com/ansible/ansible/issues/84019).
+      - ansible-test - Fix traceback that occurs after an interactive command 
fails.
+      - dnf5 - fix installing a package using ``state=latest`` when a binary 
of the
+        same name as the package is already installed 
(https://github.com/ansible/ansible/issues/84259)
+      - dnf5 - matching on a binary can be achieved only by specifying a full 
path
+        (https://github.com/ansible/ansible/issues/84334)
+      - runas become - Fix up become logic to still get the SYSTEM token with 
the
+        most privileges when running as SYSTEM.
+      minor_changes:
+      - ansible-test - When detection of the current container network fails, 
a warning
+        is now issued and execution continues. This simplifies usage in cases 
where
+        the current container cannot be inspected, such as when running in 
GitHub
+        Codespaces.
+      release_summary: '| Release Date: 2024-11-25
+
+        | `Porting Guide 
<https://docs.ansible.com/ansible-core/2.18/porting_guides/porting_guide_core_2.18.html>`__
+
+        '
+      security_fixes:
+      - Templating will not prefer AnsibleUnsafe when a variable is referenced 
via
+        hostvars - CVE-2024-11079
+    codename: Fool in the Rain
+    fragments:
+    - 2.18.1rc1_summary.yaml
+    - 84019-ignore_unreachable-loop.yml
+    - 84259-dnf5-latest-fix.yml
+    - 84334-dnf5-consolidate-settings.yml
+    - ansible-test-fix-command-traceback.yml
+    - ansible-test-network-detection.yml
+    - become-runas-system-deux.yml
+    - unsafe_hostvars_fix.yml
+    release_date: '2024-11-25'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.18.0/lib/ansible/executor/task_executor.py 
new/ansible_core-2.18.1/lib/ansible/executor/task_executor.py
--- old/ansible_core-2.18.0/lib/ansible/executor/task_executor.py       
2024-11-04 19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/lib/ansible/executor/task_executor.py       
2024-12-02 18:46:46.000000000 +0100
@@ -150,6 +150,7 @@
                         if 'unreachable' in item and item['unreachable']:
                             item_ignore_unreachable = 
item.pop('_ansible_ignore_unreachable')
                             if not res.get('unreachable'):
+                                res['unreachable'] = True
                                 self._task.ignore_unreachable = 
item_ignore_unreachable
                             elif self._task.ignore_unreachable and not 
item_ignore_unreachable:
                                 self._task.ignore_unreachable = 
item_ignore_unreachable
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.18.0/lib/ansible/module_utils/ansible_release.py 
new/ansible_core-2.18.1/lib/ansible/module_utils/ansible_release.py
--- old/ansible_core-2.18.0/lib/ansible/module_utils/ansible_release.py 
2024-11-04 19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/lib/ansible/module_utils/ansible_release.py 
2024-12-02 18:46:46.000000000 +0100
@@ -17,6 +17,6 @@
 
 from __future__ import annotations
 
-__version__ = '2.18.0'
+__version__ = '2.18.1'
 __author__ = 'Ansible, Inc.'
 __codename__ = "Fool in the Rain"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.18.0/lib/ansible/module_utils/csharp/Ansible.AccessToken.cs 
new/ansible_core-2.18.1/lib/ansible/module_utils/csharp/Ansible.AccessToken.cs
--- 
old/ansible_core-2.18.0/lib/ansible/module_utils/csharp/Ansible.AccessToken.cs  
    2024-11-04 19:35:45.000000000 +0100
+++ 
new/ansible_core-2.18.1/lib/ansible/module_utils/csharp/Ansible.AccessToken.cs  
    2024-12-02 18:46:46.000000000 +0100
@@ -339,19 +339,47 @@
         public static IEnumerable<SafeNativeHandle> 
EnumerateUserTokens(SecurityIdentifier sid,
             TokenAccessLevels access = TokenAccessLevels.Query)
         {
+            return EnumerateUserTokens(sid, access, (p, h) => true);
+        }
+
+        public static IEnumerable<SafeNativeHandle> EnumerateUserTokens(
+            SecurityIdentifier sid,
+            TokenAccessLevels access,
+            Func<System.Diagnostics.Process, SafeNativeHandle, bool> 
processFilter)
+        {
+            // We always need the Query access level so we can query the 
TokenUser
+            access |= TokenAccessLevels.Query;
+
             foreach (System.Diagnostics.Process process in 
System.Diagnostics.Process.GetProcesses())
             {
-                // We always need the Query access level so we can query the 
TokenUser
                 using (process)
-                using (SafeNativeHandle hToken = TryOpenAccessToken(process, 
access | TokenAccessLevels.Query))
+                using (SafeNativeHandle processHandle = 
NativeMethods.OpenProcess(ProcessAccessFlags.QueryInformation, false, 
(UInt32)process.Id))
                 {
-                    if (hToken == null)
+                    if (processHandle.IsInvalid)
+                    {
                         continue;
+                    }
 
-                    if (!sid.Equals(GetTokenUser(hToken)))
+                    if (!processFilter(process, processHandle))
+                    {
                         continue;
+                    }
+
+                    SafeNativeHandle accessToken;
+                    if (!NativeMethods.OpenProcessToken(processHandle, access, 
out accessToken))
+                    {
+                        continue;
+                    }
+
+                    using (accessToken)
+                    {
+                        if (!sid.Equals(GetTokenUser(accessToken)))
+                        {
+                            continue;
+                        }
 
-                    yield return hToken;
+                        yield return accessToken;
+                    }
                 }
             }
         }
@@ -440,18 +468,5 @@
             for (int i = 0; i < array.Length; i++, ptrOffset = 
IntPtr.Add(ptrOffset, Marshal.SizeOf(typeof(T))))
                 array[i] = (T)Marshal.PtrToStructure(ptrOffset, typeof(T));
         }
-
-        private static SafeNativeHandle 
TryOpenAccessToken(System.Diagnostics.Process process, TokenAccessLevels access)
-        {
-            try
-            {
-                using (SafeNativeHandle hProcess = OpenProcess(process.Id, 
ProcessAccessFlags.QueryInformation, false))
-                    return OpenProcessToken(hProcess, access);
-            }
-            catch (Win32Exception)
-            {
-                return null;
-            }
-        }
     }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.18.0/lib/ansible/module_utils/csharp/Ansible.Become.cs 
new/ansible_core-2.18.1/lib/ansible/module_utils/csharp/Ansible.Become.cs
--- old/ansible_core-2.18.0/lib/ansible/module_utils/csharp/Ansible.Become.cs   
2024-11-04 19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/lib/ansible/module_utils/csharp/Ansible.Become.cs   
2024-12-02 18:46:46.000000000 +0100
@@ -93,10 +93,21 @@
             CachedRemoteInteractive,
             CachedUnlock
         }
+
+        [Flags]
+        public enum ProcessChildProcessPolicyFlags
+        {
+            None = 0x0,
+            NoChildProcessCreation = 0x1,
+            AuditNoChildProcessCreation = 0x2,
+            AllowSecureProcessCreation = 0x4,
+        }
     }
 
     internal class NativeMethods
     {
+        public const int ProcessChildProcessPolicy = 13;
+
         [DllImport("advapi32.dll", SetLastError = true)]
         public static extern bool AllocateLocallyUniqueId(
             out Luid Luid);
@@ -116,6 +127,13 @@
         [DllImport("kernel32.dll")]
         public static extern UInt32 GetCurrentThreadId();
 
+        [DllImport("kernel32.dll", SetLastError = true)]
+        public static extern bool GetProcessMitigationPolicy(
+            SafeNativeHandle hProcess,
+            int MitigationPolicy,
+            ref NativeHelpers.ProcessChildProcessPolicyFlags lpBuffer,
+            IntPtr dwLength);
+
         [DllImport("user32.dll", SetLastError = true)]
         public static extern NoopSafeHandle GetProcessWindowStation();
 
@@ -217,6 +235,7 @@
         };
         private static int WINDOWS_STATION_ALL_ACCESS = 0x000F037F;
         private static int DESKTOP_RIGHTS_ALL_ACCESS = 0x000F01FF;
+        private static bool _getProcessMitigationPolicySupported = true;
 
         public static Result CreateProcessAsUser(string username, string 
password, string command)
         {
@@ -333,12 +352,13 @@
                 // Grant access to the current Windows Station and Desktop to 
the become user
                 GrantAccessToWindowStationAndDesktop(account);
 
-                // Try and impersonate a SYSTEM token. We need the 
SeTcbPrivilege for
-                //  - LogonUser for a service SID
-                //  - S4U logon
-                //  - Token elevation
+                // Try and impersonate a SYSTEM token, we need a SYSTEM token 
to either become a well known service
+                // account or have administrative rights on the become access 
token.
+                // If we ultimately are becoming the SYSTEM account we want 
the token with the most privileges available.
+                // https://github.com/ansible/ansible/issues/71453
+                bool usedForProcess = becomeSid == "S-1-5-18";
                 systemToken = GetPrimaryTokenForUser(new 
SecurityIdentifier("S-1-5-18"),
-                    new List<string>() { "SeTcbPrivilege" });
+                    new List<string>() { "SeTcbPrivilege" }, usedForProcess);
                 if (systemToken != null)
                 {
                     try
@@ -356,9 +376,11 @@
 
             try
             {
+                if (becomeSid == "S-1-5-18")
+                    userTokens.Add(systemToken);
                 // Cannot use String.IsEmptyOrNull() as an empty string is an 
account that doesn't have a pass.
                 // We only use S4U if no password was defined or it was null
-                if (!SERVICE_SIDS.Contains(becomeSid) && password == null && 
logonType != LogonType.NewCredentials)
+                else if (!SERVICE_SIDS.Contains(becomeSid) && password == null 
&& logonType != LogonType.NewCredentials)
                 {
                     // If no password was specified, try and duplicate an 
existing token for that user or use S4U to
                     // generate one without network credentials
@@ -381,11 +403,6 @@
                     string domain = null;
                     switch (becomeSid)
                     {
-                        case "S-1-5-18":
-                            logonType = LogonType.Service;
-                            domain = "NT AUTHORITY";
-                            username = "SYSTEM";
-                            break;
                         case "S-1-5-19":
                             logonType = LogonType.Service;
                             domain = "NT AUTHORITY";
@@ -427,8 +444,10 @@
             return userTokens;
         }
 
-        private static SafeNativeHandle 
GetPrimaryTokenForUser(SecurityIdentifier sid,
-            List<string> requiredPrivileges = null)
+        private static SafeNativeHandle GetPrimaryTokenForUser(
+            SecurityIdentifier sid,
+            List<string> requiredPrivileges = null,
+            bool usedForProcess = false)
         {
             // According to CreateProcessWithTokenW we require a token with
             //  TOKEN_QUERY, TOKEN_DUPLICATE and TOKEN_ASSIGN_PRIMARY
@@ -438,7 +457,19 @@
                 TokenAccessLevels.AssignPrimary |
                 TokenAccessLevels.Impersonate;
 
-            foreach (SafeNativeHandle hToken in 
TokenUtil.EnumerateUserTokens(sid, dwAccess))
+            SafeNativeHandle userToken = null;
+            int privilegeCount = 0;
+
+            // If we are using this token for the process, we need to check the
+            // process mitigation policy allows child processes to be created.
+            var processFilter = usedForProcess
+                ? (Func<System.Diagnostics.Process, SafeNativeHandle, 
bool>)((p, t) =>
+                {
+                    return GetProcessChildProcessPolicyFlags(t) == 
NativeHelpers.ProcessChildProcessPolicyFlags.None;
+                })
+                : ((p, t) => true);
+
+            foreach (SafeNativeHandle hToken in 
TokenUtil.EnumerateUserTokens(sid, dwAccess, processFilter))
             {
                 // Filter out any Network logon tokens, using become with that 
is useless when S4U
                 // can give us a Batch logon
@@ -448,6 +479,10 @@
 
                 List<string> actualPrivileges = 
TokenUtil.GetTokenPrivileges(hToken).Select(x => x.Name).ToList();
 
+                // If the token has less or the same number of privileges than 
the current token, skip it.
+                if (usedForProcess && privilegeCount >= actualPrivileges.Count)
+                    continue;
+
                 // Check that the required privileges are on the token
                 if (requiredPrivileges != null)
                 {
@@ -459,16 +494,22 @@
                 // Duplicate the token to convert it to a primary token with 
the access level required.
                 try
                 {
-                    return TokenUtil.DuplicateToken(hToken, 
TokenAccessLevels.MaximumAllowed,
+                    userToken = TokenUtil.DuplicateToken(hToken, 
TokenAccessLevels.MaximumAllowed,
                         SecurityImpersonationLevel.Anonymous, 
TokenType.Primary);
+                    privilegeCount = actualPrivileges.Count;
                 }
                 catch (Process.Win32Exception)
                 {
                     continue;
                 }
+
+                // If we don't care about getting the token with the most 
privileges, escape the loop as we already
+                // have a token.
+                if (!usedForProcess)
+                    break;
             }
 
-            return null;
+            return userToken;
         }
 
         private static SafeNativeHandle GetS4UTokenForUser(SecurityIdentifier 
sid, LogonType logonType)
@@ -581,6 +622,35 @@
                 return null;
         }
 
+        private static NativeHelpers.ProcessChildProcessPolicyFlags 
GetProcessChildProcessPolicyFlags(SafeNativeHandle processHandle)
+        {
+            // Because this is only used to check the policy, we ignore any
+            // errors and pretend that the policy is None.
+            NativeHelpers.ProcessChildProcessPolicyFlags policy = 
NativeHelpers.ProcessChildProcessPolicyFlags.None;
+
+            if (_getProcessMitigationPolicySupported)
+            {
+                try
+                {
+                    if (NativeMethods.GetProcessMitigationPolicy(
+                        processHandle,
+                        NativeMethods.ProcessChildProcessPolicy,
+                        ref policy,
+                        (IntPtr)4))
+                    {
+                        return policy;
+                    }
+                }
+                catch (EntryPointNotFoundException)
+                {
+                    // If the function is not available, we won't try to call 
it again
+                    _getProcessMitigationPolicySupported = false;
+                }
+            }
+
+            return policy;
+        }
+
         private static NativeHelpers.SECURITY_LOGON_TYPE 
GetTokenLogonType(SafeNativeHandle hToken)
         {
             TokenStatistics stats = TokenUtil.GetTokenStatistics(hToken);
@@ -637,4 +707,4 @@
             { }
         }
     }
-}
+}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.18.0/lib/ansible/modules/command.py 
new/ansible_core-2.18.1/lib/ansible/modules/command.py
--- old/ansible_core-2.18.0/lib/ansible/modules/command.py      2024-11-04 
19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/lib/ansible/modules/command.py      2024-12-02 
18:46:46.000000000 +0100
@@ -15,12 +15,11 @@
 description:
      - The M(ansible.builtin.command) module takes the command name followed 
by a list of space-delimited arguments.
      - The given command will be executed on all selected nodes.
-     - The command(s) will not be
-       processed through the shell, so variables like C($HOSTNAME) and 
operations
-       like C("*"), C("<"), C(">"), C("|"), C(";") and C("&") will not work.
+     - The command(s) will not be processed through the shell, so operations 
like C("*"), C("<"), C(">"), C("|"), C(";") and C("&") will not work.
+       Also, environment variables are resolved via Python, not shell, see 
O(expand_argument_vars) and are left unchanged if not matched.
        Use the M(ansible.builtin.shell) module if you need these features.
-     - To create C(command) tasks that are easier to read than the ones using 
space-delimited
-       arguments, pass parameters using the C(args) L(task 
keyword,https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html#task)
+     - To create C(command) tasks that are easier to read than the ones using 
space-delimited arguments,
+       pass parameters using the C(args) L(task 
keyword,https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html#task)
        or use O(cmd) parameter.
      - Either a free form command or O(cmd) parameter is required, see the 
examples.
      - For Windows targets, use the M(ansible.windows.win_command) module 
instead.
@@ -41,8 +40,8 @@
 options:
   expand_argument_vars:
     description:
-      - Expands the arguments that are variables, for example C($HOME) will be 
expanded before being passed to the
-        command to run.
+      - Expands the arguments that are variables, for example C($HOME) will be 
expanded before being passed to the command to run.
+      - If a variable is not matched, it is left unchanged, unlike shell 
substitution which would remove it.
       - Set to V(false) to disable expansion and treat the value as a literal 
argument.
     type: bool
     default: true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.18.0/lib/ansible/modules/dnf5.py 
new/ansible_core-2.18.1/lib/ansible/modules/dnf5.py
--- old/ansible_core-2.18.0/lib/ansible/modules/dnf5.py 2024-11-04 
19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/lib/ansible/modules/dnf5.py 2024-12-02 
18:46:46.000000000 +0100
@@ -358,6 +358,21 @@
 
 def is_installed(base, spec):
     settings = libdnf5.base.ResolveSpecSettings()
+    try:
+        settings.set_group_with_name(True)
+        # Disable checking whether SPEC is a binary -> `/usr/(s)bin/<SPEC>`,
+        # this prevents scenarios like the following:
+        #   * the `sssd-common` package is installed and provides 
`/usr/sbin/sssd` binary
+        #   * the `sssd` package is NOT installed
+        #   * due to `set_with_binaries(True)` being default 
`is_installed(base, "sssd")` would "unexpectedly" return True
+        # If users wish to target the `sssd` binary they can by specifying the 
full path `name=/usr/sbin/sssd` explicitly
+        # due to settings.set_with_filenames(True) being default.
+        settings.set_with_binaries(False)
+    except AttributeError:
+        # dnf5 < 5.2.0.0
+        settings.group_with_name = True
+        settings.with_binaries = False
+
     installed_query = libdnf5.rpm.PackageQuery(base)
     installed_query.filter_installed()
     match, nevra = installed_query.resolve_pkg_spec(spec, settings, True)
@@ -646,9 +661,12 @@
         settings = libdnf5.base.GoalJobSettings()
         try:
             settings.set_group_with_name(True)
+            settings.set_with_binaries(False)
         except AttributeError:
             # dnf5 < 5.2.0.0
             settings.group_with_name = True
+            settings.with_binaries = False
+
         if self.bugfix or self.security:
             advisory_query = libdnf5.advisory.AdvisoryQuery(base)
             types = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.18.0/lib/ansible/plugins/lookup/varnames.py 
new/ansible_core-2.18.1/lib/ansible/plugins/lookup/varnames.py
--- old/ansible_core-2.18.0/lib/ansible/plugins/lookup/varnames.py      
2024-11-04 19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/lib/ansible/plugins/lookup/varnames.py      
2024-12-02 18:46:46.000000000 +0100
@@ -13,11 +13,14 @@
       _terms:
         description: List of Python regex patterns to search for in variable 
names.
         required: True
+    seealso:
+        - plugin_type: lookup
+          plugin: ansible.builtin.vars
 """
 
 EXAMPLES = """
 - name: List variables that start with qz_
-  ansible.builtin.debug: msg="{{ lookup('ansible.builtin.varnames', 
'^qz_.+')}}"
+  ansible.builtin.debug: msg="{{ lookup('ansible.builtin.varnames', '^qz_.+') 
}}"
   vars:
     qz_1: hello
     qz_2: world
@@ -25,13 +28,16 @@
     qz_: "I won't show either"
 
 - name: Show all variables
-  ansible.builtin.debug: msg="{{ lookup('ansible.builtin.varnames', '.+')}}"
+  ansible.builtin.debug: msg="{{ lookup('ansible.builtin.varnames', '.+') }}"
 
 - name: Show variables with 'hosts' in their names
-  ansible.builtin.debug: msg="{{ lookup('ansible.builtin.varnames', 'hosts')}}"
+  ansible.builtin.debug: msg="{{ q('varnames', 'hosts') }}"
 
 - name: Find several related variables that end specific way
-  ansible.builtin.debug: msg="{{ lookup('ansible.builtin.varnames', 
'.+_zone$', '.+_location$') }}"
+  ansible.builtin.debug: msg="{{ query('ansible.builtin.varnames', '.+_zone$', 
'.+_location$') }}"
+
+- name: display values from variables found via varnames (note "*" is used to 
dereference the list to a 'list of arguments')
+  debug: msg="{{ lookup('vars', *lookup('varnames', 'ansible_play_.+')) }}"
 
 """
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.18.0/lib/ansible/plugins/lookup/vars.py 
new/ansible_core-2.18.1/lib/ansible/plugins/lookup/vars.py
--- old/ansible_core-2.18.0/lib/ansible/plugins/lookup/vars.py  2024-11-04 
19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/lib/ansible/plugins/lookup/vars.py  2024-12-02 
18:46:46.000000000 +0100
@@ -17,6 +17,10 @@
         description:
             - What to return if a variable is undefined.
             - If no default is set, it will result in an error if any of the 
variables is undefined.
+    seealso:
+    - plugin_type: lookup
+      plugin: ansible.builtin.varnames
+
 """
 
 EXAMPLES = """
@@ -27,20 +31,23 @@
     myvar: ename
 
 - name: Show default empty since i dont have 'variablnotename'
-  ansible.builtin.debug: msg="{{ lookup('ansible.builtin.vars', 'variabl' + 
myvar, default='')}}"
+  ansible.builtin.debug: msg="{{ lookup('ansible.builtin.vars', 'variabl' + 
myvar, default='') }}"
   vars:
     variablename: hello
     myvar: notename
 
 - name: Produce an error since i dont have 'variablnotename'
-  ansible.builtin.debug: msg="{{ lookup('ansible.builtin.vars', 'variabl' + 
myvar)}}"
+  ansible.builtin.debug: msg="{{ q('vars', 'variabl' + myvar) }}"
   ignore_errors: True
   vars:
     variablename: hello
     myvar: notename
 
 - name: find several related variables
-  ansible.builtin.debug: msg="{{ lookup('ansible.builtin.vars', 
'ansible_play_hosts', 'ansible_play_batch', 'ansible_play_hosts_all') }}"
+  ansible.builtin.debug: msg="{{ query('ansible.builtin.vars', 
'ansible_play_hosts', 'ansible_play_batch', 'ansible_play_hosts_all') }}"
+
+- name: show values from variables found via varnames (note "*" is used to 
dereference the list to a 'list of arguments')
+  debug: msg="{{ q('vars', *q('varnames', 'ansible_play_.+')) }}"
 
 - name: Access nested variables
   ansible.builtin.debug: msg="{{ lookup('ansible.builtin.vars', 'variabl' + 
myvar).sub_var }}"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.18.0/lib/ansible/release.py 
new/ansible_core-2.18.1/lib/ansible/release.py
--- old/ansible_core-2.18.0/lib/ansible/release.py      2024-11-04 
19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/lib/ansible/release.py      2024-12-02 
18:46:46.000000000 +0100
@@ -17,6 +17,6 @@
 
 from __future__ import annotations
 
-__version__ = '2.18.0'
+__version__ = '2.18.1'
 __author__ = 'Ansible, Inc.'
 __codename__ = "Fool in the Rain"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.18.0/lib/ansible/template/__init__.py 
new/ansible_core-2.18.1/lib/ansible/template/__init__.py
--- old/ansible_core-2.18.0/lib/ansible/template/__init__.py    2024-11-04 
19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/lib/ansible/template/__init__.py    2024-12-02 
18:46:46.000000000 +0100
@@ -48,7 +48,7 @@
 from ansible.module_utils.common.text.converters import to_native, to_text, 
to_bytes
 from ansible.module_utils.common.collections import is_sequence
 from ansible.plugins.loader import filter_loader, lookup_loader, test_loader
-from ansible.template.native_helpers import ansible_native_concat, 
ansible_eval_concat, ansible_concat
+from ansible.template.native_helpers import AnsibleUndefined, 
ansible_native_concat, ansible_eval_concat, ansible_concat
 from ansible.template.template import AnsibleJ2Template
 from ansible.template.vars import AnsibleJ2Vars
 from ansible.utils.display import Display
@@ -312,35 +312,6 @@
     return functools.update_wrapper(wrapper, func)
 
 
-class AnsibleUndefined(StrictUndefined):
-    '''
-    A custom Undefined class, which returns further Undefined objects on 
access,
-    rather than throwing an exception.
-    '''
-    def __getattr__(self, name):
-        if name == '__UNSAFE__':
-            # AnsibleUndefined should never be assumed to be unsafe
-            # This prevents ``hasattr(val, '__UNSAFE__')`` from evaluating to 
``True``
-            raise AttributeError(name)
-        # Return original Undefined object to preserve the first failure 
context
-        return self
-
-    def __getitem__(self, key):
-        # Return original Undefined object to preserve the first failure 
context
-        return self
-
-    def __repr__(self):
-        return 'AnsibleUndefined(hint={0!r}, obj={1!r}, name={2!r})'.format(
-            self._undefined_hint,
-            self._undefined_obj,
-            self._undefined_name
-        )
-
-    def __contains__(self, item):
-        # Return original Undefined object to preserve the first failure 
context
-        return self
-
-
 class AnsibleContext(Context):
     '''
     A custom context, which intercepts resolve_or_missing() calls and sets a 
flag
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.18.0/lib/ansible/template/native_helpers.py 
new/ansible_core-2.18.1/lib/ansible/template/native_helpers.py
--- old/ansible_core-2.18.0/lib/ansible/template/native_helpers.py      
2024-11-04 19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/lib/ansible/template/native_helpers.py      
2024-12-02 18:46:46.000000000 +0100
@@ -5,13 +5,19 @@
 
 
 import ast
+from collections.abc import Mapping
 from itertools import islice, chain
 from types import GeneratorType
 
+from ansible.module_utils.common.collections import is_sequence
 from ansible.module_utils.common.text.converters import to_text
 from ansible.module_utils.six import string_types
 from ansible.parsing.yaml.objects import AnsibleVaultEncryptedUnicode
 from ansible.utils.native_jinja import NativeJinjaText
+from ansible.utils.unsafe_proxy import wrap_var
+import ansible.module_utils.compat.typing as t
+
+from jinja2.runtime import StrictUndefined
 
 
 _JSON_MAP = {
@@ -28,6 +34,40 @@
         return ast.Constant(value=_JSON_MAP[node.id])
 
 
+def _is_unsafe(value: t.Any) -> bool:
+    """
+    Our helper function, which will also recursively check dict and
+    list entries due to the fact that they may be repr'd and contain
+    a key or value which contains jinja2 syntax and would otherwise
+    lose the AnsibleUnsafe value.
+    """
+    to_check = [value]
+    seen = set()
+
+    while True:
+        if not to_check:
+            break
+
+        val = to_check.pop(0)
+        val_id = id(val)
+
+        if val_id in seen:
+            continue
+        seen.add(val_id)
+
+        if isinstance(val, AnsibleUndefined):
+            continue
+        if isinstance(val, Mapping):
+            to_check.extend(val.keys())
+            to_check.extend(val.values())
+        elif is_sequence(val):
+            to_check.extend(val)
+        elif getattr(val, '__UNSAFE__', False):
+            return True
+
+    return False
+
+
 def ansible_eval_concat(nodes):
     """Return a string of concatenated compiled nodes. Throw an undefined error
     if any of the nodes is undefined.
@@ -43,17 +83,28 @@
     if not head:
         return ''
 
+    unsafe = False
+
     if len(head) == 1:
         out = head[0]
 
         if isinstance(out, NativeJinjaText):
             return out
 
+        unsafe = _is_unsafe(out)
         out = to_text(out)
     else:
         if isinstance(nodes, GeneratorType):
             nodes = chain(head, nodes)
-        out = ''.join([to_text(v) for v in nodes])
+
+        out_values = []
+        for v in nodes:
+            if not unsafe and _is_unsafe(v):
+                unsafe = True
+
+            out_values.append(to_text(v))
+
+        out = ''.join(out_values)
 
     # if this looks like a dictionary, list or bool, convert it to such
     if out.startswith(('{', '[')) or out in ('True', 'False'):
@@ -68,6 +119,9 @@
         except (TypeError, ValueError, SyntaxError, MemoryError):
             pass
 
+    if unsafe:
+        out = wrap_var(out)
+
     return out
 
 
@@ -78,7 +132,19 @@
 
     Used in Templar.template() when jinja2_native=False and convert_data=False.
     """
-    return ''.join([to_text(v) for v in nodes])
+    unsafe = False
+    values = []
+    for v in nodes:
+        if not unsafe and _is_unsafe(v):
+            unsafe = True
+
+        values.append(to_text(v))
+
+    out = ''.join(values)
+    if unsafe:
+        out = wrap_var(out)
+
+    return out
 
 
 def ansible_native_concat(nodes):
@@ -95,6 +161,8 @@
     if not head:
         return None
 
+    unsafe = False
+
     if len(head) == 1:
         out = head[0]
 
@@ -115,10 +183,21 @@
         # short-circuit literal_eval for anything other than strings
         if not isinstance(out, string_types):
             return out
+
+        unsafe = _is_unsafe(out)
+
     else:
         if isinstance(nodes, GeneratorType):
             nodes = chain(head, nodes)
-        out = ''.join([to_text(v) for v in nodes])
+
+        out_values = []
+        for v in nodes:
+            if not unsafe and _is_unsafe(v):
+                unsafe = True
+
+            out_values.append(to_text(v))
+
+        out = ''.join(out_values)
 
     try:
         evaled = ast.literal_eval(
@@ -128,10 +207,45 @@
             ast.parse(out, mode='eval')
         )
     except (TypeError, ValueError, SyntaxError, MemoryError):
+        if unsafe:
+            out = wrap_var(out)
+
         return out
 
     if isinstance(evaled, string_types):
         quote = out[0]
-        return f'{quote}{evaled}{quote}'
+        evaled = f'{quote}{evaled}{quote}'
+
+    if unsafe:
+        evaled = wrap_var(evaled)
 
     return evaled
+
+
+class AnsibleUndefined(StrictUndefined):
+    """
+    A custom Undefined class, which returns further Undefined objects on 
access,
+    rather than throwing an exception.
+    """
+    def __getattr__(self, name):
+        if name == '__UNSAFE__':
+            # AnsibleUndefined should never be assumed to be unsafe
+            # This prevents ``hasattr(val, '__UNSAFE__')`` from evaluating to 
``True``
+            raise AttributeError(name)
+        # Return original Undefined object to preserve the first failure 
context
+        return self
+
+    def __getitem__(self, key):
+        # Return original Undefined object to preserve the first failure 
context
+        return self
+
+    def __repr__(self):
+        return 'AnsibleUndefined(hint={0!r}, obj={1!r}, name={2!r})'.format(
+            self._undefined_hint,
+            self._undefined_obj,
+            self._undefined_name
+        )
+
+    def __contains__(self, item):
+        # Return original Undefined object to preserve the first failure 
context
+        return self
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.18.0/lib/ansible/vars/hostvars.py 
new/ansible_core-2.18.1/lib/ansible/vars/hostvars.py
--- old/ansible_core-2.18.0/lib/ansible/vars/hostvars.py        2024-11-04 
19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/lib/ansible/vars/hostvars.py        2024-12-02 
18:46:46.000000000 +0100
@@ -92,10 +92,12 @@
         return self._find_host(host_name) is not None
 
     def __iter__(self):
-        yield from self._inventory.hosts
+        # include implicit localhost only if it has variables set
+        yield from self._inventory.hosts | {'localhost': 
self._inventory.localhost} if self._inventory.localhost else {}
 
     def __len__(self):
-        return len(self._inventory.hosts)
+        # include implicit localhost only if it has variables set
+        return len(self._inventory.hosts) + (1 if self._inventory.localhost 
else 0)
 
     def __repr__(self):
         out = {}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ansible_core-2.18.0/pyproject.toml 
new/ansible_core-2.18.1/pyproject.toml
--- old/ansible_core-2.18.0/pyproject.toml      2024-11-04 19:35:45.000000000 
+0100
+++ new/ansible_core-2.18.1/pyproject.toml      2024-12-02 18:46:46.000000000 
+0100
@@ -1,5 +1,5 @@
 [build-system]
-requires = ["setuptools >= 66.1.0, <= 75.3.0"]  # lower bound to support 
controller Python versions, upper bound for latest version tested at release
+requires = ["setuptools >= 66.1.0, <= 75.6.0"]  # lower bound to support 
controller Python versions, 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.18.0/test/integration/targets/dnf/tasks/repo.yml 
new/ansible_core-2.18.1/test/integration/targets/dnf/tasks/repo.yml
--- old/ansible_core-2.18.0/test/integration/targets/dnf/tasks/repo.yml 
2024-11-04 19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/test/integration/targets/dnf/tasks/repo.yml 
2024-12-02 18:46:46.000000000 +0100
@@ -517,3 +517,73 @@
       dnf:
         name: provides_foo*
         state: absent
+
+# https://github.com/ansible/ansible/issues/84259
+- name: test installing a package named `package-name` while a package 
providing `/usr/sbin/package-name` is installed
+  block:
+    - dnf:
+        name: package-name
+        state: absent
+
+    - dnf:
+        name: provides-binary
+        state: present
+
+    - dnf:
+        name: package-name
+        state: latest
+      register: dnf_result
+
+    - assert:
+        that:
+          - dnf_result is changed
+  always:
+    - name: Clean up
+      dnf:
+        name:
+          - provides-binary
+          - package-name
+        state: absent
+
+- name: test installing a package that provides a binary by specifying the 
binary name
+  block:
+    - dnf:
+        name: provides-binary
+        state: absent
+
+    - dnf:
+        name: /usr/sbin/package-name
+        state: present
+      register: dnf_result
+
+    - assert:
+        that:
+          - dnf_result is changed
+  always:
+    - name: Clean up
+      dnf:
+        name: provides-binary
+        state: absent
+
+# https://github.com/ansible/ansible/issues/84334
+- name: test that a binary is not matched by its base name
+  block:
+    - dnf:
+        name: provides-binary
+        state: present
+
+    - dnf:
+        name: package-name
+        state: absent
+      register: dnf_result
+
+    - assert:
+        that:
+          - dnf_result is not changed
+  always:
+    - name: Clean up
+      dnf:
+        name:
+          - provides-binary
+          - package-name
+        state: absent
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.18.0/test/integration/targets/ignore_unreachable/runme.sh 
new/ansible_core-2.18.1/test/integration/targets/ignore_unreachable/runme.sh
--- 
old/ansible_core-2.18.0/test/integration/targets/ignore_unreachable/runme.sh    
    2024-11-04 19:35:45.000000000 +0100
+++ 
new/ansible_core-2.18.1/test/integration/targets/ignore_unreachable/runme.sh    
    2024-12-02 18:46:46.000000000 +0100
@@ -1,6 +1,8 @@
 #!/usr/bin/env bash
 set -eux
 
+export ANSIBLE_TIMEOUT=1
+
 export ANSIBLE_CONNECTION_PLUGINS=./fake_connectors
 # use fake connectors that raise errors at different stages
 ansible-playbook test_with_bad_plugins.yml -i inventory -v "$@"
@@ -14,3 +16,9 @@
 else
     echo "Connection to nonexistent hosts failed without using 
ignore_unreachable. Success!"
 fi
+
+if ansible-playbook test_base_loop_cannot_connect.yml -i inventory -v "$@" > 
out.txt; then
+    echo "Playbook intended to fail succeeded. Connection succeeded to 
nonexistent host"
+    exit 1
+fi
+grep out.txt -e 'ignored=1' | grep 'unreachable=2' | grep 'ok=1'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.18.0/test/integration/targets/ignore_unreachable/test_base_loop_cannot_connect.yml
 
new/ansible_core-2.18.1/test/integration/targets/ignore_unreachable/test_base_loop_cannot_connect.yml
--- 
old/ansible_core-2.18.0/test/integration/targets/ignore_unreachable/test_base_loop_cannot_connect.yml
       1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible_core-2.18.1/test/integration/targets/ignore_unreachable/test_base_loop_cannot_connect.yml
       2024-12-02 18:46:46.000000000 +0100
@@ -0,0 +1,41 @@
+- hosts: localhost,nonexistent
+  gather_facts: false
+  tasks:
+  - name: Test ignore_unreachable for all items (pass)
+    ping:
+    ignore_unreachable: "{{ item.ignore_unreachable }}"
+    loop:
+      - ignore_unreachable: true
+      - ignore_unreachable: true
+    register: unreachable_ignored
+
+  - name: Test ignore_unreachable for second item (fail)
+    ping:
+    ignore_unreachable: "{{ item.ignore_unreachable }}"
+    loop:
+      - ignore_unreachable: false
+      - ignore_unreachable: true
+    register: unreachable_first
+
+  - meta: clear_host_errors
+
+  - name: Test ignore_unreachable for first item (fail)
+    ping:
+    ignore_unreachable: "{{ item.ignore_unreachable }}"
+    loop:
+      - ignore_unreachable: true
+      - ignore_unreachable: false
+    register: unreachable_last
+
+  - meta: clear_host_errors
+
+  - assert:
+      that:
+        - unreachable_ignored is not unreachable
+        - unreachable_first["results"][0] is unreachable
+        - unreachable_first["results"][-1] is not unreachable
+        - unreachable_first is unreachable
+        - unreachable_last["results"][-1] is unreachable
+        - unreachable_last["results"][0] is not unreachable
+        - unreachable_last is unreachable
+    when: inventory_hostname == 'nonexistent'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.18.0/test/integration/targets/setup_rpm_repo/library/create_repo.py
 
new/ansible_core-2.18.1/test/integration/targets/setup_rpm_repo/library/create_repo.py
--- 
old/ansible_core-2.18.0/test/integration/targets/setup_rpm_repo/library/create_repo.py
      2024-11-04 19:35:45.000000000 +0100
+++ 
new/ansible_core-2.18.1/test/integration/targets/setup_rpm_repo/library/create_repo.py
      2024-12-02 18:46:46.000000000 +0100
@@ -15,8 +15,10 @@
     from rpmfluff.make import make_gif
     from rpmfluff.sourcefile import GeneratedSourceFile
     from rpmfluff.rpmbuild import SimpleRpmBuild
+    from rpmfluff.utils import expectedArch
     from rpmfluff.yumrepobuild import YumRepoBuild
 except ImportError:
+    expectedArch = None  # define here to avoid NameError as it is used on top 
level in SPECS
     HAS_RPMFLUFF = False
 
 
@@ -30,6 +32,7 @@
     recommends: list[str] | None = None
     requires: list[str] | None = None
     file: str | None = None
+    binary: str | None = None
 
 
 SPECS = [
@@ -58,6 +61,8 @@
     RPM(name='broken-b', version='1.0', requires=['broken-a = 1.2.3-1']),
     RPM(name='broken-c', version='1.0', requires=['broken-c = 1.2.4-1']),
     RPM(name='broken-d', version='1.0', requires=['broken-a']),
+    RPM(name='provides-binary', version='1.0', arch=[expectedArch], 
binary='/usr/sbin/package-name'),
+    RPM(name='package-name', version='1.0'),
 ]
 
 
@@ -81,10 +86,13 @@
                 )
             )
 
+        if spec.binary:
+            pkg.add_simple_compilation(installPath=spec.binary)
+
         pkgs.append(pkg)
 
     repo = YumRepoBuild(pkgs)
-    repo.make('noarch', 'i686', 'x86_64')
+    repo.make('noarch', 'i686', 'x86_64', expectedArch)
 
     for pkg in pkgs:
         pkg.clean()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.18.0/test/integration/targets/template/cve-2024-11079.yml 
new/ansible_core-2.18.1/test/integration/targets/template/cve-2024-11079.yml
--- 
old/ansible_core-2.18.0/test/integration/targets/template/cve-2024-11079.yml    
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/ansible_core-2.18.1/test/integration/targets/template/cve-2024-11079.yml    
    2024-12-02 18:46:46.000000000 +0100
@@ -0,0 +1,30 @@
+- name: test CVE-2024-11079 loop variables preserve unsafe hostvars
+  hosts: localhost
+  gather_facts: false
+  tasks:
+  - set_fact:
+      foo:
+        safe:
+          prop: '{{ "{{" }} unsafe_var {{ "}}" }}'
+        unsafe:
+          prop: !unsafe '{{ unsafe_var }}'
+
+  - name: safe var through hostvars loop is templated
+    assert:
+      that:
+      - item.prop == expected
+    loop:
+    - "{{ hostvars['localhost']['foo']['safe'] }}"
+    vars:
+      unsafe_var: bar
+      expected: bar
+
+  - name: unsafe var through hostvars loop is not templated
+    assert:
+      that:
+      - item.prop == expected
+    loop:
+    - "{{ hostvars['localhost']['foo']['unsafe'] }}"
+    vars:
+      unsafe_var: bar
+      expected: !unsafe '{{ unsafe_var }}'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.18.0/test/integration/targets/template/runme.sh 
new/ansible_core-2.18.1/test/integration/targets/template/runme.sh
--- old/ansible_core-2.18.0/test/integration/targets/template/runme.sh  
2024-11-04 19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/test/integration/targets/template/runme.sh  
2024-12-02 18:46:46.000000000 +0100
@@ -41,6 +41,10 @@
 # ensure unsafe is preserved, even with extra newlines
 ansible-playbook unsafe.yml -v "$@"
 
+# CVE 2024-11079
+ANSIBLE_JINJA2_NATIVE=true ansible-playbook cve-2024-11079.yml -v "$@"
+ANSIBLE_JINJA2_NATIVE=false ansible-playbook cve-2024-11079.yml -v "$@"
+
 # ensure Jinja2 overrides from a template are used
 ansible-playbook template_overrides.yml -v "$@"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.18.0/test/lib/ansible_test/_internal/containers.py 
new/ansible_core-2.18.1/test/lib/ansible_test/_internal/containers.py
--- old/ansible_core-2.18.0/test/lib/ansible_test/_internal/containers.py       
2024-11-04 19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/test/lib/ansible_test/_internal/containers.py       
2024-12-02 18:46:46.000000000 +0100
@@ -292,10 +292,13 @@
         current_container_id = get_docker_container_id()
 
         if current_container_id:
-            # Make sure any additional containers we launch use the same 
network as the current container we're running in.
-            # This is needed when ansible-test is running in a container that 
is not connected to Docker's default network.
-            container = docker_inspect(args, current_container_id, always=True)
-            network = container.get_network_name()
+            try:
+                # Make sure any additional containers we launch use the same 
network as the current container we're running in.
+                # This is needed when ansible-test is running in a container 
that is not connected to Docker's default network.
+                container = docker_inspect(args, current_container_id, 
always=True)
+                network = container.get_network_name()
+            except ContainerNotFoundError:
+                display.warning('Unable to detect the network for the current 
container. Use the `--docker-network` option if containers are unreachable.')
 
     # The default docker behavior puts containers on the same network.
     # The default podman behavior puts containers on isolated networks which 
don't allow communication between containers or network disconnect.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.18.0/test/lib/ansible_test/_internal/util.py 
new/ansible_core-2.18.1/test/lib/ansible_test/_internal/util.py
--- old/ansible_core-2.18.0/test/lib/ansible_test/_internal/util.py     
2024-11-04 19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/test/lib/ansible_test/_internal/util.py     
2024-12-02 18:46:46.000000000 +0100
@@ -1014,15 +1014,15 @@
             self._callback()
 
 
-def format_command_output(stdout: str, stderr: str) -> str:
+def format_command_output(stdout: str | None, stderr: str | None) -> str:
     """Return a formatted string containing the given stdout and stderr (if 
any)."""
     message = ''
 
-    if stderr := stderr.strip():
+    if stderr and (stderr := stderr.strip()):
         message += '>>> Standard Error\n'
         message += f'{stderr}{Display.clear}\n'
 
-    if stdout := stdout.strip():
+    if stdout and (stdout := stdout.strip()):
         message += '>>> Standard Output\n'
         message += f'{stdout}{Display.clear}\n'
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.18.0/test/units/ansible_test/_internal/test_util.py 
new/ansible_core-2.18.1/test/units/ansible_test/_internal/test_util.py
--- old/ansible_core-2.18.0/test/units/ansible_test/_internal/test_util.py      
1970-01-01 01:00:00.000000000 +0100
+++ new/ansible_core-2.18.1/test/units/ansible_test/_internal/test_util.py      
2024-12-02 18:46:46.000000000 +0100
@@ -0,0 +1,36 @@
+from __future__ import annotations
+
+import pytest
+
+
+def test_failed_non_interactive_captured_command() -> None:
+    """Verify failed non-interactive captured commands raise a 
`SubprocessError` with `stdout` and `stderr` set."""
+    from ansible_test._internal.util import raw_command, SubprocessError
+
+    with pytest.raises(SubprocessError, match='Command "ls /dev/null 
/does/not/exist" returned exit status [0-9]+.\n>>> Standard Error\n') as error:
+        raw_command(['ls', '/dev/null', '/does/not/exist'], True)
+
+    assert '/dev/null' in error.value.stdout
+    assert '/does/not/exist' in error.value.stderr
+
+
+def test_failed_non_interactive_command() -> None:
+    """Verify failed non-interactive non-captured commands raise a 
`SubprocessError` with `stdout` and `stderr` set to an empty string."""
+    from ansible_test._internal.util import raw_command, SubprocessError
+
+    with pytest.raises(SubprocessError, match='Command "ls /dev/null 
/does/not/exist" returned exit status [0-9]+.') as error:
+        raw_command(['ls', '/dev/null', '/does/not/exist'], False)
+
+    assert error.value.stdout == ''
+    assert error.value.stderr == ''
+
+
+def test_failed_interactive_command() -> None:
+    """Verify failed interactive commands raise a `SubprocessError` with 
`stdout` and `stderr` set to `None`."""
+    from ansible_test._internal.util import raw_command, SubprocessError
+
+    with pytest.raises(SubprocessError, match='Command "ls /dev/null 
/does/not/exist" returned exit status [0-9]+.') as error:
+        raw_command(['ls', '/dev/null', '/does/not/exist'], False, 
interactive=True)
+
+    assert error.value.stdout is None
+    assert error.value.stderr is None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ansible_core-2.18.0/test/units/ansible_test/conftest.py 
new/ansible_core-2.18.1/test/units/ansible_test/conftest.py
--- old/ansible_core-2.18.0/test/units/ansible_test/conftest.py 2024-11-04 
19:35:45.000000000 +0100
+++ new/ansible_core-2.18.1/test/units/ansible_test/conftest.py 2024-12-02 
18:46:46.000000000 +0100
@@ -7,7 +7,7 @@
 
 
 @pytest.fixture(autouse=True, scope='session')
-def ansible_test():
-    """Make ansible_test available on sys.path for unit testing 
ansible-test."""
+def inject_ansible_test():
+    """Make ansible_test available on `sys.path` for unit testing 
ansible-test."""
     test_lib = 
os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'lib')
     sys.path.insert(0, test_lib)

++++++ ansible_core-2.18.0.tar.gz.sha256 -> ansible_core-2.18.1.tar.gz.sha256 
++++++
--- /work/SRC/openSUSE:Factory/ansible-core/ansible_core-2.18.0.tar.gz.sha256   
2024-12-02 16:58:56.756726852 +0100
+++ 
/work/SRC/openSUSE:Factory/.ansible-core.new.28523/ansible_core-2.18.1.tar.gz.sha256
        2024-12-05 17:10:06.321273161 +0100
@@ -1 +1 @@
-87fbebbfe8d961e9b153e84b4438ba3a327dbfdcd4ad05a6065d9ff5d9d02e7b  
ansible_core-2.18.0.tar.gz
+14cac1f92bbdae881cb0616eddeb17925e8cb507e486087975e724533d9de74f  
ansible_core-2.18.1.tar.gz

Reply via email to