7 min de lecture

Des agents IA qui ouvrent des pull requests avec des contrôles sûrs

Les agents IA qui ouvrent des pull requests ont besoin d'un périmètre de dépôt strict, de branches protégées, d'un routage des réviseurs, de preuves de test et d'une trace d'audit pour chaque modification.

Des agents IA qui ouvrent des pull requests avec des contrôles sûrs

Les agents IA qui ouvrent des pull requests via une API peuvent faire gagner un temps précieux aux équipes d'ingénierie, mais seulement si le dépôt traite chaque modification générée comme une contribution non fiable dont l'auteur peut être identifié. La limite utile est simple : un agent peut préparer une modification proposée ; les personnes et les contrôles du dépôt décident si elle a sa place dans le code.

J'ai vu des équipes rendre ce processus dangereux en se concentrant sur la qualité du code produit par le modèle et en négligeant les permissions qui l'entourent. Les incidents les plus graves sont souvent très banals. Une tâche destinée à un service de staging aboutit dans un dépôt de production. Un jeton trop large accorde discrètement un accès en écriture à tous les projets. Après un délai d'attente, un agent ouvre dix pull requests presque identiques. Quelqu'un en fusionne une parce que son titre semble plausible.

Une configuration sûre ne suppose pas que l'agent sera prudent. Elle limite les endroits où il peut agir, fait passer la modification par la revue habituelle et laisse une trace assez complète pour permettre une enquête ultérieure.

Le périmètre du dépôt doit être explicite et imposé par la machine

Un agent doit recevoir des permissions pour un ensemble nommé de dépôts, et non un périmètre générique couvrant toute l'organisation que quelqu'un prévoit de réduire plus tard. Le périmètre répond à une question concrète : dans quels dépôts ce processus peut-il lire, écrire des branches et ouvrir des pull requests ?

Conservez la liste d'autorisation en dehors des instructions de l'agent. Les prompts peuvent guider son comportement, mais ils n'imposent pas l'autorisation. Le composant qui détient l'identifiant du dépôt ou effectue la requête API doit refuser tout dépôt absent de la liste.

Pour chaque dépôt autorisé, définissez les branches de base permises et l'espace de noms d'écriture autorisé. Voici un exemple utile :

repositories:
  - name: acme/payments-api
    base_branches: ["main", "release/2025.1"]
    write_branch_prefix: "agent/"
    pull_request_drafts: true
  - name: acme/docs
    base_branches: ["main"]
    write_branch_prefix: "agent/"
    pull_request_drafts: false

Ce fragment empêche un incident courant : un agent reçoit la demande de « corriger le texte du paiement », trouve un fichier similaire dans un dépôt qu'il peut parcourir et écrit à cet endroit parce que son identifiant l'y autorise. La liste d'autorisation transforme cette erreur en requête refusée, plutôt qu'en tâche de nettoyage pour quelqu'un d'autre.

Le périmètre couvre aussi les opérations sur le dépôt. La plupart des agents doivent lire des fichiers, créer une branche, pousser des commits, lire les vérifications et créer ou mettre à jour une pull request. Ils ont rarement besoin de modifier les paramètres du dépôt, d'enregistrer des webhooks, de changer les règles de protection des branches, d'ajouter des clés de déploiement, de gérer les membres ou de fusionner des modifications. N'accordez pas ces permissions simplement parce qu'elles sont incluses dans un jeton large et pratique.

Utilisez une identité de bot distincte plutôt que le jeton d'accès personnel d'un développeur. Un jeton personnel rend l'attribution floue, résiste mal aux changements de poste et possède souvent des permissions que personne ne se souvient d'avoir accordées. Une identité de bot vous donne un acteur unique à suspendre en cas de comportement anormal.

L'accès en lecture mérite la même attention que l'accès en écriture. Un agent capable d'inspecter tous les dépôts privés peut exposer du code source ou de la configuration dans ses journaux, son contexte de tâche ou ses réponses. Donnez-lui le plus petit ensemble de dépôts utile, même s'il ne reçoit jamais d'identifiant d'écriture direct.

