fix(cli): start the browser sign-in on Python 3.10's macOS browser and strip terminal control characters from 401 text

Python 3.10's macOS browser class has no name attribute, so every 401 with no passed key crashed before the sign-in, and a 401 body could put escape sequences on the terminal
This commit is contained in:
mateo-berri 2026-10-30 04:06:05 -07:00
parent 26a26a5b9d
commit 24a0b694e4
2 changed files with 33 additions and 2 deletions

View file

@ -1,4 +1,5 @@
import os
import re
import subprocess
import sys
import time
@ -41,6 +42,7 @@ _DISPLAY_VARIABLES: Final = ("DISPLAY", "WAYLAND_DISPLAY")
_SIGNED_IN_LOGIN_WITHOUT_KEY_ROW: Final = HTTPStatus.NOT_FOUND
_WAIT_FOR_ANOTHER_SIGN_IN_SECONDS: Final = LOGIN_TIMEOUT_SECONDS + 60
_PROXY_REASON_CHARS: Final = 500
_TERMINAL_CONTROL_CHARACTERS: Final = re.compile(r"[\x00-\x08\x0b-\x1f\x7f-\x9f]")
def _runs_in_ci(environ: Mapping[str, str]) -> bool:
@ -87,7 +89,7 @@ def _locate_browser(
def _shows_a_window(browser: webbrowser.BaseBrowser) -> bool:
return Path(browser.name).name not in _TEXT_MODE_BROWSERS
return Path(getattr(browser, "name", "")).name not in _TEXT_MODE_BROWSERS
@dataclass(frozen=True, slots=True)
@ -212,7 +214,7 @@ def _proxy_reason(error: UnauthorizedError) -> str:
original: Final = error.orig_exception
response: Final = original.response if isinstance(original, requests.HTTPError) else None
body: Final = response.text.strip() if response is not None else ""
reason: Final = redact_string(body) if body else str(error)
reason: Final = _TERMINAL_CONTROL_CHARACTERS.sub("", redact_string(body) if body else str(error))
return reason if len(reason) <= _PROXY_REASON_CHARS else f"{reason[:_PROXY_REASON_CHARS]}..."

View file

@ -307,6 +307,18 @@ def test_an_ssh_session_without_a_display_never_opens_a_browser_on_the_remote_sc
assert requests_mock.call_count == 0
class BrowserWithoutAName(webbrowser.BaseBrowser):
def __init__(self) -> None:
self._name = "default"
def test_a_browser_object_without_a_name_still_starts_the_sign_in(requests_mock: Mocker) -> None:
sign_in: Final = PkceBrowserSignIn(find_browser=lambda _name: BrowserWithoutAName(), environ={})
assert sign_in.unavailable_because() is None
assert requests_mock.call_count == 0
@pytest.mark.parametrize(
"environ",
[
@ -640,6 +652,23 @@ def test_a_long_401_body_is_cut_before_it_reaches_the_terminal(
assert sign_in.calls == []
def test_terminal_control_characters_in_a_401_body_never_reach_the_terminal(
requests_mock: Mocker, secret_vault_factory: type[FakeSecretVault]
) -> None:
requests_mock.post(
f"{BASE_URL}/key/generate", status_code=401, text="\x1b]0;title\x07refused\x1b[2J\r\nsecond line\x9b31m"
)
sign_in: Final = FakeBrowserSignIn(_credential())
result: Final = _lite(["keys", "generate"], secret_vault_factory(), sign_in, ["--api-key", "sk-explicit"])
assert result.exit_code == 1
assert "refused" in result.stderr
assert "second line" in result.stderr
assert not {"\x1b", "\x07", "\x9b", "\r"} & set(result.stderr)
assert sign_in.calls == []
def test_a_failed_sign_in_names_the_reason_and_points_at_lite_login(
requests_mock: Mocker, secret_vault_factory: type[FakeSecretVault]
) -> None: