""" Tests RGPD — droit à l'effacement (art. 17) : anonymisation d'un `sub` OIDC dans toutes les tables qui le référencent (routes/rgpd.py, services/rgpd_service.py, models/rgpd_model.py). """ from models import annonce_model, fichier_model, evenement_model, audit_model from services import annonce_service, evenement_service, rgpd_service def _seed_user_data(db, sub): """Crée une ligne dans chaque table référençant `sub`, y compris audit_log (via les services, comme le ferait l'application réelle). create_annonce() et create_evenement() journalisent déjà chacun une ligne dans audit_log (CREATE_ANNONCE, CREATE_EVENEMENT) ; on ajoute un LOGIN explicite pour obtenir 3 lignes audit_log au total pour ce sub. """ annonce_id = annonce_service.create_annonce(db, "Titre", "Contenu", sub) fichier_model.insert(db, "doc.pdf", "uuid-stocke", "application/pdf", 10, sub) evenement_service.create_evenement( db, "Réunion", "desc", "2026-09-10T10:00:00", "2026-09-10T11:00:00", sub ) from services import audit_service audit_service.log(db, "LOGIN", None, "SUCCESS", sub, "127.0.0.1") return annonce_id # --- Accès ------------------------------------------------------------------- def test_rgpd01_sans_auth_401(client): resp = client.delete("/api/admin/users/sub-cible/data") assert resp.status_code == 401 def test_rgpd02_non_admin_403(user_session): resp = user_session.delete("/api/admin/users/sub-cible/data") assert resp.status_code == 403 def test_rgpd03_sub_inconnu_404(admin_session): resp = admin_session.delete("/api/admin/users/sub-jamais-vu/data") assert resp.status_code == 404 # --- Anonymisation effective --------------------------------------------- def test_rgpd04_anonymisation_remplace_le_sub_partout(db, admin_session): target_sub = "sub-a-effacer-0001" annonce_id = _seed_user_data(db, target_sub) resp = admin_session.delete(f"/api/admin/users/{target_sub}/data") assert resp.status_code == 200 body = resp.get_json() assert body["status"] == "anonymized" pseudonym = body["pseudonym"] assert pseudonym.startswith("anon:") assert body["rows_updated"] == { "annonces": 1, "fichiers": 1, "evenements": 1, "audit_log": 3, } # Le sub d'origine n'apparaît plus nulle part... assert annonce_model.get(db, annonce_id)["auteur_sub"] == pseudonym fichiers = fichier_model.fetch_all(db) assert fichiers[0]["uploader_sub"] == pseudonym evenements = evenement_model.fetch_all(db) assert evenements[0]["createur_sub"] == pseudonym recent = audit_model.fetch_recent(db) subs_restants = [row["utilisateur_sub"] for row in recent] assert target_sub not in subs_restants # ... mais une entrée d'audit trace l'action d'anonymisation elle-même, # journalisée sous l'identité de l'ADMIN qui l'a déclenchée (pas la # cible, déjà pseudonymisée à ce stade). actions = {row["action"] for row in recent} assert "RGPD_ANONYMIZE_USER" in actions def test_rgpd05_pseudonyme_deterministe_pour_un_meme_sub(db): target_sub = "sub-deterministe-0002" _seed_user_data(db, target_sub) result = rgpd_service.anonymize_user(db, target_sub, pepper="pepper-de-test") assert result["anonymized"] is True # Toutes les tables ont reçu EXACTEMENT le même pseudonyme. pseudo = result["pseudonym"] assert annonce_model.fetch_all(db)[0]["auteur_sub"] == pseudo assert fichier_model.fetch_all(db)[0]["uploader_sub"] == pseudo def test_rgpd06_deja_anonymise_refuse(db, admin_session): target_sub = "sub-double-appel-0003" _seed_user_data(db, target_sub) first = admin_session.delete(f"/api/admin/users/{target_sub}/data") pseudonym = first.get_json()["pseudonym"] second = admin_session.delete(f"/api/admin/users/{pseudonym}/data") assert second.status_code == 400