# Des agents de planification et d’exécution pour des changements de production plus sûrs

Un agent de planification ne devrait pas pouvoir transformer sa propre recommandation en changement de production. Donnez-lui la possibilité d’inspecter, de comparer et d’argumenter. Donnez à un agent d’exécution distinct un petit ensemble de droits d’action, puis demandez-lui de prouver que l’action demandée correspond à un changement approuvé.

Cette séparation peut sembler bureaucratique jusqu’au jour où vous voyez un agent faire passer une hypothèse plausible mais erronée à travers une frontière d’API. La plupart des incidents ne ressemblent pas à des attaques de dessin animé. Un agent lit une procédure obsolète, prend un nom d’hôte de staging pour celui de la production ou suit un texte non fiable dans un ticket. Si le même processus détient l’identifiant et l’autorité d’agir, l’erreur devient une modification avant que quiconque ait le temps de la remarquer.

## Un plan est un élément de preuve, pas une autorisation

Les agents de planification et d’exécution ont besoin d’autorités différentes, car la planification produit une affirmation sur le monde, tandis que l’exécution modifie le monde. Même un bon plan peut reposer sur des données obsolètes, un contexte incomplet du dépôt ou des instructions copiées depuis une source non fiable. Traiter un plan comme une permission revient à fusionner deux décisions qui méritent un examen séparé.

Un planificateur doit réunir les faits, expliquer les incertitudes, proposer des alternatives et produire une demande limitée. Il ne doit pas détenir un jeton de production simplement parce qu’il doit mentionner un endpoint dans un rapport. S’il lui faut des faits provenant d’un système protégé, exposez une opération de lecture conçue à cet effet, qui ne renvoie que les faits nécessaires, ou demandez à un humain de fournir le résultat pertinent.

L’exécuteur a une mission différente. Il reçoit une demande précise et détermine si elle entre dans son périmètre limité. Il ne relance pas la discussion de conception, ne parcourt pas des tickets arbitraires et n’accepte pas une phrase comme « répare le déploiement ». Cette phrase peut suffire dans une conversation. Elle ne constitue pas un contrat exploitable pour un processus possédant des identifiants.

Cette distinction corrige aussi une habitude que les équipes appellent « human in the loop » lorsqu’elles veulent dire « une personne a jeté un coup d’œil à une longue transcription de conversation ». Un réviseur ne peut pas reconstituer de manière fiable, à partir de prose, chaque appel d’outil qu’un agent pourrait effectuer. En revanche, il peut examiner une demande courte et structurée qui indique la cible, l’opération, les entrées, l’effet attendu et le chemin de restauration.

Le contrôle AC-5 de la norme NIST SP 800-53 demande une séparation des tâches afin de réduire le risque qu’une personne puisse utiliser abusivement un système sans être détectée. Le texte vise les personnes, mais le raisonnement s’applique tout aussi bien aux agents. Ne copiez pas une ancienne hiérarchie d’approbation dans un prompt. Séparez les capacités dans les identifiants et les interfaces d’outils réels.

## L’exécuteur doit être plus limité que le plan

L’exécuteur doit avoir moins de liberté que le planificateur, et pas seulement un prompt différent. Un agent distinct capable d’exécuter des commandes shell arbitraires avec un identifiant cloud étendu ne réduit pas réellement le risque. Il peut toujours réinterpréter une demande vague, découvrir d’autres ressources et effectuer des modifications sans rapport.

Commencez par un catalogue d’actions. Chaque action doit nommer une opération et accepter un petit nombre de paramètres. Par exemple, `deploy_service_revision` peut accepter un nom de service, un identifiant de révision immuable et un environnement cible. Il ne doit pas accepter un fragment shell ou une URL arbitraire.

La restriction la plus utile est souvent sémantique plutôt que technique. Un identifiant peut autoriser un déploiement, mais un wrapper d’exécution peut tout de même refuser un tag mutable comme `latest`, refuser la production en l’absence d’un identifiant de changement et refuser un service qui ne figure pas dans sa liste autorisée. Ces contrôles transforment des hypothèses qui vivent habituellement dans une procédure en code capable de refuser une demande risquée.

