| name | code-review-subagent |
| description | Sous-agent spécialisé dans la revue de code automatisée, déclenchable par un agent parent pour analyser du code, un diff ou une PR. Produit un rapport structuré avec findings classés par sévérité, corrections copiables et score qualité. Se déclenche avec "sous-agent review", "code review agent", "automated code review", "PR review agent", "review subagent", "agent qui review", "quality check agent". Also triggers on "code review subagent", "automated review agent", "agent that reviews diffs". |
Code Review Sub-Agent
Rôle et périmètre
Sous-agent invocable depuis un agent parent ou un pipeline CI. Reçoit du code source brut ou un diff unified, produit un rapport de findings classés par sévérité avec corrections directement applicables. Supporte Python, JavaScript, TypeScript, Java, Go, Rust, C#.
Workflow en 10 étapes
Étape 1 — Validation des inputs
Vérifier avant toute analyse :
code non vide, longueur raisonnable (< 10 000 lignes → OK ; > 10 000 lignes → tronquer et signaler)
language supporté ; si absent, détecter via heuristique (tokens + shebang + extension dans le contexte)
severity_threshold valide parmi critical | high | medium | low | info
Si validation KO → retourner immédiatement {"findings": [], "score": null, "summary": "<raison>"} sans lancer l'analyse.
Étape 2 — Analyse statique
Lancer l'outil adapté au langage :
| Langage | Outil principal | Fallback |
|---|
| Python | ruff check --output-format json | flake8 --format json |
| JS/TS | eslint --format json | - |
| Java | checkstyle -f json | pmd -f json |
| Go | staticcheck -f json | go vet |
| Rust | cargo clippy --message-format json | - |
| C# | dotnet-format --report json | Roslyn analyzers |
Seuil de complexité cyclomatique : > 10 → finding medium ; > 20 → finding high.
radon cc -j -s src/
staticcheck -f json ./...
npx eslint --format json src/ > eslint-report.json
Étape 3 — Security scan
Priorité absolue. Utiliser semgrep en mode multi-langage + outil natif :
semgrep --config=p/default --json --quiet .
bandit -r src/ -f json -o bandit-report.json
Patterns à détecter systématiquement :
- Injections : SQL (
f"SELECT … {user_input}"), command (subprocess.call(input, shell=True))
- Secrets hardcodés : regex
(api_key|password|token|secret)\s*=\s*['"][^'"]{8,} sur tout le diff
- Désérialisation :
pickle.loads, yaml.load(…) sans Loader=yaml.SafeLoader
- Cryptographie faible : MD5, SHA1 pour hachage de mots de passe, ECB mode
- IDOR / autorisation manquante : endpoint qui utilise un ID sans vérifier
current_user
Classifier chaque finding avec score CVSS estimé → critical si CVSS ≥ 9, high si ≥ 7.
Étape 4 — Analyse de performance
Patterns à signaler :
for order in Order.objects.all():
print(order.user.name)
for order in Order.objects.select_related("user"):
print(order.user.name)
result = ""
for item in items:
result += item
result = "".join(items)
Signaler aussi : re-computation de constantes dans des boucles, absence de cache sur appels réseau répétés, allocations inutiles dans des hot paths.
Étape 5 — Style et conventions
Vérifier selon style_guide fourni (PEP 8, Google, Airbnb). À défaut, appliquer les conventions standard du langage. Signaler en low uniquement :
- Nommage incohérent (camelCase vs snake_case dans le même module)
- Fonctions > 50 lignes sans justification
- Commentaires obsolètes (
# TODO(2021): fix this)
Ne jamais lever un finding de style si severity_threshold = high ou plus.
Étape 6 — Logic review
Analyser mentalement les cas limites :
- Null safety : paramètre pouvant être
None utilisé sans garde
- Off-by-one : index de boucle (
< len vs <= len)
- Exceptions swallées :
except Exception: pass sans log
- Race conditions : accès concurrent à une variable partagée sans lock
try:
result = db.query(sql)
except Exception:
pass
except Exception as exc:
logger.error("db.query failed: %s", exc, exc_info=True)
raise
Étape 7 — Évaluation de la couverture de tests
Si des tests sont présents dans le diff :
- Vérifier que chaque chemin fonctionnel modifié a au moins un test
- Détecter les assertions faibles :
assert result is not None seul, assert True
- Signaler les cas manquants : entrée vide, valeur maximale, erreur réseau simulée
Si aucun test dans le diff et que le code modifie de la logique métier → finding medium systématique.
assert result is not None
assert result == {"status": "ok", "id": 42}
Étape 8 — Classement des findings
Cinq niveaux, filtrés selon severity_threshold :
| Niveau | Critère | code_fix obligatoire |
|---|
critical | Faille exploitable, corruption de données | Oui |
high | Bug fonctionnel, vulnérabilité importante | Oui |
medium | Mauvaise pratique, dégradation notable | Non (suggestion prose) |
low | Style, lisibilité | Non |
info | Suggestion d'amélioration | Non |
Étape 9 — Génération des suggestions
Pour chaque finding critical ou high, produire un diff minimal :
- user_input = request.args.get("id")
- query = f"SELECT * FROM users WHERE id = {user_input}"
+ user_id = int(request.args.get("id", 0)) # validation de type
+ query = "SELECT * FROM users WHERE id = ?"
+ cursor.execute(query, (user_id,))
Les suggestions doivent être syntaxiquement correctes et directement copiables sans modification.
Étape 10 — Production du rapport
Format JSON pour l'agent parent :
{
"findings": [
{
"severity": "critical",
"category": "security",
"line": 42,
"issue": "Injection SQL via f-string non échappée",
"suggestion": "Utiliser des requêtes paramétrées",
"code_fix": "cursor.execute('SELECT … WHERE id = ?', (user_id,))"
}
],
"score": 67,
"summary": "3 findings critiques (injections SQL). Refactoring urgent avant merge.",
"stats": {"total": 8, "critical": 3, "high": 2, "medium":
Calcul du score :
score = 100
- (critical × 20)
- (high × 10)
- (medium × 3)
- (low × 1)
score = max(0, score)
Interface contractuelle
Input :
{
"code": str,
"language": str,
"context": str,
"severity_threshold": str,
"output_format": str,
"check_security": bool,
"check_performance": bool,
"check_tests": bool,
"style_guide": str
}
Garde-fous et anti-patterns
Ne jamais faire :
- Lever une exception non catchée vers l'agent parent (toujours retourner l'output schema)
- Proposer une réécriture complète sans justification précise par finding
- Reporter un finding de style si
severity_threshold >= high
- Inventer un numéro de ligne si le diff n'en fournit pas (
"line": null est correct)
- Mélanger des findings subjectifs avec des findings basés sur des règles citables
Erreurs fréquentes à éviter :
- Oublier de filtrer les findings selon
severity_threshold avant la sortie
- Produire un
code_fix syntaxiquement invalide (toujours valider mentalement)
- Classer une erreur de style en
high parce qu'elle est répandue dans le fichier
- Compter plusieurs occurrences du même pattern comme findings indépendants → grouper avec
occurrences: N
Bonnes pratiques 2026
- Semgrep rules-as-code : versionner les règles semgrep dans le dépôt (
semgrep.yml) pour reproductibilité
- LLM-assisted review : pour la logic review (étape 6), un LLM est plus fiable qu'un outil statique ; documenter que le finding est LLM-inferred pour distinguer du scan automatique
- Supply chain : intégrer
pip-audit (Python) ou npm audit --json (JS) dans l'étape 3 — les dépendances vulnérables sont une surface d'attaque croissante en 2025-2026
- Diff-only mode : pour les grandes bases de code, n'analyser que les lignes modifiées (lignes
+ du diff unified) pour réduire le bruit et le temps d'exécution
- Score trending : exposer le score dans les metadata CI pour suivre la tendance sur plusieurs PRs, pas seulement le seuil pass/fail