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-09-12 21:15:42 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/salt (Old) and /work/SRC/openSUSE:Factory/.salt.new.1265 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "salt" Sat Sep 12 21:15:42 2026 rev:206 rq:1377419 version:3006.0 Changes: -------- --- /work/SRC/openSUSE:Factory/salt/salt.changes 2026-09-07 11:28:15.415754498 +0200 +++ /work/SRC/openSUSE:Factory/.salt.new.1265/salt.changes 2026-09-12 21:16:28.057262840 +0200 @@ -1,0 +2,26 @@ +Fri Sep 11 14:27:22 UTC 2026 - Pablo Suárez Hernández <[email protected]> + +- tornado: httputil: Apply multipart limit earlier (bsc#1280008) + +- Added: + * patch-tornado-for-ghsa-8423-8fgw-73vq-783.patch + +------------------------------------------------------------------- +Thu Sep 10 10:09:57 UTC 2026 - Pablo Suárez Hernández <[email protected]> + +- Add __pillar__ global in templates and matchers (bsc#1274616) + +- Added: + * add-__pillar__-global-in-templates-and-matchers-776.patch + +------------------------------------------------------------------- +Wed Sep 9 07:36:20 UTC 2026 - Victor Zhestkov <[email protected]> + +- Remove rpm-vercmp dependency and fix pkg.version_cmp +- Remove usages of pkg_resources (bsc#1262135) + +- Added: + * remove-rpm-vercmp-dependency-and-fix-pkg.version_cmp.patch + * remove-usages-of-pkg_resources-bsc-1262135.patch + +------------------------------------------------------------------- New: ---- add-__pillar__-global-in-templates-and-matchers-776.patch patch-tornado-for-ghsa-8423-8fgw-73vq-783.patch remove-rpm-vercmp-dependency-and-fix-pkg.version_cmp.patch remove-usages-of-pkg_resources-bsc-1262135.patch ----------(New B)---------- New:- Added: * add-__pillar__-global-in-templates-and-matchers-776.patch New:- Added: * patch-tornado-for-ghsa-8423-8fgw-73vq-783.patch New:- Added: * remove-rpm-vercmp-dependency-and-fix-pkg.version_cmp.patch * remove-usages-of-pkg_resources-bsc-1262135.patch New: * remove-rpm-vercmp-dependency-and-fix-pkg.version_cmp.patch * remove-usages-of-pkg_resources-bsc-1262135.patch ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ salt.spec ++++++ --- /var/tmp/diff_new_pack.oehukb/_old 2026-09-12 21:16:31.996426786 +0200 +++ /var/tmp/diff_new_pack.oehukb/_new 2026-09-12 21:16:31.998426869 +0200 @@ -691,6 +691,17 @@ Patch222: fix-test_tcp-for-pytest-8-779.patch # PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/70201 Patch223: fix-mount.swap-activation-when-using-uuid-and-introd.patch +# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/68505 +Patch224: remove-usages-of-pkg_resources-bsc-1262135.patch +# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/782 +# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/68342 +# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/70231 +Patch225: remove-rpm-vercmp-dependency-and-fix-pkg.version_cmp.patch +# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/776 +# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/64043 +Patch226: add-__pillar__-global-in-templates-and-matchers-776.patch +# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/70269 +Patch227: patch-tornado-for-ghsa-8423-8fgw-73vq-783.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.oehukb/_old 2026-09-12 21:16:32.138432698 +0200 +++ /var/tmp/diff_new_pack.oehukb/_new 2026-09-12 21:16:32.141432823 +0200 @@ -1,3 +1,3 @@ -5746100f02d4887a866f1f09a973f8fb5d533c42 +6611f033fee9b85d997d265e3a79393d1c670a7d (No newline at EOF) ++++++ add-__pillar__-global-in-templates-and-matchers-776.patch ++++++ >From 3cc335e77e564f7c1e68c95bed6e45d84bc0dc1a Mon Sep 17 00:00:00 2001 From: Marek Czernek <[email protected]> Date: Thu, 10 Sep 2026 12:03:16 +0200 Subject: [PATCH] Add `__pillar__` global in templates and matchers (#776) * Add `__pillar__` global in templates and matchers This is a partial cherry-pick of https://github.com/saltstack/salt/pull/64043 * Fix unit tests Add test from alt PR Fix linter Fix test assertion for ext_pillar_first Address frebib's PR comments: ensure opts['pillar'] is set in __init__ and explicitly update pack Fix linter: remove trailing newlines Add explicit tests for pillar_opts, ssh_merge_pillar, decrypt_pillar and non-ext_pillar_first paths Fix formatting and final logic verification for dunder pillar Fixup --------- Co-authored-by: Daniel A. Wozniak <[email protected]> --- salt/loader/__init__.py | 17 ++++++++++++++++- salt/matchers/confirm_top.py | 6 +++++- salt/matchers/pillar_exact_match.py | 11 ++++++++--- salt/matchers/pillar_match.py | 11 ++++++++--- salt/matchers/pillar_pcre_match.py | 11 ++++++++--- salt/pillar/__init__.py | 17 +++++++++++++---- tests/pytests/unit/pillar/test_pillar.py | 24 +++++++++++++++++++++++- tests/unit/test_pillar.py | 1 + 8 files changed, 82 insertions(+), 16 deletions(-) diff --git a/salt/loader/__init__.py b/salt/loader/__init__.py index b41cc64b8e6..f09c6615909 100644 --- a/salt/loader/__init__.py +++ b/salt/loader/__init__.py @@ -418,19 +418,34 @@ def metaproxy(opts, loaded_base_name=None): ) -def matchers(opts, loaded_base_name=None): +def matchers(opts, loaded_base_name=None, context=None, pillar=None): """ Return the matcher services plugins :param dict opts: The Salt options dictionary :param str loaded_base_name: The imported modules namespace when imported by the salt loader. + :param dict context: The Salt context dictionary + :param dict pillar: The Salt pillar dictionary """ + if context is None: + context = {} + + pack = { + "__salt__": {}, + "__runners__": {}, + "__grains__": opts.get("grains", {}), + "__context__": context, + } + if pillar is not None: + pack["__pillar__"] = pillar + return LazyLoader( _module_dirs(opts, "matchers"), opts, tag="matchers", loaded_base_name=loaded_base_name, + pack=pack, ) diff --git a/salt/matchers/confirm_top.py b/salt/matchers/confirm_top.py index d2edc99d8f8..659cd5c772a 100644 --- a/salt/matchers/confirm_top.py +++ b/salt/matchers/confirm_top.py @@ -24,7 +24,11 @@ def confirm_top(match, data, nodegroups=None): if "matchers" in __context__: matchers = __context__["matchers"] else: - matchers = salt.loader.matchers(__opts__) + # Matchers need pillar data if available + pillar = __pillar__ if "__pillar__" in globals() else None + if hasattr(pillar, "value"): + pillar = pillar.value() + matchers = salt.loader.matchers(__opts__, context=__context__, pillar=pillar) __context__["matchers"] = matchers funcname = matcher + "_match.match" if matcher == "nodegroup": diff --git a/salt/matchers/pillar_exact_match.py b/salt/matchers/pillar_exact_match.py index ac62c49f9de..ea233ad9415 100644 --- a/salt/matchers/pillar_exact_match.py +++ b/salt/matchers/pillar_exact_match.py @@ -20,11 +20,16 @@ def match(tgt, delimiter=":", opts=None, minion_id=None): log.error("Got insufficient arguments for pillar match statement from master") return False - if "pillar" in opts: + if opts.get("pillar"): pillar = opts["pillar"] - elif "ext_pillar" in opts: - log.info("No pillar found, fallback to ext_pillar") + elif "__pillar__" in globals(): + pillar = __pillar__ + if hasattr(pillar, "value"): + pillar = pillar.value() + elif opts.get("ext_pillar"): pillar = opts["ext_pillar"] + else: + pillar = {} return salt.utils.data.subdict_match( pillar, tgt, delimiter=delimiter, exact_match=True diff --git a/salt/matchers/pillar_match.py b/salt/matchers/pillar_match.py index 87b0df606ba..929bf7cb489 100644 --- a/salt/matchers/pillar_match.py +++ b/salt/matchers/pillar_match.py @@ -21,10 +21,15 @@ def match(tgt, delimiter=DEFAULT_TARGET_DELIM, opts=None, minion_id=None): log.error("Got insufficient arguments for pillar match statement from master") return False - if "pillar" in opts: + if opts.get("pillar"): pillar = opts["pillar"] - elif "ext_pillar" in opts: - log.info("No pillar found, fallback to ext_pillar") + elif "__pillar__" in globals(): + pillar = __pillar__ + if hasattr(pillar, "value"): + pillar = pillar.value() + elif opts.get("ext_pillar"): pillar = opts["ext_pillar"] + else: + pillar = {} return salt.utils.data.subdict_match(pillar, tgt, delimiter=delimiter) diff --git a/salt/matchers/pillar_pcre_match.py b/salt/matchers/pillar_pcre_match.py index ba76a26fa4b..8c627fc80ac 100644 --- a/salt/matchers/pillar_pcre_match.py +++ b/salt/matchers/pillar_pcre_match.py @@ -23,11 +23,16 @@ def match(tgt, delimiter=DEFAULT_TARGET_DELIM, opts=None, minion_id=None): ) return False - if "pillar" in opts: + if opts.get("pillar"): pillar = opts["pillar"] - elif "ext_pillar" in opts: - log.info("No pillar found, fallback to ext_pillar") + elif "__pillar__" in globals(): + pillar = __pillar__ + if hasattr(pillar, "value"): + pillar = pillar.value() + elif opts.get("ext_pillar"): pillar = opts["ext_pillar"] + else: + pillar = {} return salt.utils.data.subdict_match( pillar, tgt, delimiter=delimiter, regex_match=True diff --git a/salt/pillar/__init__.py b/salt/pillar/__init__.py index 0b532aca5ed..599a236b17e 100644 --- a/salt/pillar/__init__.py +++ b/salt/pillar/__init__.py @@ -572,6 +572,12 @@ class Pillar: self.saltenv = saltenv self.client = salt.fileclient.get_file_client(self.opts, True) self.avail = self.__gather_avail() + self.pillar_data = self.opts.get("pillar", {}) + if not isinstance(self.pillar_data, dict): + self.pillar_data = {} + else: + # Ensure we have a plain dict and not a proxy into opts + self.pillar_data = dict(self.pillar_data) if opts.get("file_client", "") == "local" and not opts.get( "use_master_when_local", False @@ -589,7 +595,9 @@ class Pillar: self.functions = functions self.opts["minion_id"] = minion_id - self.matchers = salt.loader.matchers(self.opts) + self.matchers = salt.loader.matchers(self.opts, pillar=self.pillar_data) + if hasattr(self.matchers, "pack"): + self.matchers.pack["__pillar__"] = self.pillar_data self.rend = salt.loader.render(self.opts, self.functions) ext_pillar_opts = copy.deepcopy(self.opts) # Keep the incoming opts ID intact, ie, the master id @@ -883,7 +891,7 @@ class Pillar: """ matches = {} if reload: - self.matchers = salt.loader.matchers(self.opts) + self.matchers = salt.loader.matchers(self.opts, pillar=self.pillar_data) for saltenv, body in top.items(): if self.opts["pillarenv"]: if saltenv != self.opts["pillarenv"]: @@ -1254,12 +1262,13 @@ class Pillar: top, top_errors = self.get_top() if ext: if self.opts.get("ext_pillar_first", False): - self.opts["pillar"], errors = self.ext_pillar(self.pillar_override) + pillar, errors = self.ext_pillar(self.pillar_override) + self.pillar_data.update(pillar) self.rend = salt.loader.render(self.opts, self.functions) matches = self.top_matches(top, reload=True) pillar, errors = self.render_pillar(matches, errors=errors) pillar = merge( - self.opts["pillar"], + self.pillar_data, pillar, self.merge_strategy, self.opts.get("renderer", "yaml"), diff --git a/tests/pytests/unit/pillar/test_pillar.py b/tests/pytests/unit/pillar/test_pillar.py index 11eda34318b..f01f8cee2a2 100644 --- a/tests/pytests/unit/pillar/test_pillar.py +++ b/tests/pytests/unit/pillar/test_pillar.py @@ -7,7 +7,7 @@ import salt.loader import salt.pillar import salt.utils.cache from salt.utils.odict import OrderedDict -from tests.support.mock import MagicMock +from tests.support.mock import MagicMock, patch @pytest.mark.parametrize( @@ -175,3 +175,25 @@ def test_remote_pillar_timeout(temp_salt_minion, tmp_path): pillar.channel.crypted_transfer_decode_dictentry = mock with pytest.raises(salt.exceptions.SaltClientError): pillar.compile_pillar() + + +def test_ssh_merge_pillar_in_dunder_pillar(temp_salt_minion): + """ + Test that ssh_merge_pillar correctly merges extra pillar data from opts["pillar"] into __pillar__ + """ + opts = temp_salt_minion.config.copy() + opts["ssh_merge_pillar"] = True + opts["pillar"] = {"ssh_key": "ssh_value"} + + grains = salt.loader.grains(opts) + pillar = salt.pillar.Pillar(opts, grains, temp_salt_minion.id, "base") + + pil_value = {"normal_key": "normal_value"} + with patch.object(pillar, "render_pillar", return_value=(pil_value, [])): + compiled = pillar.compile_pillar() + assert compiled["ssh_key"] == "ssh_value" + assert compiled["normal_key"] == "normal_value" + + # The loader pack should contain the merged SSH pillar + assert pillar.functions.pack["__pillar__"]["ssh_key"] == "ssh_value" + assert pillar.functions["pillar.get"]("ssh_key") == "ssh_value" diff --git a/tests/unit/test_pillar.py b/tests/unit/test_pillar.py index b71c0e9a371..67102eb2535 100644 --- a/tests/unit/test_pillar.py +++ b/tests/unit/test_pillar.py @@ -89,6 +89,7 @@ class PillarTestCase(TestCase): "renderer_blacklist": [], "renderer_whitelist": [], "state_top": "", + "pillar": {}, "pillar_roots": {"dev": [], "base": []}, "file_roots": {"dev": [], "base": []}, "extension_modules": "", -- 2.55.0 ++++++ patch-tornado-for-ghsa-8423-8fgw-73vq-783.patch ++++++ >From 7f13812c030dfc5469e3d2bc09ea7366c9960088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= <[email protected]> Date: Fri, 11 Sep 2026 15:16:34 +0100 Subject: [PATCH] Patch tornado for GHSA-8423-8fgw-73vq (#783) * Patch tornado for GHSA-8423-8fgw-73vq httputil: Apply multipart max_parts limit earlier This prevents some CPU and memory amplification attacks. https://github.com/tornadoweb/tornado/security/advisories/GHSA-8423-8fgw-73vq https://github.com/tornadoweb/tornado/commit/de85b3f87446e323e881bbaa3d5a74f4b76e5f05 * Add changelog entry --- changelog/70269.fixed.md | 1 + salt/ext/tornado/httputil.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changelog/70269.fixed.md diff --git a/changelog/70269.fixed.md b/changelog/70269.fixed.md new file mode 100644 index 00000000000..20096970be0 --- /dev/null +++ b/changelog/70269.fixed.md @@ -0,0 +1 @@ +- Patch tornado for GHSA-8423-8fgw-73vq diff --git a/salt/ext/tornado/httputil.py b/salt/ext/tornado/httputil.py index b230a85d7b9..587657f0c39 100644 --- a/salt/ext/tornado/httputil.py +++ b/salt/ext/tornado/httputil.py @@ -916,7 +916,9 @@ def parse_multipart_form_data(boundary, data, arguments, files, config=None): final_boundary_index = data.rfind(b"--" + boundary + b"--") if final_boundary_index == -1: raise HTTPInputError("Invalid multipart/form-data: no final boundary found") - parts = data[:final_boundary_index].split(b"--" + boundary + b"\r\n") + parts = data[:final_boundary_index].split( + b"--" + boundary + b"\r\n", config.max_parts + 1 + ) if len(parts) > config.max_parts: raise HTTPInputError("multipart/form-data has too many parts") for part in parts: -- 2.55.0 ++++++ remove-rpm-vercmp-dependency-and-fix-pkg.version_cmp.patch ++++++ ++++ 1298 lines (skipped) ++++++ remove-usages-of-pkg_resources-bsc-1262135.patch ++++++ >From 624fffbc7caa0ecb9f1309a3e7997aec7cca31cd Mon Sep 17 00:00:00 2001 From: Victor Zhestkov <[email protected]> Date: Wed, 9 Sep 2026 09:19:56 +0200 Subject: [PATCH] Remove usages of pkg_resources (bsc#1262135) * Remove usages of pkg_resources * Fix pre-commit and lint failures --------- Co-authored-by: twangboy <[email protected]> --- salt/modules/pip.py | 16 ++-------------- salt/states/pip_state.py | 26 +++++--------------------- salt/utils/versions.py | 7 +++++++ tests/pytests/unit/utils/test_cloud.py | 7 +++---- 4 files changed, 17 insertions(+), 39 deletions(-) diff --git a/salt/modules/pip.py b/salt/modules/pip.py index 68a2a442a1e..b30e472886e 100644 --- a/salt/modules/pip.py +++ b/salt/modules/pip.py @@ -84,8 +84,6 @@ import shutil import sys import tempfile -import pkg_resources # pylint: disable=3rd-party-module-not-gated - import salt.utils.data import salt.utils.files import salt.utils.json @@ -96,11 +94,6 @@ import salt.utils.url import salt.utils.versions from salt.exceptions import CommandExecutionError, CommandNotFoundError -try: - import pkg_resources -except ImportError: - pkg_resources = None - # This needs to be named logger so we don't shadow it in pip.install logger = logging.getLogger(__name__) # pylint: disable=invalid-name @@ -120,12 +113,7 @@ def __virtual__(): entire filesystem. If it's not installed in a conventional location, the user is required to provide the location of pip each time it is used. """ - if pkg_resources is None: - ret = False, 'Package dependency "pkg_resource" is missing' - else: - ret = "pip" - - return ret + return "pip" def _pip_bin_env(cwd, bin_env): @@ -1711,7 +1699,7 @@ def list_all_versions( versions = [ v for v in match.group(1).split(", ") if v and excludes.match(v) ] - versions.sort(key=pkg_resources.parse_version) + versions.sort(key=salt.utils.versions.parse) break if not versions: return None diff --git a/salt/states/pip_state.py b/salt/states/pip_state.py index 542a7f6c751..bcab1cd2835 100644 --- a/salt/states/pip_state.py +++ b/salt/states/pip_state.py @@ -28,16 +28,6 @@ import salt.utils.data import salt.utils.versions from salt.exceptions import CommandExecutionError, CommandNotFoundError -try: - import pkg_resources - - HAS_PKG_RESOURCES = True -except ImportError: - HAS_PKG_RESOURCES = False - - -# pylint: disable=import-error - def purge_pip(): """ @@ -141,8 +131,6 @@ def __virtual__(): """ Only load if the pip module is available in __salt__ """ - if HAS_PKG_RESOURCES is False: - return False, "The pkg_resources python library is not installed" if "pip.list" in __salt__: return __virtualname__ return False @@ -345,26 +333,22 @@ def _check_if_installed( def _pep440_version_cmp(pkg1, pkg2, ignore_epoch=False): """ - Compares two version strings using pkg_resources.parse_version. + Compares two version strings using packaging.version.Version. Return -1 if version1 < version2, 0 if version1 ==version2, and 1 if version1 > version2. Return None if there was a problem making the comparison. """ - if HAS_PKG_RESOURCES is False: - log.warning( - "The pkg_resources packages was not loaded. Please install setuptools." - ) - return None + normalize = lambda x: str(x).split("!", 1)[-1] if ignore_epoch else str(x) pkg1 = normalize(pkg1) pkg2 = normalize(pkg2) try: - if pkg_resources.parse_version(pkg1) < pkg_resources.parse_version(pkg2): + if salt.utils.versions.Version(pkg1) < salt.utils.versions.Version(pkg2): return -1 - if pkg_resources.parse_version(pkg1) == pkg_resources.parse_version(pkg2): + if salt.utils.versions.Version(pkg1) == salt.utils.versions.Version(pkg2): return 0 - if pkg_resources.parse_version(pkg1) > pkg_resources.parse_version(pkg2): + if salt.utils.versions.Version(pkg1) > salt.utils.versions.Version(pkg2): return 1 except Exception as exc: # pylint: disable=broad-except log.exception(exc) diff --git a/salt/utils/versions.py b/salt/utils/versions.py index 2426f47b6b4..5abd634584c 100644 --- a/salt/utils/versions.py +++ b/salt/utils/versions.py @@ -464,3 +464,10 @@ def check_boto_reqs( ) return True + + +def parse(version): + """ + A replacement for `pkg_resources.parse_version` which is being deprecated. + """ + return packaging.version.parse(version) diff --git a/tests/pytests/unit/utils/test_cloud.py b/tests/pytests/unit/utils/test_cloud.py index db9d258d399..a9d926e858e 100644 --- a/tests/pytests/unit/utils/test_cloud.py +++ b/tests/pytests/unit/utils/test_cloud.py @@ -448,11 +448,10 @@ def test_winrm_pinnned_version(): except ImportError: raise pytest.skip('The "winrm" python module is not installed in this env.') else: - import pkg_resources + from importlib.metadata import version - winrm_pkg = pkg_resources.get_distribution("pywinrm") - assert winrm_pkg.version >= "0.3.0" - # fmt: on + winrm_version = version("pywinrm") + assert winrm_version >= "0.3.0" def test_ssh_gateway_arguments_default_alive_args(): -- 2.55.0