Un préfixe de branche est une limite d'exécution, pas une préférence de nommage

L'agent doit créer des branches uniquement sous un préfixe dédié tel que agent/, et le serveur du dépôt doit imposer cette restriction. Une convention écrite dans un prompt finira par être contournée, à cause d'un appel d'outil mal formé, d'un bug de nouvelle tentative ou d'un agent cherchant à satisfaire une tâche trop large.

Protégez main, les branches de release, les branches d'environnement et toute branche qui déclenche un déploiement automatique. L'agent ne doit pas pouvoir y pousser, effectuer un push forcé ou modifier les règles qui les protègent.

Rendez les noms de branches suffisamment déterministes pour faciliter l'enquête et suffisamment uniques pour éviter les collisions. Incluez une référence à la tâche et un court suffixe aléatoire ou identifiant d'exécution :

agent/OPS-1842-retry-payment-7f3a

Ne laissez pas l'agent utiliser directement les titres des tickets comme noms de branches. Ces titres peuvent contenir des secrets, des noms de clients, des caractères dangereux ou une formulation trompeuse. Générez le nom de branche dans le contrôleur, puis transmettez-le à l'agent comme valeur immuable.

Le commit de base doit lui aussi suivre une règle explicite. Au début d'une exécution, le contrôleur doit résoudre la branche de base approuvée en SHA de commit et l'enregistrer. L'agent crée sa branche depuis ce SHA, et non depuis ce que main signifie après une longue génération de code. Cela ne supprime pas la dérive, mais la rend visible et reproductible.

Une branche ne doit contenir que les commits associés à la tâche qui lui a été attribuée. Pas de balayage de formatage opportuniste, de mise à jour de dépendance sans rapport ni tentative de « nettoyer » le code voisin parce qu'il semblait étrange. Les modifications générées paraissent souvent convaincantes, et les réviseurs manqueront plus facilement les changements sans rapport lorsqu'ils se trouvent dans un patch par ailleurs raisonnable.

Définissez un budget de modification avant le début du travail. Il peut limiter le nombre de fichiers modifiés, le nombre total de lignes ou les chemins situés hors du composant demandé. Ce plafond ne mesure pas à lui seul le risque. C'est un signal d'arrêt qui indique à l'agent de demander une nouvelle tâche au lieu de transformer discrètement une petite réparation en réécriture de tout le dépôt.

La création d'une pull request nécessite une transaction API vérifiée

Une réponse HTTP réussie ne prouve pas que l'agent a ouvert la bonne pull request. Le contrôleur doit vérifier le dépôt, la branche source, la branche de base, le SHA du commit et l'identifiant de la pull request renvoyé avant d'annoncer la réussite.

Pour une API de type GitHub, les champs importants sont le titre proposé, head, base, le corps et le statut draft. Le point d'accès exact varie selon la forge, mais les contrôles de sécurité restent les mêmes :

{
  "title": "OPS-1842: retry transient payment gateway failures",
  "head": "agent/OPS-1842-retry-payment-7f3a",
  "base": "main",
  "body": "Task: OPS-1842\nBase commit: 4b2c...\nTests: unit payment retry suite\nLimits: no configuration changes",
  "draft": true
}

Avant d'envoyer cette requête, interrogez la branche et vérifiez que son SHA de pointe correspond au commit enregistré par l'exécution. Après la réponse, récupérez la pull request et comparez son head, son base et son état avec la requête. Enregistrez le numéro immuable ou l'identifiant de nœud de la pull request fourni par la plateforme, et pas seulement son URL.

Les nouvelles tentatives nécessitent un traitement particulier. Les délais d'attente réseau créent le problème classique des pull requests en double : le serveur peut avoir créé la pull request 418 alors que le client n'a pas reçu la réponse et réessaie. Conservez dans votre contrôleur un enregistrement d'idempotence contenant l'identifiant de tâche, le dépôt, la branche, le SHA de base et le numéro de la pull request. Lors d'une nouvelle tentative, recherchez la branche et la pull request existantes avant d'appeler la création.

