Garde-fous — une seule politique pour chaque action modificatrice
Les agents de Control Center peuvent supprimer des fichiers, pousser des branches, publier des demandes de tirage et appeler des API externes. Chacune de ces actions représente un type de risque différent et, pendant longtemps, une seule d’entre elles — les commandes shell — avait une politique. Les garde-fous existent pour répondre uniformément à une seule question, pour chaque action modificatrice qu’un agent peut poser, peu importe l’environnement d’exécution ou l’outil qui la propose : cette action est-elle autorisée, exige-t-elle une approbation, ou est-elle refusée?
Un seul moteur, tous les points de passage obligés
Section intitulée “Un seul moteur, tous les points de passage obligés”Il n’existe qu’un seul moteur de politiques. Il est consulté à chaque point où une action peut quitter le système : le registre d’outils du harnais intégré, la barrière du répartiteur MCP côté serveur et les mutations d’opérations de dépôt. Une règle écrite une seule fois s’applique donc autant à l’environnement d’exécution intégré qu’aux CLI d’agents externes : il n’existe aucun second chemin, plus discret, pour la contourner. L’ancienne politique de commandes, réservée à bash, fonctionne toujours : une règle peut correspondre à 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 limite ce que le processus
résultant peut atteindre. cc_server applique le bac à sable là où l’hôte offre
un backend — mais Windows n’en offre aucun et Linux exige 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 vaut la peine de savoir avant de
décider à quel point être permissif.
ActionClass : une taxonomie volontairement fermée
Section intitulée “ActionClass : une taxonomie volontairement fermée”Chaque outil modificateur déclare à quelles ActionClasses il appartient, parmi un ensemble fermé de treize classes d’effet. Cinq d’entre elles demandent d’abord par défaut; les autres autorisent, et seule une règle change cela.
| Classe | Valeur par défaut | 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 demande de tirage |
prPublish |
Demander d’abord | Publier une revue ou fusionner une PR |
vendorSyncWrite |
Demander d’abord | Écrire dans un outil de suivi externe (Linear, Jira, synchronisation GitHub) |
fileWriteOutsideWorktree |
Autoriser | Écrire un fichier hors de l’arbre de travail isolé |
gitCommit |
Autoriser | Créer un commit git |
networkEgress |
Autoriser | Sorties réseau (récupération sur le Web, HTTP arbitraire) |
secretAccess |
Autoriser | Lire un secret ou un justificatif d’authentification |
packageInstall |
Autoriser | Installer un paquet (npm, pip, pub, brew) |
processSpawn |
Autoriser | Lancer un processus (le shell et tout ce qui appelle 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 supposant que le
socle du bac à sable s’applique sous elles. C’est le cas là où l’hôte offre un
backend, mais pas sous Windows ni sur une machine Linux dépourvue de bwrap et
de socat; donc si vous voulez que fileWriteOutsideWorktree ou
packageInstall y soient contrôlés, c’est une règle que vous devez écrire.
L’ensemble est fermé à dessein. Un nouvel outil modificateur qui ne déclare aucune classe échoue au test de cliquet, de sorte que la taxonomie ne peut croître que par une décision explicite et argumentée — « la prolifération de la taxonomie signe 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 hors 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 établit une correspondance
(scope, ActionClass | command prefix) → allow | prompt | deny. Les portées
s’emboîtent de la plus précise à la moins précise :
espace > agent > espace de travail > préréglage du mode > valeur par défaut
La résolution se fait par ordre de spécificité : la première portée qui contient une règle correspondante tranche, et la résolution s’arrête là. Le critère de la règle la plus restrictive ne sert qu’à départager — entre deux règles de même spécificité dans une même portée et lors de la combinaison des quelques classes que déclare une même action. Dans une portée, une règle de commande correspond au préfixe de commande le plus long. Nulle part une autorisation ne l’emporte sur un refus.
Deux décisions offrent des garanties fermes :
- Demandes fermées par défaut. Une décision
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 selon la règle la plus restrictive; lorsque plusieurs classes demandent une approbation, une seule confirmation les énumère toutes.
Il n’existe volontairement aucun verrou par tour. Chaque appel d’outil résout de nouveau la politique à partir de zéro, de sorte que les demandes répétées pour la même action sont bornées par le « se souvenir de cette décision » de l’exploitant plutôt que 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 est un contrôle — une barrière de capacité qui
n’autorise que le verbe est la configuration à l’origine de la plupart des
incidents d’agents publiés.
Une contrainte peut nommer :
- chemins — motifs glob (
repos/**,!**/.env) - références — références git, avec négation par
!(['**', '!main']se lit « toute branche sauf main ») - hôtes — destinations réseau, avec caractères génériques de sous-domaine
(
*.internal) - commandes — 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 fait de garder la grammaire fermée et sans boucle, et ces trois propriétés sont précisément l’objectif : chaque règle se présente 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 peut 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 la poussée vers
main» l’emporte sur « autoriser la poussée » sans que personne ait à réfléchir à l’ordre. - Une règle restrictive (refus / demande) s’applique lorsque la requête touche l’une quelconque des valeurs qu’elle nomme; une règle permissive (autorisation) ne s’applique que lorsque la requête se trouve entièrement à l’intérieur. Interpréter les deux de la même façon permettrait à un agent de blanchir un chemin interdit en le regroupant avec un chemin inoffensif.
- Une règle qui nomme une facette dont la requête ne dit rien n’est ni appliquée ni ignorée : elle est escaladée vers une 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 rejetterait chaque poussée que l’extracteur ne peut 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 et ce qu’elle ne peut pas
Section intitulée “Ce qu’une règle de commande peut intercepter et ce qu’elle ne peut pas”Une règle commandPrefix correspond sur une limite de mot : git push couvre
git push origin main, mais pas git pushx. Elle ne normalise pas le shell.
git push (deux espaces), cd sub && git push et GIT_DIR=… git push sont
toutes des chaînes différentes, et aucune ne correspond à une règle portant sur
git push.
Il s’agit d’une limite bien réelle, et elle est énoncée plutôt que dissimulée :
les règles de commande sont un outil de commodité pour l’exploitant, qui sert à
façonner le comportement ordinaire d’un agent, et non une frontière contre un
agent hostile. Les frontières sont les classes d’effet (qu’un outil déclare et
ne peut pas reformuler), le filet de commandes du mode sous le magasin de
politiques, et le bac à sable du système d’exploitation sous les deux. Une règle
de commande qui se résout en allow n’assouplit jamais ni l’un ni l’autre : le
filet du mode s’exécute ensuite et son deny est définitif.
Approbations permanentes
Section intitulée “Approbations permanentes”Répondre à une demande par « se souvenir de ceci » écrit une véritable règle de
politique : limitée à une portée (espace / agent / espace de travail),
contrainte par ses arguments (approuver une poussée vers feature/login
accorde feature/**, pas main) et à révocation automatique selon un TTL
explicite. Dire oui pour les quelques prochaines heures n’équivaut pas à
réécrire discrètement votre politique permanente, et les règles ainsi écrites
aboutissent 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 :
- indicatif — autoriser, mais consigner que la règle a correspondu. C’est le chemin de l’adoption : déployez d’abord une règle stricte en mode indicatif, consultez la piste 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 — refuser, avec possibilité de passer outre pour quiconque détient l’autorisation de dérogation, moyennant une justification consignée. La dérogation est elle-même un événement audité.
- strict (valeur par défaut) — refuser. Rien ne peut y déroger.
Le palier géré
Section intitulée “Le palier géré”L’exploitant d’une 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 selon la règle la plus restrictive avec la
chaîne propre à chaque espace de travail — elles ne forment pas une portée en
tête de cette chaîne, parce qu’un allow géré placé en tête permettrait à
l’installation de passer outre un refus d’un espace de travail, soit l’inverse de
ce à quoi sert un mécanisme de resserrement. Une règle gérée ne peut donc jamais
que resserrer.
Définir CC_SERVER_MANAGED_POLICY comme un fichier JSON l’emporte entièrement
sur les règles stockées, ce qui permet à un exploitant d’épingler une posture
qu’aucune interface d’administration ne peut renverser — la réponse à « puis-je
empêcher mes développeurs de désactiver les contrôles de sécurité? ».
Le réglage d’autonomie est un profil, pas un système parallèle
Section intitulée “Le réglage d’autonomie est un profil, pas un système parallèle”Le réglage d’autonomie par espace est un profil nommé qui s’applique à ce même
magasin de politiques, et non un second mécanisme. Ses trois réglages sont
stockés et transmis sous les valeurs proposeOnly, actWithApproval et
actFreely (les formes avec traits d’union ne sont que de la prose d’interface,
et autonomy.setForSpace rejette tout le reste). Le laisser non défini équivaut
à actWithApproval.
Voici l’effet de chacun sur une décision résolue :
proposeOnlyrefuse d’emblée tout outil soumis à une règle. L’agent peut toujours raisonner et répondre; il ne peut simplement pas agir, et son message en explique la raison.actWithApproval(et la valeur non définie) correspond à la barrière d’approbation fermée par défaut décrite ci-dessus.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 escaladée vers un approbateur — elle est
autorisée et personne n’est consulté. Seule une règle deny explicite survit au
réglage. actFreely est donc une concession délibérée d’autonomie, et non un
simple réglage de commodité, 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 obligé
delegate_task par les quatre garde-fous : un plafond de profondeur (3 par
défaut), la détection de cycles, un plafond d’autonomie (un délégataire ne
peut jamais agir avec plus d’autonomie que son délégateur — 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). Chaque refus est prononcé sans
ambiguïté, 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 environnements d’exécution 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ù aucune barrière ne peut s’interposer. Plutôt que de prétendre le contraire, chaque adaptateur porte une matrice d’honnêteté : pour chaque adaptateur, on indique 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 le processus
ne sont pas isolés par un bac à sable — la surface d’outils et ce moteur de
politiques constituent la seule frontière de système de fichiers dont il dispose.
Claude Code déclare que ses propres appels d’outils ne sont pas
interceptables, parce qu’il est lancé avec --dangerously-skip-permissions;
Control Center voit ses appels mcp__* et, au moyen d’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, parce que la seule défaillance 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 sous Paramètres → Espace de travail → Autorisations
des agents (/workspaces/<id>/settings/workspace/permissions). Cet écran
contient la matrice de politiques où les règles sont écrites, des modèles de
politique, une sonde « et si ? », la piste 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 montre quelle règle a tranché 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 connexes
Section intitulée “Concepts connexes”- Bac à sable et sécurité : ce qui limite 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é, adhésion et présence : les espaces, les principaux et l’emplacement du réglage d’autonomie
- Configurer les garde-fous : écrire et tester des règles en pratique