@@ -664,6 +664,9 @@ def test_configure_mtls_channel_cert_loading_exceptions(
664664
665665 assert not auth_session .is_mtls
666666
667+ @mock .patch (
668+ "google.auth.transport._mtls_helper._get_cert_config_path" , return_value = None
669+ )
667670 @mock .patch (
668671 "google.auth.transport._mtls_helper.get_client_cert_and_key" , autospec = True
669672 )
@@ -677,7 +680,7 @@ def test_configure_mtls_channel_cert_loading_exceptions(
677680 },
678681 )
679682 def test_configure_mtls_channel_without_client_cert_env (
680- self , get_client_cert_and_key
683+ self , get_client_cert_and_key , mock_get_cert_config_path
681684 ):
682685 env_to_patch = {
683686 environment_vars .GOOGLE_API_USE_CLIENT_CERTIFICATE : "" ,
@@ -937,9 +940,19 @@ def test_cert_rotation_logic_skipped_on_other_refresh_status_codes(self):
937940 # Assert mTLS check logic was SKIPPED (Inner Check was False)
938941 assert not mock_helper .check_parameters_for_unauthorized_response .called
939942
940- def test_cert_rotation_skipped_on_non_mtls_url (self ):
943+ @pytest .mark .parametrize (
944+ "non_mtls_url" ,
945+ [
946+ "http://example.com/" ,
947+ "https://storage.googleapis.com/bucket/mtls.googleapis.com" ,
948+ "https://logging.googleapis.com/v2/entries?filter=mtls.googleapis.com" ,
949+ "https://example.com/mtls.sandbox.googleapis.com" ,
950+ ],
951+ )
952+ def test_cert_rotation_skipped_on_non_mtls_url (self , non_mtls_url ):
941953 """
942- Tests that mTLS cert rotation is skipped on a non-mTLS URL even if
954+ Tests that mTLS cert rotation is skipped on non-mTLS URLs (including
955+ those containing mTLS substrings in paths/query parameters) even if
943956 mTLS is enabled and an UNAUTHORIZED (401) response is received.
944957 """
945958 credentials = mock .Mock (wraps = CredentialsStub ())
@@ -953,19 +966,53 @@ def test_cert_rotation_skipped_on_non_mtls_url(self):
953966 authed_session = google .auth .transport .requests .AuthorizedSession (
954967 credentials , refresh_timeout = 60
955968 )
956- authed_session .mount (self .TEST_URL , adapter )
969+ authed_session .mount ("https://" , adapter )
970+ authed_session .mount ("http://" , adapter )
957971 authed_session ._is_mtls = True
972+ authed_session ._cached_cert = b"cached_cert"
958973
959- with mock .patch (
960- "google.auth.transport.requests._mtls_helper" , autospec = True
961- ) as mock_helper :
962- authed_session .request ("GET" , self .TEST_URL )
974+ with mock .patch .object (
975+ google .auth .transport ._mtls_helper ,
976+ "check_parameters_for_unauthorized_response" ,
977+ ) as mock_check_params :
978+ authed_session .request ("GET" , non_mtls_url )
963979
964980 # Assert refresh happened
965981 assert credentials .refresh .called
966982
967983 # Assert mTLS check logic was SKIPPED
968- assert not mock_helper .check_parameters_for_unauthorized_response .called
984+ assert not mock_check_params .called
985+
986+ def test_cert_rotation_triggered_on_psc_url (self ):
987+ """
988+ Tests that mTLS cert rotation IS triggered on a Private Service Connect
989+ (PSC) mTLS endpoint when an UNAUTHORIZED (401) response is received.
990+ """
991+ credentials = mock .Mock (wraps = CredentialsStub ())
992+ adapter = AdapterStub (
993+ [
994+ make_response (status = http_client .UNAUTHORIZED ),
995+ make_response (status = http_client .OK ),
996+ ]
997+ )
998+ psc_url = "https://storage.p.googleapis.com/b/my-bucket"
999+ authed_session = google .auth .transport .requests .AuthorizedSession (
1000+ credentials , refresh_timeout = 60
1001+ )
1002+ authed_session .mount (psc_url , adapter )
1003+ authed_session ._is_mtls = True
1004+ authed_session ._cached_cert = b"cached_cert"
1005+
1006+ with mock .patch .object (
1007+ google .auth .transport ._mtls_helper ,
1008+ "check_parameters_for_unauthorized_response" ,
1009+ return_value = (b"new_cert" , b"new_key" , "old_fp" , "old_fp" ),
1010+ ) as mock_check_params :
1011+ authed_session .request ("GET" , psc_url )
1012+
1013+ # Assert mTLS check logic was called on PSC endpoint
1014+ mock_check_params .assert_called_once ()
1015+ assert credentials .refresh .called
9691016
9701017 def test_configure_mtls_channel_subsequent_failure (self ):
9711018 # 1. Setup successful mTLS configuration
0 commit comments