diff --git a/00001-rpath.patch b/00001-rpath.patch index cd063e5..778c077 100644 --- a/00001-rpath.patch +++ b/00001-rpath.patch @@ -1,10 +1,9 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 13 Jan 2010 21:25:18 +0000 -Subject: 00001: Fixup distutils/unixccompiler.py to remove standard library - path from rpath +Subject: [PATCH] 00001: Fixup distutils/unixccompiler.py to remove standard + library path from rpath Was Patch0 in ivazquez' python3000 specfile -Was Patch0 in ivazquez' python3000 specfile --- Lib/distutils/unixccompiler.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/00251-change-user-install-location.patch b/00251-change-user-install-location.patch index 7b68621..b0a4c9c 100644 --- a/00251-change-user-install-location.patch +++ b/00251-change-user-install-location.patch @@ -1,7 +1,7 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Mon, 15 Feb 2021 12:19:27 +0100 -Subject: 00251: Change user install location +Subject: [PATCH] 00251: Change user install location MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit diff --git a/00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-gh-28549-gh-28589.patch b/00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-gh-28549-gh-28589.patch index 7dbd3bb..7ab6c6c 100644 --- a/00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-gh-28549-gh-28589.patch +++ b/00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-gh-28549-gh-28589.patch @@ -1,8 +1,8 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Hrn=C4=8Diar?= Date: Tue, 7 Dec 2021 14:41:59 +0100 -Subject: 00371: Revert "bpo-1596321: Fix threading._shutdown() for the main - thread (GH-28549) (GH-28589)" +Subject: [PATCH] 00371: Revert "bpo-1596321: Fix threading._shutdown() for the + main thread (GH-28549) (GH-28589)" This reverts commit 38c67738c64304928c68d5c2bd78bbb01d979b94. It introduced regression causing FreeIPA's tests to fail. diff --git a/00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch b/00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch new file mode 100644 index 0000000..7d2a813 --- /dev/null +++ b/00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch @@ -0,0 +1,500 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Victor Stinner +Date: Fri, 15 Dec 2023 16:10:40 +0100 +Subject: [PATCH] 00415: [CVE-2023-27043] gh-102988: Reject malformed addresses + in email.parseaddr() (#111116) + +Detect email address parsing errors and return empty tuple to +indicate the parsing error (old API). Add an optional 'strict' +parameter to getaddresses() and parseaddr() functions. Patch by +Thomas Dwyer. + +Co-Authored-By: Thomas Dwyer +--- + Doc/library/email.utils.rst | 19 +- + Lib/email/utils.py | 151 ++++++++++++- + Lib/test/test_email/test_email.py | 204 +++++++++++++++++- + ...-10-20-15-28-08.gh-issue-102988.dStNO7.rst | 8 + + 4 files changed, 361 insertions(+), 21 deletions(-) + create mode 100644 Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst + +diff --git a/Doc/library/email.utils.rst b/Doc/library/email.utils.rst +index 0e266b6a45..6723dc4f13 100644 +--- a/Doc/library/email.utils.rst ++++ b/Doc/library/email.utils.rst +@@ -60,13 +60,18 @@ of the new API. + begins with angle brackets, they are stripped off. + + +-.. function:: parseaddr(address) ++.. function:: parseaddr(address, *, strict=True) + + Parse address -- which should be the value of some address-containing field such + as :mailheader:`To` or :mailheader:`Cc` -- into its constituent *realname* and + *email address* parts. Returns a tuple of that information, unless the parse + fails, in which case a 2-tuple of ``('', '')`` is returned. + ++ If *strict* is true, use a strict parser which rejects malformed inputs. ++ ++ .. versionchanged:: 3.13 ++ Add *strict* optional parameter and reject malformed inputs by default. ++ + + .. function:: formataddr(pair, charset='utf-8') + +@@ -84,12 +89,15 @@ of the new API. + Added the *charset* option. + + +-.. function:: getaddresses(fieldvalues) ++.. function:: getaddresses(fieldvalues, *, strict=True) + + This method returns a list of 2-tuples of the form returned by ``parseaddr()``. + *fieldvalues* is a sequence of header field values as might be returned by +- :meth:`Message.get_all `. Here's a simple +- example that gets all the recipients of a message:: ++ :meth:`Message.get_all `. ++ ++ If *strict* is true, use a strict parser which rejects malformed inputs. ++ ++ Here's a simple example that gets all the recipients of a message:: + + from email.utils import getaddresses + +@@ -99,6 +107,9 @@ of the new API. + resent_ccs = msg.get_all('resent-cc', []) + all_recipients = getaddresses(tos + ccs + resent_tos + resent_ccs) + ++ .. versionchanged:: 3.13 ++ Add *strict* optional parameter and reject malformed inputs by default. ++ + + .. function:: parsedate(date) + +diff --git a/Lib/email/utils.py b/Lib/email/utils.py +index cfdfeb3f1a..9522341fab 100644 +--- a/Lib/email/utils.py ++++ b/Lib/email/utils.py +@@ -48,6 +48,7 @@ + specialsre = re.compile(r'[][\\()<>@,:;".]') + escapesre = re.compile(r'[\\"]') + ++ + def _has_surrogates(s): + """Return True if s contains surrogate-escaped binary data.""" + # This check is based on the fact that unless there are surrogates, utf8 +@@ -106,12 +107,127 @@ def formataddr(pair, charset='utf-8'): + return address + + ++def _iter_escaped_chars(addr): ++ pos = 0 ++ escape = False ++ for pos, ch in enumerate(addr): ++ if escape: ++ yield (pos, '\\' + ch) ++ escape = False ++ elif ch == '\\': ++ escape = True ++ else: ++ yield (pos, ch) ++ if escape: ++ yield (pos, '\\') + +-def getaddresses(fieldvalues): +- """Return a list of (REALNAME, EMAIL) for each fieldvalue.""" +- all = COMMASPACE.join(str(v) for v in fieldvalues) +- a = _AddressList(all) +- return a.addresslist ++ ++def _strip_quoted_realnames(addr): ++ """Strip real names between quotes.""" ++ if '"' not in addr: ++ # Fast path ++ return addr ++ ++ start = 0 ++ open_pos = None ++ result = [] ++ for pos, ch in _iter_escaped_chars(addr): ++ if ch == '"': ++ if open_pos is None: ++ open_pos = pos ++ else: ++ if start != open_pos: ++ result.append(addr[start:open_pos]) ++ start = pos + 1 ++ open_pos = None ++ ++ if start < len(addr): ++ result.append(addr[start:]) ++ ++ return ''.join(result) ++ ++ ++supports_strict_parsing = True ++ ++def getaddresses(fieldvalues, *, strict=True): ++ """Return a list of (REALNAME, EMAIL) or ('','') for each fieldvalue. ++ ++ When parsing fails for a fieldvalue, a 2-tuple of ('', '') is returned in ++ its place. ++ ++ If strict is true, use a strict parser which rejects malformed inputs. ++ """ ++ ++ # If strict is true, if the resulting list of parsed addresses is greater ++ # than the number of fieldvalues in the input list, a parsing error has ++ # occurred and consequently a list containing a single empty 2-tuple [('', ++ # '')] is returned in its place. This is done to avoid invalid output. ++ # ++ # Malformed input: getaddresses(['alice@example.com ']) ++ # Invalid output: [('', 'alice@example.com'), ('', 'bob@example.com')] ++ # Safe output: [('', '')] ++ ++ if not strict: ++ all = COMMASPACE.join(str(v) for v in fieldvalues) ++ a = _AddressList(all) ++ return a.addresslist ++ ++ fieldvalues = [str(v) for v in fieldvalues] ++ fieldvalues = _pre_parse_validation(fieldvalues) ++ addr = COMMASPACE.join(fieldvalues) ++ a = _AddressList(addr) ++ result = _post_parse_validation(a.addresslist) ++ ++ # Treat output as invalid if the number of addresses is not equal to the ++ # expected number of addresses. ++ n = 0 ++ for v in fieldvalues: ++ # When a comma is used in the Real Name part it is not a deliminator. ++ # So strip those out before counting the commas. ++ v = _strip_quoted_realnames(v) ++ # Expected number of addresses: 1 + number of commas ++ n += 1 + v.count(',') ++ if len(result) != n: ++ return [('', '')] ++ ++ return result ++ ++ ++def _check_parenthesis(addr): ++ # Ignore parenthesis in quoted real names. ++ addr = _strip_quoted_realnames(addr) ++ ++ opens = 0 ++ for pos, ch in _iter_escaped_chars(addr): ++ if ch == '(': ++ opens += 1 ++ elif ch == ')': ++ opens -= 1 ++ if opens < 0: ++ return False ++ return (opens == 0) ++ ++ ++def _pre_parse_validation(email_header_fields): ++ accepted_values = [] ++ for v in email_header_fields: ++ if not _check_parenthesis(v): ++ v = "('', '')" ++ accepted_values.append(v) ++ ++ return accepted_values ++ ++ ++def _post_parse_validation(parsed_email_header_tuples): ++ accepted_values = [] ++ # The parser would have parsed a correctly formatted domain-literal ++ # The existence of an [ after parsing indicates a parsing failure ++ for v in parsed_email_header_tuples: ++ if '[' in v[1]: ++ v = ('', '') ++ accepted_values.append(v) ++ ++ return accepted_values + + + def _format_timetuple_and_zone(timetuple, zone): +@@ -205,16 +321,33 @@ def parsedate_to_datetime(data): + tzinfo=datetime.timezone(datetime.timedelta(seconds=tz))) + + +-def parseaddr(addr): ++def parseaddr(addr, *, strict=True): + """ + Parse addr into its constituent realname and email address parts. + + Return a tuple of realname and email address, unless the parse fails, in + which case return a 2-tuple of ('', ''). ++ ++ If strict is True, use a strict parser which rejects malformed inputs. + """ +- addrs = _AddressList(addr).addresslist +- if not addrs: +- return '', '' ++ if not strict: ++ addrs = _AddressList(addr).addresslist ++ if not addrs: ++ return ('', '') ++ return addrs[0] ++ ++ if isinstance(addr, list): ++ addr = addr[0] ++ ++ if not isinstance(addr, str): ++ return ('', '') ++ ++ addr = _pre_parse_validation([addr])[0] ++ addrs = _post_parse_validation(_AddressList(addr).addresslist) ++ ++ if not addrs or len(addrs) > 1: ++ return ('', '') ++ + return addrs[0] + + +diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py +index 8b16cca9bf..5b19bb38f6 100644 +--- a/Lib/test/test_email/test_email.py ++++ b/Lib/test/test_email/test_email.py +@@ -16,6 +16,7 @@ + + import email + import email.policy ++import email.utils + + from email.charset import Charset + from email.generator import Generator, DecodedGenerator, BytesGenerator +@@ -3288,15 +3289,154 @@ def test_getaddresses(self): + [('Al Person', 'aperson@dom.ain'), + ('Bud Person', 'bperson@dom.ain')]) + ++ def test_getaddresses_comma_in_name(self): ++ """GH-106669 regression test.""" ++ self.assertEqual( ++ utils.getaddresses( ++ [ ++ '"Bud, Person" ', ++ 'aperson@dom.ain (Al Person)', ++ '"Mariusz Felisiak" ', ++ ] ++ ), ++ [ ++ ('Bud, Person', 'bperson@dom.ain'), ++ ('Al Person', 'aperson@dom.ain'), ++ ('Mariusz Felisiak', 'to@example.com'), ++ ], ++ ) ++ ++ def test_parsing_errors(self): ++ """Test for parsing errors from CVE-2023-27043 and CVE-2019-16056""" ++ alice = 'alice@example.org' ++ bob = 'bob@example.com' ++ empty = ('', '') ++ ++ # Test utils.getaddresses() and utils.parseaddr() on malformed email ++ # addresses: default behavior (strict=True) rejects malformed address, ++ # and strict=False which tolerates malformed address. ++ for invalid_separator, expected_non_strict in ( ++ ('(', [(f'<{bob}>', alice)]), ++ (')', [('', alice), empty, ('', bob)]), ++ ('<', [('', alice), empty, ('', bob), empty]), ++ ('>', [('', alice), empty, ('', bob)]), ++ ('[', [('', f'{alice}[<{bob}>]')]), ++ (']', [('', alice), empty, ('', bob)]), ++ ('@', [empty, empty, ('', bob)]), ++ (';', [('', alice), empty, ('', bob)]), ++ (':', [('', alice), ('', bob)]), ++ ('.', [('', alice + '.'), ('', bob)]), ++ ('"', [('', alice), ('', f'<{bob}>')]), ++ ): ++ address = f'{alice}{invalid_separator}<{bob}>' ++ with self.subTest(address=address): ++ self.assertEqual(utils.getaddresses([address]), ++ [empty]) ++ self.assertEqual(utils.getaddresses([address], strict=False), ++ expected_non_strict) ++ ++ self.assertEqual(utils.parseaddr([address]), ++ empty) ++ self.assertEqual(utils.parseaddr([address], strict=False), ++ ('', address)) ++ ++ # Comma (',') is treated differently depending on strict parameter. ++ # Comma without quotes. ++ address = f'{alice},<{bob}>' ++ self.assertEqual(utils.getaddresses([address]), ++ [('', alice), ('', bob)]) ++ self.assertEqual(utils.getaddresses([address], strict=False), ++ [('', alice), ('', bob)]) ++ self.assertEqual(utils.parseaddr([address]), ++ empty) ++ self.assertEqual(utils.parseaddr([address], strict=False), ++ ('', address)) ++ ++ # Real name between quotes containing comma. ++ address = '"Alice, alice@example.org" ' ++ expected_strict = ('Alice, alice@example.org', 'bob@example.com') ++ self.assertEqual(utils.getaddresses([address]), [expected_strict]) ++ self.assertEqual(utils.getaddresses([address], strict=False), [expected_strict]) ++ self.assertEqual(utils.parseaddr([address]), expected_strict) ++ self.assertEqual(utils.parseaddr([address], strict=False), ++ ('', address)) ++ ++ # Valid parenthesis in comments. ++ address = 'alice@example.org (Alice)' ++ expected_strict = ('Alice', 'alice@example.org') ++ self.assertEqual(utils.getaddresses([address]), [expected_strict]) ++ self.assertEqual(utils.getaddresses([address], strict=False), [expected_strict]) ++ self.assertEqual(utils.parseaddr([address]), expected_strict) ++ self.assertEqual(utils.parseaddr([address], strict=False), ++ ('', address)) ++ ++ # Invalid parenthesis in comments. ++ address = 'alice@example.org )Alice(' ++ self.assertEqual(utils.getaddresses([address]), [empty]) ++ self.assertEqual(utils.getaddresses([address], strict=False), ++ [('', 'alice@example.org'), ('', ''), ('', 'Alice')]) ++ self.assertEqual(utils.parseaddr([address]), empty) ++ self.assertEqual(utils.parseaddr([address], strict=False), ++ ('', address)) ++ ++ # Two addresses with quotes separated by comma. ++ address = '"Jane Doe" , "John Doe" ' ++ self.assertEqual(utils.getaddresses([address]), ++ [('Jane Doe', 'jane@example.net'), ++ ('John Doe', 'john@example.net')]) ++ self.assertEqual(utils.getaddresses([address], strict=False), ++ [('Jane Doe', 'jane@example.net'), ++ ('John Doe', 'john@example.net')]) ++ self.assertEqual(utils.parseaddr([address]), empty) ++ self.assertEqual(utils.parseaddr([address], strict=False), ++ ('', address)) ++ ++ # Test email.utils.supports_strict_parsing attribute ++ self.assertEqual(email.utils.supports_strict_parsing, True) ++ + def test_getaddresses_nasty(self): +- eq = self.assertEqual +- eq(utils.getaddresses(['foo: ;']), [('', '')]) +- eq(utils.getaddresses( +- ['[]*-- =~$']), +- [('', ''), ('', ''), ('', '*--')]) +- eq(utils.getaddresses( +- ['foo: ;', '"Jason R. Mastaler" ']), +- [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')]) ++ for addresses, expected in ( ++ (['"Sürname, Firstname" '], ++ [('Sürname, Firstname', 'to@example.com')]), ++ ++ (['foo: ;'], ++ [('', '')]), ++ ++ (['foo: ;', '"Jason R. Mastaler" '], ++ [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')]), ++ ++ ([r'Pete(A nice \) chap) '], ++ [('Pete (A nice ) chap his account his host)', 'pete@silly.test')]), ++ ++ (['(Empty list)(start)Undisclosed recipients :(nobody(I know))'], ++ [('', '')]), ++ ++ (['Mary <@machine.tld:mary@example.net>, , jdoe@test . example'], ++ [('Mary', 'mary@example.net'), ('', ''), ('', 'jdoe@test.example')]), ++ ++ (['John Doe '], ++ [('John Doe (comment)', 'jdoe@machine.example')]), ++ ++ (['"Mary Smith: Personal Account" '], ++ [('Mary Smith: Personal Account', 'smith@home.example')]), ++ ++ (['Undisclosed recipients:;'], ++ [('', '')]), ++ ++ ([r', "Giant; \"Big\" Box" '], ++ [('', 'boss@nil.test'), ('Giant; "Big" Box', 'bob@example.net')]), ++ ): ++ with self.subTest(addresses=addresses): ++ self.assertEqual(utils.getaddresses(addresses), ++ expected) ++ self.assertEqual(utils.getaddresses(addresses, strict=False), ++ expected) ++ ++ addresses = ['[]*-- =~$'] ++ self.assertEqual(utils.getaddresses(addresses), ++ [('', '')]) ++ self.assertEqual(utils.getaddresses(addresses, strict=False), ++ [('', ''), ('', ''), ('', '*--')]) + + def test_getaddresses_embedded_comment(self): + """Test proper handling of a nested comment""" +@@ -3485,6 +3625,54 @@ def test_mime_classes_policy_argument(self): + m = cls(*constructor, policy=email.policy.default) + self.assertIs(m.policy, email.policy.default) + ++ def test_iter_escaped_chars(self): ++ self.assertEqual(list(utils._iter_escaped_chars(r'a\\b\"c\\"d')), ++ [(0, 'a'), ++ (2, '\\\\'), ++ (3, 'b'), ++ (5, '\\"'), ++ (6, 'c'), ++ (8, '\\\\'), ++ (9, '"'), ++ (10, 'd')]) ++ self.assertEqual(list(utils._iter_escaped_chars('a\\')), ++ [(0, 'a'), (1, '\\')]) ++ ++ def test_strip_quoted_realnames(self): ++ def check(addr, expected): ++ self.assertEqual(utils._strip_quoted_realnames(addr), expected) ++ ++ check('"Jane Doe" , "John Doe" ', ++ ' , ') ++ check(r'"Jane \"Doe\"." ', ++ ' ') ++ ++ # special cases ++ check(r'before"name"after', 'beforeafter') ++ check(r'before"name"', 'before') ++ check(r'b"name"', 'b') # single char ++ check(r'"name"after', 'after') ++ check(r'"name"a', 'a') # single char ++ check(r'"name"', '') ++ ++ # no change ++ for addr in ( ++ 'Jane Doe , John Doe ', ++ 'lone " quote', ++ ): ++ self.assertEqual(utils._strip_quoted_realnames(addr), addr) ++ ++ ++ def test_check_parenthesis(self): ++ addr = 'alice@example.net' ++ self.assertTrue(utils._check_parenthesis(f'{addr} (Alice)')) ++ self.assertFalse(utils._check_parenthesis(f'{addr} )Alice(')) ++ self.assertFalse(utils._check_parenthesis(f'{addr} (Alice))')) ++ self.assertFalse(utils._check_parenthesis(f'{addr} ((Alice)')) ++ ++ # Ignore real name between quotes ++ self.assertTrue(utils._check_parenthesis(f'")Alice((" {addr}')) ++ + + # Test the iterator/generators + class TestIterators(TestEmailBase): +diff --git a/Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst b/Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst +new file mode 100644 +index 0000000000..3d0e9e4078 +--- /dev/null ++++ b/Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst +@@ -0,0 +1,8 @@ ++:func:`email.utils.getaddresses` and :func:`email.utils.parseaddr` now ++return ``('', '')`` 2-tuples in more situations where invalid email ++addresses are encountered instead of potentially inaccurate values. Add ++optional *strict* parameter to these two functions: use ``strict=False`` to ++get the old behavior, accept malformed inputs. ++``getattr(email.utils, 'supports_strict_parsing', False)`` can be use to check ++if the *strict* paramater is available. Patch by Thomas Dwyer and Victor ++Stinner to improve the CVE-2023-27043 fix. diff --git a/00419-gh-112769-test_zlib-fix-comparison-of-zlib_runtime_version-with-non-int-suffix-gh-112771-gh-112774.patch b/00419-gh-112769-test_zlib-fix-comparison-of-zlib_runtime_version-with-non-int-suffix-gh-112771-gh-112774.patch new file mode 100644 index 0000000..1e718a6 --- /dev/null +++ b/00419-gh-112769-test_zlib-fix-comparison-of-zlib_runtime_version-with-non-int-suffix-gh-112771-gh-112774.patch @@ -0,0 +1,66 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= +Date: Tue, 5 Dec 2023 21:02:06 +0100 +Subject: [PATCH] 00419: gh-112769: test_zlib: Fix comparison of + ZLIB_RUNTIME_VERSION with non-int suffix (GH-112771) (GH-112774) + +zlib-ng defines the version as "1.3.0.zlib-ng". +(cherry picked from commit d384813ff18b33280a90b6d2011654528a2b6ad1) +--- + Lib/test/test_zlib.py | 28 ++++++++++++++++------------ + 1 file changed, 16 insertions(+), 12 deletions(-) + +diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py +index cb0610837b..98cac4fb91 100644 +--- a/Lib/test/test_zlib.py ++++ b/Lib/test/test_zlib.py +@@ -19,6 +19,20 @@ + 'requires Decompress.copy()') + + ++def _zlib_runtime_version_tuple(zlib_version=zlib.ZLIB_RUNTIME_VERSION): ++ # Register "1.2.3" as "1.2.3.0" ++ # or "1.2.0-linux","1.2.0.f","1.2.0.f-linux" ++ v = zlib_version.split('-', 1)[0].split('.') ++ if len(v) < 4: ++ v.append('0') ++ elif not v[-1].isnumeric(): ++ v[-1] = '0' ++ return tuple(map(int, v)) ++ ++ ++ZLIB_RUNTIME_VERSION_TUPLE = _zlib_runtime_version_tuple() ++ ++ + class VersionTestCase(unittest.TestCase): + + def test_library_version(self): +@@ -445,9 +459,8 @@ def test_flushes(self): + sync_opt = ['Z_NO_FLUSH', 'Z_SYNC_FLUSH', 'Z_FULL_FLUSH', + 'Z_PARTIAL_FLUSH'] + +- ver = tuple(int(v) for v in zlib.ZLIB_RUNTIME_VERSION.split('.')) + # Z_BLOCK has a known failure prior to 1.2.5.3 +- if ver >= (1, 2, 5, 3): ++ if ZLIB_RUNTIME_VERSION_TUPLE >= (1, 2, 5, 3): + sync_opt.append('Z_BLOCK') + + sync_opt = [getattr(zlib, opt) for opt in sync_opt +@@ -776,16 +789,7 @@ def test_large_unconsumed_tail(self, size): + + def test_wbits(self): + # wbits=0 only supported since zlib v1.2.3.5 +- # Register "1.2.3" as "1.2.3.0" +- # or "1.2.0-linux","1.2.0.f","1.2.0.f-linux" +- v = zlib.ZLIB_RUNTIME_VERSION.split('-', 1)[0].split('.') +- if len(v) < 4: +- v.append('0') +- elif not v[-1].isnumeric(): +- v[-1] = '0' +- +- v = tuple(map(int, v)) +- supports_wbits_0 = v >= (1, 2, 3, 5) ++ supports_wbits_0 = ZLIB_RUNTIME_VERSION_TUPLE >= (1, 2, 3, 5) + + co = zlib.compressobj(level=1, wbits=15) + zlib15 = co.compress(HAMLET_SCENE) + co.flush() diff --git a/00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch b/00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch deleted file mode 100644 index 2e2f3c6..0000000 --- a/00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: "Miss Islington (bot)" - <31488909+miss-islington@users.noreply.github.com> -Date: Mon, 31 Mar 2025 20:29:04 +0200 -Subject: 00452: Properly apply exported CFLAGS for dtrace/systemtap builds - -When using --with-dtrace the resulting object file could be missing -specific CFLAGS exported by the build system due to the systemtap -script using specific defaults. - -Exporting the CC and CFLAGS variables before the dtrace invocation -allows us to properly apply CFLAGS exported by the build system -even when cross-compiling. - -Co-authored-by: stratakis ---- - Makefile.pre.in | 4 ++-- - .../next/Build/2025-03-31-19-22-41.gh-issue-131865.PIJy7X.rst | 2 ++ - 2 files changed, 4 insertions(+), 2 deletions(-) - create mode 100644 Misc/NEWS.d/next/Build/2025-03-31-19-22-41.gh-issue-131865.PIJy7X.rst - -diff --git a/Makefile.pre.in b/Makefile.pre.in -index fa99dd86c4..e9ba702a5c 100644 ---- a/Makefile.pre.in -+++ b/Makefile.pre.in -@@ -1001,7 +1001,7 @@ Python/frozen.o: $(srcdir)/Python/importlib.h $(srcdir)/Python/importlib_externa - # an include guard, so we can't use a pipeline to transform its output. - Include/pydtrace_probes.h: $(srcdir)/Include/pydtrace.d - $(MKDIR_P) Include -- $(DTRACE) $(DFLAGS) -o $@ -h -s $< -+ CC="$(CC)" CFLAGS="$(CFLAGS)" $(DTRACE) $(DFLAGS) -o $@ -h -s $< - : sed in-place edit with POSIX-only tools - sed 's/PYTHON_/PyDTrace_/' $@ > $@.tmp - mv $@.tmp $@ -@@ -1011,7 +1011,7 @@ Python/import.o: $(srcdir)/Include/pydtrace.h - Modules/gcmodule.o: $(srcdir)/Include/pydtrace.h - - Python/pydtrace.o: $(srcdir)/Include/pydtrace.d $(DTRACE_DEPS) -- $(DTRACE) $(DFLAGS) -o $@ -G -s $< $(DTRACE_DEPS) -+ CC="$(CC)" CFLAGS="$(CFLAGS)" $(DTRACE) $(DFLAGS) -o $@ -G -s $< $(DTRACE_DEPS) - - Objects/typeobject.o: Objects/typeslots.inc - -diff --git a/Misc/NEWS.d/next/Build/2025-03-31-19-22-41.gh-issue-131865.PIJy7X.rst b/Misc/NEWS.d/next/Build/2025-03-31-19-22-41.gh-issue-131865.PIJy7X.rst -new file mode 100644 -index 0000000000..a287e0b228 ---- /dev/null -+++ b/Misc/NEWS.d/next/Build/2025-03-31-19-22-41.gh-issue-131865.PIJy7X.rst -@@ -0,0 +1,2 @@ -+The DTrace build now properly passes the ``CC`` and ``CFLAGS`` variables -+to the ``dtrace`` command when utilizing SystemTap on Linux. diff --git a/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch b/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch deleted file mode 100644 index 1eaf3a2..0000000 --- a/00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch +++ /dev/null @@ -1,214 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: yevgeny hong -Date: Tue, 26 Mar 2024 16:45:43 +0900 -Subject: 00462: Fix PySSL_SetError handling SSL_ERROR_SYSCALL - -Python 3.10 changed from using SSL_write() and SSL_read() to SSL_write_ex() and -SSL_read_ex(), but did not update handling of the return value. - -Change error handling so that the return value is not examined. -OSError (not EOF) is now returned when retval is 0. - -This resolves the issue of failing tests when a system is -stressed on OpenSSL 3.5. - -Co-authored-by: Serhiy Storchaka -Co-authored-by: Petr Viktorin ---- - Lib/test/test_ssl.py | 41 +++++++--------- - ...-02-18-09-50-31.gh-issue-115627.HGchj0.rst | 2 + - Modules/_ssl.c | 48 +++++++------------ - 3 files changed, 38 insertions(+), 53 deletions(-) - create mode 100644 Misc/NEWS.d/next/Library/2024-02-18-09-50-31.gh-issue-115627.HGchj0.rst - -diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py -index f4bba8ff03..f772bd6ab6 100644 ---- a/Lib/test/test_ssl.py -+++ b/Lib/test/test_ssl.py -@@ -2607,16 +2607,18 @@ def run(self): - self.write(msg.lower()) - except OSError as e: - # handles SSLError and socket errors -+ if isinstance(e, ConnectionError): -+ # OpenSSL 1.1.1 sometimes raises -+ # ConnectionResetError when connection is not -+ # shut down gracefully. -+ if self.server.chatty and support.verbose: -+ print(f" Connection reset by peer: {self.addr}") -+ -+ self.close() -+ self.running = False -+ return - if self.server.chatty and support.verbose: -- if isinstance(e, ConnectionError): -- # OpenSSL 1.1.1 sometimes raises -- # ConnectionResetError when connection is not -- # shut down gracefully. -- print( -- f" Connection reset by peer: {self.addr}" -- ) -- else: -- handle_error("Test server failure:\n") -+ handle_error("Test server failure:\n") - try: - self.write(b"ERROR\n") - except OSError: -@@ -3298,23 +3300,16 @@ def test_wrong_cert_tls13(self): - client_context.wrap_socket(socket.socket(), - server_hostname=hostname, - suppress_ragged_eofs=False) as s: -- # TLS 1.3 perform client cert exchange after handshake - s.connect((HOST, server.port)) -- try: -+ with self.assertRaisesRegex( -+ OSError, -+ 'alert unknown ca|EOF occurred|TLSV1_ALERT_UNKNOWN_CA|closed by the remote host|Connection reset by peer' -+ ): -+ # TLS 1.3 perform client cert exchange after handshake - s.write(b'data') - s.read(1000) - s.write(b'should have failed already') - s.read(1000) -- except ssl.SSLError as e: -- if support.verbose: -- sys.stdout.write("\nSSLError is %r\n" % e) -- except OSError as e: -- if e.errno != errno.ECONNRESET: -- raise -- if support.verbose: -- sys.stdout.write("\nsocket.error is %r\n" % e) -- else: -- self.fail("Use of invalid cert should have failed!") - - def test_rude_shutdown(self): - """A brutal shutdown of an SSL server should raise an OSError -@@ -4560,8 +4555,8 @@ def msg_cb(conn, direction, version, content_type, msg_type, data): - # test sometimes fails with EOF error. Test passes as long as - # server aborts connection with an error. - with self.assertRaisesRegex( -- ssl.SSLError, -- '(certificate required|EOF occurred)' -+ OSError, -+ 'certificate required|EOF occurred|closed by the remote host|Connection reset by peer' - ): - # receive CertificateRequest - data = s.recv(1024) -diff --git a/Misc/NEWS.d/next/Library/2024-02-18-09-50-31.gh-issue-115627.HGchj0.rst b/Misc/NEWS.d/next/Library/2024-02-18-09-50-31.gh-issue-115627.HGchj0.rst -new file mode 100644 -index 0000000000..75d926ab59 ---- /dev/null -+++ b/Misc/NEWS.d/next/Library/2024-02-18-09-50-31.gh-issue-115627.HGchj0.rst -@@ -0,0 +1,2 @@ -+Fix the :mod:`ssl` module error handling of connection terminate by peer. -+It now throws an OSError with the appropriate error code instead of an EOFError. -diff --git a/Modules/_ssl.c b/Modules/_ssl.c -index af770c7f18..7b3cf61474 100644 ---- a/Modules/_ssl.c -+++ b/Modules/_ssl.c -@@ -582,7 +582,7 @@ PySSL_ChainExceptions(PySSLSocket *sslsock) { - } - - static PyObject * --PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno) -+PySSL_SetError(PySSLSocket *sslsock, const char *filename, int lineno) - { - PyObject *type; - char *errstr = NULL; -@@ -595,7 +595,6 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno) - _sslmodulestate *state = get_state_sock(sslsock); - type = state->PySSLErrorObject; - -- assert(ret <= 0); - e = ERR_peek_last_error(); - - if (sslsock->ssl != NULL) { -@@ -628,32 +627,21 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno) - case SSL_ERROR_SYSCALL: - { - if (e == 0) { -- PySocketSockObject *s = GET_SOCKET(sslsock); -- if (ret == 0 || (((PyObject *)s) == Py_None)) { -+ /* underlying BIO reported an I/O error */ -+ ERR_clear_error(); -+#ifdef MS_WINDOWS -+ if (err.ws) { -+ return PyErr_SetFromWindowsErr(err.ws); -+ } -+#endif -+ if (err.c) { -+ errno = err.c; -+ return PyErr_SetFromErrno(PyExc_OSError); -+ } -+ else { - p = PY_SSL_ERROR_EOF; - type = state->PySSLEOFErrorObject; - errstr = "EOF occurred in violation of protocol"; -- } else if (s && ret == -1) { -- /* underlying BIO reported an I/O error */ -- ERR_clear_error(); --#ifdef MS_WINDOWS -- if (err.ws) { -- return PyErr_SetFromWindowsErr(err.ws); -- } --#endif -- if (err.c) { -- errno = err.c; -- return PyErr_SetFromErrno(PyExc_OSError); -- } -- else { -- p = PY_SSL_ERROR_EOF; -- type = state->PySSLEOFErrorObject; -- errstr = "EOF occurred in violation of protocol"; -- } -- } else { /* possible? */ -- p = PY_SSL_ERROR_SYSCALL; -- type = state->PySSLSyscallErrorObject; -- errstr = "Some I/O error occurred"; - } - } else { - if (ERR_GET_LIB(e) == ERR_LIB_SYS) { -@@ -1014,7 +1002,7 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self) - err.ssl == SSL_ERROR_WANT_WRITE); - Py_XDECREF(sock); - if (ret < 1) -- return PySSL_SetError(self, ret, __FILE__, __LINE__); -+ return PySSL_SetError(self, __FILE__, __LINE__); - if (PySSL_ChainExceptions(self) < 0) - return NULL; - Py_RETURN_NONE; -@@ -2433,7 +2421,7 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b) - - Py_XDECREF(sock); - if (retval == 0) -- return PySSL_SetError(self, retval, __FILE__, __LINE__); -+ return PySSL_SetError(self, __FILE__, __LINE__); - if (PySSL_ChainExceptions(self) < 0) - return NULL; - return PyLong_FromSize_t(count); -@@ -2463,7 +2451,7 @@ _ssl__SSLSocket_pending_impl(PySSLSocket *self) - self->err = err; - - if (count < 0) -- return PySSL_SetError(self, count, __FILE__, __LINE__); -+ return PySSL_SetError(self, __FILE__, __LINE__); - else - return PyLong_FromLong(count); - } -@@ -2585,7 +2573,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len, - err.ssl == SSL_ERROR_WANT_WRITE); - - if (retval == 0) { -- PySSL_SetError(self, retval, __FILE__, __LINE__); -+ PySSL_SetError(self, __FILE__, __LINE__); - goto error; - } - if (self->exc_type != NULL) -@@ -2709,7 +2697,7 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self) - } - if (ret < 0) { - Py_XDECREF(sock); -- PySSL_SetError(self, ret, __FILE__, __LINE__); -+ PySSL_SetError(self, __FILE__, __LINE__); - return NULL; - } - if (self->exc_type != NULL) diff --git a/00474-cve-2025-15366.patch b/00474-cve-2025-15366.patch deleted file mode 100644 index 0b4fd18..0000000 --- a/00474-cve-2025-15366.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Seth Michael Larson -Date: Tue, 20 Jan 2026 14:45:42 -0600 -Subject: 00474: CVE-2025-15366 - -gh-143921: Reject control characters in IMAP commands - -(cherry-picked from commit 6262704b134db2a4ba12e85ecfbd968534f28b45) ---- - Lib/imaplib.py | 4 +++- - Lib/test/test_imaplib.py | 6 ++++++ - .../Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst | 1 + - 3 files changed, 10 insertions(+), 1 deletion(-) - create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst - -diff --git a/Lib/imaplib.py b/Lib/imaplib.py -index 54122f985b..9ab8e43bbf 100644 ---- a/Lib/imaplib.py -+++ b/Lib/imaplib.py -@@ -132,7 +132,7 @@ - # We compile these in _mode_xxx. - _Literal = br'.*{(?P\d+)}$' - _Untagged_status = br'\* (?P\d+) (?P[A-Z-]+)( (?P.*))?' -- -+_control_chars = re.compile(b'[\x00-\x1F\x7F]') - - - class IMAP4: -@@ -994,6 +994,8 @@ def _command(self, name, *args): - if arg is None: continue - if isinstance(arg, str): - arg = bytes(arg, self._encoding) -+ if _control_chars.search(arg): -+ raise ValueError("Control characters not allowed in commands") - data = data + b' ' + arg - - literal = self.literal -diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py -index f817707743..9ce59b3040 100644 ---- a/Lib/test/test_imaplib.py -+++ b/Lib/test/test_imaplib.py -@@ -505,6 +505,12 @@ def test_login(self): - self.assertEqual(data[0], b'LOGIN completed') - self.assertEqual(client.state, 'AUTH') - -+ def test_control_characters(self): -+ client, _ = self._setup(SimpleIMAPHandler) -+ for c0 in support.control_characters_c0(): -+ with self.assertRaises(ValueError): -+ client.login(f'user{c0}', 'pass') -+ - def test_logout(self): - client, _ = self._setup(SimpleIMAPHandler) - typ, data = client.login('user', 'pass') -diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst -new file mode 100644 -index 0000000000..4e13fe92bc ---- /dev/null -+++ b/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst -@@ -0,0 +1 @@ -+Reject control characters in IMAP commands. diff --git a/00475-cve-2025-15367.patch b/00475-cve-2025-15367.patch deleted file mode 100644 index 9a64894..0000000 --- a/00475-cve-2025-15367.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Seth Michael Larson -Date: Tue, 20 Jan 2026 14:46:32 -0600 -Subject: 00475: CVE-2025-15367 - -gh-143923: Reject control characters in POP3 commands - -(cherry-picked from commit b234a2b67539f787e191d2ef19a7cbdce32874e7) ---- - 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 0f8587317c..f563030f7f 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 1220ca32ef..2655e366fd 100644 ---- a/Lib/test/test_poplib.py -+++ b/Lib/test/test_poplib.py -@@ -12,6 +12,7 @@ - import unittest - from unittest import TestCase, skipUnless - from test import support as test_support -+from test.support import control_characters_c0 - from test.support import hashlib_helper - from test.support import socket_helper - from test.support import threading_helper -@@ -365,6 +366,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. diff --git a/00494-increase-the-timeout-of-test_large_content_length_truncated.patch b/00494-increase-the-timeout-of-test_large_content_length_truncated.patch deleted file mode 100644 index 58ffd5d..0000000 --- a/00494-increase-the-timeout-of-test_large_content_length_truncated.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Karolina Surma -Date: Fri, 14 Aug 2026 09:38:26 +0200 -Subject: 00494: Increase the timeout of test_large_content_length_truncated - -It has started to fail randomly when run on s390x architecture. ---- - Lib/test/test_httpservers.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py -index 5eb3c82fbd..aa8ad1c323 100644 ---- a/Lib/test/test_httpservers.py -+++ b/Lib/test/test_httpservers.py -@@ -872,7 +872,7 @@ def test_large_content_length(self): - self.assertEqual(res.read(), b'%d %d' % (size, size) + self.linesep) - - def test_large_content_length_truncated(self): -- with support.swap_attr(self.request_handler, 'timeout', 0.001): -+ with support.swap_attr(self.request_handler, 'timeout', support.LOOPBACK_TIMEOUT): - for w in range(18, 65): - size = 1 << w - headers = {'Content-Length' : str(size)} diff --git a/plan.fmf b/plan.fmf deleted file mode 100644 index 88053e4..0000000 --- a/plan.fmf +++ /dev/null @@ -1,65 +0,0 @@ -execute: - how: tmt - -provision: - hardware: - memory: '>= 3 GB' - -environment: - pybasever: '3.10' - -discover: - - name: tests_python - how: shell - url: https://src.fedoraproject.org/tests/python.git - tests: - - name: smoke - path: /smoke - test: "VERSION=${pybasever} ./venv.sh" - - name: smoke_virtualenv - path: /smoke - test: "VERSION=${pybasever} METHOD=virtualenv ./venv.sh" - - name: debugsmoke - path: /smoke - test: "PYTHON=python${pybasever}d TOX=false VERSION=${pybasever} ./venv.sh" - - name: selftest - path: /selftest - test: "VERSION=${pybasever} X='' ./parallel.sh" - - name: debugtest - path: /selftest - test: "VERSION=${pybasever} PYTHON=python${pybasever}d X='' ./parallel.sh" - - name: debugflags - path: /flags - test: "python${pybasever}d ./assertflags.py -O0" - - name: marshalparser - path: /marshalparser - test: "VERSION=${pybasever} SAMPLE=10 ./test_marshalparser_compatibility.sh" - - name: required_symbols - path: /required-symbols - test: "VERSION=${pybasever} ./check.sh" - -prepare: - - name: Install dependencies - how: install - package: - - gcc # for extension building in venv and selftest - - gdb # for test_gdb - - "python${pybasever}" # the test subject - - "python${pybasever}-debug" # for leak testing - - "python${pybasever}-devel" # for extension building in venv and selftest - - "python${pybasever}-tkinter" # for selftest - - "python${pybasever}-test" # for selftest - - tox # for venv tests - - virtualenv # for virtualenv tests - - glibc-all-langpacks # for locale tests - - marshalparser # for testing compatibility (magic numbers) with marshalparser - - binutils # for nm (symbol inspection) - - rpm # for debugging - - dnf # for upgrade and downgrade - - name: Update packages - how: shell - script: dnf upgrade -y - - name: rpm_qa - order: 100 - how: shell - script: rpm -qa | sort | tee $TMT_PLAN_DATA/rpmqa.txt diff --git a/python3.10.spec b/python3.10.spec index 3378bf7..df16825 100644 --- a/python3.10.spec +++ b/python3.10.spec @@ -13,11 +13,11 @@ URL: https://www.python.org/ # WARNING When rebasing to a new Python version, # remember to update the python3-docs package as well -%global general_version %{pybasever}.21 +%global general_version %{pybasever}.14 #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 1%{?dist} +Release: 2%{?dist} License: Python-2.0.1 @@ -68,7 +68,7 @@ License: Python-2.0.1 # from Python with the versions below. # This needs to be manually updated when we update Python. %global pip_version 23.0.1 -%global setuptools_version 79.0.1 +%global setuptools_version 65.5.0 # Expensive optimizations (mainly, profile-guided optimizations) %bcond_without optimizations @@ -192,7 +192,8 @@ BuildRequires: bluez-libs-devel BuildRequires: bzip2 BuildRequires: bzip2-devel BuildRequires: desktop-file-utils -BuildRequires: expat-devel +# See the runtime requirement in the -libs subpackage +BuildRequires: expat-devel >= 2.6 BuildRequires: findutils BuildRequires: gcc-c++ @@ -210,12 +211,12 @@ BuildRequires: libnsl2-devel BuildRequires: libtirpc-devel BuildRequires: libGL-devel BuildRequires: libuuid-devel -BuildRequires: libxcrypt-devel BuildRequires: libX11-devel BuildRequires: make BuildRequires: mpdecimal-devel BuildRequires: ncurses-devel +BuildRequires: openssl-devel BuildRequires: pkgconfig BuildRequires: readline-devel BuildRequires: redhat-rpm-config >= 127 @@ -223,15 +224,11 @@ BuildRequires: sqlite-devel BuildRequires: gdb BuildRequires: tar -BuildRequires: tcl-devel < 1:9 +BuildRequires: tcl-devel BuildRequires: tix-devel -BuildRequires: tk-devel < 1:9 +BuildRequires: tk-devel BuildRequires: tzdata -# 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 %{with valgrind} BuildRequires: valgrind-devel %endif @@ -239,7 +236,6 @@ BuildRequires: valgrind-devel BuildRequires: xz-devel BuildRequires: zlib-devel -BuildRequires: systemtap-sdt-devel BuildRequires: /usr/bin/dtrace # workaround http://bugs.python.org/issue19804 (test_uuid requires ifconfig) @@ -248,9 +244,6 @@ BuildRequires: /usr/sbin/ifconfig %if %{with rpmwheels} BuildRequires: %{python_wheel_pkg_prefix}-setuptools-wheel BuildRequires: %{python_wheel_pkg_prefix}-pip-wheel -%else -# For %%python_wheel_inject_sbom -BuildRequires: python-rpm-macros %endif %if %{without bootstrap} @@ -292,7 +285,6 @@ Source11: idle3.appdata.xml # 00001 # d06a8853cf4bae9e115f45e1d531d2dc152c5cc8 # Fixup distutils/unixccompiler.py to remove standard library path from rpath -# # Was Patch0 in ivazquez' python3000 specfile Patch1: 00001-rpath.patch @@ -328,52 +320,20 @@ Patch251: 00251-change-user-install-location.patch # https://github.com/GrahamDumpleton/mod_wsgi/issues/730 Patch371: 00371-revert-bpo-1596321-fix-threading-_shutdown-for-the-main-thread-gh-28549-gh-28589.patch -# 00452 # eb11d070c5af7d1b5e47f4e02186152d08eaf793 -# Properly apply exported CFLAGS for dtrace/systemtap builds +# 00415 # 9ca4533e0b4a03d919953017026f66c6a060756e +# [CVE-2023-27043] gh-102988: Reject malformed addresses in email.parseaddr() (#111116) # -# When using --with-dtrace the resulting object file could be missing -# specific CFLAGS exported by the build system due to the systemtap -# script using specific defaults. -# -# Exporting the CC and CFLAGS variables before the dtrace invocation -# allows us to properly apply CFLAGS exported by the build system -# even when cross-compiling. -Patch452: 00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch +# Detect email address parsing errors and return empty tuple to +# indicate the parsing error (old API). Add an optional 'strict' +# parameter to getaddresses() and parseaddr() functions. Patch by +# Thomas Dwyer. +Patch415: 00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch -# 00462 # f0db87ee65704fa5545ea25f2cca8c43fc639fab -# Fix PySSL_SetError handling SSL_ERROR_SYSCALL +# 00419 # f13682530cc7e4daec2e40acd56508846fdd3aad +# gh-112769: test_zlib: Fix comparison of ZLIB_RUNTIME_VERSION with non-int suffix (GH-112771) (GH-112774) # -# Python 3.10 changed from using SSL_write() and SSL_read() to SSL_write_ex() and -# SSL_read_ex(), but did not update handling of the return value. -# -# Change error handling so that the return value is not examined. -# OSError (not EOF) is now returned when retval is 0. -# -# This resolves the issue of failing tests when a system is -# stressed on OpenSSL 3.5. -Patch462: 00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch - -# 00474 # 837ddca0372fa87ff9cee47142200caa21e77def -# CVE-2025-15366 -# -# gh-143921: Reject control characters in IMAP commands -# -# (cherry-picked from commit 6262704b134db2a4ba12e85ecfbd968534f28b45) -Patch474: 00474-cve-2025-15366.patch - -# 00475 # 3748209a316662d4e85981ca1a7418547a1d25c6 -# CVE-2025-15367 -# -# gh-143923: Reject control characters in POP3 commands -# -# (cherry-picked from commit b234a2b67539f787e191d2ef19a7cbdce32874e7) -Patch475: 00475-cve-2025-15367.patch - -# 00494 # 430aab133397ed44cc9ee621fd311e02fee317b5 -# Increase the timeout of test_large_content_length_truncated -# -# It has started to fail randomly when run on s390x architecture. -Patch494: 00494-increase-the-timeout-of-test_large_content_length_truncated.patch +# zlib-ng defines the version as "1.3.0.zlib-ng". +Patch419: 00419-gh-112769-test_zlib-fix-comparison-of-zlib_runtime_version-with-non-int-suffix-gh-112771-gh-112774.patch # (New patches go here ^^^) # @@ -521,24 +481,12 @@ Recommends: (%{pkgname}-tkinter%{?_isa} = %{version}-%{release} if tk%{?_isa}) 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: +# When built with expat >= 2.6, but installed with older expat, we 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. +# undefined symbol: XML_SetReparseDeferralEnabled # 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. # 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}' expat.%{_target_cpu} | sed 's/.*not installed/0/') -%if v"%{expat_version}" < v"2.7.4" -Requires: expat%{?_isa} >= %{expat_version} -%endif - +Requires: expat >= 2.6 # Since patch 251 changed from distutils to sysconfig, pip needed to be adapted # The previous versions could cause serious bugs during `sudo pip install --upgrade ...` @@ -1103,11 +1051,6 @@ for file in %{buildroot}%{pylibdir}/pydoc_data/topics.py $(grep --include='*.py' rm ${directory}/{__pycache__/${module}.cpython-%{pyshortver}.opt-?.pyc,${module}.py} 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 # ====================================================== @@ -1166,8 +1109,6 @@ CheckPython() { # test_distutils # distutils.tests.test_bdist_rpm tests fail when bootstraping the Python # package: rpmbuild requires /usr/bin/pythonX.Y to be installed - # test_sendfile_close_peer_in_the_middle_of_receiving: - # https://github.com/python/cpython/issues/120226 LD_LIBRARY_PATH=$ConfDir $ConfDir/python -m test.regrtest \ -wW --slowest -j0 --timeout=1800 \ %if %{with bootstrap} @@ -1176,9 +1117,6 @@ CheckPython() { %ifarch %{mips64} -x test_ctypes \ %endif - %ifarch ppc64le - -i test_sendfile_close_peer_in_the_middle_of_receiving \ - %endif echo FINISHED: CHECKING OF PYTHON FOR CONFIGURATION: $ConfName @@ -1678,86 +1616,6 @@ CheckPython optimized # ====================================================== %changelog -* Thu Aug 13 2026 Karolina Surma - 3.10.21-1 -- Update to Python 3.10.21 - -* Thu Jul 30 2026 Miro Hrončok - 3.10.20-4 - - Skip UDP Lite tests if it's not supported - - Fixes FTBFS on Linux kernel 7.1 and newer - -* Thu Jul 16 2026 Fedora Release Engineering - 3.10.20-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild - -* Sat Apr 11 2026 Miro Hrončok - 3.10.20-2 -- Explicitly build with OpenSSL 3 -- Fix ssl.SSLError: [ASN1: NOT_ENOUGH_DATA] not enough data with OpenSSL 3.5.7+ - -* Tue Mar 03 2026 Tomáš Hrnčiar - 3.10.20-1 -- Update to 3.10.20 - -* Mon Feb 09 2026 Tomáš Hrnčiar - 3.10.19-4 -- Security fixes for CVE-2026-0865, CVE-2025-15366 and CVE-2025-15367 - -* Sat Jan 17 2026 Fedora Release Engineering - 3.10.19-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild - -* Tue Jan 06 2026 Karolina Surma - 3.10.19-2 -- Require at least the same expat version as used during the build time - -* Fri Oct 10 2025 Karolina Surma - 3.10.19-1 -- Update to Python 3.10.19 - -* Fri Jul 25 2025 Fedora Release Engineering - 3.10.18-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild - -* Wed Jun 04 2025 Tomáš Hrnčiar - 3.10.18-1 -- Update to 3.10.18 - -* Tue May 13 2025 Charalampos Stratakis - 3.10.17-3 -- Fix PySSL_SetError handling SSL_ERROR_SYSCALL -- This fixes random flakiness of test_ssl on stressed machines - -* Wed Apr 16 2025 Charalampos Stratakis - 3.10.17-2 -- test_ssl: Don't stop ThreadedEchoServer on OSError in ConnectionHandler -- Fixes: rhbz#2355052 - -* Wed Apr 09 2025 Miro Hrončok - 3.10.17-1 -- Update to 3.10.17 - -* Mon Mar 31 2025 Charalampos Stratakis - 3.10.16-6 -- Properly apply exported CFLAGS for dtrace/systemtap builds -- Fixes: rhbz#2356303 - -* Mon Feb 10 2025 Charalampos Stratakis - 3.10.16-5 -- Security fix for CVE-2025-0938 -- Fixes: rhbz#2343276 - -* Thu Feb 06 2025 Miro Hrončok - 3.10.16-4 -- Rebuilt with mpdecimal 4.0.0 - -* Sat Feb 01 2025 Björn Esser - 3.10.16-3 -- Add explicit BR: libxcrypt-devel - -* Sat Jan 18 2025 Fedora Release Engineering - 3.10.16-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild - -* Wed Dec 04 2024 Charalampos Stratakis - 3.10.16-1 -- Update to 3.10.16 -- Security fix for CVE-2024-9287 -Resolves: rhbz#2321654 - -* Wed Sep 11 2024 Miro Hrončok - 3.10.15-2 -- Fix ThreadedVSOCKSocketStreamTest - -* Mon Sep 09 2024 Tomáš Hrnčiar - 3.10.15-1 -- Update to 3.10.15 - -* Tue Jul 23 2024 Lumír Balhar - 3.10.14-4 -- Require systemtap-sdt-devel for sys/sdt.h - -* Fri Jul 19 2024 Fedora Release Engineering - 3.10.14-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild - * Wed Apr 17 2024 Miro Hrončok - 3.10.14-2 - Require expat >= 2.6 to prevent errors when creating venvs with older expat diff --git a/rpminspect.yaml b/rpminspect.yaml index 8cc18cb..83dfb5e 100644 --- a/rpminspect.yaml +++ b/rpminspect.yaml @@ -1,22 +1,22 @@ # exclude test XML data (not always valid) from XML validity check: xml: ignore: - - '/usr/lib*/python*/test/xmltestdata/*' - - '/usr/lib*/python*/test/xmltestdata/*/*' + - /usr/lib*/python*/test/xmltestdata/* + - /usr/lib*/python*/test/xmltestdata/*/* # exclude _socket from ipv4 only functions check, it has both ipv4 and ipv6 only badfuncs: allowed: - '/usr/lib*/python*/lib-dynload/_socket.*': + /usr/lib*/python*/lib-dynload/_socket.*: - inet_aton - inet_ntoa # exclude the debug build from annocheck entirely annocheck: ignore: - - '/usr/bin/python*d' - - '/usr/lib*/libpython*d.so.1.0' - - '/usr/lib*/python*/lib-dynload/*.cpython-*d-*-*-*.so' + - /usr/bin/python*d + - /usr/lib*/libpython*d.so.1.0 + - /usr/lib*/python*/lib-dynload/*.cpython-*d-*-*-*.so # don't report changed content of compiled files # that is expected with every toolchain update and not reproducible yet diff --git a/sources b/sources index 1833fd0..9acf607 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (Python-3.10.21.tar.xz) = 6f6de7c5e4c0457f2d189ed5d111c83fb8775e19123afe4f9fd0ae2b93f3fa2bbb7ad849ade6bb5227d4a6a3d63abc8e167fbe5fb54fa715660c89fd6274daee -SHA512 (Python-3.10.21.tar.xz.asc) = 72d6aeaa0f51e527f82392cf1f969b0ad50a48fe10e8b7e5feb6117718223d00757f7b375b3ac82e257571d5a61f8162e9dd59b81fcf8f2a441c6deb42be71cb +SHA512 (Python-3.10.14.tar.xz) = adee638aeca898743da4b8245c0fa1e9b94b516f22e716e60c99038f0bb3dcbf726317aa86656404be1719b5a7c58eb09533720ebc0badbb04bd9a534dd48fef +SHA512 (Python-3.10.14.tar.xz.asc) = 821046b8eb559c3ef800f26739c995e7a71469a1e765ee7d516690236e16d2637ada7b2f9535b8c0dceaacf243e7b059f6f106b4a25faae365aa2099d1ff538c diff --git a/.fmf/version b/tests/.fmf/version similarity index 100% rename from .fmf/version rename to tests/.fmf/version diff --git a/tests/provision.fmf b/tests/provision.fmf new file mode 100644 index 0000000..1a4f0f0 --- /dev/null +++ b/tests/provision.fmf @@ -0,0 +1,4 @@ +--- +standard-inventory-qcow2: + qemu: + m: 3G # Amount of VM memory diff --git a/tests/tests.yml b/tests/tests.yml new file mode 100644 index 0000000..460b4a1 --- /dev/null +++ b/tests/tests.yml @@ -0,0 +1,55 @@ +--- +- hosts: localhost + tags: + - classic + tasks: + - dnf: + name: "*" + state: latest + +- hosts: localhost + roles: + - role: standard-test-basic + tags: + - classic + repositories: + - repo: "https://src.fedoraproject.org/tests/python.git" + dest: "python" + pybasever: "3.10" + tests: + - rpm_qa: + run: rpm -qa + - smoke: + dir: python/smoke + run: "VERSION={{ pybasever }} ./venv.sh" + - smoke_virtualenv: + dir: python/smoke + run: "VERSION={{ pybasever }} METHOD=virtualenv ./venv.sh" + - debugsmoke: + dir: python/smoke + run: "PYTHON=python{{ pybasever }}d TOX=false VERSION={{ pybasever }} ./venv.sh" + - selftest: + dir: python/selftest + run: "VERSION={{ pybasever }} X='' ./parallel.sh" + - debugtest: + dir: python/selftest + run: "VERSION={{ pybasever }} PYTHON=python{{ pybasever }}d X='' ./parallel.sh" + - debugflags: + dir: python/flags + run: "python{{ pybasever }}d ./assertflags.py -O0" + - marshalparser: + dir: python/marshalparser + run: "VERSION={{ pybasever }} SAMPLE=10 test_marshalparser_compatibility.sh" + required_packages: + - gcc # for extension building in venv and selftest + - gdb # for test_gdb + - "python{{ pybasever }}" # the test subject + - "python{{ pybasever }}-debug" # for leak testing + - "python{{ pybasever }}-devel" # for extension building in venv and selftest + - "python{{ pybasever }}-tkinter" # for selftest + - "python{{ pybasever }}-test" # for selftest + - tox # for venv tests + - virtualenv # for virtualenv tests + - glibc-all-langpacks # for locale tests + - marshalparser # for testing compatibility (magic numbers) with marshalparser + - rpm # for debugging