<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>GenAI on Zwindler's Reflection</title><link>https://blog.zwindler.fr/tags/genai/</link><description>Recent content in GenAI on Zwindler's Reflection</description><generator>Hugo -- gohugo.io</generator><language>fr-fr</language><copyright>Licensed under CC BY-SA 4.0</copyright><lastBuildDate>Wed, 23 Sep 2026 20:00:00 +0200</lastBuildDate><atom:link href="https://blog.zwindler.fr/tags/genai/index.xml" rel="self" type="application/rss+xml"/><item><title>Trouver des vulnérabilités dans l'open source quand on n'est pas spécialiste en sécurité</title><link>https://blog.zwindler.fr/2026/09/23/finding-vulnerabilities-oss-not-security-specialist/</link><pubDate>Wed, 23 Sep 2026 20:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2026/09/23/finding-vulnerabilities-oss-not-security-specialist/</guid><description>&lt;img src="https://blog.zwindler.fr/2026/09/20260919_152513.webp" alt="Featured image of post Trouver des vulnérabilités dans l'open source quand on n'est pas spécialiste en sécurité" /&gt;&lt;h2 id="tldr"&gt;TL;DR
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Trouver des failles dans l&amp;rsquo;open source en 2026, &amp;ldquo;grâce&amp;rdquo; aux LLM : facile, OUI&lt;/li&gt;
&lt;li&gt;Être le &lt;em&gt;premier&lt;/em&gt; à les remonter : possible, MAIS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Trouver des failles est devenu banal. Le vrai défi, c&amp;rsquo;est d&amp;rsquo;être le premier, et de survivre au triage. C&amp;rsquo;est de ça que parle le reste de l&amp;rsquo;article.&lt;/p&gt;
&lt;h2 id="pourquoi-faire-ça-au-départ-"&gt;Pourquoi faire ça, au départ ?
&lt;/h2&gt;&lt;p&gt;La cybersécurité, ça me passionne depuis&amp;hellip; bah, depuis toujours. Mon deuxième programme d&amp;rsquo;enfant était un &lt;a class="link" href="https://winworldpc.com/product/microsoft-visual-bas/30" target="_blank" rel="noopener"
&gt;VB 3.0&lt;/a&gt; à la con, un faux virus qui avait pour seul boulot de remplir le dossier Démarrage de Windows 95/98 de milliers de commandes &lt;a class="link" href="https://en.wikipedia.org/wiki/Windows_Messenger_service" target="_blank" rel="noopener"
&gt;netsend&lt;/a&gt; auto-exécutables (si vous ne savez pas ce que c&amp;rsquo;était, allez jeter un œil !).&lt;/p&gt;
&lt;p&gt;Mais je n&amp;rsquo;en ai jamais fait mon métier, même si l&amp;rsquo;idée m&amp;rsquo;est venue à plusieurs reprises. Ces derniers mois, j&amp;rsquo;ai collaboré plus étroitement que d&amp;rsquo;habitude avec mes collègues de l&amp;rsquo;équipe cybersécurité, et j&amp;rsquo;ai fini par me lancer : je voulais voir ce que je pouvais faire avec les LLM dans ce domaine.&lt;/p&gt;
&lt;p&gt;Disclaimer : je ne suis &lt;strong&gt;PAS&lt;/strong&gt; spécialiste en cybersécurité, pas le moins du monde. Si vous ne me connaissez pas, je ne suis qu&amp;rsquo;un platform engineer qui s&amp;rsquo;y connaît en Kubernetes, virtualisation et observabilité. Je code de manière correte en golang et en python.&lt;/p&gt;
&lt;h2 id="quel-est-le-but-au-juste-"&gt;Quel est le but, au juste ?
&lt;/h2&gt;&lt;p&gt;Ces deux derniers mois, je me suis mis à traquer (sur mon temps libre) des vulnérabilités dans des logiciels open source populaires que j&amp;rsquo;utilise au quotidien dans mon travail. Certains ont un programme de bug bounty, d&amp;rsquo;autres acceptent les GitHub Security Advisories. D&amp;rsquo;autres ne répondent tout simplement pas.&lt;/p&gt;
&lt;p&gt;Pourquoi l&amp;rsquo;open source ? Bah déjà, le fait que le code soit ouvert me permet de vérifier les choses quand le LLM pense que quelque chose cloche, et de me forger ma propre opinion. L&amp;rsquo;inconvénient, honnêtement, c&amp;rsquo;est que les LLM sont aussi la raison pour laquelle l&amp;rsquo;open source se noie sous les rapports de sécurité depuis environ un an.&lt;/p&gt;
&lt;p&gt;Mais surtout : je travaille avec ces outils tous les jours, je sais donc &lt;strong&gt;COMMENT&lt;/strong&gt; ils devraient fonctionner, et ce qui &lt;strong&gt;N&amp;rsquo;EST PAS&lt;/strong&gt; normal. On reviendra là-dessus aussi.&lt;/p&gt;
&lt;p&gt;Une chose avant de commencer : tout ce qui est décrit ci-dessous a été fait sur ma propre infrastructure : clusters jetables, installations locales, VM de test. Chaque programme de bug bounty a ses règles du jeu : pas de scan d&amp;rsquo;instances tierces, pas de toucher aux données des autres, pas de déni de service sur une infra partagée. Lisez-les. Si une de vos découvertes nécessite de les enfreindre pour être prouvé, c&amp;rsquo;est que vous vous y prenez mal.&lt;/p&gt;
&lt;h2 id="ok-ok-assez-dintroduction--les-llm-peuvent-ils-trouver-des-failles-sans-expérience-en-cybersécurité-"&gt;Ok ok, assez d&amp;rsquo;introduction : les LLM peuvent-ils trouver des failles sans expérience en cybersécurité ?
&lt;/h2&gt;&lt;p&gt;Réponse courte : oui. La vraie question, c&amp;rsquo;est de savoir si ça vaut le coup, et ça dépend surtout de si vous voulez être le premier ou non, et de &lt;strong&gt;QUAND&lt;/strong&gt; vous commencez.&lt;/p&gt;
&lt;p&gt;Voici mon propre retour d&amp;rsquo;expérience sur la chasse aux vulnérabilités dans l&amp;rsquo;open source. &amp;ldquo;YMMV&amp;rdquo;, comme on dit.&lt;/p&gt;
&lt;h2 id="vous-avez-déjà-raté-le-coche"&gt;Vous avez déjà raté le coche
&lt;/h2&gt;&lt;p&gt;La première chose à savoir, c&amp;rsquo;est que (si vous commencez aujourd&amp;rsquo;hui) vous êtes &lt;strong&gt;très en retard&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est encore plus vrai pour les logiciels couverts par un bug bounty, parce que les chasseurs fouillaient déjà avant l&amp;rsquo;arrivée des LLM. Mais la pression sur ces projets a été multipliée par mille depuis.&lt;/p&gt;
&lt;p&gt;Des chiffres concrets, tirés des pages publiques de deux très gros projets (stats sur 90 jours, septembre 2026), volontairement non cités (c&amp;rsquo;est bien l&amp;rsquo;écart qui compte) :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Un programme, encore à peu près en vie : 4 193 rapports reçus, ~454 000 $ versés&lt;/li&gt;
&lt;li&gt;L&amp;rsquo;autre, essentiellement mort : 551 rapports reçus, 1 000 $ versés, dernier rapport traité il y a un mois&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Relisez bien. Ce volume, c&amp;rsquo;est en grande partie du bruit généré par de l&amp;rsquo;IA. curl a &lt;a class="link" href="https://daniel.haxx.se/blog/2026/01/26/the-end-of-the-curl-bug-bounty/" target="_blank" rel="noopener"
&gt;complètement arrêté&lt;/a&gt; son bug bounty payant en début 2026, après l&amp;rsquo;effondrement du ratio de rapports valides. D&amp;rsquo;autres projets ont suspendu les paiements ou sont passés en accès sur invitation (&lt;a class="link" href="https://hackerone.com/nextcloud/policy_versions?type=team&amp;amp;change=3773031" target="_blank" rel="noopener"
&gt;Nextcloud&lt;/a&gt;, &lt;a class="link" href="https://app.intigriti.com/programs/grafanalabs/grafanaossbbp/detail" target="_blank" rel="noopener"
&gt;Grafana&lt;/a&gt;). Les mainteneurs se noient.&lt;/p&gt;
&lt;p&gt;Alors si vous pensez être plus malin que tout le monde et que vous comptez vous faire de l&amp;rsquo;argent rapide avec votre compte Claude, réfléchissez-y à deux fois. Des centaines de personnes y avaient déjà pensé il y a un an, et il y en a un peu plus chaque jour. Vous êtes en concurrence avec elles, avec des professionnels aguerris, et avec des gens qui ont bien plus de ressources IA que vous.&lt;/p&gt;
&lt;h2 id="parlons-modèles-choisissez-vos-armes"&gt;Parlons modèles (choisissez vos armes)
&lt;/h2&gt;&lt;p&gt;J&amp;rsquo;ai d&amp;rsquo;abord essayé les options évidentes (&amp;ldquo;ça se passe mal!&amp;rdquo;) :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Claude&lt;/strong&gt; : tout ce qui touche de près ou de loin à la cybersécurité est flaggé et bascule en mode fortement restreint. Au bout de quelques heures, la session est carrément gelée. La seule parade, c&amp;rsquo;est de relancer des sessions et de perdre son contexte à chaque fois - et les blocages se font plus fréquents avec le temps, même pour du travail parfaitement légitime. La voie officielle, c&amp;rsquo;est le &lt;strong&gt;Cyber Verification Program&lt;/strong&gt; d&amp;rsquo;Anthropic (OpenAI a un équivalent, le Cybersecurity Grant Program), mais la validation semble arbitraire : plusieurs chercheurs en sécurité que je connais personnellement se sont fait refuser sans explication, et ils ne sont pas seuls.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/09/CVP_rejected.avif"
loading="lazy"
alt="Post LinkedIn d’un ingénieur sécurité senior titulaire d’un CVE du noyau Linux, partageant l’e-mail rejetant sa candidature au Cyber Verification Program d’Anthropic"
&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Google Antigravity&lt;/strong&gt; : ça a très bien marché pendant 2 jours, puis les blocages ont commencé. Google n&amp;rsquo;a aucun programme pour certifier les chasseurs légitimes, vous pouvez donc l&amp;rsquo;oublier. Un mois d&amp;rsquo;abonnement pour rien.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ce qui marche : laissez tomber les grands fournisseurs américains et passez à des alternatives moins regardantes. Soit un accès par abonnement à des modèles open weights / chinois, soit des plateformes agentic avec des quotas généreux.&lt;/p&gt;
&lt;p&gt;Et les API au token ? Très mauvaise idée pour ce genre de travail. La chasse aux failles demande un nombre absurde de tokens en lecture. Mes chiffres à moi : &lt;strong&gt;environ 11 milliards de tokens en 2 mois&lt;/strong&gt;, dont la grande majorité (plus de 90%) servie depuis le cache côté fournisseur. Même avec l&amp;rsquo;une des options les moins chères au moment où j&amp;rsquo;écris (GLM 5.3 sur un broker bien connu), ça revient à environ 1 800 $. Un modèle frontier coûterait plusieurs fois ce montant. Choisir un fournisseur dont le cache est facturé moins cher aide énormément, mais vous ne voulez quand même pas de cette facture en fin de mois.&lt;/p&gt;
&lt;p&gt;Les abonnements qui donnent accès à GLM, DeepSeek, Kimi&amp;hellip; sont probablement de bonnes options (pas encore essayé). Ce que j&amp;rsquo;ai réellement utilisé pendant 2 mois, c&amp;rsquo;est &lt;strong&gt;devin.ai&lt;/strong&gt; (l&amp;rsquo;outil agentic de Cognition, anciennement Windsurf) : leur modèle maison est compétent et, au moment où j&amp;rsquo;écris, illimité dans l&amp;rsquo;abonnement de base. Ce genre de promo va et vient, vérifiez avant de vous abonner.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Pas sponsorisé, je paie de ma poche 🥲.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="et-les-modèles-locaux-"&gt;Et les modèles locaux ?
&lt;/h2&gt;&lt;p&gt;L&amp;rsquo;idée est vraiment séduisante. Être autonome avec du matériel local (ou en louer) plutôt que de payer au token des tâches coûteuses, tout en échappant à la censure des fournisseurs, ça ressemble à une idée de génie (qui pense GIFI dans sa tête ?). C&amp;rsquo;est la première chose que j&amp;rsquo;ai essayée après mon &amp;ldquo;fiasco&amp;rdquo; Claude/Antigravity.&lt;/p&gt;
&lt;p&gt;Alors&amp;hellip; peut-on utiliser des modèles open weights locaux pour éviter de griller son quota en 20 minutes ? Avec un modèle ~30B (type Qwen, ou la meilleure variante du moment), on &lt;em&gt;peut&lt;/em&gt; trouver quelques failles sur des gros projets anciens&amp;hellip; mais c&amp;rsquo;est comme courir un marathon avec un sac à dos rempli de cailloux après les avoir peint (dédicace à Vincent). C&amp;rsquo;est faisable, mais ne vous attendez pas à ce que ce soit simple ni efficace.&lt;/p&gt;
&lt;p&gt;Si vous partez sur cette voie, le pipeline ci-dessous compte encore plus qu&amp;rsquo;avec des modèles plus &amp;ldquo;gros&amp;rdquo;.&lt;/p&gt;
&lt;h2 id="mon-pipeline"&gt;Mon pipeline
&lt;/h2&gt;&lt;p&gt;Quel que soit le modèle, la première chose dont vous avez besoin, c&amp;rsquo;est un cadre solide. Voilà ce que j&amp;rsquo;ai fait (plutôt basique, il existe peut-être des méthodes plus efficaces, mais c&amp;rsquo;est un bon point de départ) :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Analysez un composant de votre cible à la fois. Demandez au modèle de cartographier son fonctionnement en amont. Terminez-le complètement avant de passer au suivant.&lt;/li&gt;
&lt;li&gt;Une fois la cartographie faite, répartissez le travail (surtout des fichiers de code) entre des subagents, chacun focalisé sur une partie bien délimitée. Demandez-leur de chercher des anti-patterns connus dans les fonctions, des variables mal vérifiées et compagnie, et de consigner dans un fichier markdown tout ce qui leur paraît même vaguement bizarre ou dangereux, pour analyse ultérieure.&lt;/li&gt;
&lt;li&gt;Faites relire le travail des subagents par l&amp;rsquo;agent principal. Chaque constat part soit dans un dossier &amp;ldquo;non-security findings&amp;rdquo; (bugs trop faibles ou trop restreints pour être exploités : je m&amp;rsquo;en sers pour faire des PR d&amp;rsquo;amélioration en upstream), soit dans un dossier &amp;ldquo;security findings&amp;rdquo; pour contre-expertise.&lt;/li&gt;
&lt;li&gt;Une fois le scan initial terminé, demandez à l&amp;rsquo;agent principal une contre-expertise de tous les nouveaux constats sécurité validés.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="contre-expertise"&gt;Contre-expertise
&lt;/h2&gt;&lt;p&gt;C&amp;rsquo;est là que vient l&amp;rsquo;essentiel de la valeur de mes scans LLM. J&amp;rsquo;ai mis deux mois à affiner cette étape, et j&amp;rsquo;y travaille toujours.&lt;/p&gt;
&lt;p&gt;Ma checklist actuelle :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chercher sur GitHub/GitLab les issues, PR et documents d&amp;rsquo;amélioration éventuels. Soumettre un problème de sécurité déjà connu, c&amp;rsquo;est évidemment une mauvaise idée.&lt;/li&gt;
&lt;li&gt;Regarder aussi dans la doc officielle les limitations connues, les faiblesses &amp;amp; compromis documentés (c&amp;rsquo;est à dire &amp;ldquo;acceptés&amp;rdquo; par les mainteneurs, donc inéligibles), les bonnes pratiques de sécurité.&lt;/li&gt;
&lt;li&gt;Quand vous êtes sûr à 100% qu&amp;rsquo;il n&amp;rsquo;y a ni correctif public ni rapport antérieur, demandez au modèle de reproduire sur le vrai logiciel. Selon la cible, vous voudrez peut-être des runbooks pour différentes configurations sur différentes plateformes. Cette étape est particulièrement importante avec les modèles locaux, qui sortent des rapports de vulnérabilité absolument convaincants mais qui ne marchent jamais.&lt;/li&gt;
&lt;li&gt;Une fois reproduite, notez-la. La plupart des bug bounties demandent un score CVSS, mais il faut aller plus loin que ça.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Concrètement, un constat dans mon pipeline, ça ressemble à ça : un subagent signale un pattern suspect dans un fichier que personne ne lit -&amp;gt; l&amp;rsquo;orchestrateur le déduplique face aux issues publiques et aux flux de CVE -&amp;gt; si ça passe, reproduction sur un cluster &lt;a class="link" href="https://kind.sigs.k8s.io/" target="_blank" rel="noopener"
&gt;kind&lt;/a&gt; jetable ou une installation locale du vrai logiciel -&amp;gt; puis noté, rédigé, soumis&amp;hellip; et ensuite, vous attendez. Le triage prend en général quelques semaines/mois. Parfois quelques jours, et dans de rares cas plusieurs années (on y reviendra, c&amp;rsquo;est généralement le signe d&amp;rsquo;un programme surchargé ou mort).&lt;/p&gt;
&lt;h2 id="noter-à-la-juste-valeur"&gt;Noter à la juste valeur
&lt;/h2&gt;&lt;p&gt;Une fois que vous avez de vraies vulnérabilités, les noter avec un CVSS est une étape nécessaire. Mais le travail ne s&amp;rsquo;arrête pas là. Tout le monde qui a fait un peu de cybersécurité sait bien que le CVSS ne raconte pas toute l&amp;rsquo;histoire. Et les LLM auront tendance à surévaluer leurs propres constats.&lt;/p&gt;
&lt;p&gt;Faites poser ces questions à l&amp;rsquo;agent pendant la contre-expertise :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le constat est-il réaliste ?&lt;/li&gt;
&lt;li&gt;Les prérequis sont-ils réalistes ?&lt;/li&gt;
&lt;li&gt;Existeraient-ils / arriveraient-ils dans un déploiement réel, pas seulement en théorie ?&lt;/li&gt;
&lt;li&gt;La configuration est-elle saine (et non un piège où l&amp;rsquo;admin de notre scénario mériterait presque d&amp;rsquo;être compromis) ?&lt;/li&gt;
&lt;li&gt;Un attaquant chercherait-il vraiment à exploiter ça ?&lt;/li&gt;
&lt;li&gt;Le constat donne-t-il plus de droits que l&amp;rsquo;attaquant n&amp;rsquo;en a déjà ?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Toutes ces réponses (ou au moins la plupart) devraient être &amp;ldquo;oui&amp;rdquo;. Sinon, ce n&amp;rsquo;est probablement pas un problème de sécurité (ou en tout cas, c&amp;rsquo;est ce que les équipes sécurité de ces projets vous diront !), quoi qu&amp;rsquo;en dise le CVSS.&lt;/p&gt;
&lt;p&gt;Il y a évidemment des exceptions, mais pour rester simple restons dans le cas général.&lt;/p&gt;
&lt;h2 id="appropriez-vous-le-rapport"&gt;Appropriez-vous le rapport
&lt;/h2&gt;&lt;p&gt;Une fois tout ça fait, prenez le temps de le relire (vous, l&amp;rsquo;humain). Selon la qualité du modèle, vous trouverez peut être le rapport ridicule :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lisez le rapport du LLM attentivement, comprenez-le, appropriez-vous-en !&lt;/li&gt;
&lt;li&gt;Si quelque chose vous paraît bizarre, challengez le LLM&lt;/li&gt;
&lt;li&gt;Si une affirmation est exagérée, challengez le LLM&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;C&amp;rsquo;est là qu&amp;rsquo;un bagage en cybersécurité ou une connaissance fine de l&amp;rsquo;outil que vous auditez devient vraiment utile. Ça vous évitera de vous ridiculiser (l&amp;rsquo;humain, le LLM, lui, s&amp;rsquo;en fout).&lt;/p&gt;
&lt;h2 id="ne-faites-pas-partie-du-problème"&gt;Ne faites pas partie du problème
&lt;/h2&gt;&lt;p&gt;Prenons le taureau par les cornes : je viens de vous dire que les mainteneurs se noient sous les rapports générés par l&amp;rsquo;IA, et j&amp;rsquo;en ai envoyé plus de 30 moi-même. Oui, il y a un léger problème de cohérence. Voici ce que j&amp;rsquo;essaie de faire autrement :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rien n&amp;rsquo;est soumis sans avoir été reproduit sur le vrai logiciel et/ou un vrai cluster&lt;/li&gt;
&lt;li&gt;Chaque rapport est lu, compris et assumé par moi avant de partir. Si je ne peux pas l&amp;rsquo;expliquer aux mainteneurs sans le LLM, il ne part pas&lt;/li&gt;
&lt;li&gt;Les constats à faible sévérité ou limite ne passent pas par les canaux sécurité : ils finissent en issues publiques ou en PR en upstream&lt;/li&gt;
&lt;li&gt;Les notes sont contestées : pas de CVSS gonflé par le LLM&lt;/li&gt;
&lt;li&gt;Sur les petits projets, les rapports partent un par un, en attendant le triage avant d&amp;rsquo;en envoyer d&amp;rsquo;autres&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Les doublons arrivent quand même (9 pour l&amp;rsquo;instant), mais un doublon de vraie vulnérabilité reproduite coûte quelques minutes au triage sur des plateformes de bug bounty. Un rapport halluciné lui coûte potentiellement des heures, et beaucoup de la patience du maintainer.&lt;/p&gt;
&lt;h2 id="gardez-une-trace-de-tout"&gt;Gardez une trace de tout
&lt;/h2&gt;&lt;p&gt;Ça, je l&amp;rsquo;avais pas vu venir.&lt;/p&gt;
&lt;p&gt;Très très (très) vite, on est soi même ensevelli sous les reports. Après une trentaine de constats et une dizaine de rapports envoyés, je ne savais plus où j&amp;rsquo;en étais, honnêtement. Quel constat avait été reproduit ? Lequel avait déjà été soumis, et dans quel programme ? Quel rapport m&amp;rsquo;attendait, et lequel attendait les mainteneurs ? Un dossier de fichiers markdown ne passe pas à l&amp;rsquo;échelle, et les immenses tables markdown entretenues par le LLM sont vite devenues ingérables aussi.&lt;/p&gt;
&lt;p&gt;Du coup, j&amp;rsquo;ai fini par faire &amp;ldquo;Clauder&amp;rdquo; mon tableau de bord de suivi (oui, l&amp;rsquo;ironie : Claude code avec plaisir une UI pour chasser des failles, il veut juste pas faire la chasse lui-même). La source de vérité est désormais une base JSON, que le LLM met à jour via des scripts (jamais en éditant le fichier à la main). À chaque commit, un tableau kanban HTML statique est régénéré à partir de celle-ci, en suivant chaque constat tout au long de son cycle de vie.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/09/findings-kanban.avif"
loading="lazy"
alt="Tableau kanban des constats (mode démo anonymisé), avec des colonnes de “confirmée” à “fermée” et une carte par constat affichant son score composite, son CVSS et l’état de sa soumission"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Les titres ont été censurés pour des raisons évidentes)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Chaque constat est une carte qui progresse de gauche à droite :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Candidate&lt;/strong&gt; : signalée par un subagent, pas encore vérifiée&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Confirmée&lt;/strong&gt; : a survécu à la contre-expertise et à la reproduction&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rédaction&lt;/strong&gt; puis &lt;strong&gt;Prête&lt;/strong&gt; : rapport en cours de rédaction, puis prêt à envoyer&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Envoyé&lt;/strong&gt; et &lt;strong&gt;Triage&lt;/strong&gt; : soumis, en attente que le programme le regarde&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acceptée (embargo)&lt;/strong&gt; : acceptée par le programme, correctif ou divulgation en attente&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Corrigée&lt;/strong&gt; : correctif publié&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fermée&lt;/strong&gt; : rejetée comme doublon, wontfix ou informative&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Chaque carte porte un score composite (CVSS + risque de wontfix + risque de doublon, on y revient dans la section suivante), le CVSS, combien de fois elle a été soumise, et si elle a déjà été remontée en upstream. Trier par score composite me dit quoi écrire ensuite. Filtrer par programme me dit combien de places il me reste avant d&amp;rsquo;atteindre la limite de soumission.&lt;/p&gt;
&lt;p&gt;La vue stats, c&amp;rsquo;est aussi un bon retour à la réalité :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/09/findings-stats.avif"
loading="lazy"
alt="Vue stats du tableau de bord : 163 constats sur 5 programmes, 31 soumis, 10 en attente, 2 acceptés, 9 doublons, 1 wontfix, et la répartition des sévérités CVSS"
&gt;&lt;/p&gt;
&lt;p&gt;163 constats (après en avoir écarté 215 non-sécurité), sur 26 projets, et seulement 31 soumis.&lt;/p&gt;
&lt;p&gt;La seule colonne &amp;ldquo;Prête&amp;rdquo; contient déjà 118 constats. En trouver, c&amp;rsquo;est trivial. Ce qui me limite, ce n&amp;rsquo;est plus le LLM : c&amp;rsquo;est mon temps à moi pour reproduire, rédiger et assumer chaque rapport (l&amp;rsquo;humain dans la boucle &lt;strong&gt;est&lt;/strong&gt; le goulot d&amp;rsquo;étranglement), puis les plafonds de soumission des programmes. Et même dans ces conditions, être le premier et survivre au triage reste du ressort de la chance.&lt;/p&gt;
&lt;p&gt;Quel que soit l&amp;rsquo;outil que vous utilisez (un tableur fait l&amp;rsquo;affaire aussi, voire JIRA lol), mettez ça en place &lt;strong&gt;avant&lt;/strong&gt; de commencer à soumettre. Le rajouter après 10 rapports envoyés, en remuant les mails et les boîtes de réception des plateformes, c&amp;rsquo;est un exercice douloureux.&lt;/p&gt;
&lt;h2 id="vous-nêtes-pas-seul"&gt;Vous n&amp;rsquo;êtes pas seul
&lt;/h2&gt;&lt;p&gt;Même quand le programme ne verse pas de bounty, attendez-vous à de la concurrence : via les plateformes de bug bounty ou des rapports GHSA (GitHub Security Advisory). Vous pouvez partir du principe que chaque problème &amp;ldquo;facile à repérer&amp;rdquo; a été trouvé il y a des mois, plusieurs fois. Sur les projets dont l&amp;rsquo;équipe sécurité est à bout, comptez plutôt &lt;em&gt;des années&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Je ne peux pas encore donner de détails, mais je suis tombé sur une vulnérabilité qui avait été remontée il y a des années, avec un CVE réservé l&amp;rsquo;année d&amp;rsquo;avant, toujours ni corrigée ni publique.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Voilà l&amp;rsquo;état du triage de sécurité de l&amp;rsquo;open source aujourd&amp;rsquo;hui&lt;/strong&gt; : la file d&amp;rsquo;attente est plus longue que ce qu&amp;rsquo;on arrive à traiter, et ça ne s&amp;rsquo;améliore pas.&lt;/p&gt;
&lt;p&gt;Alors si vous visez à être le premier (pour le bounty, pour la gloire), il faut être plus stratégique que la moyenne :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Évitez les bugs qui se repèrent en lisant un seul fichier, ou qu&amp;rsquo;un outil SAST/DAST signalerait. Les LLM sont relativement doués pour ça, et vous pouvez être sûr que quelqu&amp;rsquo;un l&amp;rsquo;a trouvé avant vous. Malheureusement, c&amp;rsquo;est peut-être le seul type de constat que vous obtiendrez avec des modèles locaux/petits (ou il vous faut un harness très spécifique).&lt;/li&gt;
&lt;li&gt;Ciblez en priorité du code qui n&amp;rsquo;est pas le plus audité. Ne visez &lt;strong&gt;pas&lt;/strong&gt; une RCE pré-auth si vous ne savez pas ce que vous faites. Ce code a été audité par des gens bien meilleurs que vous. Visez plutôt du code récent en beta/GA, ou à l&amp;rsquo;inverse du vieux legacy qui paraît inoffensif.&lt;/li&gt;
&lt;li&gt;Visez des problèmes qui supposent de savoir comment l&amp;rsquo;outil fonctionne, et ce qui ne devrait &lt;strong&gt;pas&lt;/strong&gt; fonctionner. Les LLM sont mauvais là-dessus : si vous avez cette connaissance, vous avez un avantage.&lt;/li&gt;
&lt;li&gt;Si vous ne payez pas au token, n&amp;rsquo;hésitez pas à donner le fichier entier au subagent. J&amp;rsquo;ai découvert par hasard qu&amp;rsquo;un agent qu&amp;rsquo;on restreint aux &amp;ldquo;fonctions sensibles&amp;rdquo; en rate ÉNORMÉMENT. C&amp;rsquo;est peut-être moins vrai pour les modèles frontier, mais c&amp;rsquo;est une vérité absolue pour les modèles moins bons.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;De là, j&amp;rsquo;ai mis au point un score qui évalue mes vulnérabilités non seulement sur leur CVSS, mais aussi sur le risque de &amp;ldquo;wontfix&amp;rdquo; de la part des mainteneurs &lt;strong&gt;et&lt;/strong&gt; le risque de &amp;ldquo;doublon&amp;rdquo; parce qu&amp;rsquo;elles étaient trop faciles à trouver.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Est-ce que ça marche ? Oui, absolument. J&amp;rsquo;ai trouvé des dizaines de vulnérabilités réelles, non corrigées, dans de l&amp;rsquo;open source en production, allant de sévérité moyenne à critique.&lt;/p&gt;
&lt;p&gt;La vérité qui pique : j&amp;rsquo;ai envoyé plus de 30 rapports jusqu&amp;rsquo;ici. Sur les verdicts revenus, la plupart étaient des doublons - quelqu&amp;rsquo;un était arrivé avant moi (mon erreur de débutant : je pensais que les constats faciles passeraient, alors que &amp;ldquo;facile&amp;rdquo; signifie simplement que quelqu&amp;rsquo;un les a déjà trouvés). L&amp;rsquo;un m&amp;rsquo;a valu un CVE avec co-crédit, &lt;a class="link" href="https://github.com/kedacore/keda/security/advisories/GHSA-637c-6jxx-4rwm" target="_blank" rel="noopener"
&gt;CVE-2026-77524&lt;/a&gt;, qui vient de sortir en public : une élévation critique namespace-admin vers cluster-admin dans KEDA ; un autre advisory a été accepté mais n&amp;rsquo;est pas encore public ; et un correctif a été mergé via une issue publique. Le reste est soit encore en triage, soit bloqué derrière des limites de débit. Certaines plateformes plafonnent les soumissions, par exemple 4 rapports par programme sur une fenêtre glissante de 30 jours, un peu plus si vous chassez sur plusieurs programmes, avec en plus un plafond global sur toute la plateforme.&lt;/p&gt;
&lt;p&gt;Et quand un projet ne répond simplement pas ? Je n&amp;rsquo;ai pas encore de règle parfaite : je relance une fois après quelques semaines. La convention courante, c&amp;rsquo;est une publication publique après un embargo raisonnable (90 jours), mais je n&amp;rsquo;ai pas encore décidé si je l&amp;rsquo;appliquerai. Il y a aussi des paliers intermédiaires, comme escalader auprès d&amp;rsquo;une CNA, ou de GitHub Security Lab pour les projets hébergés sur GitHub. Un rapport qui pourrit dans une file privée n&amp;rsquo;aide personne, mais laisser une vulnérabilité non corrigée entre les mains des utilisateurs non plus.&lt;/p&gt;
&lt;p&gt;Alors : &lt;strong&gt;exploitez cette contrainte&lt;/strong&gt;. Transformez la faiblesse en atout. Tout le monde se concentre sur les mêmes cibles médiatiques (qui ne veut pas d&amp;rsquo;une RCE pré-auth ?) ou sur les failles évidentes et faciles. Si vous voulez des résultats (être le premier), laissez tomber les deux. Concentrez-vous sur les cas limites obscurs qui se retrouvent éparpillés sur 3 composants. Oui, ça demande plus de travail, de meilleurs LLM, et un peu de chance.&lt;/p&gt;
&lt;p&gt;Si vous commencez maintenant, les victoires faciles sont déjà prises. Mais c&amp;rsquo;est précisément là que se trouve votre atout : savoir comment devraient se comporter les outils que vous utilisez tous les jours, c&amp;rsquo;est quelque chose que personne ne peut louer &amp;ldquo;au token&amp;rdquo;.&lt;/p&gt;</description></item><item><title>Refonte de l'UI de GroROTI</title><link>https://blog.zwindler.fr/2026/05/22/refonte-ui-groroti/</link><pubDate>Fri, 22 May 2026 12:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2026/05/22/refonte-ui-groroti/</guid><description>&lt;img src="https://blog.zwindler.fr/2026/05/roti-avant-apr%C3%A8s.webp" alt="Featured image of post Refonte de l'UI de GroROTI" /&gt;&lt;p&gt;Si vous lisez régulièrement ce blog et mes aventures sur les réseaux sociaux, vous savez que j&amp;rsquo;aime énormément l&amp;rsquo;infrastructure, un peu le code backend (surtout en Golang), mais que dès qu&amp;rsquo;il s&amp;rsquo;agit de concevoir une interface graphique moderne et agréable, il n&amp;rsquo;y a plus personne.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est un fait établi, je n&amp;rsquo;ai aucune compétence en développement front. Dommage pour les offres FullSteak (jeu de mot pourri, mais plutôt approprié ici).&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est exactement ce qui pénalisait GroROTI, un petit outil web open source en Go que j&amp;rsquo;avais développé en 2024 (en partie sur mon temps libre, en partie lorsque j&amp;rsquo;étais chez mon ancien employeur, ce qui explique pourquoi le dépôt soit hébergé sur leur GitHub).&lt;/p&gt;
&lt;p&gt;Pour rappel, l&amp;rsquo;application permet d&amp;rsquo;évaluer rapidement et anonymement la qualité des réunions ou des ateliers via le format ROTI (Return On Time Invested).&lt;/p&gt;
&lt;p&gt;Le problème, c&amp;rsquo;est que l&amp;rsquo;outil était fonctionnel, &lt;strong&gt;mais franchement moche&lt;/strong&gt;. Un petit look Web 1.0, voire soviétique, qui était franchement assumé dans un premier temps, mais dont on se lasse assez vite.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/05/vote-avant.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Qu&amp;rsquo;à cela ne tienne. Fort de mes expériences plutôt concluantes avec la refonte de ma page &lt;a class="link" href="https://blog.zwindler.fr/conf%C3%A9rences/" target="_blank" rel="noopener"
&gt;Conférence&lt;/a&gt; (cf &amp;ldquo;&lt;a class="link" href="https://blog.zwindler.fr/2026/03/13/refonte-page-conferences-hugo/" &gt;Refonte de la page Conférences : data-driven avec Hugo&lt;/a&gt;&amp;rdquo;) et la v3 de &lt;a class="link" href="https://zwindler.github.io/101-ways-to-deploy-kubernetes/" target="_blank" rel="noopener"
&gt;mon projet pour cataloguer toutes les manières de déployer Kubernetes&lt;/a&gt; (cf &amp;ldquo;&lt;a class="link" href="https://blog.zwindler.fr/2026/03/29/101-facons-de-deployer-kubernetes-v3/" target="_blank" rel="noopener"
&gt;101 façons de déployer Kubernetes : 125 solutions, des PRs communautaires et une UI qui s&amp;rsquo;améliore&lt;/a&gt;&amp;rdquo;), j&amp;rsquo;ai fait chauffer un LLM perso pour lui demander de m&amp;rsquo;aider à rendre ça un peu plus agréable à l&amp;rsquo;oeil.&lt;/p&gt;
&lt;p&gt;Le résultat va bien au-delà de mes compétences (&amp;ldquo;la barre est au sol&amp;rdquo; comme on dit). Si on compare les captures d&amp;rsquo;écran avant (à gauche) et après (à droite), le changement est flagrant :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Une page d&amp;rsquo;accueil transformée : Fini l&amp;rsquo;alignement de texte un peu triste. On passe sur une interface épurée, une colorimétrie violette moderne (petit clin d&amp;rsquo;oeil), un bloc de création &amp;ldquo;New ROTI&amp;rdquo; bien délimité et une barre latérale pour afficher les derniers examens créés.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/05/home-avantapr%c3%a8s.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Des résultats clairs : La page de restitution des votes affiche désormais la moyenne globale en grand, ainsi que le nombre de participants et les valeurs minimales et maximales sous forme de &amp;ldquo;cartes&amp;rdquo;. Le QR code de partage est lui aussi bien mieux intégré visuellement.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/05/roti-avant-apr%c3%a8s.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Un système de notation plus intuitif : Le vieux curseur glissant a été remplacé par un système de notation à 5 étoiles (avec support des demi notes) bien plus classique et parlant pour les utilisateurs. Le tout reste accompagné d&amp;rsquo;une zone de texte (redesignée) pour les retours optionnels, quand ils sont activés.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/05/vote-avant-apr%c3%a8s.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="juste-un-lifting"&gt;Juste un lifting
&lt;/h2&gt;&lt;p&gt;Sous le capot, l&amp;rsquo;application reste la même, je n&amp;rsquo;ai pas touché au code backend (*), juste la partie templates HTML (gotpl) et CSS.&lt;/p&gt;
&lt;p&gt;(*) &lt;em&gt;c&amp;rsquo;est pas 100% vrai, j&amp;rsquo;ai fait quelques modifs en 2025, notamment pour ajouter du tracing otel, support de la CR ServiceMonitor, amélioration du build multi arch et quelques bugfixes&amp;hellip; dont je ne vous avais pas parlé.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Au final, ce petit truc en plus fait la diff entre un tool interne que je n&amp;rsquo;avais pas trop envie de mettre en avant, et un outil qui me parait utilisable en dehors de mon contexte pro :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/deezer/GroROTI" target="_blank" rel="noopener"
&gt;https://github.com/deezer/GroROTI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>GenAI et développement logiciel, épisode 2 : kubectl-debug-pvc, de l'idée à krew en 2x30 minutes</title><link>https://blog.zwindler.fr/2026/03/16/genai-llm-dev-kubectl-debug-pvc/</link><pubDate>Tue, 17 Mar 2026 18:00:00 +0100</pubDate><guid>https://blog.zwindler.fr/2026/03/16/genai-llm-dev-kubectl-debug-pvc/</guid><description>&lt;img src="https://blog.zwindler.fr/2026/03/kubectl-debug-pvc.webp" alt="Featured image of post GenAI et développement logiciel, épisode 2 : kubectl-debug-pvc, de l'idée à krew en 2x30 minutes" /&gt;&lt;h2 id="précédemment-dans-genai-et-dev"&gt;Précédemment, dans &amp;ldquo;GenAI et dev&amp;rdquo;
&lt;/h2&gt;&lt;p&gt;Dans &lt;a class="link" href="https://blog.zwindler.fr/2026/03/08/genai-llm-dev-podsweeper/" &gt;mon article précédent&lt;/a&gt;, je vous parlais de mon retour d&amp;rsquo;expérience avec PodSweeper, un projet développé avec OpenCode et Claude Opus. Le bilan était nuancé : vitesse brute impressionnante, mais race conditions, gestion d&amp;rsquo;erreur laxiste, et nécessité constante de supervision humaine (entre autres déconvenues).&lt;/p&gt;
&lt;p&gt;Aujourd&amp;rsquo;hui, je vous parle d&amp;rsquo;un deuxième projet, bien plus simple, né d&amp;rsquo;un vrai besoin en production. Et le constat est assez différent.&lt;/p&gt;
&lt;h2 id="lincident-qui-a-tout-déclenché"&gt;L&amp;rsquo;incident qui a tout déclenché
&lt;/h2&gt;&lt;p&gt;Vous connaissez peut-être cette situation : un pod en production, en état de fonctionnement, qui utilise un PVC en &lt;code&gt;ReadWriteOnce&lt;/code&gt;. Vous avez besoin d&amp;rsquo;aller regarder le contenu de ce volume. Bonne pratique de production : le pod en question ne dispose pas de shell (on réduit la surface d&amp;rsquo;attaque). Pas de &lt;code&gt;/bin/sh&lt;/code&gt;, pas de &lt;code&gt;/bin/bash&lt;/code&gt;, rien.&lt;/p&gt;
&lt;p&gt;Pas grave, on a &lt;code&gt;kubectl debug&lt;/code&gt; pour ça, me direz-vous !&lt;/p&gt;
&lt;p&gt;Ok, créons un conteneur éphémère dans le pod et&amp;hellip; ah non. &lt;code&gt;kubectl debug&lt;/code&gt; ne permet pas de monter les volumes du pod dans le conteneur éphémère. Il n&amp;rsquo;expose tout simplement pas l&amp;rsquo;option &lt;code&gt;volumeMounts&lt;/code&gt; pour les conteneurs éphémères.&lt;/p&gt;
&lt;p&gt;On pourrait couper le pod, ce qui permet de monter le PVC RWO dans un autre pod avec un shell, mais on n&amp;rsquo;a pas envie, c&amp;rsquo;est de la prod.&lt;/p&gt;
&lt;p&gt;Mon collègue Maxime (encore lui !) me propose une méthode de contournement. La procédure manuelle, c&amp;rsquo;est :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Créer un conteneur éphémère sur le pod avec &lt;code&gt;kubectl debug&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Construire à la main un patch JSON pour ajouter des &lt;code&gt;volumeMounts&lt;/code&gt; au conteneur éphémère qu&amp;rsquo;on vient de créer&lt;/li&gt;
&lt;li&gt;Dans un autre terminal, se brancher &lt;del&gt;au cul du camion&lt;/del&gt; sur l&amp;rsquo;API de kube en direct avec &lt;code&gt;kubectl proxy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Appliquer le patch via un curl sur l&amp;rsquo;API Kubernetes&lt;/li&gt;
&lt;li&gt;Attendre que le conteneur soit prêt, s&amp;rsquo;attacher au conteneur&lt;/li&gt;
&lt;li&gt;Se dire qu&amp;rsquo;il y avait quand même plus simple comme métier que patcheur de container à coup de curl.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Pour ceux qui pensent que c&amp;rsquo;est jouable, &amp;ldquo;téma la gueule du patch&amp;rdquo; comme disent (disaient ?) les jeunes :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;curl&lt;/span&gt; &lt;span class="err"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8001/api/v1/namespaces/&amp;lt;namespace&amp;gt;/pods/&amp;lt;pod&amp;gt;/ephemeralcontainers \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;-X&lt;/span&gt; &lt;span class="err"&gt;PATCH&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;-H&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;Content-Type:&lt;/span&gt; &lt;span class="err"&gt;application/strategic-merge-patch+json&amp;#39;&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;-d&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;spec&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;ephemeralContainers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;debugger&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;image&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ubuntu&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/bin/sh&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;targetContainerName&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;target-container&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;stdin&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;tty&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;volumeMounts&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;volume-name&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;mountPath&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/debug/&amp;lt;volume-name&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Si vous pensez que c&amp;rsquo;est error prone, vous avez raison. Et si vous pensez que c&amp;rsquo;est pénible à faire sous pression pendant un incident de prod, vous avez encore plus raison.&lt;/p&gt;
&lt;h2 id="side-note"&gt;Side note
&lt;/h2&gt;&lt;p&gt;Les plus aguerri·es d&amp;rsquo;entre vous dans les versions récentes de Kubernetes ont peut être entendu parler du &lt;a class="link" href="https://kep.k8s.io/2590" target="_blank" rel="noopener"
&gt;KEP-2590&lt;/a&gt;, qui introduit un (relativement) nouveau flag &lt;code&gt;--subresource&lt;/code&gt; de &lt;code&gt;kubectl&lt;/code&gt;. En effet, les containers éphémères créés par la commande &lt;code&gt;kubectl debug&lt;/code&gt; ne sont pas des &lt;em&gt;resources&lt;/em&gt; (un pod, un deployment, &amp;hellip;) mais des &lt;em&gt;subresources&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Jusqu&amp;rsquo;à cette version 1.33, il était littéralement impossible de réaliser des opérations sur les subresources avec &lt;code&gt;kubectl&lt;/code&gt;, seulement les resources.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kubernetes v1.33: Octarine&lt;/strong&gt; apporte le support du flag &amp;ndash;subresource, &lt;strong&gt;mais seulement&lt;/strong&gt; pour 3 subresources pour l&amp;rsquo;instant &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;scale&lt;/code&gt; and &lt;code&gt;resize&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://kubernetes.io/blog/2025/04/23/kubernetes-v1-33-release/#subresource-support-in-kubectl" target="_blank" rel="noopener"
&gt;https://kubernetes.io/blog/2025/04/23/kubernetes-v1-33-release/#subresource-support-in-kubectl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://kubernetes.io/docs/reference/kubectl/conventions/#subresources" target="_blank" rel="noopener"
&gt;https://kubernetes.io/docs/reference/kubectl/conventions/#subresources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pas de solution de ce côté-là non plus&amp;hellip;&lt;/p&gt;
&lt;h1 id="le-prompt-de-réunion"&gt;Le prompt de réunion
&lt;/h1&gt;&lt;p&gt;J&amp;rsquo;avais cette idée en tête depuis l&amp;rsquo;incident. Lundi matin, au début d&amp;rsquo;une réunion (pendant que les gens faisaient encore des blagues), j&amp;rsquo;ai lancé OpenCode avec Claude Opus et j&amp;rsquo;ai tapé un prompt qui décrivait :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le problème : &lt;code&gt;kubectl debug&lt;/code&gt; ne monte pas les volumes PVC s&amp;rsquo;ils sont en RWO&lt;/li&gt;
&lt;li&gt;La procédure manuelle que je faisais à la main (les étapes douloureuses décrites un peu plus haut)&lt;/li&gt;
&lt;li&gt;Ce que je voulais : un outil qui automatise tout ça&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;OpenCode + Opus m&amp;rsquo;ont posé 2 questions (et j&amp;rsquo;ai ajouté une consigne) :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;Quel langage ?&amp;rdquo;&lt;/em&gt; → &lt;strong&gt;Go&lt;/strong&gt; (je persiste)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&amp;ldquo;CLI seule ou TUI ?&amp;rdquo;&lt;/em&gt; → &lt;strong&gt;Les deux&lt;/strong&gt; (mode non-interactif pour le scripting, TUI pour l&amp;rsquo;usage quotidien)&lt;/li&gt;
&lt;li&gt;Et je lui ai demandé de toujours vérifier à chaque fois qu&amp;rsquo;il estime avoir fini de lancer le linter &lt;code&gt;golangci-lint&lt;/code&gt; (trauma de mon précédent test avec opencode)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il est parti de lui-même sur l&amp;rsquo;idée d&amp;rsquo;une TUI avec &lt;a class="link" href="https://github.com/charmbracelet/bubbletea" target="_blank" rel="noopener"
&gt;Bubble Tea&lt;/a&gt;. Puis j&amp;rsquo;ai arrêté de regarder &amp;amp; j&amp;rsquo;ai suivi ma réunion.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;~30 minutes plus tard, fin de la réunion&lt;/strong&gt;, j&amp;rsquo;ai regardé le résultat. Le POC était fonctionnel.&lt;/p&gt;
&lt;h2 id="ce-quopus-a-produit-en-30-minutes"&gt;Ce qu&amp;rsquo;Opus a produit en 30 minutes
&lt;/h2&gt;&lt;p&gt;Sans aucune intervention de ma part, le LLM a scaffoldé un projet Go complet :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Structure propre&lt;/strong&gt; : &lt;code&gt;cmd/&lt;/code&gt; pour le CLI Cobra, &lt;code&gt;pkg/k8s/&lt;/code&gt; pour toute l&amp;rsquo;interaction Kubernetes, &lt;code&gt;pkg/tui/&lt;/code&gt; pour la TUI Bubble Tea&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Le coeur du sujet&lt;/strong&gt; : un appel direct à l&amp;rsquo;API Kubernetes pour patcher le subresource &lt;code&gt;ephemeralcontainers&lt;/code&gt; du pod avec un strategic merge patch incluant les &lt;code&gt;volumeMounts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mode non-interactif&lt;/strong&gt; : &lt;code&gt;-n namespace -p pod -v volume:/mount/path&lt;/code&gt;, prêt pour le scripting&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TUI complète&lt;/strong&gt; : navigation vim-style (&lt;code&gt;j&lt;/code&gt;/&lt;code&gt;k&lt;/code&gt;), filtrage fuzzy (&lt;code&gt;/&lt;/code&gt;), multi-sélection de volumes, spinner de chargement&amp;hellip;&lt;/li&gt;
&lt;li&gt;Makefile avec tout un tas de targets (vet, lint, test, build, install)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ce que je lui ai demandé d&amp;rsquo;ajouter :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Discovery intelligente&lt;/strong&gt; : au lieu de scanner tous les pods de tous les namespaces (lent sur un de mes gros cluster), l&amp;rsquo;outil liste d&amp;rsquo;abord les PVCs cluster-wide (un seul appel API) pour identifier les namespaces pertinents, PUIS les pods dans le namespace sélectionné. On réduit drastiquement le nombre d&amp;rsquo;appels à l&amp;rsquo;API server de kube et la TUI ne montre que les namespaces et pods qui ont des volumes PVC&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Héritage du &lt;code&gt;SecurityContext&lt;/code&gt;&lt;/strong&gt; : le conteneur éphémère copie le &lt;code&gt;securityContext&lt;/code&gt; du conteneur cible, ce qui lui permet de passer les PodSecurity policies (&lt;code&gt;restricted&lt;/code&gt;, &lt;code&gt;baseline&lt;/code&gt;&amp;hellip;). C&amp;rsquo;est un cas que je n&amp;rsquo;avais pas envisagé dans mon prompt initial et qui a planté immédiatement sur un cluster bien configuré.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sans ces petites améliorations le tool était déjà utilisable (sauf pour le cas où vous avez configuré des SecurityContext), mais c&amp;rsquo;est nettement plus confortable à l&amp;rsquo;usage (parce que oui, je l&amp;rsquo;utilise).&lt;/p&gt;
&lt;p&gt;Le code de la mécanique centrale (le patch de l&amp;rsquo;API) fait quelques centaines de lignes de Go propre. Il récupère le pod, construit le patch JSON avec le conteneur éphémère et ses &lt;code&gt;volumeMounts&lt;/code&gt;, l&amp;rsquo;applique via &lt;code&gt;Patch()&lt;/code&gt; sur le subresource, attend que le conteneur soit Running, puis lance &lt;code&gt;kubectl attach&lt;/code&gt;. Rien de sorcier, c&amp;rsquo;est juste ce qu&amp;rsquo;il faut, bien fait du premier coup.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-golang" data-lang="golang"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ephemeralContainer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;corev1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EphemeralContainer&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;EphemeralContainerCommon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;corev1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EphemeralContainerCommon&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;containerName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;/bin/sh&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Stdin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TTY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;VolumeMounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mounts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SecurityContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;targetSecurityContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TargetContainerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;targetContainer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Clientset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CoreV1&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Pods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Namespace&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Patch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PodName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StrategicMergePatchType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;patchBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;metav1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PatchOptions&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;ephemeralcontainers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="les-itérations-suivantes-30-minutes-ish"&gt;Les itérations suivantes (30 minutes-ish)
&lt;/h2&gt;&lt;p&gt;Une fois le POC validé, j&amp;rsquo;ai enchaîné quelques prompts ciblés. Je lui ai demandé ce qu&amp;rsquo;on pouvait améliorer. Il a proposé (et implémenté) :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;quelques corrections mineures de code qu&amp;rsquo;il avait mal codé (mais non bloquant)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Warnings&lt;/strong&gt; : si le SecurityContext hérité a &lt;code&gt;readOnlyRootFilesystem&lt;/code&gt;, &lt;code&gt;runAsNonRoot&lt;/code&gt;, ou autre mesure de sécurité, l&amp;rsquo;outil prévient l&amp;rsquo;utilisateur avant l&amp;rsquo;attach&lt;/li&gt;
&lt;li&gt;Ajouté une CI complète à base de &lt;code&gt;goreleaser&lt;/code&gt; et de github actions&lt;/li&gt;
&lt;li&gt;Ajouté de la documentation&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="la-cerise-sur-le-macdo--publication-sur-krew"&gt;La cerise sur le Macdo : publication sur Krew
&lt;/h2&gt;&lt;p&gt;Une fois que j&amp;rsquo;avais une version propre, j&amp;rsquo;ai demandé à Opus comment faciliter l&amp;rsquo;installation du plugin. Il m&amp;rsquo;a proposé &lt;code&gt;brew&lt;/code&gt;, ou alors &lt;a class="link" href="https://krew.sigs.k8s.io/" target="_blank" rel="noopener"
&gt;Krew&lt;/a&gt;, le gestionnaire de plugins kubectl.&lt;/p&gt;
&lt;p&gt;Je lui ai demandé si le processus d&amp;rsquo;acceptation du plugin était complexe. Il a dit que non, je lui ai dit &amp;ldquo;chiche !&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Il a &lt;strong&gt;réalisé l&amp;rsquo;intégralité du processus&lt;/strong&gt; :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Création d&amp;rsquo;un fork de &lt;a class="link" href="https://github.com/kubernetes-sigs/krew-index" target="_blank" rel="noopener"
&gt;krew-index&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Rédaction du manifeste Krew (le fichier &lt;code&gt;.yaml&lt;/code&gt; qui décrit le plugin)&lt;/li&gt;
&lt;li&gt;Prise en compte de toutes les bonnes pratiques demandées par les maintainers de krew-index (format des URLs de téléchargement, descriptions courtes, checksums SHA256, etc.)&lt;/li&gt;
&lt;li&gt;Préparation de la PR, directement sur krew-index&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;J&amp;rsquo;ai juste regardé. La PR a été mergée 12 heures plus tard par les mainteneurs.&lt;/p&gt;
&lt;p&gt;Résultat : &lt;code&gt;kubectl krew install debug-pvc&lt;/code&gt; fonctionne.&lt;/p&gt;
&lt;h2 id="mini-échec---déléguer-aussi-la-démo"&gt;Mini échec - déléguer aussi la démo
&lt;/h2&gt;&lt;p&gt;Fort de ce succès avec la PR pour krew-index, je me suis demandé si on ne pourrait pas faire une démo visuelle (un GIF à ajouter dans le README.md du projet qui montre comment ça fonctionne) avec le LLM.&lt;/p&gt;
&lt;p&gt;Je lui ai demandé s&amp;rsquo;il pouvait le faire avec &lt;code&gt;asciinema&lt;/code&gt; et le LLM m&amp;rsquo;a répondu que &amp;ldquo;oui&amp;rdquo; (oui, je discute avec le LLM comme avec mes collègues). Banco, on a essayé.&lt;/p&gt;
&lt;p&gt;Le résultat était &lt;em&gt;presque&lt;/em&gt; bon, j&amp;rsquo;aurais pu m&amp;rsquo;en contenter si j&amp;rsquo;étais pas quelqu&amp;rsquo;un de pénible : c&amp;rsquo;était un poil lent. J&amp;rsquo;ai l&amp;rsquo;impression la réactivité du LLM dans ses actions était inégale, ce qui rendait le rendu un peu désagréable au visionnage. J&amp;rsquo;aurais pu insister jusqu&amp;rsquo;à avoir quelque chose de correct, mais j&amp;rsquo;ai finalement enregistré moi-même une vidéo, convertie en GIF avec &lt;code&gt;ffmpeg&lt;/code&gt;. C&amp;rsquo;était plus fluide et plus rapide que d&amp;rsquo;itérer.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/03/kubectl-debug-pvc-demo.gif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="le-diff-avec-podsweeper"&gt;Le diff avec PodSweeper
&lt;/h2&gt;&lt;p&gt;La différence de ressenti entre ce projet et PodSweeper est frappante. Là où PodSweeper était un combat constant (race conditions, amnésie du LLM, fonctionnalités hors-spécifications), &lt;code&gt;kubectl-debug-pvc&lt;/code&gt; s&amp;rsquo;est déroulé sans accroc notable.&lt;/p&gt;
&lt;p&gt;Pourquoi ? Je pense que ça tient à la nature du projet :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Une seule chose à faire&lt;/strong&gt;, clairement définie : patcher un subresource Kubernetes avec des volumeMounts&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pas de logique concurrente&lt;/strong&gt; : on fait une requête API, on attend, on s&amp;rsquo;attache&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Un domaine bien documenté&lt;/strong&gt; : l&amp;rsquo;API Kubernetes, Cobra, Bubble Tea. Le LLM connaît tout ça par coeur&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pas d&amp;rsquo;état partagé complexe&lt;/strong&gt; : pas de goroutines qui se marchent dessus, pas de graceful shutdown à gérer, de microservices multiples&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scope limité&lt;/strong&gt; : le projet entier tient dans une quinzaine de fichiers, CI et documentation incluses&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;C&amp;rsquo;est probablement le terrain de jeu idéal pour un LLM. Un problème bien cadré, un domaine technique bien balisé, une solution linéaire.&lt;/p&gt;
&lt;h2 id="quest-ce-que-jen-pense-"&gt;Qu&amp;rsquo;est-ce que j&amp;rsquo;en pense ?
&lt;/h2&gt;&lt;p&gt;Objectivement, ce genre de projet &amp;ldquo;simple&amp;rdquo; (une chose à faire, simple à comprendre) marche &lt;strong&gt;vraiment super bien&lt;/strong&gt; avec OpenCode + Opus. Je pense que c&amp;rsquo;est ce genre à cause (grâce) de ce genre de petits projets que la hype est tellement forte autour du développement agentique. On a une idée en tête qu&amp;rsquo;on avait la flemme de dev, on teste, ça marche. &amp;ldquo;WOW&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Mais je ne veux pas non plus minimiser le travail réalisé. Le fait qu&amp;rsquo;un outil fonctionnel, propre, publié sur Krew et utilisable par n&amp;rsquo;importe qui ait pu émerger d&amp;rsquo;un prompt lancé en début de réunion, c&amp;rsquo;est quand même assez dingue.&lt;/p&gt;
&lt;p&gt;Un peu flippant aussi, de se dire qu&amp;rsquo;un nombre hallucinant de micro tools vont apparaître dans les prochains mois, avec un niveau de qualité probablement inégal.&lt;/p&gt;
&lt;h2 id="le-projet"&gt;Le projet
&lt;/h2&gt;&lt;p&gt;Le code est disponible ici :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/zwindler/kubectl-debug-pvc" target="_blank" rel="noopener"
&gt;https://github.com/zwindler/kubectl-debug-pvc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Installation :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Via Krew (recommandé)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl krew install debug-pvc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Utilisation interactive (TUI)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl debug-pvc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Utilisation non-interactive&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kubectl debug-pvc -n my-namespace -p my-pod-0 -v data:/debug/data
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Si vous aussi vous avez déjà galéré à inspecter un PVC sur un pod sans shell, essayez. Et si vous trouvez des bugs, vous pourrez blâmer le LLM 😄.&lt;/p&gt;</description></item><item><title>GenAI et développement logiciel : retour d'expérience avec PodSweeper</title><link>https://blog.zwindler.fr/2026/03/08/genai-llm-dev-podsweeper/</link><pubDate>Sun, 08 Mar 2026 18:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2026/03/08/genai-llm-dev-podsweeper/</guid><description>&lt;img src="https://blog.zwindler.fr/2026/02/opencode.webp" alt="Featured image of post GenAI et développement logiciel : retour d'expérience avec PodSweeper" /&gt;&lt;h2 id="la-genai-cest-fantastique-"&gt;La GenAI, c&amp;rsquo;est fantastique ?
&lt;/h2&gt;&lt;p&gt;Pas mal de gens ont sorti leur avis sur la Gen AI pour dev en très peu de temps, alors je me rends compte qu&amp;rsquo;il est plus que temps que je poste ce brouillon commencé il y a plus de deux semaines 🙃.&lt;/p&gt;
&lt;p&gt;Pour le travail, j&amp;rsquo;utilise de plus en plus d&amp;rsquo;assistants IA pour m&amp;rsquo;épauler dans mes tâches du quotidien. En 2024, c&amp;rsquo;était surtout pour automatiser des tâches pénibles (scripter des trucs, faire une liste pénible de tâches répétitives sans coder ça proprement). Courant 2025, j&amp;rsquo;ai testé plusieurs fois de lui faire faire de l&amp;rsquo;Ops et, à chaque fois, les résultats étaient moyens, tant pour concevoir une infra cohérente, fiable et efficiente que pour de l&amp;rsquo;assistance à la résolution d&amp;rsquo;incident (cf. &lt;a class="link" href="https://blog.zwindler.fr/2025/08/15/ops-disparition-suite/#et-dans-linfra-" &gt;mon article sur le sujet&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;En 2026, sur ce dernier point, je trouve qu&amp;rsquo;on n&amp;rsquo;a toujours pas avancé, même si je reconnais qu&amp;rsquo;il existe des outils spécialisés que je n&amp;rsquo;ai pas encore suffisamment testés, open source ou non. Je peux citer &lt;a class="link" href="https://k8sgpt.ai/" target="_blank" rel="noopener"
&gt;k8sgpt&lt;/a&gt; et &lt;a class="link" href="https://github.com/HolmesGPT/holmesgpt" target="_blank" rel="noopener"
&gt;HolmesGPT&lt;/a&gt; en open source, et &lt;a class="link" href="https://www.anyshift.io/" target="_blank" rel="noopener"
&gt;Anyshift&lt;/a&gt; avec son agent SRE pour la détection de root cause et la résolution d&amp;rsquo;incident.&lt;/p&gt;
&lt;p&gt;Note : fun fact, dans son post &amp;ldquo;&lt;a class="link" href="https://alex.balmes.co/fr/blog/mon-positionnement-sur-l-intelligence-artificielle-generative#pour-les-ops" target="_blank" rel="noopener"
&gt;Mon positionnement sur l&amp;rsquo;Intelligence Artificielle Générative&lt;/a&gt;&amp;rdquo; posté juste avant moi, Alex cite une longue liste de métiers qui vont profiter de l&amp;rsquo;IA Gen, et les ops ont le droit à rien d&amp;rsquo;autre qu&amp;rsquo;un argument de plus pour passer sur Kube 😭.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai en revanche commencé à utiliser la GenAI pour réaliser plusieurs projets de sites web à 100% (&lt;em&gt;vibe coding&lt;/em&gt; ?), dont je vous ai d&amp;rsquo;ailleurs déjà parlé :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2025/12/02/jai-donn%C3%A9-1-heure-%C3%A0-des-agents-copilot-pour-migrer-un-site-de-bloggrify-%C3%A0-hugo/" &gt;Convertir un blog de Bloggrify à Hugo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2026/02/09/101-facons-de-deployer-kubernetes-nouvelle-ui/" &gt;Créer un site &amp;ldquo;joli&amp;rdquo;&lt;/a&gt; (largement au-delà de mes compétences) pour héberger les recherches que j&amp;rsquo;ai faites sur les différentes façons de déployer Kubernetes&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.zwindler.fr/2026/02/20/securite-headers-http-observatory-hugo/" &gt;Améliorer la sécurité de mon site web&lt;/a&gt; en automatisant la modification du thème Hugo que j&amp;rsquo;utilise, de manière à avoir la meilleure note sur Mozilla HTTP Observatory&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Dans les 3 cas, le résultat est là. Ou plutôt, il &lt;em&gt;semble&lt;/em&gt; l&amp;rsquo;être pour le béotien que je suis.&lt;/p&gt;
&lt;p&gt;Je n&amp;rsquo;ai jamais caché que je n&amp;rsquo;ai aucune compétence en front, et peut-être que pour un expert du domaine, ce que j&amp;rsquo;ai fait avec l&amp;rsquo;IA est horrible (ou non ?). Dans tous les cas, ça ne peut pas être pire que les UIs que j&amp;rsquo;ai faites sans. Petit exemple 😄 :&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/02/groroti.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="ou-alors--la-gêneai-"&gt;ou alors : la GêneAI ?
&lt;/h2&gt;&lt;p&gt;C&amp;rsquo;est le genre de retours qu&amp;rsquo;on voit fleurir de la part de toutes les personnes qui sont &lt;em&gt;vraiment&lt;/em&gt; expertes d&amp;rsquo;un domaine quand elles voient des novices s&amp;rsquo;extasier. On a de bons exemples avec les vidéos générées par IA : si on ne fait pas attention, on a l&amp;rsquo;impression que c&amp;rsquo;est incroyable. Mais n&amp;rsquo;importe qui avec un œil un peu critique voit tout de suite de &lt;strong&gt;GROS&lt;/strong&gt; problèmes de cohérence. Pareil pour la génération d&amp;rsquo;image, ou de musique.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est aussi vrai pour le code, et on a de très bons exemples de projets &lt;em&gt;vibe codés&lt;/em&gt; qui sont d&amp;rsquo;immondes plats de spaghetti, et des passoires en termes de cybersécurité. Bref, vous l&amp;rsquo;aurez compris, j&amp;rsquo;ai beau être utilisateur (quotidien), je ne suis pas &amp;ldquo;incroyablé&amp;rdquo; (comme disent mes enfants) par les LLMs, même les meilleurs.&lt;/p&gt;
&lt;p&gt;Pourtant, j&amp;rsquo;ai plusieurs copains qui ne jurent que par ça, notamment des gens bien plus brillants / intelligents (appelez ça comme vous voulez) que moi. Donc je me dis &lt;em&gt;&amp;ldquo;OK, peut-être que je m&amp;rsquo;y prends mal. Essayons avec ce qui se fait de mieux&lt;/em&gt;&amp;rdquo; : un IDE type &amp;ldquo;Claude Code&amp;rdquo; et un modèle Opus.&lt;/p&gt;
&lt;h2 id="léditeur"&gt;L&amp;rsquo;éditeur
&lt;/h2&gt;&lt;p&gt;Après avoir fait une petite étude de marché rapide, on se rend compte que les options sont pléthoriques : Claude Code, OpenCode, Amp Code, &amp;hellip;&lt;/p&gt;
&lt;p&gt;Le problème de Claude Code, c&amp;rsquo;est le ticket d&amp;rsquo;entrée. Je ne suis pas encore prêt à lâcher 100 ou 200 € par mois pour l&amp;rsquo;usage que j&amp;rsquo;en ai aujourd&amp;rsquo;hui. Je ne sais pas si l&amp;rsquo;offre à 20€ me suffirait ou non. Au-delà de rares side projects perso que j&amp;rsquo;ai cités plus haut, je code peu. Le gros de mes geekeries, c&amp;rsquo;est de l&amp;rsquo;infra : installer des Kube et des OS de virtualisation. Des trucs difficiles à automatiser avec un LLM.&lt;/p&gt;
&lt;p&gt;On (Pierre surtout) m&amp;rsquo;a conseillé &lt;a class="link" href="https://ampcode.com/" target="_blank" rel="noopener"
&gt;Amp Code&lt;/a&gt; pour du perso, notamment parce que de base, il y a un tier gratuit avec un certain nombre de tokens et que si on n&amp;rsquo;est pas trop gourmand, c&amp;rsquo;est assez efficace. J&amp;rsquo;ai préféré n&amp;rsquo;en faire qu&amp;rsquo;à ma tête et tester plutôt sur &lt;strong&gt;OpenCode&lt;/strong&gt;, qui a l&amp;rsquo;avantage d&amp;rsquo;être plus flexible sur les providers de LLM et la consommation de tokens. Il est d&amp;rsquo;ailleurs possible de profiter de modèles locaux (gratuits, donc) ou &lt;a class="link" href="https://opencode.ai/docs/fr/zen/" target="_blank" rel="noopener"
&gt;des modèles inclus gratuitement (en tout cas pour l&amp;rsquo;instant) tels que GLM 5 Free&lt;/a&gt;, qui est plutôt bien placé dans les modèles de dev (surtout, c&amp;rsquo;est gratuit&amp;hellip;).&lt;/p&gt;
&lt;p&gt;OK, on a l&amp;rsquo;éditeur. Maintenant, le code ?&lt;/p&gt;
&lt;p&gt;Pour me faire une idée de la pertinence du code généré par mon LLM favori (Sonnet et Opus, depuis un moment), il me faut donc un langage &lt;strong&gt;et&lt;/strong&gt; un cas d&amp;rsquo;usage que je maîtrise, pour être capable de lui dire &lt;em&gt;&amp;ldquo;non mais là, c&amp;rsquo;est n&amp;rsquo;importe quoi !?&amp;rdquo;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Cas d&amp;rsquo;usage que je maîtrise&amp;hellip; vous vous en doutez, il y aura forcément du &lt;strong&gt;Kubernetes&lt;/strong&gt; dedans.&lt;/p&gt;
&lt;p&gt;Langage que je maîtrise : j&amp;rsquo;ai appris Go en 2022 grâce à un collègue de chez Deezer (encore merci Martial !) et j&amp;rsquo;ai publié quelques outils et fait des contributions mineures. J&amp;rsquo;ai écrit une grande partie de l&amp;rsquo;outil &lt;a class="link" href="https://github.com/deezer/GroROTI" target="_blank" rel="noopener"
&gt;GroROTI&lt;/a&gt; et aussi commencé (mais jamais terminé) le développement d&amp;rsquo;un RPG en Go, fortement inspiré de Castle of the Winds, un jeu de mon enfance : &lt;a class="link" href="https://github.com/zwindler/gocastle" target="_blank" rel="noopener"
&gt;gocastle&lt;/a&gt;. Et j&amp;rsquo;ai une capacité professionnelle (même si ce n&amp;rsquo;est pas le coeur de mon métier) dans mon travail de tous les jours.&lt;/p&gt;
&lt;h2 id="après-le-contexte-le-projet"&gt;Après le contexte, le projet
&lt;/h2&gt;&lt;p&gt;OK, on a le contexte technique : Kube + Go. Reste donc l&amp;rsquo;idée à implémenter. Il faut un projet suffisamment volumineux pour que le test soit pertinent, suffisamment rigolo pour que j&amp;rsquo;aie envie d&amp;rsquo;y passer du temps perso, mais quand même un peu utile pour que j&amp;rsquo;aie envie d&amp;rsquo;en parler et de montrer l&amp;rsquo;avancement. Et surtout, un projet dont la logique métier reste à ma portée : pour évaluer honnêtement la qualité du code produit par l&amp;rsquo;IA, il faut que je sois capable de le relire et de le critiquer.&lt;/p&gt;
&lt;p&gt;Et là, dans mes tiroirs à idées débiles qui débordent de mon cerveau, je me suis souvenu de ce &amp;ldquo;pitch&amp;rdquo; de 2023-2024, que j&amp;rsquo;avais laissé moisir faute de temps :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;PodSweeper&lt;/strong&gt; : la manière la plus complexe, over-engineerée et chaotique de jouer au démineur.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/02/Wat8.webp"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="partez-pas-vous-allez-voir-cest-rigolo-si-"&gt;Partez pas, vous allez voir c&amp;rsquo;est rigolo. Si !
&lt;/h2&gt;&lt;p&gt;Au lieu d&amp;rsquo;une grille visuelle où on clique sur des cases en espérant ne pas tomber sur une &amp;ldquo;mine&amp;rdquo;, on a une &amp;ldquo;grille&amp;rdquo; virtuelle où chaque case est un Pod et le clic est un &lt;code&gt;kubectl delete&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Oui, c&amp;rsquo;est débile. Ça me plaît donc beaucoup :).&lt;/p&gt;
&lt;p&gt;Au-delà du troll assumé (over-engineering des enfers) de ce jeu, il y a quand même un objectif pédagogique derrière.&lt;/p&gt;
&lt;p&gt;Si, si, vraiment.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai pensé le jeu comme une &lt;strong&gt;introduction à la sécurité dans Kubernetes&lt;/strong&gt;, avec des niveaux de difficulté à débloquer, façon CTF de cybersécurité.&lt;/p&gt;
&lt;p&gt;Au début, vous pouvez &lt;strong&gt;tout&lt;/strong&gt; faire. Vous pouvez bien sûr jouer normalement (delete un Pod, voir s&amp;rsquo;il y a des mines à côté) pour vous faire la main. Vous pouvez aussi automatiser les actions (un script qui &amp;ldquo;clique sur une case&amp;rdquo; au hasard, récupère les hints de proximité de mines, clique à un endroit safe, &amp;hellip;).&lt;/p&gt;
&lt;p&gt;Mais vous pouvez aussi &lt;strong&gt;tricher&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Et c&amp;rsquo;est tout l&amp;rsquo;intérêt du jeu. Dans les premiers niveaux de difficulté, les manifests Kubernetes du jeu sont volontairement vulnérables. On peut donc gagner sans effort, si on sait où chercher.&lt;/p&gt;
&lt;p&gt;Cependant, très vite, les niveaux s&amp;rsquo;enchaînent et les restrictions avec. Assez rapidement, on arrive dans des bonnes pratiques de production qui empêchent toute &amp;ldquo;triche&amp;rdquo;. Et si vous trouvez des vulnérabilités non prévues dans le code du jeu lui-même&amp;hellip; eh bien, c&amp;rsquo;est du bonus 😈.&lt;/p&gt;
&lt;h2 id="le-processus-initial"&gt;Le processus initial
&lt;/h2&gt;&lt;p&gt;C&amp;rsquo;est probablement une erreur, mais j&amp;rsquo;ai fait toute la phase d&amp;rsquo;&lt;strong&gt;idéation avec Gemini&lt;/strong&gt; avant de lancer OpenCode. L&amp;rsquo;expérience aurait probablement été meilleure (a minima plus représentative) si j&amp;rsquo;avais commencé directement avec OpenCode.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai pondu tout ce que j&amp;rsquo;avais dans la tête, ainsi qu&amp;rsquo;un gros pavé informe de dizaines de lignes provenant de mes notes de quand j&amp;rsquo;ai eu l&amp;rsquo;idée en 2023, et je lui ai demandé de me sortir un fichier &lt;a class="link" href="https://github.com/zwindler/PodSweeper/blob/main/SPECIFICATION.md" target="_blank" rel="noopener"
&gt;SPECIFICATIONS.md&lt;/a&gt; avec toutes les infos importantes, remises dans l&amp;rsquo;ordre.&lt;/p&gt;
&lt;p&gt;Une fois les specs écrites, je lui ai demandé de détailler les différents niveaux et les difficultés que nous allions progressivement ajouter, dans &lt;a class="link" href="https://github.com/zwindler/PodSweeper/blob/main/GAMEPLAY.md" target="_blank" rel="noopener"
&gt;GAMEPLAY.md&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Enfin, j&amp;rsquo;ai demandé de faire un découpage du projet par &amp;ldquo;issues&amp;rdquo; et par priorité, de manière à avoir un MVP rapidement : &lt;a class="link" href="https://github.com/zwindler/PodSweeper/blob/main/ISSUES_PRIORITY.md" target="_blank" rel="noopener"
&gt;ISSUES_PRIORITY.md&lt;/a&gt;. Mon idée était de donner le plan de bataille très détaillé et découpé finement à OpenCode et de lui laisser dérouler.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Première déconvenue&lt;/strong&gt; : Gemini 3 Pro est assez mauvais pour ça. Les tâches étaient crédibles(-ish) mais ordonnées n&amp;rsquo;importe comment (dépendances entre tâches non respectées). J&amp;rsquo;ai donc lancé pour la première fois OpenCode dans mon repo et je lui ai dit &lt;em&gt;&amp;ldquo;voilà le contexte, voilà ce qu&amp;rsquo;on a imaginé comme tâches. Qu&amp;rsquo;est-ce que tu en penses ?&amp;rdquo;&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="le-bon-opencode"&gt;Le bon (open)code&amp;hellip;
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/02/opencode.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Dans les trucs assez chouettes : OpenCode + Claude Opus a tout de suite vu que le plan imaginé par Gemini était bancal, et m&amp;rsquo;a posé des questions et proposé un découpage encore imparfait mais déjà plus cohérent. C&amp;rsquo;est probablement là le gros de l&amp;rsquo;intérêt de ces logiciels. Ils embarquent des connaissances pour guider le développement logiciel et surtout (SURTOUT) apportent du cadre.&lt;/p&gt;
&lt;p&gt;Assez vite, on finit par se mettre d&amp;rsquo;accord sur un plan qui me plaît. OpenCode met à jour les documents et se met à développer (scaffolding, création des pipelines, premiers binaires et images Docker vides). On a un projet prêt à développer en un claquement de doigt, c&amp;rsquo;est assez enthousiasmant, de prime abord.&lt;/p&gt;
&lt;p&gt;Les assistants LLMs ont très envie de se jeter dans le code, ça reste vrai avec OpenCode+Opus. Alors même qu&amp;rsquo;on n&amp;rsquo;avait pas fini de discuter du plan et des options possibles, il me proposait de lui-même de passer au code. Cela dit, c&amp;rsquo;était pareil (voire pire) pour Gemini (à qui j&amp;rsquo;avais dit spécifiquement qu&amp;rsquo;on n&amp;rsquo;allait pas faire de code du tout).&lt;/p&gt;
&lt;p&gt;Très vite, les créations de fichiers s&amp;rsquo;enchaînent. J&amp;rsquo;ai du mal à suivre et à chaque pause (quand le LLM a fini une tâche et qu&amp;rsquo;il me demande s&amp;rsquo;il peut passer à la suivante), je prends de longues minutes à lire ce que le LLM a produit. C&amp;rsquo;est à la fois grisant et épuisant (relire tout ça, c&amp;rsquo;est dur pour mon cerveau rouillé).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;La vitesse brute est impressionnante.&lt;/strong&gt; En 3 sessions de 1 à 2h, j&amp;rsquo;ai un MVP fonctionnel. Je comprends qu&amp;rsquo;on parle régulièrement de 10x engineering quand on parle de génération de code avec les LLMs récents. Si on ne parle pas de génération de code brute (ce qui n&amp;rsquo;a pas vraiment de sens), à la louche, le code fonctionnel est généré entre 3x et 10x plus rapidement que ce que j&amp;rsquo;aurais pu faire seul. Des features qui mises bout à bout m&amp;rsquo;auraient pris des heures à implémenter (génération de la grille, logique de reveal, gestion des états de jeu) tombent en quelques minutes. Vous l&amp;rsquo;avez déjà lu ailleurs, je dis pareil - le goulot d&amp;rsquo;étranglement, ce n&amp;rsquo;est plus le code que je tape : c&amp;rsquo;est le code que je dois relire.&lt;/p&gt;
&lt;p&gt;De ce que j&amp;rsquo;ai lu, le code est correct, en particulier lors des premières itérations, un peu moins au bout d&amp;rsquo;un moment. Mais quand je dis &amp;ldquo;correct&amp;rdquo;, je sous-vends peut-être le truc : le code produit est du &lt;strong&gt;Go idiomatique&lt;/strong&gt;. Bonne structure en packages, conventions de nommage respectées, gestion d&amp;rsquo;erreur dans le style Go (quand elle est là&amp;hellip;), utilisation appropriée des interfaces. Ce n&amp;rsquo;est pas juste du code qui compile : c&amp;rsquo;est du code qu&amp;rsquo;un reviewer Go ne rejetterait pas d&amp;rsquo;emblée. On a pour objectif un MVP donc ça reste de la logique &amp;ldquo;métier&amp;rdquo; très simple, mais le socle est propre.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tout est testé&lt;/strong&gt;, très vite le projet contient une couverture parfaite et 100+ tests alors qu&amp;rsquo;on ne fait encore rien. Si c&amp;rsquo;était du code généré par un humain, je ne saurais pas dire si c&amp;rsquo;est une bonne chose. On est pas du tout dans du TDD, beaucoup de code teste des choses inutiles. Dans le cas du code généré par le LLM, c&amp;rsquo;est probablement pour le mieux, car le LLM a tendance à ajouter très régulièrement des régressions (on en reparlera). C&amp;rsquo;est donc intéressant ici, car :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;ça ne coûte quasiment rien en temps de dev (ça va tellement vite à générer)&lt;/li&gt;
&lt;li&gt;cela permet au LLM de se rendre compte que son code introduit une régression, et de fixer de lui-même, sans attendre.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="-et-le-mauvais-opencode"&gt;&amp;hellip; et le mauvais (open)code
&lt;/h2&gt;&lt;p&gt;Côté outil et modèle d&amp;rsquo;abord, quelques &lt;strong&gt;irritants&lt;/strong&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Par défaut, OpenCode n&amp;rsquo;incite pas le LLM à lancer &lt;code&gt;golangci-lint&lt;/code&gt; à chaque commit. On corrige ça avec un pre-commit hook et/ou les fameux AGENTS.md / skills, mais ça aurait DÛ faire partie du kit de base d&amp;rsquo;un projet golang (il y a bien les tests&amp;hellip;).&lt;/li&gt;
&lt;li&gt;Le LLM (Claude Opus sur OpenCode, mais c&amp;rsquo;est un biais habituel même en dehors) &lt;strong&gt;adore&lt;/strong&gt; les versions de logiciels qui existaient au moment de son entraînement. Il faut continuellement lui répéter que les versions qu&amp;rsquo;il suggère sont obsolètes. C&amp;rsquo;est vrai pour tout : le code Go, les dépendances, les versions des actions GitHub.&lt;/li&gt;
&lt;li&gt;On tombe très souvent dans la limite des 100k tokens. On perd du temps à &amp;ldquo;compacter&amp;rdquo; et on perd de la précision. Typiquement : le LLM me demande s&amp;rsquo;il peut &lt;code&gt;git commit&lt;/code&gt; des modifs, le contexte se compacte avant que je réponde, et il commit sans mon autorisation en redéroulant le contexte. Sur du code aussi peu sensible, ça va. Mais sur de la prod, ça serait un vrai problème.&lt;/li&gt;
&lt;li&gt;Le LLM est souvent amnésique : il oublie qu&amp;rsquo;il a accès à un cluster kind pour faire des tests réels (alors qu&amp;rsquo;il l&amp;rsquo;a fait juste avant la précédente compaction, par exemple).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Côté &lt;strong&gt;qualité du code&lt;/strong&gt; produit, c&amp;rsquo;est plus préoccupant :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Gestion d&amp;rsquo;erreur laxiste.&lt;/strong&gt; Certaines erreurs qui auraient dû retourner un FATAL (controller qui n&amp;rsquo;arrive pas à s&amp;rsquo;initialiser correctement !) sont simplement logguées comme ERROR. On se retrouve à ship des versions qui échouent silencieusement. Là encore, ça doit pouvoir se fine tuner avec un AGENTS.md.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Race conditions.&lt;/strong&gt; Je suis tombé très vite sur des race conditions assez bêtes. Dans mon cas, des pods bloqués en terminating impactaient le jeu suivant (graceful shutdown mal géré). Opus est parti en boucle sans comprendre la source du problème. J&amp;rsquo;ai dû le stopper et lui spécifier qu&amp;rsquo;il ne fallait jamais lancer une nouvelle partie sans s&amp;rsquo;être assuré que la précédente était terminée.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Génération de code en dehors des clous.&lt;/strong&gt; Parfois, sans crier gare, le LLM ajoute une fonctionnalité qui n&amp;rsquo;est pas demandée, inutile, voire qui va à l&amp;rsquo;encontre de la SPECIFICATION écrite précédemment. On est obligé de lui remettre un taquet derrière la tête.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Une fois remis sur les rails, le LLM déroule à nouveau, mais ces épisodes montrent bien que sur du code concurrent ou en dehors de user stories hyper strictes (ce qui sort du workflow de base d&amp;rsquo;opencode), la supervision humaine reste indispensable.&lt;/p&gt;
&lt;p&gt;On me répondra que je débute avec ces outils, et que j&amp;rsquo;aurais pu éviter certains écueils en configurant mieux mon environnement (AGENTS.md, pre-commit hooks, etc.). C&amp;rsquo;est vrai.&lt;/p&gt;
&lt;p&gt;Mais c&amp;rsquo;est justement là que le bât blesse : une des promesses vantées de la GenAI appliquée au dev, c&amp;rsquo;est de permettre à des non-développeurs (ou des débutants) de produire du logiciel de qualité à grande vitesse, de manière à pouvoir ship des logiciels complets. Si pour en tirer le meilleur, il faut déjà être un développeur expérimenté qui sait configurer un environnement complexe (avec les spécificités de ces outils IA), anticiper les race conditions et relire du code concurrent&amp;hellip; on n&amp;rsquo;a pas démocratisé le développement, on a juste donné un outil de plus aux gens qui savaient déjà coder. Mon profil (ops qui code, pas dev pur jus) était précisément le public cible de cette promesse. Et aujourd&amp;rsquo;hui, &amp;ldquo;les calculs sont pas bons, Kévin&amp;rdquo;.&lt;/p&gt;
&lt;h2 id="où-jen-suis-"&gt;Où j&amp;rsquo;en suis ?
&lt;/h2&gt;&lt;p&gt;Depuis tout à l&amp;rsquo;heure, je vous parle de PodSweeper. Mais il en est où, ce projet ?&lt;/p&gt;
&lt;p&gt;Après 3 sessions de 1 à 2h max, sans compter l&amp;rsquo;idéation, j&amp;rsquo;ai un MVP fonctionnel. Comme je l&amp;rsquo;ai dit plus haut, le gain de productivité est indéniable, pour quelqu&amp;rsquo;un qui n&amp;rsquo;est pas &amp;ldquo;dev&amp;rdquo; de métier.&lt;/p&gt;
&lt;p&gt;Le code est probablement &amp;ldquo;globalement&amp;rdquo; de meilleure qualité que le code golang que j&amp;rsquo;aurais pu écrire, &lt;strong&gt;mais&lt;/strong&gt; le LLM laisse passer des trous béants dans la logique métier (tout simplement parce qu&amp;rsquo;il ne réfléchit pas, alors que moi, oui. Enfin, normalement). Dur pour la confiance&amp;hellip; Il faut vraiment rester très méfiant de tout ce qui est produit.&lt;/p&gt;
&lt;p&gt;Le code est disponible à l&amp;rsquo;adresse suivante :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/zwindler/PodSweeper/tree/main" target="_blank" rel="noopener"
&gt;https://github.com/zwindler/PodSweeper/tree/main&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://blog.zwindler.fr/2026/03/podsweeper.avif"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Vous pouvez aller voir le code pour vous faire une idée. Si vous n&amp;rsquo;avez pas peur de vous spoiler, vous pouvez lire la &lt;a class="link" href="https://github.com/zwindler/PodSweeper/blob/main/SPECIFICATION.md" target="_blank" rel="noopener"
&gt;SPECIFICATION.md&lt;/a&gt; (spoilers), voire &lt;a class="link" href="https://github.com/zwindler/PodSweeper/blob/main/GAMEPLAY.md" target="_blank" rel="noopener"
&gt;GAMEPLAY.md&lt;/a&gt; (j&amp;rsquo;y détaille tous les niveaux donc c&amp;rsquo;est giga spoilers).&lt;/p&gt;
&lt;p&gt;Vous pouvez (normalement) jouer aux premiers niveaux de difficulté. Ça reste assez basique, si vous avez déjà manipulé &lt;code&gt;kubectl&lt;/code&gt; vous devriez trouver la solution très rapidement. Mon but est de rajouter des niveaux au fur et à mesure, j&amp;rsquo;en ai déjà imaginé 10, certains bien retors 😈 et d&amp;rsquo;autres viendront peut-être ensuite.&lt;/p&gt;
&lt;p&gt;Le code est en MPL v2.0 parce que c&amp;rsquo;est une licence copyleft que j&amp;rsquo;aime bien, &lt;a class="link" href="https://www.tldrlegal.com/license/mozilla-public-license-2-0-mpl-2" target="_blank" rel="noopener"
&gt;car elle est à la fois assez peu restrictive, OSI compliant et oblige quand même à reverser les modifs si on en fait dans son coin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Voilà :) si vous aussi vous trouvez ça rigolo, n&amp;rsquo;hésitez pas à tester et/ou à me faire des retours.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl apply -k https://github.com/zwindler/podsweeper//deploy/base?ref&lt;span class="o"&gt;=&lt;/span&gt;v0.1.4
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;namespace/podsweeper-game created
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl &lt;span class="nb"&gt;wait&lt;/span&gt; --for&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ready pod -l app.kubernetes.io/name&lt;span class="o"&gt;=&lt;/span&gt;podsweeper &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -n podsweeper-game --timeout&lt;span class="o"&gt;=&lt;/span&gt;60s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pod/gamemaster-54f4dddcc4-6m88z condition met
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Have fun !&lt;/p&gt;</description></item></channel></rss>