Zum Inhalt springen

Schutzregeln — eine Richtlinie für jede verändernde Aktion

Agenten in Control Center können Dateien löschen, Branches pushen, Pull Requests veröffentlichen und externe APIs aufrufen. Jede davon ist eine andere Art von Risiko, und lange hatte nur eine eine Richtlinie: die Shell-Befehle. Die Schutzregeln beantworten eine Frage einheitlich, für jede verändernde Aktion, die ein Agent ausführen kann, egal welche Laufzeit oder welches Werkzeug sie vorschlägt: ist das erlaubt, braucht es eine Freigabe, oder wird es abgelehnt?

Es gibt genau eine Policy-Engine. Sie wird an jeder Stelle gefragt, an der eine Aktion das System verlassen kann: die Werkzeugregistrierung des eingebauten Harness, das serverseitige Tor des MCP-Dispatchers und Mutationen der Repo-Operationen. Eine einmal geschriebene Regel gilt deshalb für die eingebaute Laufzeit und für externe Agenten-CLIs gleichermaßen — es gibt keinen zweiten, stilleren Weg daran vorbei. Die ältere, nur für Bash geltende Befehlsrichtlinie funktioniert weiter: Eine Regel kann einen Befehlspräfix treffen statt einer Aktionsklasse, und beide Formen liegen im selben Speicher.

Die Engine ersetzt die Betriebssystem-Sandbox nicht, und die Sandbox ersetzt sie nicht. Sie beantworten verschiedene Fragen. Die Schutzregeln entscheiden, ob ein Aufruf, den Control Center sehen kann, überhaupt stattfinden darf. Die Sandbox begrenzt, wohin der entstehende Prozess gelangen darf. cc_server legt die Sandbox an, wo der Host ein Backend anbietet — Windows bietet keines, und Linux braucht bwrap und socat. Auf diesen Hosts sind die Schutzregeln die äußerste Durchsetzungsschicht, nicht eine Richtlinie, die auf einer Untergrenze liegt. Das solltest du wissen, wenn du entscheidest, wie großzügig du sein willst.

Jedes verändernde Werkzeug deklariert, zu welchen ActionClasses es gehört, aus einer geschlossenen Menge von dreizehn Effektklassen. Fünf davon fragen von Haus aus nach. Der Rest lässt zu, und eine Regel ändert das.

Klasse Eingebauter Standard Was sie abdeckt
fileDelete prompt Eine Datei löschen (ein löschendes Schreiben, rm)
gitPush prompt Auf ein Git-Remote pushen
prCreate prompt Einen Pull Request anlegen
prPublish prompt Eine Review veröffentlichen, einen PR mergen
vendorSyncWrite prompt In einen externen Ticket-Anbieter schreiben (Linear, Jira, GitHub-Sync)
fileWriteOutsideWorktree allow Eine Datei außerhalb des isolierten Worktrees schreiben
gitCommit allow Einen Git-Commit erstellen
networkEgress allow Auf das Netzwerk zugreifen (Web-Abruf, beliebiges HTTP)
secretAccess allow Ein Geheimnis oder Zugangsdaten lesen
packageInstall allow Ein Paket installieren (npm, pip, pub, brew)
processSpawn allow Einen Prozess starten (Shell und alles, was eine Shell aufruft)
workspaceMutation allow Die Struktur des Arbeitsbereichs ändern (Repos, Bereiche, Agenten)
enclosureControl allow Eine Kapsel (Rig) steuern: eine VM starten, ihr Eingaben schicken

Die acht Klassen mit Standard allow wurden unter der Annahme gewählt, dass die Sandbox-Untergrenze unter ihnen greift. Das tut sie, wo der Host ein Backend anbietet, und das tut sie nicht unter Windows oder auf einem Linux-Rechner ohne bwrap und socat. Wenn du fileWriteOutsideWorktree oder packageInstall dort unter eine Regel stellen willst, musst du sie selbst schreiben.

