Vérification CI pour les livrables d'agents Module

Vaks PM · Guide d'intégration · Résultats CI signés · Juillet 2026

Ce que vous obtiendrez. Lorsqu'un agent IA soumet un livrable et affirme que son build a réussi, Vaks PM ne le croit plus sur parole — c'est un résultat signé émis par votre système CI qui tranche. Le propre verdict de l'agent est écarté au profit du verdict signé. Cela ferme la brèche par laquelle un agent pouvait marquer son propre travail comme réussi.

Ce que ça fait — et ce que ça ne fait pas

Un agent qui produit un travail rapporte aussi s'il a vérifié ce travail. Laissé à lui-même, cela revient à de l'auto-déclaration : l'agent corrige sa propre copie. La vérification CI remplace l'affirmation de l'agent par une preuve indépendante, signée cryptographiquement, émise par le système qui a réellement exécuté le build.

Prérequis

CôtéCe qu'il vous faut
Votre CIGitHub Actions, ou toute CI capable de POSTer un corps JSON avec une signature HMAC. Elle doit pouvoir joindre votre instance Vaks PM — c'est un appel entrant, donc une instance entièrement privée exige que la CI soit sur le même réseau ou joignable via votre propre passerelle.
Vaks PMLa permission agent:manage — un administrateur de l'organisation, ou un utilisateur détenant le grant d'administrateur IA. C'est la même permission que celle qui gouverne les agents eux-mêmes : quiconque pilote votre programme IA peut donc la configurer sans être administrateur complet.
Un secret partagéUne chaîne que vous générez, posée des deux côtés. Elle ne circule jamais ; elle sert uniquement à signer et à vérifier.
Aucune licence requise, et les agents ne peuvent pas y toucher. La vérification CI n'est pas soumise à licence. Et comme agent:manage ne peut jamais être détenue par un agent, aucun agent ne peut créer ni modifier le connecteur qui juge son propre travail.

Étape 1 — Créer le connecteur dans Vaks PM

Ouvrez Admin → Intégrations → Vérification CI et pressez Ajouter un connecteur. Choisissez le type de signataire :

Renseignez :

ChampQuoi renseigner
LibelléTexte libre, pour la liste des connecteurs.
Secret HMAC partagéLe secret que vous poserez aussi sur le webhook CI. Chiffré au repos, jamais réaffiché — laissez vide lors d'une modification pour conserver celui déjà enregistré.
Activé (accepter les résultats entrants)Cochez-le. Un connecteur désactivé rejette chaque résultat comme s'il n'existait pas.

Enregistrez, puis pressez Copier l'URL sur la carte du connecteur. C'est l'adresse vers laquelle votre CI poste :

https://<your-host>/api/v1/webhooks/ci/<provider>

<provider> vaut github ou generic. Il n'existe qu'un seul connecteur de chaque type par organisation.

Postez vers le nom d'hôte propre au tenant. L'organisation est identifiée à partir de l'hôte dans l'URL, et non d'un élément du corps. Une adresse IP ou un nom d'hôte partagé ne résout vers aucun tenant et le résultat est écarté — vous verriez 202 et rien ne se passerait. Si vous exploitez plusieurs organisations, chacune a son propre connecteur, secret et URL.

Étape 2 — Dans GitHub

Ajoutez un webhook de dépôt (ou d'organisation) : Settings → Webhooks → Add webhook.

GitHub signe le corps avec X-Hub-Signature-256 automatiquement dès que le secret est posé ; il n'y a rien à configurer sur la signature elle-même. Les exécutions en cours et les événements ping sont acceptés et ignorés — seule une exécution terminée porte un verdict.

Étape 2b — Un signataire CI générique

Si vous n'êtes pas sur GitHub, faites POSTer par votre pipeline un corps JSON plat vers l'URL /generic, signé avec le HMAC-SHA256 du corps brut, dans l'en-tête X-Vaks-CI-Signature sous la forme sha256=<hex>.

# Corps
{ "commitSha": "<full-sha>", "conclusion": "success", "runUrl": "https://ci.example.com/run/123" }

# En-tête
X-Vaks-CI-Signature: sha256=<hmac-sha256 hex of the raw body, keyed with the shared secret>

Un signataire minimal, en shell :

BODY='{"commitSha":"'"$GIT_SHA"'","conclusion":"'"$RESULT"'"}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')
curl -sS -X POST "$VAKS_CI_URL" \
  -H 'Content-Type: application/json' \
  -H "X-Vaks-CI-Signature: sha256=$SIG" \
  --data-raw "$BODY"
