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:
@@ -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
|
||||
|
||||
48
install.sh
48
install.sh
@@ -66,6 +66,10 @@ UNIT_NAME="cloudrestoreas.service"
|
||||
# línea de cron del vigilante contiene esta ruta, así que el `sh -c` que la ejecuta hace
|
||||
# match consigo mismo, el vigilante cree que el agente corre y no lo rearranca nunca.
|
||||
PGREP_PAT="^$PREFIX/$BIN_NAME"
|
||||
# Usuario del servicio. Se resuelve AQUÍ y no dentro del case de --service porque el chown de
|
||||
# propiedad tiene que correr antes, justo después del bootstrap. Precedencia: la variable
|
||||
# explícita, luego quien invocó el sudo, luego el usuario efectivo.
|
||||
SERVICE_USER="${SERVICE_USER:-${SUDO_USER:-$(id -un)}}"
|
||||
|
||||
# Localizar el binario: dist/CloudRestoreAS, dist/CloudRestoreAS-linux, o junto al script.
|
||||
SRC=""
|
||||
@@ -269,9 +273,51 @@ if [[ -n "$PANEL_ENV_FILE" ]]; then
|
||||
rm -f "$PANEL_ENV_FILE"
|
||||
fi
|
||||
|
||||
# --- Propiedad del árbol -------------------------------------------------------
|
||||
# Corriendo con sudo, el bootstrap crea config/, config/data/app.db, config/logs/, Entrada/,
|
||||
# Procesados/, Fallados/ y Temp/ como ROOT, y la siembra escribe config/.env en 0600 de root.
|
||||
# Pero el unit se registra con User=$SERVICE_USER, así que el agente arrancaría sin poder leer su
|
||||
# propia configuración ni escribir su base local: falla en bucle, y la sonda del panel lo pinta
|
||||
# verde porque comprueba existencia y no lectura. Devolver la propiedad es lo que cierra eso.
|
||||
#
|
||||
# Solo el usuario, no el grupo: basta para que el agente escriba y evita sorpresas con el grupo
|
||||
# primario del destino. Y `chown` no toca los modos, así que el 0600 del .env sobrevive.
|
||||
chown_tree_is_safe() {
|
||||
local path="$1"
|
||||
# Un chown -R sobre una ruta de sistema sería catastrófico. El panel ya valida la ruta, pero
|
||||
# este script también se corre a mano.
|
||||
case "$path" in
|
||||
/|/opt|/usr|/etc|/var|/home|/srv|/root|/bin|/sbin|/lib|/lib64|/tmp) return 1 ;;
|
||||
esac
|
||||
# Al menos dos componentes: /algo/otro.
|
||||
case "${path#/}" in
|
||||
*/*) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
if [[ "$MODE" != "update-in-place" && "$(id -u)" -eq 0 && "$SERVICE_USER" != "root" ]]; then
|
||||
if ! id -u "$SERVICE_USER" >/dev/null 2>&1; then
|
||||
echo "AVISO: el usuario '$SERVICE_USER' no existe en este servidor; no se cambia la" >&2
|
||||
echo " propiedad de $PREFIX. Revisa SERVICE_USER." >&2
|
||||
elif ! chown_tree_is_safe "$PREFIX"; then
|
||||
echo "AVISO: $PREFIX es una ruta de sistema; no se hace chown -R sobre ella." >&2
|
||||
echo " Ajústala a mano si el servicio corre como '$SERVICE_USER'." >&2
|
||||
elif chown -R "$SERVICE_USER" "$PREFIX"; then
|
||||
echo "Propiedad de $PREFIX asignada a $SERVICE_USER."
|
||||
else
|
||||
# No se asume que un comando de endurecimiento tuvo éxito: si falla, el agente no arranca
|
||||
# y es mejor decirlo ahora que dejar un servicio reiniciándose en silencio.
|
||||
echo "ERROR: no se pudo asignar la propiedad de $PREFIX a $SERVICE_USER." >&2
|
||||
echo " El servicio corre como ese usuario y no podría leer config/.env ni escribir" >&2
|
||||
echo " su base local. Corrígelo antes de arrancarlo:" >&2
|
||||
echo " chown -R $SERVICE_USER $PREFIX" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
case "$MODE" in
|
||||
service)
|
||||
SERVICE_USER="${SERVICE_USER:-${SUDO_USER:-$(id -un)}}"
|
||||
UNIT_SRC="$SCRIPT_DIR/packaging/linux/$UNIT_NAME"
|
||||
UNIT_DST="/etc/systemd/system/$UNIT_NAME"
|
||||
if [[ ! -w "$(dirname "$UNIT_DST")" ]]; then
|
||||
|
||||
Reference in New Issue
Block a user