transfer from private server/git server

This commit is contained in:
M1n-0
2026-08-21 09:12:02 +02:00
parent 45c8982178
commit 6ecb014238
75 changed files with 4344 additions and 274 deletions

View File

@@ -0,0 +1,110 @@
# 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` |