Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package salt for openSUSE:Factory checked in 
at 2026-11-10 14:39:10
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/salt (Old)
 and      /work/SRC/openSUSE:Factory/.salt.new.3759290 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "salt"

Tue Nov 10 14:39:10 2026 rev:210 rq:1396331 version:3006.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/salt/salt.changes        2026-11-04 
19:43:04.440419122 +0100
+++ /work/SRC/openSUSE:Factory/.salt.new.3759290/salt.changes   2026-11-10 
14:39:41.000714526 +0100
@@ -1,0 +2,10 @@
+Mon Nov  9 12:22:43 UTC 2026 - Marek Czernek <[email protected]>
+
+- Fix asyncio_loop AttributeError in SyncWrapper on Python 3.6
+- Support oscap options that select rules and content in xccdf_eval
+
+- Added:
+  * fix-asyncio_loop-attributeerror-in-syncwrapper-on-py.patch
+  * support-the-oscap-options-that-select-rules-and-cont.patch
+
+-------------------------------------------------------------------

New:
----
  fix-asyncio_loop-attributeerror-in-syncwrapper-on-py.patch
  support-the-oscap-options-that-select-rules-and-cont.patch

----------(New B)----------
  New:- Added:
  * fix-asyncio_loop-attributeerror-in-syncwrapper-on-py.patch
  * support-the-oscap-options-that-select-rules-and-cont.patch
  New:  * fix-asyncio_loop-attributeerror-in-syncwrapper-on-py.patch
  * support-the-oscap-options-that-select-rules-and-cont.patch
----------(New E)----------

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

Other differences:
------------------
++++++ salt.spec ++++++
--- /var/tmp/diff_new_pack.jSaoGC/_old  2026-11-10 14:39:45.449900734 +0100
+++ /var/tmp/diff_new_pack.jSaoGC/_new  2026-11-10 14:39:45.451900818 +0100
@@ -724,6 +724,11 @@
 # PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/70655
 # PATCH-FIX_UPSTREAM: 
https://github.com/saltstack/salt/commit/6ef6346378c834063e6806e18c58abd70397c8e4
 Patch234:       stabilize-testsuite-791.patch
+# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/780
+# PATCH-FIX_UPSTREAM: 
https://github.com/salt-extensions/saltext-openscap/pull/9
+Patch235:       support-the-oscap-options-that-select-rules-and-cont.patch
+# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/792
+Patch236:       fix-asyncio_loop-attributeerror-in-syncwrapper-on-py.patch
 
 ### IMPORTANT: The line below is used as a snippet marker. Do not touch it.
 ### SALT PATCHES LIST END

++++++ _lastrevision ++++++
--- /var/tmp/diff_new_pack.jSaoGC/_old  2026-11-10 14:39:45.584906385 +0100
+++ /var/tmp/diff_new_pack.jSaoGC/_new  2026-11-10 14:39:45.589906594 +0100
@@ -1,3 +1,3 @@
-c39c822ef877156b5c560b730aa36575a9094f69
+5c385cba2bbbd073943b26c128097f7d7eb34879
 (No newline at EOF)
 

