CreaRack-SL

Local Agent — Auto-update silencioso (técnica)

Qué es

El Local Agent se actualiza solo, en silencio: el usuario nunca ve ni interviene en el mantenimiento del Agente (norma fundacional). Introducido en s176 (Local Agent 2.9.0, SaaS 1.26.0) como mitigación del riesgo §6 del EPIC Full-Local Agent — al mover toda la I/O de red al Agente, su versión se volvió crítica: un Agente viejo no tiene los endpoints nuevos y rompe features.

Arquitectura (3 piezas)

1. Publicación automática del binario (PR #203)

build_agent.bat, al terminar de compilar, sube el .exe a Hetzner: scp a /tmp en root@crearack.com + docker cp al volumen persistente app_media del contenedor web (resuelto dinámicamente con docker ps | grep -web-N, porque el sufijo cambia entre redeploys de Dokploy). Si el SSH falla, avisa pero no rompe el build. El SaaS sirve ese binario en GET /downloads/CreaRackAgent.exe.

2. Lado SaaS — anuncia y empuja (PR #204, v1.25.0)

  • core/agent_release.py: get_latest_agent_version() (lee terminal/agent/version.py, la versión con la que se compiló el .exe), get_agent_sha256() (hash del .exe servido, cacheado por mtime/size), is_outdated() (SemVer numérico), agent_update_payload().
  • GET /api/agent/manifest (terminal/api/agent_update.py, auth = JWT del Agente) → {version, sha256, url} para el chequeo al arrancar.
  • Push por WebSocket: en el heartbeat ping (terminal/consumers.py), si el Agente reporta una versión por detrás de la última, el SaaS le envía command: "agent_update" con {version, sha256, url}. Dedup por versión reportada (no re-empuja cada 30 s).
  • core/views.py::download_agent: GET /downloads/CreaRackAgent.exe acepta el JWT del Agente además de la sesión de navegador (el Agente descarga con su token).

3. Lado Agente — descarga, verifica, se reemplaza (PR #205, Agent 2.9.0)

terminal/agent/core/updater.py:

  1. Recibe agent_update por el WS (o consulta /api/agent/manifest al arrancar).
  2. Descarga el .exe con su JWT a CreaRackAgent.new.exe.
  3. Verifica el SHA-256 contra el del manifest. Si no coincide → descarta (nunca ejecuta un binario sin verificar).
  4. Swap por renombrado (Windows no deja sobrescribir un .exe en marcha, pero SÍ renombrarlo): CreaRackAgent.exe → .old.exe, .new.exe → CreaRackAgent.exe, relanzar (relaunch_from_install_dir) y os._exit(0) (fiable también desde una task asyncio, donde sys.exit no terminaría el proceso). El nuevo proceso borra el .old.exe al arrancar.
  5. Solo en ocio: el swap se aplica únicamente si no hay sesiones SSH activas (network.ssh.ACTIVE_BRIDGES) — al arrancar (ocioso por definición) o cuando terminen las sesiones, para no cortar trabajo. Staging con marker update.json recuperable ante reinicio.

Decisiones de diseño

  • Silencioso, sin UI: se descartó la “Capa 1” (un banner visible avisando de versión vieja) por la norma de que la instalación/mantenimiento del Agente son transparentes para el usuario. Se implementó directamente la “Capa 2” (auto-update silencioso).
  • Disparo: push por WebSocket (inmediato para Agentes residentes) + chequeo del manifest al arrancar (robustez).
  • Seguridad: HTTPS, mismo origen, descarga autenticada (JWT), verificación SHA-256 obligatoria. Pendiente/mejora futura: firma Authenticode del .exe.
  • Orden seguro garantizado por version.py como puerta: el .exe nuevo se publica al compilar, pero el SaaS solo anuncia la versión nueva al desplegar el código → nunca se ordena actualizar a una versión cuyo .exe no esté servido.

Bootstrap (importante)

El salto 2.8.0 → 2.9.0 es manual una vez (los Agentes 2.8.0 no entienden el comando agent_update). Hay que compilar e instalar la 2.9.0 en cada equipo. De la 2.9.0 en adelante, automático para siempre.

Distribución del .exe

El binario se sirve desde el volumen app_media de Hetzner vía GET /downloads/CreaRackAgent.exe (no se versiona en git, ~23 MB). Se publica con build_agent.bat (automático) o a mano (scp+docker cp, ver context/INFRA.md). El Release de GitHub agent-vX.Y.Z guarda el .exe solo de la versión en curso (referencia/respaldo).