feat(servidor): el latido ya espeja a GitHub — con el token pedido en el momento, no guardado
El latido corre como ROOT (`HOME=/root`) y `gh` está logueado como **sergio** (`/home/sergio/.config/gh/hosts.yml`), así que root no veía credencial ninguna y el espejo se quedaba atrás 48 commits de estado al día. El camino SSH se descartó midiéndolo: ninguna de las claves de `/root/.ssh` abre el repo del espejo. `credencial-espejo-github.sh` es un ayudante de credencial de git que pide el token con `su - sergio -c 'gh auth token'` **en el momento de empujar** y no lo escribe en ningún sitio. Las alternativas se descartaron por lo que dejan en reposo: el token en `.git/config` o en `~/.git-credentials` es un secreto en claro en una caja con root compartido, y la URL con el token adentro sale además en cada mensaje de error de git. Si `gh` pierde la sesión, el push falla ruidosamente en vez de empujar con un token muerto. Y se arregla un aviso que MENTÍA, que es lo que más cuesta: `espejo-setup.sh` daba `gh auth status` por única credencial válida, así que en el latido decía «el push a GitHub va a fallar» mientras el push funcionaba. Ahora mira primero el ayudante —que es lo que git usa de hecho— y sólo cae a `gh` si no hay. Un guardián que grita en falso se deja de leer, y el día que grite de verdad tampoco. Comprobado: `git ls-remote https://github.com/…` como root del anfitrión devuelve el sha. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Semántico sayk'uy
Mana ima sutichaypas t'ikrakurqanchu: qillqalla, yachachiylla utaq willaylla t'ikrakurqan.
2 qillqakuna · +59 −3
diff --git a/scripts/espejo-setup.sh b/scripts/espejo-setup.sh
index d4ffaa96..bd7596c4 100755
--- a/scripts/espejo-setup.sh
+++ b/scripts/espejo-setup.sh
@@ -82,14 +82,26 @@ else
fi
# --- credencial de GitHub: avisar temprano, no fallar al primer push ---
-if command -v gh >/dev/null 2>&1; then
+# ⚠ `gh auth status` NO es la única forma válida de tener credencial, y darlo por supuesto hacía
+# que este aviso MINTIERA (2026-10-07). El latido corre como ROOT con `HOME=/root`, y `gh` está
+# logueado como **sergio**: `gh auth status` de root dice «NO autenticado» aunque el push funcione
+# perfectamente, porque el clon declara un AYUDANTE DE CREDENCIAL
+# (`credential.https://github.com.helper`) que pide el token en el momento. Un guardián que grita en
+# falso se deja de leer, y entonces el día que grite de verdad tampoco se lee.
+# ⇒ se mira primero el ayudante, que es lo que git va a usar de hecho.
+HELPER="$(git config --get credential.https://github.com.helper 2>/dev/null || true)"
+if [ -n "$HELPER" ]; then
+ ok "credencial por ayudante: $HELPER (no hace falta sesión de gh en ESTE usuario)"
+elif command -v gh >/dev/null 2>&1; then
if gh auth status >/dev/null 2>&1; then
ok "gh autenticado (el push a GitHub va por HTTPS con su token)"
else
- warn "gh NO autenticado ⇒ el push a GitHub va a fallar. Corré: gh auth login && gh auth setup-git"
+ warn "sin ayudante de credencial y gh NO autenticado ⇒ el push a GitHub va a fallar."
+ warn " misma sesión: gh auth login && gh auth setup-git"
+ warn " otro usuario: ver scripts/servidor/credencial-espejo-github.sh"
fi
else
- warn "no hay gh instalado ⇒ el push a GitHub va a fallar. Instalalo y corré: gh auth login && gh auth setup-git"
+ warn "no hay gh ni ayudante de credencial ⇒ el push a GitHub va a fallar."
fi
echo "listo. Verificar: git push origin main (debe reportar DOS veces, una por remoto)"
diff --git a/scripts/servidor/credencial-espejo-github.sh b/scripts/servidor/credencial-espejo-github.sh
new file mode 100755
index 00000000..9f988aa6
--- /dev/null
+++ b/scripts/servidor/credencial-espejo-github.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+# credencial-espejo-github.sh — da a git el token de GitHub del espejo, sin guardarlo en ningún sitio.
+#
+# ══ POR QUÉ EXISTE ════════════════════════════════════════════════════════════════════════════
+# El latido (`cosecha-cron.sh`, crontab de ROOT con `HOME=/root`) publica el estado y debe espejarlo
+# a GitHub. El espejo va por HTTPS con el token de `gh` —las claves SSH disponibles no llegan: se
+# comprobó el 2026-10-07 que ninguna de `/root/.ssh` abre el repo del espejo— y `gh` está logueado
+# como **sergio**, en `/home/sergio/.config/gh/hosts.yml`. Root no lo ve.
+#
+# Las alternativas se descartaron por lo que dejan a la intemperie:
+# - meter el token en `.git/config` o en un `~/.git-credentials` ⇒ secreto EN REPOSO, en claro,
+# en una caja que ya tiene root compartido.
+# - poner la URL con el token adentro (`https://x:TOKEN@github.com/…`) ⇒ lo mismo, y además sale
+# en cada mensaje de error de git.
+# - loguear `gh` como root ⇒ dos sesiones que caducan por separado, y la de root nadie la mira.
+#
+# Esto lo pide EN EL MOMENTO y no lo escribe: si `gh` pierde la sesión, el push falla ruidosamente
+# en vez de empujar con un token muerto.
+#
+# ⚠ El token NO se imprime en ninguna traza: `gh auth token` escribe sólo a stdout, que git consume.
+# No añadir `set -x` acá ni redirigir esta salida a un log.
+#
+# Uso: no se invoca a mano. Se declara como ayudante de credencial del clon del latido:
+# git -C /opt/takana config credential.https://github.com.helper /usr/local/bin/credencial-espejo-github
+#
+# git llama al ayudante con la operación en $1 (`get`/`store`/`erase`). Sólo `get` tiene respuesta:
+# no se guarda ni se borra nada, porque no hay nada guardado.
+[ "${1:-}" = "get" ] || exit 0
+
+DUENO="${DUENO_GH:-sergio}"
+USUARIO="${USUARIO_GH:-sergiovelasquezzeballos}"
+
+# `su - <dueño>` y no `sudo`: en esta caja `sudo` reenvía al anfitrión por ssh (ver CLAUDE.md) y acá
+# ya estamos en el anfitrión. El login shell es necesario para que `gh` encuentre su HOME.
+token="$(su - "$DUENO" -c 'gh auth token' 2>/dev/null)"
+if [ -z "$token" ]; then
+ # A stderr, que git muestra: un ayudante que calla deja a git pidiendo usuario y contraseña por
+ # teclado, y en un cron eso es un cuelgue sin mensaje.
+ echo "credencial-espejo-github: $DUENO no tiene sesión de gh (corré: gh auth login)" >&2
+ exit 1
+fi
+
+echo "username=$USUARIO"
+echo "password=$token"