Sandbox a zabezpečení
Proč tu na izolaci záleží
Sekce “Proč tu na izolaci záleží”Agent čte soubory, spouští příkazy shellu a volá externí API za tebe. Selhání, na kterém záleží, málokdy je zlý úmysl. Je to agent, který špatně přečte cestu a přepíše tvůj pracovní checkout, nebo který odešle větev, kterou jsi ještě neměl zkontrolovanou. Otázka, na kterou produkt musí odpovědět, tedy není „je agent důvěryhodný“, ale „jaký je dosah, když se splete“.
Control Center na to odpovídá vrstvami a vrstvy jsou nezávislé schválně. Když jedna chybí, ostatní pořád drží. Na tom záleží, protože vnější vrstva, sandbox operačního systému, je jediná podmíněná: záleží na tom, jestli hostitel backend nabídne, a na Windows ho nenabídne žádný.
Co agenta skutečně omezuje
Sekce “Co agenta skutečně omezuje”Pět věcí ohraničuje běh agenta na každém hostiteli, se sandboxem i bez něj. Žádná není hranice jádra a všechny jsou skutečné. Kde hostitel nabídne backend, sedí nad nimi sandbox operačního systému a „Co sandbox přidává a kde končí“ níže popisuje, co se tím změní.
Vlastní copy-on-write worktree. Každá konverzace si založí vlastní checkout
každého propojeného repozitáře, klonovaný copy-on-write přes přibalené nativní
rift, ne kopírovaný bajt po bajtu, takže izolace je dost levná na to, aby
byla výchozí. Registrovaný repozitář, který jsi přidal do pracovního prostoru,
není adresář, ve kterém agent pracuje. Dvě konverzace nad stejným repozitářem
si navzájem nevidí úpravy a ani jedna neupravuje tvůj checkout.
Rozlišení stojí za přesnost: worktree je na konverzaci, ne na agenta. Dva
agenti v jedné konverzaci dostanou odlišné overlay pracovní adresáře, které
sdílejí repos/ té konverzace. O to jde, spolupracují na jedné změně,
zatímco jejich soukromé adresáře agentů zůstanou oddělené. Copy-on-write je
jediný backend všude, kde se dodává rift. Když souborový systém neumí
reflink, nebo když datový adresář leží na jiném svazku než repozitář,
provisioning selže, místo aby spadl na náhradní cestu. Windows je výjimka:
copy-on-write backend tam není, takže backendem je git worktree, a nejde
o tiché zhoršení.
Omezení cest v souborových nástrojích vestavěného harnessu. Nástroje
harnessu read, write, edit, apply_patch, search, find a
search_files rozřeší každou cestu vůči pracovnímu adresáři běhu a vůči
sdíleným kořenům, adresáři repos/ konverzace, kde leží worktree, a adresáři
příloh prostoru, když existuje, a odmítnou všechno, co skončí mimo. Absolutní
cesta projde, jen když už uvnitř byla. Symlink uvnitř worktree, který z něj
ukazuje ven, se rozřeší a taky odmítne. Proto agent neumí write do ~/.ssh,
ani když tu žádný sandbox není.
Plocha nástrojů režimu. Režim konverzace
rozhoduje, které nástroje se pro běh vůbec sestaví. V režimech jen pro čtení
(plan, review, orchestrate) mutující nástroje v registru prostě nejsou
a politika příkazů shellu v těchto režimech každý mutující příkaz rovnou
zamítne, git commit, git push, npm install, docker a zbytek, a neptá
se na ně. Nástroj, který tam není, se zavolat nedá, a to je silnější záruka
než nástroj, který tam je a jen se hlídá.
Sjednocené guardraily akcí. Každý mutující nástroj deklaruje třídy efektů,
které umí způsobit, a motor politik každou vyhodnotí na allow, prompt nebo
deny, než se volání spustí. prompt bez připojeného schvalovatele se
vyhodnotí jako denied: otázka, na kterou nikdo nemůže odpovědět, není nikdy
ano. Viz Guardraily pro model
rozhodování.
Pověření od brokera a očištěné prostředí. Pověření se vystaví při každém spuštění a odeberou se, když běh skončí, a token GitHub, který běh drží, umí číst, ale ne pushovat — viz „Push jde přes Control Center“ níže. ACP, bash harnessu a Claude Code pod nativním obalem dostanou
prostředí očištěné od vektorů injekce dynamického linkeru a interpretu
(LD_PRELOAD, DYLD_INSERT_LIBRARIES, NODE_OPTIONS, GIT_SSH_COMMAND
a příbuzné), než se proces spustí. Claude Code přes NoSandboxAdapter dědí
prostředí hostitele.
Kde ty hranice řídnou
Sekce “Kde ty hranice řídnou”Souborové nástroje harnessu běží v procesu serveru, ne v podřízeném procesu,
takže by je neomezil žádný profil sandboxu, ani kdyby k nim byl připojený.
Sandboxovaným runnerem příkazů projde jen bash. Jejich omezení je kontrola
cest popsaná výš a ta kontrola je proto nosná, ne druhá linie obrany.
U nástroje bash je třeba být stejně přesný. Jeho příkazy se vyhodnotí proti
politice příkazů režimu a pak se spustí s očištěným prostředím a s worktree
jako pracovním adresářem. Kde backend je, ten start se obalí, takže zápis
příkazu shellu mimo worktree zastaví sandbox. Kde není, na Windows nebo na
Linuxu bez bwrap a socat, je politika příkazů jediné, co stojí mezi
příkazem a zbytkem disku. V režimu chat politika natvrdo zamítá pevný seznam
(eskalace oprávnění, destrukce systému a disku, únik z kontejneru a jmenného
prostoru) a u změn vzdáleného stavu se ptá (git push, gh pr create,
publikace a instalace balíčků). Co není na žádném ze seznamů, běží. Roury,
řetězy a subshelly se rozloží a každý dílčí příkaz se vyhodnotí zvlášť.
Vyhraje nejpřísnější rozhodnutí.
Claude Code použitý jako adaptér je případ, kde sandbox nese největší váhu.
Control Center ho spouští s --dangerously-skip-permissions, protože
neinteraktivní claude -p by jinak navždy čekalo na vlastní výzvu ke
schválení. Jeho čtení, zápis a úpravy probíhají v jeho vlastním procesu a Control Center je nikdy nevidí. Jeho volání Bash jdou před spuštěním na hook na serveru, který zařadí příkazový řádek a zeptá se odpovídajícího pravidla, a nástroje mcp__*, které obsluhuje Control Center, procházejí bránou jako obvykle. Kde backend je, ta neviděná
volání pořád probíhají uvnitř obalu sandboxu, takže hranicí kolem nich je
operační systém. Kde není, není tam nic. Každý adaptér to uvádí ve své matici
vynucení. Viz matice upřímnosti
adaptéru.
Push jde přes Control Center
Sekce “Push jde přes Control Center”Příznaky oprávnění pro jednotlivé agenty neexistují. Jestli agent smí vytvořit commit, pushovat, otevřít pull request, zapisovat do trackeru nebo sahat na síť, rozhodují guardraily — povolit, nejdřív se zeptat nebo zakázat — a stejná pravidla platí bez ohledu na to, který adaptér agenta spouští.
Push je akce, která musí vydržet i proti agentovi, který se snaží pravidlo
obejít, takže se vynucuje tím, co agent drží, ne tím, co spouští. S
nakonfigurovanou GitHub App dostane běh ve worktree GitHubu instalační token
vázaný na repozitář, který umí číst obsah a pracovat s pull requesty, ale
neumí pushovat. Konfigurace gitu běhu přepíše každou URL pro push na GitHub
(https://github.com/, git@github.com:, ssh://git@github.com/) na bránu
běhů agentů, loopback endpoint na cc_server. Brána přečte, které refy push
aktualizuje, zeptá se pravidla Odeslat na remote — takže platí i pravidlo
omezené na větve, třeba „zakázat push na main“ — a teprve pak push předá na
GitHub se zapisovacím tokenem, který si pro ten účel vystaví a agentovi ho
nikdy nedá. Odmítnutý push se ukáže přímo ve výstupu gitu:
! [remote rejected] main -> main (Control Center policy: …)Brána předává push jen do vlastního repozitáře worktree nebo do repozitáře na GitHubu propojeného s pracovním prostorem. Fetch jde přímo na GitHub se čtecím tokenem.
Ostatní příkazy shellu narazí na měkčí bránu. Nástroj bash harnessu a přes
hook i nástroj Bash v Claude Code zařadí každý příkazový řádek a zeptají se
pravidla, pod které spadá: git commit, merge, rebase, cherry-pick,
revert a am jsou Vytvořit commit; gh pr create je Otevřít pull
request; gh pr merge, review, comment a close jsou Zveřejnit
kontrolu nebo sloučení; gh issue create, edit, comment a close jsou
Zápis do externího trackeru; instalace balíčků jsou Nainstalovat
balíček; curl a wget jsou Přístup k síti. Pozná to běžný zápis akce
a agent odhodlaný ji schovat (eval, soubor se skriptem, přímé volání API) to
dokáže. Push na tom nezávisí.
Do sandboxu se nevkládá žádný API klíč ticketingu. Agenti zapisují tickety přes nástroje MCP v Control Center, které se ptají pravidla Zápis do externího trackeru.
Pravidlo Přístup k síti se přečte jednou, při startu běhu. Síť sandboxu je
buď zapnutá, nebo vypnutá, takže zakázat ji vypne, zatímco povolit a nejdřív se
zeptat ji nechají zapnutou; nástroje harnessu web_fetch a web_search se
pořád ptají při každém volání. Při úklidu běhu se pověření odeberou spolu s
každým zapisovacím tokenem, který brána vystavila, takže získaný údaj běh
nepřežije.
Co sandbox přidává a kde končí
Sekce “Co sandbox přidává a kde končí”Enum SandboxBackend má tři hodnoty: native (Seatbelt na macOS, bubblewrap
na Linuxu a na WSL2), none a microvm. Obal příkazů agenta používá jen
první dvě. microvm je backend uzavřeného virtuálního stroje pro interaktivní
terminály a stanice, ne tiché povýšení obalu bash. Tvar nativního backendu
vysvětluje, co získáš tam, kde je připojený, a co ti nikdy dát neměl.
cc_server hostitele při startu jednou osondá a kde backend odpoví, napojí
oba švy cesty odeslání, protože transporty jeden nesdílejí. První
(SandboxPort) obalí CLI Claude Code. Druhý (SandboxManager) obalí adaptéry
ACP a nástroj bash vestavěného harnessu. Napojit jen jeden by nechal ostatní
startovat bez obalu, a přesně to se dřív dělo. Na hostiteli bez backendu, nebo
pod --sandbox off, startují všechny bez obalu a server na startovním řádku
řekne, ve kterém případě jsi. ACP a bash harnessu prostředí pořád čistí.
Claude Code přes NoSandboxAdapter dědí prostředí hostitele.
Jedna plocha se záměrně vynechává. Terminál hostovaný na serveru bere argument
backendu pro každou relaci a cc_server ho sestaví s výchozím shellem
hostitele, takže terminál, který z aplikace otevřeš, běží bez sandboxu, dokud
klient výslovně neuvede native. Je to skutečný shell na hostiteli serveru,
ne běh agenta.
Na Linuxu bubblewrap postaví jmenný prostor připojení, takže agent opravdu
vidí jen to, co se do něj navázalo. Na macOS sandbox-exec aplikuje profil
Seatbelt, který je ve výchozím stavu permisivní. Profil, který ve výchozím
stavu všechno zakáže, udělá interaktivní shell nepoužitelný, protože vypsat
všechna volání dyld, XPC a Mach je nepraktické. Profil na macOS proto vychází
z (allow default) a vykrajuje zákazy: čtení tajných cest, politiku zápisu
vrácenou na zákaz s výslovnými povoleními nad ní, blokování unlink na každé
zakázané cestě a jejích předcích, aby přejmenování neobešlo zákaz zápisu,
zákazy exec pro binárky, které jsou vždy nebezpečné, a pro cokoli zkopírované
do zapisovatelného adresáře, a síť omezenou na porty loopback proxy plus DNS.
Praktický důsledek: na Linuxu je pohled agenta na souborový systém zúžený, na macOS agent pořád může číst většinu hostitele a tvoje registrované checkouty chrání výslovné zákazy zápisu a přejmenování, ne neviditelnost. Obojí je izolace na úrovni jmenného prostoru, ne bezpečnostní hranice jádra. Backendy to samy říkají ve svých poznámkách ke schopnostem.
Sada bind mountů je místo, kudy vede hranice mezi agenty. Overlay odeslání
(Claude Code a ACP) připojí až čtyři cesty, rozřešené pro každý běh: overlay
pracovní adresář agenta pro čtení i zápis, konfigurační adresář agenta jen pro
čtení, sdílený adresář repos/ konverzace pro čtení i zápis, když existuje,
a adresář příloh prostoru jen pro čtení, když existuje. Adresář sousedního
agenta se nikdy nepřipojí. Obal bash harnessu je užší: bind mountuje jen
pracovní adresář běhu. Stejný tvar v softwaru vynucuje kontrola cest harnessu
v procesu, takže se shodují. Jen kontrola cest ale pokrývá vlastní souborové
nástroje harnessu, které se k jmennému prostoru připojení nikdy nedostanou.
Tvoje registrované checkouty se nad to přidají do sady zákazů zápisu, v každém
režimu a na všech třech obalených cestách (Claude Code, ACP, bash harnessu).
Každé pravidlo se vypíše v doslovném zápisu i v zápisu po rozřešení symlinku.
Druhý zápis není ozdoba. Jádro porovnává zákaz s rozřešenou cestou a macOS
dělá z rozřešení běžný případ, ne výjimku: /tmp je ve skutečnosti
/private/tmp a /var/folders/… je ve skutečnosti /private/var/folders/….
Checkout dosažený kterýmkoli zápisem by šel zapisovat, a profil by přitom
vypadal, že to zakazuje.
Síť v sandboxu je seznam povolených domén pro každou relaci a vynucují ho
loopback proxy v procesu. Odchozí provoz je ve výchozím stavu zakázaný. Když
je síť vypnutá, proxy se pořád spustí, ale seznam povolených je prázdný, takže
se odmítne každé odchozí spojení. Když je zapnutá, resolver sestaví seznam
povolených z vybraného základu (poskytovatelé LLM API, hosting gitu, registry
balíčků, katalog modelů) a z domén GitHubu a porovná s ním cílového hostitele
každého spojení. Zástupné znaky fungují (*.example.com odpovídá subdoménám,
ne apexu). Samostatný seznam vždy zamítnutých má přednost před seznamem
povolených a pokrývá endpointy metadat cloudu a cíle telemetrie. Co se
nastavit nedá, je samotný seznam. Specifikace nese pole egressAllowlist
pro další domény, ale cesta odeslání ho nenaplní, takže v praxi každý běh
dostane základ plus GitHub a nic navíc.
Zamítnutí jsou na macOS pozorovatelná. Monitor čte systémový log a hledá
zamítnutí Sandboxu, odfiltruje známý šum, sloučí vlny opakovaných pokusů
a každé vynese jako SandboxViolation s tím, co se zkoušelo a co se zablokovalo. Na Linuxu cesta obalu parsuje stderr a hledá EPERM,
Operation not permitted a Permission denied a vypíše stejný typ události.
Odposlech systémového logu tam není. Dorazí na vlastní proud událostí běhu,
takže se odepřené systémové volání ukáže v přepisu, ne jen v logu. Telemetrie
existuje jen dokud nativní sandbox proces opravdu obaluje. Na hostiteli bez
backendu není co pozorovat. S guardraily to taky nesouvisí. Porušení pochází z odepřeného systémového volání, nikdy z vyhledání pravidla.
Potvrzení přicházejí z guardrailů, ne ze sandboxu
Sekce “Potvrzení přicházejí z guardrailů, ne ze sandboxu”Sandbox nemá cestu schválení. Spustí se, provede práci, vypíše události a skončí. Není v něm místo, kde by člověk odpověděl na otázku. Když v prostoru uvidíš potvrzení, schválit tenhle push nebo schválit tohle smazání, vyvolal ho motor guardrailů (nebo politika příkazů harnessu) ještě předtím, než akce vůbec došla k běhu.
Tohle pořadí je záměr. Schválení až po systémovém volání by bylo záznamem auditu, ne bránou. Proto taky pravidlo zavření při selhání žije v guardrailech. Když není připojený schvalovatel, rozhodnutí padne dřív, než cokoli poběží, a je to zamítnutí.
Diagnostika
Sekce “Diagnostika”Diagnostikujte agenta je jediné místo, které říká, co se dá zkontrolovat ručně.
Související koncepty
Sekce “Související koncepty”- Stanice a izolovaná prostředí: stupeň nad sandboxem, když práce potřebuje celý jednorázový stroj s hranicí jádra, ne obalený proces
- Guardraily: vrstva politiky nad spodní hranicí operačního systému a místo, odkud schválení skutečně přicházejí
- Životní cyklus odeslání agenta: kam izolace zapadá do toku odeslání
- Režimy: jak režim zužuje plochu nástrojů a politiku příkazů
- Backendy sandboxu: backendy a jejich konfigurace
Související návody
Sekce “Související návody”- Nastavte politiky sandboxu: pravidla akcí, vynucení pushů a podoba souborového systému
- Diagnostikujte agenta: co kontroly diagnostiky pokrývají