Compare commits

..

3 commits

Author SHA1 Message Date
Karolina Surma
f3a2a2f198 trace is officially licensed as HPND-SMC
https://gitlab.com/fedora/legal/fedora-license-data/-/issues/657#note_2815942473
2025-10-15 13:58:05 +02:00
Miro Hrončok
4244427aac Update to Python 3.13.9 2025-10-14 23:44:10 +02:00
Karolina Surma
900ee2da17 Disable JIT compilation on EPEL 10.0
clang 18 is not available there.
2025-10-08 15:50:46 +02:00
10 changed files with 258 additions and 501 deletions

View file

@ -30,7 +30,7 @@ Co-authored-by: Lumír Balhar <frenzy.madness@gmail.com>
3 files changed, 72 insertions(+), 4 deletions(-) 3 files changed, 72 insertions(+), 4 deletions(-)
diff --git a/Lib/site.py b/Lib/site.py diff --git a/Lib/site.py b/Lib/site.py
index 041dca113a..ca6320df2f 100644 index aedf36399c..2ae49a8029 100644
--- a/Lib/site.py --- a/Lib/site.py
+++ b/Lib/site.py +++ b/Lib/site.py
@@ -415,8 +415,15 @@ def getsitepackages(prefixes=None): @@ -415,8 +415,15 @@ def getsitepackages(prefixes=None):
@ -51,7 +51,7 @@ index 041dca113a..ca6320df2f 100644
if os.path.isdir(sitedir): if os.path.isdir(sitedir):
addsitedir(sitedir, known_paths) addsitedir(sitedir, known_paths)
diff --git a/Lib/sysconfig/__init__.py b/Lib/sysconfig/__init__.py diff --git a/Lib/sysconfig/__init__.py b/Lib/sysconfig/__init__.py
index 43edebce34..40e85568ea 100644 index f7bd675bb3..f1ff347c3d 100644
--- a/Lib/sysconfig/__init__.py --- a/Lib/sysconfig/__init__.py
+++ b/Lib/sysconfig/__init__.py +++ b/Lib/sysconfig/__init__.py
@@ -106,6 +106,12 @@ @@ -106,6 +106,12 @@
@ -130,7 +130,7 @@ index 43edebce34..40e85568ea 100644
# On Windows we want to substitute 'lib' for schemes rather # On Windows we want to substitute 'lib' for schemes rather
# than the native value (without modifying vars, in case it # than the native value (without modifying vars, in case it
diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py
index ce17206a3c..fd95071099 100644 index 9723300f51..310706652a 100644
--- a/Lib/test/test_sysconfig.py --- a/Lib/test/test_sysconfig.py
+++ b/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py
@@ -130,8 +130,19 @@ def test_get_path(self): @@ -130,8 +130,19 @@ def test_get_path(self):
@ -154,7 +154,7 @@ index ce17206a3c..fd95071099 100644
os.path.normpath(expected), os.path.normpath(expected),
) )
@@ -395,7 +406,7 @@ def test_get_config_h_filename(self): @@ -393,7 +404,7 @@ def test_get_config_h_filename(self):
self.assertTrue(os.path.isfile(config_h), config_h) self.assertTrue(os.path.isfile(config_h), config_h)
def test_get_scheme_names(self): def test_get_scheme_names(self):
@ -163,7 +163,7 @@ index ce17206a3c..fd95071099 100644
if HAS_USER_BASE: if HAS_USER_BASE:
wanted.extend(['nt_user', 'osx_framework_user', 'posix_user']) wanted.extend(['nt_user', 'osx_framework_user', 'posix_user'])
self.assertEqual(get_scheme_names(), tuple(sorted(wanted))) self.assertEqual(get_scheme_names(), tuple(sorted(wanted)))
@@ -407,6 +418,8 @@ def test_symlink(self): # Issue 7880 @@ -405,6 +416,8 @@ def test_symlink(self): # Issue 7880
cmd = "-c", "import sysconfig; print(sysconfig.get_platform())" cmd = "-c", "import sysconfig; print(sysconfig.get_platform())"
self.assertEqual(py.call_real(*cmd), py.call_link(*cmd)) self.assertEqual(py.call_real(*cmd), py.call_link(*cmd))

View file

@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= <miro@hroncok.cz>
Date: Fri, 25 Apr 2025 09:33:37 +0200
Subject: 00461: Downstream only: Install wheel in test venvs when setuptools <
71
---
Lib/test/support/__init__.py | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 4605938b87..a0055d6887 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -2462,9 +2462,16 @@ def run_command(cmd):
else:
python = os.path.join(venv, 'bin', python_exe)
+ setuptools_whl = _findwheel('setuptools')
+ whl_filename = os.path.basename(setuptools_whl)
+ setuptools_major = int(whl_filename.split('-')[1].split('.')[0])
+ if setuptools_major >= 71: # we need 70.1+, but that's OK
+ wheels = (setuptools_whl,)
+ else:
+ wheels = (setuptools_whl, _findwheel('wheel'))
cmd = (python, '-X', 'dev',
'-m', 'pip', 'install',
- _findwheel('setuptools'),
+ *wheels,
)
run_command(cmd)

View file

