Конфиг: fail-fast на дефолтных секретах в production

model_validator в Settings: при APP_ENV=production приложение не стартует, если
SECRET_KEY дефолтный/короче 32 символов или (при включённом бутстрапе) ADMIN_PASSWORD
дефолтный/пустой. dev/test не затронуты — там дефолты остаются нормой. #59

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfTsytzT6TojfmprRDKiV6
This commit is contained in:
2026-09-13 17:18:08 +03:00
co-authored by Claude Opus 4.8
parent 112b583264
commit 0799aee684
2 changed files with 101 additions and 2 deletions
+67
View File
@@ -0,0 +1,67 @@
"""Fail-fast конфигурации: production не стартует с дефолтными секретами (#59, F4)."""
from __future__ import annotations
import pytest
from pydantic import ValidationError
from app.core import config
_STRONG_SECRET = "k" * 40
_STRONG_ADMIN_PW = "a-strong-admin-password"
def test_production_rejects_default_secret_key():
with pytest.raises(ValidationError):
config.Settings(
app_env="production",
secret_key=config._DEFAULT_SECRET_KEY,
admin_password=_STRONG_ADMIN_PW,
)
def test_production_rejects_short_secret_key():
with pytest.raises(ValidationError):
config.Settings(
app_env="production",
secret_key="too-short",
admin_password=_STRONG_ADMIN_PW,
)
def test_production_rejects_default_admin_password():
with pytest.raises(ValidationError):
config.Settings(
app_env="production",
secret_key=_STRONG_SECRET,
admin_bootstrap_enabled=True,
admin_password=config._DEFAULT_ADMIN_PASSWORD,
)
def test_production_accepts_strong_secrets():
s = config.Settings(
app_env="production",
secret_key=_STRONG_SECRET,
admin_password=_STRONG_ADMIN_PW,
)
assert s.is_production
def test_production_skips_admin_check_when_bootstrap_disabled():
# Админ управляется вручную (bootstrap off) — дефолтный ADMIN_PASSWORD не блокирует старт.
s = config.Settings(
app_env="production",
secret_key=_STRONG_SECRET,
admin_bootstrap_enabled=False,
admin_password=config._DEFAULT_ADMIN_PASSWORD,
)
assert s.is_production
def test_development_allows_defaults():
s = config.Settings(
app_env="development",
secret_key=config._DEFAULT_SECRET_KEY,
admin_password=config._DEFAULT_ADMIN_PASSWORD,
)
assert s.is_development