🛡️ sandbox-labs GitHub ↗

📊 Estado del proyecto#

Este documento responde a una sola pregunta: qué está construido de verdad, qué lo demuestra y qué falta.

La regla que lo gobierna es la del proyecto entero: no se indica que algo fue probado si no se ejecutó la prueba, y no se ocultan los errores. Por eso aquí no aparece la palabra «listo» en ningún sitio, y cada afirmación de que algo funciona viene con el comando que hay que ejecutar para comprobarlo.

Versión: 0.1.0 · Última revisión: 2026-08-07


Resumen en tres nĂşmeros#

ConstruidoDel total
NĂşcleo de aislamiento9 de 9 controlesâś… completo y verificado en CI
Casos técnicos15de 15, con código
Casos de mercado de capitales21de 21, con cĂłdigo

Los 36 casos del catálogo tienen código y prueba que se ejecuta en cada commit. Ninguno llega a verified: para eso hace falta evidencia firmada por ejecución, y todavía no la emiten. Esa es la distancia que queda, y está medida.


Lo que se puede ejecutar hoy y comprobar#

Cinco comandos que corren en cada commit, no en un documento:

cargo run -p sandboxctl -- escape

Ocho sondas intentan escaparse del sandbox: red, PIDs, memoria, sistema de ficheros, capacidades, dispositivos, entorno y llamadas al sistema. La suite declara bwrap [experimental] sin fugas (8 contenidas) y, si alguna se escapa, CI se pone rojo. Hay además una línea base con native que debe escaparse: si no lo hace, la suite no está midiendo nada.

cargo run -p sandboxctl -- evidence verify

Verifica que cada acta de ejecución se sostiene: la huella SHA-256 coincide con el documento, la firma Ed25519 es válida, la cadena con la evidencia anterior no está rota, y los hashes de la política y de la carga corresponden a lo que hay en el repositorio.

cargo run -p sandboxctl -- markets reconcile

Seis escenarios de custodia, cada uno con el hallazgo que debe producir. Si la conciliaciĂłn deja de detectar un descuadre que declara detectar, CI se pone rojo.

cargo run -p sandboxctl -- markets check

Los 19 casos de mercado de capitales con código, con 119 escenarios que declaran de antemano qué debe salir de cada uno. Si alguno deja de detectar lo que dice detectar, CI se pone rojo.

node scripts/verify-cases.mjs

Prueba de comportamiento de los casos técnicos. Hoy cubre el caso 01 con diez comprobaciones. Un caso en estado ready sin prueba aquí hace fallar la suite: es el guardián de que el estado declarado sea cierto.


Núcleo de aislamiento — completo#

Los nueve puntos del backlog técnico están cerrados, cada uno verificado empíricamente en WSL2 con bubblewrap 0.9.0 real y confirmado en CI.

#Qué se cerróCómo se aplica de verdad
B-01LĂ­mite de procesospids.max vĂ­a cgroups v2, pedido con systemd-run --user --scope
B-02LĂ­mite de memoriamemory.max, con observaciĂłn de memory.peak y oom_kill
B-03LĂ­mite de CPUcpu.max, con lectura de cpu.stat durante la ejecuciĂłn
B-04Red por lista de permitidosNamespace de red propio + proxy por socket Unix que habla CONNECT host:port y registra cada intento, permitido o no
B-04bPuerto publicado con red contenidaEl servicio escucha en un socket Unix dentro de la jaula; un reenviador fuera publica el puerto TCP
B-05Llamadas al sistemaFiltro seccomp BPF compilado con seccompiler y entregado a bubblewrap por descriptor de fichero
B-06UID y GID--uid / --gid en un namespace de usuario, sin privilegios
B-07Compilador único de argumentosUn solo sitio traduce política → argumentos de bubblewrap. Antes había varios y divergían
B-08Integridad de la evidenciaHuella → firma Ed25519 → cadena entre actas → rehash de política y carga

La regla que lo gobierna todo#

Un control solicitado, un control aplicado y un control reportado tienen que describir la misma realidad.

Por eso toda acta distingue cinco listas: requestedControls,

obligatorio que este equipo no puede aplicar, la ejecución no ocurre: falla cerrada y explica qué falta. El detalle está en Referencia de políticas y en Formato de evidencia.


Casos técnicos — 15 de 15 con código#

#CasoEstadoQué hayQué falta
01Contenido web no confiable🟡 buildingCoordinador e intérprete separados por proceso, 15 tipos de rechazo, 10 comprobaciones automáticasFicha en el panel; levantar el servicio bajo bwrap dentro de CI
02Código generado por IA🟡 buildingEjecución sin red, entorno vacío, disco temporal, techo de tiempoRediseño: un sandbox efímero por ejecución, con cola y cancelación. Más lenguajes
03Procesamiento de archivos🟡 buildingzip slip, zip bomb, rutas absolutas, enlaces, informe por entradaRenombrar a 03-safe-archive-processing; MIME real, más formatos, checksum
04Plugins de terceros🟡 buildingManifiesto, concesión traducida a montajes y red, registro de intentos · 8 comprobacionesLos seis plugins de ejemplo; flujo de aprobación en el panel
05Custodia de claves y firma🟡 buildingFirma Ed25519 en la jaula, red none, socket Unix, clave fuera del repositorioDividir: el determinismo se va al caso 07. Límites de monto, rotación, revocación
06–15Los diez restantes🟡 buildingUn núcleo por caso con 62 comprobaciones entre todos, y su servicioLevantarlos bajo bwrap en CI; evidencia firmada. 06 y 14 necesitan además KVM

