Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python315 for openSUSE:Factory checked in at 2026-04-28 11:58:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python315 (Old) and /work/SRC/openSUSE:Factory/.python315.new.11940 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python315" Tue Apr 28 11:58:28 2026 rev:12 rq:1349644 version:3.15.0~a8 Changes: -------- --- /work/SRC/openSUSE:Factory/python315/python315.changes 2026-04-19 14:21:24.202190211 +0200 +++ /work/SRC/openSUSE:Factory/.python315.new.11940/python315.changes 2026-04-28 12:02:28.244710567 +0200 @@ -1,0 +2,35 @@ +Mon Apr 27 13:48:41 UTC 2026 - Matej Cepl <[email protected]> + +- Add CVE-2026-6019-Morsel-js_output.patch protects against HTML + injection by Base64-encoding cookie values embedded in JS + (bsc#1262654, CVE-2026-6019, gh#python/cpython#90309). + +------------------------------------------------------------------- +Sat Apr 25 16:42:59 UTC 2026 - Matej Cepl <[email protected]> + +- Add CVE-2026-1502-reject-CRLF-HTTP-tunnel.patch which rejects + CR/LF in HTTP tunnel request headers (bsc#1261969, + CVE-2026-1502, gh#python/cpython#146211). + +------------------------------------------------------------------- +Sat Apr 25 12:31:50 UTC 2026 - Matej Cepl <[email protected]> + +- Add CVE-2026-5713-validate-debug-load.patch, which validates + remote debug offset tables on load (bsc#1262132, CVE-2026-5713, + gh#python/cpython#148178). + +------------------------------------------------------------------- +Sat Apr 25 00:14:50 UTC 2026 - Matej Cepl <[email protected]> + +- Add CVE-2026-4786-webbrowser-open-action.patch, which fixes + webbrowser %action substitution bypass of dash-prefix check + (bsc#1262319, CVE-2026-4786, gh#python/cpython#148169). + +------------------------------------------------------------------- +Fri Apr 24 17:15:39 UTC 2026 - Matej Cepl <[email protected]> + +- Add CVE-2026-6100-use-after-free-decompression.patch preventing + dangling pointer which can end in the use-after-free error + (CVE-2026-6100, bsc#1262098, gh#python/cpython#148395). + +------------------------------------------------------------------- New: ---- CVE-2026-1502-reject-CRLF-HTTP-tunnel.patch CVE-2026-4786-webbrowser-open-action.patch CVE-2026-5713-validate-debug-load.patch CVE-2026-6019-Morsel-js_output.patch CVE-2026-6100-use-after-free-decompression.patch ----------(New B)---------- New: - Add CVE-2026-1502-reject-CRLF-HTTP-tunnel.patch which rejects CR/LF in HTTP tunnel request headers (bsc#1261969, New: - Add CVE-2026-4786-webbrowser-open-action.patch, which fixes webbrowser %action substitution bypass of dash-prefix check New: - Add CVE-2026-5713-validate-debug-load.patch, which validates remote debug offset tables on load (bsc#1262132, CVE-2026-5713, New: - Add CVE-2026-6019-Morsel-js_output.patch protects against HTML injection by Base64-encoding cookie values embedded in JS New: - Add CVE-2026-6100-use-after-free-decompression.patch preventing dangling pointer which can end in the use-after-free error ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python315.spec ++++++ --- /var/tmp/diff_new_pack.7MoCaJ/_old 2026-04-28 12:02:29.316754977 +0200 +++ /var/tmp/diff_new_pack.7MoCaJ/_new 2026-04-28 12:02:29.316754977 +0200 @@ -228,6 +228,21 @@ # PATCH-FIX-UPSTREAM skip-test_array_alignment.patch gh#python/cpython#144725 [email protected] # skip failing test Patch43: skip-test_array_alignment.patch +# PATCH-FIX-UPSTREAM CVE-2026-6100-use-after-free-decompression.patch bsc#1262098 [email protected] +# NULL dangling pointer to avoid use-after-free error +Patch44: CVE-2026-6100-use-after-free-decompression.patch +# PATCH-FIX-UPSTREAM CVE-2026-4786-webbrowser-open-action.patch bsc#1262319 [email protected] +# Fix webbrowser %action substitution bypass of dash-prefix check +Patch45: CVE-2026-4786-webbrowser-open-action.patch +# PATCH-FIX-UPSTREAM CVE-2026-5713-validate-debug-load.patch bsc#1262132 [email protected] +# Validate remote debug offset tables on load +Patch46: CVE-2026-5713-validate-debug-load.patch +# PATCH-FIX-UPSTREAM CVE-2026-1502-reject-CRLF-HTTP-tunnel.patch bsc#1261969 [email protected] +# Reject CR/LF in HTTP tunnel request headers +Patch47: CVE-2026-1502-reject-CRLF-HTTP-tunnel.patch +# PATCH-FIX-UPSTREAM CVE-2026-6019-Morsel-js_output.patch bsc#1262654 [email protected] +# Base64-encode cookie values embedded in JS +Patch48: CVE-2026-6019-Morsel-js_output.patch #### Python 3.15 DEVELOPMENT PATCHES BuildRequires: autoconf-archive BuildRequires: automake ++++++ CVE-2026-1502-reject-CRLF-HTTP-tunnel.patch ++++++ >From 1703bdda0ffc08f7035a8db5368d9eb448a910d2 Mon Sep 17 00:00:00 2001 From: Seth Michael Larson <[email protected]> Date: Fri, 20 Mar 2026 09:30:02 -0500 Subject: [PATCH 1/4] gh-146211: Reject CR/LF in HTTP tunnel request headers --- Lib/http/client.py | 11 ++ Lib/test/test_httplib.py | 45 ++++++++++ Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst | 2 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst Index: Python-3.15.0a8/Lib/http/client.py =================================================================== --- Python-3.15.0a8.orig/Lib/http/client.py 2026-04-25 18:44:37.063003792 +0200 +++ Python-3.15.0a8/Lib/http/client.py 2026-04-25 18:44:58.582460436 +0200 @@ -976,13 +976,22 @@ return ip def _tunnel(self): + if _contains_disallowed_url_pchar_re.search(self._tunnel_host): + raise ValueError('Tunnel host can\'t contain control characters %r' + % (self._tunnel_host,)) connect = b"CONNECT %s:%d %s\r\n" % ( self._wrap_ipv6(self._tunnel_host.encode("idna")), self._tunnel_port, self._http_vsn_str.encode("ascii")) headers = [connect] for header, value in self._tunnel_headers.items(): - headers.append(f"{header}: {value}\r\n".encode("latin-1")) + header_bytes = header.encode("latin-1") + value_bytes = value.encode("latin-1") + if not _is_legal_header_name(header_bytes): + raise ValueError('Invalid header name %r' % (header_bytes,)) + if _is_illegal_header_value(value_bytes): + raise ValueError('Invalid header value %r' % (value_bytes,)) + headers.append(b"%s: %s\r\n" % (header_bytes, value_bytes)) headers.append(b"\r\n") # Making a single send() call instead of one per line encourages # the host OS to use a more optimal packet size instead of Index: Python-3.15.0a8/Lib/test/test_httplib.py =================================================================== --- Python-3.15.0a8.orig/Lib/test/test_httplib.py 2026-04-25 18:44:38.860325778 +0200 +++ Python-3.15.0a8/Lib/test/test_httplib.py 2026-04-25 18:44:58.582739603 +0200 @@ -369,6 +369,51 @@ with self.assertRaisesRegex(ValueError, 'Invalid header'): conn.putheader(name, value) + def test_invalid_tunnel_headers(self): + cases = ( + ('Invalid\r\nName', 'ValidValue'), + ('Invalid\rName', 'ValidValue'), + ('Invalid\nName', 'ValidValue'), + ('\r\nInvalidName', 'ValidValue'), + ('\rInvalidName', 'ValidValue'), + ('\nInvalidName', 'ValidValue'), + (' InvalidName', 'ValidValue'), + ('\tInvalidName', 'ValidValue'), + ('Invalid:Name', 'ValidValue'), + (':InvalidName', 'ValidValue'), + ('ValidName', 'Invalid\r\nValue'), + ('ValidName', 'Invalid\rValue'), + ('ValidName', 'Invalid\nValue'), + ('ValidName', 'InvalidValue\r\n'), + ('ValidName', 'InvalidValue\r'), + ('ValidName', 'InvalidValue\n'), + ) + for name, value in cases: + with self.subTest((name, value)): + conn = client.HTTPConnection('example.com') + conn.set_tunnel('tunnel', headers={ + name: value + }) + conn.sock = FakeSocket('') + with self.assertRaisesRegex(ValueError, 'Invalid header'): + conn._tunnel() # Called in .connect() + + def test_invalid_tunnel_host(self): + cases = ( + 'invalid\r.host', + '\ninvalid.host', + 'invalid.host\r\n', + 'invalid.host\x00', + 'invalid host', + ) + for tunnel_host in cases: + with self.subTest(tunnel_host): + conn = client.HTTPConnection('example.com') + conn.set_tunnel(tunnel_host) + conn.sock = FakeSocket('') + with self.assertRaisesRegex(ValueError, 'Tunnel host can\'t contain control characters'): + conn._tunnel() # Called in .connect() + def test_headers_debuglevel(self): body = ( b'HTTP/1.1 200 OK\r\n' Index: Python-3.15.0a8/Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ Python-3.15.0a8/Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst 2026-04-25 18:44:58.581421658 +0200 @@ -0,0 +1,2 @@ +Reject CR/LF characters in tunnel request headers for the +HTTPConnection.set_tunnel() method. ++++++ CVE-2026-4786-webbrowser-open-action.patch ++++++ >From c70ee10996ba5b42a5a1807ad0ae1d562f447e1b Mon Sep 17 00:00:00 2001 From: Stan Ulbrych <[email protected]> Date: Tue, 31 Mar 2026 09:14:40 +0200 Subject: [PATCH 1/4] Fix webbrowser ``%action` check bypass --- Lib/test/test_webbrowser.py | 9 +++++++++ Lib/webbrowser.py | 5 +++-- Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst | 2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) Index: Python-3.15.0a8/Lib/test/test_webbrowser.py =================================================================== --- Python-3.15.0a8.orig/Lib/test/test_webbrowser.py 2026-04-25 02:20:55.914623125 +0200 +++ Python-3.15.0a8/Lib/test/test_webbrowser.py 2026-04-25 02:21:02.286413159 +0200 @@ -119,6 +119,15 @@ arguments=[URL], kw=dict(new=999)) + def test_reject_action_dash_prefixes(self): + browser = self.browser_class(name=CMD_NAME) + with self.assertRaises(ValueError): + browser.open('%action--incognito') + # new=1: action is "--new-window", so "%action" itself expands to + # a dash-prefixed flag even with no dash in the original URL. + with self.assertRaises(ValueError): + browser.open('%action', new=1) + class EdgeCommandTest(CommandTestMixin, unittest.TestCase): Index: Python-3.15.0a8/Lib/webbrowser.py =================================================================== --- Python-3.15.0a8.orig/Lib/webbrowser.py 2026-04-25 02:20:56.233818252 +0200 +++ Python-3.15.0a8/Lib/webbrowser.py 2026-04-25 02:21:02.286798435 +0200 @@ -274,7 +274,6 @@ def open(self, url, new=0, autoraise=True): sys.audit("webbrowser.open", url) - self._check_url(url) if new == 0: action = self.remote_action elif new == 1: @@ -288,7 +287,9 @@ raise Error("Bad 'new' parameter to open(); " f"expected 0, 1, or 2, got {new}") - args = [arg.replace("%s", url).replace("%action", action) + self._check_url(url.replace("%action", action)) + + args = [arg.replace("%action", action).replace("%s", url) for arg in self.remote_args] args = [arg for arg in args if arg] success = self._invoke(args, True, autoraise, url) Index: Python-3.15.0a8/Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ Python-3.15.0a8/Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst 2026-04-25 02:21:02.287194431 +0200 @@ -0,0 +1,2 @@ +A bypass in :mod:`webbrowser` allowed URLs prefixed with ``%action`` to pass +the dash-prefix safety check. ++++++ CVE-2026-5713-validate-debug-load.patch ++++++ ++++ 635 lines (skipped) ++++++ CVE-2026-6019-Morsel-js_output.patch ++++++ >From b8dd6e4a555b22558fab6c30b7200fd8a69fa40b Mon Sep 17 00:00:00 2001 From: Seth Michael Larson <[email protected]> Date: Tue, 21 Apr 2026 13:47:06 -0500 Subject: [PATCH 1/2] gh-90309: Base64-encode cookie values embedded in JS --- Lib/http/cookies.py | 8 +++-- Lib/test/test_http_cookies.py | 29 ++++++++++++------- ...6-04-21-13-46-30.gh-issue-90309.srvj9q.rst | 2 ++ 3 files changed, 26 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-04-21-13-46-30.gh-issue-90309.srvj9q.rst diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py index 769541116993c4..660fec4f1be865 100644 --- a/Lib/http/cookies.py +++ b/Lib/http/cookies.py @@ -391,17 +391,21 @@ def __repr__(self): return '<%s: %s>' % (self.__class__.__name__, self.OutputString()) def js_output(self, attrs=None): + import base64 # Print javascript output_string = self.OutputString(attrs) if _has_control_character(output_string): raise CookieError("Control characters are not allowed in cookies") + # Base64-encode value to avoid template + # injection in cookie values. + output_encoded = base64.b64encode(output_string.encode('utf-8')).decode("ascii") return """ <script type="text/javascript"> <!-- begin hiding - document.cookie = \"%s\"; + document.cookie = atob(\"%s\"); // end hiding --> </script> - """ % (output_string.replace('"', r'\"')) + """ % (output_encoded,) def OutputString(self, attrs=None): # Build up our result diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py index e2c7551c0b3341..cfcbc17bd6df80 100644 --- a/Lib/test/test_http_cookies.py +++ b/Lib/test/test_http_cookies.py @@ -1,5 +1,5 @@ # Simple test suite for http/cookies.py - +import base64 import copy import unittest import doctest @@ -175,17 +175,19 @@ def test_load(self): self.assertEqual(C.output(['path']), 'Set-Cookie: Customer="WILE_E_COYOTE"; Path=/acme') - self.assertEqual(C.js_output(), r""" + cookie_encoded = base64.b64encode(b'Customer="WILE_E_COYOTE"; Path=/acme; Version=1').decode('ascii') + self.assertEqual(C.js_output(), fr""" <script type="text/javascript"> <!-- begin hiding - document.cookie = "Customer=\"WILE_E_COYOTE\"; Path=/acme; Version=1"; + document.cookie = atob("{cookie_encoded}"); // end hiding --> </script> """) - self.assertEqual(C.js_output(['path']), r""" + cookie_encoded = base64.b64encode(b'Customer="WILE_E_COYOTE"; Path=/acme').decode('ascii') + self.assertEqual(C.js_output(['path']), fr""" <script type="text/javascript"> <!-- begin hiding - document.cookie = "Customer=\"WILE_E_COYOTE\"; Path=/acme"; + document.cookie = atob("{cookie_encoded}"); // end hiding --> </script> """) @@ -290,17 +292,19 @@ def test_quoted_meta(self): self.assertEqual(C.output(['path']), 'Set-Cookie: Customer="WILE_E_COYOTE"; Path=/acme') - self.assertEqual(C.js_output(), r""" + expected_encoded_cookie = base64.b64encode(b'Customer=\"WILE_E_COYOTE\"; Path=/acme; Version=1').decode('ascii') + self.assertEqual(C.js_output(), fr""" <script type="text/javascript"> <!-- begin hiding - document.cookie = "Customer=\"WILE_E_COYOTE\"; Path=/acme; Version=1"; + document.cookie = atob("{expected_encoded_cookie}"); // end hiding --> </script> """) - self.assertEqual(C.js_output(['path']), r""" + expected_encoded_cookie = base64.b64encode(b'Customer=\"WILE_E_COYOTE\"; Path=/acme').decode('ascii') + self.assertEqual(C.js_output(['path']), fr""" <script type="text/javascript"> <!-- begin hiding - document.cookie = "Customer=\"WILE_E_COYOTE\"; Path=/acme"; + document.cookie = atob("{expected_encoded_cookie}"); // end hiding --> </script> """) @@ -391,13 +395,16 @@ def test_setter(self): self.assertEqual( M.output(), "Set-Cookie: %s=%s; Path=/foo" % (i, "%s_coded_val" % i)) + expected_encoded_cookie = base64.b64encode( + ("%s=%s; Path=/foo" % (i, "%s_coded_val" % i)).encode("ascii") + ).decode('ascii') expected_js_output = """ <script type="text/javascript"> <!-- begin hiding - document.cookie = "%s=%s; Path=/foo"; + document.cookie = atob("%s"); // end hiding --> </script> - """ % (i, "%s_coded_val" % i) + """ % (expected_encoded_cookie,) self.assertEqual(M.js_output(), expected_js_output) for i in ["foo bar", "foo@bar"]: # Try some illegal characters diff --git a/Misc/NEWS.d/next/Security/2026-04-21-13-46-30.gh-issue-90309.srvj9q.rst b/Misc/NEWS.d/next/Security/2026-04-21-13-46-30.gh-issue-90309.srvj9q.rst new file mode 100644 index 00000000000000..3838ac0866abf1 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-04-21-13-46-30.gh-issue-90309.srvj9q.rst @@ -0,0 +1,2 @@ +Base64-encode values when embedding cookies to JavaScript to avoid injection +and escaping. >From 14da75b7550babb3227ae9c6eff7935d5d5fb337 Mon Sep 17 00:00:00 2001 From: Seth Michael Larson <[email protected]> Date: Wed, 22 Apr 2026 13:19:36 -0500 Subject: [PATCH 2/2] Add ref into newsfragment --- .../Security/2026-04-21-13-46-30.gh-issue-90309.srvj9q.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Security/2026-04-21-13-46-30.gh-issue-90309.srvj9q.rst b/Misc/NEWS.d/next/Security/2026-04-21-13-46-30.gh-issue-90309.srvj9q.rst index 3838ac0866abf1..d7d376737e4ad1 100644 --- a/Misc/NEWS.d/next/Security/2026-04-21-13-46-30.gh-issue-90309.srvj9q.rst +++ b/Misc/NEWS.d/next/Security/2026-04-21-13-46-30.gh-issue-90309.srvj9q.rst @@ -1,2 +1,3 @@ -Base64-encode values when embedding cookies to JavaScript to avoid injection +Base64-encode values when embedding cookies to JavaScript using the +:meth:`http.cookies.BaseCookie.js_output` method to avoid injection and escaping. ++++++ CVE-2026-6100-use-after-free-decompression.patch ++++++ >From b9bcc953f5744a61fd9e5dcd484594149c05bd5f Mon Sep 17 00:00:00 2001 From: Stan Ulbrych <[email protected]> Date: Fri, 10 Apr 2026 15:31:30 +0100 Subject: [PATCH 1/4] Fix dangling input pointer after `MemoryError` in _lzma/_bz2/_ZlibDecompressor.decompress --- Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst | 5 +++++ Modules/_bz2module.c | 1 + Modules/_lzmamodule.c | 1 + Modules/zlibmodule.c | 1 + 4 files changed, 8 insertions(+) Index: Python-3.15.0a8/Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ Python-3.15.0a8/Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst 2026-04-24 22:23:30.641818361 +0200 @@ -0,0 +1,5 @@ +Fix a dangling input pointer in :class:`lzma.LZMADecompressor`, +:class:`bz2.BZ2Decompressor`, and internal :class:`!zlib._ZlibDecompressor` +when memory allocation fails with :exc:`MemoryError`, which could let a +subsequent :meth:`!decompress` call read or write through a stale pointer to +the already-released caller buffer. Index: Python-3.15.0a8/Modules/_bz2module.c =================================================================== --- Python-3.15.0a8.orig/Modules/_bz2module.c 2026-04-24 22:23:26.656623482 +0200 +++ Python-3.15.0a8/Modules/_bz2module.c 2026-04-24 22:23:30.642181965 +0200 @@ -569,6 +569,7 @@ return result; error: + bzs->next_in = NULL; Py_XDECREF(result); return NULL; } Index: Python-3.15.0a8/Modules/_lzmamodule.c =================================================================== --- Python-3.15.0a8.orig/Modules/_lzmamodule.c 2026-04-24 22:23:26.656623482 +0200 +++ Python-3.15.0a8/Modules/_lzmamodule.c 2026-04-24 22:23:30.642529359 +0200 @@ -1100,6 +1100,7 @@ return result; error: + lzs->next_in = NULL; Py_XDECREF(result); return NULL; } Index: Python-3.15.0a8/Modules/zlibmodule.c =================================================================== --- Python-3.15.0a8.orig/Modules/zlibmodule.c 2026-04-24 22:23:26.656623482 +0200 +++ Python-3.15.0a8/Modules/zlibmodule.c 2026-04-24 22:23:30.642883767 +0200 @@ -1669,6 +1669,7 @@ return result; error: + self->zst.next_in = NULL; Py_XDECREF(result); return NULL; } ++++++ _scmsync.obsinfo ++++++ --- /var/tmp/diff_new_pack.7MoCaJ/_old 2026-04-28 12:02:29.532763926 +0200 +++ /var/tmp/diff_new_pack.7MoCaJ/_new 2026-04-28 12:02:29.540764257 +0200 @@ -1,6 +1,6 @@ -mtime: 1776551935 -commit: 0423793472b21025e87b219bee6e4c8c2678921d4b45a7638fcb07e7f007249e -url: https://src.opensuse.org/python-interpreters/python315.git -revision: 0423793472b21025e87b219bee6e4c8c2678921d4b45a7638fcb07e7f007249e +mtime: 1777297792 +commit: 15f8b167b6abfc2aed3bab7b669380b068c98d376a8188cbfd5a050d67113076 +url: https://src.opensuse.org/python-interpreters/python315 +revision: 15f8b167b6abfc2aed3bab7b669380b068c98d376a8188cbfd5a050d67113076 projectscmsync: https://src.opensuse.org/python-interpreters/_ObsPrj ++++++ build.specials.obscpio ++++++ ++++++ build.specials.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.gitignore new/.gitignore --- old/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/.gitignore 2026-04-27 15:49:52.000000000 +0200 @@ -0,0 +1,5 @@ +*.obscpio +*.osc +_build.* +.pbuild +python315-*-build/
