Ir al contenido

Backends del entorno aislado

Backend Valor Plataforma Disponibilidad
VM aislada microvm macOS, Linux, Windows (hipervisor de microVM) Condicionado por el sondeo del runtime de microVM; se aplica a los terminales interactivos: el shell se ejecuta dentro de un rig, no en el host
Nativo native macOS (Seatbelt), Linux y WSL2 (bubblewrap) Se sondea al arrancar; Linux rechaza una ejecución que exija denegaciones de escritura por glob de nombre de archivo, que bubblewrap no puede aplicar
Sin aislamiento none Todas El valor predeterminado al analizar, el predeterminado del terminal y el recurso de reserva cuando no hay ningún backend disponible o se ha establecido --sandbox off

SandboxBackend.fromName devuelve none cuando el valor almacenado es nulo o no se reconoce. Un "docker" almacenado se asigna a native.

microvm es el único backend con una frontera de kernel: la carga de trabajo no se ejecuta realmente en el host. Nunca es un recurso de reserva silencioso en ninguna de las dos direcciones: solicitarlo de forma explícita en un host que no puede arrancar una VM falla de forma ruidosa («pedí una VM y obtuve mi portátil» es la única degradación que el recinto no puede permitirse), y solo un predeterminado sin especificar baja a native, dejando una línea de registro que lo indica. El backend real de la sesión se comunica de vuelta al cliente y se marca con una insignia, así que un terminal nunca puede afirmar que está en un recinto mientras se ejecuta en el host. El ciclo de vida, las imágenes y la salida de red de la propia VM se tratan en la referencia de rigs.

Windows no tiene entorno aislado nativo. NativeSandboxAdapter.probe devuelve available: false en cualquier host que no sea macOS o Linux/WSL2. Por tanto, el despacho de agentes en Windows usa none. El backend microvm es aparte: está condicionado por el sondeo del runtime de microVM y se aplica a los terminales interactivos y a los rigs, no a envolver bash en el host.

El sondeo es lo que condiciona la aplicación. Se ejecuta una vez, al arrancar el servidor.

Host available Nota o indicación
macOS true sandbox-exec (Seatbelt): aislamiento de espacios de nombres, sin frontera de kernel
Linux o WSL2 con bwrap y socat true bubblewrap: aislamiento de espacios de nombres, sin frontera de kernel
Linux o WSL2 sin alguna de las herramientas false requiresInstall: true, con una indicación de instalación que nombra los paquetes que faltan
Cualquier otra plataforma false El entorno aislado nativo no se ofrece en esta plataforma

El servidor registra el resultado en una sola línea de arranque: agent sandbox ON más la nota, no OS-native agent sandbox on this host más la indicación, o agent sandbox DISABLED by --sandbox off. GET /healthz no incluye ningún campo del entorno aislado.

--sandbox / CC_SERVER_SANDBOX acepta on (predeterminado) u off. Es una renuncia, no una activación: on significa «envuelve cuando el host ofrezca un backend», nunca «exige uno».

Usa el mecanismo de entorno aislado Seatbelt de Apple (el mismo sistema que emplea macOS App Sandbox).

El perfil generado es permisivo de forma predeterminada ((allow default)) y recorta denegaciones, porque un perfil con denegación total por defecto hace que un shell interactivo sea inutilizable: hay demasiadas llamadas dyld, XPC y Mach que enumerar. La consecuencia práctica es que un agente todavía puede leer buena parte del host; tus copias de trabajo registradas están protegidas por denegaciones explícitas de escritura y de renombrado, no por invisibilidad.

  • Lecturas del sistema de archivos: denegadas para las rutas secretas (~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh, ~/Library/Keychains y el resto del conjunto de lectura denegada)
  • Escrituras del sistema de archivos: se reajustan a denegar y después se permiten subrutas explícitas, con las rutas de denegación obligatoria (archivos rc del shell, .git/hooks, la configuración de Claude, las copias de trabajo protegidas) bloqueadas incluso dentro de una raíz escribible. file-write-unlink se deniega en cada ruta denegada y en sus ancestros, de modo que un rename no puede eludir una denegación de escritura
  • Procesos: denegaciones de process-exec para los binarios siempre peligrosos, más un bloqueo a ejecutar cualquier cosa desde un directorio escribible
  • Red: restringida a los puertos del proxy en proceso más DNS: loopback no se permite sin más y los sockets Unix no se permiten. Los proxies aplican la lista de permitidos de dominios por sesión (consulta Salida de red)
  • Configuración: los perfiles se generan en cada lanzamiento a partir del SandboxSpec

Requisitos:

  • sandbox-exec (/usr/bin/sandbox-exec), presente en toda instalación de macOS: no hace falta ninguna herramienta adicional

