SEC-P0-001B3 — IA Actor Onboarding Authorization
Statut
- Branche API :
feature/sec-p0-001b3-ai-onboarding-authorization. - Périmètre : route IA onboarding acteur uniquement.
- Aucun commit créé pendant l'implémentation.
- Aucune PR documentaire créée tant que la chaîne documentaire B2 reste ouverte.
Route corrigée
| Route | Contrôleur | Request | Prompt IA | Domaine |
|---|---|---|---|---|
POST /api/v1/ai/onboarding/suggest | AIController::onboardingSuggest | OnboardingSuggestRequest | onboarding.suggest | Actor onboarding |
Cette route accepte un actor_id optionnel côté payload et peut déclencher la logique d'onboarding gratuit acteur lorsque actor_id est présent.
Arbitrage permission
Permission cible retenue :
ActorAccessService::hasPermission($user, $actorId, 'manage_actor')
Justification :
- l'action manuelle équivalente est la modification du profil acteur ;
ActeurPolicy::updatedélègue déjà àActorAccessService::hasPermission(..., 'manage_actor');- l'onboarding enrichit les données d'un acteur, il ne relève pas de
mairie_services; manage_servicesreste réservé au domaine des services municipaux.
Divergence levée
Dans cette route, le terme onboarding désigne l'aide IA à la constitution d'un profil acteur.
- Actor onboarding → acteur/profil acteur →
manage_actor. - Municipal Services →
mairie_services→manage_services.
La route POST /api/v1/ai/onboarding/suggest ne manipule pas mairie_services.
Ordre de contrôle
Le contrôle RBAC est exécuté immédiatement après validation du payload et avant :
- calcul
X-App-Source/noCreditDebit; AIGatewayService;AIQuotaService::isFirstOnboarding;- création ou mutation de quota acteur ;
- lecture ou écriture cache ;
- appel provider IA ;
- écriture
ai_usage_logs; - consommation de boost ;
- marquage
onboarding_at.
Sémantique onboarding gratuit conservée
Le comportement existant reste inchangé pour les appels autorisés :
AIGatewayServicedétecte l'onboarding gratuit uniquement pourpromptKey = onboarding.suggest,userId != nulletactorId != null;AIQuotaService::isFirstOnboarding($userId, $actorId)lit ou crée le quota acteur ;- si
onboarding_atestnull, l'appel autorisé consomme0crédit ; - après succès provider,
AIQuotaService::markOnboardingUsed($userId, $actorId)renseigneonboarding_at; - les appels sans
actor_idconservent le comportement historique de quota personnel.
Le correctif ne modifie ni le calcul de quota, ni le débit gratuit, ni la structure cache/quota.
Scénarios testés
Tests ajoutés dans tests/Feature/AI/AITest.php :
- owner autorisé ;
- collaborateur actif avec
manage_actoret sansmanage_servicesautorisé ; - admin global autorisé selon comportement historique ;
- régression IDOR avec
actor_idtiers refusée en403; - collaborateur avec
manage_servicesmais sansmanage_actorrefusé en403; - collaborateur inactif refusé en
403; - utilisateur sans acteur refusé en
403; - projection legacy
user_acteursseule refusée en403; - refus IDOR sans création de quota acteur ;
- contrat onboarding gratuit autorisé toujours routé au gateway avec
credits_used = 0.
Pour les refus, les tests prouvent :
- aucun
AIGatewayService::executeappelé ; - aucun appel provider HTTP envoyé ;
- aucun quota acteur consommé ;
- aucun quota acteur créé quand il n'existait pas ;
- aucun
onboarding_atrenseigné après refus ; - aucun
ai_usage_logscréé ; - aucun
ai_cacheécrit ; - aucun
boost_usagescréé.
Hors périmètre confirmé
Non modifiés :
mairie_services;manage_serviceshors usage test de refus ;AIQuotaService;AIGatewayService;AICacheService;AIUsageLogger;ActorPolicy;- RBAC global ;
- frontend ;
- SEC-P0-001B4, SEC-P0-001B5, SEC-P0-001B6 ;
- DB-001.
Rollback
Rollback isolé : retirer l'appel à authorizeActorForAi(..., 'manage_actor') dans AIController::onboardingSuggest.
Ce rollback restaurerait le comportement antérieur sans migration DB, mais réouvrirait le risque IDOR onboarding acteur.