Ne confondez pas outil limité et résultat limité. Un jeton d’API capable de mettre à jour `billing-api` peut aussi modifier la répartition du trafic, les variables d’environnement et les paramètres d’autoscaling. Séparez ces opérations si l’API le permet. Sinon, placez devant elle une petite passerelle qui n’accepte que l’opération que vous êtes prêt à automatiser.

Un exécuteur crédible possède généralement les limites suivantes :

- Il utilise une identité distincte pour chaque environnement.
- Il ne reçoit que des actions nommées, jamais un shell généraliste.
- Il valide les noms de cibles et les entrées immuables avant d’appeler un fournisseur.
- Sa durée de vie est courte et il ne peut pas créer des identifiants plus étendus.
- Il produit un enregistrement durable de la demande et du résultat.

Les équipes résistent souvent à cette approche parce que les outils génériques sont plus rapides à brancher. Ils sont plus rapides pour la première démonstration. Un outil étendu comme `run_command` devient coûteux dès qu’il faut expliquer pourquoi un agent a supprimé la mauvaise ressource après avoir lu une commande copiée dans un ticket.

## Une transmission a besoin d’une demande de changement vérifiable par machine

Le planificateur doit transmettre un artefact structuré qu’un exécuteur peut valider sans interpréter l’intention. Les plans en texte libre incitent l’exécuteur à combler les lacunes avec son propre raisonnement, ce qui réintroduit l’autorité de planification dans le chemin d’action.

Une demande pratique peut ressembler à ceci :

```json
{
  "request_id": "chg-2025-0417-redis-timeout",
  "environment": "production",
  "action": "deploy_service_revision",
  "target": {
    "service": "checkout-api",
    "revision": "sha256:8f31c2..."
  },
  "expected_effect": "Run the approved checkout-api revision",
  "rollback": {
    "action": "deploy_service_revision",
    "revision": "sha256:31aa09..."
  },
  "approval": {
    "approved_by": "release-manager",
    "approved_request_hash": "b2c4..."
  }
}
```

Le hachage est important. Sans lui, un réviseur peut approuver la demande qu’il a vue alors que l’exécuteur reçoit une version modifiée. L’enregistrement d’approbation doit être lié à une représentation canonique des champs exacts que l’exécuteur utilisera. Si votre système sérialise le JSON différemment selon les endroits, définissez d’abord la canonisation. Un hachage de chaîne improvisé devient un piège lorsque l’ordre des champs ou les valeurs par défaut omises peuvent modifier la charge utile.

L’exécuteur doit refuser la demande en donnant une raison claire. Une réponse utile expose le contrôle qui a échoué sans révéler de secret :

```json
{
  "status": "denied",
  "request_id": "chg-2025-0417-redis-timeout",
  "reason": "revision must be an immutable digest",
  "executed": false
}
```

Ce refus fait partie de la conception, ce n’est pas un cas limite embarrassant. Les équipes testent si les agents peuvent effectuer des actions et négligent les tests qui prouvent qu’ils ne peuvent pas dépasser leur périmètre. Testez les deux chemins.

Ne laissez pas le planificateur choisir la définition de l’action de l’exécuteur. Le responsable de la plateforme doit définir le catalogue, ses règles de validation et la correspondance avec les identifiants. Le planificateur sélectionne parmi les actions prises en charge. Il ne peut pas inventer `deploy_anything` parce qu’une tâche semble urgente.

## Des processus séparés empêchent le partage accidentel d’autorité

Deux rôles d’agent dans un même processus restent faciles à confondre. Les variables d’environnement, les caches de jetons, les répertoires de travail et les enregistrements d’outils partagés créent des chemins accidentels autour de la limite prévue. Exécutez le planificateur et l’exécuteur dans des processus distincts, avec des configurations de lancement différentes.

