Garde-fous — une politique unique pour chaque action qui modifie l’état
Les agents de Control Center peuvent supprimer des fichiers, pousser des branches, publier des pull requests et appeler des API externes. Chacune de ces actions relève d’un type de risque différent, et pendant longtemps une seule d’entre elles — les commandes shell — disposait d’une politique. Les garde-fous existent pour répondre uniformément à une seule question, pour chaque action qui modifie l’état qu’un agent peut entreprendre, quel que soit l’exécuteur ou l’outil qui la propose : cette action est-elle autorisée, nécessite-t-elle une approbation, ou est-elle refusée ?
Un seul moteur, tous les points de passage
Section intitulée « Un seul moteur, tous les points de passage »Il existe exactement un moteur de politiques. Il est consulté à chaque point où une action peut quitter le système : le registre d’outils du harnais intégré, le verrou du répartiteur MCP côté serveur et les mutations d’opérations de dépôt. Une règle écrite une fois s’applique donc aussi bien à l’exécuteur intégré qu’aux CLI d’agents externes — il n’existe pas de second chemin, plus discret, pour la contourner. L’ancienne politique de commandes limitée à bash fonctionne toujours : une règle peut cibler un préfixe de commande plutôt qu’une classe d’action, et les deux formes coexistent dans le même magasin.
Le moteur ne remplace toutefois pas le bac à sable du système d’exploitation, et
le bac à sable ne le remplace pas non plus. Ils répondent à des questions
différentes : les garde-fous décident si un appel que Control Center peut voir a
le droit de se produire, tandis que le bac à sable délimite la portée du
processus qui en résulte. cc_server applique le bac à sable lorsque l’hôte
propose un backend — mais Windows n’en propose aucun et Linux a besoin de
bwrap et socat. Sur ces
hôtes, les garde-fous constituent la couche de contrôle la plus externe plutôt
qu’une politique posée au-dessus d’un socle, ce qu’il est utile de savoir
lorsque vous décidez du degré de permissivité à adopter.
ActionClass : une taxonomie volontairement fermée
Section intitulée « ActionClass : une taxonomie volontairement fermée »Chaque outil qui modifie l’état déclare les ActionClasses auxquelles il appartient, parmi un ensemble fermé de treize classes d’effet. Cinq d’entre elles déclenchent une demande d’approbation par défaut ; les autres autorisent, et seule une règle peut changer cela.
| Classe | Valeur par défaut intégrée | Ce qu’elle couvre |
|---|---|---|
fileDelete |
Demander d’abord | Supprimer un fichier (une écriture de type suppression, rm) |
gitPush |
Demander d’abord | Pousser vers un dépôt git distant |
prCreate |
Demander d’abord | Créer une pull request |
prPublish |
Demander d’abord | Publier une revue, fusionner une PR |
vendorSyncWrite |
Demander d’abord | Écrire dans un outil de suivi de tickets externe (Linear, Jira, synchronisation GitHub) |
fileWriteOutsideWorktree |
Autoriser | Écrire un fichier en dehors de l’arbre de travail isolé |
gitCommit |
Autoriser | Créer un commit git |
networkEgress |
Autoriser | Sortie réseau (récupération web, HTTP arbitraire) |
secretAccess |
Autoriser | Lire un secret ou un identifiant |
packageInstall |
Autoriser | Installer un paquet (npm, pip, pub, brew) |
processSpawn |
Autoriser | Lancer un processus (le shell et tout ce qui passe par le shell) |
workspaceMutation |
Autoriser | Modifier la structure de l’espace de travail (dépôts, espaces, agents) |
enclosureControl |
Autoriser | Piloter une enceinte (rig) : démarrer une VM, lui envoyer des entrées |
Les huit classes autorisées par défaut ont été choisies en partant du principe
que le socle du bac à sable s’applique en dessous. C’est le cas là où l’hôte
propose un backend, mais pas sous Windows ni sur une machine Linux dépourvue de
bwrap et socat — si vous voulez y soumettre fileWriteOutsideWorktree ou
packageInstall à un contrôle, c’est une règle que vous devez écrire.
Cet ensemble est volontairement fermé. Un nouvel outil qui modifie l’état sans déclarer de classe échoue au test à cliquet, de sorte que la taxonomie ne peut s’étendre que par une décision explicite et argumentée — « la prolifération de la taxonomie est la mort de cette fonctionnalité ». Treize classes suffisent à exprimer les politiques que les gens écrivent réellement (ne jamais pousser sans demander, ne jamais supprimer en dehors d’un arbre de travail, toujours autoriser les lectures) et sont assez peu nombreuses pour que l’interface des paramètres reste compréhensible.
Règles et résolution des portées
Section intitulée « Règles et résolution des portées »Une règle associe (scope, ActionClass | command prefix) → allow | prompt | deny.
Les portées s’imbriquent de la plus spécifique à la moins spécifique :
espace > agent > espace de travail > préréglage de mode > valeur par défaut intégrée
La résolution suit l’ordre spécificité d’abord : la première portée dotée d’une règle correspondante décide, et la résolution s’arrête là. Le caractère le plus restrictif ne sert que d’arbitrage — entre deux règles de spécificité égale au sein d’une même portée, et lors de la combinaison des différentes classes que déclare une même action. Au sein d’une portée, une règle de commande correspond au préfixe de commande le plus long. « Autoriser » ne l’emporte sur « Refuser » nulle part.
Deux décisions offrent des garanties fortes :
- Demandes refusées par défaut. Un
promptsans approbateur connecté se résout en refus. Une question sans réponse n’est jamais un oui. - Combinaison la plus restrictive. Une action qui couvre plusieurs classes les combine de la façon la plus restrictive ; lorsque plusieurs classes demandent une approbation, une seule confirmation les énumère toutes.
Il n’existe délibérément aucun verrou par tour. Chaque appel d’outil réévalue la politique depuis le début, de sorte que la répétition des demandes pour une même action est bornée par le « mémoriser cette décision » de l’opérateur lui-même, et non par quoi que ce soit lié au tour.
Règles au niveau des arguments
Section intitulée « Règles au niveau des arguments »Une règle peut encadrer les ARGUMENTS d’une action, et pas seulement son verbe.
« Peut pousser » et « peut pousser vers feature/* » sont deux affirmations
différentes, et seule la seconde constitue un contrôle — un filtre de capacité
qui n’autorise que le verbe est le schéma à l’origine de la plupart des
incidents d’agents publiés.
Une contrainte peut viser :
- chemins — des motifs glob (
repos/**,!**/.env) - références — des références git, avec négation
!(['**', '!main']se lit « n’importe quelle branche sauf main ») - hôtes — des destinations réseau, avec jokers de sous-domaine (
*.internal) - commandes — des préfixes de commande, mis en correspondance sur une limite de mot
- plafonds —
maxCount/maxCents, ce qui permet d’exprimer « supprimer jusqu’à 50 fichiers »
Trois propriétés découlent du maintien d’une grammaire fermée et sans boucle, et toutes trois constituent précisément l’objectif : chaque règle se lit comme une phrase que vous pouvez relire, chaque refus peut nommer la contrainte qui a correspondu, et l’ensemble de la politique peut être énuméré — vous pouvez voir ce qu’un agent a le droit de faire avant qu’il ne s’exécute.
Trois règles qui comptent :
- Une règle contrainte est plus spécifique qu’une règle non contrainte à la
même portée, de sorte que « refuser le push vers
main» l’emporte sur « autoriser le push » sans que personne n’ait à réfléchir à l’ordre. - Une règle restrictive (Refuser / Demander d’abord) s’applique lorsque la requête touche l’une quelconque des valeurs qu’elle nomme ; une règle permissive (Autoriser) ne s’applique que si la requête est entièrement comprise dans son périmètre. Les lire de la même façon permettrait à un agent de blanchir un chemin interdit en le plaçant à côté d’un chemin anodin.
- Une règle qui nomme une facette sur laquelle la requête ne dit rien n’est ni appliquée ni ignorée : elle déclenche une demande d’approbation. L’ignorer silencieusement rendrait toute règle de branche protégée inopérante face à un outil qui ne déclare pas sa référence ; refuser silencieusement reviendrait à rejeter tout push que l’extracteur ne sait pas décrire. Sans approbateur connecté, la règle de refus par défaut déjà en place transforme cette escalade en refus.
Ce qu’une règle de commande peut intercepter ou non
Section intitulée « Ce qu’une règle de commande peut intercepter ou non »Une règle commandPrefix correspond sur une limite de mot : git push couvre
git push origin main et pas git pushx. Elle ne normalise pas le shell.
git push (deux espaces), cd sub && git push et GIT_DIR=… git push sont
des chaînes différentes, et aucune ne correspond à une règle portant sur
git push.
C’est une limite réelle, et elle est énoncée plutôt que masquée : les règles de
commande sont une commodité offerte à l’opérateur pour façonner le comportement
ordinaire des agents, et non une frontière contre un agent adversaire. Les
frontières sont les classes d’effet (qu’un outil déclare et ne peut pas
reformuler), le filet de commandes du mode situé sous le magasin de politiques,
et le bac à sable du système d’exploitation sous ces deux éléments. Une règle de
commande qui se résout en allow ne relâche jamais ni l’un ni l’autre — le
filet du mode s’exécute après, et son deny est définitif.
Approbations mémorisées
Section intitulée « Approbations mémorisées »Répondre à une demande par « mémoriser cette décision » écrit une véritable règle
de politique : limitée à une portée (espace / agent / espace de travail),
contrainte sur ses arguments (approuver un push vers feature/login accorde
feature/**, et non main) et auto-révocable au terme d’un TTL explicite.
Dire oui pour les prochaines heures n’équivaut pas à réécrire discrètement votre
politique permanente, et les règles ainsi écrites atterrissent dans le même
magasin, avec la provenance remembered et une date d’expiration, de sorte
qu’elles peuvent être révoquées avant terme.
Niveaux d’application
Section intitulée « Niveaux d’application »Chaque règle en porte un :
- consultatif — autorise, mais consigne que la règle a correspondu. C’est le chemin d’adoption : déployez une règle stricte en mode consultatif, consultez le journal d’audit pendant une semaine pour voir exactement ce qu’elle aurait bloqué, puis promouvez-la. Sans ce palier, les politiques strictes ne sont jamais activées.
- souple — refuse, avec possibilité de dérogation par une personne disposant de la permission de dérogation, accompagnée d’une justification consignée. La dérogation est elle-même un événement audité.
- strict (valeur par défaut) — refuse. Rien ne permet d’y déroger.
Le palier géré
Section intitulée « Le palier géré »Un opérateur d’installation peut épingler une politique qu’aucun administrateur
d’espace de travail ne peut assouplir. Les règles gérées résident côté serveur et
sont fusionnées de la façon la plus restrictive avec la chaîne propre à
chaque espace de travail — elles ne constituent pas une portée en tête de cette
chaîne, car un allow géré placé en tête permettrait à l’installation de passer
outre un refus d’espace de travail, soit l’inverse de ce à quoi sert un plafond.
Une règle gérée ne peut donc jamais que resserrer.
Définir CC_SERVER_MANAGED_POLICY sur un fichier JSON prime entièrement sur les
règles enregistrées, ce qui permet à un opérateur d’épingler une posture
qu’aucune interface d’administration ne peut inverser — la réponse à « puis-je
empêcher mes développeurs de désactiver les contrôles de sécurité ? »
Le cadran d’autonomie est un profil, pas un système parallèle
Section intitulée « Le cadran d’autonomie est un profil, pas un système parallèle »Le cadran d’autonomie propre à chaque espace est un profil nommé appliqué à ce
même magasin de politiques, et non un second mécanisme. Ses trois réglages sont
stockés et transmis sous la forme proposeOnly, actWithApproval et
actFreely (les formes avec traits d’union ne sont que du texte d’interface, et
autonomy.setForSpace rejette tout le reste). Ne pas le définir équivaut à
actWithApproval.
Ce que chacun fait à une décision résolue :
proposeOnlyrefuse d’emblée tout outil soumis à un contrôle. L’agent peut toujours raisonner et répondre ; il ne peut simplement pas agir, et son message en explique la raison.actWithApproval(et l’absence de réglage) correspond à la porte d’approbation à refus par défaut décrite plus haut.actFreelypré-approuve tout ce qui ne s’est pas résolu en undenystrict.
Ce dernier mérite d’être énoncé sans détour plutôt qu’adouci : sous
actFreely, une décision prompt n’est pas transmise à un approbateur —
elle est autorisée et personne n’est sollicité. Seule une règle deny explicite
survit au cadran. actFreely est donc une concession délibérée d’autonomie, et
non un réglage de confort, et la règle de refus par défaut protège précisément
le cas où cela compte (actWithApproval, la valeur par défaut).
La délégation entre agents est protégée au point de passage delegate_task par
quatre garde-fous : un plafond de profondeur (3 par défaut), la détection des
cycles, un plafond d’autonomie (un agent délégué ne peut jamais agir avec
plus d’autonomie que celui qui l’a délégué — un privilège ne peut pas être
blanchi en confiant le travail à un agent plus libre) et une enveloppe
budgétaire (la délégation est imputée au budget restant du délégateur et ne
peut pas en créer davantage). Chacun est refusé bruyamment, la raison du
garde-fou étant renvoyée mot pour mot à l’agent.
La matrice d’honnêteté des adaptateurs
Section intitulée « La matrice d’honnêteté des adaptateurs »Tous les exécuteurs ne permettent pas à Control Center d’intercepter chaque action. Les CLI d’agents externes exécutent certains outils nativement, dans leur propre processus, là où aucun verrou ne peut s’interposer. Plutôt que de prétendre le contraire, chaque adaptateur porte une matrice d’honnêteté : pour chaque adaptateur, si Control Center filtre la surface d’outils, intercepte les appels d’outils, observe le contrat d’achèvement, peut voir les outils natifs de l’exécuteur et si les outils exécutés dans le processus sont couverts par un profil de bac à sable.
Deux entrées méritent d’être lues avant de faire confiance à une configuration.
Le harnais intégré déclare que ses outils de fichiers exécutés dans son propre
processus ne sont pas placés dans un bac à sable — la surface d’outils et ce
moteur de politiques constituent sa seule frontière en matière de système de
fichiers. Claude Code déclare que ses propres appels d’outils ne sont pas
interceptables, car il est lancé avec --dangerously-skip-permissions ; Control Center voit ses appels mcp__* et, via un hook, ses lignes de commande Bash, tandis que ses propres outils de lecture, d’écriture et d’édition s’exécutent sans être vus.
L’écran des paramètres affiche cette matrice, car le seul échec impardonnable pour un système de garde-fous est de revendiquer une couverture qui n’existe pas.
Sonder la politique avant qu’elle ne morde
Section intitulée « Sonder la politique avant qu’elle ne morde »Les garde-fous se trouvent dans Paramètres → Espace de travail → Autorisations
des agents (/workspaces/<id>/settings/workspace/permissions). Cet écran
regroupe la matrice de politiques où les règles s’écrivent, des modèles de
politique, une sonde « et si ? », le journal d’audit des autorisations et la
matrice d’honnêteté des adaptateurs.
La sonde prend une classe d’action (ou une commande) et une portée, puis indique quelle règle a décidé et pourquoi. Comme la résolution est pure et déterministe — même action, même portée, même décision — la réponse de la sonde est celle que l’agent obtiendra.
Concepts liés
Section intitulée « Concepts liés »- Bac à sable et sécurité : ce qui contraint réellement l’exécution d’un agent et jusqu’où s’étend le socle du système d’exploitation sous ce moteur
- Multijoueur — identité, appartenance et présence : les espaces, les principaux et l’emplacement du cadran d’autonomie
- Configurer les garde-fous : écrire et tester des règles en pratique