Usa bubblewrap (bwrap) para crear espacios de nombres de montaje y de PID.

  • Sistema de archivos: crea un espacio de nombres de montaje en el que solo son visibles las rutas montadas con bind
  • Red: se ejecuta en un espacio de nombres de red no compartido; el tráfico llega a los proxies del host a través de puentes de sockets Unix de socat
  • Procesos: aislamiento del espacio de nombres de PID

Requisitos:

  • bubblewrap y socat instalados (sudo apt-get install bubblewrap socat en Debian/Ubuntu)
  • Compatibilidad con espacios de nombres del kernel (estándar en Linux moderno)

Bubblewrap puede ocultar una ruta existente, pero no puede prohibir un archivo .env, *.key o *.pem nuevo dentro de un bind escribible. La política de despacho estándar exige estas denegaciones por glob de nombre de archivo, así que hoy el despacho nativo de agentes falla en cerrado en Linux/WSL2 incluso cuando el sondeo encuentra bubblewrap. No se ejecuta con una política silenciosamente más débil. Para restaurar el despacho nativo en Linux se necesita un backend con reglas de nombre de archivo en el momento de la creación. Desactivar el entorno aislado es una renuncia explícita y sin confinamiento, no un equivalente.

Ningún entorno aislado. El proceso se ejecuta directamente en el host, con el acceso al sistema de archivos, a la red y a los procesos que tiene el host. ACP y la herramienta bash del arnés siguen recibiendo el entorno saneado y la política de comandos; Claude Code a través de NoSandboxAdapter hereda el entorno del host. Es aquello a lo que recurre el despacho de agentes en un host sin ningún backend disponible o con --sandbox off, y es el valor predeterminado del terminal cuando un cliente no indica ninguno.

El terminal se aísla según sus propias reglas, no por el sondeo del despacho. El defaultBackend de TerminalSessionService es none y cc_server no lo sobrescribe, así que una sesión de terminal ejecuta el shell del host salvo que el cliente pida native explícitamente: el panel de terminal de la aplicación de escritorio no lo hace.

Cuando se solicita native, el shell se envuelve a través de SandboxManager bajo un perfil de terminal fijo: $HOME y el directorio de trabajo de la sesión son escribibles, la red está abierta y se deniega la lectura de ~/.ssh, ~/.aws, ~/.gnupg, ~/.config/gh y ~/Library/Keychains. El token de forja de solo lectura y la pasarela de push no se aplican: son cosa del despacho. Si el envoltorio no es compatible, la sesión falla en lugar de mostrar una insignia nativa sobre un PTY del shell del host.

Cuando se lanza un entorno aislado, el acceso saliente a la red lo aplican proxies en proceso, no reglas de cortafuegos del kernel. En un host sin ningún backend disponible nada de esto se aplica, y un proceso lanzado llega a la red exactamente igual que lo haría el usuario del servidor.

  • El runtime del entorno aislado ejecuta un proxy HTTP/HTTPS y un proxy SOCKS5 en 127.0.0.1 dentro del proceso cc_server, un par por sesión restringida (http_proxy.dart, socks_proxy.dart). Las ejecuciones simultáneas no comparten un par.
  • Los procesos aislados reciben variables de entorno de proxy (HTTP_PROXY/HTTPS_PROXY → el proxy HTTP, ALL_PROXY → el proxy SOCKS; GIT_SSH_COMMAND encamina git por SSH a través del proxy SOCKS). En Linux el espacio de nombres de red no se comparte, así que los proxies son la única salida; en macOS el entorno aislado comparte el loopback del host y habla directamente con ellos.
  • El host de destino de cada conexión se compara con la lista de permitidos de dominios de la sesión; todo lo demás se deniega. Hay dos formas de comodín, cada una con exactamente un *: un *.example.com inicial coincide con cualquier subdominio (incluido a.b.example.com), pero no con el propio dominio raíz; un bedrock.*.amazonaws.com en una etiqueta intermedia coincide exactamente con una etiqueta (bedrock.us-east-1.amazonaws.com, no bedrock.evil.attacker.amazonaws.com).
  • La lista de permitidos se resuelve por sesión a partir de la línea base curada (kBaselineAllowedDomains: proveedores de LLM, alojamiento de Git, registros de paquetes), más los dominios de GitHub (kGithubDomains), más SandboxSpec.egressAllowlist. La ruta de despacho nunca pasa entradas adicionales de egressAllowlist, así que en la práctica cada ejecución recibe la línea base más GitHub.
  • Una lista fija de denegados (kBaselineDeniedDomains: endpoints de metadatos de la nube, sumideros de telemetría) prevalece sobre todas las permitidas.
  • networkEnabled: false sigue arrancando los proxies por sesión, pero la lista de permitidos está vacía, así que se rechaza toda conexión saliente. El despacho lo fija al arrancar la ejecución a partir de la regla Acceder a la red: denegar desactiva la red; permitir y preguntar primero la dejan activada.

