From 9f1090cdcc8d2da8bda7b01cdc4c63bd3ca3b800 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Tue, 3 Mar 2026 15:35:41 -0800 Subject: [PATCH 1/6] fix: remove deprecated rsa dependency --- packages/google-auth/google/auth/crypt/rsa.py | 7 ++++++- packages/google-auth/setup.py | 8 +++++--- packages/google-auth/testing/constraints-3.8.txt | 1 - packages/google-auth/tests/crypt/test_rsa.py | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/google-auth/google/auth/crypt/rsa.py b/packages/google-auth/google/auth/crypt/rsa.py index 4b2fb39ffbda..639be9069549 100644 --- a/packages/google-auth/google/auth/crypt/rsa.py +++ b/packages/google-auth/google/auth/crypt/rsa.py @@ -24,7 +24,6 @@ from google.auth import _helpers from google.auth.crypt import _cryptography_rsa -from google.auth.crypt import _python_rsa from google.auth.crypt import base RSA_KEY_MODULE_PREFIX = "rsa.key" @@ -37,6 +36,7 @@ class RSAVerifier(base.Verifier): public_key (Union["rsa.key.PublicKey", cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey]): The public key used to verify signatures. Raises: + ImportError: if called with an rsa.key.PublicKey, when the rsa library is not installed ValueError: if an unrecognized public key is provided """ @@ -45,6 +45,8 @@ def __init__(self, public_key): if isinstance(public_key, RSAPublicKey): impl_lib = _cryptography_rsa elif module_str.startswith(RSA_KEY_MODULE_PREFIX): + from google.auth.crypt import _python_rsa + impl_lib = _python_rsa else: raise ValueError(f"unrecognized public key type: {type(public_key)}") @@ -85,6 +87,7 @@ class RSASigner(base.Signer, base.FromServiceAccountMixin): public key or certificate. Raises: + ImportError: if called with an rsa.key.PrivateKey, when the rsa library is not installed ValueError: if an unrecognized public key is provided """ @@ -93,6 +96,8 @@ def __init__(self, private_key, key_id=None): if isinstance(private_key, RSAPrivateKey): impl_lib = _cryptography_rsa elif module_str.startswith(RSA_KEY_MODULE_PREFIX): + from google.auth.crypt import _python_rsa + impl_lib = _python_rsa else: raise ValueError(f"unrecognized private key type: {type(private_key)}") diff --git a/packages/google-auth/setup.py b/packages/google-auth/setup.py index ba9e214b1cd3..99abe1db75a6 100644 --- a/packages/google-auth/setup.py +++ b/packages/google-auth/setup.py @@ -25,9 +25,6 @@ DEPENDENCIES = ( "pyasn1-modules>=0.2.1", cryptography_base_require, - # TODO: remove rsa from dependencies in next release (replaced with cryptography)i - # https://github.com/googleapis/google-auth-library-python/issues/1810 - "rsa>=3.1.4,<5", ) requests_extra_require = ["requests >= 2.20.0, < 3.0.0"] @@ -46,6 +43,8 @@ # TODO(https://github.com/googleapis/google-auth-library-python/issues/1739): Add bounds for urllib3 and packaging dependencies. urllib3_extra_require = ["urllib3", "packaging"] +rsa_extra_require = ["rsa>=3.1.4,<5"] + # Unit test requirements. testing_extra_require = [ # TODO(https://github.com/googleapis/google-auth-library-python/issues/1735): Remove `grpcio` from testing requirements once an extra is added for `grpcio` dependency. @@ -73,6 +72,8 @@ # TODO(https://github.com/googleapis/google-auth-library-python/issues/1722): `test_aiohttp_requests` depend on # aiohttp < 3.10.0 which is a bug. Investigate and remove the pinned aiohttp version. "aiohttp < 3.10.0", + # rsa library was removed as a dependency, but we still have some code paths that support it + rsa_extra_require, ] extras = { @@ -86,6 +87,7 @@ "requests": requests_extra_require, "testing": testing_extra_require, "urllib3": urllib3_extra_require, + "rsa": rsa_extra_require, # TODO(https://github.com/googleapis/google-auth-library-python/issues/1735): Add an extra for `grpcio` dependency. # TODO(https://github.com/googleapis/google-auth-library-python/issues/1736): Add an extra for `oauth2client` dependency. } diff --git a/packages/google-auth/testing/constraints-3.8.txt b/packages/google-auth/testing/constraints-3.8.txt index 5eba7b60e183..3ca0e8edb179 100644 --- a/packages/google-auth/testing/constraints-3.8.txt +++ b/packages/google-auth/testing/constraints-3.8.txt @@ -7,7 +7,6 @@ # Then this file should have foo==1.14.0 pyasn1-modules==0.2.1 setuptools==40.3.0 -rsa==3.1.4 cryptography==38.0.3 aiohttp==3.6.2 requests==2.20.0 diff --git a/packages/google-auth/tests/crypt/test_rsa.py b/packages/google-auth/tests/crypt/test_rsa.py index 6f7aa2691330..6ed822ad9ebc 100644 --- a/packages/google-auth/tests/crypt/test_rsa.py +++ b/packages/google-auth/tests/crypt/test_rsa.py @@ -18,7 +18,7 @@ from cryptography.hazmat import backends from cryptography.hazmat.primitives import serialization import pytest -import rsa as rsa_lib +import rsa as rsa_lib # type: ignore from google.auth.crypt import _cryptography_rsa from google.auth.crypt import _python_rsa From 2aaf3c30305827907f2121a59df2be26f3c0b8c8 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Tue, 3 Mar 2026 15:41:11 -0800 Subject: [PATCH 2/6] Apply suggestion from @gemini-code-assist[bot] Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- packages/google-auth/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/google-auth/setup.py b/packages/google-auth/setup.py index 99abe1db75a6..0f09c2101394 100644 --- a/packages/google-auth/setup.py +++ b/packages/google-auth/setup.py @@ -73,7 +73,7 @@ # aiohttp < 3.10.0 which is a bug. Investigate and remove the pinned aiohttp version. "aiohttp < 3.10.0", # rsa library was removed as a dependency, but we still have some code paths that support it - rsa_extra_require, + *rsa_extra_require, ] extras = { From 8835c8303eef3853553650e7547d4dac70eb5d80 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Wed, 4 Mar 2026 17:17:23 -0800 Subject: [PATCH 3/6] run tests both with and without rsa --- packages/google-auth/noxfile.py | 11 +++++++++-- packages/google-auth/setup.py | 4 ---- .../tests/crypt/test__python_rsa.py | 3 ++- packages/google-auth/tests/crypt/test_rsa.py | 18 ++++++++++++++---- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/packages/google-auth/noxfile.py b/packages/google-auth/noxfile.py index 1a649812135e..78952b7b44bb 100644 --- a/packages/google-auth/noxfile.py +++ b/packages/google-auth/noxfile.py @@ -115,7 +115,8 @@ def mypy(session): @nox.session(python=ALL_PYTHON) -def unit(session): +@nox.parametrize(["install_deprecated_extras"], (True, False)) +def unit(session, install_deprecated_extras): # Install all test dependencies, then install this package in-place. if session.python in ("3.7",): @@ -124,7 +125,13 @@ def unit(session): constraints_path = str( CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" ) - session.install("-e", ".[testing]", "-c", constraints_path) + extras_str = "testing" + if install_deprecated_extras: + # rsa and oauth2client were both archived and support dropped, + # but we still test old code paths + session.install("oauth2client") + extras_str += ",rsa" + session.install("-e", f".[{extras_str}]", "-c", constraints_path) session.run( "pytest", f"--junitxml=unit_{session.python}_sponge_log.xml", diff --git a/packages/google-auth/setup.py b/packages/google-auth/setup.py index 0f09c2101394..8a66b7c39d0e 100644 --- a/packages/google-auth/setup.py +++ b/packages/google-auth/setup.py @@ -51,8 +51,6 @@ "grpcio", "flask", "freezegun", - # TODO(https://github.com/googleapis/google-auth-library-python/issues/1736): Remove `oauth2client` from testing requirements once an extra is added for `oauth2client` dependency. - "oauth2client", *pyjwt_extra_require, "pytest", "pytest-cov", @@ -72,8 +70,6 @@ # TODO(https://github.com/googleapis/google-auth-library-python/issues/1722): `test_aiohttp_requests` depend on # aiohttp < 3.10.0 which is a bug. Investigate and remove the pinned aiohttp version. "aiohttp < 3.10.0", - # rsa library was removed as a dependency, but we still have some code paths that support it - *rsa_extra_require, ] extras = { diff --git a/packages/google-auth/tests/crypt/test__python_rsa.py b/packages/google-auth/tests/crypt/test__python_rsa.py index 43539900f7fc..76b30bf2f8be 100644 --- a/packages/google-auth/tests/crypt/test__python_rsa.py +++ b/packages/google-auth/tests/crypt/test__python_rsa.py @@ -19,7 +19,8 @@ from pyasn1_modules import pem # type: ignore import pytest # type: ignore -import rsa # type: ignore + +rsa = pytest.importorskip("rsa") from google.auth import _helpers from google.auth.crypt import _python_rsa diff --git a/packages/google-auth/tests/crypt/test_rsa.py b/packages/google-auth/tests/crypt/test_rsa.py index 6ed822ad9ebc..4f722a6380b0 100644 --- a/packages/google-auth/tests/crypt/test_rsa.py +++ b/packages/google-auth/tests/crypt/test_rsa.py @@ -18,10 +18,15 @@ from cryptography.hazmat import backends from cryptography.hazmat.primitives import serialization import pytest -import rsa as rsa_lib # type: ignore + +try: + import rsa as rsa_lib + from google.auth.crypt import _python_rsa +except ImportError: + rsa_lib = None + _pyrhon_rsa = None from google.auth.crypt import _cryptography_rsa -from google.auth.crypt import _python_rsa from google.auth.crypt import rsa @@ -70,11 +75,13 @@ def test_init_with_cryptography_key(self, cryptography_public_key): assert isinstance(verifier._impl, _cryptography_rsa.RSAVerifier) assert verifier._impl._pubkey == cryptography_public_key + @pytest.mark.skipif(not rsa_lib, reason="rsa library not installed") def test_init_with_rsa_key(self, rsa_public_key): verifier = rsa.RSAVerifier(rsa_public_key) assert isinstance(verifier._impl, _python_rsa.RSAVerifier) assert verifier._impl._pubkey == rsa_public_key + @pytest.mark.skipif(not rsa_lib, reason="rsa library not installed") def test_warning_with_rsa(self, rsa_public_key): with pytest.warns(DeprecationWarning, match="The 'rsa' library is deprecated"): rsa.RSAVerifier(rsa_public_key) @@ -114,12 +121,14 @@ def test_init_with_cryptography_key(self, cryptography_private_key): assert signer._impl._key == cryptography_private_key assert signer._impl.key_id == "123" + @pytest.mark.skipif(not rsa_lib, reason="rsa library not installed") def test_init_with_rsa_key(self, rsa_private_key): signer = rsa.RSASigner(rsa_private_key, key_id="123") assert isinstance(signer._impl, _python_rsa.RSASigner) assert signer._impl._key == rsa_private_key assert signer._impl.key_id == "123" + @pytest.mark.skipif(not rsa_lib, reason="rsa library not installed") def test_warning_with_rsa(self, rsa_private_key): with pytest.warns(DeprecationWarning, match="The 'rsa' library is deprecated"): rsa.RSASigner(rsa_private_key, key_id="123") @@ -130,8 +139,8 @@ def test_init_with_unknown_key(self): with pytest.raises(ValueError): rsa.RSASigner(unknown_key) - def test_sign_delegates(self, rsa_private_key): - signer = rsa.RSASigner(rsa_private_key) + def test_sign_delegates(self, cryptography_private_key): + signer = rsa.RSASigner(cryptography_private_key) with mock.patch.object( signer._impl, "sign", return_value=b"signature" @@ -164,6 +173,7 @@ def test_end_to_end_cryptography_lib(self, private_key_bytes, public_key_bytes): assert isinstance(verifier._impl, _cryptography_rsa.RSAVerifier) assert isinstance(signer._impl, _cryptography_rsa.RSASigner) + @pytest.mark.skipif(not rsa_lib, reason="rsa library not installed") def test_end_to_end_rsa_lib(self, rsa_private_key, rsa_public_key): signer = rsa.RSASigner(rsa_private_key) message = b"Hello World" From e3e5b12633c127f40c1ae887dd82df16e2a77c05 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Wed, 4 Mar 2026 17:17:56 -0800 Subject: [PATCH 4/6] only duplicate tests on boundary versions --- packages/google-auth/noxfile.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/google-auth/noxfile.py b/packages/google-auth/noxfile.py index 78952b7b44bb..5e367ad9633e 100644 --- a/packages/google-auth/noxfile.py +++ b/packages/google-auth/noxfile.py @@ -41,7 +41,7 @@ "3.13", "3.14", ] -ALL_PYTHON = UNIT_TEST_PYTHON_VERSIONS +ALL_PYTHON = UNIT_TEST_PYTHON_VERSIONS.copy() ALL_PYTHON.extend(["3.7"]) # Error if a python version is missing @@ -121,6 +121,10 @@ def unit(session, install_deprecated_extras): if session.python in ("3.7",): session.skip("Python 3.7 is no longer supported") + min_py, max_py = UNIT_TEST_PYTHON_VERSIONS[0], UNIT_TEST_PYTHON_VERSIONS[-1] + if not install_deprecated_extras and session.python not in (min_py, max_py): + # only run double tests on first and last supported versions + session.skip(f"Extended tests only run on boundary Python versions ({min_py}, {max_py}) to reduce CI load.") constraints_path = str( CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" From 35e20fcddeb943288f5e9b45e2c60dfdd51f5020 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Wed, 4 Mar 2026 17:25:39 -0800 Subject: [PATCH 5/6] fixed lint --- packages/google-auth/noxfile.py | 4 +++- packages/google-auth/tests/crypt/test__python_rsa.py | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/google-auth/noxfile.py b/packages/google-auth/noxfile.py index 5e367ad9633e..e9fc880f7476 100644 --- a/packages/google-auth/noxfile.py +++ b/packages/google-auth/noxfile.py @@ -124,7 +124,9 @@ def unit(session, install_deprecated_extras): min_py, max_py = UNIT_TEST_PYTHON_VERSIONS[0], UNIT_TEST_PYTHON_VERSIONS[-1] if not install_deprecated_extras and session.python not in (min_py, max_py): # only run double tests on first and last supported versions - session.skip(f"Extended tests only run on boundary Python versions ({min_py}, {max_py}) to reduce CI load.") + session.skip( + f"Extended tests only run on boundary Python versions ({min_py}, {max_py}) to reduce CI load." + ) constraints_path = str( CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" diff --git a/packages/google-auth/tests/crypt/test__python_rsa.py b/packages/google-auth/tests/crypt/test__python_rsa.py index 76b30bf2f8be..08c2eaa7b458 100644 --- a/packages/google-auth/tests/crypt/test__python_rsa.py +++ b/packages/google-auth/tests/crypt/test__python_rsa.py @@ -20,12 +20,12 @@ from pyasn1_modules import pem # type: ignore import pytest # type: ignore -rsa = pytest.importorskip("rsa") - from google.auth import _helpers from google.auth.crypt import _python_rsa from google.auth.crypt import base +rsa = pytest.importorskip("rsa") + DATA_DIR = os.path.join(os.path.dirname(__file__), "..", "data") From c739f2a0bb1108bb9ddde0f51bee7c5ea353ea30 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Wed, 4 Mar 2026 17:29:06 -0800 Subject: [PATCH 6/6] added type ignore --- packages/google-auth/tests/crypt/test__python_rsa.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/google-auth/tests/crypt/test__python_rsa.py b/packages/google-auth/tests/crypt/test__python_rsa.py index 08c2eaa7b458..058c3a1abb6c 100644 --- a/packages/google-auth/tests/crypt/test__python_rsa.py +++ b/packages/google-auth/tests/crypt/test__python_rsa.py @@ -24,7 +24,7 @@ from google.auth.crypt import _python_rsa from google.auth.crypt import base -rsa = pytest.importorskip("rsa") +rsa = pytest.importorskip("rsa") # type: ignore DATA_DIR = os.path.join(os.path.dirname(__file__), "..", "data")