@ -0,0 +1,102 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Charalampos Stratakis <cstratak@redhat.com>
Date: Tue, 3 Jun 2025 03:02:15 +0200
Subject: 00464: Enable PAC and BTI protections for aarch64
Apply protection against ROP/JOP attacks for aarch64 on asm_trampoline.S
The BTI flag must be applied in the assembler sources for this class
of attacks to be mitigated on newer aarch64 processors.
Upstream PR: https://github.com/python/cpython/pull/130864/files
The upstream patch is incomplete but only for the case where
frame pointers are not used on 3.13+.
Since on Fedora we always compile with frame pointers the BTI/PAC
hardware protections can be enabled without losing Perf unwinding.
---
Python/asm_trampoline.S | 4 +++
Python/asm_trampoline_aarch64.h | 50 +++++++++++++++++++++++++++++++++
2 files changed, 54 insertions(+)
create mode 100644 Python/asm_trampoline_aarch64.h
diff --git a/Python/asm_trampoline.S b/Python/asm_trampoline.S
index a14e68c0e8..2513cde4e7 100644
--- a/Python/asm_trampoline.S
+++ b/Python/asm_trampoline.S
@@ -1,3 +1,5 @@
+#include "asm_trampoline_aarch64.h"
+
.text
.globl _Py_trampoline_func_start
# The following assembly is equivalent to:
@@ -21,10 +23,12 @@ _Py_trampoline_func_start:
#if defined(__aarch64__) && defined(__AARCH64EL__) && !defined(__ILP32__)
// ARM64 little endian, 64bit ABI
// generate with aarch64-linux-gnu-gcc 12.1
+ SIGN_LR
stp x29, x30, [sp, -16]!
mov x29, sp
blr x3
ldp x29, x30, [sp], 16
+ VERIFY_LR
ret
#endif
#ifdef __riscv
diff --git a/Python/asm_trampoline_aarch64.h b/Python/asm_trampoline_aarch64.h
new file mode 100644
index 0000000000..4b0ec4a7dc
--- /dev/null
+++ b/Python/asm_trampoline_aarch64.h
@@ -0,0 +1,50 @@
+#ifndef ASM_TRAMPOLINE_AARCH_64_H_
+#define ASM_TRAMPOLINE_AARCH_64_H_
+
+/*
+ * References:
+ * - https://developer.arm.com/documentation/101028/0012/5--Feature-test-macros
+ * - https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst
+ */
+
+#if defined(__ARM_FEATURE_BTI_DEFAULT) && __ARM_FEATURE_BTI_DEFAULT == 1
+ #define BTI_J hint 36 /* bti j: for jumps, IE br instructions */
+ #define BTI_C hint 34 /* bti c: for calls, IE bl instructions */
+ #define GNU_PROPERTY_AARCH64_BTI 1 /* bit 0 GNU Notes is for BTI support */
+#else
+ #define BTI_J
+ #define BTI_C
+ #define GNU_PROPERTY_AARCH64_BTI 0
+#endif
+
+#if defined(__ARM_FEATURE_PAC_DEFAULT)
+ #if __ARM_FEATURE_PAC_DEFAULT & 1
+ #define SIGN_LR hint 25 /* paciasp: sign with the A key */
+ #define VERIFY_LR hint 29 /* autiasp: verify with the A key */
+ #elif __ARM_FEATURE_PAC_DEFAULT & 2
+ #define SIGN_LR hint 27 /* pacibsp: sign with the b key */
+ #define VERIFY_LR hint 31 /* autibsp: verify with the b key */
+ #endif
+ #define GNU_PROPERTY_AARCH64_POINTER_AUTH 2 /* bit 1 GNU Notes is for PAC support */
+#else
+ #define SIGN_LR BTI_C
+ #define VERIFY_LR
+ #define GNU_PROPERTY_AARCH64_POINTER_AUTH 0
+#endif
+
+/* Add the BTI and PAC support to GNU Notes section */
+#if GNU_PROPERTY_AARCH64_BTI != 0 || GNU_PROPERTY_AARCH64_POINTER_AUTH != 0
+ .pushsection .note.gnu.property, "a"; /* Start a new allocatable section */
+ .balign 8; /* align it on a byte boundry */
+ .long 4; /* size of "GNU\0" */
+ .long 0x10; /* size of descriptor */
+ .long 0x5; /* NT_GNU_PROPERTY_TYPE_0 */
+ .asciz "GNU";
+ .long 0xc0000000; /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */
+ .long 4; /* Four bytes of data */
+ .long (GNU_PROPERTY_AARCH64_BTI|GNU_PROPERTY_AARCH64_POINTER_AUTH); /* BTI or PAC is enabled */
+ .long 0; /* padding for 8 byte alignment */
+ .popsection; /* end the section */
+#endif
+
+#endif

View file