++++++ fix-asyncio_loop-attributeerror-in-syncwrapper-on-py.patch ++++++
>From 2bdf58d97577892653d18f4b328fe1273dbee6c9 Mon Sep 17 00:00:00 2001
From: Marek Czernek <[email protected]>
Date: Mon, 9 Nov 2026 12:58:20 +0100
Subject: [PATCH] Fix asyncio_loop AttributeError in SyncWrapper on Python
 <3.11 (#792)

SyncWrapper.close() reads self.asyncio_loop, but it is not
set or used  on Python < 3.11. This caused cosmetic error
"<Class> object has no attribute 'asyncio_loop'"
being logged on every minion shutdown.

Related to 016cbde7805
---
 salt/utils/asynchronous.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/salt/utils/asynchronous.py b/salt/utils/asynchronous.py
index 5e22a12b5ae..c64d0eb8aab 100644
--- a/salt/utils/asynchronous.py
+++ b/salt/utils/asynchronous.py
@@ -183,7 +183,7 @@ class SyncWrapper:
         # never even *construct* the inner coroutine when the loop can't drive
         # it to completion.
         try:
-            if self._loop_can_run_until_complete(self.asyncio_loop):
+            if hasattr(self, "asyncio_loop") and 
self._loop_can_run_until_complete(self.asyncio_loop):
                 pending_tasks = [
                     task
                     for task in asyncio.all_tasks(self.asyncio_loop)
@@ -203,14 +203,14 @@ class SyncWrapper:
                         if not gathered.done():
                             gathered.cancel()
 
-            if self._loop_can_run_until_complete(self.asyncio_loop):
+            if hasattr(self, "asyncio_loop") and 
self._loop_can_run_until_complete(self.asyncio_loop):
                 shutdown_agens = self.asyncio_loop.shutdown_asyncgens()
                 try:
                     self.asyncio_loop.run_until_complete(shutdown_agens)
                 except Exception:  # pylint: disable=broad-except
                     shutdown_agens.close()
 
-            if self._loop_can_run_until_complete(self.asyncio_loop):
+            if hasattr(self, "asyncio_loop") and 
self._loop_can_run_until_complete(self.asyncio_loop):
                 shutdown_exec = self.asyncio_loop.shutdown_default_executor()
                 try:
                     self.asyncio_loop.run_until_complete(shutdown_exec)
-- 
2.56.0


++++++ support-the-oscap-options-that-select-rules-and-cont.patch ++++++
>From 7c02051b8d95ae253e4272bb82102f7f4b7e4546 Mon Sep 17 00:00:00 2001
From: jniedergang <[email protected]>
Date: Wed, 4 Nov 2026 13:08:38 +0100
Subject: [PATCH] Support the oscap options that select rules and content in
 xccdf_eval (#780)

* Support the oscap options that select rules and content in xccdf_eval

xccdf_eval rebuilds the oscap command line from a fixed set of keyword
arguments, so anything else a caller asks for is dropped without a word.
SUSE Multi-Linux Manager exposes an oscap arguments field that ends up
here, which means a user asking to skip a rule gets a compliance report
where that rule was evaluated anyway.

Add the options that select which rules are evaluated and where the
content comes from: skip_rule, reference, cpe, local_files, datastream_id,
xccdf_id and benchmark_id. rule and skip_rule now accept either a single
string or a list, since oscap accepts those options more than once.

The options that write result files (results, results-arf, report,
stig-viewer, thin-results) are deliberately left out: the caller owns
those paths and already passes them explicitly.
---
 changelog/780.added.md              |   1 +
 salt/modules/openscap.py            |  60 +++++++++++-
 tests/unit/modules/test_openscap.py | 146 ++++++++++++++++++++++++++++
 3 files changed, 204 insertions(+), 3 deletions(-)
 create mode 100644 changelog/780.added.md

diff --git a/changelog/780.added.md b/changelog/780.added.md
new file mode 100644
index 0000000000..dc535ef125
--- /dev/null
+++ b/changelog/780.added.md
@@ -0,0 +1 @@
+Added the oscap options selecting rules and content to `openscap.xccdf_eval`: 
`skip_rule`, `reference`, `cpe`, `local_files`, `datastream_id`, `xccdf_id` and 
`benchmark_id`. `rule` and `skip_rule` now accept a list, since oscap accepts 
those options more than once.
diff --git a/salt/modules/openscap.py b/salt/modules/openscap.py
index 926c98db9e..50210884a0 100644
--- a/salt/modules/openscap.py
+++ b/salt/modules/openscap.py
@@ -56,6 +56,18 @@ _OSCAP_EXIT_CODES_MAP = {
 }
 
 
+def _append_repeatable(cmd_opts, option, value):
+    """
+    Append one occurrence of a repeatable oscap option per value.
+
+    The value is either a single string or a list of strings.
+    """
+    values = [value] if isinstance(value, str) else value
+    for item in values:
+        cmd_opts.append(option)
+        cmd_opts.append(item)
+
+
 def xccdf_eval(xccdffile, ovalfiles=None, **kwargs):
     """
     Run ``oscap xccdf eval`` commands on minions.
@@ -75,7 +87,13 @@ def xccdf_eval(xccdffile, ovalfiles=None, **kwargs):
         the name of Profile to be evaluated
 
     rule
-        the name of a single rule to be evaluated
+        the name of a rule to be evaluated, or a list of rules, such as 
``[rule1, rule2]``
+
+    skip_rule
+        the name of a rule to be skipped, or a list of rules, such as 
``[rule1, rule2]``
+
+    reference
+        evaluate only the rules carrying the given reference, as ``NAME:ID``
 
     oval_results
         save OVAL results as well (True or False)
@@ -89,6 +107,23 @@ def xccdf_eval(xccdffile, ovalfiles=None, **kwargs):
     fetch_remote_resources
         download remote content referenced by XCCDF (True or False)
 
+    local_files
+        use the locally downloaded copies of the remote resources stored in
+        the given directory instead of downloading them
+
+    cpe
+        use given CPE dictionary or language for applicability checks
+
+    datastream_id
+        ID of the data stream in the collection to use
+
+    xccdf_id
+        ID of the component reference holding the XCCDF to evaluate
+
+    benchmark_id
+        ID of the XCCDF benchmark to evaluate, when neither datastream_id nor
+        xccdf_id is given
+
     tailoring_file
         use given XCCDF Tailoring file
 
@@ -126,8 +161,24 @@ def xccdf_eval(xccdffile, ovalfiles=None, **kwargs):
         cmd_opts.append("--profile")
         cmd_opts.append(kwargs["profile"])
     if "rule" in kwargs:
-        cmd_opts.append("--rule")
-        cmd_opts.append(kwargs["rule"])
+        _append_repeatable(cmd_opts, "--rule", kwargs["rule"])
+    if "skip_rule" in kwargs:
+        _append_repeatable(cmd_opts, "--skip-rule", kwargs["skip_rule"])
+    if "reference" in kwargs:
+        cmd_opts.append("--reference")
+        cmd_opts.append(kwargs["reference"])
+    if "cpe" in kwargs:
+        cmd_opts.append("--cpe")
+        cmd_opts.append(kwargs["cpe"])
+    if "datastream_id" in kwargs:
+        cmd_opts.append("--datastream-id")
+        cmd_opts.append(kwargs["datastream_id"])
+    if "xccdf_id" in kwargs:
+        cmd_opts.append("--xccdf-id")
+        cmd_opts.append(kwargs["xccdf_id"])
+    if "benchmark_id" in kwargs:
+        cmd_opts.append("--benchmark-id")
+        cmd_opts.append(kwargs["benchmark_id"])
     if "tailoring_file" in kwargs:
         cmd_opts.append("--tailoring-file")
         cmd_opts.append(kwargs["tailoring_file"])
@@ -136,6 +187,9 @@ def xccdf_eval(xccdffile, ovalfiles=None, **kwargs):
         cmd_opts.append(kwargs["tailoring_id"])
     if kwargs.get("fetch_remote_resources"):
         cmd_opts.append("--fetch-remote-resources")
+    if "local_files" in kwargs:
+        cmd_opts.append("--local-files")
+        cmd_opts.append(kwargs["local_files"])
     if kwargs.get("remediate"):
         cmd_opts.append("--remediate")
     cmd_opts.append(xccdffile)
diff --git a/tests/unit/modules/test_openscap.py 
b/tests/unit/modules/test_openscap.py
index c20220ea97..fbf4ed1cc0 100644
--- a/tests/unit/modules/test_openscap.py
+++ b/tests/unit/modules/test_openscap.py
@@ -445,3 +445,149 @@ class OpenscapTestCase(TestCase):
                     "returncode": 1,
                 },
             )
+
+    def test_new_openscap_xccdf_eval_success_with_skip_rules(self):
+        with patch(
+            "salt.modules.openscap.Popen",
+            MagicMock(
+                return_value=Mock(
+                    **{
+                        "returncode": 0,
+                        "communicate.return_value": (bytes(0), bytes(0)),
+                    }
+                )
+            ),
+        ):
+            response = openscap.xccdf_eval(
+                self.policy_file,
+                profile="Default",
+                skip_rule=["rule-one", "rule-two"],
+                oval_results=True,
+                results="results.xml",
+                report="report.html",
+            )
+
+            expected_cmd = [
+                "oscap",
+                "xccdf",
+                "eval",
+                "--oval-results",
+                "--results",
+                "results.xml",
+                "--report",
+                "report.html",
+                "--profile",
+                "Default",
+                "--skip-rule",
+                "rule-one",
+                "--skip-rule",
+                "rule-two",
+                self.policy_file,
+            ]
+            openscap.Popen.assert_called_once_with(
+                expected_cmd,
+                cwd=openscap.tempfile.mkdtemp.return_value,
+                stderr=subprocess.PIPE,
+                stdout=subprocess.PIPE,
+            )
+            self.assertEqual(
+                response,
+                {
+                    "upload_dir": self.random_temp_dir,
+                    "error": "",
+                    "success": True,
+                    "returncode": 0,
+                },
+            )
+
+    def test_new_openscap_xccdf_eval_success_with_single_rules_as_string(self):
+        with patch(
+            "salt.modules.openscap.Popen",
+            MagicMock(
+                return_value=Mock(
+                    **{
+                        "returncode": 0,
+                        "communicate.return_value": (bytes(0), bytes(0)),
+                    }
+                )
+            ),
+        ):
+            openscap.xccdf_eval(
+                self.policy_file,
+                profile="Default",
+                rule="rule-one",
+                skip_rule="rule-two",
+                oval_results=True,
+            )
+
+            expected_cmd = [
+                "oscap",
+                "xccdf",
+                "eval",
+                "--oval-results",
+                "--profile",
+                "Default",
+                "--rule",
+                "rule-one",
+                "--skip-rule",
+                "rule-two",
+                self.policy_file,
+            ]
+            openscap.Popen.assert_called_once_with(
+                expected_cmd,
+                cwd=openscap.tempfile.mkdtemp.return_value,
+                stderr=subprocess.PIPE,
+                stdout=subprocess.PIPE,
+            )
+
+    def test_new_openscap_xccdf_eval_success_with_content_selection(self):
+        with patch(
+            "salt.modules.openscap.Popen",
+            MagicMock(
+                return_value=Mock(
+                    **{
+                        "returncode": 0,
+                        "communicate.return_value": (bytes(0), bytes(0)),
+                    }
+                )
+            ),
+        ):
+            openscap.xccdf_eval(
+                self.policy_file,
+                profile="Default",
+                reference="stigid:RHEL-09-211010",
+                cpe="/usr/share/openscap/cpe/openscap-cpe-dict.xml",
+                datastream_id="scap_org.open-scap_datastream_from_xccdf",
+                xccdf_id="scap_org.open-scap_cref_xccdf.xml",
+                benchmark_id="xccdf_org.ssgproject.content_benchmark_RHEL-9",
+                local_files="/var/cache/openscap",
+                fetch_remote_resources=True,
+            )
+
+            expected_cmd = [
+                "oscap",
+                "xccdf",
+                "eval",
+                "--profile",
+                "Default",
+                "--reference",
+                "stigid:RHEL-09-211010",
+                "--cpe",
+                "/usr/share/openscap/cpe/openscap-cpe-dict.xml",
+                "--datastream-id",
+                "scap_org.open-scap_datastream_from_xccdf",
+                "--xccdf-id",
+                "scap_org.open-scap_cref_xccdf.xml",
+                "--benchmark-id",
+                "xccdf_org.ssgproject.content_benchmark_RHEL-9",
+                "--fetch-remote-resources",
+                "--local-files",
+                "/var/cache/openscap",
+                self.policy_file,
+            ]
+            openscap.Popen.assert_called_once_with(
+                expected_cmd,
+                cwd=openscap.tempfile.mkdtemp.return_value,
+                stderr=subprocess.PIPE,
+                stdout=subprocess.PIPE,
+            )
-- 
2.56.0

Reply via email to