Přeskočit na obsah

Backendy sandboxu

Backend Hodnota Platforma Dostupnost
Izolované VM microvm macOS, Linux, Windows (hypervizor microVM) Řízeno sondou runtime microVM; platí pro interaktivní terminály — shell běží uvnitř stanice, ne na hostiteli
Nativní native macOS (Seatbelt), Linux a WSL2 (bubblewrap) Sonda při startu; Linux odmítne běh, který vyžaduje zákazy zápisu podle globu názvu souboru, a ty bubblewrap vynutit neumí
Žádný none Vše Výchozí hodnota při parsování, výchozí stav terminálu a náhrada, když není backend k dispozici nebo je nastaveno --sandbox off

SandboxBackend.fromName vrací none pro null nebo nerozpoznanou uloženou hodnotu. Uložené "docker" se mapuje na native.

microvm je jediný backend s hranicí jádra — zátěž opravdu neběží na hostiteli. Tichá záloha to není ani jedním směrem: výslovná žádost o něj na hostiteli, který VM nespustí, selže nahlas („Požádal jsem o VM a dostal jsem svůj notebook“ je jediné zhoršení, které si uzavřený stroj nemůže dovolit) a jen neuvedená výchozí hodnota sestoupí na native, s řádkem v logu, který to řekne. Skutečný backend relace se hlásí zpátky klientovi a dostane odznak, takže terminál se nikdy nemůže vydávat za uzavřený, když běží na hostiteli. Životní cyklus, obrazy a odchozí provoz samotného VM pokrývá reference stanic.

Windows nemá nativní sandbox. NativeSandboxAdapter.probe vrací available: false na každém hostiteli, který není macOS ani Linux/WSL2. Odeslání agenta na Windows proto používá none. Backend microvm je zvlášť: řídí ho sonda podle runtime microVM a platí pro interaktivní terminály a stanice, ne pro obalení bash na hostiteli.

Vynucování pouští sonda. Běží jednou, při startu serveru.

Hostitel available Poznámka / nápověda
macOS true sandbox-exec (Seatbelt) — izolace jmenného prostoru, bez hranice jádra
Linux nebo WSL2 s bwrap a socat true bubblewrap — izolace jmenného prostoru, bez hranice jádra
Linux nebo WSL2, chybí jeden z nástrojů false requiresInstall: true, s nápovědou k instalaci, která pojmenuje chybějící balíčky
Jakákoli jiná platforma false Nativní sandbox se na téhle platformě nenabízí

Server výsledek zapíše na jeden startovací řádek: agent sandbox ON a k tomu poznámka, no OS-native agent sandbox on this host a k tomu nápověda, nebo agent sandbox DISABLED by --sandbox off. GET /healthz pole sandboxu nenese.

--sandbox / CC_SERVER_SANDBOX bere on (výchozí) nebo off. Je to vypnutí, ne zapnutí: on znamená „obal, když hostitel nabízí backend“, nikdy „vyžaduj ho“.

Používá sandboxový mechanismus Apple Seatbelt (tentýž systém jako macOS App Sandbox).

Vygenerovaný profil je ve výchozím stavu permisivní ((allow default)) a vykrajuje zákazy, protože profil, který ve výchozím stavu všechno zakáže, udělá interaktivní shell nepoužitelný — volání dyld, XPC a Mach je na vypsání moc. Praktický důsledek: agent pořád může číst většinu hostitele; tvoje registrované checkouty chrání výslovné zákazy zápisu a přejmenování, ne neviditelnost.

  • Čtení souborového systému: zakázané pro tajné cesty (~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh, ~/Library/Keychains a zbytek sady zákazů čtení)
  • Zápis do souborového systému: nejdřív se vrátí na zákaz, pak se výslovně povolí podcesty, přičemž cesty s povinným zákazem (rc soubory shellu, .git/hooks, konfigurace Claude, chráněné checkouty) jsou blokované i uvnitř zapisovatelného kořene. file-write-unlink je zakázaný na každé zakázané cestě a jejích předcích, takže přejmenování zákaz zápisu neobejde
  • Proces: process-exec zakazuje binárky, které jsou vždy nebezpečné, a k tomu blokuje spuštění čehokoli ze zapisovatelného adresáře
  • Síť: omezená na porty proxy v procesu a na DNS — loopback není povolený plošně a Unix sockety povolené nejsou. Proxy vynucují seznam povolených domén dané relace (viz Odchozí síť)
  • Konfigurace: profily se generují pro každý start ze SandboxSpec

Požadavky:

  • sandbox-exec (/usr/bin/sandbox-exec), součást každé instalace macOS — další nástroje nejsou potřeba