@ -1,133 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= <miro@hroncok.cz>
Date: Wed, 12 Aug 2026 15:18:39 +0200
Subject: 00466: Downstream only: Lower XML_COMBINED_VERSION threshold for
reparse deferral
RHEL 9 expat 2.5.0 has XML_SetReparseDeferralEnabled backported
via the CVE-2023-52425 fix, but XML_COMBINED_VERSION remains 20500.
CPython's #if XML_COMBINED_VERSION >= 20600 guards compile the setter
as a no-op, so SetReparseDeferralEnabled silently does nothing and
GetReparseDeferralEnabled always returns False, even though the expat
library actually supports (and enables) reparse deferral.
Lower the threshold from 20600 to 20500 so that CPython uses the
backported function. This makes the Python API actually work on RHEL 9
and fixes test failures (test_reparse_deferral_disabled,
test_flush_reparse_deferral_disabled, test_simple_xml_chunk_*).
The spec file BuildRequires expat-devel >= 2.5.0-2 to ensure the
backported function is available.
---
Lib/test/test_pyexpat.py | 6 +++---
Lib/test/test_sax.py | 4 ++--
Lib/test/test_xml_etree.py | 4 ++--
Modules/pyexpat.c | 6 +++---
4 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py
index ae7cec6540..7f73a8c5e7 100644
--- a/Lib/test/test_pyexpat.py
+++ b/Lib/test/test_pyexpat.py
@@ -1001,7 +1001,7 @@ def test_error_path_no_crash(self):
class ReparseDeferralTest(unittest.TestCase):
def test_getter_setter_round_trip(self):
parser = expat.ParserCreate()
- enabled = (expat.version_info >= (2, 6, 0))
+ enabled = (expat.version_info >= (2, 5, 0))
self.assertIs(parser.GetReparseDeferralEnabled(), enabled)
parser.SetReparseDeferralEnabled(False)
@@ -1010,7 +1010,7 @@ def test_getter_setter_round_trip(self):
self.assertIs(parser.GetReparseDeferralEnabled(), enabled)
def test_reparse_deferral_enabled(self):
- if expat.version_info < (2, 6, 0):
+ if expat.version_info < (2, 5, 0):
self.skipTest(f'Expat {expat.version_info} does not '
'support reparse deferral')
@@ -1041,7 +1041,7 @@ def start_element(name, _):
parser = expat.ParserCreate()
parser.StartElementHandler = start_element
- if expat.version_info >= (2, 6, 0):
+ if expat.version_info >= (2, 5, 0):
parser.SetReparseDeferralEnabled(False)
self.assertFalse(parser.GetReparseDeferralEnabled())
diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py
index 9b3014a94a..0e38c9488e 100644
--- a/Lib/test/test_sax.py
+++ b/Lib/test/test_sax.py
@@ -1215,7 +1215,7 @@ def test_expat_incremental_reset(self):
self.assertEqual(result.getvalue(), start + b"<doc>text</doc>")
- @unittest.skipIf(pyexpat.version_info < (2, 6, 0),
+ @unittest.skipIf(pyexpat.version_info < (2, 5, 0),
f'Expat {pyexpat.version_info} does not '
'support reparse deferral')
def test_flush_reparse_deferral_enabled(self):
@@ -1249,7 +1249,7 @@ def test_flush_reparse_deferral_disabled(self):
for chunk in ("<doc", ">"):
parser.feed(chunk)
- if pyexpat.version_info >= (2, 6, 0):
+ if pyexpat.version_info >= (2, 5, 0):
parser._parser.SetReparseDeferralEnabled(False)
self.assertEqual(result.getvalue(), start) # i.e. no elements started
diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
index 4a76a5be1e..effb899d7b 100644
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -1804,7 +1804,7 @@ def test_unknown_event(self):
with self.assertRaisesRegex(ValueError, "unknown event 'bogus'"):
ET.XMLPullParser(events=(x.decode() for x in (b'start', b'end', b'bogus')))
- @unittest.skipIf(pyexpat.version_info < (2, 6, 0),
+ @unittest.skipIf(pyexpat.version_info < (2, 5, 0),
f'Expat {pyexpat.version_info} does not '
'support reparse deferral')
def test_flush_reparse_deferral_enabled(self):
@@ -1834,7 +1834,7 @@ def test_flush_reparse_deferral_disabled(self):
for chunk in ("<doc", ">"):
parser.feed(chunk)
- if pyexpat.version_info >= (2, 6, 0):
+ if pyexpat.version_info >= (2, 5, 0):
if not ET is pyET:
self.skipTest(f'XMLParser.(Get|Set)ReparseDeferralEnabled '
'methods not available in C')
diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c
index 9e5d84eb5e..b008fe66c1 100644
--- a/Modules/pyexpat.c
+++ b/Modules/pyexpat.c
@@ -781,7 +781,7 @@ pyexpat_xmlparser_SetReparseDeferralEnabled_impl(xmlparseobject *self,
int enabled)
/*[clinic end generated code: output=5ec539e3b63c8c49 input=021eb9e0bafc32c5]*/
{
-#if XML_COMBINED_VERSION >= 20600
+#if XML_COMBINED_VERSION >= 20500
XML_SetReparseDeferralEnabled(self->itself, enabled ? XML_TRUE : XML_FALSE);
self->reparse_deferral_enabled = (bool)enabled;
#endif
@@ -1446,7 +1446,7 @@ newxmlparseobject(pyexpat_state *state, const char *encoding,
self->ns_prefixes = 0;
self->handlers = NULL;
self->intern = Py_XNewRef(intern);
-#if XML_COMBINED_VERSION >= 20600
+#if XML_COMBINED_VERSION >= 20500
self->reparse_deferral_enabled = true;
#else
self->reparse_deferral_enabled = false;
@@ -2332,7 +2332,7 @@ pyexpat_exec(PyObject *mod)
#else
capi->SetHashSalt16Bytes = NULL;
#endif
-#if XML_COMBINED_VERSION >= 20600
+#if XML_COMBINED_VERSION >= 20500
capi->SetReparseDeferralEnabled = XML_SetReparseDeferralEnabled;
#else
capi->SetReparseDeferralEnabled = NULL;

View file

@ -0,0 +1,69 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Karolina Surma <ksurma@redhat.com>
Date: Tue, 24 Jun 2025 11:12:13 +0200
Subject: 00466: Downstream only: Skip tests not working with older expat
version
We want to run these tests in Fedora and EPEL 10, but not in EPEL 9,
which has too old version of expat. We set the upper bound version
in the conditionalized skip to a release available in CentOS Stream 10,
which is tested as working.
---
Lib/test/test_pyexpat.py | 2 ++
Lib/test/test_sax.py | 2 ++
Lib/test/test_xml_etree.py | 6 ++++++
3 files changed, 10 insertions(+)
diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py
index a091430463..55ebf34c52 100644
--- a/Lib/test/test_pyexpat.py
+++ b/Lib/test/test_pyexpat.py
@@ -826,6 +826,8 @@ def start_element(name, _):
self.assertEqual(started, ['doc'])
+ @unittest.skipIf(expat.version_info < (2, 7, 1),
+ f"Skip for expat < 2.7.1 (version available in RHEL 10)")
def test_reparse_deferral_disabled(self):
started = []
diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py
index 9b3014a94a..90401e0d8f 100644
--- a/Lib/test/test_sax.py
+++ b/Lib/test/test_sax.py
@@ -1240,6 +1240,8 @@ def test_flush_reparse_deferral_enabled(self):
self.assertEqual(result.getvalue(), start + b"<doc></doc>")
+ @unittest.skipIf(pyexpat.version_info < (2, 7, 1),
+ f"Skip for expat < 2.7.1 (version available in RHEL 10)")
def test_flush_reparse_deferral_disabled(self):
result = BytesIO()
xmlgen = XMLGenerator(result)
diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
index 78598b35da..802d1399ea 100644
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -1548,9 +1548,13 @@ def test_simple_xml(self, chunk_size=None, flush=False):
self.assert_event_tags(parser, [('end', 'root')])
self.assertIsNone(parser.close())
+ @unittest.skipIf(pyexpat.version_info < (2, 7, 1),
+ f"Skip for expat < 2.7.1 (version available in RHEL 10)")
def test_simple_xml_chunk_1(self):
self.test_simple_xml(chunk_size=1, flush=True)
+ @unittest.skipIf(pyexpat.version_info < (2, 7, 1),
+ f"Skip for expat < 2.7.1 (version available in RHEL 10)")
def test_simple_xml_chunk_5(self):
self.test_simple_xml(chunk_size=5, flush=True)
@@ -1777,6 +1781,8 @@ def test_flush_reparse_deferral_enabled(self):
self.assert_event_tags(parser, [('end', 'doc')])
+ @unittest.skipIf(pyexpat.version_info < (2, 7, 1),
+ f"Skip for expat < 2.7.1 (version available in RHEL 10)")
def test_flush_reparse_deferral_disabled(self):
parser = ET.XMLPullParser(events=('start', 'end'))

View file

@ -1,59 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Seth Michael Larson <seth@python.org>
Date: Tue, 20 Jan 2026 14:46:32 -0600
Subject: 00475: CVE-2025-15367
Reject control characters in POP3 commands
---
Lib/poplib.py | 2 ++
Lib/test/test_poplib.py | 8 ++++++++
.../2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst | 1 +
3 files changed, 11 insertions(+)
create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst
diff --git a/Lib/poplib.py b/Lib/poplib.py
index 4469bff44b..b97274c5c3 100644
--- a/Lib/poplib.py
+++ b/Lib/poplib.py
@@ -122,6 +122,8 @@ def _putline(self, line):
def _putcmd(self, line):
if self._debugging: print('*cmd*', repr(line))
line = bytes(line, self.encoding)
+ if re.search(b'[\x00-\x1F\x7F]', line):
+ raise ValueError('Control characters not allowed in commands')
self._putline(line)
diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py
index eb6dab4015..bd621caee4 100644
--- a/Lib/test/test_poplib.py
+++ b/Lib/test/test_poplib.py
@@ -18,6 +18,7 @@
from test.support import asynchat
from test.support import asyncore
from test.support.testcase import ExtraAssertions
+from test.support import control_characters_c0
test_support.requires_working_socket(module=True)
@@ -396,6 +397,13 @@ def test_quit(self):
self.assertIsNone(self.client.sock)
self.assertIsNone(self.client.file)
+ def test_control_characters(self):
+ for c0 in control_characters_c0():
+ with self.assertRaises(ValueError):
+ self.client.user(f'user{c0}')
+ with self.assertRaises(ValueError):
+ self.client.pass_(f'{c0}pass')
+
@requires_ssl
def test_stls_capa(self):
capa = self.client.capa()
diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst
new file mode 100644
index 0000000000..3cde4df3e0
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst
@@ -0,0 +1 @@
+Reject control characters in POP3 commands.

View file

@ -1,173 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <encukou@gmail.com>
Date: Mon, 9 Feb 2026 10:44:21 +0100
Subject: 00477: Raise an error when importing stdlib modules compiled for a
different Python version
This is a downstream workaround "implementing" python#137212 -
the mechanism for the check exists in Python 3.15+, where it needs to be
added to the standard library modules.
In Fedora, we need it also in previous Python versions, as we experience
segmentation fault when importing stdlib modules after update while
Python is running.
_curses, _tkinter, _tracemalloc and readline are not calling PyModuleDef_Init,
which is modified with this patch, hence they need a
direct call to the check function.
Co-Authored-By: Karolina Surma <ksurma@redhat.com>
---
Include/moduleobject.h | 43 +++++++++++++++++++++++++++++++++++++++++
Makefile.pre.in | 3 +++
Modules/_cursesmodule.c | 6 ++++++
Modules/_tkinter.c | 6 ++++++
Modules/_tracemalloc.c | 6 ++++++
Modules/readline.c | 6 ++++++
Objects/moduleobject.c | 1 +
7 files changed, 71 insertions(+)
diff --git a/Include/moduleobject.h b/Include/moduleobject.h
index 2a17c891dd..64017c666c 100644
--- a/Include/moduleobject.h
+++ b/Include/moduleobject.h
@@ -116,6 +116,49 @@ struct PyModuleDef {
freefunc m_free;
};
+#if defined(_PyHack_check_version_on_modinit) && defined(Py_BUILD_CORE)
+/* The mechanism for the check has been implemented on Python 3.15+:
+ * https://github.com/python/cpython/pull/137212.
+ * In Fedora, we need this in older Pythons too:
+ * if somebody attempts to import a module compiled for a different Python version,
+ * instead of segmentation fault a meaningful error is raised.
+ */
+PyAPI_DATA(const unsigned long) Py_Version;
+
+static inline int
+_PyHack_CheckInternalAPIVersion(const char *mod_name)
+{
+ if (PY_VERSION_HEX != Py_Version) {
+ PyErr_Format(
+ PyExc_ImportError,
+ "internal Python C API version mismatch: "
+ "module %s compiled with %lu.%lu.%lu; "
+ "runtime version is %lu.%lu.%lu",
+ mod_name,
+ (const unsigned long)((PY_VERSION_HEX >> 24) & 0xFF),
+ (const unsigned long)((PY_VERSION_HEX >> 16) & 0xFF),
+ (const unsigned long)((PY_VERSION_HEX >> 8) & 0xFF),
+ (const unsigned long)((Py_Version >> 24) & 0xFF),
+ (const unsigned long)((Py_Version >> 16) & 0xFF),
+ (const unsigned long)((Py_Version >> 8) & 0xFF)
+ );
+ return -1;
+ }
+ return 0;
+}
+
+static inline PyObject *
+PyModuleDef_Init_with_check(PyModuleDef *def)
+{
+ if (_PyHack_CheckInternalAPIVersion(def->m_name) < 0) {
+ return NULL;
+ }
+ return PyModuleDef_Init(def);
+}
+
+#define PyModuleDef_Init PyModuleDef_Init_with_check
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 2363b99a25..f1a07645f0 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -3159,3 +3159,6 @@ MODULE__MULTIBYTECODEC_DEPS=$(srcdir)/Modules/cjkcodecs/multibytecodec.h
# Local Variables:
# mode: makefile
# End:
+
+# Fedora-specific, downstream only
+PY_STDMODULE_CFLAGS += -D_PyHack_check_version_on_modinit=1
diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c
index 1996488a0e..cfdffd8ec4 100644
--- a/Modules/_cursesmodule.c
+++ b/Modules/_cursesmodule.c
@@ -5011,6 +5011,12 @@ curses_destructor(PyObject *op)
PyMODINIT_FUNC
PyInit__curses(void)
{
+ #ifdef _PyHack_check_version_on_modinit
+ if (_PyHack_CheckInternalAPIVersion("_curses") < 0) {
+ return NULL;
+ }
+ #endif
+
PyObject *m, *d, *v, *c_api_object;
/* Initialize object type */
diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
index 4e8d75e8e1..32e58755aa 100644
--- a/Modules/_tkinter.c
+++ b/Modules/_tkinter.c
@@ -3499,6 +3499,12 @@ static struct PyModuleDef _tkintermodule = {
PyMODINIT_FUNC
PyInit__tkinter(void)
{
+ #ifdef _PyHack_check_version_on_modinit
+ if (_PyHack_CheckInternalAPIVersion("_tkinter") < 0) {
+ return NULL;
+ }
+ #endif
+
PyObject *m, *uexe, *cexe;
tcl_lock = PyThread_allocate_lock();
diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c
index 0b85187e5f..87f358ed07 100644
--- a/Modules/_tracemalloc.c
+++ b/Modules/_tracemalloc.c
@@ -215,6 +215,12 @@ static struct PyModuleDef module_def = {
PyMODINIT_FUNC
PyInit__tracemalloc(void)
{
+ #ifdef _PyHack_check_version_on_modinit
+ if (_PyHack_CheckInternalAPIVersion("_tracemalloc") < 0) {
+ return NULL;
+ }
+ #endif
+
PyObject *m;
m = PyModule_Create(&module_def);
if (m == NULL)
diff --git a/Modules/readline.c b/Modules/readline.c
index 7a612deae4..8b2f47eec1 100644
--- a/Modules/readline.c
+++ b/Modules/readline.c
@@ -1548,6 +1548,12 @@ static struct PyModuleDef readlinemodule = {
PyMODINIT_FUNC
PyInit_readline(void)
{
+ #ifdef _PyHack_check_version_on_modinit
+ if (_PyHack_CheckInternalAPIVersion("readline") < 0) {
+ return NULL;
+ }
+ #endif
+
const char *backend = "readline";
PyObject *m;
readlinestate *mod_state;
diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c
index d787f29004..31175ceb3f 100644
--- a/Objects/moduleobject.c
+++ b/Objects/moduleobject.c
@@ -43,6 +43,7 @@ _PyModule_IsExtension(PyObject *obj)
}
+#undef PyModuleDef_Init
PyObject*
PyModuleDef_Init(PyModuleDef* def)
{

View file

@ -43,9 +43,6 @@ discover:
- name: marshalparser - name: marshalparser
path: /marshalparser path: /marshalparser
test: "VERSION=${pybasever} SAMPLE=10 ./test_marshalparser_compatibility.sh" test: "VERSION=${pybasever} SAMPLE=10 ./test_marshalparser_compatibility.sh"
- name: required_symbols
path: /required-symbols
test: "VERSION=${pybasever} ./check.sh"
prepare: prepare:
- name: Install dependencies - name: Install dependencies
@ -65,9 +62,8 @@ prepare:
- virtualenv # for virtualenv tests - virtualenv # for virtualenv tests
- glibc-all-langpacks # for locale tests - glibc-all-langpacks # for locale tests
- marshalparser # for testing compatibility (magic numbers) with marshalparser - marshalparser # for testing compatibility (magic numbers) with marshalparser
- binutils # for nm (symbol inspection)
- rpm # for debugging - rpm # for debugging
- dnf # for upgrade and downgrade - dnf # for upgrade
- name: Update packages - name: Update packages
how: shell how: shell
script: dnf upgrade -y script: dnf upgrade -y

View file

@ -45,11 +45,11 @@ URL: https://www.python.org/
# WARNING When rebasing to a new Python version, # WARNING When rebasing to a new Python version,
# remember to update the python3-docs package as well # remember to update the python3-docs package as well
%global general_version %{pybasever}.15 %global general_version %{pybasever}.9
#global prerel ... #global prerel ...
%global upstream_version %{general_version}%{?prerel} %global upstream_version %{general_version}%{?prerel}
Version: %{general_version}%{?prerel:~%{prerel}} Version: %{general_version}%{?prerel:~%{prerel}}
Release: 2%{?dist} Release: 1%{?dist}
License: Python-2.0.1 License: Python-2.0.1
@ -78,10 +78,9 @@ License: Python-2.0.1
# PEP 744: JIT Compilation # PEP 744: JIT Compilation
# Whether to build with the experimental JIT compiler # Whether to build with the experimental JIT compiler
# We can only have this on Fedora 40+, where clang 18+ is available # On EPEL 10.0 clang 18 is not available, hence it's disabled
# And only on certain architectures: https://peps.python.org/pep-0744/#support
# The freethreading build (when enabled) does not support JIT yet # The freethreading build (when enabled) does not support JIT yet
%bcond jit %[(0%{?fedora} >= 40 || 0%{?epel} >= 10) && ("%{_arch}" == "x86_64" || "%{_arch}" == "aarch64")] %bcond jit 0
%if %{with jit} %if %{with jit}
# When built with JIT, it still needs to be enabled on runtime via PYTHON_JIT=1 # When built with JIT, it still needs to be enabled on runtime via PYTHON_JIT=1
%global jit_flag --enable-experimental-jit=yes-off %global jit_flag --enable-experimental-jit=yes-off
@ -109,30 +108,31 @@ License: Python-2.0.1
# This needs to be manually updated when we update Python. # This needs to be manually updated when we update Python.
# Explore the sources tarball (you need the version before %%prep is executed): # Explore the sources tarball (you need the version before %%prep is executed):
# $ tar -tf Python-%%{upstream_version}.tar.xz | grep whl # $ tar -tf Python-%%{upstream_version}.tar.xz | grep whl
%global pip_version 26.2.1 %global pip_version 25.2
%global setuptools_version 79.0.1 %global setuptools_version 79.0.1
# All of those also include a list of indirect bundled libs: # All of those also include a list of indirect bundled libs:
# pip # pip
# $ %%{_rpmconfigdir}/pythonbundles.py <(unzip -p Lib/ensurepip/_bundled/pip-*.whl pip/_vendor/vendor.txt) # $ %%{_rpmconfigdir}/pythonbundles.py <(unzip -p Lib/ensurepip/_bundled/pip-*.whl pip/_vendor/vendor.txt)
%global pip_bundled_provides %{expand: %global pip_bundled_provides %{expand:
Provides: bundled(python3dist(cachecontrol)) = 0.14.4 Provides: bundled(python3dist(cachecontrol)) = 0.14.3
Provides: bundled(python3dist(certifi)) = 2026.6.17 Provides: bundled(python3dist(certifi)) = 2025.7.14
Provides: bundled(python3dist(distlib)) = 0.4.2 Provides: bundled(python3dist(dependency-groups)) = 1.3.1
Provides: bundled(python3dist(distlib)) = 0.4
Provides: bundled(python3dist(distro)) = 1.9 Provides: bundled(python3dist(distro)) = 1.9
Provides: bundled(python3dist(idna)) = 3.18 Provides: bundled(python3dist(idna)) = 3.10
Provides: bundled(python3dist(msgpack)) = 1.1.2 Provides: bundled(python3dist(msgpack)) = 1.1.1
Provides: bundled(python3dist(packaging)) = 26.2 Provides: bundled(python3dist(packaging)) = 25
Provides: bundled(python3dist(platformdirs)) = 4.10 Provides: bundled(python3dist(platformdirs)) = 4.3.8
Provides: bundled(python3dist(pygments)) = 2.20 Provides: bundled(python3dist(pygments)) = 2.19.2
Provides: bundled(python3dist(pyproject-hooks)) = 1.2 Provides: bundled(python3dist(pyproject-hooks)) = 1.2
Provides: bundled(python3dist(requests)) = 2.34.2 Provides: bundled(python3dist(requests)) = 2.32.4
Provides: bundled(python3dist(resolvelib)) = 1.2.1 Provides: bundled(python3dist(resolvelib)) = 1.2
Provides: bundled(python3dist(rich)) = 14.2 Provides: bundled(python3dist(rich)) = 14.1
Provides: bundled(python3dist(setuptools)) = 70.3 Provides: bundled(python3dist(setuptools)) = 70.3
Provides: bundled(python3dist(tomli)) = 2.4.1 Provides: bundled(python3dist(tomli)) = 2.2.1
Provides: bundled(python3dist(tomli-w)) = 1.2 Provides: bundled(python3dist(tomli-w)) = 1.2
Provides: bundled(python3dist(truststore)) = 0.10.4 Provides: bundled(python3dist(truststore)) = 0.10.1
Provides: bundled(python3dist(urllib3)) = 2.7 Provides: bundled(python3dist(urllib3)) = 1.26.20
} }
# setuptools # setuptools
# vendor.txt not in .whl # vendor.txt not in .whl
@ -254,7 +254,7 @@ Obsoletes: python%{pybasever}%{?1:-%{1}}\
BuildRequires: autoconf BuildRequires: autoconf
BuildRequires: bluez-libs-devel BuildRequires: bluez-libs-devel
BuildRequires: bzip2-devel BuildRequires: bzip2-devel
BuildRequires: expat-devel >= 2.5.0-2 BuildRequires: expat-devel
BuildRequires: findutils BuildRequires: findutils
BuildRequires: gcc BuildRequires: gcc
BuildRequires: gdbm-devel BuildRequires: gdbm-devel
@ -267,6 +267,7 @@ BuildRequires: libuuid-devel
BuildRequires: make BuildRequires: make
BuildRequires: mpdecimal-devel BuildRequires: mpdecimal-devel
BuildRequires: ncurses-devel BuildRequires: ncurses-devel
BuildRequires: openssl-devel
BuildRequires: pkgconfig BuildRequires: pkgconfig
BuildRequires: python-rpm-macros BuildRequires: python-rpm-macros
BuildRequires: readline-devel BuildRequires: readline-devel
@ -279,10 +280,6 @@ BuildRequires: xz-devel
BuildRequires: zlib-devel BuildRequires: zlib-devel
BuildRequires: /usr/bin/dtrace BuildRequires: /usr/bin/dtrace
# Support for OpenSSL 4 only landed in Python 3.15 for now
# https://github.com/python/cpython/issues/146207
BuildRequires: (openssl-devel < 1:4 or openssl3-devel)
%if %{undefined rhel} %if %{undefined rhel}
BuildRequires: libb2-devel BuildRequires: libb2-devel
%endif %endif
@ -370,45 +367,35 @@ Source11: idle3.appdata.xml
# pypa/distutils integration: https://github.com/pypa/distutils/pull/70 # pypa/distutils integration: https://github.com/pypa/distutils/pull/70
Patch251: 00251-change-user-install-location.patch Patch251: 00251-change-user-install-location.patch
# 00466 # 713a1368544eddd55088d67f88a23ce31722a4cb # 00461 # 920175020b21c0aff5edcc4c28d688b5061f591c
# Downstream only: Lower XML_COMBINED_VERSION threshold for reparse deferral # Downstream only: Install wheel in test venvs when setuptools < 71
# Patch461: 00461-downstream-only-install-wheel-in-test-venvs-when-setuptools-71.patch
# RHEL 9 expat 2.5.0 has XML_SetReparseDeferralEnabled backported
# via the CVE-2023-52425 fix, but XML_COMBINED_VERSION remains 20500.
# CPython's #if XML_COMBINED_VERSION >= 20600 guards compile the setter
# as a no-op, so SetReparseDeferralEnabled silently does nothing and
# GetReparseDeferralEnabled always returns False, even though the expat
# library actually supports (and enables) reparse deferral.
#
# Lower the threshold from 20600 to 20500 so that CPython uses the
# backported function. This makes the Python API actually work on RHEL 9
# and fixes test failures (test_reparse_deferral_disabled,
# test_flush_reparse_deferral_disabled, test_simple_xml_chunk_*).
#
# The spec file BuildRequires expat-devel >= 2.5.0-2 to ensure the
# backported function is available.
Patch466: 00466-downstream-only-lower-xml_combined_version-threshold-for-reparse-deferral.patch
# 00475 # d44fac01037662db286449a78c8fb819788f764c # 00464 # 292acffec7a379cb6d1f3c47b9e5a2f170bbadb6
# CVE-2025-15367 # Enable PAC and BTI protections for aarch64
# #
# Reject control characters in POP3 commands # Apply protection against ROP/JOP attacks for aarch64 on asm_trampoline.S
Patch475: 00475-cve-2025-15367.patch #
# The BTI flag must be applied in the assembler sources for this class
# of attacks to be mitigated on newer aarch64 processors.
#
# Upstream PR: https://github.com/python/cpython/pull/130864/files
#
# The upstream patch is incomplete but only for the case where
# frame pointers are not used on 3.13+.
#
# Since on Fedora we always compile with frame pointers the BTI/PAC
# hardware protections can be enabled without losing Perf unwinding.
Patch464: 00464-enable-pac-and-bti-protections-for-aarch64.patch
# 00477 # 9c62c492e7f2e3b152dbf287c08d307c3f013221 # 00466 # e10760fb955ee33d2917f8a57bb4e24d71e5341c
# Raise an error when importing stdlib modules compiled for a different Python version # Downstream only: Skip tests not working with older expat version
# #
# This is a downstream workaround "implementing" python#137212 - # We want to run these tests in Fedora and EPEL 10, but not in EPEL 9,
# the mechanism for the check exists in Python 3.15+, where it needs to be # which has too old version of expat. We set the upper bound version
# added to the standard library modules. # in the conditionalized skip to a release available in CentOS Stream 10,
# In Fedora, we need it also in previous Python versions, as we experience # which is tested as working.
# segmentation fault when importing stdlib modules after update while Patch466: 00466-downstream-only-skip-tests-not-working-with-older-expat-version.patch
# Python is running.
#
# _curses, _tkinter, _tracemalloc and readline are not calling PyModuleDef_Init,
# which is modified with this patch, hence they need a
# direct call to the check function.
Patch477: 00477-raise-an-error-when-importing-stdlib-modules-compiled-for-a-different-python-version.patch
# (New patches go here ^^^) # (New patches go here ^^^)
# #
@ -534,7 +521,7 @@ Summary: Python runtime libraries
# Combined manually from https://docs.python.org/3.13/license.html # Combined manually from https://docs.python.org/3.13/license.html
# Hash of Doc/license.rst which is compared in %%prep, generated with: # Hash of Doc/license.rst which is compared in %%prep, generated with:
# $ sha256sum Doc/license.rst | cut -f1 -d" " # $ sha256sum Doc/license.rst | cut -f1 -d" "
%global license_file_hash 952ac05720d7f1dcb63589b35eb0931b1442eb250230a4ad31198eddf0ad6abc %global license_file_hash 62f2c9c2c75d511170eb464ad5f83b78cc1f37eb2eb49c2846c9aa6c4557ee99
# Licenses of incorporated software: # Licenses of incorporated software:
# Mersenne Twister in _random C extension contains code under BSD-3-Clause # Mersenne Twister in _random C extension contains code under BSD-3-Clause
# socket.getaddrinfo() and socket.getnameinfo() are BSD-3-Clause # socket.getaddrinfo() and socket.getnameinfo() are BSD-3-Clause
@ -557,11 +544,10 @@ Summary: Python runtime libraries
# mimalloc is MIT # mimalloc is MIT
# parts of asyncio from uvloop are MIT # parts of asyncio from uvloop are MIT
# Python/qsbr.c is adapted from code under BSD-2-Clause # Python/qsbr.c is adapted from code under BSD-2-Clause
# An extract of the `Unicode Character Database` converted to an internal format is Unicode-3.0
# Bundled libb2 is not declared in the upstream document, but it's: # Bundled libb2 is not declared in the upstream document, but it's:
# CC0-1.0, covered by grandfathering exception # CC0-1.0, covered by grandfathering exception
# We don't query upstream for changes, as 3.13 is the last Python version containing it. # We don't query upstream for changes, as 3.13 is the last Python version containing it.
%global libs_license Python-2.0.1 AND CC0-1.0 AND MIT AND BSD-3-Clause AND MIT-CMU AND HPND-SMC AND BSD-2-Clause AND dtoa AND Unicode-3.0 %global libs_license Python-2.0.1 AND CC0-1.0 AND MIT AND BSD-3-Clause AND MIT-CMU AND HPND-SMC AND BSD-2-Clause AND dtoa
%if %{with rpmwheels} %if %{with rpmwheels}
Requires: %{python_wheel_pkg_prefix}-pip-wheel >= 23.1.2 Requires: %{python_wheel_pkg_prefix}-pip-wheel >= 23.1.2
License: %{libs_license} License: %{libs_license}
@ -597,28 +583,6 @@ Recommends: (%{pkgname}-tkinter%{?_isa} = %{version}-%{release} if tk%{?_isa})
# The zoneinfo module needs tzdata # The zoneinfo module needs tzdata
Requires: tzdata Requires: tzdata
# The requirement on libexpat is generated, but we need to version it.
# When built with a specific expat version, but installed with an older one,
# we sometimes get:
# ImportError: /usr/lib64/python3.X/lib-dynload/pyexpat.cpython-....so:
# undefined symbol: XML_...
# The pyexpat module has build-time checks for expat version to only use the
# available symbols. However, there is no runtime protection, so when the module
# is later installed with an older expat, it may error due to undefined symbols.
# This breaks many things, including python -m venv.
# We avoid this problem by requiring at least the same version of expat that
# was used during the build time.
# We also include release, in case pyxpat uses ABI that was backported
# (e.g. XML_SetReparseDeferralEnabled was added in c9s expat 2.5.0-2).
# Other subpackages (like -debug) also need this, but they all depend on -libs.
# Since expat 2.7.4, the library has versioned symbols and this is no longer needed,
# as the generated requirement will be in the form of libexpat.so.1(LIBEXPAT_2.7.2) etc.
%global expat_version %(LANG=C rpm -q --qf '%%{version}-%%{release}' expat.%{_target_cpu} | sed 's/.*not installed/0/')
%if v"%{expat_version}" < v"2.7.4"
Requires: expat%{?_isa} >= %{expat_version}
%endif
%description -n %{pkgname}-libs %description -n %{pkgname}-libs
This package contains runtime libraries for use by Python: This package contains runtime libraries for use by Python:
- the majority of the Python standard library - the majority of the Python standard library
@ -795,9 +759,6 @@ License: %{libs_license} AND Apache-2.0 AND ISC AND LGPL-2.1-only AND MPL-2.0 AN
Provides: bundled(libb2) = 0.98.1 Provides: bundled(libb2) = 0.98.1
Provides: bundled(mimalloc) = 2.12 Provides: bundled(mimalloc) = 2.12
Requires: tzdata Requires: tzdata
%if v"%{expat_version}" < v"2.7.4"
Requires: expat%{?_isa} >= %{expat_version}
%endif
%description -n python%{pybasever}-freethreading %description -n python%{pybasever}-freethreading
The provisional Free Threading (PEP 703) build of Python. The provisional Free Threading (PEP 703) build of Python.
@ -1301,11 +1262,6 @@ for file in %{buildroot}%{pylibdir}/pydoc_data/topics.py $(grep --include='*.py'
rm ${directory}/{__pycache__/${module}.cpython-%{pyshortver}.opt-?.pyc,${module}.py} rm ${directory}/{__pycache__/${module}.cpython-%{pyshortver}.opt-?.pyc,${module}.py}
done done
%if %{without rpmwheels}
# Inject SBOM into the installed wheels (if the macro is available)
%{?python_wheel_inject_sbom:%python_wheel_inject_sbom %{buildroot}%{pylibdir}/ensurepip/_bundled/*.whl}
%endif
# ====================================================== # ======================================================
# Checks for packaging issues # Checks for packaging issues
# ====================================================== # ======================================================
@ -1818,39 +1774,6 @@ CheckPython freethreading
# ====================================================== # ======================================================
%changelog %changelog
* Wed Aug 12 2026 Miro Hrončok <mhroncok@redhat.com> - 3.13.15-2
- On EPEL 9, also supports reparse deferral in expat
* Mon Aug 10 2026 Karolina Surma <ksurma@redhat.com> - 3.13.15-1
- Update to Python 3.13.15
* Thu Jul 16 2026 Fedora Release Engineering <releng@fedoraproject.org> - 3.13.14-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild
* Thu Jun 11 2026 Karolina Surma <ksurma@redhat.com> - 3.13.14-1
- Update to Python 3.13.14
* Wed Apr 08 2026 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.13.13-1
- Update to 3.13.13
* Thu Mar 26 2026 Lumír Balhar <lbalhar@redhat.com> - 3.13.12-2
- Security fix for CVE-2026-4519 (rhbz#2449729)
* Wed Feb 04 2026 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.13.12-1
- Update to 3.13.12
* Sat Jan 17 2026 Fedora Release Engineering <releng@fedoraproject.org> - 3.13.11-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild
* Tue Jan 06 2026 Karolina Surma <ksurma@redhat.com> - 3.13.11-2
- Require at least the same expat version as used during the build time
* Fri Dec 05 2025 Miro Hrončok <mhroncok@redhat.com> - 3.13.11-1
- Update to 3.13.11
* Wed Dec 03 2025 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.13.10-1
- Update to 3.13.10
* Tue Oct 14 2025 Miro Hrončok <mhroncok@redhat.com> - 3.13.9-1 * Tue Oct 14 2025 Miro Hrončok <mhroncok@redhat.com> - 3.13.9-1
- Update to Python 3.13.9 - Update to Python 3.13.9

View file

@ -1,2 +1,2 @@
SHA512 (Python-3.13.15.tar.xz) = b0ab766a3de0b4cfdbf0b93300d7330c734d3f7057577bb03e95e39da4cdade81993e769c7fa6dfdcc13b9d43a3b399d9cd89b5477b413662e9e691c1b7886b8 SHA512 (Python-3.13.9.tar.xz) = ffc9b6e545bf5cf8f3b945f85442eb4bd28cca9adb92d8c253f44078ec2e9758f802bf72c48e0d7e503c02b2dc754c58ee913cd3b7d8e8808fac2a0aa4e006a8
SHA512 (Python-3.13.15.tar.xz.asc) = 662c00be95f62e80db43cf42099fef91f764ff7a4433cadf7eb19dedb5e4775adb12878d5ed2295fcea187731de186163ad9672ab72cde62a2335ca58ec1ad86 SHA512 (Python-3.13.9.tar.xz.asc) = c33fba3a6b22dccc08beb7f13bd61a25a30f609a54da7c8dfd3b3b4a3490a7b24c11f9617a835388f22709fb09375d35febc417cf104a18f5bec3b43ec999e82