================================================================================ AUDIT INDÉPENDANT — CODE SOURCE UNIONFLOW (Base strictement sur le code source ; aucun fichier .md lu) ================================================================================ 1. STRUCTURE ET DÉPENDANCES -------------------------------------------------------------------------------- • Trois modules Maven identifiés : unionflow-server-api, unionflow-server-impl-quarkus, unionflow-client-quarkus-primefaces-freya. Pas de POM parent commun à la racine unionflow/ ; parent déclaré via parent-pom.xml dans unionflow-server-api. • API : Java 17, Lombok, Bean Validation, Jackson, MicroProfile OpenAPI, JUnit 5, Mockito, AssertJ, Jacoco (seuils 1.00 sur lignes/instructions/méthodes/branches/classes). • Impl : dépend de unionflow-server-api 1.0.0, lions-user-manager-server-api 1.0.0, Quarkus 3.15.1, Hibernate Panache, Flyway, OIDC, MapStruct 1.6.3, POI, OpenPDF. Jacoco : 1.00 lignes/instructions/méthodes, 0.30 branches. Checkstyle non exécuté (executions commentées dans API). • Client : dépend de unionflow-server-api 1.0.0, Quarkus PrimeFaces, OIDC, REST Client. Pas de plugin Jacoco dans le client. Risques : build multi-module non unifié (pas de reactor root) ; client sans couverture automatique ; Checkstyle désactivé en API. 2. CONTRAT API / CLIENT – SERVEUR -------------------------------------------------------------------------------- • Organisations : Le client (AssociationService) appelle GET /api/organisations?page=&size= et attend PagedResponse. Le serveur (OrganisationResource) renvoie PagedResponse. OrganisationSummaryResponse est un record (id, nom, nomCourt, typeOrganisation, typeOrganisationLibelle, statut, …) ; OrganisationResponse a plus de champs. Désérialisation possible mais type déclaré incorrect et champs manquants côté client = risque PropertyNotFoundException ou données incomplètes en vue. • Membres : Client MembreService utilise GET /search et /search/advanced ; serveur expose GET /recherche (param q), GET /recherche-avancee (déprécié), POST /search/advanced. Incohérence de chemins pour recherche simple (client /search vs serveur /recherche). • Types d’organisation : Client TypeOrganisationClientService appelle DELETE /{id} (méthode disable()) ; serveur TypeOrganisationReferenceResource fait bien DELETE (suppression réelle ou conditionnelle selon rôle). Alignement OK sur le chemin. • DemandeAide : Client appelle GET /api/demandes-aide?page=&size= ; serveur renvoie List (pas PagedResponse). Pagination côté serveur faite manuellement (subList). Contrat différent si le client attend un objet PagedResponse. 3. SÉCURITÉ (ANNOTATIONS) -------------------------------------------------------------------------------- • HealthResource (/api/status) : aucune annotation @RolesAllowed ni @PermitAll. Comportement dépend de la config globale (souvent ouvert pour health checks). • DemandeAideResource, PropositionAideResource : aucune annotation @RolesAllowed sur la ressource. Accès dépend de la politique par défaut (risque d’accès non restreint). • RoleResource (/api/roles) : pas de @RolesAllowed. • Incohérence des rôles : une partie des resources utilise des rôles en UPPER_CASE (ADMIN, MEMBRE, SUPER_ADMIN, USER, SUPER_ADMINISTRATEUR, TRESORIER, etc.), d’autres en lowercase (admin, admin_organisation, membre_actif, mutuelle_resp, vote_resp, tontine_resp, ong_resp, coop_resp, culte_resp, registre_resp). AnalyticsResource utilise MANAGER, MEMBER. Risque de refus ou d’accès inattendu selon le fournisseur de rôles (Keycloak vs custom). 4. BASE DE DONNÉES ET MIGRATIONS -------------------------------------------------------------------------------- • Migrations Flyway : V1__UnionFlow_Complete_Schema.sql, V2__Entity_Schema_Alignment.sql (et README_CONSOLIDATION dans le même répertoire — non lu). Deux scripts principaux uniquement = consolidation déjà faite. Les tests désactivent Flyway (quarkus.flyway.enabled=false, migrate-at-start=false). 5. CLIENT JSF / PRIMEFACES -------------------------------------------------------------------------------- • Convertisseur UUID : UuidConverter utilisé sur plusieurs pages (cotisations membre, adhesion, organisation-form, membre-form, import/export membre, comptabilité, documents). Un seul f:viewParam repéré avec converter="uuidConverter" (membre/cotisations.xhtml, id → membreCotisationBean.membreId). Les autres liaisons UUID sont surtout sur p:selectOneMenu. Toute vue qui lie une chaîne à un UUID sans converter peut provoquer une ELException (conversion String → UUID). • Gestion des erreurs : ViewExpiredExceptionHandler enveloppe l’exception handler JSF, gère ViewExpiredException (redirection vers /, stockage redirectURL) et PropertyNotFoundException (log WARNING, redirection vers liste organisations, responseComplete). Typo dans le message de log : "already commited" (deux « m »). En cas de réponse déjà envoyée, le handler log en WARNING pour "already commited" / "already committed". • Scopes des beans : mélange ViewScoped (listes, détail, formulaires ciblés) et SessionScoped (dashboard, demandes, rôles, adhesions, etc.). RolesBean en SessionScoped pour une liste de rôles = risque de données obsolètes si l’utilisateur garde l’onglet longtemps. 6. RESSOURCES REST SERVEUR – POINTS D’ATTENTION -------------------------------------------------------------------------------- • OrganisationResource : GET sans path retourne PagedResponse avec paramètres page, size, recherche (optionnel). Client n’envoie pas « recherche ». • CotisationResource : deux chemins pour des stats (/stats et /statistiques) ; les deux exposés pour compatibilité. • TypeOrganisationReferenceResource : DELETE appelle supprimerPourSuperAdmin si SUPER_ADMIN/SUPER_ADMINISTRATEUR, sinon supprimer(id). Logique métier cohérente avec un rôle privilégié. • Pas de @RolesAllowed sur DemandeAideResource, PropositionAideResource, RoleResource, HealthResource : à documenter ou à aligner avec la politique de sécurité globale. 7. QUALITÉ ET TESTS -------------------------------------------------------------------------------- • API : Jacoco exige 1.00 sur tous les compteurs (dont branches). Très exigeant ; tout nouveau code non testé peut faire échouer le build. • Impl : même politique 1.00 sauf branches à 0.30. Quarkus JUnit 5, RestAssured, quarkus-test-security, quarkus-jacoco. • Client : pas de Jacoco configuré dans le POM ; pas de mesure de couverture côté client. • Checkstyle (API) : exécutions en plugin commentées ; la qualité de style n’est pas appliquée au build. 8. DIVERS -------------------------------------------------------------------------------- • Client TypeOrganisationClientService.disable() : nom de méthode « disable » alors que le serveur effectue une suppression (DELETE). Sémantique différente côté client. • RestClientExceptionMapper (client) : mappe 4xx/5xx vers des exceptions dédiées ; pour 5xx le message est volontairement générique (pas d’exposition de détail). • Doublon possible de DTO dashboard : MembreDashboardSyntheseResponse déplacé dans l’API (éviter split package) ; à confirmer qu’il n’existe plus dans l’impl. • RolesBean (client) : supprimerRole() retire uniquement de la liste en mémoire ; AdminUserService n’expose pas de DELETE pour les rôles. Comportement « suppression » uniquement côté client. 9. SYNTHÈSE DES RISQUES ET RECOMMANDATIONS -------------------------------------------------------------------------------- • Critique : Contrat liste organisations (PagedResponse vs PagedResponse). Aligner le type retourné ou le type attendu par le client (ex. adapter le client à OrganisationSummaryResponse ou faire renvoyer OrganisationResponse par le serveur). • Important : Ressources sans @RolesAllowed (DemandeAide, PropositionAide, Role, Health). Définir une politique explicite (au moins pour DemandeAide, PropositionAide, Role). • Important : Unification des noms de rôles (UPPER vs lowercase, MANAGER/MEMBER vs ADMIN/MEMBRE) en fonction du répertoire (Keycloak) pour éviter 403 ou accès trop larges. • Moyen : Recherche membres — aligner chemins client (/search) et serveur (/recherche) ou documenter la différence et adapter le client. • Moyen : Pagination demandes d’aide — retourner un PagedResponse si le client l’attend, ou documenter que la réponse est une List. • Mineur : Typo "already commited" dans ViewExpiredExceptionHandler. • Mineur : Activer Checkstyle ou supprimer la config si non souhaitée ; documenter l’absence de couverture côté client. ================================================================================ Fin de l’audit. ================================================================================