From cb03c1515e21c819998987d8ca58d5a85973cf1c Mon Sep 17 00:00:00 2001 From: Matt Castelaz Date: Thu, 23 Jul 2026 21:36:43 +0000 Subject: [PATCH 1/4] fix(auth): properly extract stdout from gnubby webauthn plugin failures --- .../google/oauth2/webauthn_handler.py | 14 +++++++++++++- .../tests/oauth2/test_webauthn_handler.py | 17 +++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/google-auth/google/oauth2/webauthn_handler.py b/packages/google-auth/google/oauth2/webauthn_handler.py index d46832dfd633..635a789b775d 100644 --- a/packages/google-auth/google/oauth2/webauthn_handler.py +++ b/packages/google-auth/google/oauth2/webauthn_handler.py @@ -58,9 +58,21 @@ def _call_plugin(self, cmd: str, input_json: str) -> str: # Call plugin process_result = subprocess.run( - [cmd], input=request, capture_output=True, check=True + [cmd], input=request, capture_output=True ) + if process_result.returncode != 0: + stdout_bytes = process_result.stdout[4:] if len(process_result.stdout) >= 4 else process_result.stdout + + error_msg = "Command '{}' returned non-zero exit status {}.\nStdout: {}\nStderr: {}".format( + cmd, + process_result.returncode, + stdout_bytes.decode(errors="replace").strip(), + process_result.stderr.decode(errors="replace").strip() + ) + + raise exceptions.GoogleAuthError(error_msg) + # Check length of response response_len_le = process_result.stdout[:4] response_len = struct.unpack(" Date: Thu, 23 Jul 2026 21:49:14 +0000 Subject: [PATCH 2/4] style(auth): format webauthn plugin files with black --- .../google/oauth2/webauthn_handler.py | 20 ++++++++++--------- .../tests/oauth2/test_webauthn_handler.py | 5 +++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/google-auth/google/oauth2/webauthn_handler.py b/packages/google-auth/google/oauth2/webauthn_handler.py index 635a789b775d..46553c13400a 100644 --- a/packages/google-auth/google/oauth2/webauthn_handler.py +++ b/packages/google-auth/google/oauth2/webauthn_handler.py @@ -57,20 +57,22 @@ def _call_plugin(self, cmd: str, input_json: str) -> str: request = length_bytes_le + input_json.encode() # Call plugin - process_result = subprocess.run( - [cmd], input=request, capture_output=True - ) + process_result = subprocess.run([cmd], input=request, capture_output=True) if process_result.returncode != 0: - stdout_bytes = process_result.stdout[4:] if len(process_result.stdout) >= 4 else process_result.stdout - + stdout_bytes = ( + process_result.stdout[4:] + if len(process_result.stdout) >= 4 + else process_result.stdout + ) + error_msg = "Command '{}' returned non-zero exit status {}.\nStdout: {}\nStderr: {}".format( - cmd, - process_result.returncode, + cmd, + process_result.returncode, stdout_bytes.decode(errors="replace").strip(), - process_result.stderr.decode(errors="replace").strip() + process_result.stderr.decode(errors="replace").strip(), ) - + raise exceptions.GoogleAuthError(error_msg) # Check length of response diff --git a/packages/google-auth/tests/oauth2/test_webauthn_handler.py b/packages/google-auth/tests/oauth2/test_webauthn_handler.py index f680764ac6a4..508ee9bcce63 100644 --- a/packages/google-auth/tests/oauth2/test_webauthn_handler.py +++ b/packages/google-auth/tests/oauth2/test_webauthn_handler.py @@ -147,8 +147,9 @@ def test_success_get_assertion(os_get_stub, subprocess_run_stub): got_response.response.user_handle == success_response["response"]["userHandle"] ) + def test_plugin_nonzero_exit(os_get_stub, subprocess_run_stub): - response_json = b'detailed_gnubby_internal_crash_log' + response_json = b"detailed_gnubby_internal_crash_log" response_len = struct.pack(" Date: Thu, 23 Jul 2026 21:52:00 +0000 Subject: [PATCH 3/4] fix(auth): conditionally strip stdout bytes during fallback --- .../google-auth/google/oauth2/webauthn_handler.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/google-auth/google/oauth2/webauthn_handler.py b/packages/google-auth/google/oauth2/webauthn_handler.py index 46553c13400a..3ee4a7ebbde3 100644 --- a/packages/google-auth/google/oauth2/webauthn_handler.py +++ b/packages/google-auth/google/oauth2/webauthn_handler.py @@ -60,11 +60,12 @@ def _call_plugin(self, cmd: str, input_json: str) -> str: process_result = subprocess.run([cmd], input=request, capture_output=True) if process_result.returncode != 0: - stdout_bytes = ( - process_result.stdout[4:] - if len(process_result.stdout) >= 4 - else process_result.stdout - ) + stdout_bytes = process_result.stdout + if ( + len(stdout_bytes) >= 4 + and struct.unpack(" Date: Fri, 24 Jul 2026 02:06:59 +0000 Subject: [PATCH 4/4] test(auth): explicitly set mock returncode for older tests --- packages/google-auth/tests/oauth2/test_webauthn_handler.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/google-auth/tests/oauth2/test_webauthn_handler.py b/packages/google-auth/tests/oauth2/test_webauthn_handler.py index 508ee9bcce63..15261aa1647a 100644 --- a/packages/google-auth/tests/oauth2/test_webauthn_handler.py +++ b/packages/google-auth/tests/oauth2/test_webauthn_handler.py @@ -49,6 +49,7 @@ def test_malformated_get_assertion_response(os_get_stub, subprocess_run_stub): response_len = struct.pack("