Przejdź do głównej zawartości

Backendy sandboxa

Backend Wartość Platforma Dostępność
Zamknięta VM microvm macOS, Linux, Windows (hypervisor microVM) Bramkowane sondą runtime’u microVM; dotyczy interaktywnych terminali — powłoka działa wewnątrz riga, a nie na hoście
Natywny sandbox native macOS (Seatbelt), Linux i WSL2 (bubblewrap) Sonduje się przy starcie; Linux odmawia uruchomienia wymagającego zakazów zapisu dla wzorców nazw plików, których bubblewrap nie potrafi wyegzekwować
Bez izolacji none Wszystkie Domyślna wartość parsowania, domyślna wartość terminala oraz rozwiązanie zapasowe, gdy żaden backend nie jest dostępny albo ustawiono --sandbox off

SandboxBackend.fromName zwraca none dla pustej (null) lub nierozpoznanej zapisanej wartości. Zapisana wartość "docker" jest mapowana na native.

microvm to jedyny backend z granicą jądra — obciążenie naprawdę nie działa na hoście. Nigdy nie jest cichym rozwiązaniem zapasowym w żadnym kierunku: jawne zażądanie go na hoście, który nie potrafi uruchomić VM, kończy się głośnym błędem („poprosiłem o VM, a dostałem swój laptop” to jedyna degradacja, na którą ta izolacja nie może sobie pozwolić), a tylko nieokreślona wartość domyślna schodzi do native, z linią w logu, która to komunikuje. Rzeczywisty backend sesji jest raportowany z powrotem do klienta i oznaczany plakietką, więc terminal nigdy nie może twierdzić, że jest zamknięty, gdy działa na hoście. Cykl życia, obrazy i ruch wychodzący samej VM opisuje dokumentacja referencyjna rigów.

Windows nie ma natywnego sandboxa. NativeSandboxAdapter.probe zwraca available: false na każdym hoście, który nie jest macOS ani Linux/WSL2. Wysyłanie agentów w Windows używa więc none. Backend microvm jest odrębny: jest bramkowany sondą runtime’u microVM i dotyczy interaktywnych terminali oraz rigów, a nie opakowywania bash na hoście.

To sonda bramkuje egzekwowanie. Działa raz, przy starcie serwera.

Host available Uwaga / wskazówka
macOS true sandbox-exec (Seatbelt) — izolacja przestrzeni nazw, bez granicy jądra
Linux lub WSL2 z bwrap i socat true bubblewrap — izolacja przestrzeni nazw, bez granicy jądra
Linux lub WSL2 bez któregokolwiek z narzędzi false requiresInstall: true, ze wskazówką instalacyjną wymieniającą brakujące pakiety
Każda inna platforma false Natywny sandbox nie jest oferowany na tej platformie

Serwer zapisuje wynik w jednej linii startowej: agent sandbox ON plus uwaga, no OS-native agent sandbox on this host plus wskazówka albo agent sandbox DISABLED by --sandbox off. GET /healthz nie zawiera pola sandboxa.

--sandbox / CC_SERVER_SANDBOX przyjmuje on (domyślnie) albo off. To rezygnacja (opt-out), a nie włączenie: on znaczy „opakuj, gdy host oferuje backend”, nigdy „wymagaj go”.

Wykorzystuje mechanizm sandboxa Seatbelt firmy Apple (ten sam system, którego używa macOS App Sandbox).

