fix: make xAI OAuth callback server threaded

This commit is contained in:
Fewmanism 2026-05-17 20:47:31 +09:00 committed by Teknium
parent 5613dfea93
commit eac198b6d5
2 changed files with 29 additions and 2 deletions

View file

@ -39,7 +39,7 @@ import webbrowser
from contextlib import contextmanager
from dataclasses import dataclass, field
from datetime import datetime, timezone
from http.server import BaseHTTPRequestHandler, HTTPServer
from http.server import BaseHTTPRequestHandler, HTTPServer, ThreadingHTTPServer
from pathlib import Path
from typing import Any, Callable, Dict, List, Optional, Tuple
from urllib.parse import parse_qs, urlencode, urlparse
@ -2426,8 +2426,9 @@ def _xai_start_callback_server(
expected_path = XAI_OAUTH_REDIRECT_PATH
handler_cls, result = _make_xai_callback_handler(expected_path)
class _ReuseHTTPServer(HTTPServer):
class _ReuseHTTPServer(ThreadingHTTPServer):
allow_reuse_address = True
daemon_threads = True
ports_to_try = [preferred_port]
if preferred_port != 0:

View file

@ -2,7 +2,9 @@
import base64
import json
import socket
import time
import urllib.request
from pathlib import Path
import pytest
@ -20,6 +22,7 @@ from hermes_cli.auth import (
_xai_access_token_is_expiring,
_xai_callback_cors_origin,
_xai_oauth_build_authorize_url,
_xai_start_callback_server,
_xai_validate_loopback_redirect_uri,
get_xai_oauth_auth_status,
refresh_xai_oauth_pure,
@ -278,6 +281,29 @@ def test_xai_callback_cors_origin_rejects_unknown_origin():
assert _xai_callback_cors_origin("") == ""
def test_xai_callback_server_accepts_fallback_code_while_browser_connection_is_stuck():
"""Regression: Chrome/xAI can leave a loopback connection open after
showing the Grok Build fallback code. A single-threaded callback server then
blocks forever and cannot accept the manual fallback callback.
"""
server, thread, result, redirect_uri = _xai_start_callback_server(preferred_port=0)
stuck = socket.create_connection((XAI_OAUTH_REDIRECT_HOST, server.server_address[1]), timeout=2)
try:
stuck.sendall(b"GET /callback?code=stuck")
callback_url = f"{redirect_uri}?code=fallback-code&state=state-123"
with urllib.request.urlopen(callback_url, timeout=2) as response:
body = response.read().decode("utf-8")
assert response.status == 200
assert "xAI authorization received" in body
assert result["code"] == "fallback-code"
assert result["state"] == "state-123"
finally:
stuck.close()
server.shutdown()
server.server_close()
thread.join(timeout=1.0)
# ---------------------------------------------------------------------------
# Token roundtrip + reads
# ---------------------------------------------------------------------------