mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-11 03:38:38 +00:00
fix(clinepass): never borrow the global litellm.api_key for chat
_complete_clinepass fell back to litellm.api_key when no ClinePass credential was configured, so a caller's general-purpose (usually OpenAI) key was sent to the Cline host as a Bearer token. get_llm_provider already resolves the key without that fallback; use what it resolved. Adds a regression test that asserts the sentinel key never leaves the process, and checks the request actually reached the transport so it cannot pass vacuously. Also suppress three basedpyright reportUnknownArgumentType diagnostics this change introduced (the untyped model cost map key and the dispatch context's messages/headers), which tipped the per-rule budget by +3. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
0e756bf0f8
commit
abadd88dbe
3 changed files with 31 additions and 4 deletions
|
|
@ -868,7 +868,7 @@ def _populate_provider_model_sets(model_cost_map: Dict) -> None:
|
|||
elif value.get("litellm_provider") == "deepseek":
|
||||
deepseek_models.add(key)
|
||||
elif value.get("litellm_provider") == "clinepass":
|
||||
clinepass_models.add(key)
|
||||
clinepass_models.add(key) # pyright: ignore[reportUnknownArgumentType] # key comes from the untyped model cost map
|
||||
elif value.get("litellm_provider") == "tencent":
|
||||
tencent_models.add(key)
|
||||
elif value.get("litellm_provider") == "runwayml":
|
||||
|
|
|
|||
|
|
@ -2466,15 +2466,15 @@ def _complete_clinepass(ctx: _CompletionDispatchContext) -> _CompletionDispatchR
|
|||
stream: Final = ctx.stream
|
||||
timeout: Final = ctx.timeout
|
||||
|
||||
api_key = api_key or get_secret_str("CLINEPASS_API_KEY") or litellm.api_key
|
||||
api_key = api_key or get_secret_str("CLINEPASS_API_KEY")
|
||||
|
||||
api_base = api_base or litellm.api_base or get_secret_str("CLINEPASS_API_BASE") or "https://api.cline.bot/api/v1"
|
||||
|
||||
## COMPLETION CALL
|
||||
response: Final = base_llm_http_handler.completion(
|
||||
model=model,
|
||||
messages=messages,
|
||||
headers=headers,
|
||||
messages=messages, # pyright: ignore[reportUnknownArgumentType] # ctx.messages is list[Unknown]
|
||||
headers=headers, # pyright: ignore[reportUnknownArgumentType] # ctx.headers is dict[Unknown, Unknown]
|
||||
model_response=model_response,
|
||||
api_key=api_key,
|
||||
api_base=api_base,
|
||||
|
|
|
|||
|
|
@ -125,3 +125,30 @@ def test_unknown_kwargs_are_flattened_not_wrapped_in_extra_body():
|
|||
|
||||
assert "extra_body" not in params
|
||||
assert params["some_vendor_knob"] == 7
|
||||
|
||||
|
||||
def test_chat_does_not_fall_back_to_the_global_litellm_api_key(monkeypatch):
|
||||
"""`litellm.api_key` is the caller's general-purpose (usually OpenAI) key.
|
||||
|
||||
With no ClinePass credential configured, chat must not borrow it: doing so
|
||||
sends that key to the Cline host as a Bearer token.
|
||||
"""
|
||||
sent: list[tuple[str, str]] = []
|
||||
|
||||
def record_and_stop(self, *args, **kwargs):
|
||||
sent.append((str(kwargs.get("url")), str((kwargs.get("headers") or {}).get("Authorization", ""))))
|
||||
raise RuntimeError("stop before any network I/O")
|
||||
|
||||
monkeypatch.setattr(HTTPHandler, "post", record_and_stop, raising=True)
|
||||
monkeypatch.delenv("CLINEPASS_API_KEY", raising=False)
|
||||
monkeypatch.setattr(litellm, "api_key", SENTINEL_OPENAI_KEY)
|
||||
|
||||
with contextlib.suppress(Exception):
|
||||
litellm.completion(
|
||||
model="clinepass/deepseek-v4-flash",
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
num_retries=0,
|
||||
)
|
||||
|
||||
assert sent, "the chat request never reached the transport, so nothing was checked"
|
||||
assert all(SENTINEL_OPENAI_KEY not in authorization for _, authorization in sent)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue