Backend-uri sandbox
Prezentare generală a backend-urilor
Secțiune intitulată „Prezentare generală a backend-urilor”| Backend | Valoare | Platformă | Disponibilitate |
|---|---|---|---|
| VM izolat | microvm |
macOS, Linux, Windows (microVM hypervisor) | Condiționat de sondă pe runtime-ul microVM; se aplică terminalelor interactive — shell-ul rulează într-o stație, nu pe gazdă |
| Nativ | native |
macOS (Seatbelt), Linux și WSL2 (bubblewrap) | Sondat la pornire; Linux refuză o rulare care necesită interdicții de scriere pe globuri de nume de fișiere, pe care bubblewrap nu le poate impune |
| Niciunul | none |
Toate | Implicitul la parsare, implicitul terminalului și soluția de rezervă când nu este disponibil niciun backend sau este setat --sandbox off |
SandboxBackend.fromName returnează none pentru o valoare stocată nulă sau nerecunoscută. O valoare stocată "docker" se mapează la native.
microvm este singurul backend cu o graniță de kernel — sarcina de lucru
chiar nu rulează pe gazdă. Nu este niciodată o soluție de rezervă silențioasă în
niciun sens: cererea lui explicită pe o gazdă care nu poate porni un VM eșuează
cu zgomot („Am cerut un VM și am primit laptopul meu” este singura degradare pe
care izolarea nu și-o poate permite), iar doar un implicit nespecificat coboară
la native, cu o linie de jurnal care spune asta. Backend-ul real al sesiunii este
raportat înapoi clientului și marcat cu o insignă, așa că un terminal nu poate
pretinde niciodată că este izolat în timp ce rulează pe gazdă. Ciclul de viață,
imaginile și ieșirea în rețea pentru VM-ul însuși sunt acoperite de
referința pentru stații.
Windows nu are sandbox nativ. NativeSandboxAdapter.probe returnează available: false pe orice gazdă care nu este macOS sau Linux/WSL2. Trimiterea agenților pe Windows folosește deci none. Backend-ul microvm este separat: este condiționat de sondă pe runtime-ul microVM și se aplică terminalelor interactive și stațiilor, nu învelirii bash pe gazdă.
Rezultatele sondei
Secțiune intitulată „Rezultatele sondei”Sonda este cea care condiționează aplicarea. Rulează o dată, la pornirea serverului.
| Gazdă | available |
Notă / indiciu |
|---|---|---|
| macOS | true |
sandbox-exec (Seatbelt) — izolare la nivel de namespace, fără graniță de kernel |
Linux sau WSL2 cu bwrap și socat |
true |
bubblewrap — izolare la nivel de namespace, fără graniță de kernel |
| Linux sau WSL2 căruia îi lipsește oricare dintre instrumente | false |
requiresInstall: true, cu un indiciu de instalare care numește pachetele lipsă |
| Orice altă platformă | false |
Sandbox-ul nativ nu este oferit pe această platformă |
Serverul înregistrează rezultatul într-o singură linie de pornire: agent sandbox ON plus nota, no OS-native agent sandbox on this host plus indiciul, sau agent sandbox DISABLED by --sandbox off. GET /healthz nu conține niciun câmp de sandbox.
--sandbox / CC_SERVER_SANDBOX acceptă on (implicit) sau off. Este o dezactivare opțională, nu o activare: on înseamnă „învelește când gazda oferă un backend”, niciodată „cere unul”.
Backend-ul nativ
Secțiune intitulată „Backend-ul nativ”macOS: Seatbelt
Secțiune intitulată „macOS: Seatbelt”Folosește mecanismul de sandbox Seatbelt al Apple (același sistem folosit de macOS App Sandbox).
Profilul generat este permisiv implicit ((allow default)) și decupează interdicții, pentru că un profil complet cu refuz implicit face un shell interactiv inutilizabil — sunt prea multe apeluri dyld, XPC și Mach de enumerat. Consecința practică este că un agent poate citi în continuare cea mai mare parte a gazdei; checkout-urile tale înregistrate sunt protejate prin interdicții explicite de scriere și de redenumire, nu prin invizibilitate.
- Citirile din sistemul de fișiere: interzise pentru căile secrete (
~/.ssh,~/.aws,~/.gnupg,~/.config/gh,~/Library/Keychainsși restul setului cu citire interzisă) - Scrierile în sistemul de fișiere: resetate la refuz, apoi permisiuni explicite pe subcăi, cu căile cu interdicție obligatorie (fișierele rc ale shell-ului,
.git/hooks, configurația Claude, checkout-urile protejate) blocate chiar și în interiorul unei rădăcini inscriptibile.file-write-unlinkeste interzis pe fiecare cale interzisă și pe strămoșii ei, așa că o redenumire nu poate ocoli o interdicție de scriere - Procese:
process-execinterzice binarele mereu periculoase, plus o blocare a execuției oricărui lucru dintr-un director inscriptibil - Rețea: restricționată la porturile proxy din proces plus DNS — loopback nu este permis în bloc, iar socketurile Unix nu sunt permise. Proxy-urile impun lista de permisiuni de domenii per sesiune (vezi Ieșirea în rețea)
- Configurare: profilurile sunt generate la fiecare lansare din
SandboxSpec
Cerințe:
sandbox-exec(/usr/bin/sandbox-exec), parte din orice instalare macOS — nu este necesar niciun instrument suplimentar
Linux: bubblewrap
Secțiune intitulată „Linux: bubblewrap”Folosește bubblewrap (bwrap) pentru a crea namespace-uri de montare și PID.
- Sistemul de fișiere: creează un namespace de montare în care sunt vizibile doar căile legate
- Rețea: rulează într-un namespace de rețea nepartajat; traficul ajunge la proxy-urile gazdei prin punți de socketuri Unix
socat - Procese: izolare prin namespace PID
Cerințe:
bubblewrapșisocatinstalate (sudo apt-get install bubblewrap socatpe Debian/Ubuntu)- Suport pentru namespace-uri în kernel (standard pe Linux-ul modern)
Bubblewrap poate umbri o cale existentă, dar nu poate interzice un fișier .env,
*.key sau *.pem nou în interiorul unei legături inscriptibile. Politica
standard de trimitere cere aceste interdicții pe globuri de nume de fișiere, așa
că trimiterea nativă a agenților eșuează închis pe Linux/WSL2 chiar și atunci
când sonda găsește bubblewrap. Nu rulează cu o politică slăbită în tăcere.
Este necesar un backend cu reguli de nume de fișiere la momentul creării pentru a
restabili trimiterea nativă pe Linux. Dezactivarea sandbox-ului este o renunțare
explicită la confinare, nu o soluție echivalentă.
Backend-ul none
Secțiune intitulată „Backend-ul none”Fără sandbox. Procesul rulează direct pe gazdă, cu accesul gazdei la sistemul de fișiere, rețea și procese. ACP și instrumentul bash al harness-ului primesc în continuare sanitizarea mediului și politica de comenzi; Claude Code prin NoSandboxAdapter moștenește mediul gazdei. La acesta se întoarce trimiterea agenților pe o gazdă fără niciun backend disponibil sau cu --sandbox off, și este implicitul terminalului atunci când un client nu numește niciunul.
Terminalul găzduit de server
Secțiune intitulată „Terminalul găzduit de server”Terminalul este sandboxat după propriile reguli, nu de sonda de trimitere. defaultBackend al TerminalSessionService este none, iar cc_server nu îl suprascrie, așa că o sesiune de terminal rulează shell-ul gazdei dacă clientul nu cere explicit native — panoul de terminal al aplicației desktop nu o face.
Când se cere native, shell-ul este învelit prin SandboxManager sub un profil fix de terminal: $HOME și directorul de lucru al sesiunii sunt inscriptibile, rețeaua este deschisă, iar ~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh și ~/Library/Keychains au citirea interzisă. Tokenul de forge doar pentru citire și gateway-ul de push nu se aplică — acestea sunt probleme de trimitere. Dacă învelirea nu este acceptată, sesiunea eșuează în loc să afișeze o insignă de nativ pe un PTY cu shell-ul gazdei.
Ieșirea în rețea
Secțiune intitulată „Ieșirea în rețea”Când este lansat un sandbox, accesul de ieșire în rețea este impus de proxy-uri din proces, nu de reguli de firewall la nivel de kernel. Pe o gazdă fără niciun backend disponibil nimic din toate acestea nu se aplică, iar un proces pornit ajunge la rețea exact așa cum ar face-o utilizatorul serverului.
- Runtime-ul sandbox-ului rulează un proxy HTTP/HTTPS și un proxy SOCKS5 pe
127.0.0.1în interiorul procesuluicc_server, o pereche per sesiune restricționată (http_proxy.dart,socks_proxy.dart). Rulările concurente nu împart o pereche. - Procesele din sandbox primesc variabile de mediu pentru proxy (
HTTP_PROXY/HTTPS_PROXY→ proxy-ul HTTP,ALL_PROXY→ proxy-ul SOCKS;GIT_SSH_COMMANDdirecționează git-over-SSH prin proxy-ul SOCKS). Pe Linux namespace-ul de rețea este nepartajat, așa că proxy-urile sunt singura cale de ieșire; pe macOS sandbox-ul împarte loopback-ul gazdei și vorbește cu ele direct. - Gazda țintă a fiecărei conexiuni este potrivită cu lista de permisiuni de domenii a sesiunii; orice altceva este refuzat. Două forme de wildcard, fiecare cu exact un
*: un*.example.comla început potrivește orice subdomeniu (inclusiva.b.example.com), dar nu apexul însuși; unbedrock.*.amazonaws.comcu etichetă la mijloc potrivește exact o etichetă (bedrock.us-east-1.amazonaws.com, nubedrock.evil.attacker.amazonaws.com). - Lista de permisiuni este rezolvată per sesiune din baza de referință atent selectată (
kBaselineAllowedDomains: furnizori de LLM, găzduire Git, registre de pachete), plus domeniile GitHub (kGithubDomains), plusSandboxSpec.egressAllowlist. Calea de trimitere nu transmite niciodată intrări suplimentare deegressAllowlist, așa că în practică fiecare rulare primește baza de referință plus GitHub. - O listă fixă de interdicții (
kBaselineDeniedDomains: puncte finale de metadate din cloud, destinații de telemetrie) are prioritate față de toate permisiunile. networkEnabled: falsepornește totuși proxy-urile per sesiune, dar lista de permisiuni este goală, așa că fiecare conexiune de ieșire este refuzată. Trimiterea îl setează la pornirea rulării din regula Accesează rețeaua: refuzul oprește rețeaua, permite și întreabă întâi o lasă pornită.
SandboxSpec
Secțiune intitulată „SandboxSpec”Specificația transmisă către SandboxPort.launch:
| Câmp | Tip | Descriere |
|---|---|---|
sessionId |
String |
Identificator stabil de sesiune (de obicei id-ul spațiului) |
workspaceId |
String |
Id-ul spațiului de lucru proprietar |
agentId |
String? |
Agentul legat în prezent de sandbox, dacă există |
bindMounts |
List<SandboxBindMount> |
Montări gazdă→invitat; sandbox-ul vede doar căile de gazdă listate aici |
networkEnabled |
bool (implicit true) |
Setat la trimitere din regula de ieșire în rețea (oprit doar când se rezolvă la refuz). Când este oprit, proxy-urile per sesiune pornesc totuși, dar lista de permisiuni este goală, așa că fiecare conexiune de ieșire este refuzată |
egressAllowlist |
List<String> (implicit []) |
Domenii de ieșire suplimentare permise; wildcard-uri acceptate (*.example.com, plus o formă de mijloc cu o singură etichetă). Trimiterea nu populează niciodată acest câmp, așa că o rulare învelită primește baza de referință atent selectată plus domeniile GitHub |
guestWorkdir |
String? |
Directorul de lucru implicit din interiorul sandbox-ului; apelurile exec individuale îl pot suprascrie |
mode |
Mode (implicit chat) |
Decupează regulile de scriere în sistemul de fișiere: chat păstrează montările bind inscriptibile; review, plan și orchestrate sunt doar pentru citire |
protectedPaths |
List<String> (implicit []) |
Căi de gazdă care nu trebuie să fie niciodată inscriptibile în interiorul sandbox-ului, în orice mod |
runnerStateDirs |
List<String> (implicit []) |
Directoare de gazdă în care runner-ul își păstrează propria stare, inscriptibile în orice mod (un CLAUDE_CONFIG_DIR gestionat de Control Center este cel actual) |
execGrantRoots |
List<String> (implicit []) |
Arbori de directoare aprobați de operator care redeschid blocarea de execuție pentru directoare inscriptibile pe macOS. Linux le ignoră — bwrap nu are nicio blocare de execuție pe $HOME de redeschis |
protectedPaths conține checkout-urile originale ale repo-urilor înregistrate, rezolvate la fiecare trimitere din repo-urile spațiului de lucru. Agenții lucrează exclusiv în worktree-uri copy-on-write per conversație, așa că originalele nu trebuie să fie niciodată inscriptibile din interiorul sandbox-ului — pe macOS, permisiunea generală de scriere în $HOME a Seatbelt le-ar lăsa altfel inscriptibile prin bash. Ele se alătură setului cu scriere interzisă pentru secrete în fiecare mod, inclusiv chat.
Fiecare cale cu citire interzisă și cu scriere interzisă este emisă atât în grafia ei literală, cât și în cea rezolvată prin symlink. Kernelul potrivește o regulă de interdicție cu calea rezolvată, așa că o regulă scrisă pe o cale cu symlink nu se declanșează niciodată — iar pe macOS acesta este cazul obișnuit, nu cel exotic, fiindcă /tmp se rezolvă la /private/tmp, iar /var/folders/… la /private/var/folders/…. Intrările care conțin * sau ? sunt tratate ca globuri și lăsate în pace; o cale care nu se rezolvă este păstrată așa cum a fost scrisă.
SandboxBindMount
Secțiune intitulată „SandboxBindMount”| Câmp | Tip | Descriere |
|---|---|---|
hostPath |
String |
Cale absolută pe gazdă |
guestPath |
String |
Cale în interiorul sandbox-ului (cu sandbox-ul nativ aceasta este egală cu hostPath; păstrată pentru simetria adaptoarelor) |
readOnly |
bool (implicit false) |
Montează doar pentru citire când este true |
SandboxHandle
Secțiune intitulată „SandboxHandle”Returnat de SandboxPort.launch:
| Câmp | Tip | Descriere |
|---|---|---|
sessionId |
String |
Identificator de sesiune |
backend |
SandboxBackend |
Ce backend rulează |
state |
SandboxState |
Starea ciclului de viață |
error |
Object? |
Setat când state este error |
details |
Map<String, Object?> |
Evidență privată a adaptorului (director de lucru, PID, calea profilului etc.) |
SandboxState
Secțiune intitulată „SandboxState”| Stare | Descriere |
|---|---|
created |
Specificația a fost creată, dar VM-ul nu a pornit încă |
warm |
Rulează și este gata să execute comenzi |
active |
Execută în prezent o comandă |
suspended |
Pauzat / salvat ca punct de control pe disc pentru a economisi RAM |
destroyed |
Desființat; handle-ul nu mai este valid |
error |
Lansarea a eșuat — vezi SandboxHandle.error |
Evenimente de sandbox
Secțiune intitulată „Evenimente de sandbox”| Tip de eveniment | Descriere |
|---|---|
stdout |
Ieșirea standard a sandbox-ului |
stderr |
Eroarea standard a sandbox-ului |
exit |
Procesul sandbox-ului s-a încheiat (poartă exitCode) |
starting |
Sandbox-ul pornește |
ready |
Sandbox-ul este gata să accepte apeluri exec |
killed |
Procesul a fost omorât de gazdă (OOM, timeout, oprire manuală) |
violation |
O politică de sandbox a fost încălcată (poartă un SandboxViolation) |
SandboxViolation
Secțiune intitulată „SandboxViolation”| Câmp | Tip | Descriere |
|---|---|---|
action |
String |
Verbul refuzat (de ex. file-read*, network-outbound) |
target |
String |
Calea sau gazda care a fost ținta operației refuzate |
raw |
String? |
Linia brută de jurnal, utilă pentru depanare |
- Sandbox și securitate
- Politici de sandbox
- Guardrail-uri
- CLI cc_server: flag-ul
--sandbox