Files
brain-template/agents/reviews/SuperOAuth/code-review-v1.md
Tetardtek 878886cd51 feat: brain-template v2.0 — BSI-v3 complet + tiers documentés
- README reécrit : tiers free/pro/full + modèle clé API + multi-instance
- Sync agents/ (57 agents, kernel-isolation validated)
- Sync scripts/ BSI-v3 (file-lock, preflight, human-gate, brain-status)
- KERNEL.md v0.7.0 — zones + délégation + rendering + isolation
- brain-compose.yml v0.7.0 — rendering mode + kerneluser
- workflows/ — template + brain-engine exemple
- locks/.gitkeep + claims/.gitkeep
- helloWorld : RAG boot tier full only (bsi-rag retiré du template)
2026-03-16 23:26:38 +01:00

8.0 KiB

Review agent : code-review — v1

⚠️ Ce fichier concerne la QUALITÉ DE L'AGENT, pas les tests du code applicatif. Tests code → voir projet/src/__tests__/ et Jest/Vitest.


Contexte de la review

Info Valeur
Agent reviewé code-review
Version v1
Date 2026-03-12
Projet testé Super-OAuth
Cas soumis Review de src/application/use-cases/refresh-token.use-case.ts — use case DDD, logique fingerprint + propagation session (code écrit par l'agent security lors de la session précédente)

Output résumé

  • 🔴 Bypass fingerprint si dto.deviceFingerprint absent — if (session.fp && dto.fp) skippe silencieusement si le client n'envoie pas le champ
  • 🔴 Migration silencieuse du fingerprint après mismatch — attaquant peut faire "migrer" le fingerprint vers son device en quelques refreshes
  • 🟡 Non-atomicité delete+create — si create échoue, l'utilisateur est déconnecté sans raison
  • 🟡 Incohérence commit "enforce" vs soft check effectif
  • 🟢 Erreurs génériques new Error(...) → classes domaine custom recommandées

Output brut de l'agent

Agent code-review chargé. Le fichier fait 94 lignes → rapport structuré.

---
Code Review — refresh-token.use-case.ts

---
🔴 Critique

[L.34-43] Bypass complet du fingerprint si dto.deviceFingerprint est absent

if (session.deviceFingerprint && dto.deviceFingerprint) {

La condition requiert les deux valeurs. Si un client envoie une requête sans deviceFingerprint (champ absent ou null), la vérification est
silencieusement skippée — même si la session a un fingerprint stocké. Un attaquant avec un refresh token volé n'a qu'à ne pas envoyer ce champ pour
passer sans log, sans rejet.

Comportement attendu : si session.deviceFingerprint existe, le client doit en fournir un. L'absence devrait être traitée comme une anomalie, pas comme
une dispense.

// Version corrigée (même en soft check)
if (session.deviceFingerprint) {
  if (!dto.deviceFingerprint || session.deviceFingerprint !== dto.deviceFingerprint) {
    logger.warn('Device fingerprint mismatch or missing on token refresh', { ... });
    // throw ici quand tu passes en hard reject
  }
}

---
[L.68 + L.34-43] Migration silencieuse du fingerprint après mismatch

const fingerprint = dto.deviceFingerprint ?? session.deviceFingerprint;
await this.sessionRepository.create(user.id, newRefreshToken, expiresAt, {
  ...(fingerprint && { deviceFingerprint: fingerprint }),
});

Si un mismatch est détecté au soft check (L.35), on continue quand même ET on stocke dto.deviceFingerprint comme nouveau fingerprint de la session. En
quelques refreshes successifs, un attaquant peut faire "migrer" le fingerprint vers son propre device — la session lui appartient progressivement, sans
aucun rejet.

La correction : en cas de mismatch (même soft check), conserver le fingerprint de la session originale, ne jamais le remplacer par la valeur entrante
suspecte.

// En cas de mismatch : on garde l'original
const fingerprint = (session.deviceFingerprint && dto.deviceFingerprint &&
  session.deviceFingerprint !== dto.deviceFingerprint)
    ? session.deviceFingerprint   // conserver l'original malgré le mismatch
    : (dto.deviceFingerprint ?? session.deviceFingerprint);

---
🟡 Warning

[L.65-71] Non-atomicité delete + create — risque de déconnexion silencieuse

await this.sessionRepository.deleteByRefreshToken(dto.refreshToken); // L.65
// ... calcul ...
await this.sessionRepository.create(...);                             // L.69

Si create échoue (DB timeout, contrainte, etc.), le vieux token est déjà supprimé. L'utilisateur se retrouve sans session valide et doit se reconnecter
— sans raison visible de son côté.

Pourquoi c'est important : en token rotation, la fenêtre entre delete et create est un point de défaillance classique. La solution robuste est une
transaction DB encapsulant les deux opérations. Si le repository ne supporte pas les transactions, inverser l'ordre (create d'abord, delete ensuite)
réduit le risque : en cas d'échec du delete, les deux tokens coexistent temporairement, mais l'utilisateur n'est pas déconnecté. Niveau de confiance:
élevé sur le risque, moyen sur la bonne approche selon ton schéma DB.

---
[L.34, L.62] Commit message incohérent avec la logique

Le dernier commit s'intitule feat(auth): enforce device fingerprint validation on token refresh. Le mot "enforce" implique un hard reject — mais la
logique est un soft check avec un TODO. Ce n'est pas un bug de code, mais une dette de cohérence : soit le commit message est trompeur, soit la feature
est incomplète. À clarifier avant merge ou review PR.

---
🟢 Suggestion

[L.21, L.28, L.52, L.57] Erreurs génériques → erreurs domaine custom

throw new Error('Invalid refresh token');
throw new Error('Refresh token has expired');
throw new Error('User not found');
throw new Error('Account is deactivated');

new Error(...) générique oblige la couche infra (controller/middleware) à parser le message string pour mapper le bon code HTTP — fragile et couplé. En
DDD, on préfère des classes d'erreur domaine :

// domain/errors/auth.errors.ts
export class InvalidRefreshTokenError extends Error { ... }
export class ExpiredRefreshTokenError extends Error { ... }

Le controller peut alors faire un instanceof propre pour renvoyer 401, 403, etc. C'est un refacto mineur, mais il améliore la lisibilité de la couche
HTTP et évite les bugs silencieux si un message change.

Évaluation

Ce qui a bien fonctionné

  • A annoncé le format choisi dès le début ("94 lignes → rapport structuré") — adaptatif
  • A trouvé 2 failles critiques que l'agent security avait manquées dans le code qu'il venait lui-même d'écrire — cross-validation utile
  • Explication du pourquoi pour chaque finding : vecteur d'attaque concret, pas juste "c'est mal"
  • Anti-hallucination active : "Niveau de confiance: élevé sur le risque, moyen sur la bonne approche selon ton schéma DB"
  • Tableau de synthèse en fin de rapport — lisibilité
  • A demandé avant d'appliquer les corrections ("Veux-tu que j'applique directement ?")
  • A noté l'incohérence commit "enforce" vs soft check — dette de cohérence réelle

Ce qui manquait

  • N'a pas suggéré d'invoquer l'agent testing après les corrections (même gap que security)
  • N'a pas suggéré l'agent security pour les 2 findings 🔴 — ils sont dans le domaine partagé qualité/sécu, mais une mention explicite de coordination aurait été propre
  • La suggestion domain errors (🟢) aurait pu pointer vers l'agent refacto pour le chantier complet

⚠️ Anti-hallucination respectée ?

  • A dit "Information manquante" quand nécessaire — a précisé le niveau de confiance moyen sur l'approche transaction
  • N'a pas inventé de commandes/chemins/métriques — tout ancré sur des numéros de ligne réels
  • Niveau de confiance explicite si incertain — présent sur le finding non-atomicité

📐 Périmètre respecté ?

  • Format adapté (rapport structuré pour 94 lignes)
  • A expliqué le pourquoi de chaque finding
  • N'a pas débordé sur les perfs ou l'infra
  • A demandé avant d'appliquer les corrections

Gaps identifiés → à corriger dans l'agent

Gap Correction proposée Priorité
N'a pas suggéré testing après les corrections Ajouter dans périmètre : "après tout fix, suggérer testing" moyenne
N'a pas suggéré security pour les findings critiques Ajouter : "si finding 🔴 avec vecteur d'attaque → mentionner coordination avec security" basse
N'a pas pointé refacto pour la suggestion domaine errors Ajouter : "pour suggestions de refacto structurel → mentionner refacto" basse

Action

  • Review complète
  • Gaps reportés dans agents/code-review.md changelog
  • Règles ajoutées directement dans Périmètre (Recruiter non nécessaire — corrections simples)
  • v2 planifiée (prochain audit réel)