Search providers resolved the server-configured API key (e.g.
get_secret_str("SERPER_API_KEY")) in validate_environment whenever the
caller omitted api_key, while get_complete_url independently honored a
caller-supplied api_base. A caller who passes their own api_base and no
api_key therefore made the proxy send the operator's provider key to a
host they control; POST /search_tools/test_connection forwards
request-body api_base/api_key straight into asearch, so any authenticated
user could exfiltrate the server's search credentials.
Add a shared host-aware fallback in BaseSearchConfig.resolve_server_api_key
that only applies a server-managed secret when the caller-supplied
api_base is absent or resolves to a trusted host (the provider default or
the operator's own *_API_BASE env override); otherwise it refuses and asks
for an explicit api_key. The guard only triggers when a server secret
actually exists, so keyless and self-hosted providers (searxng, you.com
free tier) keep working. Every provider that carries a server secret is
migrated to the helper; dataforseo reuses the same guard for its
login:password basic-auth credentials.
This changes behavior for callers that previously passed a per-request
api_base while relying on a server-configured key: they must now pass an
explicit api_key, or the operator must configure the base via the
provider's *_API_BASE env var (which stays trusted).
* feat(search): add TinyFish as search provider
Adds TinyFish web search (GET https://api.search.tinyfish.ai) as the
16th search provider in LiteLLM. Follows the BaseSearchConfig pattern
used by other GET-based providers like Brave.
Includes unit tests in tests/test_litellm/ for full patch coverage.
* fix(search/tinyfish): use concrete types to pass any-discipline and ruff UP006/UP045
Replace typing.Dict/List/Optional/Union with modern syntax (dict, list,
X | None) and use concrete type parameters (dict[str, str] for headers,
dict[str, object] for params) to eliminate LIT009 Any-discipline
violations. Move _append_domain_filters to module level to avoid leaking
Any through self.
* fix(search/tinyfish): eliminate Any-typed values for any-discipline gate
Use Pydantic BaseModel and TypeAdapter at httpx/base-class boundaries
to validate untyped inputs (json(), params.get(), bare set). Three
genuine external boundaries annotated with any-ok.
* style: fix black formatting for long line
* fix(search/tinyfish): move any-ok comment to violation line for any-discipline gate
The any-discipline checker matches `# any-ok` comments by line number.
The comment was on the closing-paren line (127) but the violation was
on the call-expression line (126), so the suppression did not apply.
* fix(search/tinyfish): align with approved PR #30158
Drop explicit AND from domain filter query to match the approved
implementation. Set pricing to zero. Rename test to match behavior.