N'utilisez pas un titre de tâche comme seule valeur d'idempotence. Une demande récurrente telle que « mettre à jour la documentation générée » entrerait en collision avec une exécution précédente. L'identifiant d'exécution doit identifier une exécution unique, tandis que l'identifiant de tâche aide à relier les travaux associés.

Les pull requests en brouillon constituent une bonne valeur par défaut pour le travail des agents. Elles indiquent aux réviseurs que la modification existe, mais qu'elle n'a pas encore franchi le propre seuil d'achèvement déclaré par son créateur. Un agent ne peut marquer une pull request comme prête qu'après l'exécution des commandes obligatoires et l'enregistrement de leurs résultats. Si votre dépôt n'utilise pas les brouillons, appliquez une étiquette telle que agent-created via un contrôleur fiable, et non via du texte composé par l'agent.

L'affectation des réviseurs doit suivre la propriété et le risque

Le premier réviseur doit être déterminé par les règles de propriété du dépôt, et non par un agent qui devine qui semble compétent. La documentation de CODEOWNERS de GitHub décrit une correspondance entre fichiers et propriétaires qui peut demander une revue pour les chemins modifiés. GitLab propose des mécanismes comparables d'approbation et de propriétaire de code. Ces fichiers sont utiles pour le routage, mais ils ne rendent pas automatiquement la revue obligatoire si la protection des branches ou les règles de fusion ne l'exigent pas.

Cette distinction compte. Un dépôt peut afficher une demande adressée à un propriétaire de code tout en autorisant une fusion sans son approbation, selon sa configuration. Traitez le routage et l'application de la règle comme deux contrôles distincts. Vérifiez-les avec une pull request de test volontairement non autorisée avant de faire confiance à la politique.

Utilisez la liste des fichiers modifiés après le commit final, et non les chemins que l'agent prévoyait de modifier. Un patch généré peut atteindre tardivement une bibliothèque partagée, un répertoire de déploiement ou un dossier de migration. Le calcul des réviseurs doit porter sur ce qui a réellement changé.

Ajoutez une personne responsable lorsque la tâche concerne des zones où les règles de propriété sont trop larges ou absentes. Cette personne porte l'intention de la tâche. Un propriétaire de code peut confirmer que l'implémentation convient à un composant ; la personne responsable peut confirmer que le comportement demandé convient au produit. N'affectez pas une douzaine de personnes simplement parce que le diff traverse plusieurs frontières. Les longues listes produisent le résultat habituel : chacun suppose qu'un autre réviseur s'est occupé du point difficile.

Certains chemins doivent imposer un parcours plus strict, par exemple les migrations de base de données, le code d'autorisation, les définitions de build et de release, les manifestes de dépendances, la configuration d'infrastructure et les artefacts générés. La bonne réponse n'est pas toujours « bloquer l'agent ». C'est souvent « exiger le propriétaire qui comprend les conséquences ». Une migration peut réussir les tests unitaires tout en rendant une restauration impossible.

Affectez les réviseurs via l'API uniquement après la création de la pull request et vérifiez l'affectation obtenue. Si un groupe de propriétaires ne peut pas recevoir de demande, le contrôleur doit marquer la pull request comme bloquée plutôt que de la confier discrètement à un développeur choisi au hasard. Un remplacement silencieux transforme une règle de propriété en simple décoration.

Les tests décrivent des preuves, l'approbation décide de l'acceptation

Approuvez le processus de pull request
Un nouveau processus agent nécessite l'approbation d'une session, pilotée par son autorité de signature du code.

L'agent doit préciser exactement ce qu'il a exécuté, ce qu'il n'a pas exécuté et pourquoi. « Les tests ont réussi » ne veut rien dire sans les commandes, le code de sortie et le SHA du commit testé. Conservez également ces preuves en dehors du texte de la pull request, car un agent peut modifier ce texte plus tard.

Utilisez un petit rapport structuré pour chaque exécution :