Používá bubblewrap (bwrap) k vytvoření jmenných prostorů připojení a PID.

  • Souborový systém: vytvoří jmenný prostor připojení, ve kterém jsou vidět jen navázané cesty
  • Síť: běží v nesdíleném síťovém jmenném prostoru; provoz se k proxy na hostiteli dostane přes mosty socat na Unix socketech
  • Proces: izolace jmenného prostoru PID

Požadavky:

  • Nainstalované bubblewrap a socat (sudo apt-get install bubblewrap socat na Debian/Ubuntu)
  • Podpora jmenných prostorů v jádře (na moderním Linuxu standard)

Bubblewrap umí zastínit existující cestu, ale neumí zakázat nový soubor .env, *.key nebo *.pem uvnitř zapisovatelného bindu. Standardní politika odeslání tyhle zákazy podle globu názvu souboru vyžaduje, takže nativní odeslání agenta teď selže uzavřeně na Linuxu a WSL2, i když sonda najde bubblewrap. Nespustí se s potichu slabší politikou. K obnovení nativního odeslání na Linuxu je potřeba backend s pravidly názvů souborů v okamžiku vytvoření. Vypnutí sandboxu je výslovné vypnutí bez omezení, ne rovnocenné náhradní řešení.

Bez sandboxu. Proces běží přímo na hostiteli s jeho souborovým systémem, sítí a přístupem k procesům. ACP a nástroj bash harnessu pořád dostanou očištění prostředí a politiku příkazů; Claude Code přes NoSandboxAdapter dědí prostředí hostitele. Sem spadne odeslání agenta na hostiteli bez dostupného backendu nebo s --sandbox off a je to výchozí stav terminálu, když klient uvede none.

Terminál hostovaný na serveru

Sekce “Terminál hostovaný na serveru”

Terminál má vlastní pravidla sandboxu, ne ta ze sondy odeslání. defaultBackend u TerminalSessionService je none a cc_server ho nepřepisuje, takže relace terminálu spouští shell hostitele, dokud klient výslovně nepožádá o native — panel terminálu v aplikaci na počítači o to nežádá.

Když je požadovaný native, shell se obalí přes SandboxManager pevným profilem terminálu: $HOME a pracovní adresář relace jsou zapisovatelné, síť je otevřená a ~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh a ~/Library/Keychains mají zákaz čtení. Token forge jen pro čtení a brána pro push se neuplatní — to řeší odeslání. Když obal není podporovaný, relace selže, místo aby na PTY shellu hostitele ukázala odznak nativního sandboxu.

Když se sandbox spustí, odchozí přístup k síti vynucují proxy v procesu, ne pravidla firewallu v jádře. Na hostiteli bez dostupného backendu nic z toho neplatí a spuštěný proces se k síti dostane přesně tak, jako by se k ní dostal uživatel serveru.

  • Runtime sandboxu spouští HTTP/HTTPS proxy a SOCKS5 proxy na 127.0.0.1 uvnitř procesu cc_server, jeden pár na každou omezenou relaci (http_proxy.dart, socks_proxy.dart). Souběžné běhy pár nesdílejí.
  • Sandboxované procesy dostanou proměnné prostředí proxy (HTTP_PROXY/HTTPS_PROXY → HTTP proxy, ALL_PROXY → SOCKS proxy; GIT_SSH_COMMAND vede git přes SSH skrz SOCKS proxy). Na Linuxu je síťový jmenný prostor nesdílený, takže proxy jsou jediná cesta ven; na macOS sandbox sdílí loopback hostitele a mluví s nimi přímo.
  • Cílový hostitel každého spojení se porovná se seznamem povolených domén relace; všechno ostatní se odmítne. Dva tvary zástupných znaků, každý s právě jednou *: úvodní *.example.com odpovídá libovolné subdoméně (včetně a.b.example.com), ale ne samotnému apexu; prostřední návěští bedrock.*.amazonaws.com odpovídá právě jednomu návěští (bedrock.us-east-1.amazonaws.com, ne bedrock.evil.attacker.amazonaws.com).
  • Seznam povolených se pro každou relaci sestaví z vybraného základu (kBaselineAllowedDomains: poskytovatelé LLM, hosting gitu, registry balíčků), plus domény GitHubu (kGithubDomains), plus SandboxSpec.egressAllowlist. Cesta odeslání nikdy nepředá další položky egressAllowlist, takže v praxi každý běh dostane základ plus GitHub.
  • Pevný seznam zákazů (kBaselineDeniedDomains: endpointy metadat cloudu, cíle telemetrie) má přednost před všemi povoleními.
  • networkEnabled: false proxy pro danou relaci pořád spustí, ale seznam povolených je prázdný, takže se každé odchozí spojení odmítne. Odeslání hodnotu nastaví při startu běhu podle pravidla Přístup k síti: zakázat síť vypne, povolit a nejdřív se zeptat ji nechají zapnutou.

