From ae633bde18cd96db963f94ac5919c7ee2600c37e79f3c3a1781b7c8b8d88b290 Mon Sep 17 00:00:00 2001 From: Victor Zhestkov Date: Thu, 1 Feb 2024 17:10:28 +0000 Subject: [PATCH] Accepting request 1143453 from home:PSuarezHernandez:branches:systemsmanagement:saltstack - Prevent directory traversal when creating syndic cache directory on the master (CVE-2024-22231, bsc#1219430) - Prevent directory traversal attacks in the master's serve_file method (CVE-2024-22232, bsc#1219431) - Added: * fix-cve-2024-22231-and-cve-2024-22232-bsc-1219430-bs.patch OBS-URL: https://build.opensuse.org/request/show/1143453 OBS-URL: https://build.opensuse.org/package/show/systemsmanagement:saltstack/salt?expand=0&rev=229 --- _lastrevision | 2 +- ...31-and-cve-2024-22232-bsc-1219430-bs.patch | 544 ++++++++++++++++++ salt.changes | 11 +- salt.spec | 53 +- 4 files changed, 570 insertions(+), 40 deletions(-) create mode 100644 fix-cve-2024-22231-and-cve-2024-22232-bsc-1219430-bs.patch diff --git a/_lastrevision b/_lastrevision index b59d1ee..e724caf 100644 --- a/_lastrevision +++ b/_lastrevision @@ -1 +1 @@ -d02a7d8eb7fdb302ed603f2c45525b41e812beb7 \ No newline at end of file +d0c2f35ff4a0b21786b20c884cbb191ad2e63904 \ No newline at end of file diff --git a/fix-cve-2024-22231-and-cve-2024-22232-bsc-1219430-bs.patch b/fix-cve-2024-22231-and-cve-2024-22232-bsc-1219430-bs.patch new file mode 100644 index 0000000..d08b5c1 --- /dev/null +++ b/fix-cve-2024-22231-and-cve-2024-22232-bsc-1219430-bs.patch @@ -0,0 +1,544 @@ +From 5710bc3ff3887762182f8326bd74f40d3872a69f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?= + +Date: Thu, 1 Feb 2024 11:50:16 +0000 +Subject: [PATCH] Fix "CVE-2024-22231" and "CVE-2024-22232" + (bsc#1219430, bsc#1219431) (#621) + +* Fix CVE-2024-22231 and CVE-2024-22232 + +* Add changelogs for CVE-2024-22231 and CVE-2024-22232 + +* Fix linter issue + +* Add credit + +* Fix wart in patch + +* Clean up test fixtures + +* Fix test on windows + +* Update changelog file name + +* Fix fileroots tests + +--------- + +Co-authored-by: Daniel A. Wozniak +--- + changelog/565.security.md | 4 + + salt/fileserver/__init__.py | 9 +- + salt/fileserver/roots.py | 26 +++++ + salt/master.py | 15 ++- + tests/pytests/unit/fileserver/test_roots.py | 58 +++++++-- + tests/pytests/unit/test_fileserver.py | 123 ++++++++++++++++++++ + tests/pytests/unit/test_master.py | 33 ++++++ + tests/unit/test_fileserver.py | 79 ------------- + 8 files changed, 250 insertions(+), 97 deletions(-) + create mode 100644 changelog/565.security.md + create mode 100644 tests/pytests/unit/test_fileserver.py + delete mode 100644 tests/unit/test_fileserver.py + +diff --git a/changelog/565.security.md b/changelog/565.security.md +new file mode 100644 +index 00000000000..5d7ec8202ba +--- /dev/null ++++ b/changelog/565.security.md +@@ -0,0 +1,4 @@ ++CVE-2024-22231 Prevent directory traversal when creating syndic cache directory on the master ++CVE-2024-22232 Prevent directory traversal attacks in the master's serve_file method. ++These vulerablities were discovered and reported by: ++Yudi Zhao(Huawei Nebula Security Lab),Chenwei Jiang(Huawei Nebula Security Lab) +diff --git a/salt/fileserver/__init__.py b/salt/fileserver/__init__.py +index 99f12387f91..4eca98d14a4 100644 +--- a/salt/fileserver/__init__.py ++++ b/salt/fileserver/__init__.py +@@ -568,11 +568,6 @@ class Fileserver: + saltenv = salt.utils.stringutils.to_unicode(saltenv) + back = self.backends(back) + kwargs = {} +- fnd = {"path": "", "rel": ""} +- if os.path.isabs(path): +- return fnd +- if "../" in path: +- return fnd + if salt.utils.url.is_escaped(path): + # don't attempt to find URL query arguments in the path + path = salt.utils.url.unescape(path) +@@ -588,6 +583,10 @@ class Fileserver: + args = comp.split("=", 1) + kwargs[args[0]] = args[1] + ++ fnd = {"path": "", "rel": ""} ++ if os.path.isabs(path) or "../" in path: ++ return fnd ++ + if "env" in kwargs: + # "env" is not supported; Use "saltenv". + kwargs.pop("env") +diff --git a/salt/fileserver/roots.py b/salt/fileserver/roots.py +index a02b597c6f8..e2ea92029c3 100644 +--- a/salt/fileserver/roots.py ++++ b/salt/fileserver/roots.py +@@ -27,6 +27,7 @@ import salt.utils.hashutils + import salt.utils.path + import salt.utils.platform + import salt.utils.stringutils ++import salt.utils.verify + import salt.utils.versions + + log = logging.getLogger(__name__) +@@ -98,6 +99,11 @@ def find_file(path, saltenv="base", **kwargs): + if saltenv == "__env__": + root = root.replace("__env__", actual_saltenv) + full = os.path.join(root, path) ++ ++ # Refuse to serve file that is not under the root. ++ if not salt.utils.verify.clean_path(root, full, subdir=True): ++ continue ++ + if os.path.isfile(full) and not salt.fileserver.is_file_ignored(__opts__, full): + fnd["path"] = full + fnd["rel"] = path +@@ -128,6 +134,26 @@ def serve_file(load, fnd): + ret["dest"] = fnd["rel"] + gzip = load.get("gzip", None) + fpath = os.path.normpath(fnd["path"]) ++ ++ actual_saltenv = saltenv = load["saltenv"] ++ if saltenv not in __opts__["file_roots"]: ++ if "__env__" in __opts__["file_roots"]: ++ log.debug( ++ "salt environment '%s' maps to __env__ file_roots directory", saltenv ++ ) ++ saltenv = "__env__" ++ else: ++ return fnd ++ file_in_root = False ++ for root in __opts__["file_roots"][saltenv]: ++ if saltenv == "__env__": ++ root = root.replace("__env__", actual_saltenv) ++ # Refuse to serve file that is not under the root. ++ if salt.utils.verify.clean_path(root, fpath, subdir=True): ++ file_in_root = True ++ if not file_in_root: ++ return ret ++ + with salt.utils.files.fopen(fpath, "rb") as fp_: + fp_.seek(load["loc"]) + data = fp_.read(__opts__["file_buffer_size"]) +diff --git a/salt/master.py b/salt/master.py +index 3d2ba1e29de..425b4121481 100644 +--- a/salt/master.py ++++ b/salt/master.py +@@ -1038,7 +1038,10 @@ class MWorker(salt.utils.process.SignalHandlingProcess): + """ + key = payload["enc"] + load = payload["load"] +- ret = {"aes": self._handle_aes, "clear": self._handle_clear}[key](load) ++ if key == "aes": ++ ret = self._handle_aes(load) ++ else: ++ ret = self._handle_clear(load) + raise salt.ext.tornado.gen.Return(ret) + + def _post_stats(self, start, cmd): +@@ -1213,7 +1216,7 @@ class AESFuncs(TransportMethods): + "_dir_list", + "_symlink_list", + "_file_envs", +- "_ext_nodes", # To keep compatibility with old Salt minion versions ++ "_ext_nodes", # To keep compatibility with old Salt minion versions + ) + + def __init__(self, opts, context=None): +@@ -1746,10 +1749,16 @@ class AESFuncs(TransportMethods): + self.mminion.returners[fstr](load["jid"], load["load"]) + + # Register the syndic ++ ++ # We are creating a path using user suplied input. Use the ++ # clean_path to prevent a directory traversal. ++ root = os.path.join(self.opts["cachedir"], "syndics") + syndic_cache_path = os.path.join( + self.opts["cachedir"], "syndics", load["id"] + ) +- if not os.path.exists(syndic_cache_path): ++ if salt.utils.verify.clean_path( ++ root, syndic_cache_path ++ ) and not os.path.exists(syndic_cache_path): + path_name = os.path.split(syndic_cache_path)[0] + if not os.path.exists(path_name): + os.makedirs(path_name) +diff --git a/tests/pytests/unit/fileserver/test_roots.py b/tests/pytests/unit/fileserver/test_roots.py +index 96bceb0fd3d..c1660280bc5 100644 +--- a/tests/pytests/unit/fileserver/test_roots.py ++++ b/tests/pytests/unit/fileserver/test_roots.py +@@ -5,6 +5,7 @@ + import copy + import pathlib + import shutil ++import sys + import textwrap + + import pytest +@@ -28,14 +29,14 @@ def unicode_dirname(): + return "соль" + + +-@pytest.fixture(autouse=True) ++@pytest.fixture + def testfile(tmp_path): + fp = tmp_path / "testfile" + fp.write_text("This is a testfile") + return fp + + +-@pytest.fixture(autouse=True) ++@pytest.fixture + def tmp_state_tree(tmp_path, testfile, unicode_filename, unicode_dirname): + dirname = tmp_path / "roots_tmp_state_tree" + dirname.mkdir(parents=True, exist_ok=True) +@@ -54,11 +55,15 @@ def tmp_state_tree(tmp_path, testfile, unicode_filename, unicode_dirname): + + + @pytest.fixture +-def configure_loader_modules(tmp_state_tree, temp_salt_master): +- opts = temp_salt_master.config.copy() ++def testfilepath(tmp_state_tree, testfile): ++ return tmp_state_tree / testfile.name ++ ++ ++@pytest.fixture ++def configure_loader_modules(tmp_state_tree, master_opts): + overrides = {"file_roots": {"base": [str(tmp_state_tree)]}} +- opts.update(overrides) +- return {roots: {"__opts__": opts}} ++ master_opts.update(overrides) ++ return {roots: {"__opts__": master_opts}} + + + def test_file_list(unicode_filename): +@@ -75,17 +80,17 @@ def test_find_file(tmp_state_tree): + assert full_path_to_file == ret["path"] + + +-def test_serve_file(testfile): ++def test_serve_file(testfilepath): + with patch.dict(roots.__opts__, {"file_buffer_size": 262144}): + load = { + "saltenv": "base", +- "path": str(testfile), ++ "path": str(testfilepath), + "loc": 0, + } +- fnd = {"path": str(testfile), "rel": "testfile"} ++ fnd = {"path": str(testfilepath), "rel": "testfile"} + ret = roots.serve_file(load, fnd) + +- with salt.utils.files.fopen(str(testfile), "rb") as fp_: ++ with salt.utils.files.fopen(str(testfilepath), "rb") as fp_: + data = fp_.read() + + assert ret == {"data": data, "dest": "testfile"} +@@ -277,3 +282,36 @@ def test_update_mtime_map_unicode_error(tmp_path): + }, + "backend": "roots", + } ++ ++ ++def test_find_file_not_in_root(tmp_state_tree): ++ """ ++ Fileroots should never 'find' a file that is outside of it's root. ++ """ ++ badfile = pathlib.Path(tmp_state_tree).parent / "bar" ++ badfile.write_text("Bad file") ++ badpath = f"../bar" ++ ret = roots.find_file(badpath) ++ assert ret == {"path": "", "rel": ""} ++ badpath = f"{tmp_state_tree / '..' / 'bar'}" ++ ret = roots.find_file(badpath) ++ assert ret == {"path": "", "rel": ""} ++ ++ ++def test_serve_file_not_in_root(tmp_state_tree): ++ """ ++ Fileroots should never 'serve' a file that is outside of it's root. ++ """ ++ badfile = pathlib.Path(tmp_state_tree).parent / "bar" ++ badfile.write_text("Bad file") ++ badpath = f"../bar" ++ load = {"path": "salt://|..\\bar", "saltenv": "base", "loc": 0} ++ fnd = { ++ "path": f"{tmp_state_tree / '..' / 'bar'}", ++ "rel": f"{pathlib.Path('..') / 'bar'}", ++ } ++ ret = roots.serve_file(load, fnd) ++ if "win" in sys.platform: ++ assert ret == {"data": "", "dest": "..\\bar"} ++ else: ++ assert ret == {"data": "", "dest": "../bar"} +diff --git a/tests/pytests/unit/test_fileserver.py b/tests/pytests/unit/test_fileserver.py +new file mode 100644 +index 00000000000..8dd3ea0a27d +--- /dev/null ++++ b/tests/pytests/unit/test_fileserver.py +@@ -0,0 +1,123 @@ ++import datetime ++import os ++import time ++ ++import salt.fileserver ++import salt.utils.files ++ ++ ++def test_diff_with_diffent_keys(): ++ """ ++ Test that different maps are indeed reported different ++ """ ++ map1 = {"file1": 1234} ++ map2 = {"file2": 1234} ++ assert salt.fileserver.diff_mtime_map(map1, map2) is True ++ ++ ++def test_diff_with_diffent_values(): ++ """ ++ Test that different maps are indeed reported different ++ """ ++ map1 = {"file1": 12345} ++ map2 = {"file1": 1234} ++ assert salt.fileserver.diff_mtime_map(map1, map2) is True ++ ++ ++def test_whitelist(): ++ opts = { ++ "fileserver_backend": ["roots", "git", "s3fs", "hgfs", "svn"], ++ "extension_modules": "", ++ } ++ fs = salt.fileserver.Fileserver(opts) ++ assert sorted(fs.servers.whitelist) == sorted( ++ ["git", "gitfs", "hg", "hgfs", "svn", "svnfs", "roots", "s3fs"] ++ ), fs.servers.whitelist ++ ++ ++def test_future_file_list_cache_file_ignored(tmp_path): ++ opts = { ++ "fileserver_backend": ["roots"], ++ "cachedir": tmp_path, ++ "extension_modules": "", ++ } ++ ++ back_cachedir = os.path.join(tmp_path, "file_lists/roots") ++ os.makedirs(os.path.join(back_cachedir)) ++ ++ # Touch a couple files ++ for filename in ("base.p", "foo.txt"): ++ with salt.utils.files.fopen(os.path.join(back_cachedir, filename), "wb") as _f: ++ if filename == "base.p": ++ _f.write(b"\x80") ++ ++ # Set modification time to file list cache file to 1 year in the future ++ now = datetime.datetime.utcnow() ++ future = now + datetime.timedelta(days=365) ++ mod_time = time.mktime(future.timetuple()) ++ os.utime(os.path.join(back_cachedir, "base.p"), (mod_time, mod_time)) ++ ++ list_cache = os.path.join(back_cachedir, "base.p") ++ w_lock = os.path.join(back_cachedir, ".base.w") ++ ret = salt.fileserver.check_file_list_cache(opts, "files", list_cache, w_lock) ++ assert ( ++ ret[1] is True ++ ), "Cache file list cache file is not refreshed when future modification time" ++ ++ ++def test_file_server_url_escape(tmp_path): ++ (tmp_path / "srv").mkdir() ++ (tmp_path / "srv" / "salt").mkdir() ++ (tmp_path / "foo").mkdir() ++ (tmp_path / "foo" / "bar").write_text("Bad file") ++ fileroot = str(tmp_path / "srv" / "salt") ++ badfile = str(tmp_path / "foo" / "bar") ++ opts = { ++ "fileserver_backend": ["roots"], ++ "extension_modules": "", ++ "optimization_order": [ ++ 0, ++ ], ++ "file_roots": { ++ "base": [fileroot], ++ }, ++ "file_ignore_regex": "", ++ "file_ignore_glob": "", ++ } ++ fs = salt.fileserver.Fileserver(opts) ++ ret = fs.find_file( ++ "salt://|..\\..\\..\\foo/bar", ++ "base", ++ ) ++ assert ret == {"path": "", "rel": ""} ++ ++ ++def test_file_server_serve_url_escape(tmp_path): ++ (tmp_path / "srv").mkdir() ++ (tmp_path / "srv" / "salt").mkdir() ++ (tmp_path / "foo").mkdir() ++ (tmp_path / "foo" / "bar").write_text("Bad file") ++ fileroot = str(tmp_path / "srv" / "salt") ++ badfile = str(tmp_path / "foo" / "bar") ++ opts = { ++ "fileserver_backend": ["roots"], ++ "extension_modules": "", ++ "optimization_order": [ ++ 0, ++ ], ++ "file_roots": { ++ "base": [fileroot], ++ }, ++ "file_ignore_regex": "", ++ "file_ignore_glob": "", ++ "file_buffer_size": 2048, ++ } ++ fs = salt.fileserver.Fileserver(opts) ++ ret = fs.serve_file( ++ { ++ "path": "salt://|..\\..\\..\\foo/bar", ++ "saltenv": "base", ++ "loc": 0, ++ } ++ ) ++ assert ret == {"data": "", "dest": ""} +diff --git a/tests/pytests/unit/test_master.py b/tests/pytests/unit/test_master.py +index 98c796912aa..d338307d1f8 100644 +--- a/tests/pytests/unit/test_master.py ++++ b/tests/pytests/unit/test_master.py +@@ -1,3 +1,4 @@ ++import pathlib + import time + + import pytest +@@ -249,3 +250,35 @@ def test_mworker_pass_context(): + loadler_pillars_mock.call_args_list[0][1].get("pack").get("__context__") + == test_context + ) ++ ++ ++def test_syndic_return_cache_dir_creation(encrypted_requests): ++ """master's cachedir for a syndic will be created by AESFuncs._syndic_return method""" ++ cachedir = pathlib.Path(encrypted_requests.opts["cachedir"]) ++ assert not (cachedir / "syndics").exists() ++ encrypted_requests._syndic_return( ++ { ++ "id": "mamajama", ++ "jid": "", ++ "return": {}, ++ } ++ ) ++ assert (cachedir / "syndics").exists() ++ assert (cachedir / "syndics" / "mamajama").exists() ++ ++ ++def test_syndic_return_cache_dir_creation_traversal(encrypted_requests): ++ """ ++ master's AESFuncs._syndic_return method cachdir creation is not vulnerable to a directory traversal ++ """ ++ cachedir = pathlib.Path(encrypted_requests.opts["cachedir"]) ++ assert not (cachedir / "syndics").exists() ++ encrypted_requests._syndic_return( ++ { ++ "id": "../mamajama", ++ "jid": "", ++ "return": {}, ++ } ++ ) ++ assert not (cachedir / "syndics").exists() ++ assert not (cachedir / "mamajama").exists() +diff --git a/tests/unit/test_fileserver.py b/tests/unit/test_fileserver.py +deleted file mode 100644 +index c290b16b7e4..00000000000 +--- a/tests/unit/test_fileserver.py ++++ /dev/null +@@ -1,79 +0,0 @@ +-""" +- :codeauthor: Joao Mesquita +-""" +- +- +-import datetime +-import os +-import time +- +-import salt.utils.files +-from salt import fileserver +-from tests.support.helpers import with_tempdir +-from tests.support.mixins import LoaderModuleMockMixin +-from tests.support.unit import TestCase +- +- +-class MapDiffTestCase(TestCase): +- def test_diff_with_diffent_keys(self): +- """ +- Test that different maps are indeed reported different +- """ +- map1 = {"file1": 1234} +- map2 = {"file2": 1234} +- assert fileserver.diff_mtime_map(map1, map2) is True +- +- def test_diff_with_diffent_values(self): +- """ +- Test that different maps are indeed reported different +- """ +- map1 = {"file1": 12345} +- map2 = {"file1": 1234} +- assert fileserver.diff_mtime_map(map1, map2) is True +- +- +-class VCSBackendWhitelistCase(TestCase, LoaderModuleMockMixin): +- def setup_loader_modules(self): +- return {fileserver: {}} +- +- def test_whitelist(self): +- opts = { +- "fileserver_backend": ["roots", "git", "s3fs", "hgfs", "svn"], +- "extension_modules": "", +- } +- fs = fileserver.Fileserver(opts) +- assert sorted(fs.servers.whitelist) == sorted( +- ["git", "gitfs", "hg", "hgfs", "svn", "svnfs", "roots", "s3fs"] +- ), fs.servers.whitelist +- +- @with_tempdir() +- def test_future_file_list_cache_file_ignored(self, cachedir): +- opts = { +- "fileserver_backend": ["roots"], +- "cachedir": cachedir, +- "extension_modules": "", +- } +- +- back_cachedir = os.path.join(cachedir, "file_lists/roots") +- os.makedirs(os.path.join(back_cachedir)) +- +- # Touch a couple files +- for filename in ("base.p", "foo.txt"): +- with salt.utils.files.fopen( +- os.path.join(back_cachedir, filename), "wb" +- ) as _f: +- if filename == "base.p": +- _f.write(b"\x80") +- +- # Set modification time to file list cache file to 1 year in the future +- now = datetime.datetime.utcnow() +- future = now + datetime.timedelta(days=365) +- mod_time = time.mktime(future.timetuple()) +- os.utime(os.path.join(back_cachedir, "base.p"), (mod_time, mod_time)) +- +- list_cache = os.path.join(back_cachedir, "base.p") +- w_lock = os.path.join(back_cachedir, ".base.w") +- ret = fileserver.check_file_list_cache(opts, "files", list_cache, w_lock) +- assert ( +- ret[1] is True +- ), "Cache file list cache file is not refreshed when future modification time" +-- +2.43.0 + + diff --git a/salt.changes b/salt.changes index 6df6ef5..8ff75b9 100644 --- a/salt.changes +++ b/salt.changes @@ -1,8 +1,13 @@ ------------------------------------------------------------------- -Tue Jan 30 09:40:18 UTC 2024 - Pablo Suárez Hernández +Thu Feb 1 12:19:06 UTC 2024 - Pablo Suárez Hernández -- Remove python-boto dependency for the python3-salt-testsuite package for Tumbleweed -- Rename salt-tests to python3-salt-testsuite +- Prevent directory traversal when creating syndic cache directory + on the master (CVE-2024-22231, bsc#1219430) +- Prevent directory traversal attacks in the master's serve_file + method (CVE-2024-22232, bsc#1219431) + +- Added: + * fix-cve-2024-22231-and-cve-2024-22232-bsc-1219430-bs.patch ------------------------------------------------------------------- Mon Jan 29 13:50:44 UTC 2024 - Pablo Suárez Hernández diff --git a/salt.spec b/salt.spec index 4d352da..eaef8ff 100644 --- a/salt.spec +++ b/salt.spec @@ -335,12 +335,14 @@ Patch93: prefer-unittest.mock-for-python-versions-that-are-su.patch Patch94: fix-the-aptpkg.py-unit-test-failure.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/65092 Patch95: update-__pillar__-during-pillar_refresh.patch +# PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/65969 +Patch96: fix-cve-2024-22231-and-cve-2024-22232-bsc-1219430-bs.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/65009 -Patch96: fixed-keyerror-in-logs-when-running-a-state-that-fai.patch +Patch97: fixed-keyerror-in-logs-when-running-a-state-that-fai.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/65562 -Patch97: improve-pip-target-override-condition-with-venv_pip_.patch +Patch98: improve-pip-target-override-condition-with-venv_pip_.patch # PATCH-FIX_UPSTREAM https://github.com/saltstack/salt/pull/65819 -Patch98: allow-kwargs-for-fileserver-roots-update-bsc-1218482.patch +Patch99: allow-kwargs-for-fileserver-roots-update-bsc-1218482.patch ### IMPORTANT: The line below is used as a snippet marker. Do not touch it. @@ -699,30 +701,12 @@ Requires(pre): %fillup_prereq Salt ssh is a master running without zmq. it enables the management of minions over a ssh connection. -%package -n python3-salt-testsuite +%package tests Summary: Unit and integration tests for Salt Requires: %{name} = %{version}-%{release} -Requires: python3-CherryPy -Requires: python3-Genshi -Requires: python3-Mako -%if !0%{?suse_version} > 1600 || 0%{?centos} -Requires: python3-boto -%endif -Requires: python3-boto3 -Requires: python3-docker -Requires: python3-mock -Requires: python3-pygit2 -Requires: python3-pytest >= 7.0.1 -Requires: python3-pytest-httpserver -Requires: python3-pytest-salt-factories >= 1.0.0~rc21 -Requires: python3-pytest-subtests -Requires: python3-testinfra -Requires: python3-yamllint -Obsoletes: %{name}-tests - -%description -n python3-salt-testsuite -Collection of unit, functional, and integration tests for %{name}. +%description tests +Collections of unit and integration tests for Salt %if %{with bash_completion} %package bash-completion @@ -870,12 +854,10 @@ install -Dd -m 0755 %{buildroot}%{_sysconfdir}/logrotate.d/ install -Dpm 0644 salt/cli/support/profiles/* %{buildroot}%{python3_sitelib}/salt/cli/support/profiles # Install Salt tests -install -Dd %{buildroot}%{python3_sitelib}/salt-testsuite -cp -a tests %{buildroot}%{python3_sitelib}/salt-testsuite/ -# Remove runtests.py which is not used as deprecated method of running the tests -rm %{buildroot}%{python3_sitelib}/salt-testsuite/tests/runtests.py -# Copy conf files to the testsuite as they are used by the tests -cp -a conf %{buildroot}%{python3_sitelib}/salt-testsuite/ +install -Dd -m 0750 %{buildroot}%{_datadir}/salt +install -Dd -m 0750 %{buildroot}%{_datadir}/salt/tests +cp -a tests/* %{buildroot}%{_datadir}/salt/tests/ +sed -i '1s=^#!/usr/bin/\(python\|env python\)[0-9.]*=#!/usr/bin/python3=' %{buildroot}%{_datadir}/salt/tests/runtests.py ## Install Zypper plugins only on SUSE machines %if 0%{?suse_version} @@ -1452,10 +1434,7 @@ rm -f %{_localstatedir}/cache/salt/minion/thin/version %files -n python3-salt %defattr(-,root,root,-) -%dir %{python3_sitelib}/salt -%dir %{python3_sitelib}/salt-*.egg-info -%{python3_sitelib}/salt/* -%{python3_sitelib}/salt-*.egg-info/* +%{python3_sitelib}/* %exclude %{python3_sitelib}/salt/cloud/deploy/*.sh %if %{with docs} @@ -1464,8 +1443,10 @@ rm -f %{_localstatedir}/cache/salt/minion/thin/version %doc doc/_build/html %endif -%files -n python3-salt-testsuite -%{python3_sitelib}/salt-testsuite +%files tests +%dir %{_datadir}/salt/ +%dir %{_datadir}/salt/tests/ +%{_datadir}/salt/tests/* %if %{with bash_completion} %files bash-completion