{
  "run_id": "run_01J...",
  "repository": "acme/payments-api",
  "head_sha": "8c71...",
  "commands": [
    {"command": "npm test -- payment-retry", "exit_code": 0},
    {"command": "npm run lint", "exit_code": 0}
  ],
  "not_run": ["integration suite requires payment sandbox approval"]
}

Le contrôleur doit refuser le passage à l'état prêt pour revue lorsque les preuves mentionnent un SHA différent de celui en tête de branche. Cela détecte une séquence subtile mais fréquente : l'agent exécute les tests, apporte encore une « petite » correction, puis ouvre la pull request sans rien relancer.

Les vérifications obligatoires doivent rester du côté du dépôt. L'agent ne doit pas pouvoir les ignorer, approuver sa propre pull request, modifier la protection des branches ou fusionner. Une vérification peut établir qu'une commande connue a réussi. Elle ne peut pas établir qu'une nouvelle règle d'autorisation est correcte, que le besoin a été compris ou que la tâche aurait dû être tentée dans ce dépôt.

Ne remplacez pas la revue du diff par un résumé généré. Les bons résumés aident les réviseurs à s'orienter, mais ce sont les affirmations de l'auteur. Les réviseurs doivent voir les modifications réelles, les tests, le contexte du ticket concerné et les omissions volontaires.

Chaque modification créée doit laisser une trace d'audit qui résiste aux incidents

Identifiez chaque exécution d'agent
Le journal des sessions enregistre les exécutions des agents et permet de révoquer une session instantanément.

Une URL de pull request n'est pas un journal d'audit. Elle peut disparaître lorsque les dépôts sont déplacés, les branches supprimées, les accès modifiés ou la description éditée. Conservez un relevé d'événements en ajout seulement, permettant de répondre à ces questions : qui a lancé l'exécution, quel processus a effectué chaque appel, quel dépôt a changé et qu'a renvoyé le système ?

Enregistrez au minimum :

  • un identifiant d'exécution et la référence du ticket ou de la tâche d'origine ;
  • l'identité du bot et celle du processus agent authentifié ;
  • le dépôt, la branche de base, le SHA de base, la branche source et chaque SHA de commit créé ;
  • le type de requête API, l'identifiant immuable de la pull request, les horodatages et le statut du résultat ;
  • les demandes de revue, les approbations, les résultats des vérifications, les événements de fermeture, de fusion ou de rejet.

Ne placez pas par défaut dans le journal d'audit des identifiants en clair, des fichiers source complets ou des prompts de tâche arbitraires. Les enquêteurs ont besoin de faits d'action fiables, pas d'une copie incontrôlée supplémentaire de données sensibles. Si vous conservez le contenu du patch, enregistrez une empreinte et appliquez vos règles habituelles de conservation et d'accès.

Il est utile de distinguer le journal d'activité du journal des décisions. Le premier indique qu'un appel API a créé la pull request 418. Le second indique qui a approuvé la session de l'agent, qui a modifié son autorisation et qui l'a révoquée. En cas d'incident, les deux sont importants. Vous devez savoir ce qui s'est passé et pourquoi l'acteur disposait de l'autorité nécessaire à ce moment-là.

Sallyport peut conserver les sessions des agents ainsi que les appels HTTP ou SSH individuels dans des journaux projetés depuis son journal d'audit chiffré et chaîné par hachage. La commande sp audit verify vérifie la chaîne hors ligne sur le texte chiffré. Cette approche convient lorsque l'agent demande une action sans jamais recevoir lui-même l'identifiant du dépôt.

Le chaînage par hachage rend les modifications ultérieures détectables ; il ne rend pas complet un relevé d'événements faible. Enregistrez les identités du dépôt et des commits au moment de l'action. Un relevé parfaitement vérifié de « requête HTTP envoyée » ne vous dira pas si la requête a créé la mauvaise pull request.

Gardez les identifiants hors de l'agent et séparez création et fusion

L'agent ne doit jamais détenir un jeton de dépôt étendu dans son prompt, son environnement, un fichier de travail ou la sortie d'un outil. Dès que le jeton entre dans ce contexte, il peut fuiter par les journaux, l'historique du shell, les messages d'erreur, des transcriptions copiées ou une instruction qui persuade l'agent de l'afficher. Une suppression ultérieure ne remet pas véritablement le secret sous contrôle.