Le processus du planificateur doit recevoir les outils de recherche et, éventuellement, des interfaces de lecture étroitement filtrées. Il ne doit pas voir les identifiants de l’exécuteur dans son environnement, ses fichiers de configuration ou les descriptions d’outils. Un modèle n’a pas besoin d’accéder en clair à un jeton pour en faire un usage abusif. Si le processus peut appeler un outil qui détient le jeton, la frontière de l’outil est la véritable frontière de capacité.

L’exécuteur doit recevoir la demande structurée approuvée et l’inventaire d’outils le plus réduit possible. Il ne doit pas recevoir le corps original du ticket, du contenu web arbitraire, un outil de recherche dans tout le dépôt ou la transcription de la conversation du planificateur. Ces éléments peuvent contenir une injection de prompt, de mauvaises commandes ou des instructions informelles que l’exécuteur n’a aucune raison de suivre.

Cela donne une règle simple pour le débogage : si un exécuteur a besoin de davantage de contexte pour décider quelle opération lancer, l’artefact de transmission est incomplet. Ne résolvez pas le problème en lui donnant un accès étendu à la découverte. Ajoutez le champ manquant, la règle de validation ou la décision humaine à la demande.

La séparation des processus aide aussi lors de la réponse à incident. Vous pouvez révoquer la session de l’exécuteur sans perdre l’historique de recherche du planificateur. Vous pouvez vérifier si le planificateur a proposé une cible différente de celle qui a été approuvée. Si les deux rôles partagent une session et une identité, cette reconstitution devient une affaire de conjecture.

Sallyport s’insère dans cette limite lorsqu’un agent compatible MCP a besoin d’actions HTTP ou SSH sans recevoir les identifiants API ou SSH sous-jacents. L’application conserve ces secrets dans son coffre chiffré et exécute elle-même l’appel. Le planificateur peut ainsi rester incapable d’extraire un identifiant, même si ses instructions déraillent.

## L’approbation doit intervenir au moment où les conséquences changent

Une approbation humaine doit couvrir une décision précise, et non donner une bénédiction vague à tout ce que l’agent fera ensuite. L’approbation de session est utile pour établir qu’un processus d’agent connu peut utiliser un ensemble limité d’actions peu risquées pendant une exécution. Elle remplace mal un examen lorsque l’action peut modifier des données de production, l’identité, l’exposition réseau ou de l’argent.

L’approbation par appel convient aux identifiants dont l’utilisation a des conséquences importantes. Le clic supplémentaire se justifie lorsque l’appel est irréversible, inhabituel ou coûteux à annuler. Placez-la sur une clé de suppression en production, un identifiant qui modifie le contrôle d’accès ou une opération de paiement. Ne l’imposez pas à chaque demande d’état sans risque. Une invite qui apparaît constamment devient du bruit de fond et les gens l’approuvent sans la lire.

Les approbations doivent afficher ce qu’un réviseur peut réellement évaluer : le nom de l’action, l’environnement cible, la ressource cible, l’entrée immuable et toute restauration prévue. Une boîte de dialogue qui dit seulement « L’agent demande un accès » relève du théâtre. Elle n’indique rien sur la conséquence.

La portée d’une approbation doit expirer. Une approbation liée à une exécution doit prendre fin lorsque le processus se termine. Une approbation liée à une demande de changement doit être attachée à son contenu et ne doit pas autoriser silencieusement une version ultérieure. Les autorisations d’approbation de longue durée sont séduisantes parce qu’elles réduisent les frictions, mais elles recréent le privilège permanent que la séparation devait éviter.

L’échelle de décision de Sallyport a une forme utile pour ce modèle : sa barrière de coffre refuse toute action tant qu’il est verrouillé, l’autorisation de session identifie un nouveau processus d’agent et certaines clés peuvent demander une confirmation à chaque utilisation. Cette approche est volontairement plus limitée qu’un moteur de politiques. Les équipes doivent tout de même décider quels identifiants méritent un examen à chaque appel.

