- **R-1 — Discord puede encolar tareas `tests` / `pr_review` que el worker después
deniega.** El usuario recibe una confirmación de encolado de algo que no llegará
a ejecutarse. Es comportamiento conocido, **no resuelto en 6.36.0** y **diferido
al siguiente release**. No debe interpretarse como una capacidad operativa
válida.
- **R-3** (P3) — un test puede producir volumen excesivo de salida en ciertas
ejecuciones focalizadas (higiene de CI / disco). Deuda **post-release**.
- **R-4** (P3) — `_TAREAS_API` registra owner/contexto que la ruta in-process no
consume para revalidar. Deuda arquitectónica **post-release**, sin bypass.
Fixed
- TOCTOU en `_validar_ruta_segura`: la validación y la apertura ahora son atómicas.
- Symlinks que apuntan fuera del proyecto ya no se siguen (`O_NOFOLLOW`).
- Cobertura: añadidos 21 tests en `tests/test_file_safety.py`.
- `mcp_client`: `KeyError` no manejado en `_enviar`/`_esperar_respuesta` al
reutilizar un proceso muerto tras un fallo de `stdin`.
- `mcp_client.list_tools`: valida el tipo de los elementos y filtra los que no
son `dict`; cobertura del módulo 22% → 87%.
- Baseline de esta release: **3130 passed, 43 skipped, 0 failed**.
Changed
- **BREAKING (comportamiento)**: el modelo de decisión del sandbox cambió de
blocklist a **default-deny**, con clasificación en 3 niveles
(`sandbox_utils.clasificar_comando`):
1. *Allowlist*: comandos sin metacaracteres de shell (`| ; > & $(...) \``
`$VAR`) cuyo binario base está en `sandbox_allowlist_binarios` →
ejecución directa (fricción cero).
2. *Default-deny*: cualquier otro comando (pipes, redirecciones, expansión
de variables, binarios fuera de la allowlist, casos explícitos como
`eval`, `base64 -d | sh`, `mkfs`, `shred`, `truncate`, escrituras a
`/dev/*`) → sandbox Docker obligatorio, sin confirmación adicional más
allá de la que ya aplique `permisos.json`.
3. *Blocklist legacy* (`es_comando_peligroso`, intacta): defensa en
profundidad — ya no decide sandbox sí/no; si un comando la matchea se
muestra un warning más explícito (con el patrón que disparó) antes de
confirmar.
- **BREAKING (procesos en background)**: `_lanzar_proceso_fondo` (estado.py)
sin sandbox activo aplica ahora la misma clasificación: los comandos que
antes corrían simplemente por no estar en la blocklist (p. ej.
`flutter run`) **se rechazan** si su binario no está en la allowlist.
- Nueva clave de configuración `sandbox_allowlist_binarios` (nivel superior
de `~/.snapcontext/config.json`; ejemplo en `config.example.json`): lista
de binarios con ejecución directa. Si se define **sobrescribe completa** la
lista por defecto (no hace merge). Por defecto:
`ls, cat, head, tail, wc, stat, file, diff, tree, grep, rg, git, pytest,
ruff, mypy, black, isort, npm, pip, pip3, echo, which, date`.
- `--no-sandbox` sigue forzando ejecución directa, pero los comandos fuera de
la allowlist ya no pasan en silencio: piden confirmación explícita
mostrando el motivo (y abortan en modo `--auto`/stdin no interactivo).
- Motivación: la blocklist regex anterior era trivialmente evadible
(`echo <b64> | base64 -d | sh`, `python -c 'shutil.rmtree("/")'`,
`find / -delete`, `eval "$VAR"`, heredocs, expansión de variables). Tests
nuevos en `tests/test_sandbox_inteligente.py` (un caso por evasión,
allowlist con metacaracteres, `--no-sandbox` y gate de background).
Migración
- Comandos de tu flujo habitual que antes corrían directo y ahora piden sandbox o
confirmación, revisa `sandbox_allowlist_binarios` en tu `~/.snapcontext/config.json`
y añade los binarios específicos de tu stack (p. ej. `flutter`, `dart`, `cargo`, `go`).
Recuerda que la lista definida **reemplaza** la por defecto: copia primero
la lista base de `config.example.json` y agrega los tuyos.
- Escrituras: convierte en relativas las rutas absolutas dentro del proyecto.
- Gateway Web: arranca con `--workspace-root` explícito si no es loopback, y genera
la credencial con `preparar_credencial_inicio()` (permisos `0600`).
- **Sin migración posible** (restricciones por diseño en 6.36.0): ejecución remota,
instalación remota de plugins y los tipos de tarea `tests`/`pr_review`.