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 1389Shell 137Markdown 80Rust 802602 Definiciones

⎇ main scripts/servidor/publicar-webs.sh Shell · 128 líneas · 7.7 KB Historia crudo

sitio: el dominio ya tiene SSL, y takana.gioser.net pasa a redirigir acá 008692f7b · Sergio ·

1#!/bin/sh
2# Publica los sitios de la caja: PULL de los repos y regeneración de lo generado.
3#
4# ── POR QUÉ (2026-09-18) ────────────────────────────────────────────────────────────────────────
5# La mudanza dejó los sitios como COPIAS a mano en `/work/www` —4,2 G del monorepo para
6# `tawasuyu.net`, más `takana`/`hifas`/`gioser-web`— sin ninguna forma de refrescarlas. Contenido
7# correcto y modelo frágil: el día que cambia el repo, la web no se entera y nadie lo nota, porque
8# un sitio viejo responde 200 igual que uno nuevo.
9#
10# Ahora Caddy sirve DIRECTO de los clones de git, así que **publicar = `git pull`**:
11#
12#     tawasuyu.net, www          → /work/sergio/tawasuyu            (monorepo, con rewrites a web/tawasuyu-web)
13#     gioser.net                 → /work/sergio/gioser-web/
14#     takana-os.net, www         → /work/sergio/takana/web/takana-os.net   (⚠ el ÁRBOL DE TRABAJO)
15#     takana.gioser.net          → 301 a takana-os.net              (desde el 2026-09-21)
16#     hifas.gioser.net           → /work/sergio/gioser-web/hifas    (la genera scripts/hermanas.py)
17#     gioser.net/{humanoid,muestras,vivo,ende,reencuentro} → /work/www/gioser-web/…  (MEDIOS, no están en git)
18#
19# El `.git` de los clones no se filtra: el vhost tiene `@oculto path /.* */.*` → 404, y se comprueba
20# abajo. La separación páginas-de-git / medios-de-disco es deliberada: los APK de humanoid y los
21# 265 M de `muestras` no viven en ningún repo, así que se quedan donde están.
22#
23# Idempotente. Se corre EN LA CAJA.
24set -eu
25
26# ⚠ `takana-os.net` NO ENTRA EN EL `pull` DE ARRIBA, Y ES A PROPÓSITO (2026-09-21). Su raíz no es
27# un clon de publicación: es `/work/sergio/takana`, el árbol que los agentes editan. Un `pull` ahí
28# mueve HEAD bajo los pies de quien esté trabajando (CLAUDE.md §2 ter, donde eso ya costó un commit
29# entero). Para ese sitio, publicar es guardar el fichero — no hay nada que tirar, sólo que
30# comprobar. Por eso figura abajo, en los controles, y no acá.
31MONO=${MONO:-/work/sergio/tawasuyu}
32TAKANA=${TAKANA:-/work/sergio/takana}
33WEB=${WEB:-/work/sergio/gioser-web}
34
35tirar() {  # $1 = clon
36  [ -d "$1/.git" ] || { echo "no hay clon en $1" >&2; return 1; }
37  antes=$(git -C "$1" rev-parse --short HEAD)
38  # ⚠ Sólo avance rápido: si alguien dejó cambios locales en el clon que sirve la web, esto NO los
39  # pisa — se queja y sigue. Un `git pull` que rebasa sobre un árbol servido es cómo se rompe un
40  # sitio en producción sin enterarse.
41  # ⚠ COMO EL DUEÑO, NO COMO ROOT (2026-09-18). Este guion corre como root y hacía el `pull` igual:
42  # git dejó 24 entradas de root dentro del `.git` de /work/sergio/tawasuyu —refs, logs, config,
43  # directorios de objetos— y el dueño se quedó sin poder ni hacer `fetch`: «unable to append to
44  # .git/logs/refs/remotes/origin/main». El clon quedó congelado 21 commits atrás sin que nada
45  # fallara del lado de root. Lo reportó el agente que trabaja ahí.
46  duenio=$(stat -c %U "$1" 2>/dev/null || echo root)
47  if [ "$duenio" != "root" ] && [ "$(id -u)" = "0" ]; then tira="su $duenio -s /bin/sh -c"; else tira="sh -c"; fi
48  if $tira "git -C '$1' pull -q --ff-only" 2>/dev/null; then
49    ahora=$(git -C "$1" rev-parse --short HEAD)
50    [ "$antes" = "$ahora" ] && echo "  = $1 ya estaba al día ($ahora)" || echo "  ↑ $1 $antes → $ahora"
51  else
52    echo "  ⚠ $1 NO avanzó (¿cambios locales, o divergió?) — sigue en $antes" >&2
53  fi
54}
55
56echo "==> repos"
57tirar "$MONO"
58tirar "$WEB"
59
60echo "==> páginas generadas (takana y hifas)"
61# `hermanas.py` trae el destino CABLEADO a `/home/sergio/gioser-web`, que es una ruta de gioser y en
62# esta caja no existe. Se le pasa el del clon sin tocar el fichero del repo: el parche pertenece a
63# ese repo, no a este guion.
64sed "s|^DESTINO = Path(\"/home/sergio/gioser-web\")|DESTINO = Path(\"$WEB\")|" \
65    "$WEB/scripts/hermanas.py" > /tmp/hermanas-caja.py
66python3 /tmp/hermanas-caja.py >/dev/null
67rm -f /tmp/hermanas-caja.py
68# `hermanas.py` sigue escribiendo las DOS, pero desde el 2026-09-21 la de takana ya no se sirve:
69# `takana.gioser.net` redirige al dominio propio y la página buena vive en el repo takana. Se deja
70# generar porque el guion es de ese otro repo y partirlo acá es tocarlo de paso; lo que sí cambió
71# es el control, que abajo espera un 301 y no un fichero.
72for p in takana hifas; do
73  [ -s "$WEB/$p/index.html" ] || { echo "  ✗ $p quedó sin index.html" >&2; exit 1; }
74done
75echo "  ✓ hifas $(wc -c < "$WEB/hifas/index.html") B · takana $(wc -c < "$WEB/takana/index.html") B (ya no servida)"
76
77echo "==> control: lo que se SIRVE tiene que ser lo que está en disco"
78falla=0
79comprobar() {  # $1 = url  $2 = fichero en disco
80  viv=$(curl -s --max-time 15 "$1" | sha256sum | cut -c1-12)
81  dis=$(sha256sum "$2" 2>/dev/null | cut -c1-12)
82  if [ "$viv" = "$dis" ]; then printf "  ✓ %-30s %s\n" "$1" "$viv"
83  else printf "  ✗ %-30s vivo=%s disco=%s\n" "$1" "$viv" "$dis"; falla=$((falla+1)); fi
84}
85# Un nombre que REDIRIGE no se comprueba por contenido: se comprueba por destino. Y un nombre que
86# todavía no resuelve no es un fallo del sitio —es un registro DNS que falta—, así que avisa en vez
87# de ponerse rojo: mezclar las dos cosas es cómo un control deja de leerse.
88#
89# ⚠ Quién resuelve se lo pregunto a CURL, por su código de salida 6 («couldn't resolve host»), y no
90# a `getent`: **en esta caja `getent` NO EXISTE** —musl/busybox no lo traen— así que la primera
91# versión de esta función daba `not found` (127) para TODO y declaraba «no resuelve todavía» hasta
92# de los nombres que estaban andando. Un control que nunca mira nada se ve igual que uno en verde.
93redirige() {  # $1 = url  $2 = destino esperado
94  rc=0
95  d=$(curl -s -o /dev/null -w "%{redirect_url}" --max-time 15 "$1") || rc=$?
96  if [ "$rc" -eq 6 ]; then
97    printf "  ~ %-30s el nombre no resuelve todavía (¿falta el registro A?)\n" "$1"; return 0
98  fi
99  if [ "$rc" -ne 0 ]; then
100    printf "  ✗ %-30s curl salió %s (¿certificado, o no escucha?)\n" "$1" "$rc"; falla=$((falla+1)); return 0
101  fi
102  if [ "$d" = "$2" ]; then printf "  ✓ %-30s → %s\n" "$1" "$d"
103  else printf "  ✗ %-30s → %s (esperaba %s)\n" "$1" "${d:-nada}" "$2"; falla=$((falla+1)); fi
104}
105comprobar https://tawasuyu.net/        "$MONO/web/tawasuyu-web/index.html"
106comprobar https://takana-os.net/       "$TAKANA/web/takana-os.net/index.html"
107comprobar https://hifas.gioser.net/    "$WEB/hifas/index.html"
108comprobar https://gioser.net/          "$WEB/index.html"
109redirige  https://takana.gioser.net/   https://takana-os.net/
110redirige  https://git.takana-os.net/   https://git.gioser.net/
111
112# Los medios no salen de git, pero tienen que seguir en pie.
113for u in https://gioser.net/humanoid/ https://gioser.net/muestras/; do
114  c=$(curl -s -o /dev/null -w "%{http_code}" --max-time 15 "$u")
115  [ "$c" = "200" ] && printf "  ✓ %-30s %s\n" "$u" "$c" || { printf "  ✗ %-30s %s\n" "$u" "$c"; falla=$((falla+1)); }
116done
117
118# Y que servir DESDE UN ÁRBOL DE GIT no exponga el repo. Son dos ahora, y el de takana además
119# sirve un subdirectorio del árbol vivo, así que el día que alguien suba el root un nivel quedaría
120# el repo entero publicado — y eso no falla de forma visible.
121for u in https://tawasuyu.net/.git/config https://takana-os.net/.git/config; do
122  g=$(curl -s -o /dev/null -w "%{http_code}" --max-time 15 "$u")
123  [ "$g" = "404" ] && printf "  ✓ %-30s 404 (la regla @oculto tapa el árbol)\n" "$u" \
124                   || { printf "  ✗ %-30s %s — EL REPO ESTÁ EXPUESTO\n" "$u" "$g"; falla=$((falla+1)); }
125done
126
127[ "$falla" -eq 0 ] || { echo "==> $falla control(es) en rojo" >&2; exit 1; }
128echo "==> sitios publicados y verificados"