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 2022-10-15 16:34:57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-google-auth (Old) and /work/SRC/openSUSE:Factory/.python-google-auth.new.2275 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-google-auth" Sat Oct 15 16:34:57 2022 rev:22 rq:1010915 version:2.12.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-google-auth/python-google-auth.changes 2022-09-09 18:22:53.680155641 +0200 +++ /work/SRC/openSUSE:Factory/.python-google-auth.new.2275/python-google-auth.changes 2022-10-15 16:36:12.933974355 +0200 @@ -1,0 +2,10 @@ +Fri Oct 14 09:30:55 UTC 2022 - John Paul Adrian Glaubitz <[email protected]> + +- Update to 2.12.0 + * Retry behavior (#1113) + * Modify RefreshError exception to use gcloud ADC command. (#1149) + * Revert "Update token refresh threshold from 20 seconds to 5 minutes". (186464b) +- Refresh patches for new version + * python-google-auth-no-mock.patch + +------------------------------------------------------------------- Old: ---- google-auth-2.11.0.tar.gz New: ---- google-auth-2.12.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-google-auth.spec ++++++ --- /var/tmp/diff_new_pack.eu8sbx/_old 2022-10-15 16:36:14.629978431 +0200 +++ /var/tmp/diff_new_pack.eu8sbx/_new 2022-10-15 16:36:14.637978450 +0200 @@ -19,7 +19,7 @@ %define skip_python2 1 %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-google-auth -Version: 2.11.0 +Version: 2.12.0 Release: 0 Summary: Google Authentication Library License: Apache-2.0 ++++++ google-auth-2.11.0.tar.gz -> google-auth-2.12.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/PKG-INFO new/google-auth-2.12.0/PKG-INFO --- old/google-auth-2.11.0/PKG-INFO 2022-08-20 01:29:58.960029000 +0200 +++ new/google-auth-2.12.0/PKG-INFO 2022-09-27 22:42:06.128310700 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: google-auth -Version: 2.11.0 +Version: 2.12.0 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.11.0/google/auth/_exponential_backoff.py new/google-auth-2.12.0/google/auth/_exponential_backoff.py --- old/google-auth-2.11.0/google/auth/_exponential_backoff.py 1970-01-01 01:00:00.000000000 +0100 +++ new/google-auth-2.12.0/google/auth/_exponential_backoff.py 2022-09-27 22:38:30.000000000 +0200 @@ -0,0 +1,111 @@ +# Copyright 2022 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 random +import time + +import six + +# The default amount of retry attempts +_DEFAULT_RETRY_TOTAL_ATTEMPTS = 3 + +# The default initial backoff period (1.0 second). +_DEFAULT_INITIAL_INTERVAL_SECONDS = 1.0 + +# The default randomization factor (0.1 which results in a random period ranging +# between 10% below and 10% above the retry interval). +_DEFAULT_RANDOMIZATION_FACTOR = 0.1 + +# The default multiplier value (2 which is 100% increase per back off). +_DEFAULT_MULTIPLIER = 2.0 + +"""Exponential Backoff Utility + +This is a private module that implements the exponential back off algorithm. +It can be used as a utility for code that needs to retry on failure, for example +an HTTP request. +""" + + +class ExponentialBackoff(six.Iterator): + """An exponential backoff iterator. This can be used in a for loop to + perform requests with exponential backoff. + + Args: + total_attempts Optional[int]: + The maximum amount of retries that should happen. + The default value is 3 attempts. + initial_wait_seconds Optional[int]: + The amount of time to sleep in the first backoff. This parameter + should be in seconds. + The default value is 1 second. + randomization_factor Optional[float]: + The amount of jitter that should be in each backoff. For example, + a value of 0.1 will introduce a jitter range of 10% to the + current backoff period. + The default value is 0.1. + multiplier Optional[float]: + The backoff multipler. This adjusts how much each backoff will + increase. For example a value of 2.0 leads to a 200% backoff + on each attempt. If the initial_wait is 1.0 it would look like + this sequence [1.0, 2.0, 4.0, 8.0]. + The default value is 2.0. + """ + + def __init__( + self, + total_attempts=_DEFAULT_RETRY_TOTAL_ATTEMPTS, + initial_wait_seconds=_DEFAULT_INITIAL_INTERVAL_SECONDS, + randomization_factor=_DEFAULT_RANDOMIZATION_FACTOR, + multiplier=_DEFAULT_MULTIPLIER, + ): + self._total_attempts = total_attempts + self._initial_wait_seconds = initial_wait_seconds + + self._current_wait_in_seconds = self._initial_wait_seconds + + self._randomization_factor = randomization_factor + self._multiplier = multiplier + self._backoff_count = 0 + + def __iter__(self): + self._backoff_count = 0 + self._current_wait_in_seconds = self._initial_wait_seconds + return self + + def __next__(self): + if self._backoff_count >= self._total_attempts: + raise StopIteration + self._backoff_count += 1 + + jitter_variance = self._current_wait_in_seconds * self._randomization_factor + jitter = random.uniform( + self._current_wait_in_seconds - jitter_variance, + self._current_wait_in_seconds + jitter_variance, + ) + + time.sleep(jitter) + + self._current_wait_in_seconds *= self._multiplier + return self._backoff_count + + @property + def total_attempts(self): + """The total amount of backoff attempts that will be made.""" + return self._total_attempts + + @property + def backoff_count(self): + """The current amount of backoff attempts that have been made.""" + return self._backoff_count diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/google/auth/exceptions.py new/google-auth-2.12.0/google/auth/exceptions.py --- old/google-auth-2.11.0/google/auth/exceptions.py 2022-08-20 01:27:12.000000000 +0200 +++ new/google-auth-2.12.0/google/auth/exceptions.py 2022-09-27 22:38:30.000000000 +0200 @@ -18,6 +18,15 @@ class GoogleAuthError(Exception): """Base class for all google.auth errors.""" + def __init__(self, *args, **kwargs): + super(GoogleAuthError, self).__init__(*args) + retryable = kwargs.get("retryable", False) + self._retryable = retryable + + @property + def retryable(self): + return self._retryable + class TransportError(GoogleAuthError): """Used to indicate an error occurred during an HTTP request.""" @@ -44,6 +53,10 @@ class ClientCertError(GoogleAuthError): """Used to indicate that client certificate is missing or invalid.""" + @property + def retryable(self): + return False + class OAuthError(GoogleAuthError): """Used to indicate an error occurred during an OAuth related HTTP @@ -53,9 +66,9 @@ class ReauthFailError(RefreshError): """An exception for when reauth failed.""" - def __init__(self, message=None): + def __init__(self, message=None, **kwargs): super(ReauthFailError, self).__init__( - "Reauthentication failed. {0}".format(message) + "Reauthentication failed. {0}".format(message), **kwargs ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/google/auth/impersonated_credentials.py new/google-auth-2.12.0/google/auth/impersonated_credentials.py --- old/google-auth-2.11.0/google/auth/impersonated_credentials.py 2022-08-20 01:27:12.000000000 +0200 +++ new/google-auth-2.12.0/google/auth/impersonated_credentials.py 2022-09-27 22:38:30.000000000 +0200 @@ -288,9 +288,12 @@ authed_session = AuthorizedSession(self._source_credentials) - response = authed_session.post( - url=iam_sign_endpoint, headers=headers, json=body - ) + try: + response = authed_session.post( + url=iam_sign_endpoint, headers=headers, json=body + ) + finally: + authed_session.close() if response.status_code != http_client.OK: raise exceptions.TransportError( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/google/auth/transport/__init__.py new/google-auth-2.12.0/google/auth/transport/__init__.py --- old/google-auth-2.11.0/google/auth/transport/__init__.py 2022-08-20 01:27:12.000000000 +0200 +++ new/google-auth-2.12.0/google/auth/transport/__init__.py 2022-09-27 22:38:30.000000000 +0200 @@ -29,9 +29,21 @@ import six from six.moves import http_client +TOO_MANY_REQUESTS = 429 # Python 2.7 six is missing this status code. + +DEFAULT_RETRYABLE_STATUS_CODES = ( + http_client.INTERNAL_SERVER_ERROR, + http_client.SERVICE_UNAVAILABLE, + http_client.REQUEST_TIMEOUT, + TOO_MANY_REQUESTS, +) +"""Sequence[int]: HTTP status codes indicating a request can be retried. +""" + + DEFAULT_REFRESH_STATUS_CODES = (http_client.UNAUTHORIZED,) """Sequence[int]: Which HTTP status code indicate that credentials should be -refreshed and a request should be retried. +refreshed. """ DEFAULT_MAX_REFRESH_ATTEMPTS = 2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/google/auth/transport/_aiohttp_requests.py new/google-auth-2.12.0/google/auth/transport/_aiohttp_requests.py --- old/google-auth-2.11.0/google/auth/transport/_aiohttp_requests.py 2022-08-20 01:27:12.000000000 +0200 +++ new/google-auth-2.12.0/google/auth/transport/_aiohttp_requests.py 2022-09-27 22:38:30.000000000 +0200 @@ -233,6 +233,8 @@ refreshing credentials. If not passed, an instance of :class:`~google.auth.transport.aiohttp_requests.Request` is created. + kwargs: Additional arguments passed through to the underlying + ClientSession :meth:`aiohttp.ClientSession` object. """ def __init__( @@ -243,8 +245,9 @@ refresh_timeout=None, auth_request=None, auto_decompress=False, + **kwargs, ): - super(AuthorizedSession, self).__init__() + super(AuthorizedSession, self).__init__(**kwargs) self.credentials = credentials self._refresh_status_codes = refresh_status_codes self._max_refresh_attempts = max_refresh_attempts diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/google/auth/transport/_custom_tls_signer.py new/google-auth-2.12.0/google/auth/transport/_custom_tls_signer.py --- old/google-auth-2.11.0/google/auth/transport/_custom_tls_signer.py 2022-08-20 01:27:12.000000000 +0200 +++ new/google-auth-2.12.0/google/auth/transport/_custom_tls_signer.py 2022-09-27 22:38:30.000000000 +0200 @@ -192,8 +192,8 @@ { "libs": { - "signer_library": "...", - "offload_library": "..." + "ecp_client": "...", + "tls_offload": "..." } } """ @@ -206,8 +206,8 @@ with open(self._enterprise_cert_file_path, "r") as f: enterprise_cert_json = json.load(f) libs = enterprise_cert_json["libs"] - signer_library = libs["signer_library"] - offload_library = libs["offload_library"] + signer_library = libs["ecp_client"] + offload_library = libs["tls_offload"] except (KeyError, ValueError) as caught_exc: new_exc = exceptions.MutualTLSChannelError( "enterprise cert file is invalid", caught_exc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/google/auth/version.py new/google-auth-2.12.0/google/auth/version.py --- old/google-auth-2.11.0/google/auth/version.py 2022-08-20 01:27:12.000000000 +0200 +++ new/google-auth-2.12.0/google/auth/version.py 2022-09-27 22:38:30.000000000 +0200 @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "2.11.0" +__version__ = "2.12.0" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/google/oauth2/_client.py new/google-auth-2.12.0/google/oauth2/_client.py --- old/google-auth-2.11.0/google/oauth2/_client.py 2022-08-20 01:27:12.000000000 +0200 +++ new/google-auth-2.12.0/google/oauth2/_client.py 2022-09-27 22:38:30.000000000 +0200 @@ -30,9 +30,11 @@ from six.moves import http_client from six.moves import urllib +from google.auth import _exponential_backoff from google.auth import _helpers from google.auth import exceptions from google.auth import jwt +from google.auth import transport _URLENCODED_CONTENT_TYPE = "application/x-www-form-urlencoded" _JSON_CONTENT_TYPE = "application/json" @@ -40,17 +42,22 @@ _REFRESH_GRANT_TYPE = "refresh_token" -def _handle_error_response(response_data): +def _handle_error_response(response_data, retryable_error): """Translates an error response into an exception. Args: response_data (Mapping | str): The decoded response data. + retryable_error Optional[bool]: A boolean indicating if an error is retryable. + Defaults to False. Raises: google.auth.exceptions.RefreshError: The errors contained in response_data. """ + + retryable_error = retryable_error if retryable_error else False + if isinstance(response_data, six.string_types): - raise exceptions.RefreshError(response_data) + raise exceptions.RefreshError(response_data, retryable=retryable_error) try: error_details = "{}: {}".format( response_data["error"], response_data.get("error_description") @@ -59,7 +66,45 @@ except (KeyError, ValueError): error_details = json.dumps(response_data) - raise exceptions.RefreshError(error_details, response_data) + raise exceptions.RefreshError( + error_details, response_data, retryable=retryable_error + ) + + +def _can_retry(status_code, response_data): + """Checks if a request can be retried by inspecting the status code + and response body of the request. + + Args: + status_code (int): The response status code. + response_data (Mapping | str): The decoded response data. + + Returns: + bool: True if the response is retryable. False otherwise. + """ + if status_code in transport.DEFAULT_RETRYABLE_STATUS_CODES: + return True + + try: + # For a failed response, response_body could be a string + error_desc = response_data.get("error_description") or "" + error_code = response_data.get("error") or "" + + # Per Oauth 2.0 RFC https://www.rfc-editor.org/rfc/rfc6749.html#section-4.1.2.1 + # This is needed because a redirect will not return a 500 status code. + retryable_error_descriptions = { + "internal_failure", + "server_error", + "temporarily_unavailable", + } + + if any(e in retryable_error_descriptions for e in (error_code, error_desc)): + return True + + except AttributeError: + pass + + return False def _parse_expiry(response_data): @@ -81,7 +126,13 @@ def _token_endpoint_request_no_throw( - request, token_uri, body, access_token=None, use_json=False, **kwargs + request, + token_uri, + body, + access_token=None, + use_json=False, + can_retry=True, + **kwargs ): """Makes a request to the OAuth 2.0 authorization server's token endpoint. This function doesn't throw on response errors. @@ -95,6 +146,7 @@ access_token (Optional(str)): The access token needed to make the request. use_json (Optional(bool)): Use urlencoded format or json format for the content type. The default value is False. + can_retry (bool): Enable or disable request retry behavior. kwargs: Additional arguments passed on to the request method. The kwargs will be passed to `requests.request` method, see: https://docs.python-requests.org/en/latest/api/#requests.request. @@ -104,8 +156,10 @@ side SSL certificate verification. Returns: - Tuple(bool, Mapping[str, str]): A boolean indicating if the request is - successful, and a mapping for the JSON-decoded response data. + Tuple(bool, Mapping[str, str], Optional[bool]): A boolean indicating + if the request is successful, a mapping for the JSON-decoded response + data and in the case of an error a boolean indicating if the error + is retryable. """ if use_json: headers = {"Content-Type": _JSON_CONTENT_TYPE} @@ -117,10 +171,7 @@ if access_token: headers["Authorization"] = "Bearer {}".format(access_token) - retry = 0 - # retry to fetch token for maximum of two times if any internal failure - # occurs. - while True: + def _perform_request(): response = request( method="POST", url=token_uri, headers=headers, body=body, **kwargs ) @@ -129,32 +180,44 @@ if hasattr(response.data, "decode") else response.data ) - - if response.status == http_client.OK: + response_data = "" + try: # response_body should be a JSON response_data = json.loads(response_body) - break - else: - # For a failed response, response_body could be a string - try: - response_data = json.loads(response_body) - error_desc = response_data.get("error_description") or "" - error_code = response_data.get("error") or "" - if ( - any(e == "internal_failure" for e in (error_code, error_desc)) - and retry < 1 - ): - retry += 1 - continue - except ValueError: - response_data = response_body - return False, response_data + except ValueError: + response_data = response_body + + if response.status == http_client.OK: + return True, response_data, None + + retryable_error = _can_retry( + status_code=response.status, response_data=response_data + ) + + return False, response_data, retryable_error + + request_succeeded, response_data, retryable_error = _perform_request() + + if request_succeeded or not retryable_error or not can_retry: + return request_succeeded, response_data, retryable_error + + retries = _exponential_backoff.ExponentialBackoff() + for _ in retries: + request_succeeded, response_data, retryable_error = _perform_request() + if request_succeeded or not retryable_error: + return request_succeeded, response_data, retryable_error - return True, response_data + return False, response_data, retryable_error def _token_endpoint_request( - request, token_uri, body, access_token=None, use_json=False, **kwargs + request, + token_uri, + body, + access_token=None, + use_json=False, + can_retry=True, + **kwargs ): """Makes a request to the OAuth 2.0 authorization server's token endpoint. @@ -167,6 +230,7 @@ access_token (Optional(str)): The access token needed to make the request. use_json (Optional(bool)): Use urlencoded format or json format for the content type. The default value is False. + can_retry (bool): Enable or disable request retry behavior. kwargs: Additional arguments passed on to the request method. The kwargs will be passed to `requests.request` method, see: https://docs.python-requests.org/en/latest/api/#requests.request. @@ -182,15 +246,22 @@ google.auth.exceptions.RefreshError: If the token endpoint returned an error. """ - response_status_ok, response_data = _token_endpoint_request_no_throw( - request, token_uri, body, access_token=access_token, use_json=use_json, **kwargs + + response_status_ok, response_data, retryable_error = _token_endpoint_request_no_throw( + request, + token_uri, + body, + access_token=access_token, + use_json=use_json, + can_retry=can_retry, + **kwargs ) if not response_status_ok: - _handle_error_response(response_data) + _handle_error_response(response_data, retryable_error) return response_data -def jwt_grant(request, token_uri, assertion): +def jwt_grant(request, token_uri, assertion, can_retry=True): """Implements the JWT Profile for OAuth 2.0 Authorization Grants. For more details, see `rfc7523 section 4`_. @@ -201,6 +272,7 @@ token_uri (str): The OAuth 2.0 authorizations server's token endpoint URI. assertion (str): The OAuth 2.0 assertion. + can_retry (bool): Enable or disable request retry behavior. Returns: Tuple[str, Optional[datetime], Mapping[str, str]]: The access token, @@ -214,12 +286,16 @@ """ body = {"assertion": assertion, "grant_type": _JWT_GRANT_TYPE} - response_data = _token_endpoint_request(request, token_uri, body) + response_data = _token_endpoint_request( + request, token_uri, body, can_retry=can_retry + ) try: access_token = response_data["access_token"] except KeyError as caught_exc: - new_exc = exceptions.RefreshError("No access token in response.", response_data) + new_exc = exceptions.RefreshError( + "No access token in response.", response_data, retryable=False + ) six.raise_from(new_exc, caught_exc) expiry = _parse_expiry(response_data) @@ -227,7 +303,7 @@ return access_token, expiry, response_data -def id_token_jwt_grant(request, token_uri, assertion): +def id_token_jwt_grant(request, token_uri, assertion, can_retry=True): """Implements the JWT Profile for OAuth 2.0 Authorization Grants, but requests an OpenID Connect ID Token instead of an access token. @@ -242,6 +318,7 @@ URI. assertion (str): JWT token signed by a service account. The token's payload must include a ``target_audience`` claim. + can_retry (bool): Enable or disable request retry behavior. Returns: Tuple[str, Optional[datetime], Mapping[str, str]]: @@ -254,12 +331,16 @@ """ body = {"assertion": assertion, "grant_type": _JWT_GRANT_TYPE} - response_data = _token_endpoint_request(request, token_uri, body) + response_data = _token_endpoint_request( + request, token_uri, body, can_retry=can_retry + ) try: id_token = response_data["id_token"] except KeyError as caught_exc: - new_exc = exceptions.RefreshError("No ID token in response.", response_data) + new_exc = exceptions.RefreshError( + "No ID token in response.", response_data, retryable=False + ) six.raise_from(new_exc, caught_exc) payload = jwt.decode(id_token, verify=False) @@ -288,7 +369,9 @@ try: access_token = response_data["access_token"] except KeyError as caught_exc: - new_exc = exceptions.RefreshError("No access token in response.", response_data) + new_exc = exceptions.RefreshError( + "No access token in response.", response_data, retryable=False + ) six.raise_from(new_exc, caught_exc) refresh_token = response_data.get("refresh_token", refresh_token) @@ -305,6 +388,7 @@ client_secret, scopes=None, rapt_token=None, + can_retry=True, ): """Implements the OAuth 2.0 refresh token grant. @@ -324,6 +408,7 @@ token has a wild card scope (e.g. 'https://www.googleapis.com/auth/any-api'). rapt_token (Optional(str)): The reauth Proof Token. + can_retry (bool): Enable or disable request retry behavior. Returns: Tuple[str, str, Optional[datetime], Mapping[str, str]]: The access @@ -347,5 +432,7 @@ if rapt_token: body["rapt"] = rapt_token - response_data = _token_endpoint_request(request, token_uri, body) + response_data = _token_endpoint_request( + request, token_uri, body, can_retry=can_retry + ) return _handle_refresh_grant_response(response_data, refresh_token) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/google/oauth2/_client_async.py new/google-auth-2.12.0/google/oauth2/_client_async.py --- old/google-auth-2.11.0/google/oauth2/_client_async.py 2022-08-20 01:27:12.000000000 +0200 +++ new/google-auth-2.12.0/google/oauth2/_client_async.py 2022-09-27 22:38:30.000000000 +0200 @@ -30,13 +30,14 @@ from six.moves import http_client from six.moves import urllib +from google.auth import _exponential_backoff from google.auth import exceptions from google.auth import jwt from google.oauth2 import _client as client async def _token_endpoint_request_no_throw( - request, token_uri, body, access_token=None, use_json=False + request, token_uri, body, access_token=None, use_json=False, can_retry=True ): """Makes a request to the OAuth 2.0 authorization server's token endpoint. This function doesn't throw on response errors. @@ -50,10 +51,13 @@ access_token (Optional(str)): The access token needed to make the request. use_json (Optional(bool)): Use urlencoded format or json format for the content type. The default value is False. + can_retry (bool): Enable or disable request retry behavior. Returns: - Tuple(bool, Mapping[str, str]): A boolean indicating if the request is - successful, and a mapping for the JSON-decoded response data. + Tuple(bool, Mapping[str, str], Optional[bool]): A boolean indicating + if the request is successful, a mapping for the JSON-decoded response + data and in the case of an error a boolean indicating if the error + is retryable. """ if use_json: headers = {"Content-Type": client._JSON_CONTENT_TYPE} @@ -65,11 +69,7 @@ if access_token: headers["Authorization"] = "Bearer {}".format(access_token) - retry = 0 - # retry to fetch token for maximum of two times if any internal failure - # occurs. - while True: - + async def _perform_request(): response = await request( method="POST", url=token_uri, headers=headers, body=body ) @@ -83,26 +83,36 @@ else response_body1 ) - response_data = json.loads(response_body) + try: + response_data = json.loads(response_body) + except ValueError: + response_data = response_body if response.status == http_client.OK: - break - else: - error_desc = response_data.get("error_description") or "" - error_code = response_data.get("error") or "" - if ( - any(e == "internal_failure" for e in (error_code, error_desc)) - and retry < 1 - ): - retry += 1 - continue - return response.status == http_client.OK, response_data + return True, response_data, None + + retryable_error = client._can_retry( + status_code=response.status, response_data=response_data + ) + + return False, response_data, retryable_error + + request_succeeded, response_data, retryable_error = await _perform_request() + + if request_succeeded or not retryable_error or not can_retry: + return request_succeeded, response_data, retryable_error + + retries = _exponential_backoff.ExponentialBackoff() + for _ in retries: + request_succeeded, response_data, retryable_error = await _perform_request() + if request_succeeded or not retryable_error: + return request_succeeded, response_data, retryable_error - return response.status == http_client.OK, response_data + return False, response_data, retryable_error async def _token_endpoint_request( - request, token_uri, body, access_token=None, use_json=False + request, token_uri, body, access_token=None, use_json=False, can_retry=True ): """Makes a request to the OAuth 2.0 authorization server's token endpoint. @@ -115,6 +125,7 @@ access_token (Optional(str)): The access token needed to make the request. use_json (Optional(bool)): Use urlencoded format or json format for the content type. The default value is False. + can_retry (bool): Enable or disable request retry behavior. Returns: Mapping[str, str]: The JSON-decoded response data. @@ -123,15 +134,21 @@ google.auth.exceptions.RefreshError: If the token endpoint returned an error. """ - response_status_ok, response_data = await _token_endpoint_request_no_throw( - request, token_uri, body, access_token=access_token, use_json=use_json + + response_status_ok, response_data, retryable_error = await _token_endpoint_request_no_throw( + request, + token_uri, + body, + access_token=access_token, + use_json=use_json, + can_retry=can_retry, ) if not response_status_ok: - client._handle_error_response(response_data) + client._handle_error_response(response_data, retryable_error) return response_data -async def jwt_grant(request, token_uri, assertion): +async def jwt_grant(request, token_uri, assertion, can_retry=True): """Implements the JWT Profile for OAuth 2.0 Authorization Grants. For more details, see `rfc7523 section 4`_. @@ -142,6 +159,7 @@ token_uri (str): The OAuth 2.0 authorizations server's token endpoint URI. assertion (str): The OAuth 2.0 assertion. + can_retry (bool): Enable or disable request retry behavior. Returns: Tuple[str, Optional[datetime], Mapping[str, str]]: The access token, @@ -155,12 +173,16 @@ """ body = {"assertion": assertion, "grant_type": client._JWT_GRANT_TYPE} - response_data = await _token_endpoint_request(request, token_uri, body) + response_data = await _token_endpoint_request( + request, token_uri, body, can_retry=can_retry + ) try: access_token = response_data["access_token"] except KeyError as caught_exc: - new_exc = exceptions.RefreshError("No access token in response.", response_data) + new_exc = exceptions.RefreshError( + "No access token in response.", response_data, retryable=False + ) six.raise_from(new_exc, caught_exc) expiry = client._parse_expiry(response_data) @@ -168,7 +190,7 @@ return access_token, expiry, response_data -async def id_token_jwt_grant(request, token_uri, assertion): +async def id_token_jwt_grant(request, token_uri, assertion, can_retry=True): """Implements the JWT Profile for OAuth 2.0 Authorization Grants, but requests an OpenID Connect ID Token instead of an access token. @@ -183,6 +205,7 @@ URI. assertion (str): JWT token signed by a service account. The token's payload must include a ``target_audience`` claim. + can_retry (bool): Enable or disable request retry behavior. Returns: Tuple[str, Optional[datetime], Mapping[str, str]]: @@ -195,12 +218,16 @@ """ body = {"assertion": assertion, "grant_type": client._JWT_GRANT_TYPE} - response_data = await _token_endpoint_request(request, token_uri, body) + response_data = await _token_endpoint_request( + request, token_uri, body, can_retry=can_retry + ) try: id_token = response_data["id_token"] except KeyError as caught_exc: - new_exc = exceptions.RefreshError("No ID token in response.", response_data) + new_exc = exceptions.RefreshError( + "No ID token in response.", response_data, retryable=False + ) six.raise_from(new_exc, caught_exc) payload = jwt.decode(id_token, verify=False) @@ -217,6 +244,7 @@ client_secret, scopes=None, rapt_token=None, + can_retry=True, ): """Implements the OAuth 2.0 refresh token grant. @@ -236,6 +264,7 @@ token has a wild card scope (e.g. 'https://www.googleapis.com/auth/any-api'). rapt_token (Optional(str)): The reauth Proof Token. + can_retry (bool): Enable or disable request retry behavior. Returns: Tuple[str, Optional[str], Optional[datetime], Mapping[str, str]]: The @@ -259,5 +288,7 @@ if rapt_token: body["rapt"] = rapt_token - response_data = await _token_endpoint_request(request, token_uri, body) + response_data = await _token_endpoint_request( + request, token_uri, body, can_retry=can_retry + ) return client._handle_refresh_grant_response(response_data, refresh_token) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/google/oauth2/_reauth_async.py new/google-auth-2.12.0/google/oauth2/_reauth_async.py --- old/google-auth-2.11.0/google/oauth2/_reauth_async.py 2022-08-20 01:27:12.000000000 +0200 +++ new/google-auth-2.12.0/google/oauth2/_reauth_async.py 2022-09-27 22:38:30.000000000 +0200 @@ -292,7 +292,7 @@ if rapt_token: body["rapt"] = rapt_token - response_status_ok, response_data = await _client_async._token_endpoint_request_no_throw( + response_status_ok, response_data, retryable_error = await _client_async._token_endpoint_request_no_throw( request, token_uri, body ) if ( @@ -307,7 +307,7 @@ ): if not enable_reauth_refresh: raise exceptions.RefreshError( - "Reauthentication is needed. Please run `gcloud auth login --update-adc` to reauthenticate." + "Reauthentication is needed. Please run `gcloud auth application-default login` to reauthenticate." ) rapt_token = await get_rapt_token( @@ -317,12 +317,13 @@ ( response_status_ok, response_data, + retryable_error, ) = await _client_async._token_endpoint_request_no_throw( request, token_uri, body ) if not response_status_ok: - _client._handle_error_response(response_data) + _client._handle_error_response(response_data, retryable_error) refresh_response = _client._handle_refresh_grant_response( response_data, refresh_token ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/google/oauth2/reauth.py new/google-auth-2.12.0/google/oauth2/reauth.py --- old/google-auth-2.11.0/google/oauth2/reauth.py 2022-08-20 01:27:12.000000000 +0200 +++ new/google-auth-2.12.0/google/oauth2/reauth.py 2022-09-27 22:38:30.000000000 +0200 @@ -319,7 +319,7 @@ if rapt_token: body["rapt"] = rapt_token - response_status_ok, response_data = _client._token_endpoint_request_no_throw( + response_status_ok, response_data, retryable_error = _client._token_endpoint_request_no_throw( request, token_uri, body ) if ( @@ -332,19 +332,21 @@ ): if not enable_reauth_refresh: raise exceptions.RefreshError( - "Reauthentication is needed. Please run `gcloud auth login --update-adc` to reauthenticate." + "Reauthentication is needed. Please run `gcloud auth application-default login` to reauthenticate." ) rapt_token = get_rapt_token( request, client_id, client_secret, refresh_token, token_uri, scopes=scopes ) body["rapt"] = rapt_token - (response_status_ok, response_data) = _client._token_endpoint_request_no_throw( - request, token_uri, body - ) + ( + response_status_ok, + response_data, + retryable_error, + ) = _client._token_endpoint_request_no_throw(request, token_uri, body) if not response_status_ok: - _client._handle_error_response(response_data) + _client._handle_error_response(response_data, retryable_error) return _client._handle_refresh_grant_response(response_data, refresh_token) + ( rapt_token, ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/google_auth.egg-info/PKG-INFO new/google-auth-2.12.0/google_auth.egg-info/PKG-INFO --- old/google-auth-2.11.0/google_auth.egg-info/PKG-INFO 2022-08-20 01:29:58.000000000 +0200 +++ new/google-auth-2.12.0/google_auth.egg-info/PKG-INFO 2022-09-27 22:42:05.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: google-auth -Version: 2.11.0 +Version: 2.12.0 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.11.0/google_auth.egg-info/SOURCES.txt new/google-auth-2.12.0/google_auth.egg-info/SOURCES.txt --- old/google-auth-2.11.0/google_auth.egg-info/SOURCES.txt 2022-08-20 01:29:58.000000000 +0200 +++ new/google-auth-2.12.0/google_auth.egg-info/SOURCES.txt 2022-09-27 22:42:05.000000000 +0200 @@ -9,6 +9,7 @@ google/auth/_credentials_async.py google/auth/_default.py google/auth/_default_async.py +google/auth/_exponential_backoff.py google/auth/_helpers.py google/auth/_jwt_async.py google/auth/_oauth2client.py @@ -70,6 +71,7 @@ tests/conftest.py tests/test__cloud_sdk.py tests/test__default.py +tests/test__exponential_backoff.py tests/test__helpers.py tests/test__oauth2client.py tests/test__service_account_info.py @@ -77,6 +79,7 @@ tests/test_aws.py tests/test_credentials.py tests/test_downscoped.py +tests/test_exceptions.py tests/test_external_account.py tests/test_iam.py tests/test_identity_pool.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/tests/compute_engine/test_credentials.py new/google-auth-2.12.0/tests/compute_engine/test_credentials.py --- old/google-auth-2.11.0/tests/compute_engine/test_credentials.py 2022-08-20 01:27:12.000000000 +0200 +++ new/google-auth-2.12.0/tests/compute_engine/test_credentials.py 2022-09-27 22:38:30.000000000 +0200 @@ -609,7 +609,7 @@ request = mock.create_autospec(transport.Request, instance=True) response = mock.Mock() response.data = b'{"error": "http error"}' - response.status = 500 + response.status = 404 # Throw a 404 so the request is not retried. request.side_effect = [response] self.credentials = credentials.IDTokenCredentials( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/tests/data/enterprise_cert_valid.json new/google-auth-2.12.0/tests/data/enterprise_cert_valid.json --- old/google-auth-2.11.0/tests/data/enterprise_cert_valid.json 2022-08-20 01:27:12.000000000 +0200 +++ new/google-auth-2.12.0/tests/data/enterprise_cert_valid.json 2022-09-27 22:38:30.000000000 +0200 @@ -1,6 +1,6 @@ { "libs": { - "signer_library": "/path/to/signer/lib", - "offload_library": "/path/to/offload/lib" + "ecp_client": "/path/to/signer/lib", + "tls_offload": "/path/to/offload/lib" } -} \ No newline at end of file +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/tests/oauth2/test__client.py new/google-auth-2.12.0/tests/oauth2/test__client.py --- old/google-auth-2.11.0/tests/oauth2/test__client.py 2022-08-20 01:27:12.000000000 +0200 +++ new/google-auth-2.12.0/tests/oauth2/test__client.py 2022-09-27 22:38:30.000000000 +0200 @@ -47,12 +47,14 @@ ) -def test__handle_error_response(): [email protected]("retryable", [True, False]) +def test__handle_error_response(retryable): response_data = {"error": "help", "error_description": "I'm alive"} with pytest.raises(exceptions.RefreshError) as excinfo: - _client._handle_error_response(response_data) + _client._handle_error_response(response_data, retryable) + assert excinfo.value.retryable == retryable assert excinfo.match(r"help: I\'m alive") @@ -60,8 +62,9 @@ response_data = {"foo": "bar"} with pytest.raises(exceptions.RefreshError) as excinfo: - _client._handle_error_response(response_data) + _client._handle_error_response(response_data, False) + assert not excinfo.value.retryable assert excinfo.match(r"{\"foo\": \"bar\"}") @@ -69,11 +72,33 @@ response_data = "this is an error message" with pytest.raises(exceptions.RefreshError) as excinfo: - _client._handle_error_response(response_data) + _client._handle_error_response(response_data, False) + assert not excinfo.value.retryable assert excinfo.match(response_data) +def test__can_retry_retryable(): + retryable_codes = transport.DEFAULT_RETRYABLE_STATUS_CODES + for status_code in range(100, 600): + if status_code in retryable_codes: + assert _client._can_retry(status_code, {"error": "invalid_scope"}) + else: + assert not _client._can_retry(status_code, {"error": "invalid_scope"}) + + [email protected]( + "response_data", [{"error": "internal_failure"}, {"error": "server_error"}] +) +def test__can_retry_message(response_data): + assert _client._can_retry(http_client.OK, response_data) + + [email protected]("response_data", [{"error": "invalid_scope"}]) +def test__can_retry_no_retry_message(response_data): + assert not _client._can_retry(http_client.OK, response_data) + + @mock.patch("google.auth._helpers.utcnow", return_value=datetime.datetime.min) def test__parse_expiry(unused_utcnow): result = _client._parse_expiry({"expires_in": 500}) @@ -154,8 +179,8 @@ _client._token_endpoint_request( request, "http://example.com", {"error_description": "internal_failure"} ) - # request should be called twice due to the retry - assert request.call_count == 2 + # request should be called once and then with 3 retries + assert request.call_count == 4 request = make_request( {"error": "internal_failure"}, status=http_client.BAD_REQUEST @@ -165,7 +190,55 @@ _client._token_endpoint_request( request, "http://example.com", {"error": "internal_failure"} ) - # request should be called twice due to the retry + # request should be called once and then with 3 retries + assert request.call_count == 4 + + +def test__token_endpoint_request_internal_failure_and_retry_failure_error(): + retryable_error = mock.create_autospec(transport.Response, instance=True) + retryable_error.status = http_client.BAD_REQUEST + retryable_error.data = json.dumps({"error_description": "internal_failure"}).encode( + "utf-8" + ) + + unretryable_error = mock.create_autospec(transport.Response, instance=True) + unretryable_error.status = http_client.BAD_REQUEST + unretryable_error.data = json.dumps({"error_description": "invalid_scope"}).encode( + "utf-8" + ) + + request = mock.create_autospec(transport.Request) + + request.side_effect = [retryable_error, retryable_error, unretryable_error] + + with pytest.raises(exceptions.RefreshError): + _client._token_endpoint_request( + request, "http://example.com", {"error_description": "invalid_scope"} + ) + # request should be called three times. Two retryable errors and one + # unretryable error to break the retry loop. + assert request.call_count == 3 + + +def test__token_endpoint_request_internal_failure_and_retry_succeeds(): + retryable_error = mock.create_autospec(transport.Response, instance=True) + retryable_error.status = http_client.BAD_REQUEST + retryable_error.data = json.dumps({"error_description": "internal_failure"}).encode( + "utf-8" + ) + + response = mock.create_autospec(transport.Response, instance=True) + response.status = http_client.OK + response.data = json.dumps({"hello": "world"}).encode("utf-8") + + request = mock.create_autospec(transport.Request) + + request.side_effect = [retryable_error, response] + + _ = _client._token_endpoint_request( + request, "http://example.com", {"test": "params"} + ) + assert request.call_count == 2 @@ -219,8 +292,9 @@ } ) - with pytest.raises(exceptions.RefreshError): + with pytest.raises(exceptions.RefreshError) as excinfo: _client.jwt_grant(request, "http://example.com", "assertion_value") + assert not excinfo.value.retryable def test_id_token_jwt_grant(): @@ -255,8 +329,9 @@ } ) - with pytest.raises(exceptions.RefreshError): + with pytest.raises(exceptions.RefreshError) as excinfo: _client.id_token_jwt_grant(request, "http://example.com", "assertion_value") + assert not excinfo.value.retryable @mock.patch("google.auth._helpers.utcnow", return_value=datetime.datetime.min) @@ -348,7 +423,104 @@ } ) - with pytest.raises(exceptions.RefreshError): + with pytest.raises(exceptions.RefreshError) as excinfo: _client.refresh_grant( request, "http://example.com", "refresh_token", "client_id", "client_secret" ) + assert not excinfo.value.retryable + + [email protected]("google.oauth2._client._parse_expiry", return_value=None) [email protected](_client, "_token_endpoint_request", autospec=True) +def test_jwt_grant_retry_default(mock_token_endpoint_request, mock_expiry): + _client.jwt_grant(mock.Mock(), mock.Mock(), mock.Mock()) + mock_token_endpoint_request.assert_called_with( + mock.ANY, mock.ANY, mock.ANY, can_retry=True + ) + + [email protected]("can_retry", [True, False]) [email protected]("google.oauth2._client._parse_expiry", return_value=None) [email protected](_client, "_token_endpoint_request", autospec=True) +def test_jwt_grant_retry_with_retry( + mock_token_endpoint_request, mock_expiry, can_retry +): + _client.jwt_grant(mock.Mock(), mock.Mock(), mock.Mock(), can_retry=can_retry) + mock_token_endpoint_request.assert_called_with( + mock.ANY, mock.ANY, mock.ANY, can_retry=can_retry + ) + + [email protected]("google.auth.jwt.decode", return_value={"exp": 0}) [email protected](_client, "_token_endpoint_request", autospec=True) +def test_id_token_jwt_grant_retry_default(mock_token_endpoint_request, mock_jwt_decode): + _client.id_token_jwt_grant(mock.Mock(), mock.Mock(), mock.Mock()) + mock_token_endpoint_request.assert_called_with( + mock.ANY, mock.ANY, mock.ANY, can_retry=True + ) + + [email protected]("can_retry", [True, False]) [email protected]("google.auth.jwt.decode", return_value={"exp": 0}) [email protected](_client, "_token_endpoint_request", autospec=True) +def test_id_token_jwt_grant_retry_with_retry( + mock_token_endpoint_request, mock_jwt_decode, can_retry +): + _client.id_token_jwt_grant( + mock.Mock(), mock.Mock(), mock.Mock(), can_retry=can_retry + ) + mock_token_endpoint_request.assert_called_with( + mock.ANY, mock.ANY, mock.ANY, can_retry=can_retry + ) + + [email protected]("google.oauth2._client._parse_expiry", return_value=None) [email protected](_client, "_token_endpoint_request", autospec=True) +def test_refresh_grant_retry_default(mock_token_endpoint_request, mock_parse_expiry): + _client.refresh_grant( + mock.Mock(), mock.Mock(), mock.Mock(), mock.Mock(), mock.Mock() + ) + mock_token_endpoint_request.assert_called_with( + mock.ANY, mock.ANY, mock.ANY, can_retry=True + ) + + [email protected]("can_retry", [True, False]) [email protected]("google.oauth2._client._parse_expiry", return_value=None) [email protected](_client, "_token_endpoint_request", autospec=True) +def test_refresh_grant_retry_with_retry( + mock_token_endpoint_request, mock_parse_expiry, can_retry +): + _client.refresh_grant( + mock.Mock(), + mock.Mock(), + mock.Mock(), + mock.Mock(), + mock.Mock(), + can_retry=can_retry, + ) + mock_token_endpoint_request.assert_called_with( + mock.ANY, mock.ANY, mock.ANY, can_retry=can_retry + ) + + [email protected]("can_retry", [True, False]) +def test__token_endpoint_request_no_throw_with_retry(can_retry): + response_data = {"error": "help", "error_description": "I'm alive"} + body = "dummy body" + + mock_response = mock.create_autospec(transport.Response, instance=True) + mock_response.status = http_client.INTERNAL_SERVER_ERROR + mock_response.data = json.dumps(response_data).encode("utf-8") + + mock_request = mock.create_autospec(transport.Request) + mock_request.return_value = mock_response + + _client._token_endpoint_request_no_throw( + mock_request, mock.Mock(), body, mock.Mock(), mock.Mock(), can_retry=can_retry + ) + + if can_retry: + assert mock_request.call_count == 4 + else: + assert mock_request.call_count == 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/tests/oauth2/test_reauth.py new/google-auth-2.12.0/tests/oauth2/test_reauth.py --- old/google-auth-2.11.0/tests/oauth2/test_reauth.py 2022-08-20 01:27:12.000000000 +0200 +++ new/google-auth-2.12.0/tests/oauth2/test_reauth.py 2022-09-27 22:38:30.000000000 +0200 @@ -260,7 +260,7 @@ with mock.patch( "google.oauth2._client._token_endpoint_request_no_throw" ) as mock_token_request: - mock_token_request.return_value = (False, {"error": "Bad request"}) + mock_token_request.return_value = (False, {"error": "Bad request"}, False) with pytest.raises(exceptions.RefreshError) as excinfo: reauth.refresh_grant( MOCK_REQUEST, @@ -273,6 +273,7 @@ enable_reauth_refresh=True, ) assert excinfo.match(r"Bad request") + assert not excinfo.value.retryable mock_token_request.assert_called_with( MOCK_REQUEST, "token_uri", @@ -292,8 +293,8 @@ "google.oauth2._client._token_endpoint_request_no_throw" ) as mock_token_request: mock_token_request.side_effect = [ - (False, {"error": "invalid_grant", "error_subtype": "rapt_required"}), - (True, {"access_token": "access_token"}), + (False, {"error": "invalid_grant", "error_subtype": "rapt_required"}, True), + (True, {"access_token": "access_token"}, None), ] with mock.patch( "google.oauth2.reauth.get_rapt_token", return_value="new_rapt_token" @@ -319,8 +320,8 @@ "google.oauth2._client._token_endpoint_request_no_throw" ) as mock_token_request: mock_token_request.side_effect = [ - (False, {"error": "invalid_grant", "error_subtype": "rapt_required"}), - (True, {"access_token": "access_token"}), + (False, {"error": "invalid_grant", "error_subtype": "rapt_required"}, True), + (True, {"access_token": "access_token"}, None), ] with pytest.raises(exceptions.RefreshError) as excinfo: reauth.refresh_grant( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/tests/test__exponential_backoff.py new/google-auth-2.12.0/tests/test__exponential_backoff.py --- old/google-auth-2.11.0/tests/test__exponential_backoff.py 1970-01-01 01:00:00.000000000 +0100 +++ new/google-auth-2.12.0/tests/test__exponential_backoff.py 2022-09-27 22:38:30.000000000 +0200 @@ -0,0 +1,41 @@ +# Copyright 2022 Google Inc. +# +# 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 mock + +from google.auth import _exponential_backoff + + [email protected]("time.sleep", return_value=None) +def test_exponential_backoff(mock_time): + eb = _exponential_backoff.ExponentialBackoff() + curr_wait = eb._current_wait_in_seconds + iteration_count = 0 + + for attempt in eb: + backoff_interval = mock_time.call_args[0][0] + jitter = curr_wait * eb._randomization_factor + + assert (curr_wait - jitter) <= backoff_interval <= (curr_wait + jitter) + assert attempt == iteration_count + 1 + assert eb.backoff_count == iteration_count + 1 + assert eb._current_wait_in_seconds == eb._multiplier ** (iteration_count + 1) + + curr_wait = eb._current_wait_in_seconds + iteration_count += 1 + + assert eb.total_attempts == _exponential_backoff._DEFAULT_RETRY_TOTAL_ATTEMPTS + assert eb.backoff_count == _exponential_backoff._DEFAULT_RETRY_TOTAL_ATTEMPTS + assert iteration_count == _exponential_backoff._DEFAULT_RETRY_TOTAL_ATTEMPTS + assert mock_time.call_count == _exponential_backoff._DEFAULT_RETRY_TOTAL_ATTEMPTS diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/tests/test__oauth2client.py new/google-auth-2.12.0/tests/test__oauth2client.py --- old/google-auth-2.11.0/tests/test__oauth2client.py 2022-08-20 01:27:12.000000000 +0200 +++ new/google-auth-2.12.0/tests/test__oauth2client.py 2022-09-27 22:38:30.000000000 +0200 @@ -17,12 +17,19 @@ import sys import mock -import oauth2client.client # type: ignore -import oauth2client.contrib.gce # type: ignore -import oauth2client.service_account # type: ignore import pytest # type: ignore from six.moves import reload_module +try: + import oauth2client.client # type: ignore + import oauth2client.contrib.gce # type: ignore + import oauth2client.service_account # type: ignore +except ImportError: # pragma: NO COVER + pytest.skip( + "Skipping oauth2client tests since oauth2client is not installed.", + allow_module_level=True, + ) + from google.auth import _oauth2client diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/tests/test_exceptions.py new/google-auth-2.12.0/tests/test_exceptions.py --- old/google-auth-2.11.0/tests/test_exceptions.py 1970-01-01 01:00:00.000000000 +0100 +++ new/google-auth-2.12.0/tests/test_exceptions.py 2022-09-27 22:38:30.000000000 +0200 @@ -0,0 +1,55 @@ +# Copyright 2022 Google Inc. +# +# 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 pytest # type: ignore + +from google.auth import exceptions # type:ignore + + [email protected]( + params=[ + exceptions.GoogleAuthError, + exceptions.TransportError, + exceptions.RefreshError, + exceptions.UserAccessTokenError, + exceptions.DefaultCredentialsError, + exceptions.MutualTLSChannelError, + exceptions.OAuthError, + exceptions.ReauthFailError, + exceptions.ReauthSamlChallengeFailError, + ] +) +def retryable_exception(request): + return request.param + + [email protected](params=[exceptions.ClientCertError]) +def non_retryable_exception(request): + return request.param + + +def test_default_retryable_exceptions(retryable_exception): + assert not retryable_exception().retryable + + [email protected]("retryable", [True, False]) +def test_retryable_exceptions(retryable_exception, retryable): + retryable_exception = retryable_exception(retryable=retryable) + assert retryable_exception.retryable == retryable + + [email protected]("retryable", [True, False]) +def test_non_retryable_exceptions(non_retryable_exception, retryable): + non_retryable_exception = non_retryable_exception(retryable=retryable) + assert not non_retryable_exception.retryable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.11.0/tests/test_pluggable.py new/google-auth-2.12.0/tests/test_pluggable.py --- old/google-auth-2.11.0/tests/test_pluggable.py 2022-08-20 01:27:12.000000000 +0200 +++ new/google-auth-2.12.0/tests/test_pluggable.py 2022-09-27 22:38:30.000000000 +0200 @@ -427,8 +427,10 @@ assert excinfo.match(r"The token returned by the executable is expired.") @mock.patch.dict(os.environ, {"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"}) - def test_retrieve_subject_token_file_cache(self): - ACTUAL_CREDENTIAL_SOURCE_EXECUTABLE_OUTPUT_FILE = "actual_output_file" + def test_retrieve_subject_token_file_cache(self, tmpdir): + ACTUAL_CREDENTIAL_SOURCE_EXECUTABLE_OUTPUT_FILE = tmpdir.join( + "actual_output_file" + ) ACTUAL_CREDENTIAL_SOURCE_EXECUTABLE = { "command": "command", "timeout_millis": 30000, @@ -472,8 +474,10 @@ assert subject_token == self.EXECUTABLE_OIDC_TOKEN @mock.patch.dict(os.environ, {"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"}) - def test_retrieve_subject_token_file_cache_value_error_report(self): - ACTUAL_CREDENTIAL_SOURCE_EXECUTABLE_OUTPUT_FILE = "actual_output_file" + def test_retrieve_subject_token_file_cache_value_error_report(self, tmpdir): + ACTUAL_CREDENTIAL_SOURCE_EXECUTABLE_OUTPUT_FILE = tmpdir.join( + "actual_output_file" + ) ACTUAL_CREDENTIAL_SOURCE_EXECUTABLE = { "command": "command", "timeout_millis": 30000, @@ -499,8 +503,10 @@ os.remove(ACTUAL_CREDENTIAL_SOURCE_EXECUTABLE_OUTPUT_FILE) @mock.patch.dict(os.environ, {"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"}) - def test_retrieve_subject_token_file_cache_refresh_error_retry(self): - ACTUAL_CREDENTIAL_SOURCE_EXECUTABLE_OUTPUT_FILE = "actual_output_file" + def test_retrieve_subject_token_file_cache_refresh_error_retry(self, tmpdir): + ACTUAL_CREDENTIAL_SOURCE_EXECUTABLE_OUTPUT_FILE = tmpdir.join( + "actual_output_file" + ) ACTUAL_CREDENTIAL_SOURCE_EXECUTABLE = { "command": "command", "timeout_millis": 30000, @@ -637,7 +643,7 @@ @mock.patch.dict(os.environ, {"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"}) def test_retrieve_subject_token_without_expiration_time_should_fail_when_output_file_specified( - self + self, ): EXECUTABLE_SUCCESSFUL_OIDC_RESPONSE = { "version": 1, @@ -665,9 +671,11 @@ @mock.patch.dict(os.environ, {"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"}) def test_retrieve_subject_token_without_expiration_time_should_fail_when_retrieving_from_output_file( - self + self, tmpdir ): - ACTUAL_CREDENTIAL_SOURCE_EXECUTABLE_OUTPUT_FILE = "actual_output_file" + ACTUAL_CREDENTIAL_SOURCE_EXECUTABLE_OUTPUT_FILE = tmpdir.join( + "actual_output_file" + ) ACTUAL_CREDENTIAL_SOURCE_EXECUTABLE = { "command": "command", "timeout_millis": 30000, @@ -692,7 +700,7 @@ @mock.patch.dict(os.environ, {"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"}) def test_retrieve_subject_token_without_expiration_time_should_pass_when_output_file_not_specified( - self + self, ): EXECUTABLE_SUCCESSFUL_OIDC_RESPONSE = { "version": 1, ++++++ python-google-auth-no-mock.patch ++++++ --- /var/tmp/diff_new_pack.eu8sbx/_old 2022-10-15 16:36:14.777978786 +0200 +++ /var/tmp/diff_new_pack.eu8sbx/_new 2022-10-15 16:36:14.781978796 +0200 @@ -1,6 +1,6 @@ -diff -Nru google-auth-2.11.0.orig/tests/compute_engine/test_credentials.py google-auth-2.11.0/tests/compute_engine/test_credentials.py ---- google-auth-2.11.0.orig/tests/compute_engine/test_credentials.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/compute_engine/test_credentials.py 2022-09-08 14:01:15.569972516 +0200 +diff -Nru google-auth-2.12.0.orig/tests/compute_engine/test_credentials.py google-auth-2.12.0/tests/compute_engine/test_credentials.py +--- google-auth-2.12.0.orig/tests/compute_engine/test_credentials.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/compute_engine/test_credentials.py 2022-10-14 11:30:25.664406383 +0200 @@ -14,7 +14,7 @@ import base64 import datetime @@ -10,9 +10,9 @@ import pytest # type: ignore import responses # type: ignore -diff -Nru google-auth-2.11.0.orig/tests/compute_engine/test__metadata.py google-auth-2.11.0/tests/compute_engine/test__metadata.py ---- google-auth-2.11.0.orig/tests/compute_engine/test__metadata.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/compute_engine/test__metadata.py 2022-09-08 14:01:15.569972516 +0200 +diff -Nru google-auth-2.12.0.orig/tests/compute_engine/test__metadata.py google-auth-2.12.0/tests/compute_engine/test__metadata.py +--- google-auth-2.12.0.orig/tests/compute_engine/test__metadata.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/compute_engine/test__metadata.py 2022-10-14 11:30:25.664406383 +0200 @@ -16,7 +16,7 @@ import json import os @@ -22,9 +22,9 @@ import pytest # type: ignore from six.moves import http_client from six.moves import reload_module -diff -Nru google-auth-2.11.0.orig/tests/conftest.py google-auth-2.11.0/tests/conftest.py ---- google-auth-2.11.0.orig/tests/conftest.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/conftest.py 2022-09-08 14:01:15.509971920 +0200 +diff -Nru google-auth-2.12.0.orig/tests/conftest.py google-auth-2.12.0/tests/conftest.py +--- google-auth-2.12.0.orig/tests/conftest.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/conftest.py 2022-10-14 11:30:25.620405922 +0200 @@ -15,7 +15,7 @@ import os import sys @@ -34,9 +34,9 @@ import pytest # type: ignore -diff -Nru google-auth-2.11.0.orig/tests/crypt/test__python_rsa.py google-auth-2.11.0/tests/crypt/test__python_rsa.py ---- google-auth-2.11.0.orig/tests/crypt/test__python_rsa.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/crypt/test__python_rsa.py 2022-09-08 14:01:15.589972714 +0200 +diff -Nru google-auth-2.12.0.orig/tests/crypt/test__python_rsa.py google-auth-2.12.0/tests/crypt/test__python_rsa.py +--- google-auth-2.12.0.orig/tests/crypt/test__python_rsa.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/crypt/test__python_rsa.py 2022-10-14 11:30:25.676406509 +0200 @@ -15,7 +15,7 @@ import json import os @@ -46,9 +46,9 @@ from pyasn1_modules import pem # type: ignore import pytest # type: ignore import rsa # type: ignore -diff -Nru google-auth-2.11.0.orig/tests/oauth2/test_challenges.py google-auth-2.11.0/tests/oauth2/test_challenges.py ---- google-auth-2.11.0.orig/tests/oauth2/test_challenges.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/oauth2/test_challenges.py 2022-09-08 14:01:15.557972396 +0200 +diff -Nru google-auth-2.12.0.orig/tests/oauth2/test_challenges.py google-auth-2.12.0/tests/oauth2/test_challenges.py +--- google-auth-2.12.0.orig/tests/oauth2/test_challenges.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/oauth2/test_challenges.py 2022-10-14 11:30:25.656406299 +0200 @@ -17,7 +17,7 @@ import base64 import sys @@ -58,9 +58,9 @@ import pytest # type: ignore import pyu2f # type: ignore -diff -Nru google-auth-2.11.0.orig/tests/oauth2/test__client.py google-auth-2.11.0/tests/oauth2/test__client.py ---- google-auth-2.11.0.orig/tests/oauth2/test__client.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/oauth2/test__client.py 2022-09-08 14:01:15.549972317 +0200 +diff -Nru google-auth-2.12.0.orig/tests/oauth2/test__client.py google-auth-2.12.0/tests/oauth2/test__client.py +--- google-auth-2.12.0.orig/tests/oauth2/test__client.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/oauth2/test__client.py 2022-10-14 11:30:25.648406216 +0200 @@ -16,7 +16,7 @@ import json import os @@ -70,9 +70,9 @@ import pytest # type: ignore import six from six.moves import http_client -diff -Nru google-auth-2.11.0.orig/tests/oauth2/test_credentials.py google-auth-2.11.0/tests/oauth2/test_credentials.py ---- google-auth-2.11.0.orig/tests/oauth2/test_credentials.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/oauth2/test_credentials.py 2022-09-08 14:01:15.553972357 +0200 +diff -Nru google-auth-2.12.0.orig/tests/oauth2/test_credentials.py google-auth-2.12.0/tests/oauth2/test_credentials.py +--- google-auth-2.12.0.orig/tests/oauth2/test_credentials.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/oauth2/test_credentials.py 2022-10-14 11:30:25.652406258 +0200 @@ -18,7 +18,7 @@ import pickle import sys @@ -82,9 +82,9 @@ import pytest # type: ignore from google.auth import _helpers -diff -Nru google-auth-2.11.0.orig/tests/oauth2/test_gdch_credentials.py google-auth-2.11.0/tests/oauth2/test_gdch_credentials.py ---- google-auth-2.11.0.orig/tests/oauth2/test_gdch_credentials.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/oauth2/test_gdch_credentials.py 2022-09-08 14:01:15.545972277 +0200 +diff -Nru google-auth-2.12.0.orig/tests/oauth2/test_gdch_credentials.py google-auth-2.12.0/tests/oauth2/test_gdch_credentials.py +--- google-auth-2.12.0.orig/tests/oauth2/test_gdch_credentials.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/oauth2/test_gdch_credentials.py 2022-10-14 11:30:25.644406174 +0200 @@ -17,7 +17,7 @@ import json import os @@ -94,9 +94,9 @@ import pytest # type: ignore import requests import six -diff -Nru google-auth-2.11.0.orig/tests/oauth2/test_id_token.py google-auth-2.11.0/tests/oauth2/test_id_token.py ---- google-auth-2.11.0.orig/tests/oauth2/test_id_token.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/oauth2/test_id_token.py 2022-09-08 14:01:15.545972277 +0200 +diff -Nru google-auth-2.12.0.orig/tests/oauth2/test_id_token.py google-auth-2.12.0/tests/oauth2/test_id_token.py +--- google-auth-2.12.0.orig/tests/oauth2/test_id_token.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/oauth2/test_id_token.py 2022-10-14 11:30:25.648406216 +0200 @@ -15,7 +15,7 @@ import json import os @@ -106,9 +106,9 @@ import pytest # type: ignore from google.auth import environment_vars -diff -Nru google-auth-2.11.0.orig/tests/oauth2/test_reauth.py google-auth-2.11.0/tests/oauth2/test_reauth.py ---- google-auth-2.11.0.orig/tests/oauth2/test_reauth.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/oauth2/test_reauth.py 2022-09-08 14:01:15.553972357 +0200 +diff -Nru google-auth-2.12.0.orig/tests/oauth2/test_reauth.py google-auth-2.12.0/tests/oauth2/test_reauth.py +--- google-auth-2.12.0.orig/tests/oauth2/test_reauth.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/oauth2/test_reauth.py 2022-10-14 11:30:25.652406258 +0200 @@ -14,7 +14,7 @@ import copy @@ -118,9 +118,9 @@ import pytest # type: ignore from google.auth import exceptions -diff -Nru google-auth-2.11.0.orig/tests/oauth2/test_service_account.py google-auth-2.11.0/tests/oauth2/test_service_account.py ---- google-auth-2.11.0.orig/tests/oauth2/test_service_account.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/oauth2/test_service_account.py 2022-09-08 14:01:15.549972317 +0200 +diff -Nru google-auth-2.12.0.orig/tests/oauth2/test_service_account.py google-auth-2.12.0/tests/oauth2/test_service_account.py +--- google-auth-2.12.0.orig/tests/oauth2/test_service_account.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/oauth2/test_service_account.py 2022-10-14 11:30:25.648406216 +0200 @@ -16,7 +16,7 @@ import json import os @@ -130,9 +130,9 @@ from google.auth import _helpers from google.auth import crypt -diff -Nru google-auth-2.11.0.orig/tests/oauth2/test_sts.py google-auth-2.11.0/tests/oauth2/test_sts.py ---- google-auth-2.11.0.orig/tests/oauth2/test_sts.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/oauth2/test_sts.py 2022-09-08 14:01:15.561972436 +0200 +diff -Nru google-auth-2.12.0.orig/tests/oauth2/test_sts.py google-auth-2.12.0/tests/oauth2/test_sts.py +--- google-auth-2.12.0.orig/tests/oauth2/test_sts.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/oauth2/test_sts.py 2022-10-14 11:30:25.656406299 +0200 @@ -14,7 +14,7 @@ import json @@ -142,9 +142,9 @@ import pytest # type: ignore from six.moves import http_client from six.moves import urllib -diff -Nru google-auth-2.11.0.orig/tests/test_app_engine.py google-auth-2.11.0/tests/test_app_engine.py ---- google-auth-2.11.0.orig/tests/test_app_engine.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/test_app_engine.py 2022-09-08 14:01:15.533972159 +0200 +diff -Nru google-auth-2.12.0.orig/tests/test_app_engine.py google-auth-2.12.0/tests/test_app_engine.py +--- google-auth-2.12.0.orig/tests/test_app_engine.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/test_app_engine.py 2022-10-14 11:30:25.640406132 +0200 @@ -14,7 +14,7 @@ import datetime @@ -154,9 +154,9 @@ import pytest # type: ignore from google.auth import app_engine -diff -Nru google-auth-2.11.0.orig/tests/test_aws.py google-auth-2.11.0/tests/test_aws.py ---- google-auth-2.11.0.orig/tests/test_aws.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/test_aws.py 2022-09-08 14:01:15.601972833 +0200 +diff -Nru google-auth-2.12.0.orig/tests/test_aws.py google-auth-2.12.0/tests/test_aws.py +--- google-auth-2.12.0.orig/tests/test_aws.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/test_aws.py 2022-10-14 11:30:25.684406593 +0200 @@ -15,7 +15,7 @@ import datetime import json @@ -166,9 +166,9 @@ import pytest # type: ignore from six.moves import http_client from six.moves import urllib -diff -Nru google-auth-2.11.0.orig/tests/test__cloud_sdk.py google-auth-2.11.0/tests/test__cloud_sdk.py ---- google-auth-2.11.0.orig/tests/test__cloud_sdk.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/test__cloud_sdk.py 2022-09-08 14:01:15.541972237 +0200 +diff -Nru google-auth-2.12.0.orig/tests/test__cloud_sdk.py google-auth-2.12.0/tests/test__cloud_sdk.py +--- google-auth-2.12.0.orig/tests/test__cloud_sdk.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/test__cloud_sdk.py 2022-10-14 11:30:25.644406174 +0200 @@ -17,7 +17,7 @@ import os import subprocess @@ -178,9 +178,9 @@ import pytest # type: ignore from google.auth import _cloud_sdk -diff -Nru google-auth-2.11.0.orig/tests/test__default.py google-auth-2.11.0/tests/test__default.py ---- google-auth-2.11.0.orig/tests/test__default.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/test__default.py 2022-09-08 14:01:15.565972476 +0200 +diff -Nru google-auth-2.12.0.orig/tests/test__default.py google-auth-2.12.0/tests/test__default.py +--- google-auth-2.12.0.orig/tests/test__default.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/test__default.py 2022-10-14 11:30:25.664406383 +0200 @@ -15,7 +15,7 @@ import json import os @@ -190,9 +190,9 @@ import pytest # type: ignore from google.auth import _default -diff -Nru google-auth-2.11.0.orig/tests/test_downscoped.py google-auth-2.11.0/tests/test_downscoped.py ---- google-auth-2.11.0.orig/tests/test_downscoped.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/test_downscoped.py 2022-09-08 14:01:15.569972516 +0200 +diff -Nru google-auth-2.12.0.orig/tests/test_downscoped.py google-auth-2.12.0/tests/test_downscoped.py +--- google-auth-2.12.0.orig/tests/test_downscoped.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/test_downscoped.py 2022-10-14 11:30:25.664406383 +0200 @@ -15,7 +15,7 @@ import datetime import json @@ -202,9 +202,21 @@ import pytest # type: ignore from six.moves import http_client from six.moves import urllib -diff -Nru google-auth-2.11.0.orig/tests/test_external_account.py google-auth-2.11.0/tests/test_external_account.py ---- google-auth-2.11.0.orig/tests/test_external_account.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/test_external_account.py 2022-09-08 14:01:15.509971920 +0200 +diff -Nru google-auth-2.12.0.orig/tests/test__exponential_backoff.py google-auth-2.12.0/tests/test__exponential_backoff.py +--- google-auth-2.12.0.orig/tests/test__exponential_backoff.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/test__exponential_backoff.py 2022-10-14 11:30:25.616405880 +0200 +@@ -12,7 +12,7 @@ + # See the License for the specific language governing permissions and + # limitations under the License. + +-import mock ++from unittest import mock + + from google.auth import _exponential_backoff + +diff -Nru google-auth-2.12.0.orig/tests/test_external_account.py google-auth-2.12.0/tests/test_external_account.py +--- google-auth-2.12.0.orig/tests/test_external_account.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/test_external_account.py 2022-10-14 11:30:25.620405922 +0200 @@ -15,7 +15,7 @@ import datetime import json @@ -214,9 +226,9 @@ import pytest # type: ignore from six.moves import http_client from six.moves import urllib -diff -Nru google-auth-2.11.0.orig/tests/test_iam.py google-auth-2.11.0/tests/test_iam.py ---- google-auth-2.11.0.orig/tests/test_iam.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/test_iam.py 2022-09-08 14:01:15.577972595 +0200 +diff -Nru google-auth-2.12.0.orig/tests/test_iam.py google-auth-2.12.0/tests/test_iam.py +--- google-auth-2.12.0.orig/tests/test_iam.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/test_iam.py 2022-10-14 11:30:25.664406383 +0200 @@ -16,7 +16,7 @@ import datetime import json @@ -226,9 +238,9 @@ import pytest # type: ignore from six.moves import http_client -diff -Nru google-auth-2.11.0.orig/tests/test_identity_pool.py google-auth-2.11.0/tests/test_identity_pool.py ---- google-auth-2.11.0.orig/tests/test_identity_pool.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/test_identity_pool.py 2022-09-08 14:01:15.577972595 +0200 +diff -Nru google-auth-2.12.0.orig/tests/test_identity_pool.py google-auth-2.12.0/tests/test_identity_pool.py +--- google-auth-2.12.0.orig/tests/test_identity_pool.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/test_identity_pool.py 2022-10-14 11:30:25.664406383 +0200 @@ -16,7 +16,7 @@ import json import os @@ -238,9 +250,9 @@ import pytest # type: ignore from six.moves import http_client from six.moves import urllib -diff -Nru google-auth-2.11.0.orig/tests/test_impersonated_credentials.py google-auth-2.11.0/tests/test_impersonated_credentials.py ---- google-auth-2.11.0.orig/tests/test_impersonated_credentials.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/test_impersonated_credentials.py 2022-09-08 14:01:15.593972754 +0200 +diff -Nru google-auth-2.12.0.orig/tests/test_impersonated_credentials.py google-auth-2.12.0/tests/test_impersonated_credentials.py +--- google-auth-2.12.0.orig/tests/test_impersonated_credentials.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/test_impersonated_credentials.py 2022-10-14 11:30:25.680406551 +0200 @@ -19,7 +19,7 @@ # Because Python 2.7 # from typing import List @@ -250,9 +262,9 @@ import pytest # type: ignore from six.moves import http_client -diff -Nru google-auth-2.11.0.orig/tests/test_jwt.py google-auth-2.11.0/tests/test_jwt.py ---- google-auth-2.11.0.orig/tests/test_jwt.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/test_jwt.py 2022-09-08 14:01:15.581972634 +0200 +diff -Nru google-auth-2.12.0.orig/tests/test_jwt.py google-auth-2.12.0/tests/test_jwt.py +--- google-auth-2.12.0.orig/tests/test_jwt.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/test_jwt.py 2022-10-14 11:30:25.668406425 +0200 @@ -17,7 +17,7 @@ import json import os @@ -262,21 +274,21 @@ import pytest # type: ignore from google.auth import _helpers -diff -Nru google-auth-2.11.0.orig/tests/test__oauth2client.py google-auth-2.11.0/tests/test__oauth2client.py ---- google-auth-2.11.0.orig/tests/test__oauth2client.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/test__oauth2client.py 2022-09-08 14:01:15.537972198 +0200 +diff -Nru google-auth-2.12.0.orig/tests/test__oauth2client.py google-auth-2.12.0/tests/test__oauth2client.py +--- google-auth-2.12.0.orig/tests/test__oauth2client.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/test__oauth2client.py 2022-10-14 11:30:25.640406132 +0200 @@ -16,7 +16,7 @@ import os import sys -import mock +from unittest import mock - import oauth2client.client # type: ignore - import oauth2client.contrib.gce # type: ignore - import oauth2client.service_account # type: ignore -diff -Nru google-auth-2.11.0.orig/tests/test_pluggable.py google-auth-2.11.0/tests/test_pluggable.py ---- google-auth-2.11.0.orig/tests/test_pluggable.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/test_pluggable.py 2022-09-08 14:01:15.597972793 +0200 + import pytest # type: ignore + from six.moves import reload_module + +diff -Nru google-auth-2.12.0.orig/tests/test_pluggable.py google-auth-2.12.0/tests/test_pluggable.py +--- google-auth-2.12.0.orig/tests/test_pluggable.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/test_pluggable.py 2022-10-14 11:30:25.684406593 +0200 @@ -17,7 +17,7 @@ import os import subprocess @@ -286,9 +298,9 @@ import pytest # type: ignore # from six.moves import http_client -diff -Nru google-auth-2.11.0.orig/tests/transport/test__custom_tls_signer.py google-auth-2.11.0/tests/transport/test__custom_tls_signer.py ---- google-auth-2.11.0.orig/tests/transport/test__custom_tls_signer.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/transport/test__custom_tls_signer.py 2022-09-08 14:01:15.513971960 +0200 +diff -Nru google-auth-2.12.0.orig/tests/transport/test__custom_tls_signer.py google-auth-2.12.0/tests/transport/test__custom_tls_signer.py +--- google-auth-2.12.0.orig/tests/transport/test__custom_tls_signer.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/transport/test__custom_tls_signer.py 2022-10-14 11:30:25.624405964 +0200 @@ -16,7 +16,7 @@ import ctypes import os @@ -298,9 +310,9 @@ import pytest # type: ignore from requests.packages.urllib3.util.ssl_ import create_urllib3_context # type: ignore import urllib3.contrib.pyopenssl # type: ignore -diff -Nru google-auth-2.11.0.orig/tests/transport/test_grpc.py google-auth-2.11.0/tests/transport/test_grpc.py ---- google-auth-2.11.0.orig/tests/transport/test_grpc.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/transport/test_grpc.py 2022-09-08 14:01:15.517971999 +0200 +diff -Nru google-auth-2.12.0.orig/tests/transport/test_grpc.py google-auth-2.12.0/tests/transport/test_grpc.py +--- google-auth-2.12.0.orig/tests/transport/test_grpc.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/transport/test_grpc.py 2022-10-14 11:30:25.624405964 +0200 @@ -16,7 +16,7 @@ import os import time @@ -310,9 +322,9 @@ import pytest # type: ignore from google.auth import _helpers -diff -Nru google-auth-2.11.0.orig/tests/transport/test__mtls_helper.py google-auth-2.11.0/tests/transport/test__mtls_helper.py ---- google-auth-2.11.0.orig/tests/transport/test__mtls_helper.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/transport/test__mtls_helper.py 2022-09-08 14:01:15.521972039 +0200 +diff -Nru google-auth-2.12.0.orig/tests/transport/test__mtls_helper.py google-auth-2.12.0/tests/transport/test__mtls_helper.py +--- google-auth-2.12.0.orig/tests/transport/test__mtls_helper.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/transport/test__mtls_helper.py 2022-10-14 11:30:25.628406006 +0200 @@ -15,7 +15,7 @@ import os import re @@ -322,9 +334,9 @@ from OpenSSL import crypto import pytest # type: ignore -diff -Nru google-auth-2.11.0.orig/tests/transport/test_mtls.py google-auth-2.11.0/tests/transport/test_mtls.py ---- google-auth-2.11.0.orig/tests/transport/test_mtls.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/transport/test_mtls.py 2022-09-08 14:01:15.521972039 +0200 +diff -Nru google-auth-2.12.0.orig/tests/transport/test_mtls.py google-auth-2.12.0/tests/transport/test_mtls.py +--- google-auth-2.12.0.orig/tests/transport/test_mtls.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/transport/test_mtls.py 2022-10-14 11:30:25.632406048 +0200 @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. @@ -334,9 +346,9 @@ import pytest # type: ignore from google.auth import exceptions -diff -Nru google-auth-2.11.0.orig/tests/transport/test_requests.py google-auth-2.11.0/tests/transport/test_requests.py ---- google-auth-2.11.0.orig/tests/transport/test_requests.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/transport/test_requests.py 2022-09-08 14:01:15.525972079 +0200 +diff -Nru google-auth-2.12.0.orig/tests/transport/test_requests.py google-auth-2.12.0/tests/transport/test_requests.py +--- google-auth-2.12.0.orig/tests/transport/test_requests.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/transport/test_requests.py 2022-10-14 11:30:25.632406048 +0200 @@ -18,7 +18,7 @@ import sys @@ -346,9 +358,9 @@ import OpenSSL import pytest # type: ignore import requests -diff -Nru google-auth-2.11.0.orig/tests/transport/test_urllib3.py google-auth-2.11.0/tests/transport/test_urllib3.py ---- google-auth-2.11.0.orig/tests/transport/test_urllib3.py 2022-08-20 01:27:12.000000000 +0200 -+++ google-auth-2.11.0/tests/transport/test_urllib3.py 2022-09-08 14:01:15.513971960 +0200 +diff -Nru google-auth-2.12.0.orig/tests/transport/test_urllib3.py google-auth-2.12.0/tests/transport/test_urllib3.py +--- google-auth-2.12.0.orig/tests/transport/test_urllib3.py 2022-09-27 22:38:30.000000000 +0200 ++++ google-auth-2.12.0/tests/transport/test_urllib3.py 2022-10-14 11:30:25.620405922 +0200 @@ -15,7 +15,7 @@ import os import sys
