gioser

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 188Rust 55Shell 30Markdown 281211 Definiciones

servidor: el aviso periódico de novedades del repo, que sólo grita cuando cambia

Corre `takana outdated --json` contra el índice firmado y deja el resultado en un fichero de
estado. No actualiza nada: instalar es reproducir y verificar, y eso no se cuelga de un cron — el
aviso dice qué comando correr.

Tres cosas deliberadas:
 · Sólo grita cuando la LISTA de novedades difiere de la del ciclo anterior. Un guardián que repite
   lo mismo cada 30 min se deja de leer, y entonces no avisa de nada.
 · La huella es nombre+versión publicada, no el JSON entero: éste trae contadores que se mueven
   solos y harían «cambiar» un estado idéntico.
 · Un repo caído NO se resume en «al día»: lo dice, sale ≠ 0 y conserva el último estado bueno.

Probado en los tres caminos contra un repo servido por HTTP en la caja.

4f4fecf862bb49ef8d0cb88080b5ab088de4433f · por Sergio · (hace 1 mes) · padre 9fe1e010e · ver el árbol en este commit

Delta semántico

Ninguna definición cambió: el cambio es de texto, documentación o datos.

1 archivos · +84 −0

diff --git a/scripts/servidor/avisar-actualizaciones.sh b/scripts/servidor/avisar-actualizaciones.sh
new file mode 100755
index 00000000..677e3ad8
--- /dev/null
+++ b/scripts/servidor/avisar-actualizaciones.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+# avisar-actualizaciones.sh — pregunta al repo si hay novedades para lo que esta máquina tiene
+# instalado, y AVISA sólo cuando la respuesta cambia.
+#
+# ── QUÉ HACE Y QUÉ NO ───────────────────────────────────────────────────────────────────────────
+# Corre `takana outdated --json` (que no construye, no baja `.swm` y no escribe nada: lee el índice
+# firmado y la DB de instalados) y deja el resultado en un fichero de estado. **No actualiza nada**:
+# instalar es reproducir y verificar, y eso no se cuelga de un cron. El aviso dice qué correr.
+#
+# ── POR QUÉ SÓLO AVISA CUANDO CAMBIA ────────────────────────────────────────────────────────────
+# Un guardián que grita lo mismo cada 30 minutos se deja de leer, y entonces no avisa de nada — es
+# la lección que ya está escrita en `vigia-subcomandos.py` ([[guardianes-el-ruido-los-mata]]).
+# Así que el ciclo normal es una línea sola («al día», o «3 novedades, las mismas de antes») y el
+# grito sale cuando la LISTA de novedades difiere de la del ciclo anterior.
+#
+# ── LA FIRMA NO ES OPCIONAL ACÁ ─────────────────────────────────────────────────────────────────
+# Se pasa `--trust`: decidir «hay que actualizar» a partir de un catálogo que nadie firmó es la
+# forma exacta de que te instalen lo que quieran. `outdated` aborta si el índice está manipulado
+# (BAD-SIG) e informa si está sin firmar o firmado por una clave desconocida — ese informe sale en
+# el log y en el estado, no se traga.
+#
+# Uso:    scripts/servidor/avisar-actualizaciones.sh
+#         */30 * * * * cd /work/sergio/takana && scripts/servidor/avisar-actualizaciones.sh \
+#                        >>work/avisar-actualizaciones.log 2>&1
+#
+# Env:    REPO   origen(es) del catálogo — dir local o lista HTTP(S) separada por comas
+#         DB     DB de instalados (def /var/lib/hammer/installed.json)
+#         TRUST  directorio de claves de confianza (def ./trust)
+#         STATE  fichero de estado (def work/actualizaciones.json)
+#         TAKANA binario (def ./target/release/takana)
+set -eu
+ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT"
+
+REPO="${REPO:-https://repo.gioser.net}"
+DB="${DB:-/var/lib/hammer/installed.json}"
+TRUST="${TRUST:-$ROOT/trust}"
+STATE="${STATE:-$ROOT/work/actualizaciones.json}"
+TAKANA="${TAKANA:-$ROOT/target/release/takana}"
+
+[ -x "$TAKANA" ] || { echo "!! falta $TAKANA (cargo build --release)" >&2; exit 2; }
+mkdir -p "$(dirname "$STATE")"
+
+NUEVO="$STATE.nuevo"
+if ! "$TAKANA" outdated --repo "$REPO" --db "$DB" --trust "$TRUST" --json >"$NUEVO" 2>"$NUEVO.err"; then
+    # Un repo caído o un índice manipulado NO se resume en «al día»: se dice, y se deja el estado
+    # anterior intacto para no borrar la última respuesta buena.
+    echo "$(date -u +%FT%TZ) ✗ no pude preguntarle al repo $REPO:"
+    sed 's/^/    /' "$NUEVO.err"
+    rm -f "$NUEVO" "$NUEVO.err"
+    exit 1
+fi
+rm -f "$NUEVO.err"
+
+# La huella es la LISTA de novedades (nombre+versión publicada), no el JSON entero: el JSON trae
+# contadores que se mueven solos (p.ej. `no_instalados`) y harían «cambiar» un estado idéntico.
+huella() { [ -f "$1" ] || { echo ""; return; }; python3 - "$1" <<'PY'
+import json, sys
+try:
+    d = json.load(open(sys.argv[1]))
+except Exception:
+    print(""); raise SystemExit
+print(",".join(sorted(f"{n['name']}={n['publicada']}" for n in d.get("novedades", []))))
+PY
+}
+
+ANTES="$(huella "$STATE")"
+AHORA="$(huella "$NUEVO")"
+mv "$NUEVO" "$STATE"
+
+N=$(python3 -c 'import json,sys; print(len(json.load(open(sys.argv[1])).get("novedades",[])))' "$STATE")
+SELLO="$(date -u +%FT%TZ)"
+
+if [ "$N" = "0" ]; then
+    echo "$SELLO · al día contra $REPO"
+    exit 0
+fi
+
+if [ "$AHORA" = "$ANTES" ]; then
+    echo "$SELLO · $N novedad(es), las mismas del ciclo anterior (estado en $STATE)"
+    exit 0
+fi
+
+echo "$SELLO ⚠ HAY $N NOVEDAD(ES) en $REPO:"
+"$TAKANA" outdated --repo "$REPO" --db "$DB" --trust "$TRUST" | sed 's/^/    /'