Skip to content

Commit 7e42f32

Browse files
authored
Merge branch '3.10' into backport-9768834-3.10
2 parents 18dfe06 + dac88d8 commit 7e42f32

20 files changed

Lines changed: 356 additions & 105 deletions

‎.github/workflows/build.yml‎

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
run_tests: ${{ steps.check.outputs.run_tests }}
3131
run_ssl_tests: ${{ steps.check.outputs.run_ssl_tests }}
3232
steps:
33-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
33+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
3434
- name: Check for source changes
3535
id: check
3636
run: |
@@ -59,13 +59,14 @@ jobs:
5959
check_abi:
6060
name: 'Check if the ABI has changed'
6161
runs-on: ubuntu-22.04 # 24.04 causes spurious errors
62+
timeout-minutes: 30
6263
needs: check_source
6364
if: needs.check_source.outputs.run_tests == 'true'
6465
steps:
65-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
66+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
6667
with:
6768
persist-credentials: false
68-
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
69+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
6970
- name: Install dependencies
7071
run: |
7172
sudo ./.github/workflows/posix-deps-apt.sh
@@ -97,16 +98,16 @@ jobs:
9798
needs: check_source
9899
if: needs.check_source.outputs.run_tests == 'true'
99100
steps:
100-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
101+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
101102
with:
102103
persist-credentials: false
103-
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
104+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
104105
- name: Install dependencies
105106
run: sudo ./.github/workflows/posix-deps-apt.sh
106107
- name: Add ccache to PATH
107108
run: echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
108109
- name: Configure ccache action
109-
uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
110+
uses: hendrikmuhs/ccache-action@f09c25b45002a07be2955cbe52e8cee55643f89d # v1.2.24
110111
- name: Check Autoconf version 2.69 and aclocal 1.16.3
111112
run: |
112113
grep "Generated by GNU Autoconf 2.69" configure
@@ -149,7 +150,7 @@ jobs:
149150
env:
150151
IncludeUwp: 'true'
151152
steps:
152-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
153+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
153154
- name: Build CPython
154155
run: .\PCbuild\build.bat -e -p Win32
155156
- name: Display build info
@@ -165,7 +166,7 @@ jobs:
165166
env:
166167
IncludeUwp: 'true'
167168
steps:
168-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
169+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
169170
- name: Register MSVC problem matcher
170171
run: echo "::add-matcher::.github/problem-matchers/msvc.json"
171172
- name: Build CPython
@@ -186,7 +187,7 @@ jobs:
186187
HOMEBREW_NO_INSTALL_CLEANUP: 1
187188
PYTHONSTRICTEXTENSIONBUILD: 1
188189
steps:
189-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
190+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
190191
- name: Install Homebrew dependencies
191192
run: |
192193
brew bundle --file=Misc/Brewfile
@@ -218,7 +219,7 @@ jobs:
218219
OPENSSL_VER: 3.0.11
219220
PYTHONSTRICTEXTENSIONBUILD: 1
220221
steps:
221-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
222+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
222223
- name: Register gcc problem matcher
223224
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
224225
- name: Install dependencies
@@ -230,7 +231,7 @@ jobs:
230231
echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV"
231232
- name: 'Restore OpenSSL build'
232233
id: cache-openssl
233-
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
234+
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
234235
with:
235236
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
236237
key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
@@ -241,7 +242,7 @@ jobs:
241242
run: |
242243
echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
243244
- name: Configure ccache action
244-
uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
245+
uses: hendrikmuhs/ccache-action@f09c25b45002a07be2955cbe52e8cee55643f89d # v1.2.24
245246
- name: Configure CPython
246247
run: ./configure --with-pydebug --with-openssl=$OPENSSL_DIR
247248
- name: Build CPython
@@ -267,7 +268,7 @@ jobs:
267268
OPENSSL_DIR: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}
268269
LD_LIBRARY_PATH: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}/lib
269270
steps:
270-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
271+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
271272
with:
272273
persist-credentials: false
273274
- name: Register gcc problem matcher
@@ -281,7 +282,7 @@ jobs:
281282
echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> "$GITHUB_ENV"
282283
- name: 'Restore OpenSSL build'
283284
id: cache-openssl
284-
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
285+
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
285286
with:
286287
path: ./multissl/openssl/${{ env.OPENSSL_VER }}
287288
key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
@@ -292,7 +293,7 @@ jobs:
292293
run: |
293294
echo "PATH=/usr/lib/ccache:$PATH" >> "$GITHUB_ENV"
294295
- name: Configure ccache action
295-
uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
296+
uses: hendrikmuhs/ccache-action@f09c25b45002a07be2955cbe52e8cee55643f89d # v1.2.24
296297
- name: Configure CPython
297298
run: ./configure --with-pydebug --with-openssl=$OPENSSL_DIR
298299
- name: Build CPython

