litellm/tests/unit/proxy/client/cli
zoveki cfddaafe18
fix(cli): end the local login when lite logout cannot check the OS keychain (#50098)
* fix(cli): end the local login when logout cannot check the OS keychain

With no usable keyring, lite logout kept a secret-free token.json as a note
that the keychain went unchecked. Every reader took that note for a live
keychain-backed login, so lite whoami, lite auth print-token, and the bare
lite shell all reported a login the user had just ended, and a keychain that
answered again could pair the note with an earlier login's entry and sign
the machine back in.

Logout now removes token.json whatever the keychain answers. When the
keychain could not be checked and there was a login to end, it records that
in a separate owner-only keychain_unchecked file beside it, written after
the removal so a full disk still has room for it. A repeat logout still
warns while that file is there, and a logout that confirms the keychain is
clean removes it.

* fix(cli): keep warning after a logout the keychain refused to clear

A keychain that will not give up its entry gets the same note as one that
could not be checked, so a later logout made while the keychain is out of
reach does not report a clean logout while the credential is still there.

* fix(cli): revoke the login a logout left in an unreachable keychain once it answers

A logout made while the keychain was locked ended the local login and dropped the metadata that pairs with the refresh token still in the keychain, so the next logout had nothing to revoke. The not-cleared note now keeps that record without its secret, and a later logout pairs it with the keychain entry and revokes it before erasing.

* fix(cli): revoke a locked-keychain login on the next login, and only once after a refused erase

A login made after a logout that could not reach the keychain now revokes the
login it replaces, read from the keychain_not_cleared note, as the merge base
did through the kept token.json. A keychain that refused the erase had already
handed that logout the refresh token, so its note no longer pairs with the entry
and the next logout does not revoke the same token again.

* fix(cli): keep the first login revocable after a second locked-keychain logout

A logout whose login kept its secret in token.json never reached the
keychain, so it now leaves the note an earlier logout wrote in place, or
writes an empty one, instead of overwriting it. The first login's refresh
token stays revocable once the keychain answers, and a keychain-less
machine no longer keeps user and team ids in the note.

Also documents the limits that remain in the CLI README and drops the
docstrings from the tests this PR added.

* fix(cli): revoke the keychain's login after a login made while the keychain was locked

* fix(cli): stop lite from reading the stored login before login and logout

The cli group resolved the stored API key before every command, and that read moved a
locked-keychain login's secret over the keychain entry the logout note names, so logout and
login never saw the first login to revoke it.

* fix(cli): keep the login a locked logout left in the keychain revocable

While the keychain still holds the login an earlier logout could not
end, reading the stored login now serves the secret token.json kept and
leaves that keychain entry alone, whatever the login times say. A clock
that stepped back no longer serves the ended login, and commands other
than logout and login no longer move the newer secret over it. A silent
renewal that writes over the entry revokes that login on the proxy.

* fix(cli): keep a login revocable when its note cannot be written, and never block logout on an earlier login's proxy

A locked logout whose note cannot take the login's record now puts token.json back, so the next logout that reaches the keychain still revokes that login, as the base did. A logout that ends both a current login and an earlier one left in the keychain warns when the earlier login's proxy cannot record the revocation, as lite login does, instead of refusing to log out of the current proxy.

* fix(cli): move a locked keychain login's token file into its note instead of putting it back

* fix(cli): never tell a logout to delete the record of a keychain login it could not move aside

A read-only ~/.litellm made the locked-keychain logout say to delete token.json, which would leave the keychain's login unrevoked. It now says the logout did not happen and asks to make the directory writable. The README also says an older lite cannot finish a logout this release started.

---------

Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
2026-11-08 11:17:59 +00:00
..
autoroute test(proxy): move auth, hooks, policy_engine and client tests into tests/unit/proxy (#43998) 2026-10-01 10:11:45 -07:00
__init__.py test(proxy): move auth, hooks, policy_engine and client tests into tests/unit/proxy (#43998) 2026-10-01 10:11:45 -07:00
conftest.py test(proxy): move auth, hooks, policy_engine and client tests into tests/unit/proxy (#43998) 2026-10-01 10:11:45 -07:00
test_agents.py feat(proxy): give Codex accurate model entries for every model in /v1/models (#49825) 2026-11-05 19:31:32 -08:00
test_auth_commands.py fix(cli): end the local login when lite logout cannot check the OS keychain (#50098) 2026-11-08 11:17:59 +00:00
test_chat_commands.py fix(proxy)!: end a chat completions stream with an error event when a guardrail blocks mid-stream (#46953) 2026-10-17 18:00:12 -07:00
test_claude_settings.py perf(cli): start lite without initializing the litellm SDK (#46803) 2026-10-17 04:53:32 +00:00
test_codex_settings.py test(proxy): move auth, hooks, policy_engine and client tests into tests/unit/proxy (#43998) 2026-10-01 10:11:45 -07:00
test_config_commands.py feat(cli): keep the ChatGPT login with lite codex --subscription (#48741) 2026-10-28 05:36:26 -07:00
test_configure_commands.py test(proxy): move auth, hooks, policy_engine and client tests into tests/unit/proxy (#43998) 2026-10-01 10:11:45 -07:00
test_credentials_commands.py perf(cli): start lite without initializing the litellm SDK (#46803) 2026-10-17 04:53:32 +00:00
test_debug_commands.py fix(ui): percent-encode request id in spend log detail URL (#48630) 2026-10-27 13:33:47 -07:00
test_encryption_commands.py refactor(typing): clear 1181 basedpyright Any errors across 431 files (#47789) 2026-10-24 11:31:09 -07:00
test_global_options.py fix(cli): end the local login when lite logout cannot check the OS keychain (#50098) 2026-11-08 11:17:59 +00:00
test_interface.py fix(cli): run group subcommands in the lite shell and default to the logged-in gateway (#46511) 2026-10-14 18:25:34 -07:00
test_keys_commands.py chore(typing): clear 670 basedpyright Any errors by validating provider payloads at the boundary (#45388) 2026-10-13 15:35:23 -07:00
test_model_groups_commands.py test(proxy): move auth, hooks, policy_engine and client tests into tests/unit/proxy (#43998) 2026-10-01 10:11:45 -07:00
test_models_commands.py test(proxy): move auth, hooks, policy_engine and client tests into tests/unit/proxy (#43998) 2026-10-01 10:11:45 -07:00
test_pi.py feat(lite): offer each model group's reasoning efforts in pi, OpenCode and Codex (#48949) 2026-10-29 18:15:44 -07:00
test_pkce_login.py test(proxy): move auth, hooks, policy_engine and client tests into tests/unit/proxy (#43998) 2026-10-01 10:11:45 -07:00
test_statusline_script.py fix(cli): show full-session auto-router cost comparison (#44959) 2026-10-06 16:24:14 -07:00
test_up_commands.py feat(cli): keep the claude.ai login with lite claude --subscription and save pkce in config (#47385) 2026-10-19 15:33:29 -07:00
test_users_commands.py test(proxy): move auth, hooks, policy_engine and client tests into tests/unit/proxy (#43998) 2026-10-01 10:11:45 -07:00