System checks (tempest check-config)¶
Valide a configuração antes de servir tráfego — segredo de assinatura
vazio, CORS * com credenciais, SQLite em produção. Um framework de
checks no estilo Django: funções que inspecionam suas settings e emitem
mensagens; a CLI (ou um hook de startup) roda todas e falha se alguma for
séria.
O problema¶
Um deploy com JWT_SECRET vazio sobe feliz e só quebra (ou pior, aceita
tokens forjados) em produção. Erros de config não aparecem nos testes —
eles dependem do ambiente. Faltava um lugar para declarar "isto tem que
ser verdade pra subir".
Rodando os checks embutidos¶
A SDK já traz checks para os deslizes mais comuns. Rode contra as settings do projeto:
A CLI auto-detecta o objeto de settings em locais convencionais
(src.core.settings:settings, app.core.settings:settings, …). Aponte
manualmente quando precisar:
Saída típica:
WARNING: (security.W001) JWT_SECRET is empty — token verification is effectively disabled.
HINT: Set a random secret in production (dev-only when empty).
INFO: (deployment.I001) DEBUG is enabled.
HINT: Ensure DEBUG is off in production (it leaks internals).
2 message(s), 0 at/above ERROR.
Sai com código ≠ 0 quando alguma mensagem atinge o --fail-level
(padrão error) — então serve como gate de CI e checagem pré-deploy.
Suba a régua para tratar avisos como bloqueio:
Checks embutidos (todos best-effort — pulam silenciosamente quando o atributo não existe nas suas settings):
| id | Nível | O quê |
|---|---|---|
security.W001 / W002 |
WARNING | JWT_SECRET / SECRET_KEY / TOKEN_SECRET vazio ou < 32 chars |
security.W003 |
WARNING | CORS * com credenciais |
database.W001 |
WARNING | DATABASE_URL SQLite com DEBUG desligado |
deployment.I001 |
INFO | DEBUG ligado |
deployment.I002 |
INFO | bind em 0.0.0.0 |
Escrevendo o seu check¶
Um check é uma função que recebe o contexto (suas settings) e devolve
mensagens. Decore com @check:
from tempest_fastapi_sdk.checks import check, error, CheckMessage
@check("security")
def stripe_key_present(settings: object) -> list[CheckMessage]:
"""Falha o deploy se a chave da Stripe não estiver configurada."""
if not getattr(settings, "STRIPE_API_KEY", ""):
return [
error(
"STRIPE_API_KEY is not set.",
hint="Export it before deploying the billing service.",
id="billing.E001",
)
]
return []
Os construtores debug / info / warning / error / critical
montam a CheckMessage com o nível certo. A tag ("security") permite
rodar um subconjunto:
Checks precisam ser importados para registrar
O @check registra no import do módulo. A CLI importa suas settings
(e o que elas importarem), então checks definidos junto das settings
carregam sozinhos. Para módulos soltos, use --import:
Falhando rápido no startup¶
Rode os checks no lifespan para um deploy mal-configurado não servir tráfego:
from contextlib import asynccontextmanager
from collections.abc import AsyncGenerator
from fastapi import FastAPI
from tempest_fastapi_sdk.checks import run_system_checks, SystemCheckError
from src.core.settings import settings
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
try:
run_system_checks(settings) # levanta em ERROR+
except SystemCheckError as exc:
# logue exc.messages e aborte o boot
raise
yield
run_system_checks levanta SystemCheckError quando alguma mensagem
atinge o fail_level (padrão ERROR); run_checks faz o mesmo mas só
devolve a lista, sem levantar.
Recap¶
tempest check-configroda os checks contra suas settings; sai ≠ 0 no--fail-level(padrãoerror).- Embutidos cobrem segredo, CORS, SQLite-em-prod, DEBUG, bind.
@check("tag")registra o seu;debug/info/warning/error/criticalmontam a mensagem.run_system_checks(settings)no lifespan aborta um boot mal-configurado.