Hermes demande désormais une approbation avant de désinstaller un paquet

Un paquet npm global ralentit vos builds sans raison apparente. Vous mettez la main dessus et vous tapez npm uninstall -g some-package sans y penser à deux fois. Deux jours plus tard, il manque dans la CI, et tous les projets de cette machine sont impactés. Installer quelque chose se remarque ; supprimer quelque chose s’oublie, et les dégâts sont presque toujours partagés. Et pourtant, quand Hermes Agent exécutait cette commande pour vous, rien ne s’arrêtait pour demander : le portail d’approbation des commandes dangereuses ne connaissait que les primitives shell comme rm -rf. Le PR #109170 comble précisément ce trou.
Installer fait rarement mal. Supprimer, si.
D’abord, le mécanisme. L’approbation des commandes dangereuses est un ensemble de règles de motifs intégrées à Hermes : lorsque l’agent s’apprête à exécuter une commande dont les conséquences sont irréversibles, il affiche une demande d’approbation et attend votre réponse au lieu de foncer. L’intention est simple : qu’une opération irréversible ne passe pas inaperçue.
Vu sous cet angle, installer et désinstaller ne sont pas symétriques. Installer est additif : ce qui apparaît finit par se remarquer, et en cas de problème, vous le supprimez. Désinstaller est soustractif, et le plus souvent d’une soustraction partagée : retirez un paquet global et tous les projets de la machine qui en dépendaient sont touchés, sans que rien ne vous signale qu’il vient de disparaître quelque chose.
C’est exactement cette asymétrie qui explique que la modification ne freine que les désinstallations. npm update -g, pip install, brew upgrade et yarn install ne sont toujours pas signalés et ne demandent toujours rien. Si l’on freinait aussi les installations, la barre d’approbation ne serait plus qu’un bruit que l’on valide une dizaine de fois par jour : pire que pas de barrière du tout.
La table de motifs ne connaissait que les primitives shell
Le problème se trouvait dans DANGEROUS_PATTERNS, la table de motifs de tools/approval_detection.py. Ce qu’elle attrapait, c’était les primitives shell : rm -rf, git reset --hard et consorts — des commandes brutales, archi-connues, évidentes au premier coup d’œil. Pour les verbes de suppression des gestionnaires de paquets, il n’existait pas la moindre règle.
C’est pourquoi, lors de l’incident à l’origine de l’issue #10199, la commande s’est exécutée de bout en bout sans aucune demande. Non pas un mauvais verdict, mais simplement : aucune règle ne couvrait cette commande.
Les cinq écritures de suppression désormais interceptées
Le PR #109170 va droit au but : il ajoute, dans DANGEROUS_PATTERNS, une règle « package manager uninstall » par gestionnaire de paquets. Le diff complet fait +34 / −0 sur deux fichiers, tools/approval_detection.py et tests/tools/test_approval.py.
À partir de maintenant, tout ceci passe par l’approbation des commandes dangereuses :
- npm —
npm uninstall -g some-package. Verbes de suppression :uninstall/unlink/remove/rm/r/un - pnpm —
pnpm remove. Verbes de suppression :uninstall/remove/rm/un - yarn —
yarn remove. La règle accepte unglobalfacultatif devant, puisuninstall/remove - pip / pip3 —
pip uninstall. Le verbe de suppression estuninstall - brew —
brew uninstall. Verbes de suppression :uninstall/remove/rm
Notez bien ce que ciblent les règles : le verbe de suppression du gestionnaire, pas un nom de paquet précis. Peu importe sur quoi le verbe pointe et combien de cibles suivent — la commande est signalée.
Deux endroits où ils ont évité les faux positifs
La façon classique de casser une table de règles, c’est de la rendre trop large et de se mettre à bloquer des commandes légitimes. Deux détails méritent ici d’être soulignés.
Premièrement, les règles sont ancrées à la position de commande via _CMDPOS. Comme les autres règles de noms de commandes de ce fichier, le motif ne correspond qu’à l’endroit où la commande commence réellement. Le texte entre guillemets n’est donc pas mal interprété : git commit -m "document npm uninstall usage" n’est qu’un message de commit et ne déclenche rien.
Deuxièmement, chaque option globale accepte un argument qui n’est pas un tiret. Autrement dit, npm --prefix DIR uninstall x, pip --proxy URL uninstall x et yarn --cwd DIR remove x sont eux aussi interceptés. Une option suivie d’un argument est une forme quotidienne ; l’oublier rendrait la règle purement décorative.
Les tests ont suivi. tests/tools/test_approval.py ajoute 6 cas paramétrés qui regroupent six écritures de suppression sous une même clé. Ces cas étaient rouges face à l’ancien code ; après correction, 129 cas passent, et la suite complète de tests/tools/ est verte à 9141.
Ce que cela change pour vous
Si quelqu’un surveille votre session Hermes, c’est simple : l’agent s’arrête et demande avant de désinstaller un paquet, et vous confirmez ou refusez. Un clic de plus, en échange de la certitude que ce qui a été supprimé est bien ce que vous vouliez supprimer.
Le cas qui mérite vraiment réflexion en amont, c’est le travail sans surveillance : tâches cron, agents lancés en arrière-plan. Personne n’est là pour répondre à une demande d’approbation, donc une désinstallation qui aurait dû être freinée reste bloquée à mi-chemin. Si un flux automatisé a réellement besoin de désinstaller des paquets, ne comptez pas sur un passage en force : testez d’abord la commande contre les vrais garde-fous avec hermes approvals test, regardez sur quel verdict elle tombe, puis décidez si vous l’autorisez, si vous remaniez le flux, ou si vous tenez carrément l’agent à l’écart de cette étape. Le comportement des approbations en contexte cron est détaillé dans le guide des approbations sans surveillance.
Une distinction à ne pas mélanger : l’approbation des commandes dangereuses et approvals.deny sont deux mécanismes différents. La première est la table de motifs intégrée, et elle fonctionne sans la moindre configuration de votre part ; la seconde est une liste de refus prédéfinie que vous maintenez vous-même. Cet article ne traite que de la première. Pour la seconde, voyez la configuration des approbations intelligentes — inutile de la répéter ici.
Enfin, l’état de publication, dit sans détour : c’est arrivé dans main le 2026-09-12, soit après la v0.21.2 (publiée le 2026-09-11). Ce n’est donc encore présent dans aucune version publiée — c’est dans la branche principale, et cela vous parviendra avec la prochaine version. Pour savoir ce que ferait votre build actuelle, hermes approvals test est la réponse directe ; les notes de version de la v0.21.2 correspondent à la dernière publication avant ce changement.
En bref
- Les désinstallations de gestionnaires de paquets passent désormais par l’approbation des commandes dangereuses :
npm uninstall -g,pnpm remove,yarn remove,pip uninstalletbrew uninstallsont couvertes. - Les installations et les mises à jour ne demandent toujours rien :
npm update -g,pip install,brew upgradeetyarn installne sont pas touchées. L’approbation reste réservée à ce qui est vraiment irréversible. - Les règles sont ancrées à la position de commande, donc un
npm uninstallentre guillemets n’est pas signalé à tort, et une option globale suivie d’un argument ne les contourne pas. - La modification est fusionnée dans
mainet n’est encore sortie dans aucune version.