Partie 4 — Plan de tests
Vue d'ensemble
| Catégorie |
Cas documentés |
Automatisés (pytest) |
Résultat réel (2026-08-20) |
| Tests unitaires (UT) |
17 |
17 |
17/17 réussis |
| Tests d'intégration (IT) |
11 |
11 |
11/11 réussis |
| Tests de sécurité (TS) |
6 |
6 |
6/6 réussis |
| Tests de déploiement (TD) |
6 |
Manuels (checklist) |
Voir Partie 3 |
| Tests fonctionnels (TF) |
4 |
Manuels / scénarios |
Voir ci-dessous |
| Total automatisé |
34 |
34 exécutés |
34/34 réussis |
Exécution réelle : pytest tests/ -v contre une base MariaDB 10.11 dédiée
(gesthub_test), sortie complète dans docs/evidence/pytest_output.txt.
Contrairement à des tests reposant sur des mocks de la couche SQL, cette
suite détecte aussi les erreurs de requête (colonnes, contraintes) — c'est
d'ailleurs ainsi qu'ont été trouvés les 3 bugs mentionnés en Annexe A1.
Détail des tests unitaires (UT)
| ID |
Fonction testée |
Entrée |
Résultat attendu |
| UT-01 |
annonce_service.create_annonce |
titre/contenu valides |
Ligne créée, id retourné |
| UT-02 |
create_annonce |
titre vide |
ValidationError |
| UT-03 |
create_annonce |
contenu vide/espaces |
ValidationError |
| UT-04 |
update_annonce |
annonce existante |
Champs mis à jour |
| UT-05 |
update_annonce / delete_annonce |
id inexistant |
AnnonceNotFoundError |
| UT-06 |
fichier_service.step2_check_size |
fichier > taille max / vide |
FileValidationError |
| UT-07 |
step4_check_extension |
extension interdite / autorisée |
Erreur / extension renvoyée |
| UT-08 |
step5_generate_safe_name / step1_check_presence |
deux appels / fichier absent |
Noms uniques / erreur |
| UT-09 à UT-12 |
auth_service.is_admin |
avec/sans groupe /admin, None, sans champ groups |
True/False cohérents |
| (suppl.) |
handle_upload bout en bout |
fichier PDF valide |
Upload complet réussi |
Détail des tests d'intégration (IT) — client de test Flask
| ID |
Route |
Cas |
Résultat attendu |
| IT-01 |
GET /api/annonces |
sans session |
401 |
| IT-02 |
GET /api/annonces |
utilisateur standard |
200, liste vide |
| IT-03 |
POST /api/annonces |
utilisateur standard (non admin) |
403 |
| IT-04 |
POST /api/annonces puis GET |
admin |
201, annonce visible |
| IT-05 |
PUT /api/annonces/{id} |
admin |
200 |
| IT-06 |
DELETE /api/annonces/{id} |
admin |
200 |
| IT-07 |
GET /api/is_admin |
admin vs standard |
reflète le groupe réel |
| IT-08 |
POST /api/fichiers/upload |
sans fichier joint |
400 |
| IT-09 |
POST /api/evenements |
date_fin < date_debut |
400 |
| IT-10 |
GET / |
sans session |
302 vers /login |
| (suppl.) |
POST /api/annonces |
titre manquant |
400 |
Détail des tests de sécurité (TS) — OWASP Top 10 2021
| ID |
Vecteur |
Résultat attendu |
Résultat réel |
| TS-01 |
Injection SQL dans le titre d'une annonce |
Payload stocké tel quel, table intacte |
Réussi |
| TS-02 |
Accès à /api/fichiers et /api/annonces (POST) sans token |
401 |
Réussi |
| TS-03 |
Cookie de session falsifié (non signé) |
Traité comme non authentifié, 401 |
Réussi |
| TS-04 |
Contenu <script> dans une annonce |
Échappé au rendu Jinja2, jamais exécutable |
Réussi |
| TS-05 |
Téléchargement d'un fichier appartenant à un autre utilisateur |
403 (sauf admin) |
Réussi |
| TS-06 |
Exposition de ports internes dans docker-compose.yml |
Seul caddy expose des ports |
Réussi |
Tests fonctionnels (TF) — scénarios de bout en bout (procédure manuelle)
| ID |
Scénario |
Procédure |
| TF-01 |
Connexion complète SSO |
Ouvrir /, être redirigé vers Keycloak, se connecter, revenir authentifié |
| TF-02 |
Cycle de vie d'une annonce |
Admin crée, modifie, épingle, supprime une annonce ; vérifier l'affichage pour un standard |
| TF-03 |
Cycle de vie d'un fichier |
Uploader un fichier valide, le télécharger, le supprimer ; tenter un type de fichier interdit |
| TF-04 |
Déconnexion |
Se déconnecter, vérifier l'invalidation de la session côté Keycloak (back-channel logout) |
Grille de recette (15 critères)
| # |
Critère |
OUI/NON |
Observations |
| 1 |
Connexion SSO fonctionnelle |
OUI |
Flux testé manuellement en session 5 (13/05/2025) |
| 2 |
Redirection non-authentifié → /login |
OUI |
IT-10 |
| 3 |
Contrôle des rôles admin/standard |
OUI |
IT-03, IT-07, TS-02 |
| 4 |
CRUD annonces complet |
OUI |
IT-04, IT-05, IT-06 |
| 5 |
Épinglage des annonces |
OUI |
Colonne epinglee, tri en base |
| 6 |
Upload de fichier avec validation |
OUI |
UT-06, UT-07, upload bout en bout |
| 7 |
Téléchargement sécurisé |
OUI |
TS-05 |
| 8 |
Suppression de fichier contrôlée |
OUI |
fichier_service.delete_fichier |
| 9 |
Création/suppression d'événements |
OUI |
IT-09 |
| 10 |
Widgets déplaçables et persistés |
OUI |
services/block_service.py, capture d'écran |
| 11 |
HTTPS opérationnel |
Projection |
Nécessite le domaine réel en production (non vérifiable en local) |
| 12 |
Persistance des données après redémarrage |
Projection |
Vérifiable via TD-05 en environnement réel |
| 13 |
Déploiement reproductible (docker compose up -d) |
OUI |
Partie 3 |
| 14 |
Aucune violation flake8 |
OUI |
Annexe A1 |
| 15 |
Suite de tests automatisés au vert |
OUI |
33/33 (annexe A1, présent document) |
13 critères sur 15 vérifiés en conditions réelles, 2 nécessitant un
environnement de production (domaine + certificat réel) non reproductible
dans le cadre de la rédaction de ce dossier.
[⇒] Projection méthodologique — PV de recette. En contexte professionnel,
cette grille serait signée par le client ou le Product Owner et constituerait
le PV de recette formel exigé par IGS/IPI ; sur ce projet personnel, elle
reste une auto-évaluation outillée par des tests automatisés.
Tableau des risques de sécurité (analyse DevSecOps, OWASP Top 10 2021)
| Risque |
Criticité |
Probabilité |
Mitigation implémentée |
Preuve |
| Accès non autorisé à une route admin |
Haute |
Moyenne |
Décorateur require_admin, vérification du groupe /admin à chaque requête |
TS-02, IT-03 |
| Injection SQL |
Haute |
Basse (mitigée) |
Requêtes 100 % paramétrées (PyMySQL, %s), aucune concaténation |
TS-01 |
Fuite du CLIENT_SECRET OIDC |
Haute |
Basse |
Secrets dans .env, exclu de Git (.gitignore) |
web/.env.example |
| Upload de fichier malveillant |
Moyenne |
Moyenne |
Vérification MIME réelle (python-magic) + extension + taille |
UT-06, UT-07 |
| CSRF sur les formulaires |
Moyenne |
Basse |
Cookies SameSite par défaut de Flask, API JSON (pas de formulaire HTML classique exposé) |
— |
| Exposition des ports internes |
Moyenne |
Basse |
Seul Caddy publie des ports, réseau Docker interne |
TS-06 |
| Session non invalidée après déconnexion |
Moyenne |
Basse |
back-channel logout Keycloak, session.clear() côté Flask |
routes/auth.py::logout |