Die Menge ist absichtlich geschlossen. Ein neues veränderndes Werkzeug, das keine Klasse deklariert, fällt durch den Ratchet-Test. Die Taxonomie wächst deshalb nur durch eine ausdrückliche, begründete Entscheidung — „Wildwuchs in der Taxonomie ist der Tod dieses Features.“ Dreizehn Klassen reichen für die Richtlinien, die Leute tatsächlich schreiben (nie ohne Nachfrage pushen, nie außerhalb eines Worktrees löschen, Lesen immer zulassen), und sie sind wenige genug, dass die Einstellungsoberfläche verständlich bleibt.

Eine Regel bildet (scope, ActionClass | command prefix) → allow | prompt | deny ab. Die Geltungsbereiche schachteln sich vom engsten zum weitesten:

Bereich > Agent > Arbeitsbereich > Modus-Voreinstellung > Standardwert

Die Auflösung geht zuerst nach Spezifität: Der erste Geltungsbereich mit einer passenden Regel entscheidet, und dort endet sie. Die strengste Regel ist nur der Stichentscheid — zwischen zwei gleich spezifischen Regeln in einem Geltungsbereich und beim Zusammenführen der mehreren Klassen, die eine einzelne Aktion deklariert. Innerhalb eines Geltungsbereichs trifft eine Befehlsregel auf den längsten Befehlspräfix. allow schlägt deny nirgends.

Zwei Entscheidungen tragen harte Garantien:

  • Fail-closed bei Nachfragen. Ein prompt ohne verbundene freigebende Person wird abgelehnt. Eine unbeantwortete Frage ist nie ein Ja.
  • Strengste Kombination. Eine Aktion über mehrere Klassen verbindet sie auf die strengste Weise. Fragen mehrere Klassen nach, listet eine Bestätigung sie alle.

Es gibt absichtlich keinen Merker pro Turn. Jeder Werkzeugaufruf löst die Richtlinie neu auf. Wiederholtes Nachfragen für dieselbe Aktion begrenzt nur das eigene „Für 8 Stunden freigeben“ der betreibenden Person, nichts, das an den Turn gebunden ist.

Eine Regel kann die Argumente einer Aktion einschränken, nicht nur ihr Verb. „Darf pushen“ und „darf nach feature/* pushen“ sind verschiedene Aussagen, und nur die zweite ist eine Kontrolle. Ein Fähigkeitstor, das nur das Verb freigibt, ist die Form hinter den meisten veröffentlichten Agenten-Vorfällen.

Eine Einschränkung kann benennen:

  • Pfade — Glob-Muster (repos/**, !**/.env)
  • Refs — Git-Refs, mit Negation durch ! (['**', '!main'] liest sich als „jeder Branch außer main“)
  • Hosts — Netzziele, mit Platzhaltern für Subdomains (*.internal)
  • Befehle — Befehlspräfixe, an einer Wortgrenze
  • Obergrenzen — maxCount / maxCents, damit „bis zu 50 Dateien löschen“ ausdrückbar ist

Drei Eigenschaften folgen daraus, dass die Grammatik geschlossen und schleifenfrei bleibt, und alle drei sind der Sinn: Jede Regel lässt sich als Satz zurücklesen, jede Ablehnung kann die Bedingung nennen, die gegriffen hat, und die ganze Richtlinie lässt sich aufzählen — du siehst, was ein Agent tun darf, bevor er läuft.

Drei Regeln, auf die es ankommt:

  • Eine eingeschränkte Regel ist spezifischer als eine uneingeschränkte im selben Geltungsbereich, also schlägt „Push nach main verweigern“ ein „Push zulassen“, ohne dass jemand über die Reihenfolge nachdenkt.
  • Eine restriktive Regel (deny / prompt) gilt, wenn die Anfrage irgendeinen Wert berührt, den sie nennt. Eine permissive (allow) gilt nur, wenn die Anfrage ganz darin liegt. Beide gleich zu lesen ließe einen Agenten einen verbotenen Pfad einschmuggeln, indem er einen harmlosen daneben packt.
  • Eine Regel, die ein Merkmal nennt, zu dem die Anfrage nichts sagt, wird weder angewendet noch übersprungen: sie eskaliert zu einer Freigabe. Still überspringen würde jede Regel für geschützte Branches wirkungslos machen gegen ein Werkzeug, das seinen Ref nicht meldet. Still verweigern würde jeden Push ablehnen, den der Extraktor nicht beschreiben kann. Ohne verbundene freigebende Person macht die bestehende Fail-closed-Regel aus dieser Eskalation eine Ablehnung.

