diff --git a/changelog/61829.fixed b/changelog/61829.fixed new file mode 100644 index 000000000000..b41ba41e640e --- /dev/null +++ b/changelog/61829.fixed @@ -0,0 +1 @@ +Ensure that `salt://` URIs never contain backslashes, converting them to forward slashes instead. A specific situation to handle is caching files on Windows minions, where Jinja relative imports introduce a backslash into the path. diff --git a/salt/utils/url.py b/salt/utils/url.py index 5a3cbfeaad63..a30610394c13 100644 --- a/salt/utils/url.py +++ b/salt/utils/url.py @@ -41,6 +41,7 @@ def create(path, saltenv=None): """ join `path` and `saltenv` into a 'salt://' URL. """ + path = path.replace("\\", "/") if salt.utils.platform.is_windows(): path = salt.utils.path.sanitize_win_path(path) path = salt.utils.data.decode(path) diff --git a/tests/pytests/unit/utils/jinja/test_salt_cache_loader.py b/tests/pytests/unit/utils/jinja/test_salt_cache_loader.py index 54c7edd6ab9b..d7d989368294 100644 --- a/tests/pytests/unit/utils/jinja/test_salt_cache_loader.py +++ b/tests/pytests/unit/utils/jinja/test_salt_cache_loader.py @@ -176,8 +176,8 @@ def test_relative_import( result = tmpl.render() assert result == "Hey world !a b !" assert len(fc.requests) == 3 - assert fc.requests[0]["path"] == os.path.join("salt://relative", "rhello") - assert fc.requests[1]["path"] == os.path.join("salt://relative", "rmacro") + assert fc.requests[0]["path"] == "salt://relative/rhello" + assert fc.requests[1]["path"] == "salt://relative/rmacro" assert fc.requests[2]["path"] == "salt://macro" # This must fail when rendered: attempts to import from outside file root template = jinja.get_template("relative/rescape") diff --git a/tests/unit/utils/test_url.py b/tests/unit/utils/test_url.py index 1029b93a91be..fa30b91c0c4d 100644 --- a/tests/unit/utils/test_url.py +++ b/tests/unit/utils/test_url.py @@ -68,6 +68,32 @@ def test_create_url_saltenv(self): self.assertEqual(salt.utils.url.create(path, saltenv), url) + def test_create_url_with_backslash_in_path(self): + """ + Test creating a 'salt://' URL + """ + src_path = r"? interesting\&path.filetype" + tgt_path = "? interesting/&path.filetype" + url = "salt://" + tgt_path + if salt.utils.platform.is_windows(): + url = "salt://_ interesting/&path.filetype" + + self.assertEqual(salt.utils.url.create(src_path), url) + + def test_create_url_saltenv_with_backslash_in_path(self): + """ + Test creating a 'salt://' URL with a saltenv + """ + saltenv = "raumklang" + src_path = r"? interesting\&path.filetype" + tgt_path = "? interesting/&path.filetype" + if salt.utils.platform.is_windows(): + tgt_path = "_ interesting/&path.filetype" + + url = "salt://" + tgt_path + "?saltenv=" + saltenv + + self.assertEqual(salt.utils.url.create(src_path, saltenv), url) + # is_escaped tests def test_is_escaped_windows(self):