flexigo-support-bot / tests /test_security.py
victor34593993's picture
Release 2026-06-15/16: B2 billing-orphan fix + demo conversion (B1/B3/B4/B5) + conversation history (72h) + per-tenant teach-the-bot + onboarding videos
4778987 verified
Raw
History Blame
1.89 kB
"""Security hardening: refuse the default signing key in prod; throttle /chat."""
from __future__ import annotations
from types import SimpleNamespace
import pytest
from app.main import _check_security
from app.routes import chat
def _settings(**over):
base = dict(testing=False, admin_token="tok", secret_key="a-real-strong-key")
base.update(over)
return SimpleNamespace(**base)
def test_default_secret_key_refuses_to_boot_in_prod():
with pytest.raises(RuntimeError, match="SECRET_KEY"):
_check_security(_settings(secret_key="dev-insecure-change-me"))
def test_strong_secret_key_boots():
_check_security(_settings()) # no raise
def test_testing_mode_skips_the_guard():
# tests run with the default key; testing=True must never crash them
_check_security(_settings(testing=True, secret_key="dev-insecure-change-me"))
# ---- /chat rate limit ----
def _req(ip="1.2.3.4"):
return SimpleNamespace(headers={"x-forwarded-for": ip}, client=SimpleNamespace(host=ip))
def test_chat_rate_limit_blocks_after_burst(monkeypatch):
# fresh limiter so other tests don't pollute the window
from app.ratelimit import RateLimiter
monkeypatch.setattr(chat, "_chat_limiter", RateLimiter(chat._CHAT_PER_IP_PER_MIN, 60))
req = _req("9.9.9.9")
for _ in range(chat._CHAT_PER_IP_PER_MIN):
chat._enforce_chat_rate(req) # allowed
with pytest.raises(Exception) as ei:
chat._enforce_chat_rate(req) # one over -> 429
assert getattr(ei.value, "status_code", None) == 429
def test_chat_rate_limit_is_per_ip(monkeypatch):
from app.ratelimit import RateLimiter
monkeypatch.setattr(chat, "_chat_limiter", RateLimiter(2, 60))
chat._enforce_chat_rate(_req("1.1.1.1"))
chat._enforce_chat_rate(_req("1.1.1.1"))
# a different IP still has its own fresh budget
chat._enforce_chat_rate(_req("2.2.2.2"))