From 2b671b5f9208650e8e42e07782d95477cc41f42a Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Wed, 15 May 2024 10:57:10 +0300 Subject: [PATCH] [8.2.x] cacheprovider: fix `.pytest_cache` not being world-readable --- changelog/12308.bugfix.rst | 1 + src/_pytest/cacheprovider.py | 7 +++++++ testing/test_cacheprovider.py | 15 +++++++++++++++ 3 files changed, 23 insertions(+) create mode 100644 changelog/12308.bugfix.rst diff --git a/changelog/12308.bugfix.rst b/changelog/12308.bugfix.rst new file mode 100644 index 00000000000..07995427a1a --- /dev/null +++ b/changelog/12308.bugfix.rst @@ -0,0 +1 @@ +Fix a regression in pytest 8.2.0 where the permissions of automatically-created ``.pytest_cache`` directories became ``rwx------`` instead of the expected ``rwxr-xr-x``. diff --git a/src/_pytest/cacheprovider.py b/src/_pytest/cacheprovider.py index e9f66f1f44f..7a77dd3de85 100755 --- a/src/_pytest/cacheprovider.py +++ b/src/_pytest/cacheprovider.py @@ -213,6 +213,13 @@ def _ensure_cache_dir_and_supporting_files(self) -> None: dir=self._cachedir.parent, ) as newpath: path = Path(newpath) + + # Reset permissions to the default, see #12308. + # Note: there's no way to get the current umask atomically, eek. + umask = os.umask(0o022) + os.umask(umask) + path.chmod(0o777 - umask) + with open(path.joinpath("README.md"), "xt", encoding="UTF-8") as f: f.write(README_CONTENT) with open(path.joinpath(".gitignore"), "xt", encoding="UTF-8") as f: diff --git a/testing/test_cacheprovider.py b/testing/test_cacheprovider.py index 304e5414abc..d623bcff39e 100644 --- a/testing/test_cacheprovider.py +++ b/testing/test_cacheprovider.py @@ -31,6 +31,21 @@ def test_config_cache_mkdir(self, pytester: Pytester) -> None: p = config.cache.mkdir("name") assert p.is_dir() + def test_cache_dir_permissions(self, pytester: Pytester) -> None: + """The .pytest_cache directory should have world-readable permissions + (depending on umask). + + Regression test for #12308. + """ + pytester.makeini("[pytest]") + config = pytester.parseconfigure() + assert config.cache is not None + p = config.cache.mkdir("name") + assert p.is_dir() + # Instead of messing with umask, make sure .pytest_cache has the same + # permissions as the default that `mkdir` gives `p`. + assert (p.parent.stat().st_mode & 0o777) == (p.stat().st_mode & 0o777) + def test_config_cache_dataerror(self, pytester: Pytester) -> None: pytester.makeini("[pytest]") config = pytester.parseconfigure()