Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-google-auth for openSUSE:Factory checked in at 2024-01-05 22:59:55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-google-auth (Old) and /work/SRC/openSUSE:Factory/.python-google-auth.new.28375 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-google-auth" Fri Jan 5 22:59:55 2024 rev:38 rq:1136770 version:2.26.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-google-auth/python-google-auth.changes 2023-12-17 21:29:09.342678654 +0100 +++ /work/SRC/openSUSE:Factory/.python-google-auth.new.28375/python-google-auth.changes 2024-01-05 22:59:57.703094970 +0100 @@ -1,0 +2,13 @@ +Thu Jan 4 09:50:33 UTC 2024 - John Paul Adrian Glaubitz <[email protected]> + +- Update to 2.26.1 + * Ensure that refresh worker is pickle-able. (#1447) +- from version 2.26.0 + * Add optional non blocking refresh for sync auth code (a6dc2c3) + * Add optional non blocking refresh for sync auth code (#1368) + * External account user cred universe domain support (#1437) + * Guard delete statements. Add default fallback for _use_non_blocking_refresh. (#1445) +- Refresh patches for new version + * python-google-auth-no-mock.patch + +------------------------------------------------------------------- Old: ---- google-auth-2.25.2.tar.gz New: ---- google-auth-2.26.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-google-auth.spec ++++++ --- /var/tmp/diff_new_pack.zSGf5j/_old 2024-01-05 22:59:58.631128973 +0100 +++ /var/tmp/diff_new_pack.zSGf5j/_new 2024-01-05 22:59:58.631128973 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-google-auth # -# Copyright (c) 2023 SUSE LLC +# Copyright (c) 2024 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ %{?sle15_python_module_pythons} Name: python-google-auth -Version: 2.25.2 +Version: 2.26.1 Release: 0 Summary: Google Authentication Library License: Apache-2.0 ++++++ google-auth-2.25.2.tar.gz -> google-auth-2.26.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.25.2/PKG-INFO new/google-auth-2.26.1/PKG-INFO --- old/google-auth-2.25.2/PKG-INFO 2023-12-08 20:37:44.102259600 +0100 +++ new/google-auth-2.26.1/PKG-INFO 2024-01-03 23:52:08.752571800 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: google-auth -Version: 2.25.2 +Version: 2.26.1 Summary: Google Authentication Library Home-page: https://github.com/googleapis/google-auth-library-python Author: Google Cloud Platform diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.25.2/google/auth/_refresh_worker.py new/google-auth-2.26.1/google/auth/_refresh_worker.py --- old/google-auth-2.25.2/google/auth/_refresh_worker.py 1970-01-01 01:00:00.000000000 +0100 +++ new/google-auth-2.26.1/google/auth/_refresh_worker.py 2024-01-03 23:49:22.000000000 +0100 @@ -0,0 +1,109 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import copy +import logging +import threading + +import google.auth.exceptions as e + +_LOGGER = logging.getLogger(__name__) + + +class RefreshThreadManager: + """ + Organizes exactly one background job that refresh a token. + """ + + def __init__(self): + """Initializes the manager.""" + + self._worker = None + self._lock = threading.Lock() # protects access to worker threads. + + def start_refresh(self, cred, request): + """Starts a refresh thread for the given credentials. + The credentials are refreshed using the request parameter. + request and cred MUST not be None + + Returns True if a background refresh was kicked off. False otherwise. + + Args: + cred: A credentials object. + request: A request object. + Returns: + bool + """ + if cred is None or request is None: + raise e.InvalidValue( + "Unable to start refresh. cred and request must be valid and instantiated objects." + ) + + with self._lock: + if self._worker is not None and self._worker._error_info is not None: + return False + + if self._worker is None or not self._worker.is_alive(): # pragma: NO COVER + self._worker = RefreshThread(cred=cred, request=copy.deepcopy(request)) + self._worker.start() + return True + + def clear_error(self): + """ + Removes any errors that were stored from previous background refreshes. + """ + with self._lock: + if self._worker: + self._worker._error_info = None + + def __getstate__(self): + """Pickle helper that serializes the _lock attribute.""" + state = self.__dict__.copy() + state["_lock"] = None + return state + + def __setstate__(self, state): + """Pickle helper that deserializes the _lock attribute.""" + state["_key"] = threading.Lock() + self.__dict__.update(state) + + +class RefreshThread(threading.Thread): + """ + Thread that refreshes credentials. + """ + + def __init__(self, cred, request, **kwargs): + """Initializes the thread. + + Args: + cred: A Credential object to refresh. + request: A Request object used to perform a credential refresh. + **kwargs: Additional keyword arguments. + """ + + super().__init__(**kwargs) + self._cred = cred + self._request = request + self._error_info = None + + def run(self): + """ + Perform the credential refresh. + """ + try: + self._cred.refresh(self._request) + except Exception as err: # pragma: NO COVER + _LOGGER.error(f"Background refresh failed due to: {err}") + self._error_info = err diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.25.2/google/auth/credentials.py new/google-auth-2.26.1/google/auth/credentials.py --- old/google-auth-2.25.2/google/auth/credentials.py 2023-12-08 20:34:40.000000000 +0100 +++ new/google-auth-2.26.1/google/auth/credentials.py 2024-01-03 23:49:22.000000000 +0100 @@ -16,11 +16,13 @@ """Interfaces for credentials.""" import abc +from enum import Enum import os from google.auth import _helpers, environment_vars from google.auth import exceptions from google.auth import metrics +from google.auth._refresh_worker import RefreshThreadManager class Credentials(metaclass=abc.ABCMeta): @@ -59,6 +61,9 @@ """Optional[str]: The universe domain value, default is googleapis.com """ + self._use_non_blocking_refresh = False + self._refresh_worker = RefreshThreadManager() + @property def expired(self): """Checks if the credentials are expired. @@ -66,10 +71,12 @@ Note that credentials can be invalid but not expired because Credentials with :attr:`expiry` set to None is considered to never expire. + + .. deprecated:: v2.24.0 + Prefer checking :attr:`token_state` instead. """ if not self.expiry: return False - # Remove some threshold from expiry to err on the side of reporting # expiration early so that we avoid the 401-refresh-retry loop. skewed_expiry = self.expiry - _helpers.REFRESH_THRESHOLD @@ -81,10 +88,35 @@ This is True if the credentials have a :attr:`token` and the token is not :attr:`expired`. + + .. deprecated:: v2.24.0 + Prefer checking :attr:`token_state` instead. """ return self.token is not None and not self.expired @property + def token_state(self): + """ + See `:obj:`TokenState` + """ + if self.token is None: + return TokenState.INVALID + + # Credentials that can't expire are always treated as fresh. + if self.expiry is None: + return TokenState.FRESH + + expired = _helpers.utcnow() >= self.expiry + if expired: + return TokenState.INVALID + + is_stale = _helpers.utcnow() >= (self.expiry - _helpers.REFRESH_THRESHOLD) + if is_stale: + return TokenState.STALE + + return TokenState.FRESH + + @property def quota_project_id(self): """Project to use for quota and billing purposes.""" return self._quota_project_id @@ -154,6 +186,25 @@ if self.quota_project_id: headers["x-goog-user-project"] = self.quota_project_id + def _blocking_refresh(self, request): + if not self.valid: + self.refresh(request) + + def _non_blocking_refresh(self, request): + use_blocking_refresh_fallback = False + + if self.token_state == TokenState.STALE: + use_blocking_refresh_fallback = not self._refresh_worker.start_refresh( + self, request + ) + + if self.token_state == TokenState.INVALID or use_blocking_refresh_fallback: + self.refresh(request) + # If the blocking refresh succeeds then we can clear the error info + # on the background refresh worker, and perform refreshes in a + # background thread. + self._refresh_worker.clear_error() + def before_request(self, request, method, url, headers): """Performs credential-specific before request logic. @@ -171,11 +222,17 @@ # pylint: disable=unused-argument # (Subclasses may use these arguments to ascertain information about # the http request.) - if not self.valid: - self.refresh(request) + if self._use_non_blocking_refresh: + self._non_blocking_refresh(request) + else: + self._blocking_refresh(request) + metrics.add_metric_header(headers, self._metric_header_for_usage()) self.apply(headers) + def with_non_blocking_refresh(self): + self._use_non_blocking_refresh = True + class CredentialsWithQuotaProject(Credentials): """Abstract base for credentials supporting ``with_quota_project`` factory""" @@ -188,7 +245,7 @@ billing purposes Returns: - google.oauth2.credentials.Credentials: A new credentials instance. + google.auth.credentials.Credentials: A new credentials instance. """ raise NotImplementedError("This credential does not support quota project.") @@ -209,11 +266,28 @@ token_uri (str): The uri to use for fetching/exchanging tokens Returns: - google.oauth2.credentials.Credentials: A new credentials instance. + google.auth.credentials.Credentials: A new credentials instance. """ raise NotImplementedError("This credential does not use token uri.") +class CredentialsWithUniverseDomain(Credentials): + """Abstract base for credentials supporting ``with_universe_domain`` factory""" + + def with_universe_domain(self, universe_domain): + """Returns a copy of these credentials with a modified universe domain. + + Args: + universe_domain (str): The universe domain to use + + Returns: + google.auth.credentials.Credentials: A new credentials instance. + """ + raise NotImplementedError( + "This credential does not support with_universe_domain." + ) + + class AnonymousCredentials(Credentials): """Credentials that do not provide any authentication information. @@ -422,3 +496,16 @@ # pylint: disable=missing-raises-doc # (pylint doesn't recognize that this is abstract) raise NotImplementedError("Signer must be implemented.") + + +class TokenState(Enum): + """ + Tracks the state of a token. + FRESH: The token is valid. It is not expired or close to expired, or the token has no expiry. + STALE: The token is close to expired, and should be refreshed. The token can be used normally. + INVALID: The token is expired or invalid. The token cannot be used for a normal operation. + """ + + FRESH = 1 + STALE = 2 + INVALID = 3 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.25.2/google/auth/external_account.py new/google-auth-2.26.1/google/auth/external_account.py --- old/google-auth-2.25.2/google/auth/external_account.py 2023-12-08 20:34:40.000000000 +0100 +++ new/google-auth-2.26.1/google/auth/external_account.py 2024-01-03 23:49:22.000000000 +0100 @@ -415,16 +415,8 @@ new_cred._metrics_options = self._metrics_options return new_cred + @_helpers.copy_docstring(credentials.CredentialsWithUniverseDomain) def with_universe_domain(self, universe_domain): - """Create a copy of these credentials with the given universe domain. - - Args: - universe_domain (str): The universe domain value. - - Returns: - google.auth.external_account.Credentials: A new credentials - instance. - """ kwargs = self._constructor_args() kwargs.update(universe_domain=universe_domain) new_cred = self.__class__(**kwargs) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.25.2/google/auth/external_account_authorized_user.py new/google-auth-2.26.1/google/auth/external_account_authorized_user.py --- old/google-auth-2.25.2/google/auth/external_account_authorized_user.py 2023-12-08 20:34:40.000000000 +0100 +++ new/google-auth-2.26.1/google/auth/external_account_authorized_user.py 2024-01-03 23:49:22.000000000 +0100 @@ -43,6 +43,7 @@ from google.oauth2 import sts from google.oauth2 import utils +_DEFAULT_UNIVERSE_DOMAIN = "googleapis.com" _EXTERNAL_ACCOUNT_AUTHORIZED_USER_JSON_TYPE = "external_account_authorized_user" @@ -75,6 +76,7 @@ revoke_url=None, scopes=None, quota_project_id=None, + universe_domain=_DEFAULT_UNIVERSE_DOMAIN, ): """Instantiates a external account authorized user credentials object. @@ -98,6 +100,8 @@ quota_project_id (str): The optional project ID used for quota and billing. This project may be different from the project used to create the credentials. + universe_domain (Optional[str]): The universe domain. The default value + is googleapis.com. Returns: google.auth.external_account_authorized_user.Credentials: The @@ -116,6 +120,7 @@ self._revoke_url = revoke_url self._quota_project_id = quota_project_id self._scopes = scopes + self._universe_domain = universe_domain or _DEFAULT_UNIVERSE_DOMAIN if not self.valid and not self.can_refresh: raise exceptions.InvalidOperation( @@ -162,6 +167,7 @@ "revoke_url": self._revoke_url, "scopes": self._scopes, "quota_project_id": self._quota_project_id, + "universe_domain": self._universe_domain, } @property @@ -297,6 +303,12 @@ kwargs.update(token_url=token_uri) return self.__class__(**kwargs) + @_helpers.copy_docstring(credentials.CredentialsWithUniverseDomain) + def with_universe_domain(self, universe_domain): + kwargs = self.constructor_args() + kwargs.update(universe_domain=universe_domain) + return self.__class__(**kwargs) + @classmethod def from_info(cls, info, **kwargs): """Creates a Credentials instance from parsed external account info. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.25.2/google/auth/impersonated_credentials.py new/google-auth-2.26.1/google/auth/impersonated_credentials.py --- old/google-auth-2.25.2/google/auth/impersonated_credentials.py 2023-12-08 20:34:40.000000000 +0100 +++ new/google-auth-2.26.1/google/auth/impersonated_credentials.py 2024-01-03 23:49:22.000000000 +0100 @@ -259,7 +259,10 @@ """ # Refresh our source credentials if it is not valid. - if not self._source_credentials.valid: + if ( + self._source_credentials.token_state == credentials.TokenState.STALE + or self._source_credentials.token_state == credentials.TokenState.INVALID + ): self._source_credentials.refresh(request) body = { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.25.2/google/auth/version.py new/google-auth-2.26.1/google/auth/version.py --- old/google-auth-2.25.2/google/auth/version.py 2023-12-08 20:34:40.000000000 +0100 +++ new/google-auth-2.26.1/google/auth/version.py 2024-01-03 23:49:22.000000000 +0100 @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "2.25.2" +__version__ = "2.26.1" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.25.2/google/oauth2/credentials.py new/google-auth-2.26.1/google/oauth2/credentials.py --- old/google-auth-2.25.2/google/oauth2/credentials.py 2023-12-08 20:34:40.000000000 +0100 +++ new/google-auth-2.26.1/google/oauth2/credentials.py 2024-01-03 23:49:22.000000000 +0100 @@ -160,7 +160,11 @@ # unpickling certain callables (lambda, functools.partial instances) # because they need to be importable. # Instead, the refresh_handler setter should be used to repopulate this. - del state_dict["_refresh_handler"] + if "_refresh_handler" in state_dict: + del state_dict["_refresh_handler"] + + if "_refresh_worker" in state_dict: + del state_dict["_refresh_worker"] return state_dict def __setstate__(self, d): @@ -183,6 +187,8 @@ self._universe_domain = d.get("_universe_domain") or _DEFAULT_UNIVERSE_DOMAIN # The refresh_handler setter should be used to repopulate this. self._refresh_handler = None + self._refresh_worker = None + self._use_non_blocking_refresh = d.get("_use_non_blocking_refresh", False) @property def refresh_token(self): @@ -302,15 +308,8 @@ universe_domain=self._universe_domain, ) + @_helpers.copy_docstring(credentials.CredentialsWithUniverseDomain) def with_universe_domain(self, universe_domain): - """Create a copy of the credential with the given universe domain. - - Args: - universe_domain (str): The universe domain value. - - Returns: - google.oauth2.credentials.Credentials: A new credentials instance. - """ return self.__class__( self.token, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.25.2/google/oauth2/service_account.py new/google-auth-2.26.1/google/oauth2/service_account.py --- old/google-auth-2.25.2/google/oauth2/service_account.py 2023-12-08 20:34:40.000000000 +0100 +++ new/google-auth-2.26.1/google/oauth2/service_account.py 2024-01-03 23:49:22.000000000 +0100 @@ -325,16 +325,8 @@ cred._always_use_jwt_access = always_use_jwt_access return cred + @_helpers.copy_docstring(credentials.CredentialsWithUniverseDomain) def with_universe_domain(self, universe_domain): - """Create a copy of these credentials with the given universe domain. - - Args: - universe_domain (str): The universe domain value. - - Returns: - google.auth.service_account.Credentials: A new credentials - instance. - """ cred = self._make_copy() cred._universe_domain = universe_domain if universe_domain != _DEFAULT_UNIVERSE_DOMAIN: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.25.2/google_auth.egg-info/PKG-INFO new/google-auth-2.26.1/google_auth.egg-info/PKG-INFO --- old/google-auth-2.25.2/google_auth.egg-info/PKG-INFO 2023-12-08 20:37:44.000000000 +0100 +++ new/google-auth-2.26.1/google_auth.egg-info/PKG-INFO 2024-01-03 23:52:08.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: google-auth -Version: 2.25.2 +Version: 2.26.1 Summary: Google Authentication Library Home-page: https://github.com/googleapis/google-auth-library-python Author: Google Cloud Platform diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.25.2/google_auth.egg-info/SOURCES.txt new/google-auth-2.26.1/google_auth.egg-info/SOURCES.txt --- old/google-auth-2.25.2/google_auth.egg-info/SOURCES.txt 2023-12-08 20:37:44.000000000 +0100 +++ new/google-auth-2.26.1/google_auth.egg-info/SOURCES.txt 2024-01-03 23:52:08.000000000 +0100 @@ -12,6 +12,7 @@ google/auth/_helpers.py google/auth/_jwt_async.py google/auth/_oauth2client.py +google/auth/_refresh_worker.py google/auth/_service_account_info.py google/auth/api_key.py google/auth/app_engine.py @@ -75,6 +76,7 @@ tests/test__exponential_backoff.py tests/test__helpers.py tests/test__oauth2client.py +tests/test__refresh_worker.py tests/test__service_account_info.py tests/test_api_key.py tests/test_app_engine.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.25.2/tests/oauth2/test_credentials.py new/google-auth-2.26.1/tests/oauth2/test_credentials.py --- old/google-auth-2.25.2/tests/oauth2/test_credentials.py 2023-12-08 20:34:40.000000000 +0100 +++ new/google-auth-2.26.1/tests/oauth2/test_credentials.py 2024-01-03 23:49:22.000000000 +0100 @@ -24,6 +24,7 @@ from google.auth import _helpers from google.auth import exceptions from google.auth import transport +from google.auth.credentials import TokenState from google.oauth2 import credentials @@ -61,6 +62,7 @@ assert not credentials.expired # Scopes aren't required for these credentials assert not credentials.requires_scopes + assert credentials.token_state == TokenState.INVALID # Test properties assert credentials.refresh_token == self.REFRESH_TOKEN assert credentials.token_uri == self.TOKEN_URI @@ -911,7 +913,11 @@ assert list(creds.__dict__).sort() == list(unpickled.__dict__).sort() for attr in list(creds.__dict__): - assert getattr(creds, attr) == getattr(unpickled, attr) + # Worker should always be None + if attr == "_refresh_worker": + assert getattr(unpickled, attr) is None + else: + assert getattr(creds, attr) == getattr(unpickled, attr) def test_pickle_and_unpickle_universe_domain(self): # old version of auth lib doesn't have _universe_domain, so the pickled @@ -945,7 +951,7 @@ for attr in list(creds.__dict__): # For the _refresh_handler property, the unpickled creds should be # set to None. - if attr == "_refresh_handler": + if attr == "_refresh_handler" or attr == "_refresh_worker": assert getattr(unpickled, attr) is None else: assert getattr(creds, attr) == getattr(unpickled, attr) @@ -957,6 +963,8 @@ # this mimics a pickle created with a previous class definition with # fewer attributes del creds.__dict__["_quota_project_id"] + del creds.__dict__["_refresh_handler"] + del creds.__dict__["_refresh_worker"] unpickled = pickle.loads(pickle.dumps(creds)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.25.2/tests/test__refresh_worker.py new/google-auth-2.26.1/tests/test__refresh_worker.py --- old/google-auth-2.25.2/tests/test__refresh_worker.py 1970-01-01 01:00:00.000000000 +0100 +++ new/google-auth-2.26.1/tests/test__refresh_worker.py 2024-01-03 23:49:22.000000000 +0100 @@ -0,0 +1,156 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pickle +import random +import threading +import time + +import mock +import pytest # type: ignore + +from google.auth import _refresh_worker, credentials, exceptions + +MAIN_THREAD_SLEEP_MS = 100 / 1000 + + +class MockCredentialsImpl(credentials.Credentials): + def __init__(self, sleep_seconds=None): + self.refresh_count = 0 + self.token = None + self.sleep_seconds = sleep_seconds if sleep_seconds else None + + def refresh(self, request): + if self.sleep_seconds: + time.sleep(self.sleep_seconds) + self.token = request + self.refresh_count += 1 + + [email protected] +def test_thread_count(): + return 25 + + +def _cred_spinlock(cred): + while cred.token is None: # pragma: NO COVER + time.sleep(MAIN_THREAD_SLEEP_MS) + + +def test_invalid_start_refresh(): + w = _refresh_worker.RefreshThreadManager() + with pytest.raises(exceptions.InvalidValue): + w.start_refresh(None, None) + + +def test_start_refresh(): + w = _refresh_worker.RefreshThreadManager() + cred = MockCredentialsImpl() + request = mock.MagicMock() + assert w.start_refresh(cred, request) + + assert w._worker is not None + + _cred_spinlock(cred) + + assert cred.token == request + assert cred.refresh_count == 1 + + +def test_nonblocking_start_refresh(): + w = _refresh_worker.RefreshThreadManager() + cred = MockCredentialsImpl(sleep_seconds=1) + request = mock.MagicMock() + assert w.start_refresh(cred, request) + + assert w._worker is not None + assert not cred.token + assert cred.refresh_count == 0 + + +def test_multiple_refreshes_multiple_workers(test_thread_count): + w = _refresh_worker.RefreshThreadManager() + cred = MockCredentialsImpl() + request = mock.MagicMock() + + def _thread_refresh(): + time.sleep(random.randrange(0, 5)) + assert w.start_refresh(cred, request) + + threads = [ + threading.Thread(target=_thread_refresh) for _ in range(test_thread_count) + ] + for t in threads: + t.start() + + _cred_spinlock(cred) + + assert cred.token == request + # There is a chance only one thread has enough time to perform a refresh. + # Generally multiple threads will have time to perform a refresh + assert cred.refresh_count > 0 + + +def test_refresh_error(): + w = _refresh_worker.RefreshThreadManager() + cred = mock.MagicMock() + request = mock.MagicMock() + + cred.refresh.side_effect = exceptions.RefreshError("Failed to refresh") + + assert w.start_refresh(cred, request) + + while w._worker._error_info is None: # pragma: NO COVER + time.sleep(MAIN_THREAD_SLEEP_MS) + + assert w._worker is not None + assert isinstance(w._worker._error_info, exceptions.RefreshError) + + +def test_refresh_error_call_refresh_again(): + w = _refresh_worker.RefreshThreadManager() + cred = mock.MagicMock() + request = mock.MagicMock() + + cred.refresh.side_effect = exceptions.RefreshError("Failed to refresh") + + assert w.start_refresh(cred, request) + + while w._worker._error_info is None: # pragma: NO COVER + time.sleep(MAIN_THREAD_SLEEP_MS) + + assert not w.start_refresh(cred, request) + + +def test_refresh_dead_worker(): + cred = MockCredentialsImpl() + request = mock.MagicMock() + + w = _refresh_worker.RefreshThreadManager() + w._worker = None + + w.start_refresh(cred, request) + + _cred_spinlock(cred) + + assert cred.token == request + assert cred.refresh_count == 1 + + +def test_pickle(): + w = _refresh_worker.RefreshThreadManager() + + pickled_manager = pickle.dumps(w) + manager = pickle.loads(pickled_manager) + assert isinstance(manager, _refresh_worker.RefreshThreadManager) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.25.2/tests/test_credentials.py new/google-auth-2.26.1/tests/test_credentials.py --- old/google-auth-2.25.2/tests/test_credentials.py 2023-12-08 20:34:40.000000000 +0100 +++ new/google-auth-2.26.1/tests/test_credentials.py 2024-01-03 23:49:22.000000000 +0100 @@ -14,6 +14,7 @@ import datetime +import mock import pytest # type: ignore from google.auth import _helpers @@ -23,6 +24,11 @@ class CredentialsImpl(credentials.Credentials): def refresh(self, request): self.token = request + self.expiry = ( + datetime.datetime.utcnow() + + _helpers.REFRESH_THRESHOLD + + datetime.timedelta(seconds=5) + ) def with_quota_project(self, quota_project_id): raise NotImplementedError() @@ -43,6 +49,13 @@ assert not credentials.expired assert not credentials.valid assert credentials.universe_domain == "googleapis.com" + assert not credentials._use_non_blocking_refresh + + +def test_with_non_blocking_refresh(): + c = CredentialsImpl() + c.with_non_blocking_refresh() + assert c._use_non_blocking_refresh def test_expired_and_valid(): @@ -220,3 +233,108 @@ ) assert scoped_credentials is unscoped_credentials + + +def test_nonblocking_refresh_fresh_credentials(): + c = CredentialsImpl() + + c._refresh_worker = mock.MagicMock() + + request = "token" + + c.refresh(request) + assert c.token_state == credentials.TokenState.FRESH + + c.with_non_blocking_refresh() + c.before_request(request, "http://example.com", "GET", {}) + + +def test_nonblocking_refresh_invalid_credentials(): + c = CredentialsImpl() + c.with_non_blocking_refresh() + + request = "token" + headers = {} + + assert c.token_state == credentials.TokenState.INVALID + + c.before_request(request, "http://example.com", "GET", headers) + assert c.token_state == credentials.TokenState.FRESH + assert c.valid + assert c.token == "token" + assert headers["authorization"] == "Bearer token" + assert "x-identity-trust-boundary" not in headers + + +def test_nonblocking_refresh_stale_credentials(): + c = CredentialsImpl() + c.with_non_blocking_refresh() + + request = "token" + headers = {} + + # Invalid credentials MUST require a blocking refresh. + c.before_request(request, "http://example.com", "GET", headers) + assert c.token_state == credentials.TokenState.FRESH + assert not c._refresh_worker._worker + + c.expiry = ( + datetime.datetime.utcnow() + + _helpers.REFRESH_THRESHOLD + - datetime.timedelta(seconds=1) + ) + + # STALE credentials SHOULD spawn a non-blocking worker + assert c.token_state == credentials.TokenState.STALE + c.before_request(request, "http://example.com", "GET", headers) + assert c._refresh_worker._worker is not None + + assert c.token_state == credentials.TokenState.FRESH + assert c.valid + assert c.token == "token" + assert headers["authorization"] == "Bearer token" + assert "x-identity-trust-boundary" not in headers + + +def test_nonblocking_refresh_failed_credentials(): + c = CredentialsImpl() + c.with_non_blocking_refresh() + + request = "token" + headers = {} + + # Invalid credentials MUST require a blocking refresh. + c.before_request(request, "http://example.com", "GET", headers) + assert c.token_state == credentials.TokenState.FRESH + assert not c._refresh_worker._worker + + c.expiry = ( + datetime.datetime.utcnow() + + _helpers.REFRESH_THRESHOLD + - datetime.timedelta(seconds=1) + ) + + # STALE credentials SHOULD spawn a non-blocking worker + assert c.token_state == credentials.TokenState.STALE + c._refresh_worker._worker = mock.MagicMock() + c._refresh_worker._worker._error_info = "Some Error" + c.before_request(request, "http://example.com", "GET", headers) + assert c._refresh_worker._worker is not None + + assert c.token_state == credentials.TokenState.FRESH + assert c.valid + assert c.token == "token" + assert headers["authorization"] == "Bearer token" + assert "x-identity-trust-boundary" not in headers + + +def test_token_state_no_expiry(): + c = CredentialsImpl() + + request = "token" + c.refresh(request) + + c.expiry = None + assert c.token_state == credentials.TokenState.FRESH + + c.before_request(request, "http://example.com", "GET", {}) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.25.2/tests/test_downscoped.py new/google-auth-2.26.1/tests/test_downscoped.py --- old/google-auth-2.25.2/tests/test_downscoped.py 2023-12-08 20:34:40.000000000 +0100 +++ new/google-auth-2.26.1/tests/test_downscoped.py 2024-01-03 23:49:22.000000000 +0100 @@ -25,6 +25,7 @@ from google.auth import downscoped from google.auth import exceptions from google.auth import transport +from google.auth.credentials import TokenState EXPRESSION = ( @@ -676,6 +677,7 @@ assert credentials.valid assert not credentials.expired + assert credentials.token_state == TokenState.FRESH credentials.before_request(request, "POST", "https://example.com/api", headers) @@ -687,8 +689,24 @@ assert not credentials.valid assert credentials.expired + assert credentials.token_state == TokenState.STALE credentials.before_request(request, "POST", "https://example.com/api", headers) + assert credentials.token_state == TokenState.FRESH + + # New token should be retrieved. + assert headers == { + "authorization": "Bearer {}".format(SUCCESS_RESPONSE["access_token"]) + } + + utcnow.return_value = datetime.datetime.min + datetime.timedelta(seconds=6000) + + assert not credentials.valid + assert credentials.expired + assert credentials.token_state == TokenState.INVALID + + credentials.before_request(request, "POST", "https://example.com/api", headers) + assert credentials.token_state == TokenState.FRESH # New token should be retrieved. assert headers == { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.25.2/tests/test_external_account.py new/google-auth-2.26.1/tests/test_external_account.py --- old/google-auth-2.25.2/tests/test_external_account.py 2023-12-08 20:34:40.000000000 +0100 +++ new/google-auth-2.26.1/tests/test_external_account.py 2024-01-03 23:49:22.000000000 +0100 @@ -24,6 +24,7 @@ from google.auth import exceptions from google.auth import external_account from google.auth import transport +from google.auth.credentials import TokenState IMPERSONATE_ACCESS_TOKEN_REQUEST_METRICS_HEADER_VALUE = ( @@ -1494,6 +1495,7 @@ assert credentials.valid assert not credentials.expired + assert credentials.token_state == TokenState.FRESH credentials.before_request(request, "POST", "https://example.com/api", headers) @@ -1508,8 +1510,10 @@ assert not credentials.valid assert credentials.expired + assert credentials.token_state == TokenState.STALE credentials.before_request(request, "POST", "https://example.com/api", headers) + assert credentials.token_state == TokenState.FRESH # New token should be retrieved. assert headers == { @@ -1551,8 +1555,10 @@ assert credentials.valid assert not credentials.expired + assert credentials.token_state == TokenState.FRESH credentials.before_request(request, "POST", "https://example.com/api", headers) + assert credentials.token_state == TokenState.FRESH # Cached token should be used. assert headers == { @@ -1566,6 +1572,10 @@ assert not credentials.valid assert credentials.expired + assert credentials.token_state == TokenState.STALE + + credentials.before_request(request, "POST", "https://example.com/api", headers) + assert credentials.token_state == TokenState.FRESH credentials.before_request(request, "POST", "https://example.com/api", headers) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.25.2/tests/test_external_account_authorized_user.py new/google-auth-2.26.1/tests/test_external_account_authorized_user.py --- old/google-auth-2.25.2/tests/test_external_account_authorized_user.py 2023-12-08 20:34:40.000000000 +0100 +++ new/google-auth-2.26.1/tests/test_external_account_authorized_user.py 2024-01-03 23:49:22.000000000 +0100 @@ -44,6 +44,8 @@ BASIC_AUTH_ENCODING = "dXNlcm5hbWU6cGFzc3dvcmQ=" SCOPES = ["email", "profile"] NOW = datetime.datetime(1990, 8, 27, 6, 54, 30) +FAKE_UNIVERSE_DOMAIN = "fake-universe-domain" +DEFAULT_UNIVERSE_DOMAIN = external_account_authorized_user._DEFAULT_UNIVERSE_DOMAIN class TestCredentials(object): @@ -98,6 +100,7 @@ assert creds.refresh_token == REFRESH_TOKEN assert creds.audience == AUDIENCE assert creds.token_url == TOKEN_URL + assert creds.universe_domain == DEFAULT_UNIVERSE_DOMAIN def test_basic_create(self): creds = external_account_authorized_user.Credentials( @@ -105,6 +108,7 @@ expiry=datetime.datetime.max, scopes=SCOPES, revoke_url=REVOKE_URL, + universe_domain=FAKE_UNIVERSE_DOMAIN, ) assert creds.expiry == datetime.datetime.max @@ -115,6 +119,7 @@ assert creds.scopes == SCOPES assert creds.is_user assert creds.revoke_url == REVOKE_URL + assert creds.universe_domain == FAKE_UNIVERSE_DOMAIN def test_stunted_create_no_refresh_token(self): with pytest.raises(ValueError) as excinfo: @@ -339,6 +344,7 @@ assert info["token_info_url"] == TOKEN_INFO_URL assert info["client_id"] == CLIENT_ID assert info["client_secret"] == CLIENT_SECRET + assert info["universe_domain"] == DEFAULT_UNIVERSE_DOMAIN assert "token" not in info assert "expiry" not in info assert "revoke_url" not in info @@ -350,6 +356,7 @@ expiry=NOW, revoke_url=REVOKE_URL, quota_project_id=QUOTA_PROJECT_ID, + universe_domain=FAKE_UNIVERSE_DOMAIN, ) info = creds.info @@ -363,6 +370,7 @@ assert info["expiry"] == NOW.isoformat() + "Z" assert info["revoke_url"] == REVOKE_URL assert info["quota_project_id"] == QUOTA_PROJECT_ID + assert info["universe_domain"] == FAKE_UNIVERSE_DOMAIN def test_to_json(self): creds = self.make_credentials() @@ -375,6 +383,7 @@ assert info["token_info_url"] == TOKEN_INFO_URL assert info["client_id"] == CLIENT_ID assert info["client_secret"] == CLIENT_SECRET + assert info["universe_domain"] == DEFAULT_UNIVERSE_DOMAIN assert "token" not in info assert "expiry" not in info assert "revoke_url" not in info @@ -386,6 +395,7 @@ expiry=NOW, revoke_url=REVOKE_URL, quota_project_id=QUOTA_PROJECT_ID, + universe_domain=FAKE_UNIVERSE_DOMAIN, ) json_info = creds.to_json() info = json.loads(json_info) @@ -400,6 +410,7 @@ assert info["expiry"] == NOW.isoformat() + "Z" assert info["revoke_url"] == REVOKE_URL assert info["quota_project_id"] == QUOTA_PROJECT_ID + assert info["universe_domain"] == FAKE_UNIVERSE_DOMAIN def test_to_json_full_with_strip(self): creds = self.make_credentials( @@ -467,6 +478,26 @@ assert new_creds._revoke_url == creds._revoke_url assert new_creds._quota_project_id == creds._quota_project_id + def test_with_universe_domain(self): + creds = self.make_credentials( + token=ACCESS_TOKEN, + expiry=NOW, + revoke_url=REVOKE_URL, + quota_project_id=QUOTA_PROJECT_ID, + ) + new_creds = creds.with_universe_domain(FAKE_UNIVERSE_DOMAIN) + assert new_creds._audience == creds._audience + assert new_creds._refresh_token == creds._refresh_token + assert new_creds._token_url == creds._token_url + assert new_creds._token_info_url == creds._token_info_url + assert new_creds._client_id == creds._client_id + assert new_creds._client_secret == creds._client_secret + assert new_creds.token == creds.token + assert new_creds.expiry == creds.expiry + assert new_creds._revoke_url == creds._revoke_url + assert new_creds._quota_project_id == QUOTA_PROJECT_ID + assert new_creds.universe_domain == FAKE_UNIVERSE_DOMAIN + def test_from_file_required_options_only(self, tmpdir): from_creds = self.make_credentials() config_file = tmpdir.join("config.json") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.25.2/tests/test_impersonated_credentials.py new/google-auth-2.26.1/tests/test_impersonated_credentials.py --- old/google-auth-2.25.2/tests/test_impersonated_credentials.py 2023-12-08 20:34:40.000000000 +0100 +++ new/google-auth-2.26.1/tests/test_impersonated_credentials.py 2024-01-03 23:49:22.000000000 +0100 @@ -242,7 +242,7 @@ request_kwargs = request.call_args[1] assert request_kwargs["url"] == self.IAM_ENDPOINT_OVERRIDE - @pytest.mark.parametrize("time_skew", [100, -100]) + @pytest.mark.parametrize("time_skew", [150, -150]) def test_refresh_source_credentials(self, time_skew): credentials = self.make_credentials(lifetime=None) ++++++ python-google-auth-no-mock.patch ++++++ --- /var/tmp/diff_new_pack.zSGf5j/_old 2024-01-05 22:59:59.003142604 +0100 +++ /var/tmp/diff_new_pack.zSGf5j/_new 2024-01-05 22:59:59.007142751 +0100 @@ -1,7 +1,6 @@ -Index: google-auth-2.23.0/tests/compute_engine/test_credentials.py -=================================================================== ---- google-auth-2.23.0.orig/tests/compute_engine/test_credentials.py -+++ google-auth-2.23.0/tests/compute_engine/test_credentials.py +diff -Nru google-auth-2.26.1.orig/tests/compute_engine/test_credentials.py google-auth-2.26.1/tests/compute_engine/test_credentials.py +--- google-auth-2.26.1.orig/tests/compute_engine/test_credentials.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/compute_engine/test_credentials.py 2024-01-04 10:40:25.973375772 +0100 @@ -14,7 +14,7 @@ import base64 import datetime @@ -11,11 +10,10 @@ import pytest # type: ignore import responses # type: ignore -Index: google-auth-2.23.0/tests/compute_engine/test__metadata.py -=================================================================== ---- google-auth-2.23.0.orig/tests/compute_engine/test__metadata.py -+++ google-auth-2.23.0/tests/compute_engine/test__metadata.py -@@ -18,7 +18,7 @@ import importlib +diff -Nru google-auth-2.26.1.orig/tests/compute_engine/test__metadata.py google-auth-2.26.1/tests/compute_engine/test__metadata.py +--- google-auth-2.26.1.orig/tests/compute_engine/test__metadata.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/compute_engine/test__metadata.py 2024-01-04 10:40:25.976709143 +0100 +@@ -18,7 +18,7 @@ import json import os @@ -24,10 +22,9 @@ import pytest # type: ignore from google.auth import _helpers -Index: google-auth-2.23.0/tests/conftest.py -=================================================================== ---- google-auth-2.23.0.orig/tests/conftest.py -+++ google-auth-2.23.0/tests/conftest.py +diff -Nru google-auth-2.26.1.orig/tests/conftest.py google-auth-2.26.1/tests/conftest.py +--- google-auth-2.26.1.orig/tests/conftest.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/conftest.py 2024-01-04 10:40:25.873374649 +0100 @@ -15,7 +15,7 @@ import os import sys @@ -37,11 +34,10 @@ import pytest # type: ignore -Index: google-auth-2.23.0/tests/crypt/test__python_rsa.py -=================================================================== ---- google-auth-2.23.0.orig/tests/crypt/test__python_rsa.py -+++ google-auth-2.23.0/tests/crypt/test__python_rsa.py -@@ -16,7 +16,7 @@ import io +diff -Nru google-auth-2.26.1.orig/tests/crypt/test__python_rsa.py google-auth-2.26.1/tests/crypt/test__python_rsa.py +--- google-auth-2.26.1.orig/tests/crypt/test__python_rsa.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/crypt/test__python_rsa.py 2024-01-04 10:40:26.013376222 +0100 +@@ -16,7 +16,7 @@ import json import os @@ -50,10 +46,9 @@ from pyasn1_modules import pem # type: ignore import pytest # type: ignore import rsa # type: ignore -Index: google-auth-2.23.0/tests/oauth2/test_challenges.py -=================================================================== ---- google-auth-2.23.0.orig/tests/oauth2/test_challenges.py -+++ google-auth-2.23.0/tests/oauth2/test_challenges.py +diff -Nru google-auth-2.26.1.orig/tests/oauth2/test_challenges.py google-auth-2.26.1/tests/oauth2/test_challenges.py +--- google-auth-2.26.1.orig/tests/oauth2/test_challenges.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/oauth2/test_challenges.py 2024-01-04 10:40:25.953375548 +0100 @@ -17,7 +17,7 @@ import base64 import sys @@ -63,11 +58,10 @@ import pytest # type: ignore import pyu2f # type: ignore -Index: google-auth-2.23.0/tests/oauth2/test__client.py -=================================================================== ---- google-auth-2.23.0.orig/tests/oauth2/test__client.py -+++ google-auth-2.23.0/tests/oauth2/test__client.py -@@ -18,7 +18,7 @@ import json +diff -Nru google-auth-2.26.1.orig/tests/oauth2/test__client.py google-auth-2.26.1/tests/oauth2/test__client.py +--- google-auth-2.26.1.orig/tests/oauth2/test__client.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/oauth2/test__client.py 2024-01-04 10:40:25.940042064 +0100 +@@ -18,7 +18,7 @@ import os import urllib @@ -76,11 +70,10 @@ import pytest # type: ignore from google.auth import _helpers -Index: google-auth-2.23.0/tests/oauth2/test_credentials.py -=================================================================== ---- google-auth-2.23.0.orig/tests/oauth2/test_credentials.py -+++ google-auth-2.23.0/tests/oauth2/test_credentials.py -@@ -18,7 +18,7 @@ import os +diff -Nru google-auth-2.26.1.orig/tests/oauth2/test_credentials.py google-auth-2.26.1/tests/oauth2/test_credentials.py +--- google-auth-2.26.1.orig/tests/oauth2/test_credentials.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/oauth2/test_credentials.py 2024-01-04 10:40:25.946708806 +0100 +@@ -18,7 +18,7 @@ import pickle import sys @@ -89,11 +82,10 @@ import pytest # type: ignore from google.auth import _helpers -Index: google-auth-2.23.0/tests/oauth2/test_gdch_credentials.py -=================================================================== ---- google-auth-2.23.0.orig/tests/oauth2/test_gdch_credentials.py -+++ google-auth-2.23.0/tests/oauth2/test_gdch_credentials.py -@@ -17,7 +17,7 @@ import datetime +diff -Nru google-auth-2.26.1.orig/tests/oauth2/test_gdch_credentials.py google-auth-2.26.1/tests/oauth2/test_gdch_credentials.py +--- google-auth-2.26.1.orig/tests/oauth2/test_gdch_credentials.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/oauth2/test_gdch_credentials.py 2024-01-04 10:40:25.930041952 +0100 +@@ -17,7 +17,7 @@ import json import os @@ -102,10 +94,9 @@ import pytest # type: ignore import requests -Index: google-auth-2.23.0/tests/oauth2/test_id_token.py -=================================================================== ---- google-auth-2.23.0.orig/tests/oauth2/test_id_token.py -+++ google-auth-2.23.0/tests/oauth2/test_id_token.py +diff -Nru google-auth-2.26.1.orig/tests/oauth2/test_id_token.py google-auth-2.26.1/tests/oauth2/test_id_token.py +--- google-auth-2.26.1.orig/tests/oauth2/test_id_token.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/oauth2/test_id_token.py 2024-01-04 10:40:25.936708693 +0100 @@ -15,7 +15,7 @@ import json import os @@ -115,10 +106,9 @@ import pytest # type: ignore from google.auth import environment_vars -Index: google-auth-2.23.0/tests/oauth2/test_reauth.py -=================================================================== ---- google-auth-2.23.0.orig/tests/oauth2/test_reauth.py -+++ google-auth-2.23.0/tests/oauth2/test_reauth.py +diff -Nru google-auth-2.26.1.orig/tests/oauth2/test_reauth.py google-auth-2.26.1/tests/oauth2/test_reauth.py +--- google-auth-2.26.1.orig/tests/oauth2/test_reauth.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/oauth2/test_reauth.py 2024-01-04 10:40:25.950042176 +0100 @@ -14,7 +14,7 @@ import copy @@ -128,11 +118,10 @@ import pytest # type: ignore from google.auth import exceptions -Index: google-auth-2.23.0/tests/oauth2/test_service_account.py -=================================================================== ---- google-auth-2.23.0.orig/tests/oauth2/test_service_account.py -+++ google-auth-2.23.0/tests/oauth2/test_service_account.py -@@ -16,7 +16,7 @@ import datetime +diff -Nru google-auth-2.26.1.orig/tests/oauth2/test_service_account.py google-auth-2.26.1/tests/oauth2/test_service_account.py +--- google-auth-2.26.1.orig/tests/oauth2/test_service_account.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/oauth2/test_service_account.py 2024-01-04 10:40:25.943375435 +0100 +@@ -16,7 +16,7 @@ import json import os @@ -141,11 +130,10 @@ import pytest # type: ignore from google.auth import _helpers -Index: google-auth-2.23.0/tests/oauth2/test_sts.py -=================================================================== ---- google-auth-2.23.0.orig/tests/oauth2/test_sts.py -+++ google-auth-2.23.0/tests/oauth2/test_sts.py -@@ -16,7 +16,7 @@ import http.client as http_client +diff -Nru google-auth-2.26.1.orig/tests/oauth2/test_sts.py google-auth-2.26.1/tests/oauth2/test_sts.py +--- google-auth-2.26.1.orig/tests/oauth2/test_sts.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/oauth2/test_sts.py 2024-01-04 10:40:25.956708918 +0100 +@@ -16,7 +16,7 @@ import json import urllib @@ -154,10 +142,9 @@ import pytest # type: ignore from google.auth import exceptions -Index: google-auth-2.23.0/tests/test_app_engine.py -=================================================================== ---- google-auth-2.23.0.orig/tests/test_app_engine.py -+++ google-auth-2.23.0/tests/test_app_engine.py +diff -Nru google-auth-2.26.1.orig/tests/test_app_engine.py google-auth-2.26.1/tests/test_app_engine.py +--- google-auth-2.26.1.orig/tests/test_app_engine.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/test_app_engine.py 2024-01-04 10:40:25.906708356 +0100 @@ -14,7 +14,7 @@ import datetime @@ -167,11 +154,10 @@ import pytest # type: ignore from google.auth import app_engine -Index: google-auth-2.23.0/tests/test_aws.py -=================================================================== ---- google-auth-2.23.0.orig/tests/test_aws.py -+++ google-auth-2.23.0/tests/test_aws.py -@@ -18,7 +18,7 @@ import json +diff -Nru google-auth-2.26.1.orig/tests/test_aws.py google-auth-2.26.1/tests/test_aws.py +--- google-auth-2.26.1.orig/tests/test_aws.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/test_aws.py 2024-01-04 10:40:26.040043188 +0100 +@@ -18,7 +18,7 @@ import os import urllib.parse @@ -180,11 +166,10 @@ import pytest # type: ignore from google.auth import _helpers -Index: google-auth-2.23.0/tests/test__cloud_sdk.py -=================================================================== ---- google-auth-2.23.0.orig/tests/test__cloud_sdk.py -+++ google-auth-2.23.0/tests/test__cloud_sdk.py -@@ -18,7 +18,7 @@ import os +diff -Nru google-auth-2.26.1.orig/tests/test__cloud_sdk.py google-auth-2.26.1/tests/test__cloud_sdk.py +--- google-auth-2.26.1.orig/tests/test__cloud_sdk.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/test__cloud_sdk.py 2024-01-04 10:40:25.920041839 +0100 +@@ -18,7 +18,7 @@ import subprocess import sys @@ -193,10 +178,21 @@ import pytest # type: ignore from google.auth import _cloud_sdk -Index: google-auth-2.23.0/tests/test__default.py -=================================================================== ---- google-auth-2.23.0.orig/tests/test__default.py -+++ google-auth-2.23.0/tests/test__default.py +diff -Nru google-auth-2.26.1.orig/tests/test_credentials.py google-auth-2.26.1/tests/test_credentials.py +--- google-auth-2.26.1.orig/tests/test_credentials.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/test_credentials.py 2024-01-04 10:40:25.960042289 +0100 +@@ -14,7 +14,7 @@ + + import datetime + +-import mock ++from unittest import mock + import pytest # type: ignore + + from google.auth import _helpers +diff -Nru google-auth-2.26.1.orig/tests/test__default.py google-auth-2.26.1/tests/test__default.py +--- google-auth-2.26.1.orig/tests/test__default.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/test__default.py 2024-01-04 10:40:25.963375660 +0100 @@ -15,7 +15,7 @@ import json import os @@ -206,11 +202,10 @@ import pytest # type: ignore from google.auth import _default -Index: google-auth-2.23.0/tests/test_downscoped.py -=================================================================== ---- google-auth-2.23.0.orig/tests/test_downscoped.py -+++ google-auth-2.23.0/tests/test_downscoped.py -@@ -17,7 +17,7 @@ import http.client as http_client +diff -Nru google-auth-2.26.1.orig/tests/test_downscoped.py google-auth-2.26.1/tests/test_downscoped.py +--- google-auth-2.26.1.orig/tests/test_downscoped.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/test_downscoped.py 2024-01-04 10:40:25.966709030 +0100 +@@ -17,7 +17,7 @@ import json import urllib @@ -219,10 +214,9 @@ import pytest # type: ignore from google.auth import _helpers -Index: google-auth-2.23.0/tests/test__exponential_backoff.py -=================================================================== ---- google-auth-2.23.0.orig/tests/test__exponential_backoff.py -+++ google-auth-2.23.0/tests/test__exponential_backoff.py +diff -Nru google-auth-2.26.1.orig/tests/test__exponential_backoff.py google-auth-2.26.1/tests/test__exponential_backoff.py +--- google-auth-2.26.1.orig/tests/test__exponential_backoff.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/test__exponential_backoff.py 2024-01-04 10:40:25.863374536 +0100 @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. @@ -232,11 +226,10 @@ from google.auth import _exponential_backoff -Index: google-auth-2.23.0/tests/test_external_account_authorized_user.py -=================================================================== ---- google-auth-2.23.0.orig/tests/test_external_account_authorized_user.py -+++ google-auth-2.23.0/tests/test_external_account_authorized_user.py -@@ -16,7 +16,7 @@ import datetime +diff -Nru google-auth-2.26.1.orig/tests/test_external_account_authorized_user.py google-auth-2.26.1/tests/test_external_account_authorized_user.py +--- google-auth-2.26.1.orig/tests/test_external_account_authorized_user.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/test_external_account_authorized_user.py 2024-01-04 10:40:25.963375660 +0100 +@@ -16,7 +16,7 @@ import http.client as http_client import json @@ -245,11 +238,10 @@ import pytest # type: ignore from google.auth import exceptions -Index: google-auth-2.23.0/tests/test_external_account.py -=================================================================== ---- google-auth-2.23.0.orig/tests/test_external_account.py -+++ google-auth-2.23.0/tests/test_external_account.py -@@ -17,7 +17,7 @@ import http.client as http_client +diff -Nru google-auth-2.26.1.orig/tests/test_external_account.py google-auth-2.26.1/tests/test_external_account.py +--- google-auth-2.26.1.orig/tests/test_external_account.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/test_external_account.py 2024-01-04 10:40:25.866707907 +0100 +@@ -17,7 +17,7 @@ import json import urllib @@ -258,11 +250,10 @@ import pytest # type: ignore from google.auth import _helpers -Index: google-auth-2.23.0/tests/test_iam.py -=================================================================== ---- google-auth-2.23.0.orig/tests/test_iam.py -+++ google-auth-2.23.0/tests/test_iam.py -@@ -17,7 +17,7 @@ import datetime +diff -Nru google-auth-2.26.1.orig/tests/test_iam.py google-auth-2.26.1/tests/test_iam.py +--- google-auth-2.26.1.orig/tests/test_iam.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/test_iam.py 2024-01-04 10:40:25.983375885 +0100 +@@ -17,7 +17,7 @@ import http.client as http_client import json @@ -271,11 +262,10 @@ import pytest # type: ignore from google.auth import _helpers -Index: google-auth-2.23.0/tests/test_identity_pool.py -=================================================================== ---- google-auth-2.23.0.orig/tests/test_identity_pool.py -+++ google-auth-2.23.0/tests/test_identity_pool.py -@@ -18,7 +18,7 @@ import json +diff -Nru google-auth-2.26.1.orig/tests/test_identity_pool.py google-auth-2.26.1/tests/test_identity_pool.py +--- google-auth-2.26.1.orig/tests/test_identity_pool.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/test_identity_pool.py 2024-01-04 10:40:25.990042626 +0100 +@@ -18,7 +18,7 @@ import os import urllib @@ -284,11 +274,10 @@ import pytest # type: ignore from google.auth import _helpers -Index: google-auth-2.23.0/tests/test_impersonated_credentials.py -=================================================================== ---- google-auth-2.23.0.orig/tests/test_impersonated_credentials.py -+++ google-auth-2.23.0/tests/test_impersonated_credentials.py -@@ -17,7 +17,7 @@ import http.client as http_client +diff -Nru google-auth-2.26.1.orig/tests/test_impersonated_credentials.py google-auth-2.26.1/tests/test_impersonated_credentials.py +--- google-auth-2.26.1.orig/tests/test_impersonated_credentials.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/test_impersonated_credentials.py 2024-01-04 10:40:26.030043076 +0100 +@@ -17,7 +17,7 @@ import json import os @@ -297,11 +286,10 @@ import pytest # type: ignore from google.auth import _helpers -Index: google-auth-2.23.0/tests/test_jwt.py -=================================================================== ---- google-auth-2.23.0.orig/tests/test_jwt.py -+++ google-auth-2.23.0/tests/test_jwt.py -@@ -17,7 +17,7 @@ import datetime +diff -Nru google-auth-2.26.1.orig/tests/test_jwt.py google-auth-2.26.1/tests/test_jwt.py +--- google-auth-2.26.1.orig/tests/test_jwt.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/test_jwt.py 2024-01-04 10:40:25.993375997 +0100 +@@ -17,7 +17,7 @@ import json import os @@ -310,10 +298,9 @@ import pytest # type: ignore from google.auth import _helpers -Index: google-auth-2.23.0/tests/test_metrics.py -=================================================================== ---- google-auth-2.23.0.orig/tests/test_metrics.py -+++ google-auth-2.23.0/tests/test_metrics.py +diff -Nru google-auth-2.26.1.orig/tests/test_metrics.py google-auth-2.26.1/tests/test_metrics.py +--- google-auth-2.26.1.orig/tests/test_metrics.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/test_metrics.py 2024-01-04 10:40:25.926708581 +0100 @@ -14,7 +14,7 @@ import platform @@ -323,11 +310,10 @@ from google.auth import metrics from google.auth import version -Index: google-auth-2.23.0/tests/test__oauth2client.py -=================================================================== ---- google-auth-2.23.0.orig/tests/test__oauth2client.py -+++ google-auth-2.23.0/tests/test__oauth2client.py -@@ -17,7 +17,7 @@ import importlib +diff -Nru google-auth-2.26.1.orig/tests/test__oauth2client.py google-auth-2.26.1/tests/test__oauth2client.py +--- google-auth-2.26.1.orig/tests/test__oauth2client.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/test__oauth2client.py 2024-01-04 10:40:25.910041727 +0100 +@@ -17,7 +17,7 @@ import os import sys @@ -336,11 +322,10 @@ import pytest # type: ignore try: -Index: google-auth-2.23.0/tests/test_pluggable.py -=================================================================== ---- google-auth-2.23.0.orig/tests/test_pluggable.py -+++ google-auth-2.23.0/tests/test_pluggable.py -@@ -16,7 +16,7 @@ import json +diff -Nru google-auth-2.26.1.orig/tests/test_pluggable.py google-auth-2.26.1/tests/test_pluggable.py +--- google-auth-2.26.1.orig/tests/test_pluggable.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/test_pluggable.py 2024-01-04 10:40:26.033376446 +0100 +@@ -16,7 +16,7 @@ import os import subprocess @@ -349,11 +334,22 @@ import pytest # type: ignore from google.auth import exceptions -Index: google-auth-2.23.0/tests/transport/test__custom_tls_signer.py -=================================================================== ---- google-auth-2.23.0.orig/tests/transport/test__custom_tls_signer.py -+++ google-auth-2.23.0/tests/transport/test__custom_tls_signer.py -@@ -16,7 +16,7 @@ import base64 +diff -Nru google-auth-2.26.1.orig/tests/test__refresh_worker.py google-auth-2.26.1/tests/test__refresh_worker.py +--- google-auth-2.26.1.orig/tests/test__refresh_worker.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/test__refresh_worker.py 2024-01-04 10:40:26.016709592 +0100 +@@ -17,7 +17,7 @@ + import threading + import time + +-import mock ++from unittest import mock + import pytest # type: ignore + + from google.auth import _refresh_worker, credentials, exceptions +diff -Nru google-auth-2.26.1.orig/tests/transport/test__custom_tls_signer.py google-auth-2.26.1/tests/transport/test__custom_tls_signer.py +--- google-auth-2.26.1.orig/tests/transport/test__custom_tls_signer.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/transport/test__custom_tls_signer.py 2024-01-04 10:40:25.880041390 +0100 +@@ -15,7 +15,7 @@ import ctypes import os @@ -362,11 +358,10 @@ import pytest # type: ignore from requests.packages.urllib3.util.ssl_ import create_urllib3_context # type: ignore import urllib3.contrib.pyopenssl # type: ignore -Index: google-auth-2.23.0/tests/transport/test_grpc.py -=================================================================== ---- google-auth-2.23.0.orig/tests/transport/test_grpc.py -+++ google-auth-2.23.0/tests/transport/test_grpc.py -@@ -16,7 +16,7 @@ import datetime +diff -Nru google-auth-2.26.1.orig/tests/transport/test_grpc.py google-auth-2.26.1/tests/transport/test_grpc.py +--- google-auth-2.26.1.orig/tests/transport/test_grpc.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/transport/test_grpc.py 2024-01-04 10:40:25.883374761 +0100 +@@ -16,7 +16,7 @@ import os import time @@ -375,10 +370,9 @@ import pytest # type: ignore from google.auth import _helpers -Index: google-auth-2.23.0/tests/transport/test__mtls_helper.py -=================================================================== ---- google-auth-2.23.0.orig/tests/transport/test__mtls_helper.py -+++ google-auth-2.23.0/tests/transport/test__mtls_helper.py +diff -Nru google-auth-2.26.1.orig/tests/transport/test__mtls_helper.py google-auth-2.26.1/tests/transport/test__mtls_helper.py +--- google-auth-2.26.1.orig/tests/transport/test__mtls_helper.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/transport/test__mtls_helper.py 2024-01-04 10:40:25.890041502 +0100 @@ -15,7 +15,7 @@ import os import re @@ -388,10 +382,9 @@ from OpenSSL import crypto import pytest # type: ignore -Index: google-auth-2.23.0/tests/transport/test_mtls.py -=================================================================== ---- google-auth-2.23.0.orig/tests/transport/test_mtls.py -+++ google-auth-2.23.0/tests/transport/test_mtls.py +diff -Nru google-auth-2.26.1.orig/tests/transport/test_mtls.py google-auth-2.26.1/tests/transport/test_mtls.py +--- google-auth-2.26.1.orig/tests/transport/test_mtls.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/transport/test_mtls.py 2024-01-04 10:40:25.893374873 +0100 @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. @@ -401,11 +394,10 @@ import pytest # type: ignore from google.auth import exceptions -Index: google-auth-2.23.0/tests/transport/test_requests.py -=================================================================== ---- google-auth-2.23.0.orig/tests/transport/test_requests.py -+++ google-auth-2.23.0/tests/transport/test_requests.py -@@ -19,7 +19,7 @@ import os +diff -Nru google-auth-2.26.1.orig/tests/transport/test_requests.py google-auth-2.26.1/tests/transport/test_requests.py +--- google-auth-2.26.1.orig/tests/transport/test_requests.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/transport/test_requests.py 2024-01-04 10:40:25.896708244 +0100 +@@ -19,7 +19,7 @@ import sys import freezegun @@ -414,11 +406,10 @@ import OpenSSL import pytest # type: ignore import requests -Index: google-auth-2.23.0/tests/transport/test_urllib3.py -=================================================================== ---- google-auth-2.23.0.orig/tests/transport/test_urllib3.py -+++ google-auth-2.23.0/tests/transport/test_urllib3.py -@@ -16,7 +16,7 @@ import http.client as http_client +diff -Nru google-auth-2.26.1.orig/tests/transport/test_urllib3.py google-auth-2.26.1/tests/transport/test_urllib3.py +--- google-auth-2.26.1.orig/tests/transport/test_urllib3.py 2024-01-03 23:49:22.000000000 +0100 ++++ google-auth-2.26.1/tests/transport/test_urllib3.py 2024-01-04 10:40:25.876708019 +0100 +@@ -16,7 +16,7 @@ import os import sys