Generowany profil jest domyślnie permisywny ((allow default)) i wycina z niego odmowy, bo w pełni odmawiający domyślnie profil czyni interaktywną powłokę bezużyteczną — wywołań dyld, XPC i Mach jest zbyt wiele, by je wyliczyć. Praktyczna konsekwencja jest taka, że agent nadal może odczytać większość hosta; Twoje zarejestrowane kopie robocze chronią jawne odmowy zapisu i zmiany nazwy, a nie niewidzialność.

  • Odczyty systemu plików: odmawiane dla ścieżek z sekretami (~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh, ~/Library/Keychains i pozostałych ze zbioru zakazu odczytu)
  • Zapisy systemu plików: resetowane do odmowy, a następnie jawne zezwolenia na podścieżki, przy czym ścieżki objęte obowiązkowym zakazem (pliki rc powłoki, .git/hooks, konfiguracja Claude, chronione kopie robocze) są blokowane nawet wewnątrz korzenia z prawem zapisu. file-write-unlink jest odmawiany na każdej zabronionej ścieżce i jej przodkach, więc zmiana nazwy nie może ominąć zakazu zapisu
  • Procesy: odmowy process-exec dla zawsze niebezpiecznych plików binarnych oraz blokada wykonywania czegokolwiek z katalogu z prawem zapisu
  • Sieć: ograniczona do portów proxy działających w procesie plus DNS — pętla zwrotna nie jest dozwolona hurtowo, a gniazda Unix nie są dozwolone. Proxy egzekwują listę dozwolonych domen dla sesji (zobacz Ruch wychodzący w sieci)
  • Konfiguracja: profile są generowane przy każdym starcie na podstawie SandboxSpec

Wymagania:

  • sandbox-exec (/usr/bin/sandbox-exec), część każdej instalacji macOS — nie wymaga dodatkowych narzędzi

Używa bubblewrap (bwrap) do tworzenia przestrzeni nazw montowania i PID.

  • System plików: tworzy przestrzeń nazw montowania, w której widoczne są tylko podmontowane ścieżki
  • Sieć: działa w niewspółdzielonej przestrzeni nazw sieci; ruch dociera do proxy hosta przez mostki gniazd Unix socat
  • Procesy: izolacja przestrzeni nazw PID

Wymagania:

  • zainstalowane bubblewrap i socat (sudo apt-get install bubblewrap socat w Debianie/Ubuntu)
  • obsługa przestrzeni nazw w jądrze (standard w nowoczesnym Linuksie)

Bubblewrap potrafi przesłonić istniejącą ścieżkę, ale nie potrafi zakazać nowego pliku .env, *.key lub *.pem wewnątrz podmontowanego katalogu z prawem zapisu. Standardowa polityka wysyłania wymaga tych zakazów dla wzorców nazw plików, więc natywne wysyłanie agentów obecnie odmawia działania na Linuksie/WSL2, nawet gdy sonda znajdzie bubblewrap. Nie działa z cicho osłabioną polityką. Aby przywrócić natywne wysyłanie w Linuksie, potrzebny jest backend z regułami nazw plików działającymi w momencie tworzenia. Wyłączenie sandboxowania to jawne, nieograniczone zrezygnowanie, a nie równoważne obejście.

Brak sandboxowania. Proces działa bezpośrednio na hoście, z dostępem hosta do systemu plików, sieci i procesów. ACP i narzędzie bash harnessa nadal otrzymują sanityzację środowiska oraz politykę poleceń; Claude Code przez NoSandboxAdapter dziedziczy środowisko hosta. Do tego rozwiązania schodzi wysyłanie agentów na hoście bez dostępnego backendu albo z --sandbox off i jest to domyślne ustawienie terminala, gdy klient nie wskazuje żadnego backendu.

Terminal jest sandboxowany na własnych zasadach, a nie przez sondę wysyłania. defaultBackend w TerminalSessionService ma wartość none i cc_server go nie nadpisuje, więc sesja terminala uruchamia powłokę hosta, chyba że klient wprost poprosi o native — panel terminala w aplikacji desktopowej tego nie robi.

Gdy zażądano native, powłoka jest opakowywana przez SandboxManager w stałym profilu terminala: $HOME i katalog roboczy sesji mają prawo zapisu, sieć jest otwarta, a ~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh i ~/Library/Keychains mają zakaz odczytu. Token hosta kodu tylko do odczytu i brama push nie mają tu zastosowania — to sprawy wysyłania. Jeśli opakowanie nie jest obsługiwane, sesja kończy się błędem, zamiast pokazywać natywną plakietkę na PTY z powłoką hosta.

