Files
team-tryouts/audit/README.md
T
GGThedandClaude Opus 5 fa0a378827 docs(audit): audit securite, maintenabilite et standards de la stack
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]>
2026-08-07 13:02:54 -04:00

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 :

  1. 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 commit 2d3721b.
  2. 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 table users est vide.
  3. Le CORS par défaut accepte toutes les origines avec supports_credentials=True dès que CORS_ALLOWED_ORIGINS n'est pas défini — ce qui est le cas dans le .env.exemple fourni.

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 un SELECT 1 de healthcheck.
  • Aucun |safe, aucun {% autoescape false %} dans les templates ; les innerHTML de main.js ne 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, ligne auth.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.