From dc703f5d0ae5880d4630fca0d167fd2d5d2007c2 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Fri, 16 Oct 2026 20:34:07 -0700 Subject: [PATCH] fix(cli): open only the browser lite checked, so a failing BROWSER is reported instead of a hidden console browser waiting --- .../proxy/client/cli/commands/auto_sign_in.py | 2 +- .../proxy/client/cli/test_auto_sign_in.py | 31 ++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/litellm/proxy/client/cli/commands/auto_sign_in.py b/litellm/proxy/client/cli/commands/auto_sign_in.py index 51f5a86ce85..7c313531145 100644 --- a/litellm/proxy/client/cli/commands/auto_sign_in.py +++ b/litellm/proxy/client/cli/commands/auto_sign_in.py @@ -49,7 +49,7 @@ def _ssh_session_without_a_display(environ: Mapping[str, str]) -> bool: return over_ssh and not any(environ.get(name) for name in _DISPLAY_VARIABLES) -_OPEN_URL_IN_BROWSER: Final = "import sys, webbrowser; sys.exit(0 if webbrowser.open(sys.argv[1]) else 1)" +_OPEN_URL_IN_BROWSER: Final = "import sys, webbrowser; sys.exit(0 if webbrowser.get().open(sys.argv[1]) else 1)" def open_browser_detached(url: str) -> PkceFailure | None: diff --git a/tests/unit/proxy/client/cli/test_auto_sign_in.py b/tests/unit/proxy/client/cli/test_auto_sign_in.py index a67106f6cb1..a53ba4cd496 100644 --- a/tests/unit/proxy/client/cli/test_auto_sign_in.py +++ b/tests/unit/proxy/client/cli/test_auto_sign_in.py @@ -12,7 +12,7 @@ from requests_mock import Mocker from litellm.proxy.client.cli import cli from litellm.proxy.client.cli.commands.auth import CliTokenData, get_stored_api_key, save_token -from litellm.proxy.client.cli.commands.auto_sign_in import PkceBrowserSignIn +from litellm.proxy.client.cli.commands.auto_sign_in import PkceBrowserSignIn, open_browser_detached from litellm.proxy.client.cli.commands.pkce_login import PkceCredential, PkceFailure, pkce_token_record from tests.unit.litellm_core_utils.fake_secret_vault import FakeSecretVault @@ -250,6 +250,35 @@ def test_a_browser_the_user_picked_starts_the_sign_in_and_names_how_long_it_wait ] + +def _browser_script(path: Path, ran: Path, exit_code: int) -> Path: + path.write_text(f'#!/bin/sh\n: > "{ran}"\nexit {exit_code}\n') + path.chmod(0o755) + return path + + +@pytest.mark.parametrize( + ("picked_exit_code", "expected"), + [(0, None), (1, PkceFailure("the web browser did not open"))], + ids=["picked-browser-opens", "picked-browser-fails"], +) +def test_the_browser_launcher_opens_only_the_browser_lite_picked_and_never_a_hidden_console_one( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch, picked_exit_code: int, expected: PkceFailure | None +) -> None: + picked_ran: Final = tmp_path / "picked-browser-ran" + console_ran: Final = tmp_path / "console-browser-ran" + picked: Final = _browser_script(tmp_path / "picked-browser", picked_ran, picked_exit_code) + _browser_script(tmp_path / "www-browser", console_ran, 0) + monkeypatch.setenv("PATH", str(tmp_path)) + monkeypatch.setenv("TERM", "xterm") + monkeypatch.setenv("BROWSER", str(picked)) + monkeypatch.delenv("DISPLAY", raising=False) + monkeypatch.delenv("WAYLAND_DISPLAY", raising=False) + + assert open_browser_detached(f"{BASE_URL}/v1/cli/authorize?state=abc") == expected + assert picked_ran.exists() + assert not console_ran.exists() + @pytest.mark.parametrize( ("command", "method", "path", "body"), [