‎.github/workflows/doc.yml‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ jobs:
3232
name: 'Docs'
3333
runs-on: ubuntu-latest
3434
steps:
35-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
35+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
3636
- name: Register Sphinx problem matcher
3737
run: echo "::add-matcher::.github/problem-matchers/sphinx.json"
3838
- name: 'Set up Python'
39-
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
39+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
4040
with:
4141
python-version: '3.12'
4242
cache: 'pip'
@@ -46,7 +46,7 @@ jobs:
4646
- name: 'Build HTML documentation'
4747
run: make -C Doc/ SPHINXOPTS="-q" SPHINXERRORHANDLING="-W --keep-going" html
4848
- name: 'Upload'
49-
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
49+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
5050
with:
5151
name: doc-html
5252
path: Doc/build/html
@@ -58,10 +58,10 @@ jobs:
5858
name: 'Doctest'
5959
runs-on: ubuntu-latest
6060
steps:
61-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
61+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
6262
- name: Register Sphinx problem matcher
6363
run: echo "::add-matcher::.github/problem-matchers/sphinx.json"
64-
- uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
64+
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
6565
with:
6666
path: ~/.cache/pip
6767
key: ubuntu-doc-${{ hashFiles('Doc/requirements.txt') }}

‎.github/workflows/stale.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717

1818
steps:
1919
- name: "Check PRs"
20-
uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0
20+
uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11.0.0
2121
with:
2222
repo-token: ${{ secrets.GITHUB_TOKEN }}
2323
stale-pr-message: 'This PR is stale because it has been open for 30 days with no activity.'

‎.github/workflows/verify-ensurepip-wheels.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ jobs:
2424
verify:
2525
runs-on: ubuntu-latest
2626
steps:
27-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
28-
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
27+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
28+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
2929
with:
3030
python-version: '3'
3131
- name: Compare checksums of bundled pip and setuptools to ones published on PyPI

‎.github/workflows/verify-expat.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
runs-on: ubuntu-latest
2424
timeout-minutes: 5
2525
steps:
26-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
26+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
2727
with:
2828
persist-credentials: false
2929
- name: Download and verify bundled libexpat files

‎Doc/library/urllib.request.rst‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -922,8 +922,14 @@ These methods are available on :class:`HTTPPasswordMgr` and
922922

923923
*uri* can be either a single URI, or a sequence of URIs. *realm*, *user* and
924924
*passwd* must be strings. This causes ``(user, passwd)`` to be used as
925-
authentication tokens when authentication for *realm* and a super-URI of any of
926-
the given URIs is given.
925+
authentication tokens when authentication for *realm* and a super-URI of any
926+
of the given URIs is given. If a URI includes a scheme, its credentials only
927+
match authentication URIs with the same scheme or no scheme. A URI without a
928+
scheme matches authentication URIs with any scheme.
929+
930+
.. versionchanged:: next
931+
Authentication credentials for URIs with a scheme are now scoped by
932+
that scheme.
927933

928934

929935
.. method:: HTTPPasswordMgr.find_user_password(realm, authuri)

