Revue statique de l'ensemble du code Python, de la configuration CI/nginx, du .gitignore et des dependances. 44 constats documentes avec references fichier:ligne, impact et correctif propose. - audit/01-securite.md 19 constats (4 critiques) - audit/02-maintenabilite.md 15 constats - audit/03-standards-stack.md 10 ecarts aux conventions Flask/SQLAlchemy - audit/plan-remediation.md ordre de traitement en 6 lots Points critiques : secrets de production reels committes dans app/.env.exemple, seed automatique en production avec mot de passe password, CORS ouvert a toutes les origines avec credentials par defaut, token du bot Discord imprime sur stdout au demarrage. Aucune modification du code applicatif. Co-Authored-By: Claude Opus 5 <[email protected]>
4.8 KiB
Audit — Team Tryouts
Audit statique de l'application team-tryouts (Flask 3.1 / SQLAlchemy 2.0 / Jinja2 / PostgreSQL).
| Branche | audit/securite-maintenabilite-standards |
| Base | main @ 08f02f7 |
| Date | 2026-08-07 |
| Périmètre | Sécurité · Maintenabilité · Respect des standards de la stack |
| Méthode | Revue de code statique (100 % du code Python, config CI/nginx, .gitignore, dépendances). Aucun test dynamique, aucune exécution de l'app. |
Documents
| Fichier | Contenu |
|---|---|
01-securite.md |
19 constats de sécurité, du critique au faible |
02-maintenabilite.md |
15 constats de maintenabilité et d'outillage |
03-standards-stack.md |
10 écarts aux conventions Flask / SQLAlchemy / 12-factor |
plan-remediation.md |
Ordre de traitement proposé |
Synthèse exécutive
L'application est fonctionnellement riche et le socle est sain sur plusieurs points : ORM utilisé partout (aucune injection SQL), autoescape Jinja2 actif et aucun |safe dans les 40 templates, CSRF activé globalement, hachage de mots de passe via Werkzeug, modèle d'autorisation polymorphe cohérent (can_manage_this_tryout, can_manage_this_org_team), en-têtes de sécurité complets et verrouillage de compte après 5 échecs.
Ces bonnes bases sont annulées par une poignée de défauts de configuration et de déploiement, pas par la logique métier. Les trois plus graves sont indépendants du code applicatif :
- Des secrets de production réels sont publiés dans le dépôt (
app/.env.exemple) : token du bot Discord, URL PostgreSQL Render complète avec mot de passe,SECRET_KEY. Ils sont dans l'historique git depuis le commit2d3721b. - Un déploiement neuf s'auto-amorce avec des comptes
admin/password— le seed de démo se déclenche automatiquement en production quand la tableusersest vide. - Le CORS par défaut accepte toutes les origines avec
supports_credentials=Truedès queCORS_ALLOWED_ORIGINSn'est pas défini — ce qui est le cas dans le.env.exemplefourni.
Le README affirme « Authorization Checks: Proper ownership validation on all sensitive operations ». C'est vrai pour les tryouts, matchs et équipes, mais faux pour la gestion des utilisateurs : les trois routes create_user, edit_user et edit_profile importent des schémas de validation Marshmallow… et ne les appellent jamais. Aucune politique de mot de passe ne s'applique sur ces chemins.
Côté outillage, la CI est en trompe-l'œil : le job « Security Scan » pointe vers un fichier qui n'existe pas à cet emplacement, le job « Tests » est un echo en continue-on-error, et requirements.txt est encodé en UTF-16, ce qui casse pip-audit. Enfin, .gitignore contient *.html : tout nouveau template créé est silencieusement ignoré par git.
Répartition des constats
| Sévérité | Sécurité | Maintenabilité | Standards | Total |
|---|---|---|---|---|
| 🔴 Critique | 4 | — | — | 4 |
| 🟠 Élevé | 4 | 4 | 1 | 9 |
| 🟡 Moyen | 7 | 7 | 6 | 20 |
| 🔵 Faible | 4 | 4 | 3 | 11 |
| Total | 19 | 15 | 10 | 44 |
Les 5 actions à mener en premier
| # | Action | Détail |
|---|---|---|
| 1 | Révoquer les 3 secrets exposés puis purger l'historique git | SEC-01 |
| 2 | Désactiver le seed automatique en production | SEC-02 |
| 3 | Refuser le démarrage si CORS_ALLOWED_ORIGINS est vide |
SEC-03 |
| 4 | Supprimer le print() du token Discord |
SEC-04 |
| 5 | Brancher les schémas Marshmallow sur les routes utilisateurs | SEC-06 |
Ce qui est déjà bien fait
Pour éviter de le casser lors des corrections :
- Aucune injection SQL — l'ORM est utilisé sans exception ; le seul
text()est unSELECT 1de healthcheck. - Aucun
|safe, aucun{% autoescape false %}dans les templates ; lesinnerHTMLdemain.jsne manipulent que des chaînes littérales. - Autorisation par dispatch polymorphe (
Admin/Manager/Coach/Player/Scout) plutôt que par comparaison de chaînes de rôles — approche propre et testable. - Protection contre la fixation de session au login (
session.clear()avec préservation du token CSRF, ligneauth.py:133-138). - Validation anti-open-redirect sur le paramètre
next(auth.py:23-36). - En-têtes de sécurité complets et HSTS conditionné à HTTPS réel.
- Filtre de redaction des secrets dans les logs (
logging_config.py:18-50). - Découpage des modèles en fichiers par entité, avec ordre d'import documenté par couches.