Prescan explícito de Windows Defender ANTES del swap (ADR: cerrar s201 · cierre diagnóstico auto-update)
Contexto
El auto-update del Agente sufría fallos aleatorios no-deterministas que NO se producían con instalación manual del mismo binario. Diagnóstico s201 (activo desde 03-07-2026).
Carrera crítica: El instalador del navegador tarda minutos entre descargar el .exe y ejecutarlo (el usuario hace click). En ese tiempo, Windows Defender completa su análisis cloud. El auto-update descarga y ejecuta en segundos → el análisis está a medias → MpCmdRun (protección cloud de Defender) retiene la extracción del onefile del binario congelando el arranque sin matarlo.
Observación del watchdog de 2.13.4: Detectó “process alive but not responding” tras 30 segundos y decidió: “debe estar roto, killamos y hacemos rollback”. Pero el proceso NO estaba roto, estaba retenido. Resultado: rollback de un binario funcional.
Decisión
Prescan proactivo de Defender ANTES del swap (nuevo en 2.13.5):
- En
_apply_swap(), antes de_selftest_new_exe(), llamar a_defender_prescan(NEW_EXE) _defender_prescanejecutaMpCmdRun -Scan -ScanType 3 -File <path>(síncrono, 180 s timeout)- Al terminar, el análisis es “conocido” y el primer arranque post-swap behave como el de la instalación manual
- Best-effort: sin MpCmdRun (Linux CI, otro AV), se salta con traza
Rationale
- Replicar el tiempo “muerto” del flujo manual: 30-60 segundos de análisis pre-ejecución
- Más simple que esperar pasivamente: no podemos pedir al usuario que espere; el prescan los hace al Agente (la máquina que se actualiza)
- No depende de certificados: Windows Defender es gratis + built-in en Windows 10/11
- Alineación con watchdog paciente (2.13.5): el sondeo de 10 s cada 150 s da tiempo al prescan + análisis + arranque inicial del binario nuevo
Alternativas consideradas (y rechazadas)
| Alternativa | Motivo del rechazo |
|---|---|
| Esperar 60 s entre descarga y swap | Dejaría el Agente sin servicio 60 s innecesariamente; el prescan es más eficiente |
| Bajar la confianza del certificado de código (pagar) | Costo O(100 €/año); Defender es gratis |
| Habilitar análisis offline (descarga local de sigs) | O(150 MB) en el onefile; sin garantías offline en máquinas con blue screen |
| Usar VirusTotal o similar | Dependencia externa + latencia + límites de rate; incompatible con aire cerrado |
Implementación
Archivo: terminal/agent/core/updater.py
def _defender_prescan(path) -> None:
"""Fuerza el análisis de Defender ANTES del primer arranque post-swap."""
import subprocess
mpcmdrun = os.path.join(os.environ.get("PROGRAMFILES", r"C:\Program Files"),
"Windows Defender", "MpCmdRun.exe")
if not os.path.exists(mpcmdrun):
_wlog("prescan Defender omitido (MpCmdRun no encontrado)")
return
try:
proc = subprocess.run(
[mpcmdrun, "-Scan", "-ScanType", "3", "-File", str(path)],
capture_output=True,
timeout=180,
creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0),
)
# rc 0 = limpio · rc 2 = amenaza (self-test posterior fallará → swap abortado)
_wlog(f"prescan Defender del staged: rc={proc.returncode}")
except Exception as e:
_wlog(f"prescan Defender fallo (no bloqueante): {type(e).__name__}: {e}")
Invocado en _apply_swap() antes del self-test.
Verificación
3 tests en tests/agent/test_agent_updater_trace.py:
- Watchdog contiene
WaitHealthyy pollea cada 10 s (regresión contra 2.13.4) - Prescan se salta sin MpCmdRun (CI + otro AV)
version.txtse reconcilia tras rollback
Impacto
- ✅ Cierre de s201: primer rescate autónomo del watchdog se recupera sin revertir versiones buenas
- ✅ Instalación manual y auto-update ahora comparten el mismo “tiempo de análisis”
- ✅ Sin impacto en máquinas sin Defender (se salta gracefully)
- ✅ Sin cambios de UI, help, o documentación pública
Véase también
- [[feature—terminal—auto-update-self-healing-2-13-5]]
- [[feature—terminal—traza-persistente-swap-auto-update]]
- [[concept—general—como-funciona-el-mecanismo-de-auto-update-del-local-agent]]
- [[incident—20260705—s201-auto-update-falla-aleatorio]]