From f588166691a6c86fada38ccc6a2b5e5011b8bb03 Mon Sep 17 00:00:00 2001 From: Jony <13896935+zyz619963502zyz@users.noreply.github.com> Date: Mon, 14 Sep 2026 11:24:45 +0800 Subject: [PATCH] fix(google-chat): avoid guessing auth failure cause --- plugins/platforms/google_chat/adapter.py | 5 ++++- tests/gateway/test_google_chat.py | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/plugins/platforms/google_chat/adapter.py b/plugins/platforms/google_chat/adapter.py index 083bed98ac..41a667534f 100644 --- a/plugins/platforms/google_chat/adapter.py +++ b/plugins/platforms/google_chat/adapter.py @@ -690,7 +690,10 @@ class GoogleChatAdapter(BasePlatformAdapter): """Run streaming_pull with exponential backoff + full jitter; fatal after N attempts. ``subscribe()`` returns a Future that resolves when the stream dies.""" pubsub_fatals = { - gax_exceptions.Unauthenticated: ("pubsub_auth", "Pub/Sub authentication failed (SA key invalid/revoked)"), + gax_exceptions.Unauthenticated: ( + "pubsub_auth", + "Pub/Sub authentication failed; check service-account credentials and gateway logs", + ), gax_exceptions.PermissionDenied: ("pubsub_permission", "SA lacks pubsub.subscriber on the subscription"), } attempt = 0 diff --git a/tests/gateway/test_google_chat.py b/tests/gateway/test_google_chat.py index 8b307663ef..43c6ad24aa 100644 --- a/tests/gateway/test_google_chat.py +++ b/tests/gateway/test_google_chat.py @@ -1518,6 +1518,22 @@ class TestADCFallback: class TestSupervisorReconnect: + @pytest.mark.asyncio + async def test_unauthenticated_status_does_not_guess_credential_cause( + self, adapter + ): + """An auth rejection may have causes other than a revoked SA key.""" + adapter._subscriber.subscribe.side_effect = ( + _gc_mod.gax_exceptions.Unauthenticated("request rejected") + ) + + await adapter._run_supervisor() + + assert adapter.fatal_error_code == "pubsub_auth" + assert adapter.fatal_error_message == ( + "Pub/Sub authentication failed; check service-account credentials and gateway logs" + ) + @pytest.mark.asyncio async def test_fatal_after_max_retries(self, adapter, monkeypatch): """Simulate 10+ failing subscribe() calls and assert fatal error set."""