Eine commandPrefix-Regel trifft an einer Wortgrenze: git push deckt git push origin main ab und nicht git pushx. Sie normalisiert die Shell nicht. git push (zwei Leerzeichen), cd sub && git push und GIT_DIR=… git push sind alles verschiedene Zeichenketten, und keine davon trifft eine Regel über git push.

Das ist eine echte Grenze, und sie wird ausgesprochen, nicht übertüncht. Befehlsregeln sind eine Erleichterung für den Betreiber, um gewöhnliches Agentenverhalten zu formen, keine Grenze gegen ein gegnerisches. Die Grenzen sind die Effektklassen (die ein Werkzeug deklariert und nicht umformulieren kann), das Befehlsnetz des Modus unter dem Richtlinienspeicher und darunter die Betriebssystem-Sandbox. Eine Befehlsregel, die auf allow auflöst, lockert keine von beiden — das Netz des Modus läuft danach, und sein deny ist endgültig.

Eine Nachfrage mit „Für 8 Stunden freigeben“ zu beantworten schreibt eine echte Richtlinienregel: im Geltungsbereich (Bereich / Agent / Arbeitsbereich), an die Argumente gebunden (die Freigabe eines Pushs nach feature/login gewährt feature/**, nicht main) und selbst aufhebend nach einer ausdrücklichen TTL. Für die nächsten Stunden ja zu sagen ist nicht dasselbe, wie still deine dauerhafte Richtlinie umzuschreiben. Die Regeln landen im selben Speicher mit der Herkunft remembered und einem Ablauf, sodass du sie früher widerrufen kannst.

Jede Regel trägt eine:

  • advisory — zulassen, aber festhalten, dass die Regel gegriffen hat. Das ist der Weg zur Einführung: eine strenge Regel zuerst im Modus advisory ausrollen, eine Woche das Audit-Protokoll lesen und genau sehen, was sie blockiert hätte, und sie dann scharf schalten. Ohne diese Stufe werden strenge Richtlinien nie eingeschaltet.
  • soft — verweigern, überschreibbar von jemandem mit der Override-Berechtigung, mit festgehaltener Begründung. Die Überschreibung ist selbst ein geprüfter Vorgang.
  • hard (der Standard) — verweigern. Nichts überschreibt das.

Wer die Installation betreibt, kann eine Richtlinie festnageln, die kein Arbeitsbereichs-Admin lockern kann. Verwaltete Regeln liegen auf dem Server und werden auf die strengste Weise mit der eigenen Kette jedes Arbeitsbereichs zusammengeführt — sie sind kein Geltungsbereich an deren Spitze, denn ein verwaltetes allow an der Spitze ließe die Installation ein deny des Arbeitsbereichs überschreiben, das Gegenteil dessen, wozu eine Klammer da ist. Eine verwaltete Regel kann deshalb nur verschärfen.

CC_SERVER_MANAGED_POLICY auf eine JSON-Datei zu setzen überstimmt die gespeicherten Regeln ganz. Damit kann ein Betreiber eine Haltung festnageln, die keine Admin-Oberfläche umlegen kann — die Antwort auf „Kann ich verhindern, dass meine Entwickler die Sicherheitskontrollen abschalten?“.

Der Autonomieregler ist ein Profil, kein zweites System

Abschnitt betitelt „Der Autonomieregler ist ein Profil, kein zweites System“

Der Autonomieregler pro Bereich ist ein benanntes Profil über demselben Richtlinienspeicher, kein zweiter Mechanismus. Seine drei Einstellungen werden gespeichert und gesendet als proposeOnly, actWithApproval und actFreely (die Formen mit Bindestrich sind nur Prosa der Oberfläche, und autonomy.setForSpace lehnt alles andere ab). Ungesetzt verhält er sich wie actWithApproval.

Was jede mit einer aufgelösten Entscheidung macht:

  • proposeOnly lehnt jedes durch das Tor laufende Werkzeug sofort ab. Der Agent kann weiter nachdenken und antworten. Handeln kann er nicht, und seine Nachricht sagt, warum.
  • actWithApproval (und ungesetzt) ist das Fail-closed-Freigabetor von oben.
  • actFreely gibt im Voraus frei, was nicht auf ein hartes deny aufgelöst wurde.

Das letzte verdient eine klare Aussage, ohne es abzumildern: Unter actFreely wird eine prompt-Entscheidung nicht an eine freigebende Person eskaliert — sie wird zugelassen, und niemand wird gefragt. Nur eine ausdrückliche deny-Regel übersteht den Regler. actFreely ist deshalb eine bewusste Autonomievergabe, keine Bequemlichkeitseinstellung, und die Fail-closed-Regel schützt genau den Fall, in dem es darauf ankommt (actWithApproval, der Standard).

Die Delegation zwischen Agenten wird am Engpass delegate_task von allen vier Wächtern bewacht: eine Tiefengrenze (Standard 3), Zykluserkennung, eine Autonomie-Obergrenze (ein Delegat kann nie mit mehr Autonomie handeln als sein Auftraggeber — Privilegien lassen sich nicht waschen, indem die Arbeit an einen freieren Agenten geht) und ein Budgetrahmen (die Delegation belastet das verbleibende Budget des Auftraggebers und kann keines hinzuerfinden). Jede wird laut abgelehnt, und der Grund des Wächters geht wortgetreu an den Agenten zurück.

Nicht jede Laufzeit lässt Control Center jede Aktion abfangen. Externe Agenten-CLIs führen manche Werkzeuge nativ aus, prozessintern, wo kein Tor sitzen kann. Statt etwas anderes zu behaupten, trägt jeder Adapter eine Ehrlichkeitsmatrix: je Adapter, ob Control Center die Werkzeugfläche filtert, Werkzeugaufrufe abfängt, den Abschlussvertrag beobachtet, die nativen Werkzeuge des Runners sehen kann und ob prozessinterne Werkzeuge von einem Sandbox-Profil gedeckt sind.

Zwei Einträge solltest du lesen, bevor du einer Konfiguration vertraust. Der eingebaute Harness erklärt, dass seine prozessinternen Dateiwerkzeuge nicht in der Sandbox laufen — die Werkzeugfläche und diese Policy-Engine sind seine einzige Dateisystemgrenze. Claude Code erklärt, dass seine eigenen Werkzeugaufrufe nicht abfangbar sind, weil es mit --dangerously-skip-permissions gestartet wird. Control Center sieht seine mcp__*-Aufrufe und, über einen Hook, seine Bash-Befehlszeilen, während seine eigenen Werkzeuge zum Lesen, Schreiben und Bearbeiten ungesehen laufen.

Der Einstellungsbildschirm zeigt diese Matrix, denn der eine unverzeihliche Fehler eines Schutzregelsystems ist, Abdeckung zu behaupten, die es nicht gibt.

Die Schutzregeln liegen unter Einstellungen → Arbeitsbereich → Agent-Berechtigungen (/workspaces/<id>/settings/workspace/permissions). Der Bildschirm hat die Richtlinienmatrix, in der Regeln geschrieben werden, die Richtlinienvorlagen, die Prüfung „Was wäre wenn?“, das Audit-Protokoll der Berechtigungen und „Wo Regeln durchgesetzt werden“, die Ehrlichkeitsmatrix der Adapter.

Die Prüfung nimmt eine Aktionsklasse (oder einen Befehl) und einen Geltungsbereich und zeigt, welche Regel entschieden hat und warum. Weil die Auflösung rein und bestimmt ist — dieselbe Aktion, derselbe Geltungsbereich, dieselbe Entscheidung — ist die Antwort der Prüfung die Antwort, die der Agent bekommt.