## L’injection de prompt atteint les planificateurs avant les exécuteurs

L’injection de prompt entre souvent par le travail normal du planificateur. Un commentaire de dépôt lui dit d’exécuter une commande. Un ticket d’assistance contient une fausse instruction lui demandant d’exfiltrer une configuration. Une page web lui dit d’ignorer les consignes précédentes. Les agents de planification voient davantage de texte non fiable que les exécuteurs ne devraient jamais en voir.

La mauvaise réponse habituelle consiste à passer des mois à rédiger l’instruction parfaite qui dit au planificateur de ne pas se faire piéger. Le comportement du modèle peut s’améliorer, mais les instructions textuelles ne remplacent pas les limites d’autorité. Supposez que le planificateur puisse répéter une mauvaise instruction dans son plan. Faites ensuite en sorte que l’exécuteur refuse toute demande qui sort de son catalogue, de son périmètre ou de la liaison avec l’approbation.

Prenons un échec courant. Un planificateur étudie une latence et lit une ancienne note d’incident recommandant de ramener à zéro le nombre de réplicas d’un service avant de drainer le trafic. Il rédige un plan qui nomme le mauvais environnement parce que la note utilisait un nom d’hôte copié. Si ce planificateur peut appeler un outil de déploiement généraliste, il peut transformer une recommandation obsolète en interruption de service.

Avec une conception séparée, l’échec s’arrête à plusieurs endroits. La demande transmise doit nommer explicitement la production. L’exécuteur n’accepte qu’une action de déploiement de révision, pas une modification du nombre de réplicas. Le réviseur humain voit la cible réelle et l’effet demandé. Le journal de l’exécuteur enregistre le refus si la demande ne correspond pas. Aucun de ces contrôles ne demande au planificateur de reconnaître parfaitement un texte empoisonné ou obsolète.

Marquez la sortie du planificateur comme une entrée non fiable du chemin d’exécution. Cette mention doit modifier le traitement des données, pas seulement afficher un avertissement dans l’interface. N’interpolez pas la prose du planificateur dans des commandes shell. Ne le laissez pas remplir des chemins HTTP, des en-têtes ou des paramètres de requête sans contrôles de type et listes autorisées. Un schéma JSON aide, mais la validation du schéma ne vous dit pas à elle seule si `production` est une cible autorisée.

## L’accès en lecture peut tout de même ouvrir un chemin vers les dommages

Les équipes donnent souvent aux planificateurs un accès en lecture étendu parce que « cela ne peut rien modifier ». Cette phrase a causé de nombreux problèmes évitables. L’accès en lecture peut révéler des données clients, des noms d’hôtes internes, des historiques de déploiement, des indicateurs de fonctionnalité, des habitudes d’accès et les noms de systèmes privilégiés. Il peut aussi fournir précisément les informations dont un attaquant a besoin pour formuler une demande d’action convaincante.

Classez les lectures selon leur sensibilité et selon ce qu’elles permettent. Un endpoint de santé qui renvoie l’état d’un service n’est pas équivalent à un endpoint d’export de base de données. Un inventaire de services qui liste des noms publics n’est pas équivalent à une API de gestion des identifiants qui renvoie des identifiants et des métadonnées de secrets. Ne placez pas ces deux fonctions derrière le même outil générique `read_only`.

Donnez au planificateur des faits dérivés lorsque c’est possible. Au lieu de lui donner accès à chaque événement de déploiement, proposez une opération qui renvoie la révision actuelle, l’état de santé et l’identifiant du dernier changement approuvé pour un service nommé. Au lieu d’un accès étendu aux requêtes de base de données, fournissez une métrique qui répond à la question de diagnostic. Vous réduisez ainsi les fuites accidentelles et la quantité de contenu susceptible de transporter des instructions hostiles.

