ontoref-outreach/site/scripts/build/check-live-server.nu
2026-07-17 01:01:30 +01:00

135 lines
7.2 KiB
Text

#!/usr/bin/env nu
# ¿ESTE SERVIDOR ES EL SITIO, O SOLO ALGO QUE RESPONDE EN ESE PUERTO?
#
# Toda comprobación contra la superficie viva empieza dando por hecho lo único que nunca verifica:
# que al otro lado del puerto está el sitio. `check-served-live.nu` lo dice en su cabecera — «la
# superficie viva es la única publicación que hay» — y luego acepta un `--base-url` y se cree lo
# que le dan. Puede medir un servidor que no es este sitio y decirlo todo en verde.
#
# ── QUÉ PASÓ, MEDIDO (2026-07-16) ────────────────────────────────────────────────────────────
#
# Un servidor arrancado por una vía degradada —sin el entorno de run.sh— no trae RUSTELO_SITE_ROUTES,
# así que NO FUSIONA las rutas que el sitio declara en site/config/routes/. Responde 200 en todo lo
# que la imagen compartida trae compilado y 404 en lo que este sitio aporta. Contra ese servidor:
# /conceptos daba 404 y /sobre-el-idioma daba 404. De ahí salió media sesión persiguiendo un fallo
# de rutas que no existía, y dos diagnósticos falsos encadenados («las rutas están rotas», «el
# conmutador de idioma manda a 404»). Las rutas estaban perfectas. El servidor no era el sitio.
#
# ── POR QUÉ NO COMPRUEBA LA CANONICAL, QUE SERÍA MÁS CORTO ──────────────────────────────────
#
# Un servidor degradado emite `canonical = http://127.0.0.1:3030` y uno de run.sh emite
# `https://ontoref.dev`, porque run.sh exporta SITE_BASE_URL. Sería una línea. Y sería
# `a-check-measures-the-capability-not-a-proxy` (adr-072) en estado puro: SITE_BASE_URL no es
# «servir las rutas del sitio», es otra variable que resulta que hoy viaja en el mismo autobús.
# El día que alguien exporte una y no la otra, la puerta dice OK sobre un servidor ciego — y lo
# dirá con toda la confianza, que es lo que hace peligroso a un proxy.
#
# Así que se mide LA CAPACIDAD: pedir las rutas que el sitio declara, y comprobar que el servidor
# las conoce. Es la pregunta entera y no su sombra.
#
# ── Y SE PREGUNTA CON MARCADOR POSITIVO ─────────────────────────────────────────────────────
#
# No «el título no es el de la 404»: en este sitio un 404 responde 200 con «ontoref — Article»
# (medido hoy: /adr/999), la copia del 404 viaja incrustada en todas las páginas, y afirmar por
# ausencia de un negativo es como se cuelan los falsos verdes. La ruta declara `title_key`, y el
# .ftl dice qué texto es. Eso es lo que la página tiene que traer: la afirmación positiva de que
# el servidor sirve ESTA página, no de que no sirve otra.
#
# Uso:
# nu scripts/build/check-live-server.nu --base-url http://localhost:3030 --root .
def main [
--base-url: string = "http://localhost:3030",
--root: string = ".",
] {
let routes_dir = ([$root, "site", "config", "routes"] | path join)
if not ($routes_dir | path exists) {
print $"check-live-server: NO MIRÉ — ($routes_dir) no existe, y es lo único que dice qué rutas"
print " aporta este sitio. Sin eso no puedo distinguir un servidor bueno de uno ciego."
exit 1
}
# Las rutas del CONSUMIDOR, que son exactamente las que un servidor degradado se salta. Las de la
# imagen compartida no sirven de testigo: las responde igual sin haber leído nada de este sitio.
let declared = (
glob $"($routes_dir)/*.ncl"
| each {|f|
let r = (do { ^nickel export --format json $f } | complete)
if $r.exit_code != 0 {
print $"check-live-server: NO MIRÉ — ($f) no exporta: ($r.stderr | str trim | lines | first)"
exit 1
}
($r.stdout | from json).routes
}
| flatten
| where {|r| ($r.enabled? | default true) }
)
# CERO RUTAS DECLARADAS ES UN HALLAZGO, NUNCA UN «TODO BIEN». Si el glob no encuentra nada, o el
# esquema cambió y `routes` ya no se llama así, esta puerta no tiene nada que pedir — y una puerta
# sin nada que pedir pasa siempre. Es `a-check-can-say-i-did-not-look` (adr-072), y es el modo en
# que las puertas se mueren solas: en verde.
if ($declared | is-empty) {
print $"check-live-server: NO MIRÉ — ($routes_dir) no declaró ni una ruta habilitada."
print " Una puerta sin nada que pedir pasa siempre. Eso no es un servidor sano: es ignorancia."
exit 1
}
mut bad = []
mut ok = []
for r in $declared {
let lang = ($r.language? | default "")
let key = ($r.title_key? | default "")
if ($key | is-empty) {
$bad = ($bad | append $"($r.path) — la ruta no declara title_key, así que no tengo marcador positivo que pedir")
continue
}
# El texto que el sitio PROMETE para esa página. Se busca en su idioma: una clave resuelta
# contra el .ftl equivocado compararía la página con la promesa de otro idioma.
let ftl_dir = ([$root, "site", "i18n", "locales", $lang, "pages"] | path join)
let want = (
glob $"($ftl_dir)/*.ftl"
| each {|f| open --raw $f | lines | where {|l| $l | str starts-with $"($key) = " } }
| flatten
| each {|l| $l | str replace $"($key) = " "" | str trim }
| get -o 0
)
if $want == null or ($want | is-empty) {
$bad = ($bad | append $"($r.path) — title_key '($key)' no está en ($lang)/pages/*.ftl: la ruta promete un texto que no existe")
continue
}
let res = (do { ^curl -s -o /tmp/cls-page.html -w "%{http_code}" $"($base_url)($r.path)" } | complete)
let code = ($res.stdout | str trim)
let body = (if ("/tmp/cls-page.html" | path exists) { open --raw /tmp/cls-page.html } else { "" })
let title = ($body | parse --regex '(?s)<title>(?<t>.*?)</title>' | get -o t.0 | default "")
if $code != "200" {
$bad = ($bad | append $"($r.path) [($lang)] — HTTP ($code). El sitio la declara y el servidor no la conoce.")
} else if not ($title | str contains $want) {
# El 404 de este sitio responde 200. Por eso el veredicto lo da el TÍTULO contra la promesa,
# no el código: una página que existe trae lo que su title_key dice; una que no, trae la
# cáscara genérica y el mismo 200.
$bad = ($bad | append $"($r.path) [($lang)] — 200, pero el título es «($title)» y su title_key promete «($want)». Es la cáscara, no la página.")
} else {
$ok = ($ok | append $"($r.path) [($lang)]")
}
}
if ($bad | is-not-empty) {
print "check-live-server: ESTE SERVIDOR NO ES ESTE SITIO — rutas que el sitio declara y él no sirve:"
for b in $bad { print $" ✗ ($b)" }
print ""
print " Casi siempre significa que el servidor se arrancó sin el entorno de run.sh, así que"
print " RUSTELO_SITE_ROUTES no está y NO fusionó site/config/routes/. Responde 200 en todo lo"
print " que la imagen compartida trae compilado y 404 en lo que aporta este sitio."
print ""
print " ./run-secure.sh # SOPS exec-env → run.sh → el entorno completo"
print ""
print " NO midas nada contra este servidor: lo que te diga sobre esta web no es sobre esta web."
exit 1
}
print $"check-live-server: el servidor sirve las ($ok | length) rutas que este sitio declara — ($ok | str join ', ')"
}