fix(install): devolver la propiedad del árbol al usuario del servicio

Instalando con sudo, el agente quedaba sin poder leer ni escribir NADA de lo
suyo, y tanto el panel como su sonda lo reportaban como éxito.

El bootstrap ejecuta el binario como root, y ese arranque crea todo el árbol bajo
PREFIX: config/, config/data/app.db, config/logs/, Entrada/, Procesados/,
Fallados/ y Temp/. La siembra escribe config/.env en 0600, también de root. Pero
el unit se registra con User=$SUDO_USER, así que el agente arranca como una
cuenta común que no puede leer su configuración (load_dotenv sin try/except),
ni guardar jobs en su base, ni mover ZIPs entre las carpetas de trabajo.
install.sh no hacía chown en ninguna parte.

Reproducido en un contenedor antes de arreglarlo: .env root:root 600, app.db y
Entrada/ de root, las tres operaciones del agente fallando — y `test -f` de la
sonda del panel dando ok, o sea verde justo en el caso roto.

SERVICE_USER se resuelve ahora al principio (antes se calculaba dentro del case
de --service, después del bootstrap y de la siembra), conservando la misma
cadena de precedencia. El chown va después de ambos pasos, solo cuando el script
corre como root y el servicio no es root, y solo del usuario —no del grupo—;
`chown` no toca los modos, así que el 0600 del .env sobrevive.

Con dos cuidados que no son opcionales:

- Guarda contra un PREFIX de sistema: un `chown -R` sobre / o /opt sería
  catastrófico. Se rechazan las rutas de sistema y las de un solo componente,
  avisando en vez de abortar una instalación ya hecha.
- Si el chown falla se reporta como ERROR con el comando de arreglo, no se traga.
  Es el mismo criterio que el repo ya aplica al icacls de Windows: no se asume
  que un comando de endurecimiento tuvo éxito.

Probado: arreglo, guarda de /opt, usuario inexistente, y sin sudo (no intenta
nada). Windows no necesita el arreglo simétrico y queda documentado por qué: la
tarea corre como SYSTEM con RunLevel Highest y install.ps1 no restringe ninguna
ACL, así que hereda de su carpeta padre y puede leer todo lo del Administrador.
This commit is contained in:
2026-07-30 16:16:28 -06:00
parent f02cd1f4c3
commit 874fe0c46f
2 changed files with 56 additions and 1 deletions

View File

@@ -193,6 +193,15 @@ switch ($Mode) {
Write-Step 'Registrando tarea programada ONSTART (SYSTEM)'
# Sin NSSM: una tarea ONSTART como SYSTEM cubre el 24/7 headless con lo que ya
# trae el SO. QT_QPA_PLATFORM=offscreen porque SYSTEM no tiene sesión gráfica.
#
# Correr como SYSTEM es además lo que evita aquí el problema de propiedad que en Linux
# sí hay que resolver: allá el instalador crea el árbol como root pero el unit corre
# como un usuario común, que no podría leer su config/.env ni escribir su base local
# (de ahí el `chown -R` de install.sh). SYSTEM tiene control total sobre el sistema de
# archivos local y este script no restringe ninguna ACL del prefijo, así que hereda de
# su carpeta padre y puede leer y escribir todo lo que creó el Administrador. No hace
# falta un arreglo simétrico; si algún día se cambia el principal a una cuenta común,
# entonces sí habría que ajustar los permisos del árbol.
$action = New-ScheduledTaskAction -Execute $dest `
-Argument '--start-engine --headless' -WorkingDirectory $Prefix
$trigger = New-ScheduledTaskTrigger -AtStartup