Guardrail — una sola policy per ogni azione che modifica lo stato
Gli agenti in Control Center possono eliminare file, fare push di branch, pubblicare pull request e chiamare API esterne. Ognuna di queste è un diverso tipo di rischio, e per molto tempo solo una di esse — i comandi della shell — aveva una policy. I guardrail esistono per rispondere in modo uniforme a una sola domanda, per ogni azione che modifica lo stato e che un agente può compiere, qualunque sia il runtime o lo strumento che la propone: è consentita, richiede un’approvazione o viene negata?
Un motore solo, ogni collo di bottiglia
Sezione intitolata “Un motore solo, ogni collo di bottiglia”Esiste esattamente un motore di policy. Viene consultato in ogni punto in cui un’azione può uscire dal sistema: il registro degli strumenti dell’harness integrato, il cancello del dispatcher MCP lato server e le mutazioni delle operazioni sui repo. Una regola scritta una volta vale quindi sia per il runtime integrato sia per le CLI degli agenti esterni — non esiste un secondo percorso, più silenzioso, che la aggiri. La vecchia policy dei comandi, valida solo per bash, funziona ancora: una regola può corrispondere a un prefisso di comando invece che a una classe di azione, e le due forme convivono nello stesso archivio.
Il motore, però, non sostituisce la sandbox del sistema operativo, e la sandbox
non sostituisce il motore. Rispondono a domande diverse: i guardrail decidono
se una chiamata che Control Center riesce a vedere può avvenire o meno, mentre
la sandbox delimita fin dove può arrivare il processo che ne deriva.
cc_server applica la sandbox dove l’host offre un backend — ma su Windows
non ne esiste alcuno e Linux richiede bwrap e
socat. Su quegli host i
guardrail sono lo strato di applicazione più esterno, non una policy che poggia
su una base: cosa utile da sapere quando decidi quanto essere permissivo.
ActionClass: una tassonomia chiusa di proposito
Sezione intitolata “ActionClass: una tassonomia chiusa di proposito”Ogni strumento che modifica lo stato dichiara a quali ActionClasses appartiene, all’interno di un insieme chiuso di tredici classi di effetto. Cinque richiedono conferma fin da subito; le altre consentono, e solo una regola cambia le cose.
| Classe | Predefinito integrato | Cosa copre |
|---|---|---|
fileDelete |
prompt | Eliminare un file (una scrittura a forma di eliminazione, rm) |
gitPush |
prompt | Fare push verso un remoto git |
prCreate |
prompt | Creare una pull request |
prPublish |
prompt | Pubblicare una revisione, unire una PR |
vendorSyncWrite |
prompt | Scrivere su un fornitore di ticket esterno (Linear, Jira, sincronizzazione GitHub) |
fileWriteOutsideWorktree |
allow | Scrivere un file fuori dal worktree isolato |
gitCommit |
allow | Creare un commit git |
networkEgress |
allow | Traffico di rete in uscita (web fetch, HTTP arbitrario) |
secretAccess |
allow | Leggere un segreto o una credenziale |
packageInstall |
allow | Installare un pacchetto (npm, pip, pub, brew) |
processSpawn |
allow | Avviare un processo (shell e tutto ciò che invoca una shell) |
workspaceMutation |
allow | Modificare la struttura dello spazio di lavoro (repo, spazi, agenti) |
enclosureControl |
allow | Pilotare un recinto (rig): avviare una VM, inviarle input |
Le otto classi consentite per impostazione predefinita sono state scelte
presupponendo che sotto di esse valga la base della sandbox. Vale dove l’host
offre un backend, e non vale su Windows né su una macchina Linux priva di
bwrap e socat — quindi se lì vuoi mettere fileWriteOutsideWorktree o
packageInstall sotto una regola, quella regola devi scriverla.
L’insieme è chiuso di proposito. Un nuovo strumento che modifica lo stato e non dichiara alcuna classe non supera il test a cricchetto, quindi la tassonomia può crescere solo con una decisione esplicita e argomentata — «la proliferazione della tassonomia è la morte di questa funzione». Tredici classi bastano per esprimere le policy che la gente scrive davvero (non fare mai push senza chiedere, non eliminare mai fuori da un worktree, consentire sempre le letture) e sono abbastanza poche da mantenere comprensibile l’interfaccia delle impostazioni.
Regole e risoluzione degli ambiti
Sezione intitolata “Regole e risoluzione degli ambiti”Una regola associa (scope, ActionClass | command prefix) → allow | prompt | deny.
Gli ambiti si annidano dal più specifico al più generico:
spazio > agente > spazio di lavoro > preimpostazione della modalità > predefinito integrato
La risoluzione dà priorità alla specificità: il primo ambito con una regola corrispondente decide, e lì la risoluzione si ferma. La regola più restrittiva è solo uno spareggio — tra due regole ugualmente specifiche dentro uno stesso ambito e quando si combinano le varie classi dichiarate da una singola azione. Dentro un ambito, una regola sui comandi corrisponde al prefisso di comando più lungo. allow non batte deny da nessuna parte.
Due decisioni portano garanzie ferree:
- Prompt chiusi per impostazione predefinita. Un
promptsenza alcun approvatore collegato si risolve in negato. Una domanda senza risposta non è mai un sì. - Combinazione più restrittiva. Un’azione che attraversa più classi le combina nella forma più restrittiva; quando più classi richiedono conferma, un’unica conferma le elenca tutte.
Non esiste di proposito alcun blocco valido per un solo turno. Ogni chiamata a uno strumento risolve di nuovo la policy da zero, quindi le richieste ripetute per la stessa azione sono limitate dal «ricorda questa decisione» dell’operatore, non da qualcosa legato al turno.
Regole a livello di argomenti
Sezione intitolata “Regole a livello di argomenti”Una regola può vincolare gli ARGOMENTI di un’azione, non solo il suo verbo. «Può
fare push» e «può fare push verso feature/*» sono affermazioni diverse, e solo
la seconda è un controllo — un controllo di capacità che autorizza soltanto il
verbo è la forma dietro la maggior parte degli incidenti pubblicati sugli
agenti.
Un vincolo può indicare:
- percorsi — pattern glob (
repos/**,!**/.env) - ref — ref git, con negazione
!(['**', '!main']si legge come «qualsiasi branch tranne main») - host — destinazioni di rete, con wildcard sui sottodomini (
*.internal) - comandi — prefissi di comando, confrontati su un confine di parola
- tetti —
maxCount/maxCents, così «elimina fino a 50 file» è esprimibile
Tre proprietà derivano dal mantenere la grammatica chiusa e senza cicli, e tutte e tre sono il punto: ogni regola si legge come una frase che puoi rileggere, ogni rifiuto può indicare il vincolo che ha corrisposto, e l’intera policy può essere enumerata — puoi vedere cosa un agente può fare prima che venga eseguito.
Tre regole che contano:
- Una regola vincolata è più specifica di una non vincolata nello stesso
ambito, quindi «nega il push verso
main» batte «consenti il push» senza che nessuno debba pensare all’ordine. - Una regola restrittiva (deny / prompt) si applica quando la richiesta tocca qualsiasi valore che essa indica; una permissiva (allow) si applica solo quando la richiesta è interamente al suo interno. Leggere le due allo stesso modo permetterebbe a un agente di riciclare un percorso proibito affiancandogli un percorso innocuo.
- Una regola che indica una dimensione su cui la richiesta non dice nulla non viene né applicata né saltata: si trasforma in un’approvazione. Saltarla in silenzio renderebbe inerte ogni regola sui branch protetti di fronte a uno strumento che non dichiara il proprio ref; negare in silenzio rifiuterebbe ogni push che l’estrattore non riesce a descrivere. Senza un approvatore collegato, la regola preesistente di chiusura predefinita trasforma quell’escalation in un rifiuto.
Cosa può e non può intercettare una regola sui comandi
Sezione intitolata “Cosa può e non può intercettare una regola sui comandi”Una regola commandPrefix corrisponde su un confine di parola: git push
copre git push origin main e non git pushx. Non normalizza la shell.
git push (due spazi), cd sub && git push e GIT_DIR=… git push sono
stringhe diverse e nessuna di esse corrisponde a una regola su git push.
È un limite reale, e viene dichiarato invece che mascherato: le regole sui
comandi sono una comodità per l’operatore che vuole modellare il comportamento
ordinario di un agente, non un confine contro un agente ostile. I confini
sono le classi di effetto (che uno strumento dichiara e non può riformulare),
la rete di comandi della modalità sotto l’archivio delle policy e la sandbox
del sistema operativo sotto entrambi. Una regola sui comandi che si risolve in
allow non allenta nessuno dei due — la rete della modalità viene eseguita
dopo e il suo deny è definitivo.
Approvazioni permanenti
Sezione intitolata “Approvazioni permanenti”Rispondere a un prompt con «ricorda questa decisione» scrive una vera regola di
policy: con ambito (spazio / agente / spazio di lavoro), vincolata agli
argomenti (approvare un push verso feature/login concede feature/**, non
main) e auto-revocante dopo un TTL esplicito. Dire sì per le prossime ore
non è la stessa cosa che riscrivere in silenzio la tua policy permanente, e le
regole così scritte finiscono nello stesso archivio con provenienza
remembered e una scadenza, quindi possono essere revocate in anticipo.
Livelli di applicazione
Sezione intitolata “Livelli di applicazione”Ogni regola ne porta uno:
- advisory — consente, ma registra che la regola ha corrisposto. È il percorso di adozione: introduci una regola severa in modalità advisory, leggi il registro di audit per una settimana per vedere esattamente cosa avrebbe bloccato, poi promuovila. Senza questo livello, le policy severe non vengono mai attivate.
- soft — nega, ma è sovrascrivibile da chi ha il permesso di sovrascrittura, con una giustificazione registrata. La sovrascrittura è essa stessa un evento sottoposto ad audit.
- hard (il valore predefinito) — nega. Nulla la sovrascrive.
Il livello gestito
Sezione intitolata “Il livello gestito”Chi gestisce un’installazione può fissare policy che nessun amministratore di
spazio di lavoro può allentare. Le regole gestite risiedono sul lato server e
vengono unite nella forma più restrittiva alla catena di ogni spazio di
lavoro — non sono un ambito in cima a quella catena, perché un allow gestito
in testa alla catena permetterebbe all’installazione di sovrascrivere un deny di
uno spazio di lavoro, l’opposto di ciò a cui serve un limite. Una regola gestita
può quindi solo irrigidire.
Impostare CC_SERVER_MANAGED_POLICY su un file JSON prevale del tutto sulle
regole archiviate, ed è ciò che permette a un operatore di fissare un
atteggiamento che nessuna interfaccia di amministrazione può ribaltare — la
risposta a «posso impedire ai miei sviluppatori di disattivare i controlli di
sicurezza?».
Il selettore dell’autonomia è un profilo, non un sistema parallelo
Sezione intitolata “Il selettore dell’autonomia è un profilo, non un sistema parallelo”Il selettore dell’autonomia per spazio è un profilo con un nome sopra questo
stesso archivio delle policy, non un secondo meccanismo. Le sue tre impostazioni
vengono archiviate e inviate come proposeOnly, actWithApproval e actFreely
(le forme con il trattino sono solo prosa dell’interfaccia e
autonomy.setForSpace rifiuta qualsiasi altro valore). Se non viene impostato,
si comporta come actWithApproval.
Che effetto ha ciascuna impostazione su una decisione risolta:
proposeOnlynega senz’altro ogni strumento soggetto a controllo. L’agente può ancora ragionare e rispondere; semplicemente non può agire, e il suo messaggio spiega perché.actWithApproval(e non impostato) è il cancello di approvazione a chiusura predefinita descritto sopra.actFreelypre-approva tutto ciò che non si è risolto in undenynetto.
Quest’ultima merita di essere detta chiaramente, senza ammorbidirla: con
actFreely una decisione prompt non viene inoltrata a un approvatore — è
consentita e nessuno viene interpellato. Solo una regola deny esplicita
sopravvive al selettore. Quindi actFreely è una concessione deliberata di
autonomia, non un’impostazione di comodo, e la regola di chiusura predefinita
protegge esattamente il caso in cui conta (actWithApproval, il valore
predefinito).
La delega tra agenti è sorvegliata nel punto di controllo delegate_task da
tutte e quattro le guardie: un tetto di profondità (3 per impostazione
predefinita), il rilevamento dei cicli, un tetto di autonomia (un delegato
non può mai agire con più autonomia del suo delegante — il privilegio non si
ricicla affidando il lavoro a un agente più libero) e un perimetro di budget
(la delega addebita il budget residuo del delegante e non può crearne altro).
Ognuna viene rifiutata a voce alta, con il motivo della guardia restituito
all’agente parola per parola.
La matrice di onestà degli adapter
Sezione intitolata “La matrice di onestà degli adapter”Non tutti i runtime permettono a Control Center di intercettare ogni azione. Le CLI degli agenti esterni eseguono alcuni strumenti in modo nativo, nel processo, dove non può esserci alcun controllo. Anziché fingere il contrario, ogni adapter porta con sé una matrice di onestà: per ogni adapter, se Control Center filtra la superficie degli strumenti, intercetta le chiamate agli strumenti, osserva il contratto di completamento, riesce a vedere gli strumenti nativi dell’esecutore e se gli strumenti nel processo sono coperti da un profilo sandbox.
Due voci meritano una lettura prima che ti fidi di una configurazione. L’harness
integrato dichiara che i suoi strumenti per i file nel processo non sono
isolati nella sandbox — la superficie degli strumenti e questo motore di policy
sono l’unico confine del filesystem che ha. Claude Code dichiara che le sue
stesse chiamate agli strumenti non sono intercettabili, perché viene
avviato con --dangerously-skip-permissions; Control Center vede le sue chiamate mcp__* e, tramite un hook, le sue righe di comando Bash, mentre i suoi strumenti di lettura, scrittura e modifica vengono eseguiti senza essere visti.
La schermata delle impostazioni mostra questa matrice, perché l’unico fallimento imperdonabile per un sistema di guardrail è dichiarare una copertura che non esiste.
Sondare la policy prima che morda
Sezione intitolata “Sondare la policy prima che morda”I guardrail si trovano in Impostazioni → Spazio di lavoro → Autorizzazioni
degli agenti (/workspaces/<id>/settings/workspace/permissions). La schermata
contiene la matrice delle policy in cui si scrivono le regole, i modelli di
policy, una sonda del tipo «E se?», il registro di controllo delle
autorizzazioni e la matrice di onestà degli adapter.
La sonda accetta una classe di azione (o un comando) e un ambito e mostra quale regola ha deciso e perché. Poiché la risoluzione è pura e deterministica — stessa azione, stesso ambito, stessa decisione — la risposta della sonda è la risposta che riceverà l’agente.
Concetti correlati
Sezione intitolata “Concetti correlati”- Sandbox e sicurezza: cosa vincola davvero l’esecuzione di un agente e fin dove arriva la base del sistema operativo sotto questo motore
- Multigiocatore e presenza: spazi, identità e dove si trova il selettore dell’autonomia
- Configura i guardrail: scrivere e provare le regole nella pratica