QUA-001, volet dialecte.
`postgresql://` ne veut pas dire "le pilote installe" : SQLAlchemy y lit
psycopg2 et importe ce module a la creation du moteur. requirements.txt
epingle psycopg 3 (`psycopg[binary]`) et pas psycopg2. Une installation
propre demarree sur cette URL leve donc
ModuleNotFoundError: No module named 'psycopg2'
avant la premiere requete. Verifie dans le .venv du depot, et c est
exactement la forme que Render distribue -- celle que docs/deployment.md et
docs/database-restore.md donnaient en exemple.
normalise_database_url() nomme le pilote quand l URL n en nomme pas.
`postgres://` (alias hérite, abandonne par SQLAlchemy en 1.4) est traite de
meme. Une URL qui nomme deja son pilote est laissee telle quelle, y compris
`postgresql+psycopg2://` : un environnement qui a psycopg2 garde le choix.
La normalisation a lieu apres l application de la configuration passee en
argument, pour couvrir aussi les appels de test. backup.py n avait pas
besoin d etre touche : il retirait deja le suffixe +pilote.
Documentation alignee sur les trois fichiers qui donnaient l exemple, dont
docs/deployment.md qui proposait sqlite:/// pour DATABASE_URL alors que
create_app refuse de demarrer sans PostgreSQL.
Reste de QUA-001, dit franchement
- les trois paquets parasites (dotenv, login, discord) ne sont plus dans
requirements.txt : deja retires. psycopg est deja epingle.
- la consolidation vers des groupes de dependances n est PAS faite. Le
deploiement est un miroir de fichiers lftp sans etape de construction ;
les groupes PEP 735 demandent pip >= 25.1 sur une machine dont on ne
peut pas verifier la version d ici. A revoir avec OPS-011.
14 tests, dont trois qui prouvent que l echec est reel et non theorique.
Co-Authored-By: Claude Opus 5 <[email protected]>
Il n'existait aucun test, et le code n'offrait aucune prise pour en ecrire :
create_app() exigeait SECRET_KEY et DATABASE_URL dans l'environnement,
creait les tables et demarrait un bot Discord. C'etait la cause, pas le
symptome.
create_app(config=None)
Les valeurs par defaut viennent toujours de l'environnement, les
surcharges de l'appelant sont appliquees ensuite, et la validation
vient en dernier pour qu'un test puisse fournir les siennes. Deux
effets de bord passent sous drapeau, actifs par defaut pour que la
production et le developpement se comportent a l'identique :
AUTO_CREATE_TABLES controle db.create_all()
ENABLE_DISCORD_BOT controle start_bot()
FORCE_HTTPS passe egalement en configuration : lu via os.getenv a
chaque requete, il renvoyait un 301 sur tout appel de test.
Suite de tests : 47 tests, 3 xfail, 32 % de couverture.
tests/conftest.py fabriques par role, connexion par le vrai
formulaire, base SQLite temporaire
test_auth_session.py expiration de session, desactivation de
compte, deconnexion
test_security_headers.py en-tetes, non-divulgation sur /health,
echappement de nl2br
test_authorization.py acces anonyme, vertical, horizontal,
validation des entrees, CSRF
Les tests marques xfail(strict=True) decrivent des constats non encore
corriges. Ils echouent par construction ; le mode strict transforme une
reussite inattendue en echec, ce qui signale qu'il faut retirer le
marqueur. Trois subsistent : enumeration de comptes (SEC-AUTH-006), CSP
unsafe-inline (SEC-WEB-001), auto-retrogradation du dernier administrateur
(SEC-AUTHZ-007).
pyproject.toml
Configuration pytest et ruff. Ruff n'avait aucune configuration : la CI
l'executait avec le jeu de regles par defaut. Les 33 F401 de
app/models/__init__.py sont ignores par fichier, c'est une facade de
re-export intentionnelle.
requirements-dev.txt separe l'outillage de test des dependances de
production.
Co-Authored-By: Claude Opus 5 <[email protected]>