Ninguno está en ready. Los núcleos se comprueban —80 comprobaciones entre los doce casos con prueba—, pero ninguno se levanta bajo bwrap dentro de CI ni emite evidencia firmada por ejecución, que es el requisito para verified.


Mercado de capitales — 21 de 21 con código#

Sin dinero real, sin valores reales, sin credenciales reales y sin conectividad de producciĂłn. El simulador no es una autorizaciĂłn regulatoria de la CMF ni de ninguna otra autoridad, y nada de lo que produzca es una recomendaciĂłn de inversiĂłn.

La base: construida y probada#

El crate sandbox-markets tiene las dos piezas de las que dependen todos los casos financieros:

Pesos y dĂłlares no se suman porque no compila. Nunca coma flotante: un f64 no representa 0,10 de forma exacta, y en un libro contable eso es un descuadre que aparece tarde y en producciĂłn.

transacciĂłn que no cuadra no se registra.

Los casos#

#CasoEstadoQué hayQué falta
CM-02Sistema alternativo de transacciĂłnđźź  prototypeLibro de Ăłrdenes con 11 invariantes: prioridad precio-tiempo, precio fijado por la orden que descansa, libro nunca cruzadoLos 7 escenarios; Ăłrdenes de mercado; reconstrucciĂłn completa de la sesiĂłn
CM-03Custodia y segregación de activos🟢 functionalEl invariante de custodia, 5 tipos de hallazgo, 6 escenarios verificados en cada commitDividendos, bloqueos, garantías, insolvencia del custodio
CM-00, CM-01, CM-04–CM-20Los diecinueve restantes🟠 prototypeUn módulo por caso con su modelo y 119 escenarios que se ejecutan en cada commitEvidencia firmada por ejecución; datos que no sean los suyos

Lo que está construido y no se ve#

Piezas que no son un caso pero sostienen todo lo demás:

PiezaDóndeQué hace
Compilador de polĂ­ticascrates/sandbox-core/src/compiler.rsEl Ăşnico sitio que traduce una polĂ­tica a argumentos de bubblewrap
cgroups v2crates/sandbox-core/src/cgroup.rsPide lĂ­mites por systemd-run y observa lo que realmente se consumiĂł
seccompcrates/sandbox-core/src/seccomp.rsCompila el filtro BPF y lo entrega por descriptor de fichero
Proxy de salidacrates/sandbox-core/src/egress.rsLista de permitidos sin comodines, con registro de cada conexiĂłn
Firma de evidenciacrates/sandbox-core/src/signing.rsEd25519, clave local con permisos 0600, fuera del control de versiones
Reenviador de puertoscrates/sandboxctl/src/forward.rsPuente TCP ↔ socket Unix, para publicar sin dar red a la jaula
Barrido de huérfanoscrates/sandboxctl/src/service.rsservice down --all mata también lo que quedó vivo sin registro

Esa última línea existe por un incidente real de este proyecto: tres sandboxes sobrevivieron cuatro horas sin que nada pudiera encontrarlos, porque se había quitado --die-with-parent y un script de limpieza había borrado sus registros. Está contado en RUNBOOK.


Lo que se decidió no hacer, y por qué#

DecisiĂłnMotivo
No usar npm, sino pnpmFicheros de bloqueo deterministas y una Ăşnica forma de instalar
No usar libseccomp (C), sino seccompiler (Rust puro)Evitar una dependencia nativa que rompe la construcciĂłn reproducible
No escribir cgroups directamenteEn WSL2 /init.scope no es escribible; systemd-run --user --scope funciona en ambos
Vaciar el entorno con env -i en vez de quitar variables una a unasystemd inyecta variables propias; quitarlas de una en una siempre deja alguna
No incluir malware real, ni siquiera para el caso 06Regla del proyecto, sin excepciones
No conectar con ningĂşn sistema financiero realRegla de la familia de mercado de capitales, sin excepciones

Los estados y lo que significan#

EstadoQué significa exactamente
plannedEspecificado, sin cĂłdigo
prototypeCĂłdigo que corre, sin prueba de comportamiento
functionalSe ejecuta y hay una prueba concreta que lo demuestra
verifiedAdemás emite evidencia firmada y CI la valida
production-researchInvestigaciĂłn, no desplegable
deprecatedSe conserva por compatibilidad

Qué sigue#

El orden no es arbitrario: cada elemento desbloquea al siguiente.

  1. Caso 01 a functional — levantarlo bajo bwrap en CI y añadir su ficha al

panel.

  1. Caso 04 — plugins por capacidades. Se apoya en el proxy de salida, que ya

existe.

  1. CM-02 a functional — reconstrucción completa de la sesión, que es

requisito previo de CM-09.

  1. Caso 02, el rediseño — sandbox efímero por ejecución.
  2. CM-00 — la puerta de la familia financiera: sin ella, los demás casos no

tienen lĂ­mites que respetar.


Ver también: Catálogo completo · Fichas de los casos · Cuando algo falla · Backlog de implementación · Runbook