Gdy sandbox jest uruchamiany, dostęp wychodzący do sieci jest egzekwowany przez proxy działające w procesie, a nie przez reguły firewalla jądra. Na hoście bez dostępnego backendu nic z tego nie obowiązuje, a uruchomiony proces dociera do sieci dokładnie tak, jak zrobiłby to użytkownik serwera.

  • Runtime sandboxa uruchamia proxy HTTP/HTTPS oraz proxy SOCKS5 na 127.0.0.1 wewnątrz procesu cc_server, po jednej parze na ograniczoną sesję (http_proxy.dart, socks_proxy.dart). Równoległe uruchomienia nie dzielą pary.
  • Procesy w sandboxie otrzymują zmienne środowiskowe proxy (HTTP_PROXY/HTTPS_PROXY → proxy HTTP, ALL_PROXY → proxy SOCKS; GIT_SSH_COMMAND kieruje git po SSH przez proxy SOCKS). W Linuksie przestrzeń nazw sieci jest niewspółdzielona, więc proxy to jedyne wyjście; w macOS sandbox współdzieli pętlę zwrotną hosta i rozmawia z nimi bezpośrednio.
  • Docelowy host każdego połączenia jest dopasowywany do listy dozwolonych domen sesji; wszystko inne jest odrzucane. Istnieją dwie formy wieloznaczne, każda z dokładnie jednym *: wiodąca *.example.com pasuje do dowolnej subdomeny (w tym a.b.example.com), ale nie do samej domeny głównej; środkowa etykieta bedrock.*.amazonaws.com pasuje do dokładnie jednej etykiety (bedrock.us-east-1.amazonaws.com, a nie bedrock.evil.attacker.amazonaws.com).
  • Lista dozwolonych jest wyznaczana dla każdej sesji na podstawie wyselekcjonowanej bazy (kBaselineAllowedDomains: dostawcy LLM, hosting Git, rejestry pakietów) plus domeny GitHub (kGithubDomains), plus SandboxSpec.egressAllowlist. Ścieżka wysyłania nigdy nie przekazuje dodatkowych wpisów egressAllowlist, więc w praktyce każde uruchomienie dostaje bazę plus GitHuba.
  • Stała lista zakazów (kBaselineDeniedDomains: punkty końcowe metadanych chmury, ujścia telemetrii) ma pierwszeństwo przed wszystkimi zezwoleniami.
  • networkEnabled: false nadal uruchamia proxy dla sesji, ale lista dozwolonych jest pusta, więc każde połączenie wychodzące jest odrzucane. Wysyłanie ustawia tę wartość na starcie uruchomienia na podstawie reguły Dostęp do sieci: odmowa wyłącza sieć, zezwól i zapytaj najpierw zostawiają ją włączoną.

Specyfikacja przekazywana do SandboxPort.launch:

Pole Typ Opis
sessionId String Stabilny identyfikator sesji (zwykle identyfikator przestrzeni)
workspaceId String Identyfikator obszaru roboczego będącego właścicielem
agentId String? Agent aktualnie powiązany z sandboxem, jeśli istnieje
bindMounts List<SandboxBindMount> Montowania host→gość; sandbox widzi tylko wymienione tu ścieżki hosta
networkEnabled bool (domyślnie true) Ustawiane przy wysyłaniu na podstawie reguły ruchu wychodzącego sieci (wyłączone tylko wtedy, gdy rozstrzyga się na odmowę). Gdy wyłączone, proxy dla sesji nadal startują, ale lista dozwolonych jest pusta, więc każde połączenie wychodzące jest odrzucane
egressAllowlist List<String> (domyślnie []) Dodatkowe dozwolone domeny ruchu wychodzącego; obsługiwane wieloznaczniki (*.example.com oraz środkowa forma z jedną etykietą). Wysyłanie nigdy tego nie wypełnia, więc opakowane uruchomienie dostaje wyselekcjonowaną bazę plus domeny GitHub
guestWorkdir String? Domyślny katalog roboczy wewnątrz sandboxa; pojedyncze wywołania exec mogą go nadpisać
mode Mode (domyślnie chat) Wycina reguły zapisu systemu plików: chat pozostawia montowania z prawem zapisu; review, plan i orchestrate są tylko do odczytu
protectedPaths List<String> (domyślnie []) Ścieżki hosta, które nigdy nie mogą mieć prawa zapisu wewnątrz sandboxa, w żadnym trybie
runnerStateDirs List<String> (domyślnie []) Katalogi hosta, w których runner trzyma własny stan, z prawem zapisu w każdym trybie (obecnie zarządzany przez Control Center CLAUDE_CONFIG_DIR)
execGrantRoots List<String> (domyślnie []) Zatwierdzone przez operatora drzewa katalogów, które ponownie otwierają blokadę wykonywania z katalogu z prawem zapisu w macOS. Linux je ignoruje — bwrap nie ma blokady wykonywania w $HOME, którą można by ponownie otworzyć