Specifikace předaná do SandboxPort.launch:

Pole Typ Popis
sessionId String Stabilní identifikátor relace (obvykle id prostoru)
workspaceId String Id vlastnicího pracovního prostoru
agentId String? Agent právě navázaný na sandbox, pokud nějaký je
bindMounts List<SandboxBindMount> Připojení hostitel→host; sandbox vidí jen cesty hostitele uvedené tady
networkEnabled bool (výchozí true) Nastaví ho odeslání podle pravidla pro odchozí síťový provoz (vypnuté jen tehdy, když vyjde zakázat). Když je vypnuté, proxy pro danou relaci se pořád spustí, ale seznam povolených je prázdný, takže se každé odchozí spojení odmítne
egressAllowlist List<String> (výchozí []) Další povolené domény odchozího provozu; podporuje zástupné znaky (*.example.com a tvar s jedním prostředním návěštím). Odeslání tohle pole nikdy nenaplní, takže obalený běh dostane vybraný základ plus domény GitHubu
guestWorkdir String? Výchozí pracovní adresář uvnitř sandboxu; jednotlivá volání exec ho umí přepsat
mode Mode (výchozí chat) Vykrajuje pravidla zápisu do souborového systému: chat nechává bind mounty zapisovatelné; review, plan a orchestrate jsou jen pro čtení
protectedPaths List<String> (výchozí []) Cesty hostitele, které uvnitř sandboxu nesmí být v žádném režimu zapisovatelné
runnerStateDirs List<String> (výchozí []) Adresáře hostitele, ve kterých si runner drží vlastní stav, zapisovatelné v každém režimu (zatím je to CLAUDE_CONFIG_DIR spravovaný Control Center)
execGrantRoots List<String> (výchozí []) Stromy adresářů schválené operátorem, které na macOS znovu otevřou blok exec ze zapisovatelného adresáře. Linux je ignoruje — bwrap nemá v $HOME blok exec, který by šlo znovu otevřít

protectedPaths drží původní registrované checkouty repozitářů, rozřešené při každém odeslání z repozitářů pracovního prostoru. Agenti pracují jen v copy-on-write worktree dané konverzace, takže originály nesmí jít zevnitř sandboxu zapisovat — na macOS by je jinak plošné povolení zápisu Seatbeltu do $HOME nechalo zapisovatelné přes bash. Přidají se do sady zákazů zápisu tajemství v každém režimu, včetně chat.

Každá cesta se zákazem čtení i se zákazem zápisu se vypíše v doslovném zápisu i v zápisu po rozřešení symlinku. Jádro porovnává pravidlo zákazu s rozřešenou cestou, takže pravidlo zapsané proti cestě se symlinkem se nikdy neuplatní — a na macOS je to běžný případ, ne výjimka, protože /tmp se rozřeší na /private/tmp a /var/folders/… na /private/var/folders/…. Položky obsahující * nebo ? se berou jako globy a nechají se být; cesta, která se nerozřeší, zůstane zapsaná tak, jak byla.

Pole Typ Popis
hostPath String Absolutní cesta na hostiteli
guestPath String Cesta uvnitř sandboxu (u nativního sandboxu se rovná hostPath; ponechaná kvůli symetrii adaptérů)
readOnly bool (výchozí false) Když je true, připojí se jen pro čtení

Vrací ho SandboxPort.launch:

Pole Typ Popis
sessionId String Identifikátor relace
backend SandboxBackend Který backend běží
state SandboxState Stav životního cyklu
error Object? Nastavené, když je state rovno error
details Map<String, Object?> Soukromá evidence adaptéru (pracovní adresář, PID, cesta k profilu atd.)
Stav Popis
created Specifikace je vytvořená, ale VM ještě nestartovalo
warm Běží a je připravené spouštět příkazy
active Právě provádí příkaz
suspended Pozastavené / checkpoint na disku, aby se ušetřila RAM
destroyed Uklizené; handle už neplatí
error Start selhal — viz SandboxHandle.error
Typ události Popis
stdout Standardní výstup ze sandboxu
stderr Standardní chybový výstup ze sandboxu
exit Proces sandboxu skončil (nese exitCode)
starting Sandbox se spouští
ready Sandbox je připravený přijímat volání exec
killed Proces ukončil hostitel (OOM, timeout, ruční zastavení)
violation Politika sandboxu byla porušena (nese SandboxViolation)
Pole Typ Popis
action String Odmítnuté sloveso (např. file-read*, network-outbound)
target String Cesta nebo hostitel, na který odmítnutá operace mířila
raw String? Surový řádek logu, užitečný při ladění