diff --git a/litellm/proxy/client/cli/commands/auto_sign_in.py b/litellm/proxy/client/cli/commands/auto_sign_in.py index aca26989057..ea769a4a717 100644 --- a/litellm/proxy/client/cli/commands/auto_sign_in.py +++ b/litellm/proxy/client/cli/commands/auto_sign_in.py @@ -28,8 +28,11 @@ def _runs_in_ci(environ: Mapping[str, str]) -> bool: return environ.get("CI", "").strip().lower() not in {"", "0", "false"} -def _open_browser_off_stdout(url: str) -> bool: - return subprocess.run((sys.executable, "-I", "-m", "webbrowser", url), stdout=2, check=False).returncode == 0 +_OPEN_URL_IN_BROWSER: Final = "import sys, webbrowser; webbrowser.open(sys.argv[1])" + + +def open_browser_off_stdout(url: str) -> None: + subprocess.run((sys.executable, "-I", "-c", _OPEN_URL_IN_BROWSER, url), stdout=2, check=False) def pkce_browser_sign_in( @@ -37,7 +40,7 @@ def pkce_browser_sign_in( echo: Callable[[str], None], find_browser: Callable[[], webbrowser.BaseBrowser] = webbrowser.get, environ: Mapping[str, str] = os.environ, - open_browser: Callable[[str], object] = _open_browser_off_stdout, + open_browser: Callable[[str], object] = open_browser_off_stdout, ) -> PkceCredential | PkceFailure: if _runs_in_ci(environ): return PkceFailure("the CI environment variable is set, so lite does not open a browser") 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 36bb5a31d3b..949a0321f75 100644 --- a/tests/unit/proxy/client/cli/test_auto_sign_in.py +++ b/tests/unit/proxy/client/cli/test_auto_sign_in.py @@ -10,7 +10,7 @@ from click.testing import CliRunner, Result 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 pkce_browser_sign_in +from litellm.proxy.client.cli.commands.auto_sign_in import open_browser_off_stdout, pkce_browser_sign_in from litellm.proxy.client.cli.commands.pkce_login import PkceCredential, PkceFailure, pkce_token_record BASE_URL: Final = "https://proxy.example.com" @@ -215,6 +215,19 @@ def test_a_browser_the_user_picked_starts_the_sign_in_and_names_how_long_it_wait ] +def test_the_browser_launcher_keeps_stdout_clean_and_never_rings_the_terminal_bell( + capfd: pytest.CaptureFixture[str], monkeypatch: pytest.MonkeyPatch, tmp_path: Path +): + chatty_browser = tmp_path / "chatty-browser" + chatty_browser.write_text('#!/bin/sh\necho "Opening in existing browser session."\n') + chatty_browser.chmod(0o755) + monkeypatch.setenv("BROWSER", str(chatty_browser)) + + open_browser_off_stdout(f"{BASE_URL}/v1/cli/authorize?state=fake") + + assert capfd.readouterr() == ("", "Opening in existing browser session.\n") + + @pytest.mark.parametrize( ("command", "method", "path", "body"), [