Compare commits
No commits in common. "rawhide" and "f44" have entirely different histories.
4 changed files with 1 additions and 292 deletions
133
5097.patch
133
5097.patch
|
|
@ -1,133 +0,0 @@
|
|||
From 8d2659ac68ec8d46dfd8c2fc0ab057b647ac7940 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= <miro@hroncok.cz>
|
||||
Date: Wed, 1 Jul 2026 15:05:18 +0200
|
||||
Subject: [PATCH] Deal with ssl.PROTOCOL_TLSv1 removal from Python built with
|
||||
OpenSSL 4+
|
||||
|
||||
https://github.com/python/cpython/commit/3364e7e62fa24d0e19133fb0f90b1c24ef1110c5
|
||||
removed ssl.PROTOCOL_TLSv1 when python is built with OpenSSL 4+.
|
||||
|
||||
We are hitting this error in Fedora (where we already updated OpenSSL):
|
||||
|
||||
ImportError while loading conftest '/builddir/build/BUILD/python-urllib3-2.7.0-build/urllib3-2.7.0/test/conftest.py'.
|
||||
test/__init__.py:42: in <module>
|
||||
import urllib3.contrib.pyopenssl as pyopenssl
|
||||
../BUILDROOT/usr/lib/python3.15/site-packages/urllib3/contrib/pyopenssl.py:72: in <module>
|
||||
ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_METHOD,
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
E AttributeError: module 'ssl' has no attribute 'PROTOCOL_TLSv1'. Did you mean '.PROTOCOL_TLS' instead of '.PROTOCOL_TLSv1'?
|
||||
|
||||
Used LLM to figure out what to use as a replacement protocol in tests.
|
||||
|
||||
Assisted-By: Claude Opus 4.6
|
||||
---
|
||||
changelog/5097.bugfix.rst | 2 ++
|
||||
src/urllib3/contrib/pyopenssl.py | 4 +++-
|
||||
test/test_ssl.py | 14 ++++++++------
|
||||
test/test_util.py | 24 +++++++++++++++---------
|
||||
4 files changed, 28 insertions(+), 16 deletions(-)
|
||||
create mode 100644 changelog/5097.bugfix.rst
|
||||
|
||||
diff --git a/changelog/5097.bugfix.rst b/changelog/5097.bugfix.rst
|
||||
new file mode 100644
|
||||
index 0000000000..73ed0ddaa1
|
||||
--- /dev/null
|
||||
+++ b/changelog/5097.bugfix.rst
|
||||
@@ -0,0 +1,2 @@
|
||||
+Fixed an ``AttributeError`` on Python built with OpenSSL 4+, where
|
||||
+``ssl.PROTOCOL_TLSv1`` no longer exists.
|
||||
diff --git a/src/urllib3/contrib/pyopenssl.py b/src/urllib3/contrib/pyopenssl.py
|
||||
index 42781590ee..76a225b7bf 100644
|
||||
--- a/src/urllib3/contrib/pyopenssl.py
|
||||
+++ b/src/urllib3/contrib/pyopenssl.py
|
||||
@@ -68,9 +68,11 @@ class UnsupportedExtension(Exception): # type: ignore[no-redef]
|
||||
_openssl_versions: dict[int, int] = {
|
||||
util.ssl_.PROTOCOL_TLS: OpenSSL.SSL.SSLv23_METHOD, # type: ignore[attr-defined]
|
||||
util.ssl_.PROTOCOL_TLS_CLIENT: OpenSSL.SSL.SSLv23_METHOD, # type: ignore[attr-defined]
|
||||
- ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_METHOD,
|
||||
}
|
||||
|
||||
+if hasattr(ssl, "PROTOCOL_TLSv1") and hasattr(OpenSSL.SSL, "TLSv1_METHOD"):
|
||||
+ _openssl_versions[ssl.PROTOCOL_TLSv1] = OpenSSL.SSL.TLSv1_METHOD
|
||||
+
|
||||
if hasattr(ssl, "PROTOCOL_TLSv1_1") and hasattr(OpenSSL.SSL, "TLSv1_1_METHOD"):
|
||||
_openssl_versions[ssl.PROTOCOL_TLSv1_1] = OpenSSL.SSL.TLSv1_1_METHOD
|
||||
|
||||
diff --git a/test/test_ssl.py b/test/test_ssl.py
|
||||
index 6b1ab8589b..1e4063bf68 100644
|
||||
--- a/test/test_ssl.py
|
||||
+++ b/test/test_ssl.py
|
||||
@@ -176,19 +176,21 @@ def test_create_urllib3_context_default_ciphers(
|
||||
|
||||
context.set_ciphers.assert_not_called()
|
||||
|
||||
+ # PROTOCOL_TLS_SERVER is used as a stand-in for any non-default ssl_version.
|
||||
+ # PROTOCOL_TLSv1/TLSv1_2 are unavailable when Python is built with OpenSSL 4+.
|
||||
@pytest.mark.parametrize(
|
||||
"kwargs",
|
||||
[
|
||||
{
|
||||
- "ssl_version": ssl.PROTOCOL_TLSv1,
|
||||
+ "ssl_version": ssl.PROTOCOL_TLS_SERVER,
|
||||
"ssl_minimum_version": ssl.TLSVersion.MINIMUM_SUPPORTED,
|
||||
},
|
||||
{
|
||||
- "ssl_version": ssl.PROTOCOL_TLSv1,
|
||||
+ "ssl_version": ssl.PROTOCOL_TLS_SERVER,
|
||||
"ssl_maximum_version": ssl.TLSVersion.TLSv1,
|
||||
},
|
||||
{
|
||||
- "ssl_version": ssl.PROTOCOL_TLSv1,
|
||||
+ "ssl_version": ssl.PROTOCOL_TLS_SERVER,
|
||||
"ssl_minimum_version": ssl.TLSVersion.MINIMUM_SUPPORTED,
|
||||
"ssl_maximum_version": ssl.TLSVersion.MAXIMUM_SUPPORTED,
|
||||
},
|
||||
@@ -229,10 +231,10 @@ def test_create_urllib3_context_ssl_version_and_ssl_min_max_version_no_warning(
|
||||
@pytest.mark.parametrize(
|
||||
"kwargs",
|
||||
[
|
||||
- {"ssl_version": ssl.PROTOCOL_TLSv1, "ssl_minimum_version": None},
|
||||
- {"ssl_version": ssl.PROTOCOL_TLSv1, "ssl_maximum_version": None},
|
||||
+ {"ssl_version": ssl.PROTOCOL_TLS_SERVER, "ssl_minimum_version": None},
|
||||
+ {"ssl_version": ssl.PROTOCOL_TLS_SERVER, "ssl_maximum_version": None},
|
||||
{
|
||||
- "ssl_version": ssl.PROTOCOL_TLSv1,
|
||||
+ "ssl_version": ssl.PROTOCOL_TLS_SERVER,
|
||||
"ssl_minimum_version": None,
|
||||
"ssl_maximum_version": None,
|
||||
},
|
||||
diff --git a/test/test_util.py b/test/test_util.py
|
||||
index 8612ab5eaf..18c65f0312 100644
|
||||
--- a/test/test_util.py
|
||||
+++ b/test/test_util.py
|
||||
@@ -1216,15 +1216,21 @@ def test_resolve_cert_reqs(
|
||||
) -> None:
|
||||
assert resolve_cert_reqs(candidate) == requirements
|
||||
|
||||
- @pytest.mark.parametrize(
|
||||
- "candidate, version",
|
||||
- [
|
||||
- (ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1),
|
||||
- ("PROTOCOL_TLSv1", ssl.PROTOCOL_TLSv1),
|
||||
- ("TLSv1", ssl.PROTOCOL_TLSv1),
|
||||
- (ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23),
|
||||
- ],
|
||||
- )
|
||||
+ candidate_version = [
|
||||
+ (ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23),
|
||||
+ ("PROTOCOL_SSLv23", ssl.PROTOCOL_SSLv23),
|
||||
+ ("SSLv23", ssl.PROTOCOL_SSLv23),
|
||||
+ ]
|
||||
+ if hasattr(ssl, "PROTOCOL_TLSv1"):
|
||||
+ candidate_version.extend(
|
||||
+ [
|
||||
+ (ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1),
|
||||
+ ("PROTOCOL_TLSv1", ssl.PROTOCOL_TLSv1),
|
||||
+ ("TLSv1", ssl.PROTOCOL_TLSv1),
|
||||
+ ]
|
||||
+ )
|
||||
+
|
||||
+ @pytest.mark.parametrize("candidate, version", candidate_version)
|
||||
def test_resolve_ssl_version(self, candidate: int | str, version: int) -> None:
|
||||
assert resolve_ssl_version(candidate) == version
|
||||
|
||||
83
5103.patch
83
5103.patch
|
|
@ -1,83 +0,0 @@
|
|||
From 13fa1e033b37405b228599ee590af485dc3e38aa Mon Sep 17 00:00:00 2001
|
||||
From: Illia Volochii <illia.volochii@gmail.com>
|
||||
Date: Sat, 18 Jul 2026 13:25:41 +0200
|
||||
Subject: [PATCH] Replace deprecated pyOpenSSL `X509.get_subject` and
|
||||
`Context.set_passwd_cb` methods (#5103)
|
||||
|
||||
Rebased on top of urllib3-2.7.0.
|
||||
---
|
||||
src/urllib3/contrib/pyopenssl.py | 35 ++++++++++++++++++++++++++-------
|
||||
1 file changed, 28 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/src/urllib3/contrib/pyopenssl.py b/src/urllib3/contrib/pyopenssl.py
|
||||
index 76a225b7bf..a1b2c3d4e5 100644
|
||||
--- a/src/urllib3/contrib/pyopenssl.py
|
||||
+++ b/src/urllib3/contrib/pyopenssl.py
|
||||
@@ -42,6 +42,8 @@
|
||||
|
||||
import OpenSSL.SSL # type: ignore[import-not-found]
|
||||
from cryptography import x509
|
||||
+from cryptography.hazmat.primitives.serialization import load_pem_private_key
|
||||
+from cryptography.x509.oid import NameOID
|
||||
|
||||
try:
|
||||
from cryptography.x509 import UnsupportedExtension # type: ignore[attr-defined]
|
||||
@@ -272,6 +274,15 @@
|
||||
return names
|
||||
|
||||
|
||||
+def _get_common_name(peer_cert: X509) -> str | None:
|
||||
+ """
|
||||
+ Given a pyOpenSSL certificate, return the subject's common name.
|
||||
+ """
|
||||
+ cert = peer_cert.to_cryptography()
|
||||
+ names = cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)
|
||||
+ return typing.cast(str, names[0].value) if names else None
|
||||
+
|
||||
+
|
||||
class WrappedSocket:
|
||||
"""API-compatibility wrapper for Python OpenSSL's Connection-class."""
|
||||
|
||||
@@ -396,7 +407,7 @@
|
||||
return OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_ASN1, x509) # type: ignore[no-any-return]
|
||||
|
||||
return {
|
||||
- "subject": ((("commonName", x509.get_subject().CN),),), # type: ignore[dict-item]
|
||||
+ "subject": ((("commonName", _get_common_name(x509)),),), # type: ignore[dict-item]
|
||||
"subjectAltName": get_subj_alt_name(x509),
|
||||
}
|
||||
|
||||
@@ -482,16 +493,28 @@
|
||||
self,
|
||||
certfile: str,
|
||||
keyfile: str | None = None,
|
||||
- password: str | None = None,
|
||||
+ password: str | bytes | None = None,
|
||||
) -> None:
|
||||
try:
|
||||
self._ctx.use_certificate_chain_file(certfile)
|
||||
if password is not None:
|
||||
if not isinstance(password, bytes):
|
||||
- password = password.encode("utf-8") # type: ignore[assignment]
|
||||
- self._ctx.set_passwd_cb(lambda *_: password)
|
||||
- self._ctx.use_privatekey_file(keyfile or certfile)
|
||||
- except OpenSSL.SSL.Error as e:
|
||||
+ password = password.encode("utf-8")
|
||||
+ # pyOpenSSL added cryptography-key support in 24.3.0.
|
||||
+ # Keep using the older password-callback path until 2026's
|
||||
+ # versions because set_passwd_cb() became deprecated in 26.3.0.
|
||||
+ if int(OpenSSL.__version__.split(".")[0]) >= 26:
|
||||
+ with open(keyfile or certfile, "rb") as key_file:
|
||||
+ private_key = load_pem_private_key(key_file.read(), password)
|
||||
+ # cryptography's loader returns a wider private-key union
|
||||
+ # than pyOpenSSL accepts, so we add `type: ignore` here.
|
||||
+ self._ctx.use_privatekey(private_key) # type: ignore[arg-type]
|
||||
+ else:
|
||||
+ self._ctx.set_passwd_cb(lambda *_: password)
|
||||
+ self._ctx.use_privatekey_file(keyfile or certfile)
|
||||
+ else:
|
||||
+ self._ctx.use_privatekey_file(keyfile or certfile)
|
||||
+ except (OpenSSL.SSL.Error, TypeError, ValueError) as e:
|
||||
raise ssl.SSLError(f"Unable to load certificate chain: {e!r}") from e
|
||||
|
||||
def set_alpn_protocols(self, protocols: list[bytes | str]) -> None:
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
From c420e267acb739917bee96e021ad9a2d27de8aae Mon Sep 17 00:00:00 2001
|
||||
From: Colin Watson <cjwatson@debian.org>
|
||||
Date: Tue, 30 Jun 2026 21:48:57 +0100
|
||||
Subject: [PATCH] Fix test failures with pytest >= 9.1 (#5094)
|
||||
|
||||
Co-authored-by: Illia Volochii <illia.volochii@gmail.com>
|
||||
---
|
||||
changelog/5094.misc.rst | 1 +
|
||||
test/test_util.py | 3 +--
|
||||
uv.lock | 6 +++---
|
||||
3 files changed, 5 insertions(+), 5 deletions(-)
|
||||
create mode 100644 changelog/5094.misc.rst
|
||||
|
||||
diff --git a/changelog/5094.misc.rst b/changelog/5094.misc.rst
|
||||
new file mode 100644
|
||||
index 0000000000..e6f2a24f2f
|
||||
--- /dev/null
|
||||
+++ b/changelog/5094.misc.rst
|
||||
@@ -0,0 +1 @@
|
||||
+Fixed test failures with pytest >= 9.1.
|
||||
diff --git a/test/test_util.py b/test/test_util.py
|
||||
index fb8f81eb7e..8612ab5eaf 100644
|
||||
--- a/test/test_util.py
|
||||
+++ b/test/test_util.py
|
||||
@@ -7,7 +7,6 @@
|
||||
import sys
|
||||
import typing
|
||||
import warnings
|
||||
-from itertools import chain
|
||||
from test import ImportBlocker, ModuleStash, notBrotli, notZstd, onlyBrotli, onlyZstd
|
||||
from unittest import mock
|
||||
from unittest.mock import MagicMock, Mock, patch
|
||||
@@ -438,7 +437,7 @@ def test_percent_encoded_control_ipv6_zone_ids_raise(self, url: str) -> None:
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"url, expected_url",
|
||||
- chain(parse_url_host_map, non_round_tripping_parse_url_host_map),
|
||||
+ [*parse_url_host_map, *non_round_tripping_parse_url_host_map],
|
||||
)
|
||||
def test_parse_url(self, url: str, expected_url: Url) -> None:
|
||||
returned_url = parse_url(url)
|
||||
diff --git a/uv.lock b/uv.lock
|
||||
index 03ec5fb75a..82d0c070eb 100644
|
||||
--- a/uv.lock
|
||||
+++ b/uv.lock
|
||||
@@ -1707,7 +1707,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
-version = "9.0.3"
|
||||
+version = "9.1.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32' or (extra == 'group-7-urllib3-dev' and extra == 'group-7-urllib3-dev-min-pyopenssl') or (extra == 'group-7-urllib3-dev-min-pyopenssl' and extra == 'group-7-urllib3-mypy')" },
|
||||
@@ -1718,9 +1718,9 @@ dependencies = [
|
||||
{ name = "pygments" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11' or (extra == 'group-7-urllib3-dev' and extra == 'group-7-urllib3-dev-min-pyopenssl') or (extra == 'group-7-urllib3-dev-min-pyopenssl' and extra == 'group-7-urllib3-mypy')" },
|
||||
]
|
||||
-sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" }
|
||||
+sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" }
|
||||
wheels = [
|
||||
- { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" },
|
||||
+ { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -31,15 +31,6 @@ Source0: %{url}/archive/%{version}/urllib3-%{version}.tar.gz
|
|||
%global hypercorn_commit d1719f8c1570cbd8e6a3719ffdb14a4d72880abb
|
||||
Source1: %{hypercorn_url}/archive/%{hypercorn_commit}/hypercorn-%{hypercorn_commit}.tar.gz
|
||||
|
||||
# Deal with ssl.PROTOCOL_TLSv1 removal from Python built with OpenSSL 4+
|
||||
Patch: https://github.com/urllib3/urllib3/pull/5097.patch
|
||||
# Replace deprecated pyOpenSSL X509.get_subject and Context.set_passwd_cb methods
|
||||
# https://github.com/urllib3/urllib3/pull/5103 rebased
|
||||
Patch: 5103.patch
|
||||
|
||||
# Compatibility with the latest pytest
|
||||
Patch: https://github.com/urllib3/urllib3/commit/c420e267.patch
|
||||
|
||||
BuildArch: noarch
|
||||
|
||||
BuildRequires: python3-devel
|
||||
|
|
@ -91,7 +82,7 @@ Recommends: python3-urllib3+socks
|
|||
|
||||
|
||||
%prep
|
||||
%autosetup -p1 -n urllib3-%{version}
|
||||
%autosetup -n urllib3-%{version}
|
||||
%setup -q -n urllib3-%{version} -T -D -b 1
|
||||
|
||||
# Allow setuptools-scm 10+
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue