# Changelog ## [1.1.4] - 2026-07-31 Recoge todo lo que sigue de esta sección y **sustituye a 1.1.3**, cuyo artefacto publicado se generó antes de los arreglos: su `install.ps1` no traía `-UpdateInPlace` y su binario llevaba el `runner.py` que ignoraba `--headless` en Windows. Actualizar con él mataba el agente, cambiaba la tarea programada a SYSTEM y la dejaba sin arrancar, porque Qt no puede crear su plataforma como SYSTEM en la sesión 0 sin `offscreen`. Los paquetes genéricos de Gitea son inmutables, así que se quema el número en lugar de reemplazar 1.1.3: dos contenidos distintos con la misma versión fue exactamente lo que hizo caro el diagnóstico. Hay que reconstruir los binarios aunque el código ya estuviera arreglado, porque `__version__` va compilado dentro del ejecutable y el PANEL compara el sello `config/.version` contra la versión que creía estar instalando. ## [Sin publicar] ### La actualización de Windows decía que funcionó y no cambiaba nada Actualizar sobre un servidor con el agente en una carpeta **no estándar** terminaba en verde y dejaba el servidor con la versión anterior. La causa: todo el camino de Windows identificaba al agente por **nombre**, mientras que lo único que se actualiza se identifica por **ruta**. - **`install.ps1` alinea la tarea programada con el binario instalado.** `Start-ScheduledTask` ejecuta la ruta registrada en la acción de la tarea, no el `-Prefix`: si difieren, se copiaba el binario nuevo en un sitio y se arrancaba el viejo del otro. Ahora se reapunta la tarea conservando disparador, principal, ajustes y argumentos; si no se puede corregir, **falla**. - **La confirmación de arranque mira la ruta del proceso**, no solo su nombre. Un agente viejo que nunca se detuvo satisfacía igual de bien un `Get-Process -Name CloudRestoreAS`. Si la ruta no es legible —un proceso de SYSTEM no la expone a una cuenta sin elevación— se acepta por nombre y se avisa, en vez de revertir una actualización correcta por falta de información. - **Nuevo `scripts/emular-actualizacion-windows.ps1`**: reproduce el escenario completo con un agente falso, sin elevación y sin tocar la instalación real de la máquina. Es lo que destapó este defecto y el siguiente. - **Corregido `Merge-EnvFile` con un `config\.env` de una sola línea.** Al asignar la salida de un `if`, PowerShell desenrolla un array de un elemento a escalar, así que `$lines.Count` reventaba bajo `Set-StrictMode` y la siembra de credenciales abortaba la instalación. ### Instalación y actualización desatendidas en Windows El instalador de Windows nunca recibió la maquinaria de actualización segura que sí tiene `install.sh`, y la asimetría se notaba en producción: actualizar desde el PANEL dejaba el servidor sin agente, o fallaba con un error que no correspondía. - **`install.ps1 -UpdateInPlace`**: actualiza una instalación existente conservando su tarea programada y su configuración, y sin correr el bootstrap (una segunda instancia purgaría el `Temp\` de la que está viva). Es el modo que usa el PANEL para actualizar. - **No se interrumpe una restauración en curso** (`Temp\` no vacío): sale con **75** (`EX_TEMPFAIL`), que el PANEL traduce a "reintenta luego". Windows no tenía esta guarda y una reinstalación a destiempo se llevaba por delante el respaldo que se estuviera restaurando, dejándolo vetado y la base en `SINGLE_USER`. - **Respaldo y reversión automática**: si el binario nuevo no arranca, se vuelve al anterior. El respaldo solo se descarta tras confirmar que la versión nueva corre. - **Rearranque garantizado en todos los modos.** La detención corría siempre, pero solo `-Service` volvía a arrancar algo: actualizar con `desktop` o `none` mataba el agente y se iba sin dejar señal. - La espera a que el SO libere el `.exe` pasa de 5 s a 30 s con reintentos de la copia: con un antivirus escaneando un onefile de ~270 MB, 5 s se quedaban cortos y la copia abortaba. - Se distingue **"no es administrador"** de **"es administrador con el token filtrado por UAC"**, que es lo que recibe una sesión de OpenSSH. Se veían idénticos y el remedio es el opuesto: el segundo no se arregla cambiando de cuenta sino con `LocalAccountTokenFilterPolicy`. ### `--headless` ahora funciona en Windows `_ensure_qt_platform()` salía de inmediato en `win32`, así que la bandera no hacía nada ahí. La tarea ONSTART corre como SYSTEM en la sesión 0, sin escritorio interactivo, y arrancaba con el plugin Qt `windows` intentando crear una ventana real. En Linux el mismo modo funcionaba porque el unit de systemd fija `QT_QPA_PLATFORM=offscreen` por fuera, y esa asimetría escondió el defecto. Ahora `--headless` fuerza `offscreen` en todas las plataformas y no se muestra ventana. ### Documentación - `README.md` afirmaba que la app no puede correr como servicio de Windows y sugería NSSM, lo que contradecía a `install.ps1` desde que existe. Corregido. - `packaging/LEEME.txt` solo documentaba el camino manual para Windows; ahora incluye el instalador, igual que ya hacía para Linux. ## [1.1.0] - 2026-07-29 ### Distribución e instalación automatizada vía Gitea + PANEL #### Publicación de versiones - Artefactos con versión en el nombre: `CloudRestoreAS--{linux,win}-.{tar.gz,zip}`, más `SHA256SUMS` y `release.json` (manifiesto con sha256, tamaño y deps embebidas). - `packaging/scripts/publish-release.sh`: publica en los paquetes genéricos de Gitea (`ADUANASOFT/generic/cloudrestoreas/`) y **verifica el sha256 contra la propia API de Gitea** antes de dar la publicación por buena. Soporta `--dry-run`, `--force` y `--notify-panel`. - `build-all.sh --publish` encadena build → empaquetado → publicación. Se niega a publicar si falta una plataforma: los paquetes genéricos son inmutables y corregirlo quemaría el número de versión. #### Contrato con el PANEL - `POST /api/restore/instance-config` ahora reporta también `platform` y `arch`, para que el PANEL sepa qué artefacto le corresponde a cada servidor. - `processed_folder` ya se envía en ese mismo reporte (antes se calculaba, no se mandaba). #### Instaladores - **Nuevo `install.ps1`**: instalador de despliegue Windows, autocontenido. Registra una tarea programada ONSTART como SYSTEM para el 24/7 headless — sin NSSM ni descargas en el servidor destino. Detiene la instancia en ejecución antes de reemplazar el `.exe`. - El antiguo `install.ps1` (preparación del entorno de desarrollo: Python, venv, pip) se movió a `scripts/dev-setup.ps1`. **Se estaba empaquetando por error** en el zip del ejecutable autocontenido, que no necesita nada de eso. - `install.sh` e `install.ps1` aceptan `--panel-env-file` / `-PanelEnvFile`: fusionan las claves `CLOUDRESTORE_PANEL_*` en `config/.env` (replace-or-append, idempotente, con lista blanca) y borran el archivo. El token viaja por archivo 0600, nunca por argumentos, para que no quede visible en `ps` ni en el historial del destino. - `install.sh` detiene el servicio antes de reemplazar el binario y lo vuelve a levantar si estaba activo. (La razón que se dio aquí —que un ELF en ejecución da `ETXTBSY`— era incorrecta: eso le pasa a `cp`, no a `install`, que desvincula el destino antes de crearlo. Ver BUILD.md.) #### Versionado - `app/__init__.py` es la fuente única de la versión; el diálogo *Acerca de* ya no la trae hardcodeada. - Flag `--version` en el binario, y sello `config/.version` que escribe el bootstrap (el instalador remoto lo lee por SFTP, porque el `.exe` se compila con `console=False`). - El `.exe` ya lleva metadatos de versión de Windows (`VSVersionInfo`). #### Correcciones - `config/7zip` y `config/odbc` se re-despliegan cuando el build trae otras versiones embebidas, comparando un sello con el sha256 de `bundled-versions.json`. Antes solo se copiaban si la carpeta estaba vacía, así que una actualización con driver ODBC nuevo conservaba el viejo indefinidamente. ## [1.0.0] - 2026-01-25 ### Lanzamiento Inicial #### Características Principales - ✅ Interfaz gráfica completa con PySide6/Qt - ✅ Motor de procesamiento concurrente con workers configurables - ✅ Vigilancia automática de carpeta de entrada - ✅ Soporte para archivos ZIP multipart (.zip.001, .zip.002, etc.) - ✅ Extracción automática con 7-Zip - ✅ Restauración automática de bases de datos SQL Server - ✅ Sistema de mapeo de nodos (archivo → base de datos) - ✅ Minimización a bandeja del sistema (system tray) - ✅ Base de datos SQLite para métricas y auditoría - ✅ Logging rotativo con múltiples niveles - ✅ Cifrado de contraseñas con DPAPI - ✅ Soporte Windows Auth y SQL Auth - ✅ Modo Dry Run para pruebas - ✅ Detección de estabilidad de archivos - ✅ Soporte para marcador .ready - ✅ Timeouts configurables - ✅ Tolerancia a fallos y manejo de errores #### Tabs de la Interfaz - Dashboard: Estadísticas en tiempo real - Jobs: Gestión y visualización de jobs con detalles - Nodos: CRUD de mapeos nodo → base de datos - Configuración: Configuración completa de la aplicación - Logs: Visualización de eventos y logs #### Base de Datos - Tabla `jobs`: Registro completo de jobs - Tabla `job_steps`: Pasos detallados de cada job - Tabla `nodes`: Mapeos de nodos - Tabla `events`: Log de eventos - Tabla `config`: Configuración persistente #### Documentación - README.md: Documentación completa - QUICKSTART.md: Guía rápida de inicio - ADVANCED.md: Configuración avanzada - SCRIPTS.md: Ejemplos de scripts de automatización #### Scripts Incluidos - `runner.py`: Punto de entrada principal - `install.ps1`: Script de instalación automática - `build.ps1`: Script para generar ejecutable con PyInstaller - `test_installation.py`: Script de verificación de instalación #### Requisitos del Sistema - Windows 10/11 o Windows Server 2019/2022+ - Python 3.11+ - 7-Zip - ODBC Driver 17 for SQL Server - SQL Server 2016+ (destino de restauraciones) #### Dependencias - PySide6 >= 6.6.0 - pyodbc >= 5.0.0 - pywin32 >= 306 ### Características Futuras Planificadas #### v1.1.0 (Próximo Release) - [ ] Reintentos automáticos configurables desde UI - [ ] Notificaciones por email - [ ] Verificación de espacio en disco antes de procesar - [ ] Soporte para múltiples instancias SQL Server - [ ] Importación/Exportación de nodos desde CSV - [ ] Dashboard mejorado con gráficos - [ ] Filtros avanzados en tabla de jobs #### v1.2.0 (Futuro) - [ ] API REST para integración externa - [ ] Webhooks para notificaciones - [ ] Programación de restauraciones (scheduling) - [ ] Soporte para otros formatos de compresión (RAR, TAR) - [ ] Modo cluster (múltiples instancias coordinadas) - [ ] Soporte para Azure SQL Database - [ ] Backup/Restore de configuración desde UI #### v2.0.0 (Largo Plazo) - [ ] Soporte multiplataforma (Linux) - [ ] Interfaz web opcional - [ ] Modo servicio de Windows - [ ] Soporte para PostgreSQL y MySQL - [ ] Machine learning para predicción de tiempos - [ ] Dashboard en tiempo real con WebSockets ### Problemas Conocidos #### Limitaciones Actuales - Solo soporta una configuración SQL Server (no múltiples instancias) - Reintentos automáticos no expuestos en UI (requiere edición manual) - No hay verificación automática de espacio en disco - System tray no muestra notificaciones toast - No hay soporte nativo para archivos RAR #### Workarounds Documentados - Múltiples instancias SQL: Ver ADVANCED.md sección 7 - Notificaciones: Ver SCRIPTS.md para monitoreo externo - Limpieza automática: Ver SCRIPTS.md para scripts de limpieza ### Notas de Seguridad - Las contraseñas se cifran con DPAPI (vinculadas a usuario/máquina) - Los logs pueden contener información sensible (rutas, nombres de DB) - Se recomienda ejecutar con cuenta de servicio dedicada - Asegurar permisos apropiados en carpetas de trabajo ### Agradecimientos Desarrollado por el equipo de Aduanasoft para automatización de restauraciones de bases de datos SQL Server. --- **Nota de Versión**: Esta es la versión inicial de CloudRestoreAS. Se agradecen comentarios y sugerencias para futuras versiones.