liksi logo
IA

Trois règles pour ne plus croire un agent sur parole

Comment faire confiance aux tests et aux rapports qu'écrit un agent ? Retour d'expérience sur des montées de version Keycloak menées chez plusieurs clients.

Malo Toanen 8 min de lecture

Sommaire
Sommaire

Il y a quelques mois, une faille de sécurité a été publiée sur Keycloak, le gestionnaire d’identités open source. J’ai dû enchaîner les montées de version chez plusieurs clients. Quelques jours par migration, aucune connaissance de leur infrastructure ni de leurs usages, et une recette que le client mène lui-même, donc des tests de validation que je ne verrais pas passer. Il me fallait un maximum de vérifications en local avant la recette, pour arriver avec autre chose qu’une liste de points d’attention recopiés des notes de version.

Voici à quoi j’ai abouti. Deux instances Keycloak tournent en parallèle dans Docker, celle de la version de départ du client et celle de la version cible. Un script compare tout ce qui peut l’être entre les deux et qualifie chaque écart, attendu ou anormal. Ces écarts s’accumulent d’une migration à l’autre dans un fichier unique, versionné. Il compte 53 changements de comportement à ce jour, dont plusieurs que les notes de version de Keycloak ne mentionnent nulle part. Un contrôle par mutation introduit délibérément des défauts connus dans l’instance, pour vérifier que la comparaison les détecte. C’est cet ensemble que j’appelle le banc de test, réutilisable d’un client à l’autre.

Je n’ai écrit aucune spécification à l’avance. Trois semaines de calendrier séparent le premier prompt du dernier, pour l’équivalent d’un jour et demi à deux jours de travail réel. L’agent a tout produit, session après session. Mon rôle s’est limité à le guider et à lui poser des questions, toujours autour du même besoin : avoir confiance dans les tests produits, et dans le rapport remis au client.

Trois règles en sont sorties, chacune après un incident précis :

01
Toute affirmation doit être sourcée par une mesure. Sans mesure derrière elle, une affirmation ne vaut que la confiance qu'on accorde à son auteur.
02
Toute mesure doit être reproductible. Deux restitutions de la même mesure qui ne concordent pas ne prouvent rien.
03
Toute hypothèse doit porter sa provenance. Écrite sans sa source, elle devient indiscernable d'un fait vérifié.

1. Sourcer chaque affirmation par une mesure

Les deux premières migrations étaient encore en cours quand une question m’est venue, en relisant les scripts de test que l’agent avait écrits.

❯Comment être sûr que les tests que tu as écrits sont pertinents, et apportent un bon niveau de confiance quant aux migrations effectuées ?

Rien dans le banc de test ne permettait d’y répondre. Les tests passaient, mais aucun ne s’était encore retrouvé face à un vrai problème. Une affirmation du type « oui, les tests sont pertinents » n’a aucune valeur venant de celui qui les a écrits, qu’il soit humain ou agent.

Je n’ai pas eu à décrire le protocole attendu, la question a suffi. L’agent a proposé un contrôle par mutation et l’a implémenté : casser volontairement quelque chose de connu dans l’instance, puis vérifier que la comparaison le détecte. Un rôle retiré à un groupe d’utilisateurs, une étape de connexion supprimée, une contrainte de mot de passe désactivée. Chaque dégradation correspond à un problème qu’une migration ratée pourrait provoquer. Six minutes après mon feu vert, le contrôle tournait sur 7 mutations, toutes détectées. L’agent a ajouté des mutations au fil de la matinée. Une heure et demie plus tard, le contrôle en détectait 14 sur 14 chez un client, 13 sur 13 chez l’autre.

Le contrôle par mutation a changé la question que je pose à un test. Qu’il passe ne me suffit pas. Je veux savoir s’il échoue quand le problème est là.

2. Rendre chaque mesure reproductible

Le contrôle par mutation prouve qu’un test détecte un défaut réel, mais pas que le rapport remis au client restitue fidèlement ce résultat. Écrit dans deux rapports différents, le même constat prend-il la même forme ?

En relisant côte à côte les rapports de migration de deux clients, j’ai trouvé dix chiffres qui ne concordaient pas. L’agent lisait les résultats dans un terminal, puis les recopiait dans le rapport au fil de la rédaction. Devant un chiffre du rapport, impossible de retrouver la mesure d’où il venait. Les deux rapports se contredisaient même sur un fait mesurable, sans qu’aucun en apporte la preuve : l’un annonçait une reconnexion des utilisateurs, l’autre des sessions actives non affectées.

Les chiffres n’étaient que la partie visible. Ces rapports portaient aussi la même liste de changements à vérifier chez le client, qui aurait dû être identique puisqu’elle ne dépend que des versions en jeu. Elle ne l’était pas. Chaque changement y était rédigé autrement d’un rapport à l’autre. Il a fallu les reprendre un par un et choisir à chaque fois laquelle des deux rédactions garder. Reproduire un résultat, c’est aussi reproduire la prose qui le restitue.

