Cobre o caminho completo sem depender da VPS estar no ar: cifra com uma chave de teste descartavel, troca a chave do app por monkeypatch e exercita a rota. 8 casos: recusa sem token e com token errado; caminho feliz; envelope adulterado (o GCM tem que estourar, nao passar); cifrado com outra chave; payload fora do contrato (422, nao 200 nem 500); e dois travando o contrato com a API da VPS — se o PayloadCompras dos dois lados divergir, quebra aqui em vez de em producao. Fixtures em tests/fixtures/: par de chaves so pra teste, o payload real do Holmes e o payload ja tratado. O .gitignore abre excecao estreita pra tests/fixtures/*.pem — chave real continua barrada. Tambem: - 422 passa a usar HTTP_422_UNPROCESSABLE_CONTENT (o _ENTITY deprecou) - app/services/holmes.py removido: o conector nao fala com o Holmes - app/utils/cesar.py entra como veio Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
56 lines
2 KiB
Python
56 lines
2 KiB
Python
import logging
|
|
|
|
from app.config import settings
|
|
from app.schemas import Envelope, PayloadCompras
|
|
from app.seguranca import autorizar
|
|
from app.services import cripto
|
|
from fastapi import APIRouter, Depends, HTTPException, status
|
|
from pydantic import ValidationError
|
|
|
|
router = APIRouter(prefix="/compras", tags=["compras"])
|
|
|
|
# Carregada uma vez no import: parsear PEM a cada request e desperdicio.
|
|
_CHAVE = cripto.carregar_chave_privada(settings.vps.chave_privada)
|
|
|
|
|
|
@router.post("/dados", dependencies=[Depends(autorizar)])
|
|
async def receber_compras(envelope: Envelope) -> dict:
|
|
"""
|
|
Recebe o envelope cifrado da API da VPS, abre e valida.
|
|
|
|
Fase atual: so registra o que chegou. O INSERT no Oracle entra depois —
|
|
quando entrar, tem que ser MERGE por id_processo, senao reentrega de
|
|
webhook duplica linha.
|
|
"""
|
|
try:
|
|
bruto = cripto.descriptografar(envelope.model_dump(), _CHAVE)
|
|
except Exception as e:
|
|
# Chave errada, envelope adulterado ou algoritmo diferente.
|
|
logging.error(f"Falha ao abrir envelope: {type(e).__name__}: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST, detail="envelope invalido"
|
|
)
|
|
|
|
try:
|
|
dados = PayloadCompras.model_validate(bruto)
|
|
except ValidationError as e:
|
|
# Decifrou mas o formato mudou: os dois lados sairam de sincronia.
|
|
logging.error(f"Payload fora do contrato: {e}")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
|
|
detail="payload nao bate com o contrato esperado",
|
|
)
|
|
|
|
logging.info(
|
|
f"Compra recebida | processo={dados.id_processo} "
|
|
f"protocolo={dados.protocolo} cnpj={dados.cnpj} "
|
|
f"pedido={dados.pedido_linx} total={dados.valor_total} "
|
|
f"parcelas={len(dados.parcelas)}"
|
|
)
|
|
|
|
return {
|
|
"status": "recebido",
|
|
"id_processo": dados.id_processo,
|
|
"parcelas": len(dados.parcelas),
|
|
"persistido": False, # vira True quando o Oracle entrar
|
|
}
|