CreaRack-SL

Cadena de fallback del bootstrap — current → previous → embebido

Descripción

El bootstrap del Agente nunca intenta ejecutar código inexistente. Implementa una cadena de fallback escalonada:

  1. current.txt → apunta a app-CURRENT.zip (paquete publicado en el servidor).
  2. previous.txt → apunta a app-PREVIOUS.zip (versión anterior, guardada tras un update exitoso).
  3. Embebido en el .exe → código que viaja en el bootstrap (último recurso).

Si cualquier punto de la cadena falla (paquete corrupto, firma inválida, no existe), el bootstrap baja al siguiente nivel.

Invariante

El bootstrap SIEMPRE tiene código ejecutable — la cadena garantiza que al menos el nivel embebido existe (está en el .exe).

Flujos de ejecución

1. Arranque normal

Lee current.txt
  ├─ Existe y pasa SHA-256 + Ed25519 → Extrae app-CURRENT.zip, lanza app_main.py
  └─ Falla (corrupto / modificado / no existe) → Intenta previous
          ├─ Existe y pasa verificación → Extrae app-PREVIOUS.zip, lanza
          └─ No existe o falla → Extrae código embebido del .exe, lanza

2. Update exitoso

Descarga app-X.Y.Z.zip desde servidor
Verifica SHA-256 + Ed25519
Extrae y prueba (gate --selftest)
Genera puntero: current.txt → app-X.Y.Z.zip
Guarda backup: previous.txt ← app-ANTERIOR.zip (que estaba en current)
Relanza bootstrap

3. Update fallido + rollback

Descarga app-X.Y.Z.zip
Verifica OK
Extrae y lanzan → FALLA en --selftest o en primer arranque
Watchdog detecta (health check fallido)
  ├─ Reintenta app-X.Y.Z una vez (cubre abort transitorio)
  └─ Si reintento falla:
        ├─ Si existe previous.txt → Restaura current.txt ← previous.txt, relanza
        └─ Si NO existe previous.txt → Borra current.txt, cae al embebido

Implementación

Bootstrap (terminal/agent/bootstrap.py)

def load_app_main():
    # 1. Try current
    if current_exists() and verify_signature(current):
        return extract_and_run(current)
    
    # 2. Try previous
    if previous_exists() and verify_signature(previous):
        return extract_and_run(previous)
    
    # 3. Fall back to embedded
    return extract_embedded_and_run()

Updater (core/pkg_updater.py)

  • Descarga y verifica.
  • Genera puntero atómico (current.txt).
  • Guarda backup de anterior (previous.txt).
  • Watchdog reintenta + fallback.

Casos de uso que resuelve

CasoSin cadenaCon cadena
Update con paquete corruptoAgente muerto, manual fixRollback a previous automático
AV bloquea paquete en arranqueMuertoReintenta, luego previous/embebido
Primera transición de embebido a paqueteprevious.txt vacío, rollback rotoBorra current.txt, cae a embebido
Servidor offline (no puedo actualizar)Agente esperando update infinitoEjecuta current o previous normalmente
Cliente reinstala desde setup-stubCódigo embebido garantizado✓

Densidad de la cadena

La cadena es más fuerte cuanto más paquetes se han actualizado exitosamente:

  • 1ª ejecución (desde setup-stub): solo embebido disponible.
  • Tras 1er update exitoso: current + embebido (previous vacío).
  • Tras 2º update: current + previous + embebido (máxima fortaleza).

Una máquina que nunca actualiza indefinidamente sigue siendo funcional (embebido).

Testing

  • tests/agent/test_agent_launcher.py:
    • Verificación de paquete corrupto → fallback.
    • AV bloquea en arranque → rollback.
    • previous.txt vacío → caída a embebido.
    • Marker de extracción → idempotencia.

Véase también

  • [[feature—agent-lanzador—rollback-silencioso-infalible]]
  • [[feature—agent-lanzador—bootstrap-zip]]
  • [[feature—agent-lanzador—paquete-firmado-ed25519]]
  • [[concept—agent-lanzador—plan-f3]]
  • [[incident—20260707—bootstrap-2-14-0-roto]]