diff --git a/docs/28-servidor-de-produccion.md b/docs/28-servidor-de-produccion.md index 92741253..4045efad 100644 --- a/docs/28-servidor-de-produccion.md +++ b/docs/28-servidor-de-produccion.md @@ -546,6 +546,35 @@ habría hidratado y muerto al final. Comprobado después del arreglo, contra el por HTTP: `parted` (6 parches **y** binario en `/usr/sbin`) instala en 0,17 s y responde `parted (GNU parted) 3.7`; `bash` instala y responde `5.3.0(1)-release`. +### 5.7 El nombre ya existe: `repo.gioser.net` *(2026-09-21)* + +Dado de alta en la zona de Hetzner (la DNS de `gioser.net` está ahí: `helium`/`hydrogen`/`oxygen`), +con la convención que ya usaban `takana`, `git`, `gitea`, `sergio` y `www`: **`repo` A → +2.29.29.217, ttl 60**. Resuelve *(comprobado contra Cloudflare; el resolutor de Google todavía +servía el NXDOMAIN cacheado — negativo de 1 h por el `minimum` del SOA, no es un fallo del alta)*. + +⚠ **La API vieja de DNS de Hetzner ya no es la buena.** `dns.hetzner.com/api/v1/zones` con +`Auth-API-Token` devuelve **HTML de la consola web** (301 → 200 de una SPA), que es lo peor que +puede devolver: no falla, contesta. Las zonas viven hoy en la **API de cloud** y las lee el MISMO +token de `~/.config/hcloud/cli.toml`: + +```sh +curl -H "Authorization: Bearer $TOKEN" https://api.hetzner.cloud/v1/zones # gioser.net = 986350 +curl -H "Authorization: Bearer $TOKEN" https://api.hetzner.cloud/v1/zones/986350/rrsets +``` + +Hoy el nombre resuelve y **no sirve nada**: `http://repo.gioser.net` da el 308 global de Caddy y el +HTTPS muere en el handshake (`tlsv1 alert internal error`) porque no hay site block ⇒ no hay +certificado. Falta el vhost, que es root y va a mano: `scripts/servidor/publicar-repo.sh` publica y +firma en `/srv/repo`, comprueba el lazo y **imprime el bloque sin tocar el Caddyfile** — en esta +caja Caddy sirve 19 dominios y su config ya acumula 20 `.bak`; un guion que la reescribe a ciegas es +cómo se tiran 19 sitios para levantar uno. + +⚠ **Y trae su propia guarda contra el error más fácil de cometer:** si el `takana` de la caja es +anterior al §5.5 (se detecta porque no conoce `outdated`), **aborta antes de publicar**. Con uno +viejo el repo sale con las 16 recetas multi-parche irreproducibles y 8 paquetes prometiendo un +binario que no existe — y eso no se nota hasta que alguien instala. + ⚠ **Lo que queda vivo y no se tocó:** un `install ` DIRECTO sigue fallando tras hidratar, porque el `.swm` exige que el `target_bin` exista y para una librería no hay respuesta buena. Hacer `target_bin` opcional toca el formato ([SDD 06](06-swm-format.md)) y es su propia unidad de trabajo. diff --git a/scripts/servidor/publicar-repo.sh b/scripts/servidor/publicar-repo.sh new file mode 100755 index 00000000..18695a67 --- /dev/null +++ b/scripts/servidor/publicar-repo.sh @@ -0,0 +1,79 @@ +#!/bin/sh +# publicar-repo.sh — deja el repo FIRMADO servido en `repo.gioser.net`. Se corre EN LA CAJA, como +# root (la clave privada de release vive en `/root/.config/takana/keys/`, SDD 28 §2116). +# +# ── QUÉ HACE ──────────────────────────────────────────────────────────────────────────────────── +# 1. publica la clausura del perfil en `/srv/repo` con `repo-perfil.sh` (que ABORTA si no está la +# clave: un índice firmado con una efímera que nadie conoce no lo verifica nadie), +# 2. comprueba que el índice verifica contra `trust/`, +# 3. dice si Caddy ya sirve el nombre, y **si no, imprime el bloque y para**. +# +# ── POR QUÉ NO EDITA EL CADDYFILE ─────────────────────────────────────────────────────────────── +# En esta caja Caddy sirve 19 dominios y su Caddyfile ya acumula 20 `.bak` (SDD 28 §1). Un guion que +# lo reescribe a ciegas es cómo se tiran 19 sitios para levantar uno. El bloque va a mano, una vez: +# +# repo.gioser.net { +# root * /srv/repo +# file_server browse +# } +# +# y después `caddy reload --config /etc/caddy/Caddyfile`. El DNS ya está: `repo` A → 2.29.29.217, +# ttl 60, en la zona de Hetzner (dado de alta el 2026-09-21). +# +# ⚠ **Un solo origen es exactamente lo que el ADR 0014 existe para no tener.** Esta caja sirviéndose +# a sí misma está bien como camino normal, pero el `--repo` de los clientes debería llevar también +# el Storage Box: el primer origen roto, si es el único, es el último. +# +# Uso: sudo scripts/servidor/publicar-repo.sh [perfil] +# Env: PERFIL (def servidor) · STORE (def /store) · DESTINO (def /srv/repo) +# NOMBRE (def repo.gioser.net) · TRUST (def ./trust) +set -eu +ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT" + +PERFIL="${1:-${PERFIL:-servidor}}" +STORE="${STORE:-/store}" +DESTINO="${DESTINO:-/srv/repo}" +NOMBRE="${NOMBRE:-repo.gioser.net}" +TRUST="${TRUST:-$ROOT/trust}" +TAKANA="${TAKANA:-$ROOT/target/release/takana}" + +[ "$(id -u)" = "0" ] || { echo "!! corré esto como root: la clave de release está en /root/.config/takana/keys/" >&2; exit 2; } +[ -x "$TAKANA" ] || { echo "!! falta $TAKANA (cargo build --release)" >&2; exit 2; } + +# ⚠ El binario TIENE que traer el arreglo de los parches múltiples y del target_bin (SDD 28 §5.5): +# con uno anterior, las 16 recetas con ≥2 parches se publican irreproducibles y 8 paquetes más +# (bash, sed, tar, parted, dhcpcd, squid, wpa_supplicant, zsh) prometen un binario que no existe. +"$TAKANA" outdated --help >/dev/null 2>&1 || { + echo "!! este $TAKANA es anterior al arreglo del SDD 28 §5.5 (no conoce 'outdated')." >&2 + echo " Reconstruilo —cargo build --release— antes de publicar, o el repo sale roto." >&2 + exit 2 +} + +echo "==> publicando el perfil '$PERFIL' en $DESTINO" +install -d -m 755 "$DESTINO" +PERFIL="$PERFIL" STORE="$STORE" REPO="$DESTINO" TRUST="$TRUST" "$ROOT/scripts/repo-perfil.sh" "$PERFIL" + +echo +echo "==> ¿lo sirve Caddy?" +if curl -fsS -m 10 "https://$NOMBRE/index.json" -o /dev/null 2>/dev/null; then + echo " ✓ https://$NOMBRE/index.json responde" + echo + echo " probalo desde cualquier hub (necesita el lab: install reproduce desde fuente):" + echo " takana install zsh --repo https://$NOMBRE --trust ./trust --require-signed" + echo " y el aviso periódico:" + echo " REPO=https://$NOMBRE scripts/servidor/avisar-actualizaciones.sh" +else + cat <