protectedPaths zawiera oryginalne, zarejestrowane kopie robocze repozytoriów, wyznaczane przy każdym wysłaniu z repozytoriów obszaru roboczego. Agenci pracują wyłącznie w kopiowanych przy zapisie worktree przypadających na rozmowę, więc oryginały nigdy nie mogą mieć prawa zapisu z wnętrza sandboxa — w macOS ogólne zezwolenie Seatbelt na zapis w $HOME pozostawiłoby im prawo zapisu przez bash. Dołączają do zestawu zakazu zapisu dla sekretów w każdym trybie, w tym w chat.

Każda ścieżka zakazu odczytu i zakazu zapisu jest emitowana zarówno w dosłownym zapisie, jak i w zapisie po rozwiązaniu dowiązań symbolicznych. Jądro dopasowuje regułę zakazu do rozwiązanej ścieżki, więc reguła zapisana względem ścieżki będącej dowiązaniem symbolicznym nigdy nie zadziała — a w macOS to przypadek częsty, nie egzotyczny, bo /tmp rozwiązuje się do /private/tmp, a /var/folders/… do /private/var/folders/…. Wpisy zawierające * lub ? są traktowane jako wzorce i pozostawiane bez zmian; ścieżka, która się nie rozwiązuje, jest zachowywana w zapisanej postaci.

Pole Typ Opis
hostPath String Ścieżka bezwzględna na hoście
guestPath String Ścieżka wewnątrz sandboxa (w sandboxie natywnym jest równa hostPath; zachowana dla symetrii adapterów)
readOnly bool (domyślnie false) Gdy true, montuj tylko do odczytu

Zwracany przez SandboxPort.launch:

Pole Typ Opis
sessionId String Identyfikator sesji
backend SandboxBackend Który backend działa
state SandboxState Stan cyklu życia
error Object? Ustawiane, gdy state ma wartość error
details Map<String, Object?> Wewnętrzna księgowość adaptera (katalog roboczy, PID, ścieżka profilu itd.)
Stan Opis
created Specyfikacja utworzona, ale VM jeszcze nie wystartowała
warm Działa i jest gotowa do wykonywania poleceń
active Wykonuje właśnie polecenie
suspended Wstrzymana / zapisana na dysk jako punkt kontrolny, aby oszczędzać RAM
destroyed Rozebrana; uchwyt nie jest już ważny
error Uruchomienie nie powiodło się — zobacz SandboxHandle.error
Typ zdarzenia Opis
stdout Standardowe wyjście z sandboxa
stderr Standardowe wyjście błędów z sandboxa
exit Proces sandboxa zakończył się (niesie exitCode)
starting Sandbox się uruchamia
ready Sandbox jest gotowy przyjmować wywołania exec
killed Proces zabity przez hosta (OOM, przekroczenie limitu czasu, ręczne zatrzymanie)
violation Naruszono politykę sandboxa (niesie SandboxViolation)
Pole Typ Opis
action String Zabronione działanie (np. file-read*, network-outbound)
target String Ścieżka lub host będący celem zabronionej operacji
raw String? Surowa linia logu, przydatna przy debugowaniu