Gate CI
Un seul appel HTTP porte toute la gate : votre CI envoie le diff, le code de statut porte le verdict.
L'endpoint
POST /api/ci/gate
Authorization: Bearer <workspace token>
Body: raw output of `git diff base...HEAD`Le statut de la réponse, c'est la décision :
| Statut | Signification |
|---|---|
422 | Au moins une violation bloquante (sévérité error). curl --fail-with-body sort en code non nul → le job CI échoue → le merge est bloqué. |
200 | Conforme, uniquement des violations non bloquantes, un diff vide — ou la gate n'a pas pu s'exécuter (fail-open, voir plus bas). |
401 | Token absent ou invalide. |
Formats de réponse
Par défaut, le corps est du text/plain lisible par un humain, pensé pour les logs CI. Envoyez Accept: application/json pour obtenir une réponse structurée à la place — les codes de statut sont les mêmes :
{ "status": "failure", "blocking": 1, "rulesApplied": 8, "filesAnalysed": 3,
"violations": [ { "ruleId": "…", "path": "src/api.ts", "line": 42,
"severity": "error", "comment": "…",
"suggestion": "…" | null } ] }
// empty diff: { "status": "empty" }
// gate couldn't run: { "status": "unavailable", "reason": "…" }
// diff over 4 MB (413): { "status": "oversize", "reason": "…", "limitBytes": 4194304 }Suggestions de correction
Une violation peut porter une suggestion : une ligne courte et concrète sur la façon de corriger ce qui a été signalé. Dans la sortie text/plain, elle apparaît sous la violation, préfixée par ↳ suggested fix ; en JSON, c'est un champ suggestion de l'objet violation, à null quand il n'y en a pas (les analyses anciennes peuvent omettre la clé). Elle apparaît aussi dans l'historique des analyses et dans les rapports de scan de repo.
À lire comme une piste, pas comme un patch. La gate ne voit que les lignes ajoutées du diff — pas le reste de votre repo. Une suggestion peut donc passer à côté d'un helper que vous avez déjà, d'une signature qu'elle n'a jamais vue ou d'une convention qui vit dans un autre fichier, et se tromper alors même que la violation, elle, est juste. Rien n'est appliqué automatiquement, et le silence est la valeur par défaut : quand le modèle n'a pas de correction sûre, il renvoie null plutôt que d'en inventer une. Relisez une suggestion avant d'agir dessus, exactement comme vous relisez la violation.
En-têtes de contexte (optionnels)
| En-tête | Usage |
|---|---|
X-Normik-Repo | Libellé du repo affiché dans l'historique des analyses (par ex. acme/shop). |
X-Normik-Sha | SHA du commit de tête du diff contrôlé. |
X-Normik-PR | Numéro de la pull request. |
Fail-open, par conception
Si aucun provider IA n'est configuré, ou si l'appel au modèle échoue (clé invalide, quota, panne du provider), la gate renvoie 200 avec une explication au lieu de bloquer. Une quality gate doit arrêter le code non conforme — jamais prendre vos livraisons en otage à cause d'un incident chez un tiers. Le blocage est réservé aux vraies violations de sévérité error.
Les snippets générés étendent cette garantie côté client : ils récupèrent le code de statut HTTP au lieu de s'appuyer sur curl --fail, et ne font échouer le job que sur un 422. Un hôte injoignable, un timeout ou une 5xx laissent le pipeline au vert, avec une explication dans le log.
GitHub Actions — avec commentaires de PR
Le snippet généré (Settings → CI integration) demande du JSON, poste un résumé des violations en commentaire de PR avec le GITHUB_TOKEN du workflow lui-même (permissions: pull-requests: write), et ne sort en 1 que sur un 422. Pas d'application, pas de webhook : le commentaire vient de votre pipeline, pas d'un bot que nous exploitons.
GitLab CI — avec notes de MR en option
Le même appel, depuis un job merge_request_event avec GIT_DEPTH: "0" et un fetch de la branche cible. Le snippet généré poste aussi le rapport de violations en note de merge request — mais cette partie est opt-in, et voici pourquoi : le CI_JOB_TOKEN natif de GitLab n'a pas le droit d'écrire des notes de MR, donc aucun snippet ne peut commenter avec les identifiants dont un pipeline dispose déjà.
Pour activer les commentaires, créez un project access token (ou un token personnel) avec le scope api et au moins le rôle Developer, puis exposez-le au pipeline en variable CI masquée nommée NORMIK_GITLAB_TOKEN. Le job appelle alors POST /projects/:id/merge_requests/:iid/notes avec ce token dès que des violations sont remontées. Laissez la variable non définie et le job se comporte exactement pareil par ailleurs : le verdict reste dans le log du job et dans le dashboard Normik.
Poster une note est best-effort dans les deux sens : un commentaire raté ne fait jamais échouer le pipeline, et le statut de sortie du job reste décidé uniquement par le code de statut de la gate.
Ce qui est analysé
- Uniquement les fichiers présents dans le diff, et uniquement leurs lignes ajoutées — les fichiers supprimés et les changements binaires sont ignorés.
- Uniquement les règles dont les scopes en glob matchent au moins un fichier modifié.
- Chaque exécution est consignée dans l'historique des analyses, avec ses violations et sa consommation de tokens.