‎Lib/tarfile.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2655,7 +2655,11 @@ def makelink_with_filter(self, tarinfo, targetpath,
26552655
return
26562656
else:
26572657
if os.path.exists(tarinfo._link_target):
2658-
os.link(tarinfo._link_target, targetpath)
2658+
# Resolve the target so the hard link points to the file
2659+
# itself. Otherwise os.link() may duplicate a symlink to a
2660+
# shallower location, where it's relative target escapes the
2661+
# destination directory. (CVE-2026-82049)
2662+
os.link(os.path.realpath(tarinfo._link_target), targetpath)
26592663
return
26602664
except symlink_exception:
26612665
keyerror_to_extracterror = True

‎Lib/test/support/os_helper.py‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import unittest
1010
import warnings
1111

12+
from test import support
13+
1214

1315
# Filename used for testing
1416
if os.name == 'java':
@@ -190,6 +192,24 @@ def skip_unless_symlink(test):
190192
return test if ok else unittest.skip(msg)(test)
191193

192194

195+
_can_hardlink = None
196+
197+
198+
def can_hardlink():
199+
global _can_hardlink
200+
if _can_hardlink is None:
201+
# Android blocks hard links using SELinux
202+
# (https://stackoverflow.com/q/32365690).
203+
_can_hardlink = hasattr(os, "link") and not support.is_android
204+
return _can_hardlink
205+
206+
207+
def skip_unless_hardlink(test):
208+
ok = can_hardlink()
209+
msg = "requires hardlink support"
210+
return test if ok else unittest.skip(msg)(test)
211+
212+
193213
_can_xattr = None
194214

195215

‎Lib/test/test_tarfile.py‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4024,6 +4024,23 @@ def test_sneaky_hardlink_fallback_deep(self):
40244024
self.expect_file("a/b/s", symlink_to=os.path.join('..', 'escape'))
40254025
self.expect_file("s", symlink_to=os.path.join('..', 'escape'))
40264026

4027+
@os_helper.skip_unless_hardlink
4028+
def test_sneaky_hardlink_relocation(self):
4029+
with ArchiveMaker() as arc:
4030+
arc.add("a/escape", content="decoy")
4031+
arc.add("a/b/s", symlink_to=os.path.join("..", "escape"))
4032+
arc.add("s", hardlink_to=os.path.join("a", "b", "s"))
4033+
4034+
for filter in 'data', 'tar':
4035+
with self.subTest(filter), self.check_context(arc.open(), filter):
4036+
self.expect_file("a/escape", content="decoy")
4037+
if os_helper.can_symlink():
4038+
self.expect_file("a/b/s", symlink_to=os.path.join('..', 'escape'))
4039+
else:
4040+
self.expect_file("a/b/s", content="decoy")
4041+
self.expect_file("s", content="decoy")
4042+
self.assertFalse((self.destdir / "s").is_symlink())
4043+
40274044
def test_exfiltration_via_symlink(self):
40284045
# (CVE-2025-4138)
40294046
# Test changing symlinks that result in a symlink pointing outside

‎Lib/test/test_urllib2.py‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,50 @@ def test_password_manager_default_port(self):
269269
self.assertEqual(find_user_pass("i", "http://j.example.com:80"),
270270
(None, None))
271271

272+
def test_password_manager_scheme(self):
273+
mgr = urllib.request.HTTPPasswordMgr()
274+
mgr.add_password(
275+
"realm", "https://example.com/", "user", "password")
276+
277+
self.assertEqual(
278+
mgr.find_user_password("realm", "https://example.com/"),
279+
("user", "password"))
280+
self.assertEqual(
281+
mgr.find_user_password("realm", "http://example.com/"),
282+
(None, None))
283+
# Support an authority without a scheme.
284+
self.assertEqual(
285+
mgr.find_user_password("realm", "example.com"),
286+
("user", "password"))
287+
# An authority without a scheme continues to match any scheme.
288+
mgr.add_password(
289+
"realm", "schemeless.example.com", "user", "password")
290+
for scheme in "http", "https":
291+
with self.subTest(scheme=scheme):
292+
self.assertEqual(
293+
mgr.find_user_password(
294+
"realm", f"{scheme}://schemeless.example.com/"),
295+
("user", "password"))
296+
297+
# A network-path reference also has no scheme.
298+
mgr.add_password(
299+
"realm", "//network-path.example.com/", "user", "password")
300+
self.assertEqual(
301+
mgr.find_user_password(
302+
"realm", "https://network-path.example.com/"),
303+
("user", "password"))
304+
305+
def test_password_manager_reduced_uri(self):
306+
mgr = urllib.request.HTTPPasswordMgr()
307+
308+
self.assertEqual(
309+
mgr.reduce_uri("http://example.com/path"),
310+
("example.com:80", "/path"))
311+
self.assertTrue(
312+
mgr.is_suburi(
313+
("example.com", "/path"),
314+
("example.com", "/path/subpath")))
315+
272316

273317
class MockOpener:
274318
addheaders = []
@@ -1712,6 +1756,18 @@ def test_basic_prior_auth_auto_send(self):
17121756
# expect request to be sent with auth header
17131757
self.assertTrue(http_handler.has_auth_header)
17141758

1759+
def test_basic_prior_auth_different_scheme(self):
1760+
pwd_manager = HTTPPasswordMgrWithPriorAuth()
1761+
auth_handler = HTTPBasicAuthHandler(pwd_manager)
1762+
auth_handler.add_password(
1763+
None, "https://example.com/", "user", "password",
1764+
is_authenticated=True)
1765+
1766+
request = Request("http://example.com/")
1767+
auth_handler.http_request(request)
1768+
1769+
self.assertFalse(request.has_header("Authorization"))
1770+
17151771
def test_basic_prior_auth_send_after_first_success(self):
17161772
# Auto send auth header after authentication is successful once
17171773

0 commit comments

Comments
 (0)