C’est ici que les équipes réagissent parfois de façon excessive et rendent la planification inutilisable. La solution n’est pas de rendre l’agent aveugle. Il faut déterminer quels faits la tâche exige et créer une interface de lecture pour ces faits. Si un planificateur a régulièrement besoin d’un champ supplémentaire, ajoutez-le délibérément après avoir examiné le cas d’usage. Ne résolvez pas chaque lacune en lui donnant accès à une console de production.

## Les journaux doivent permettre de reconstituer un désaccord

Une piste d’audit doit répondre à plus que la question « un appel d’API a-t-il eu lieu ? ». Après une modification contestée, vous devez comparer l’artefact proposé par le planificateur, celui qu’un humain a approuvé, la demande validée par l’exécuteur, l’appel externe exact et la réponse. L’absence d’un seul de ces éléments laisse place à un récit plutôt qu’à des preuves.

Conservez un identifiant de demande stable tout au long du parcours. Le planificateur l’attribue ou le reçoit. L’approbation y est liée ainsi qu’à son hachage de contenu. L’exécuteur l’enregistre avec son identité de processus et le résultat de l’action. La passerelle externe l’enregistre avec la destination sortante et le statut de la réponse. Évitez de journaliser des jetons bearer, des mots de passe, des clés privées ou des charges utiles sensibles complètes simplement pour faciliter la corrélation.

La preuve d’intégrité compte, car les journaux applicatifs ordinaires sont souvent stockés dans des systèmes que les administrateurs peuvent modifier. Une séquence d’événements liée par hachage rend les modifications ultérieures détectables si vous conservez l’état de chaîne attendu. Elle ne prouve pas magiquement que chaque événement est vrai. Elle rend plus difficile la dissimulation d’une réécriture silencieuse de l’historique enregistré, ce qui est précisément nécessaire lorsque l’accès au stockage des journaux recoupe les personnes examinées.

Sallyport produit ses journaux Sessions et Activity à partir d’un journal d’audit chiffré et chaîné par hachage, et `sp audit verify` vérifie la chaîne hors ligne sur le texte chiffré sans clé du coffre. C’est utile lors d’une enquête, car la vérification ne nécessite pas de remettre les identifiants d’action au réviseur.

Faites un exercice de reconstitution avant qu’un incident ne vous y oblige. Choisissez un changement approuvé et demandez à un collègue de répondre à cinq questions à partir des enregistrements : quel agent l’a proposé, qui a approuvé la demande exacte, quel exécuteur l’a lancé, quelle opération sortante a eu lieu et quel résultat a été renvoyé. Si une réponse dépend de la mémoire ou d’une transcription de conversation, améliorez les enregistrements.

## La première action automatisée doit être banale et réversible

Commencez la séparation avec une action dont le responsable est clair, dont l’ensemble de cibles est limité et dont la restauration a déjà été répétée. Déployer dans un environnement hors production avec une révision immuable est un meilleur premier cas que modifier des règles d’accès ou supprimer des comptes obsolètes. Un travail banal vous permet de découvrir les failles de conception sans miser la production sur une démonstration.

Faites passer la même tâche dans le workflow jusqu’à ce que le schéma de demande ne change plus pour des raisons triviales. Surveillez les échecs prévisibles : les planificateurs omettent une cible, les réviseurs approuvent une description générique, les exécuteurs ont besoin d’un contexte non déclaré et les journaux ne parviennent pas à associer l’approbation à l’appel. Chaque échec indique où l’autorité fuit encore entre les rôles.

Ne mesurez pas la réussite au nombre d’approbations supprimées. Vérifiez plutôt que l’exécuteur refuse une mauvaise cible, une révision non approuvée et une action non prise en charge, tout en exécutant l’action prévue. Un système qui rend chaque action facile a probablement rendu trop d’actions possibles.

Lorsque le workflow tient ses promesses, élargissez-le à une seule famille d’actions à la fois. Gardez le planificateur curieux et l’exécuteur prévisible. L’automatisation de production gagne la confiance lorsque ses refus sont aussi délibérés que ses réussites.
