mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-12 23:01:41 +00:00
fix(cli): only guard the default settings.json with the lite up and autoroute backups on login --config-claude
This commit is contained in:
parent
b554d79914
commit
b3f2de058b
3 changed files with 40 additions and 7 deletions
|
|
@ -41,9 +41,9 @@ from litellm.litellm_core_utils.cli_token_utils import (
|
|||
)
|
||||
|
||||
from .claude_settings import (
|
||||
SETTINGS_FILE_OWNERS,
|
||||
ClaudeSettingsError,
|
||||
claude_settings_path,
|
||||
settings_file_owners,
|
||||
write_claude_settings,
|
||||
)
|
||||
from .pkce_login import (
|
||||
|
|
@ -782,7 +782,7 @@ def _configure_claude_code(base_url: str) -> None:
|
|||
"""Point Claude Code at base_url by patching the settings.json it reads."""
|
||||
settings_path: Final = claude_settings_path(os.environ)
|
||||
try:
|
||||
write_claude_settings(base_url, settings_path, SETTINGS_FILE_OWNERS)
|
||||
write_claude_settings(base_url, settings_path, settings_file_owners(settings_path))
|
||||
except ClaudeSettingsError as e:
|
||||
raise click.ClickException(f"Logged in, but could not configure Claude Code: {e}")
|
||||
click.echo(f"\nConfigured Claude Code: {settings_path} now routes through {base_url.rstrip('/')}.")
|
||||
|
|
|
|||
|
|
@ -64,6 +64,11 @@ def claude_settings_path(environ: Mapping[str, str]) -> Path:
|
|||
return Path(config_dir).expanduser() / "settings.json"
|
||||
|
||||
|
||||
def settings_file_owners(settings_path: Path) -> tuple[SettingsFileOwner, ...]:
|
||||
"""The commands whose backups guard settings_path: `lite up` and `lite autoroute up` only ever manage the default file."""
|
||||
return SETTINGS_FILE_OWNERS if settings_path == CLAUDE_SETTINGS_PATH else ()
|
||||
|
||||
|
||||
def load_json_or_empty(path: Path) -> dict[str, JsonValue]:
|
||||
try:
|
||||
content: Final = path.read_bytes() if path.exists() else b""
|
||||
|
|
@ -197,5 +202,6 @@ __all__ = (
|
|||
"load_json_or_empty",
|
||||
"merge_claude_settings",
|
||||
"resolve_api_key_helper",
|
||||
"settings_file_owners",
|
||||
"write_claude_settings",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1398,9 +1398,10 @@ class TestLoginConfigClaude:
|
|||
def setup_method(self):
|
||||
self.runner = CliRunner()
|
||||
|
||||
def _run_login(self, tmp_path, args, base_url="https://test.example.com"):
|
||||
def _run_login(self, tmp_path, args, base_url="https://test.example.com", *, config_dir_env=None):
|
||||
settings_path = tmp_path / "claude" / "settings.json"
|
||||
backup_path = tmp_path / "claude_settings_backup.json"
|
||||
env = {"CLAUDE_CONFIG_DIR": str(settings_path.parent)} if config_dir_env is None else config_dir_env
|
||||
poll_response = Mock()
|
||||
poll_response.status_code = 200
|
||||
poll_response.json.return_value = {
|
||||
|
|
@ -1417,17 +1418,19 @@ class TestLoginConfigClaude:
|
|||
patch("litellm.proxy.client.cli.commands.auth.save_cli_token"),
|
||||
patch("litellm.proxy.client.cli.interface.show_commands"),
|
||||
patch(
|
||||
"litellm.proxy.client.cli.commands.auth.SETTINGS_FILE_OWNERS",
|
||||
"litellm.proxy.client.cli.commands.claude_settings.SETTINGS_FILE_OWNERS",
|
||||
(SettingsFileOwner(backup_path, "lite up", "lite down"),),
|
||||
),
|
||||
patch(
|
||||
"litellm.proxy.client.cli.commands.claude_settings.CLAUDE_SETTINGS_PATH",
|
||||
tmp_path / "default-home" / ".claude" / "settings.json",
|
||||
),
|
||||
patch(
|
||||
"litellm.proxy.client.cli.commands.claude_settings.shutil.which",
|
||||
return_value="/usr/local/bin/lite",
|
||||
),
|
||||
):
|
||||
result = self.runner.invoke(
|
||||
login, args, obj={"base_url": base_url}, env={"CLAUDE_CONFIG_DIR": str(settings_path.parent)}
|
||||
)
|
||||
result = self.runner.invoke(login, args, obj={"base_url": base_url}, env=env)
|
||||
return result, settings_path, backup_path
|
||||
|
||||
def test_default_login_does_not_touch_claude_settings(self, tmp_path):
|
||||
|
|
@ -1460,6 +1463,30 @@ class TestLoginConfigClaude:
|
|||
assert written["theme"] == "dark"
|
||||
assert written["env"]["KEEP"] == "me"
|
||||
|
||||
def test_flag_refuses_while_lite_up_holds_the_default_settings_file(self, tmp_path):
|
||||
default_settings_path = tmp_path / "default-home" / ".claude" / "settings.json"
|
||||
(tmp_path / "claude_settings_backup.json").write_text("{}")
|
||||
|
||||
result, _settings_path, _backup_path = self._run_login(
|
||||
tmp_path, ["--config-claude"], config_dir_env={"CLAUDE_CONFIG_DIR": ""}
|
||||
)
|
||||
|
||||
assert result.exit_code != 0
|
||||
assert "Login successful!" in result.output
|
||||
assert "`lite up` is currently managing" in result.output
|
||||
assert "Run `lite down` first" in result.output
|
||||
assert not default_settings_path.exists()
|
||||
|
||||
def test_flag_writes_an_alternate_config_dir_even_while_lite_up_holds_the_default_file(self, tmp_path):
|
||||
(tmp_path / "claude_settings_backup.json").write_text("{}")
|
||||
|
||||
result, settings_path, _backup_path = self._run_login(tmp_path, ["--config-claude"])
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
written = json.loads(settings_path.read_text())
|
||||
assert written["apiKeyHelper"] == "/usr/local/bin/lite --base-url https://test.example.com auth print-token"
|
||||
assert f"Configured Claude Code: {settings_path} now routes through https://test.example.com." in result.output
|
||||
|
||||
def test_settings_failure_is_reported_without_claiming_login_failed(self, tmp_path):
|
||||
settings_path = tmp_path / "claude" / "settings.json"
|
||||
settings_path.parent.mkdir(parents=True)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue