Skip to content

Commit f372c74

Browse files
authored
Merge branch 'main' into add-build-constraints
2 parents e53db93 + f49a2d9 commit f372c74

File tree

8 files changed

+41
-17
lines changed

8 files changed

+41
-17
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ jobs:
115115
strategy:
116116
fail-fast: true
117117
matrix:
118-
os: [ubuntu-22.04, macos-13, macos-latest]
118+
os: [ubuntu-22.04, macos-latest]
119119
python:
120120
- "3.9"
121121
- "3.10"

docs/html/development/architecture/anatomy.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ The ``README``, license, ``pyproject.toml``, and so on are in the top level.
3030
* ``html/`` *[sources to HTML documentation avail. online]*
3131
* ``man/`` has man pages the distros can use by running ``man pip``
3232
* ``pip_sphinxext.py`` *[an extension -- pip-specific plugins to Sphinx that do not apply to other packages]*
33-
* ``requirements.txt``
3433

3534
* ``news/`` *[pip stores news fragments… Every time pip makes a user-facing change, a file is added to this directory (usually a short note referring to a GitHub issue) with the right extension & name so it gets included in changelog…. So every release the maintainers will be deleting old files in this directory? Yes - we use the towncrier automation to generate a NEWS file, and auto-delete old stuff. There’s more about this in the contributor documentation!]*
3635

news/13528.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Ensure the self-check files in the cache has same permissions as the rest of the cache.

pyproject.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@ include = [
104104
"build-project/build-project.py",
105105
"build-project/build-requirements.in",
106106
"build-project/build-requirements.txt",
107-
"docs/requirements.txt",
108107
"docs/**/*.css",
109108
"docs/**/*.dot",
110109
"docs/**/*.md",
@@ -272,6 +271,11 @@ max-branches = 28 # default is 12
272271
max-returns = 13 # default is 6
273272
max-statements = 134 # default is 50
274273

274+
[tool.ruff.per-file-target-version]
275+
# `__pip-runner__.py` should be Python 2.7 compatible but the
276+
# earliest version of Python ruff will check is 3.7
277+
"src/pip/__pip-runner__.py" = "py37"
278+
275279
######################################################################################
276280
# mypy
277281
#

src/pip/_internal/network/cache.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313
from pip._vendor.cachecontrol.caches import SeparateBodyFileCache
1414
from pip._vendor.requests.models import Response
1515

16-
from pip._internal.utils.filesystem import adjacent_tmp_file, replace
16+
from pip._internal.utils.filesystem import (
17+
adjacent_tmp_file,
18+
copy_directory_permissions,
19+
replace,
20+
)
1721
from pip._internal.utils.misc import ensure_dir
1822

1923

@@ -82,16 +86,7 @@ def _write_to_file(self, path: str, writer_func: Callable[[BinaryIO], Any]) -> N
8286
writer_func(f)
8387
# Inherit the read/write permissions of the cache directory
8488
# to enable multi-user cache use-cases.
85-
mode = (
86-
os.stat(self.directory).st_mode
87-
& 0o666 # select read/write permissions of cache directory
88-
| 0o600 # set owner read/write permissions
89-
)
90-
# Change permissions only if there is no risk of following a symlink.
91-
if os.chmod in os.supports_fd:
92-
os.chmod(f.fileno(), mode)
93-
elif os.chmod in os.supports_follow_symlinks:
94-
os.chmod(f.name, mode, follow_symlinks=False)
89+
copy_directory_permissions(self.directory, f)
9590

9691
replace(f.name, path)
9792

src/pip/_internal/self_outdated_check.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,12 @@
2727
get_best_invocation_for_this_pip,
2828
get_best_invocation_for_this_python,
2929
)
30-
from pip._internal.utils.filesystem import adjacent_tmp_file, check_path_owner, replace
30+
from pip._internal.utils.filesystem import (
31+
adjacent_tmp_file,
32+
check_path_owner,
33+
copy_directory_permissions,
34+
replace,
35+
)
3136
from pip._internal.utils.misc import (
3237
ExternallyManagedEnvironment,
3338
check_externally_managed,
@@ -100,13 +105,15 @@ def set(self, pypi_version: str, current_time: datetime.datetime) -> None:
100105
if not self._statefile_path:
101106
return
102107

108+
statefile_directory = os.path.dirname(self._statefile_path)
109+
103110
# Check to make sure that we own the directory
104-
if not check_path_owner(os.path.dirname(self._statefile_path)):
111+
if not check_path_owner(statefile_directory):
105112
return
106113

107114
# Now that we've ensured the directory is owned by this user, we'll go
108115
# ahead and make sure that all our directories are created.
109-
ensure_dir(os.path.dirname(self._statefile_path))
116+
ensure_dir(statefile_directory)
110117

111118
state = {
112119
# Include the key so it's easy to tell which pip wrote the
@@ -120,6 +127,7 @@ def set(self, pypi_version: str, current_time: datetime.datetime) -> None:
120127

121128
with adjacent_tmp_file(self._statefile_path) as f:
122129
f.write(text.encode())
130+
copy_directory_permissions(statefile_directory, f)
123131

124132
try:
125133
# Since we have a prefix-specific state file, we can just

src/pip/_internal/utils/filesystem.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,3 +150,15 @@ def directory_size(path: str) -> int | float:
150150

151151
def format_directory_size(path: str) -> str:
152152
return format_size(directory_size(path))
153+
154+
155+
def copy_directory_permissions(directory: str, target_file: BinaryIO) -> None:
156+
mode = (
157+
os.stat(directory).st_mode & 0o666 # select read/write permissions of directory
158+
| 0o600 # set owner read/write permissions
159+
)
160+
# Change permissions only if there is no risk of following a symlink.
161+
if os.chmod in os.supports_fd:
162+
os.chmod(target_file.fileno(), mode)
163+
elif os.chmod in os.supports_follow_symlinks:
164+
os.chmod(target_file.name, mode, follow_symlinks=False)

tests/unit/test_self_check_outdated.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,11 @@ def test_writes_expected_statefile(self, tmpdir: Path) -> None:
189189
"last_check": "2000-01-01T00:00:00+00:00",
190190
"pypi_version": "1.0.0",
191191
}
192+
# Check that the self-check cache entries inherit the root cache permissions.
193+
statefile_permissions = os.stat(expected_path).st_mode & 0o666
194+
selfcheckdir_permissions = os.stat(cache_dir / "selfcheck").st_mode & 0o666
195+
cache_permissions = os.stat(cache_dir).st_mode & 0o666
196+
assert statefile_permissions == selfcheckdir_permissions == cache_permissions
192197

193198

194199
@patch("pip._internal.self_outdated_check._self_version_check_logic")

0 commit comments

Comments
 (0)