La especificación que se pasa a SandboxPort.launch:

Campo Tipo Descripción
sessionId String Identificador estable de la sesión (normalmente el id del espacio)
workspaceId String Id del espacio de trabajo propietario
agentId String? Agente vinculado actualmente al entorno aislado, si lo hay
bindMounts List<SandboxBindMount> Montajes host→huésped; el entorno aislado solo ve las rutas del host que se enumeran aquí
networkEnabled bool (predeterminado true) Lo fija el despacho a partir de la regla de salida a la red (desactivado solo cuando se resuelve como denegar). Cuando está desactivado, los proxies por sesión siguen arrancando, pero la lista de permitidos está vacía, así que se rechaza toda conexión saliente
egressAllowlist List<String> (predeterminado []) Dominios de salida permitidos adicionales; se admiten comodines (*.example.com, más una forma intermedia de una sola etiqueta). El despacho nunca rellena este campo, así que una ejecución envuelta recibe la línea base curada más los dominios de GitHub
guestWorkdir String? Directorio de trabajo predeterminado dentro del entorno aislado; cada llamada exec puede anularlo
mode Mode (predeterminado chat) Define las reglas de escritura del sistema de archivos: chat mantiene los montajes bind escribibles; review, plan y orchestrate son de solo lectura
protectedPaths List<String> (predeterminado []) Rutas del host que nunca deben ser escribibles dentro del entorno aislado, en ningún modo
runnerStateDirs List<String> (predeterminado []) Directorios del host donde el runner guarda su propio estado, escribibles en todos los modos (el actual es un CLAUDE_CONFIG_DIR gestionado por Control Center)
execGrantRoots List<String> (predeterminado []) Árboles de directorios aprobados por el operador que vuelven a abrir el bloqueo de exec en directorios escribibles en macOS. Linux los ignora: bwrap no tiene ningún bloqueo de exec en $HOME que reabrir

protectedPaths contiene las copias de trabajo originales de los repositorios registrados, resueltas en cada despacho a partir de los repositorios del espacio de trabajo. Los agentes trabajan exclusivamente en worktrees de copia en escritura por conversación, así que los originales nunca deben ser escribibles desde dentro del entorno aislado: en macOS, el permiso general de escritura de Seatbelt sobre $HOME los dejaría si no escribibles a través de bash. Se suman al conjunto de denegación de escritura de secretos en todos los modos, chat incluido.

Cada ruta de lectura denegada y de escritura denegada se emite tanto en su forma literal como en su forma resuelta por enlaces simbólicos. El kernel compara una regla de denegación con la ruta resuelta, así que una regla escrita contra una ruta con enlaces simbólicos nunca se dispara; y en macOS ese es el caso habitual y no el exótico, ya que /tmp se resuelve a /private/tmp y /var/folders/… a /private/var/folders/…. Las entradas que contienen * o ? se tratan como globs y se dejan tal cual; una ruta que no se resuelve se conserva tal como se escribió.

Campo Tipo Descripción
hostPath String Ruta absoluta en el host
guestPath String Ruta dentro del entorno aislado (con el entorno aislado nativo es igual a hostPath; se conserva por simetría con los adaptadores)
readOnly bool (predeterminado false) Monta en solo lectura cuando es true

Lo devuelve SandboxPort.launch:

Campo Tipo Descripción
sessionId String Identificador de la sesión
backend SandboxBackend Qué backend está en ejecución
state SandboxState Estado del ciclo de vida
error Object? Se establece cuando state es error
details Map<String, Object?> Contabilidad privada del adaptador (directorio de trabajo, PID, ruta del perfil, etc.)
Estado Descripción
created Especificación creada, pero la VM aún no se ha iniciado
warm En ejecución y lista para ejecutar comandos
active Ejecutando un comando en este momento
suspended En pausa o con checkpoint en disco para ahorrar RAM
destroyed Desmontado; el handle ya no es válido
error El lanzamiento falló; consulta SandboxHandle.error
Tipo de evento Descripción
stdout Salida estándar del entorno aislado
stderr Error estándar del entorno aislado
exit El proceso del entorno aislado terminó (lleva exitCode)
starting El entorno aislado se está iniciando
ready El entorno aislado está listo para aceptar llamadas exec
killed Proceso terminado por el host (OOM, tiempo de espera agotado, parada manual)
violation Se ha infringido una política del entorno aislado (lleva un SandboxViolation)
Campo Tipo Descripción
action String El verbo denegado (p. ej. file-read*, network-outbound)
target String Ruta o host que era el destino de la operación denegada
raw String? Línea de registro sin procesar, útil para depurar