Utilisez une passerelle d'action ou un contrôleur limité qui accepte une demande précise : créer une branche dans ce dépôt, pousser ces commits vers ce préfixe autorisé, créer une pull request en brouillon vers cette branche de base approuvée ou demander ces réviseurs. La passerelle injecte les identifiants et renvoie le résultat. Elle doit refuser les appels qui ne respectent pas le périmètre déclaré.

Les droits de création et de fusion sont différents. Un service capable de créer une pull request peut proposer des milliers de mauvaises modifications. Un service capable de fusionner peut en envoyer une seule dans la production. Ne les combinez pas pour rendre une démonstration plus fluide. Conservez l'action de fusion sous le contrôle des règles de protection des branches et d'une personne responsable, même lorsque l'agent a produit un patch irréprochable.

L'autorisation par exécution est également préférable à un processus d'agent approuvé en permanence. Les outils d'agent peuvent lancer des sous-processus, être réutilisés dans des tâches inattendues et rester actifs après la fin de la tâche qui justifiait l'accès. Donnez à un processus une session limitée, enregistrez l'approbation et rendez la révocation immédiate.

Un exercice d'échec révèle les lacunes que le texte des politiques dissimule

Gardez les clés du dépôt hors des agents
Sallyport injecte les identifiants HTTP depuis son coffre chiffré. L'agent reçoit les résultats, pas les clés du dépôt.

Effectuez un exercice contrôlé avant de vous fier à la création automatisée de pull requests. Utilisez un dépôt de test ou une politique de branche temporaire et donnez à l'agent une tâche qui tente de franchir chaque limite. L'objectif est de vérifier les refus et leur enregistrement, pas d'admirer une démonstration du parcours nominal.

Commencez par un dépôt autorisé et un dépôt interdit. Vérifiez que le contrôleur peut créer la pull request en brouillon attendue dans le premier et refuse la seconde avant l'apparition de toute branche. Tentez ensuite un push vers main, un push forcé vers une branche agent/ et une pull request vers une branche de release non approuvée. Examinez les événements du dépôt, pas uniquement les messages du contrôleur.

Simulez ensuite un délai d'attente après l'arrivée de la requête de création auprès de l'API du dépôt. Redémarrez l'exécution et vérifiez qu'elle retrouve la pull request d'origine au lieu d'en ouvrir une nouvelle. Modifiez la branche après l'enregistrement des résultats de test et vérifiez que le passage à l'état prêt s'arrête à cause du décalage de SHA.

Enfin, révoquez la session de l'agent pendant une exécution et tentez un nouvel appel API. L'appel doit échouer, le refus doit apparaître dans le relevé des décisions et aucun identifiant ne doit être visible dans la sortie de l'agent. Si l'un de ces tests dépend de l'intervention d'une personne qui remarquerait un message de chat, le contrôle n'existe pas encore.

La première mesure concrète consiste à inventorier le jeton utilisé aujourd'hui par votre agent. Listez chaque dépôt qu'il peut toucher, chaque branche qu'il peut modifier et sa capacité éventuelle à fusionner ou à changer les paramètres. La plupart des équipes découvrent que le jeton est plus large que nécessaire. Réduisez ce périmètre avant de demander à l'agent de produire une nouvelle pull request.

FAQ

Quelles permissions faut-il donner à un agent IA pour ouvrir des pull requests ?

Un agent doit utiliser une identité de bot dédiée, avec uniquement les permissions de dépôt et d'API nécessaires pour créer des branches, pousser vers un espace de noms autorisé et ouvrir des pull requests. Il ne doit pas disposer de permissions de maintenance, d'administration ou de fusion. La limite imposée aux identifiants compte autant que les instructions.

Faut-il autoriser les agents IA à pousser directement vers la branche main ?