Ce qui compte comme un succès. Une seule chose : conclusion égal à success (insensible à la casse). Toute autre valeur — failure, cancelled, timed_out, n'importe laquelle — est un échec. Le champ peut aussi s'appeler status ou state, et le commit peut être commitSha, commit_sha ou sha. Un commit absent ou un verdict null signifie que le résultat est ignoré, pas échoué.

Étape 3 — L'exiger sur un projet

Un connecteur seul se contente d'enregistrer les résultats signés. Pour qu'un résultat fasse réellement barrage à un livrable, deux choses doivent s'aligner :

Commencez en report only pour voir la corroboration circuler sans affecter les revues, puis basculez en enforce une fois que vous faites confiance au signal.

Il n'y a jamais de blocage définitif. Si un projet exige une CI signée mais ne dispose d'aucun mécanisme capable de la fournir, l'exigence est escaladée vers une revue humaine plutôt que de bloquer indéfiniment. Un livrable n'est jamais bloqué à attendre une preuve qui ne peut pas arriver.

Étape 4 — Vérifier la configuration

Déclenchez une exécution CI pour qu'un résultat signé soit envoyé, puis vérifiez la carte du connecteur dans Admin → Intégrations → Vérification CI :

Parcourez ensuite une fois le chemin réel : faites soumettre par un agent un livrable avec le commit correspondant, et vérifiez dans l'écran de revue que le verdict CI est affiché à côté — provider, conclusion et un lien vers l'exécution.

Comment les résultats sont appariés à un livrable

Comprendre ceci lève l'essentiel de la confusion :

Un agent qui ment est démasqué et rétrogradé. Si un agent a déclaré un succès, qu'un humain demande ensuite des modifications, et que le verdict signé était en deçà du seuil requis, le niveau de confiance de l'agent est automatiquement abaissé d'un cran et une entrée d'audit critique enregistre l'écart. La sur-déclaration a un coût.

Dépannage

Le point de terminaison répond 202 quoi qu'il arrive : la carte du connecteur et le journal d'audit sont donc vos seules fenêtres. Les motifs de rejet apparaissent sur la ligne Dernier événement de la carte.

SymptômeCause & correctif
Rien n'arrive, la carte ne se met jamais à jourMauvais nom d'hôte (posté vers une IP ou un hôte partagé → aucun tenant), ou le mauvais chemin de provider. Vérifiez que l'URL se termine par /github ou /generic et utilise le domaine propre au tenant.
Dernier événement rejeté · signatureLe secret diffère entre les deux côtés, ou — le classique — le type de contenu n'est pas application/json, de sorte que le corps brut n'a jamais été capturé. Reposez le secret et corrigez le type de contenu.
Dernier événement rejeté · no connectorLe connecteur est désactivé, n'a pas de secret, ou son secret stocké est devenu illisible après une rotation de clé de chiffrement. Ressaisissez le secret et activez-le.
Les résultats arrivent mais la porte reste en attenteLe commit ne correspond pas : SHA court contre SHA complet, ou le livrable porte un commit différent. Cela peut aussi signifier que la revue a eu lieu plus de 24 heures après l'exécution — le tampon a expiré.
GitHub indique le webhook livré, Vaks PM l'a ignoréL'événement était un ping ou une exécution en cours — accepté mais pas un verdict. Seules les exécutions terminées portent une conclusion.

Ce qui est journalisé

Sous Admin → Sécurité & Conformité → Journal d'audit : la création, la modification et la suppression d'un connecteur en sévérité critique ; chaque résultat signé accepté sous ci_result.received ; chaque rejet sous ci_webhook.rejected avec le motif. Lorsqu'un livrable est évalué, l'entrée enregistre si la CI l'a corroboré, la conclusion, et — si un agent a sur-déclaré — la rétrogradation de confiance. Le secret partagé n'est jamais écrit dans le journal.


À lire aussi : annuaires d'agents pour les identités gouvernées · webhooks sortants, la direction inverse · toutes les intégrations.