summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobot-piglet <[email protected]>2025-02-08 20:17:29 +0300
committerrobot-piglet <[email protected]>2025-02-08 20:32:11 +0300
commit6b7c255668de517dff6462bd377d345d240f8a67 (patch)
tree1bde953b7f2b6d9e8efd72a0ceebfa0a791a024c
parent2309a9980fd82ba7df5a21876c790e7e4d776ded (diff)
Intermediate changes
commit_hash:f4cb1bdccfb534d71b7f461fc8f8e5656c47bfa5
-rw-r--r--contrib/python/fonttools/.dist-info/METADATA13
-rw-r--r--contrib/python/fonttools/fontTools/__init__.py2
-rw-r--r--contrib/python/fonttools/fontTools/feaLib/builder.py8
-rw-r--r--contrib/python/fonttools/fontTools/ttLib/tables/_g_l_y_f.py36
-rw-r--r--contrib/python/fonttools/ya.make2
-rw-r--r--contrib/python/google-auth/py3/.dist-info/METADATA2
-rw-r--r--contrib/python/google-auth/py3/google/auth/_default.py22
-rw-r--r--contrib/python/google-auth/py3/google/auth/compute_engine/_metadata.py12
-rw-r--r--contrib/python/google-auth/py3/google/auth/iam.py5
-rw-r--r--contrib/python/google-auth/py3/google/auth/impersonated_credentials.py101
-rw-r--r--contrib/python/google-auth/py3/google/auth/version.py2
-rw-r--r--contrib/python/google-auth/py3/tests/compute_engine/test__metadata.py24
-rw-r--r--contrib/python/google-auth/py3/tests/test_impersonated_credentials.py120
-rw-r--r--contrib/python/google-auth/py3/ya.make2
-rw-r--r--yt/yt/client/cache/config.cpp2
15 files changed, 334 insertions, 19 deletions
diff --git a/contrib/python/fonttools/.dist-info/METADATA b/contrib/python/fonttools/.dist-info/METADATA
index 931191c2892..68bd23ea996 100644
--- a/contrib/python/fonttools/.dist-info/METADATA
+++ b/contrib/python/fonttools/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.2
Name: fonttools
-Version: 4.55.4
+Version: 4.55.6
Summary: Tools to manipulate font files
Home-page: http://github.com/fonttools/fonttools
Author: Just van Rossum
@@ -389,6 +389,17 @@ Have fun!
Changelog
~~~~~~~~~
+4.55.6 (released 2025-01-24)
+----------------------------
+
+- [glyf] Fixed regression introduced in 4.55.5 when computing bounds of nested composite glyphs with transformed components (#3752).
+
+4.55.5 (released 2025-01-23)
+----------------------------
+
+- [glyf] Fixed recalcBounds of transformed components with unrounded coordinates (#3750).
+- [feaLib] Allow duplicate script/language statements (#3749).
+
4.55.4 (released 2025-01-21)
----------------------------
diff --git a/contrib/python/fonttools/fontTools/__init__.py b/contrib/python/fonttools/fontTools/__init__.py
index d1af15d948f..83406338269 100644
--- a/contrib/python/fonttools/fontTools/__init__.py
+++ b/contrib/python/fonttools/fontTools/__init__.py
@@ -3,6 +3,6 @@ from fontTools.misc.loggingTools import configLogger
log = logging.getLogger(__name__)
-version = __version__ = "4.55.4"
+version = __version__ = "4.55.6"
__all__ = ["version", "log", "configLogger"]
diff --git a/contrib/python/fonttools/fontTools/feaLib/builder.py b/contrib/python/fonttools/fontTools/feaLib/builder.py
index 1cfe1c3a137..a6ba8f2f612 100644
--- a/contrib/python/fonttools/fontTools/feaLib/builder.py
+++ b/contrib/python/fonttools/fontTools/feaLib/builder.py
@@ -1106,7 +1106,13 @@ class Builder(object):
if (language == "dflt" or include_default) and lookups:
self.features_[key] = lookups[:]
else:
- self.features_[key] = []
+ # if we aren't including default we need to manually remove the
+ # default lookups, which were added to all declared langsystems
+ # as they were encountered (we don't remove all lookups because
+ # we want to allow duplicate script/lang statements;
+ # see https://github.com/fonttools/fonttools/issues/3748
+ cur_lookups = self.features_.get(key, [])
+ self.features_[key] = [x for x in cur_lookups if x not in lookups]
self.language_systems = frozenset([(self.script_, language)])
if required:
diff --git a/contrib/python/fonttools/fontTools/ttLib/tables/_g_l_y_f.py b/contrib/python/fonttools/fontTools/ttLib/tables/_g_l_y_f.py
index 92b69e70b1f..eaa9920f008 100644
--- a/contrib/python/fonttools/fontTools/ttLib/tables/_g_l_y_f.py
+++ b/contrib/python/fonttools/fontTools/ttLib/tables/_g_l_y_f.py
@@ -1187,7 +1187,7 @@ class Glyph(object):
):
return
try:
- coords, endPts, flags = self.getCoordinates(glyfTable)
+ coords, endPts, flags = self.getCoordinates(glyfTable, round=otRound)
self.xMin, self.yMin, self.xMax, self.yMax = coords.calcIntBounds()
except NotImplementedError:
pass
@@ -1206,9 +1206,7 @@ class Glyph(object):
Return True if bounds were calculated, False otherwise.
"""
for compo in self.components:
- if hasattr(compo, "firstPt") or hasattr(compo, "transform"):
- return False
- if not float(compo.x).is_integer() or not float(compo.y).is_integer():
+ if not compo._hasOnlyIntegerTranslate():
return False
# All components are untransformed and have an integer x/y translate
@@ -1241,7 +1239,7 @@ class Glyph(object):
else:
return self.numberOfContours == -1
- def getCoordinates(self, glyfTable):
+ def getCoordinates(self, glyfTable, *, round=noRound):
"""Return the coordinates, end points and flags
This method returns three values: A :py:class:`GlyphCoordinates` object,
@@ -1267,13 +1265,27 @@ class Glyph(object):
for compo in self.components:
g = glyfTable[compo.glyphName]
try:
- coordinates, endPts, flags = g.getCoordinates(glyfTable)
+ coordinates, endPts, flags = g.getCoordinates(
+ glyfTable, round=round
+ )
except RecursionError:
raise ttLib.TTLibError(
"glyph '%s' contains a recursive component reference"
% compo.glyphName
)
coordinates = GlyphCoordinates(coordinates)
+ # if asked to round e.g. while computing bboxes, it's important we
+ # do it immediately before a component transform is applied to a
+ # simple glyph's coordinates in case these might still contain floats;
+ # however, if the referenced component glyph is another composite, we
+ # must not round here but only at the end, after all the nested
+ # transforms have been applied, or else rounding errors will compound.
+ if (
+ round is not noRound
+ and g.numberOfContours > 0
+ and not compo._hasOnlyIntegerTranslate()
+ ):
+ coordinates.toInt(round=round)
if hasattr(compo, "firstPt"):
# component uses two reference points: we apply the transform _before_
# computing the offset between the points
@@ -1930,6 +1942,18 @@ class GlyphComponent(object):
result = self.__eq__(other)
return result if result is NotImplemented else not result
+ def _hasOnlyIntegerTranslate(self):
+ """Return True if it's a 'simple' component.
+
+ That is, it has no anchor points and no transform other than integer translate.
+ """
+ return (
+ not hasattr(self, "firstPt")
+ and not hasattr(self, "transform")
+ and float(self.x).is_integer()
+ and float(self.y).is_integer()
+ )
+
class GlyphCoordinates(object):
"""A list of glyph coordinates.
diff --git a/contrib/python/fonttools/ya.make b/contrib/python/fonttools/ya.make
index 461b5646645..9ada57d3f69 100644
--- a/contrib/python/fonttools/ya.make
+++ b/contrib/python/fonttools/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(4.55.4)
+VERSION(4.55.6)
LICENSE(MIT)
diff --git a/contrib/python/google-auth/py3/.dist-info/METADATA b/contrib/python/google-auth/py3/.dist-info/METADATA
index f1724bbf73f..952e020e3cd 100644
--- a/contrib/python/google-auth/py3/.dist-info/METADATA
+++ b/contrib/python/google-auth/py3/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: google-auth
-Version: 2.37.0
+Version: 2.38.0
Summary: Google Authentication Library
Home-page: https://github.com/googleapis/google-auth-library-python
Author: Google Cloud Platform
diff --git a/contrib/python/google-auth/py3/google/auth/_default.py b/contrib/python/google-auth/py3/google/auth/_default.py
index cdc8b7a6460..1234fb25d78 100644
--- a/contrib/python/google-auth/py3/google/auth/_default.py
+++ b/contrib/python/google-auth/py3/google/auth/_default.py
@@ -85,6 +85,17 @@ def load_credentials_from_file(
user credentials, external account credentials, or impersonated service
account credentials.
+ .. warning::
+ Important: If you accept a credential configuration (credential JSON/File/Stream)
+ from an external source for authentication to Google Cloud Platform, you must
+ validate it before providing it to any Google API or client library. Providing an
+ unvalidated credential configuration to Google APIs or libraries can compromise
+ the security of your systems and data. For more information, refer to
+ `Validate credential configurations from external sources`_.
+
+ .. _Validate credential configurations from external sources:
+ https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
+
Args:
filename (str): The full path to the credentials file.
scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
@@ -137,6 +148,17 @@ def load_credentials_from_dict(
user credentials, external account credentials, or impersonated service
account credentials.
+ .. warning::
+ Important: If you accept a credential configuration (credential JSON/File/Stream)
+ from an external source for authentication to Google Cloud Platform, you must
+ validate it before providing it to any Google API or client library. Providing an
+ unvalidated credential configuration to Google APIs or libraries can compromise
+ the security of your systems and data. For more information, refer to
+ `Validate credential configurations from external sources`_.
+
+ .. _Validate credential configurations from external sources:
+ https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
+
Args:
info (Dict[str, Any]): A dict object containing the credentials
scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
diff --git a/contrib/python/google-auth/py3/google/auth/compute_engine/_metadata.py b/contrib/python/google-auth/py3/google/auth/compute_engine/_metadata.py
index 8d692972fd6..06f99de0e2c 100644
--- a/contrib/python/google-auth/py3/google/auth/compute_engine/_metadata.py
+++ b/contrib/python/google-auth/py3/google/auth/compute_engine/_metadata.py
@@ -201,7 +201,7 @@ def get(
url = _helpers.update_query(base_url, query_params)
backoff = ExponentialBackoff(total_attempts=retry_count)
-
+ failure_reason = None
for attempt in backoff:
try:
response = request(url=url, method="GET", headers=headers_to_use)
@@ -213,6 +213,11 @@ def get(
retry_count,
response.status,
)
+ failure_reason = (
+ response.data.decode("utf-8")
+ if hasattr(response.data, "decode")
+ else response.data
+ )
continue
else:
break
@@ -225,10 +230,13 @@ def get(
retry_count,
e,
)
+ failure_reason = e
else:
raise exceptions.TransportError(
"Failed to retrieve {} from the Google Compute Engine "
- "metadata service. Compute Engine Metadata server unavailable".format(url)
+ "metadata service. Compute Engine Metadata server unavailable due to {}".format(
+ url, failure_reason
+ )
)
content = _helpers.from_bytes(response.data)
diff --git a/contrib/python/google-auth/py3/google/auth/iam.py b/contrib/python/google-auth/py3/google/auth/iam.py
index dcf0dbf9d58..1e4cdffec18 100644
--- a/contrib/python/google-auth/py3/google/auth/iam.py
+++ b/contrib/python/google-auth/py3/google/auth/iam.py
@@ -48,6 +48,11 @@ _IAM_SIGN_ENDPOINT = (
+ "/serviceAccounts/{}:signBlob"
)
+_IAM_SIGNJWT_ENDPOINT = (
+ "https://iamcredentials.googleapis.com/v1/projects/-"
+ + "/serviceAccounts/{}:signJwt"
+)
+
_IAM_IDTOKEN_ENDPOINT = (
"https://iamcredentials.googleapis.com/v1/"
+ "projects/-/serviceAccounts/{}:generateIdToken"
diff --git a/contrib/python/google-auth/py3/google/auth/impersonated_credentials.py b/contrib/python/google-auth/py3/google/auth/impersonated_credentials.py
index d51c8ef1e85..ed7e3f00b1c 100644
--- a/contrib/python/google-auth/py3/google/auth/impersonated_credentials.py
+++ b/contrib/python/google-auth/py3/google/auth/impersonated_credentials.py
@@ -38,12 +38,15 @@ from google.auth import exceptions
from google.auth import iam
from google.auth import jwt
from google.auth import metrics
+from google.oauth2 import _client
_REFRESH_ERROR = "Unable to acquire impersonated credentials"
_DEFAULT_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds
+_GOOGLE_OAUTH2_TOKEN_ENDPOINT = "https://oauth2.googleapis.com/token"
+
def _make_iam_token_request(
request,
@@ -177,6 +180,7 @@ class Credentials(
target_principal,
target_scopes,
delegates=None,
+ subject=None,
lifetime=_DEFAULT_TOKEN_LIFETIME_SECS,
quota_project_id=None,
iam_endpoint_override=None,
@@ -204,9 +208,12 @@ class Credentials(
quota_project_id (Optional[str]): The project ID used for quota and billing.
This project may be different from the project used to
create the credentials.
- iam_endpoint_override (Optiona[str]): The full IAM endpoint override
+ iam_endpoint_override (Optional[str]): The full IAM endpoint override
with the target_principal embedded. This is useful when supporting
impersonation with regional endpoints.
+ subject (Optional[str]): sub field of a JWT. This field should only be set
+ if you wish to impersonate as a user. This feature is useful when
+ using domain wide delegation.
"""
super(Credentials, self).__init__()
@@ -231,6 +238,7 @@ class Credentials(
self._target_principal = target_principal
self._target_scopes = target_scopes
self._delegates = delegates
+ self._subject = subject
self._lifetime = lifetime or _DEFAULT_TOKEN_LIFETIME_SECS
self.token = None
self.expiry = _helpers.utcnow()
@@ -275,6 +283,39 @@ class Credentials(
# Apply the source credentials authentication info.
self._source_credentials.apply(headers)
+ # If a subject is specified a domain-wide delegation auth-flow is initiated
+ # to impersonate as the provided subject (user).
+ if self._subject:
+ if self.universe_domain != credentials.DEFAULT_UNIVERSE_DOMAIN:
+ raise exceptions.GoogleAuthError(
+ "Domain-wide delegation is not supported in universes other "
+ + "than googleapis.com"
+ )
+
+ now = _helpers.utcnow()
+ payload = {
+ "iss": self._target_principal,
+ "scope": _helpers.scopes_to_string(self._target_scopes or ()),
+ "sub": self._subject,
+ "aud": _GOOGLE_OAUTH2_TOKEN_ENDPOINT,
+ "iat": _helpers.datetime_to_secs(now),
+ "exp": _helpers.datetime_to_secs(now) + _DEFAULT_TOKEN_LIFETIME_SECS,
+ }
+
+ assertion = _sign_jwt_request(
+ request=request,
+ principal=self._target_principal,
+ headers=headers,
+ payload=payload,
+ delegates=self._delegates,
+ )
+
+ self.token, self.expiry, _ = _client.jwt_grant(
+ request, _GOOGLE_OAUTH2_TOKEN_ENDPOINT, assertion
+ )
+
+ return
+
self.token, self.expiry = _make_iam_token_request(
request=request,
principal=self._target_principal,
@@ -478,3 +519,61 @@ class IDTokenCredentials(credentials.CredentialsWithQuotaProject):
self.expiry = datetime.utcfromtimestamp(
jwt.decode(id_token, verify=False)["exp"]
)
+
+
+def _sign_jwt_request(request, principal, headers, payload, delegates=[]):
+ """Makes a request to the Google Cloud IAM service to sign a JWT using a
+ service account's system-managed private key.
+ Args:
+ request (Request): The Request object to use.
+ principal (str): The principal to request an access token for.
+ headers (Mapping[str, str]): Map of headers to transmit.
+ payload (Mapping[str, str]): The JWT payload to sign. Must be a
+ serialized JSON object that contains a JWT Claims Set.
+ delegates (Sequence[str]): The chained list of delegates required
+ to grant the final access_token. If set, the sequence of
+ identities must have "Service Account Token Creator" capability
+ granted to the prceeding identity. For example, if set to
+ [serviceAccountB, serviceAccountC], the source_credential
+ must have the Token Creator role on serviceAccountB.
+ serviceAccountB must have the Token Creator on
+ serviceAccountC.
+ Finally, C must have Token Creator on target_principal.
+ If left unset, source_credential must have that role on
+ target_principal.
+
+ Raises:
+ google.auth.exceptions.TransportError: Raised if there is an underlying
+ HTTP connection error
+ google.auth.exceptions.RefreshError: Raised if the impersonated
+ credentials are not available. Common reasons are
+ `iamcredentials.googleapis.com` is not enabled or the
+ `Service Account Token Creator` is not assigned
+ """
+ iam_endpoint = iam._IAM_SIGNJWT_ENDPOINT.format(principal)
+
+ body = {"delegates": delegates, "payload": json.dumps(payload)}
+ body = json.dumps(body).encode("utf-8")
+
+ response = request(url=iam_endpoint, method="POST", headers=headers, body=body)
+
+ # support both string and bytes type response.data
+ response_body = (
+ response.data.decode("utf-8")
+ if hasattr(response.data, "decode")
+ else response.data
+ )
+
+ if response.status != http_client.OK:
+ raise exceptions.RefreshError(_REFRESH_ERROR, response_body)
+
+ try:
+ jwt_response = json.loads(response_body)
+ signed_jwt = jwt_response["signedJwt"]
+ return signed_jwt
+
+ except (KeyError, ValueError) as caught_exc:
+ new_exc = exceptions.RefreshError(
+ "{}: No signed JWT in response.".format(_REFRESH_ERROR), response_body
+ )
+ raise new_exc from caught_exc
diff --git a/contrib/python/google-auth/py3/google/auth/version.py b/contrib/python/google-auth/py3/google/auth/version.py
index 06ec7e7fb79..41a80e6c676 100644
--- a/contrib/python/google-auth/py3/google/auth/version.py
+++ b/contrib/python/google-auth/py3/google/auth/version.py
@@ -12,4 +12,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-__version__ = "2.37.0"
+__version__ = "2.38.0"
diff --git a/contrib/python/google-auth/py3/tests/compute_engine/test__metadata.py b/contrib/python/google-auth/py3/tests/compute_engine/test__metadata.py
index 03ba8de497d..a768b17fa0d 100644
--- a/contrib/python/google-auth/py3/tests/compute_engine/test__metadata.py
+++ b/contrib/python/google-auth/py3/tests/compute_engine/test__metadata.py
@@ -346,12 +346,32 @@ def test_get_return_none_for_not_found_error():
@mock.patch("time.sleep", return_value=None)
def test_get_failure_connection_failed(mock_sleep):
request = make_request("")
- request.side_effect = exceptions.TransportError()
+ request.side_effect = exceptions.TransportError("failure message")
with pytest.raises(exceptions.TransportError) as excinfo:
_metadata.get(request, PATH)
- assert excinfo.match(r"Compute Engine Metadata server unavailable")
+ assert excinfo.match(
+ r"Compute Engine Metadata server unavailable due to failure message"
+ )
+
+ request.assert_called_with(
+ method="GET",
+ url=_metadata._METADATA_ROOT + PATH,
+ headers=_metadata._METADATA_HEADERS,
+ )
+ assert request.call_count == 5
+
+
+def test_get_too_many_requests_retryable_error_failure():
+ request = make_request("too many requests", status=http_client.TOO_MANY_REQUESTS)
+
+ with pytest.raises(exceptions.TransportError) as excinfo:
+ _metadata.get(request, PATH)
+
+ assert excinfo.match(
+ r"Compute Engine Metadata server unavailable due to too many requests"
+ )
request.assert_called_with(
method="GET",
diff --git a/contrib/python/google-auth/py3/tests/test_impersonated_credentials.py b/contrib/python/google-auth/py3/tests/test_impersonated_credentials.py
index 371477b8a9f..0321a1a1d7b 100644
--- a/contrib/python/google-auth/py3/tests/test_impersonated_credentials.py
+++ b/contrib/python/google-auth/py3/tests/test_impersonated_credentials.py
@@ -72,6 +72,17 @@ def mock_donor_credentials():
yield grant
+def mock_dwd_credentials():
+ with mock.patch("google.oauth2._client.jwt_grant", autospec=True) as grant:
+ grant.return_value = (
+ "1/fFAGRNJasdfz70BzhT3Zg",
+ _helpers.utcnow() + datetime.timedelta(seconds=500),
+ {},
+ )
+ yield grant
+
+
class MockResponse:
def __init__(self, json_data, status_code):
self.json_data = json_data
@@ -124,6 +135,7 @@ class TestImpersonatedCredentials(object):
source_credentials=SOURCE_CREDENTIALS,
lifetime=LIFETIME,
target_principal=TARGET_PRINCIPAL,
+ subject=None,
iam_endpoint_override=None,
):
@@ -133,6 +145,7 @@ class TestImpersonatedCredentials(object):
target_scopes=self.TARGET_SCOPES,
delegates=self.DELEGATES,
lifetime=lifetime,
+ subject=subject,
iam_endpoint_override=iam_endpoint_override,
)
@@ -240,6 +253,28 @@ class TestImpersonatedCredentials(object):
)
@pytest.mark.parametrize("use_data_bytes", [True, False])
+ def test_refresh_with_subject_success(self, use_data_bytes, mock_dwd_credentials):
+ credentials = self.make_credentials(subject="[email protected]", lifetime=None)
+
+ response_body = {"signedJwt": "example_signed_jwt"}
+
+ request = self.make_request(
+ data=json.dumps(response_body),
+ status=http_client.OK,
+ use_data_bytes=use_data_bytes,
+ )
+
+ with mock.patch(
+ "google.auth.metrics.token_request_access_token_impersonate",
+ return_value=ACCESS_TOKEN_REQUEST_METRICS_HEADER_VALUE,
+ ):
+ credentials.refresh(request)
+
+ assert credentials.valid
+ assert not credentials.expired
+ assert credentials.token == "1/fFAGRNJasdfz70BzhT3Zg"
+
+ @pytest.mark.parametrize("use_data_bytes", [True, False])
def test_refresh_success_nonGdu(self, use_data_bytes, mock_donor_credentials):
source_credentials = service_account.Credentials(
SIGNER, "[email protected]", TOKEN_URI, universe_domain="foo.bar"
@@ -419,6 +454,33 @@ class TestImpersonatedCredentials(object):
assert not credentials.valid
assert credentials.expired
+ def test_refresh_failure_subject_with_nondefault_domain(
+ self, mock_donor_credentials
+ ):
+ source_credentials = service_account.Credentials(
+ SIGNER, "[email protected]", TOKEN_URI, universe_domain="foo.bar"
+ )
+ credentials = self.make_credentials(
+ source_credentials=source_credentials, subject="[email protected]"
+ )
+
+ expire_time = (_helpers.utcnow().replace(microsecond=0)).isoformat("T") + "Z"
+ response_body = {"accessToken": "token", "expireTime": expire_time}
+ request = self.make_request(
+ data=json.dumps(response_body), status=http_client.OK
+ )
+
+ with pytest.raises(exceptions.GoogleAuthError) as excinfo:
+ credentials.refresh(request)
+
+ assert excinfo.match(
+ "Domain-wide delegation is not supported in universes other "
+ + "than googleapis.com"
+ )
+
+ assert not credentials.valid
+ assert credentials.expired
+
def test_expired(self):
credentials = self.make_credentials(lifetime=None)
assert credentials.expired
@@ -811,3 +873,61 @@ class TestImpersonatedCredentials(object):
id_creds.refresh(request)
assert id_creds.quota_project_id == "project-foo"
+
+ def test_sign_jwt_request_success(self):
+ principal = "[email protected]"
+ expected_signed_jwt = "correct_signed_jwt"
+
+ response_body = {"keyId": "1", "signedJwt": expected_signed_jwt}
+ request = self.make_request(
+ data=json.dumps(response_body), status=http_client.OK
+ )
+
+ signed_jwt = impersonated_credentials._sign_jwt_request(
+ request=request, principal=principal, headers={}, payload={}
+ )
+
+ assert signed_jwt == expected_signed_jwt
+ request.assert_called_once_with(
+ url="https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/[email protected]:signJwt",
+ method="POST",
+ headers={},
+ body=json.dumps({"delegates": [], "payload": json.dumps({})}).encode(
+ "utf-8"
+ ),
+ )
+
+ def test_sign_jwt_request_http_error(self):
+ principal = "[email protected]"
+
+ request = self.make_request(
+ data="error_message", status=http_client.BAD_REQUEST
+ )
+
+ with pytest.raises(exceptions.RefreshError) as excinfo:
+ _ = impersonated_credentials._sign_jwt_request(
+ request=request, principal=principal, headers={}, payload={}
+ )
+
+ assert excinfo.match(impersonated_credentials._REFRESH_ERROR)
+
+ assert excinfo.value.args[0] == "Unable to acquire impersonated credentials"
+ assert excinfo.value.args[1] == "error_message"
+
+ def test_sign_jwt_request_invalid_response_error(self):
+ principal = "[email protected]"
+
+ request = self.make_request(data="invalid_data", status=http_client.OK)
+
+ with pytest.raises(exceptions.RefreshError) as excinfo:
+ _ = impersonated_credentials._sign_jwt_request(
+ request=request, principal=principal, headers={}, payload={}
+ )
+
+ assert excinfo.match(impersonated_credentials._REFRESH_ERROR)
+
+ assert (
+ excinfo.value.args[0]
+ == "Unable to acquire impersonated credentials: No signed JWT in response."
+ )
+ assert excinfo.value.args[1] == "invalid_data"
diff --git a/contrib/python/google-auth/py3/ya.make b/contrib/python/google-auth/py3/ya.make
index 0b08f76a8e0..bb762919dc6 100644
--- a/contrib/python/google-auth/py3/ya.make
+++ b/contrib/python/google-auth/py3/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(2.37.0)
+VERSION(2.38.0)
LICENSE(Apache-2.0)
diff --git a/yt/yt/client/cache/config.cpp b/yt/yt/client/cache/config.cpp
index f0cd2caca5a..232c6d98939 100644
--- a/yt/yt/client/cache/config.cpp
+++ b/yt/yt/client/cache/config.cpp
@@ -11,7 +11,7 @@ using namespace NApi;
void TClientsCacheConfig::Register(TRegistrar registrar)
{
registrar.Parameter("default_connection", &TThis::DefaultConnection)
- .Alias("defailt_config")
+ .Alias("default_config")
.DefaultNew();
registrar.Parameter("per_cluster_connection", &TThis::PerClusterConnection)
.Alias("cluster_configs")