Donnez à l'agent un préfixe de branche tel que agent/ et refusez ses pushes partout ailleurs. Protégez les branches par défaut et les branches de release afin que seul votre processus normal de fusion puisse les modifier. L'agent ne pourra ainsi pas contourner la revue en choisissant une cible pratique.

Quelle doit être la taille d'une pull request générée par une IA ?

Une pull request doit avoir un objectif cohérent, un diff limité et des tests clairement indiqués. Si une tâche nécessite une refactorisation sans rapport, des mises à jour de dépendances et une modification de comportement, séparez-la. La qualité de la revue s'effondre lorsqu'une personne doit reconstituer plusieurs décisions à la fois.

Comment affecter des réviseurs aux pull requests créées par une IA ?

Utilisez les règles de propriété du dépôt pour l'affectation initiale, puis ajoutez une personne responsable lorsque les changements concernent des fichiers générés, des migrations, des permissions, des définitions de déploiement ou du code sensible sur le plan de la sécurité. CODEOWNERS facilite le routage, mais ne remplace pas les exigences de revue. Un réviseur obligatoire doit être imposé par la protection des branches ou les règles de fusion.

Que faut-il enregistrer lorsqu'un agent crée une pull request ?

Enregistrez la session de l'agent, l'identité de l'acteur, le dépôt, le SHA du commit, les noms de branches, les paramètres de la requête, l'URL de la pull request, les horodatages, les approbations et le résultat de la fusion. Conservez la référence de la tâche et, si vos règles de conservation l'autorisent, une empreinte du patch. Un titre et une URL ne constituent pas un journal d'audit exploitable.

Est-il sûr de laisser un agent IA créer automatiquement des pull requests ?

Cela peut être sûr si l'agent n'a aucun droit de fusion, ne travaille que dans des dépôts autorisés et ne peut pas pousser vers des branches protégées. Exigez une revue humaine, des vérifications réussies et un relevé clair de chaque action. Traitez l'agent comme un contributeur non fiable doté de mains rapides, pas comme un mainteneur.

Un agent IA peut-il ouvrir des pull requests via une API ?

Utilisez l'API de la plateforme du dépôt pour créer la branche depuis un commit de base explicite, pousser les commits et créer la pull request vers une branche de base approuvée. Vérifiez la réponse, enregistrez l'identifiant renvoyé et arrêtez-vous si une requête échoue. Ne récupérez pas les informations depuis l'interface web et ne déduisez pas la réussite d'une URL générée.

Un agent doit-il mettre à jour une pull request existante ou en créer une nouvelle ?

L'agent doit proposer une nouvelle pull request lorsque le résultat attendu a changé, que la branche d'origine a été remplacée ou que les réviseurs doivent prendre une décision distincte. Il ne doit mettre à jour une pull request existante que si la tâche et la responsabilité restent les mêmes. Réutiliser une pull request pour dissimuler un nouveau périmètre constitue un échec de revue.

Comment empêcher un agent de créer des pull requests en double ?

Utilisez des données d'idempotence dans votre propre contrôleur : enregistrez un identifiant de tâche, le dépôt, le SHA de base, le nom de branche et le numéro de la pull request créée avant de réessayer. Lors d'une nouvelle tentative, recherchez la branche et la pull request ouverte existante avant d'en créer une autre. La plupart des API de dépôt acceptent les requêtes répétées, mais cela ne rend pas les doublons inoffensifs.

Des tests réussis rendent-ils les pull requests IA sûres à fusionner ?

Non. Un diff propre ne dit pas grand-chose sur le fait que l'agent a choisi le bon comportement, modifié le bon dépôt ou utilisé une dépendance approuvée. Les tests et les règles de revue doivent rester obligatoires, et les personnes doivent disposer de suffisamment de contexte pour juger la modification demandée.

Sallyport

Sallyport exécute les appels d'API et les commandes SSH à la place de votre agent IA. Les clés restent dans un coffre-fort local sur votre Mac ; vous approuvez chaque exécution et chaque action est consignée dans un journal scellé.

© 2026 Sallyport · Open source sous Apache-2.0 · Oleg Sotnikov