fix(cli): read a 401 body only as UTF-8 and print nothing from any other body
Some checks failed
Cost map pins recheck / rerun-cost-map-guard (push) Has been cancelled
LiteLLM Rust DB / db-queries (push) Has been cancelled
LiteLLM Rust / rust-lint (push) Has been cancelled
LiteLLM Rust / rust-test (push) Has been cancelled
LiteLLM Rust / rust-wheel (push) Has been cancelled
Terraform Provider / gofmt, vet, build, test (push) Has been cancelled
Terraform Provider / Provider endpoints vs proxy OpenAPI schema (push) Has been cancelled

The fallback to the declared charset crashed on a NUL in the charset name, and a stray Shift_JIS lead byte swallowed the first letter of a key so redaction missed it. Reading only UTF-8 avoids both. A body in another charset now shows the HTTP error text
This commit is contained in:
mateo-berri 2026-10-30 15:06:58 -07:00
parent b827c19110
commit 669614c032
2 changed files with 26 additions and 42 deletions

View file

@ -216,24 +216,10 @@ def _displayable(text: str) -> str:
return "" if _UNPRINTABLE_CHARACTERS.search(normalized) else redact_string(normalized)
def _text_in_declared_charset(response: requests.Response) -> str:
try:
return response.text
except UnicodeError:
return ""
def _response_text(response: requests.Response) -> str:
try:
return response.content.decode("utf-8")
except UnicodeDecodeError:
return _text_in_declared_charset(response)
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(response) if response is not None else ""
body: Final = response.content.decode("utf-8", errors="replace") if response is not None else ""
reason: Final = _displayable(body) or _displayable(str(error)) or _NO_PROXY_REASON
return reason if len(reason) <= _PROXY_REASON_CHARS else f"{reason[:_PROXY_REASON_CHARS]}..."

View file

@ -749,40 +749,37 @@ def test_a_utf8_401_body_with_no_charset_prints_as_written(
@pytest.mark.parametrize(
"reason, charset",
"content, charset",
[
("caf\u00e9", "iso-8859-1"),
("the key\u2019s owner", "windows-1252"),
("\u65e5\u672c", "shift_jis"),
("refused", "utf-16"),
(b"forbidden \xff\xfe", "utf-8"),
(b"forbidden \xff\xfe", "undefined"),
(b"forbidden \xff\xfe", "idna"),
(b"forbidden \xff\xfe", "bad\x00name"),
("forbidden caf\u00e9".encode("iso-8859-1"), "iso-8859-1"),
("forbidden \u2019".encode("windows-1252"), "windows-1252"),
("forbidden \u65e5\u672c".encode("shift_jis"), "shift_jis"),
("forbidden".encode("utf-16"), "utf-16"),
(f"forbidden \x81sk-{FAKE_SECRET}".encode("latin-1"), "shift_jis"),
],
ids=[
"stray_bytes_in_utf8",
"undefined_charset",
"idna_charset",
"nul_in_the_charset_name",
"latin1",
"windows_1252",
"shift_jis",
"utf16",
"lead_byte_before_a_key",
],
)
def test_a_401_body_in_a_declared_charset_prints_as_written(
requests_mock: Mocker, secret_vault_factory: type[FakeSecretVault], reason: str, charset: str
def test_a_401_body_that_is_not_utf8_is_never_printed(
requests_mock: Mocker, secret_vault_factory: type[FakeSecretVault], content: bytes, charset: str
) -> None:
requests_mock.post(
f"{BASE_URL}/key/generate",
status_code=401,
content=reason.encode(charset),
headers={"Content-Type": f"text/plain; charset={charset}"},
)
result: Final = _lite(
["keys", "generate"], secret_vault_factory(), FakeBrowserSignIn(_credential()), ["--api-key", "sk-explicit"]
)
assert result.exit_code == 1
assert f"The proxy said: {reason}" in result.stderr
@pytest.mark.parametrize("charset", ["utf-8", "undefined", "idna"])
def test_a_401_body_its_charset_cannot_read_is_never_printed(
requests_mock: Mocker, secret_vault_factory: type[FakeSecretVault], charset: str
) -> None:
requests_mock.post(
f"{BASE_URL}/key/generate",
status_code=401,
content=b"forbidden \xff\xfe",
content=content,
headers={"Content-Type": f"text/plain; charset={charset}"},
)
@ -795,6 +792,7 @@ def test_a_401_body_its_charset_cannot_read_is_never_printed(
assert "The proxy said: " in result.stderr
assert "forbidden" not in result.stderr
assert "\ufffd" not in result.stderr
assert FAKE_SECRET[-8:] not in result.stderr
@pytest.mark.parametrize(