mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-11 03:38:38 +00:00
* feat(proxy): LITELLM_FIPS_MODE startup gate with provider assertion, TLS verify guard and loud password migration Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * refactor(proxy): match ssl_verify off detection to runtime str_to_bool semantics Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * refactor(proxy): drop tautological fips probe test and satisfy CodeQL return checks Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(proxy): inject the fake Prisma client through the module boundary instead of patching _setup_prisma_client Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: yucheng <yucheng@berri.ai> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
106 lines
4.2 KiB
Python
106 lines
4.2 KiB
Python
import pytest
|
|
|
|
from litellm.proxy.common_utils.fips import (
|
|
FipsModeError,
|
|
FipsModeOff,
|
|
FipsModeOn,
|
|
MalformedFipsMode,
|
|
ProviderDoesNotEnforceFips,
|
|
TlsVerificationDisabled,
|
|
enforce_fips_boot_verdict,
|
|
fips_boot_verdict,
|
|
is_fips_mode,
|
|
parse_fips_mode,
|
|
)
|
|
|
|
|
|
def _verdict(
|
|
raw: str | None,
|
|
*,
|
|
enforcing: bool = True,
|
|
ssl_env: str | None = None,
|
|
ssl_setting: object = True,
|
|
):
|
|
return fips_boot_verdict(
|
|
raw_fips_mode=raw,
|
|
provider_enforces_fips=lambda: enforcing,
|
|
ssl_verify_environment=ssl_env,
|
|
ssl_verify_setting=ssl_setting,
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("raw", [None, "false", "0", "no", "off", "", " False "])
|
|
def test_unset_and_false_spellings_leave_fips_mode_off(raw):
|
|
assert parse_fips_mode(raw) == FipsModeOff()
|
|
assert is_fips_mode({"LITELLM_FIPS_MODE": raw}.get) is False
|
|
|
|
|
|
@pytest.mark.parametrize("raw", ["true", "1", "yes", "on", " TRUE "])
|
|
def test_true_spellings_turn_fips_mode_on(raw):
|
|
assert parse_fips_mode(raw) == FipsModeOn()
|
|
assert is_fips_mode({"LITELLM_FIPS_MODE": raw}.get) is True
|
|
|
|
|
|
@pytest.mark.parametrize("raw", ["enforced", "2", "strict", "yes please"])
|
|
def test_anything_else_is_malformed_and_refused_with_the_offending_value(raw):
|
|
assert parse_fips_mode(raw) == MalformedFipsMode(value=raw)
|
|
with pytest.raises(FipsModeError) as refused:
|
|
enforce_fips_boot_verdict(_verdict(raw, enforcing=False), announce=lambda _: None)
|
|
assert f"LITELLM_FIPS_MODE={raw} is not a boolean" in str(refused.value)
|
|
assert "true or false" in str(refused.value)
|
|
|
|
|
|
def test_off_never_consults_the_provider_or_tls_settings():
|
|
def explode() -> bool:
|
|
raise AssertionError("provider probe must not run while FIPS mode is off")
|
|
|
|
verdict = fips_boot_verdict(
|
|
raw_fips_mode=None, provider_enforces_fips=explode, ssl_verify_environment="false", ssl_verify_setting=False
|
|
)
|
|
assert verdict == FipsModeOff()
|
|
enforce_fips_boot_verdict(verdict, announce=lambda _: pytest.fail("nothing to announce when off"))
|
|
|
|
|
|
def test_on_with_an_enforcing_provider_and_verified_tls_boots():
|
|
verdict = _verdict("true", enforcing=True, ssl_env="true", ssl_setting="/etc/ssl/certs/ca.pem")
|
|
assert verdict == FipsModeOn()
|
|
enforce_fips_boot_verdict(verdict, announce=lambda _: pytest.fail("nothing to announce when on"))
|
|
|
|
|
|
def test_on_with_a_non_enforcing_provider_is_refused_and_names_the_fix():
|
|
announced = []
|
|
with pytest.raises(FipsModeError) as refused:
|
|
enforce_fips_boot_verdict(_verdict("true", enforcing=False), announce=announced.append)
|
|
message = str(refused.value)
|
|
assert message.startswith("LiteLLM proxy refused to start")
|
|
assert "LITELLM_FIPS_MODE is on but this Python does not enforce FIPS" in message
|
|
assert "FIPS image" in message
|
|
assert announced == [f"\n{message}\n\n"]
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"ssl_env, ssl_setting, sources",
|
|
[
|
|
("false", True, ("SSL_VERIFY",)),
|
|
(" FALSE ", True, ("SSL_VERIFY",)),
|
|
(None, False, ("litellm_settings.ssl_verify",)),
|
|
(None, "False", ("litellm_settings.ssl_verify",)),
|
|
("false", False, ("SSL_VERIFY", "litellm_settings.ssl_verify")),
|
|
],
|
|
)
|
|
def test_disabled_tls_verification_is_refused_naming_every_source(ssl_env, ssl_setting, sources):
|
|
verdict = _verdict("true", enforcing=True, ssl_env=ssl_env, ssl_setting=ssl_setting)
|
|
assert verdict == TlsVerificationDisabled(sources=sources)
|
|
with pytest.raises(FipsModeError) as refused:
|
|
enforce_fips_boot_verdict(verdict, announce=lambda _: None)
|
|
assert "TLS certificate verification is disabled by " + " and ".join(sources) in str(refused.value)
|
|
|
|
|
|
@pytest.mark.parametrize("ssl_setting", [True, "true", "/etc/ssl/certs/ca.pem", None, "", "0", "no"])
|
|
def test_verified_or_custom_bundle_tls_settings_are_not_treated_as_disabled(ssl_setting):
|
|
assert _verdict("true", enforcing=True, ssl_setting=ssl_setting) == FipsModeOn()
|
|
|
|
|
|
def test_disabled_tls_is_reported_before_the_provider_so_operators_see_config_mistakes_first():
|
|
assert _verdict("true", enforcing=False, ssl_env="false") == TlsVerificationDisabled(sources=("SSL_VERIFY",))
|
|
assert _verdict("true", enforcing=False) == ProviderDoesNotEnforceFips()
|