❯ce tableau devrait a priori être le même pour toutes les migrations (en fonction des versions embarquées), je voudrais le persister dans un document dédié afin de le rendre plus déterministe. Compare les 2 versions […], détermine pour chaque point la meilleure, qui sera à conserver pour les prochaines migrations.

L’agent ne rédige plus rien au moment du rapport. Un fichier unique porte chaque changement avec sa formulation définitive. L’agent lit le contexte de la migration pour savoir qui doit le vérifier, le banc de test ou le client, au lieu de trancher à la rédaction. Le générateur en tire le rapport. Trois générations successives d’un même rapport produisent aujourd’hui un fichier identique, octet pour octet.

3. Tracer la provenance de chaque hypothèse

Cette règle est venue d’un diagnostic raté. Après un test de migration, des sessions utilisateur se perdaient. L’agent a avancé une explication cohérente et documentée dans les notes de version : un changement de format des cookies entre deux versions de Keycloak. Elle était fausse. Pour la tester, l’agent a lancé deux instances de la même version, sans aucune migration entre les deux. Les sessions s’y perdaient aussi. Le format des cookies n’y était donc pour rien.

Deux autres hypothèses sont tombées de la même façon. D’abord l’absence de persistance en base. J’ai retrouvé les sessions attendues, rangées ailleurs que prévu. Puis l’arrêt des nœuds du cluster. Après un redémarrage complet, la session revenait.

La cause réelle n’avait rien à voir avec Keycloak. Le serveur web placé devant l’instance migrée n’exposait pas le même port que l’instance de référence. Or Keycloak efface un cookie de connexion qui lui revient par un autre port que celui qui l’a émis. Mon propre banc de test fabriquait cette session perdue, sans rapport avec la migration.

L’agent a produit trois hypothèses plausibles, écrites avec la même assurance. Les deux premières étaient fausses, et j’avais déjà transmis la première aux clients comme une cause établie. Une fois dans un rapport, plus rien ne distingue une hypothèse d’un fait vérifié. Comprendre que ce n’étaient que des hypothèses m’a poussé à chercher la vraie cause avant de toucher aux rapports :

❯Il faudrait déterminer la cause avant de mettre à jour les rapports.

Depuis, chaque explication porte sa provenance : mesure directe, documentation officielle ou déduction. À défaut, le verdict devient non déterminé plutôt qu’une supposition habillée en certitude.

Ce que ça coûte de généraliser

Les deux migrations sont passées en recette puis en production chez les clients, sans incident. C’est le résultat qui compte. Il ne prouve pourtant rien à lui seul, puisqu’une migration réussie ne dit pas que le banc de test y était pour quelque chose.

Je peux en revanche mesurer ce qu’il ne couvre pas. Il s’appuie sur une configuration Keycloak que l’agent a reconstituée à partir du code : des utilisateurs, des rôles, des applications connectées, assemblés pour couvrir ce que le produit sait faire. Elle couvre la non-régression technique, sans rien dire des usages réels. J’avais décidé dès le premier jour de ne pas réclamer l’export de leur configuration aux clients, notamment pour que le banc de test soit le plus autonome possible.

J’ai demandé à l’agent ce que ce choix me coûtait.

❯Que se passerait-il si on avait un export du realm (de recette) d'un client : quels points pourraient être couverts […] ?

L’agent a d’abord répondu en regardant la configuration reconstituée, celle-là même qui a servi à écrire les vérifications. Il jugeait l’outil avec l’outil, et ne pouvait que confirmer ce que nous savions déjà. Il a fallu compter autrement. J’ai repris un par un les changements qui concernent chaque migration, en notant pour chacun ce que le banc de test établit avant la recette. Aujourd’hui, 22 ou 23 (selon la migration) reposent entièrement sur la recette du client. Avec un export de sa configuration, il n’en resterait que 9 ou 10 : le banc de test établirait les autres en amont, et la recette n’aurait plus qu’à les confirmer.

Les deux migrations qui ont produit le banc de test visaient la même version de Keycloak. Certaines vérifications que j’attribue aujourd’hui au banc de test ne valent peut-être que pour cette version. Je le saurai à la prochaine migration.

Ce que l’agent n’a pas fait

Ce récit vient de trois moments où l’agent s’est trompé, ce qui donne de lui une image incomplète. Le reste du temps, il a produit à peu près tout : les deux instances, les scripts de comparaison, le contrôle par mutation et la calibration, le générateur de rapport et le fichier qui décrit les 53 changements de comportement. Le premier jour, je lui avais interdit de reproduire la faille de sécurité. Quand une vérification l’aurait demandé, il l’a signalé dans son compte rendu au lieu de passer outre.

Ce que je n’ai jamais obtenu sans le demander, c’est le doute. Aucune des trois règles ne figurait dans une demande initiale. Chacune est née d’une question que j’ai posée en relisant. L’agent, lui, n’a jamais signalé de lui-même qu’il n’était pas sûr.

Note : les prompts cités dans cet article sont les prompts réels échangés avec l’agent, non reformulés, à quelques fautes de frappe près. Les coupes sont signalées par […], il s’agit de noms de clients ou de passages hors sujet. Les réponses de l’agent, elles, sont résumées dans mes mots plutôt que citées.