From 93362fc21bb17467ac1f4e30f1bd645e7b8ad8e5 Mon Sep 17 00:00:00 2001 From: Sergio Date: Mon, 14 Sep 2026 21:40:45 +0000 Subject: [PATCH] =?UTF-8?q?el=20TLS=20arreglado=20en=20la=20caja,=20la=20d?= =?UTF-8?q?istro=20con=20nombre,=20y=20el=20ENOSPC=20que=20no=20era=20de?= =?UTF-8?q?=20la=20ra=C3=ADz?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **curl ya valida**: `ca-certificates` re-sellado con **119 hash-links en el capath**, generados en el build, y la caja baja por HTTPS sin apaño (200). Tardó tres intentos y los dos primeros los cazó la guarda de la propia receta: `c_rehash` no estaba en el PATH (lo instala esa misma receta en `/out/usr/bin`) y los certificados no están sueltos en `usr/share/ca-certificates/` sino en `mozilla/`, así que sólo veía el bundle y lo saltaba —correctamente— con «does not contain exactly one certificate». Sin la guarda habría sellado un capath vacío las tres veces. **fastfetch 2.68.1 corre en la caja** (pedido del usuario) y al correrlo destapó que **`/etc/os-release` no existía**: la distro era anónima para cualquier programa que no fuera suyo. Ahora `OS: takana x86_64`. Va como receta propia (`source.dir`) y no como constante de `takana-bootstrap`: meterlo ahí re-sellaría el product-rootfs —el baseline del selfhost— por cinco líneas. Sin VERSION_ID ni fecha: un sello con la fecha del build cambiaría el hash cada día sin motivo, y con él la clausura de toda imagen que lo lleve. 🧨 Y el hallazgo estructural: `upgrade apply` falló dos veces con **No space left on device teniendo 3 G libres en la raíz**. No era `/` ni los inodos (9%): el estado de generaciones vive en **`/var/lib/hammer`, que es sda3 y mide 487 MB** — la partición «estado» del layout. Cada generación guarda una copia del árbol aplicado (272 MB el nuestro), así que dos no caben. Movido a `/work` por symlink, igual que qorpa, y la generación 6 entró. El layout de la imagen necesita revisión: 512 MB no alcanzan para un mecanismo que guarda un árbol por generación, y el síntoma apunta al sitio equivocado. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn --- docs/28-servidor-de-produccion.md | 36 ++++++++++++++++++++++++ docs/state/targets.toml | 5 ++++ recipes/ca-certificates.toml | 7 ++++- recipes/fastfetch.toml | 8 +++++- recipes/os-release.toml | 38 ++++++++++++++++++++++++++ recipes/os-release/tree/etc/os-release | 5 ++++ 6 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 recipes/os-release.toml create mode 100644 recipes/os-release/tree/etc/os-release diff --git a/docs/28-servidor-de-produccion.md b/docs/28-servidor-de-produccion.md index 54a51ef8..5dd21933 100644 --- a/docs/28-servidor-de-produccion.md +++ b/docs/28-servidor-de-produccion.md @@ -1406,6 +1406,42 @@ está instalado. ⇒ `qorpa pull` tiene que descomprimir con `zstd -dc | tar -x` alternativa es una imagen `.tar.gz` (Ubuntu base) — que además obliga a reinstalar las deps del venv, porque el de gioser trae extensiones de **CPython 3.14** y Ubuntu 24.04 lleva 3.12. +### 6.24 El TLS arreglado, la distro con nombre, y **por qué `upgrade` se quedaba sin espacio** + +**El `curl` ya valida.** Con `ca-certificates` re-sellado —**119 hash-links en el capath**, generados +en el build— la caja baja por HTTPS **sin ningún apaño**: `curl -I https://…` → **200**. El arreglo +tardó tres intentos y los dos primeros los cazó la guarda que puse en la propia receta: primero +`c_rehash` no estaba en el `PATH` (lo instala esa misma receta en `/out/usr/bin`), y después los +certificados **no estaban sueltos** en `usr/share/ca-certificates/` sino en su subdirectorio +`mozilla/`, así que `c_rehash` sólo veía el bundle y lo saltaba —correctamente— con «does not +contain exactly one certificate». Sin la guarda, las tres veces habría sellado un capath vacío. + +**`fastfetch` (2.68.1) corre en la caja** — y al correrlo apareció otra ausencia: + +``` +OS: takana x86_64 ← ahora +Host: vServer (20171111) +Kernel: Linux 7.1.2 · CPU: AMD EPYC-Rome (4) · Memory: 393 MiB / 7.58 GiB +``` + +…porque **`/etc/os-release` NO EXISTÍA**. La distro era anónima para cualquier programa que no fuera +suyo. Se resolvió con una receta propia (`os-release`, `source.dir`) en vez de una constante en +`takana-bootstrap`: meterlo ahí re-sellaría el `product-rootfs` —el baseline del selfhost— por cinco +líneas. Sin `VERSION_ID` ni fecha a propósito: un sello con la fecha del build cambiaría el hash del +artefacto, y con él la clausura de toda imagen que lo lleve, cada día y sin motivo. + +#### 🧨 `/var/lib/hammer` es una partición de 487 MB — y ahí viven las generaciones + +`upgrade apply` falló dos veces con `No space left on device` teniendo **3 G libres en la raíz**. Ni +el espacio de `/` ni los inodos (9% usados): el estado de generaciones vive en +**`/var/lib/hammer`, que es `sda3` y mide 487 MB** (la partición «estado» del layout). Cada +generación guarda una copia del árbol aplicado — el nuestro son **272 MB** — así que **dos no caben**. + +⇒ El estado se movió a `/work` por symlink, igual que `qorpa`. Tras eso: `✓ generación 6 aplicada`. +**El layout de la imagen necesita revisión**: 512 MB de «estado» no alcanzan para un mecanismo que +guarda un árbol entero por generación, y el síntoma (`ENOSPC` con la raíz medio vacía) apunta al +sitio equivocado. + ## 7. Reusar los scripts que ya existen, y no escribir de nuevo Pedido explícito del usuario. El inventario de lo que ya hace el trabajo: diff --git a/docs/state/targets.toml b/docs/state/targets.toml index 9d641ca0..48e5c135 100644 --- a/docs/state/targets.toml +++ b/docs/state/targets.toml @@ -102,6 +102,11 @@ hereda = ["base"] # declara abajo es el subconjunto que ya estaba sellado y que un usuario de esta capa espera # encontrar — cero recetas nuevas, cero builds: sólo dejan de ser invisibles. paquetes = [ + # `os-release` (2026-09-14): la IDENTIDAD del sistema, que no existía. Se descubrió al meter + # fastfetch: la caja decía «Host: vServer» y ni una palabra de takana, porque `/etc/os-release` no + # estaba. Lo lee todo el que quiera saber en qué distro corre — sin él, la distro es anónima para + # cualquier programa que no sea suyo. + "os-release", # `fastfetch` (2026-09-14, pedido del usuario): la tarjeta de presentación del sistema. En una # distro propia es lo primero que contesta «¿qué estoy corriendo?» sin leer tres ficheros de # `/proc`, y en una caja recién instalada distingue «arrancó» de «arrancó lo que yo creía». diff --git a/recipes/ca-certificates.toml b/recipes/ca-certificates.toml index afa59c75..b170577f 100644 --- a/recipes/ca-certificates.toml +++ b/recipes/ca-certificates.toml @@ -83,7 +83,12 @@ make install DESTDIR="/out" # ⚠ `c_rehash` lo compila e instala ESTA receta (`install -m755 c_rehash /out/usr/bin`), así que # no está en el `PATH` del sandbox: hay que invocarlo por su ruta de destino. La primera versión # lo llamaba por nombre, no lo encontraba, y la guarda de abajo cazó el silencio. - cp "/out"/usr/share/ca-certificates/*.crt "/out"/etc/ssl/certs/ 2>/dev/null || true + # ⚠ Los certificados NO están sueltos en `usr/share/ca-certificates/`: cuelgan de un + # subdirectorio (`mozilla/`). El primer intento copiaba `…/ca-certificates/*.crt`, no casaba con + # nada, y `c_rehash` sólo encontraba el bundle — que salta con «does not contain exactly one + # certificate», que es correcto y parecía el problema cuando el problema era que no había nada + # más que mirar. + find "/out"/usr/share/ca-certificates -name '*.crt' -exec cp {} "/out"/etc/ssl/certs/ \; "/out"/usr/bin/c_rehash "/out"/etc/ssl/certs || ./c_rehash "/out"/etc/ssl/certs || true # Falla ruidosamente si el rehash no produjo NADA: un capath sin enlaces es exactamente el bug # que esto viene a cerrar, y sellarlo en silencio lo devolvería intacto. diff --git a/recipes/fastfetch.toml b/recipes/fastfetch.toml index a4dbc6c0..e70cf292 100644 --- a/recipes/fastfetch.toml +++ b/recipes/fastfetch.toml @@ -33,6 +33,12 @@ flags = [] build = ["cmake", "linux-headers"] [build.phases] -configure = "cmake -S . -B build -DCMAKE_LINK_DEPENDS_USE_LINKER=OFF -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DENABLE_SYSTEM_YYJSON=OFF -DENABLE_VULKAN=OFF -DENABLE_OPENCL=OFF -DENABLE_X11=OFF -DENABLE_XRANDR=OFF -DENABLE_WAYLAND=OFF -DENABLE_DCONF=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_CHAFA=OFF -DENABLE_DBUS=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_LIBNM=OFF -DENABLE_LIBZFS=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OSMESA=OFF -DENABLE_DRM=OFF -DENABLE_ELF=OFF -DENABLE_LIBCJSON=OFF" +# ⚠ `-Wno-error=date-time`: `version.c` usa `__DATE__`/`__TIME__` y el lab compila con +# `-Werror=date-time` —la política de reproducibilidad del sandbox, que aquí hizo exactamente su +# trabajo y paró el build—. Desactivarlo es SEGURO **porque el sandbox exporta `SOURCE_DATE_EPOCH`**: +# con esa variable definida, clang hace que `__DATE__`/`__TIME__` rindan esa fecha fija en vez de la +# del reloj, así que el binario sigue siendo determinista. Sin `SOURCE_DATE_EPOCH` esto sería +# hornear la hora del build dentro del artefacto, que es justo lo que el warning previene. +configure = "cmake -S . -B build -DCMAKE_C_FLAGS=-Wno-error=date-time -DCMAKE_LINK_DEPENDS_USE_LINKER=OFF -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DENABLE_SYSTEM_YYJSON=OFF -DENABLE_VULKAN=OFF -DENABLE_OPENCL=OFF -DENABLE_X11=OFF -DENABLE_XRANDR=OFF -DENABLE_WAYLAND=OFF -DENABLE_DCONF=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_CHAFA=OFF -DENABLE_DBUS=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_LIBNM=OFF -DENABLE_LIBZFS=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OSMESA=OFF -DENABLE_DRM=OFF -DENABLE_ELF=OFF -DENABLE_LIBCJSON=OFF" compile = "cmake --build build" install = "DESTDIR=/out cmake --install build" diff --git a/recipes/os-release.toml b/recipes/os-release.toml new file mode 100644 index 00000000..1aad2292 --- /dev/null +++ b/recipes/os-release.toml @@ -0,0 +1,38 @@ +# os-release — la identidad del sistema, que hasta hoy NO EXISTÍA. +# +# Se descubrió al meter `fastfetch` (2026-09-14): en la caja de producción decía +# +# Host: vServer (20171111) +# Kernel: Linux 7.1.2 +# +# …y ni una palabra de takana, porque `/etc/os-release` no está. No es cosmético: ese fichero es lo +# que TODO el mundo lee para saber en qué distro corre — fastfetch, los instaladores de terceros, los +# scripts de CI, el propio `qorpa` el día que quiera distinguir anfitrión de huésped. Una distro sin +# `os-release` es anónima para cualquier programa que no sea suyo. +# +# ══ POR QUÉ UNA RECETA Y NO UNA CONSTANTE EN `takana-bootstrap` ════════════════════════════════ +# El `/etc/passwd` del producto SÍ es una constante de Rust, y esa decisión ya costó: para añadir un +# usuario había que recompilar takana (lo arregló `[[user]]`). Meter `os-release` ahí re-sellaría el +# `product-rootfs`, que es el **baseline del selfhost**, por un fichero de cinco líneas. Como receta +# entra por perfil, se edita sin tocar el bootstrap y su radio es cero. +# +# ⚠ SIN VERSIÓN NI FECHA, a propósito. Un `VERSION_ID` con la fecha del build haría que este +# artefacto —y con él la clausura de toda imagen que lo lleve— cambiara de hash cada día sin que +# nada haya cambiado. La versión de una distro de árbol único es el hash de su imagen, que ya existe. +name = "os-release" +version = "1" +license = "MIT" + +[source] +dir = "os-release/tree" + +[build] +compiler = "zig-cc" +target = "x86_64-linux-musl" +link = "static" +flags = [] + +[build.phases] +configure = "true" +compile = "true" +install = "mkdir -p /out/etc && cp /src/etc/os-release /out/etc/os-release && mkdir -p /out/usr/lib && ln -sf ../../etc/os-release /out/usr/lib/os-release" diff --git a/recipes/os-release/tree/etc/os-release b/recipes/os-release/tree/etc/os-release new file mode 100644 index 00000000..a5435a59 --- /dev/null +++ b/recipes/os-release/tree/etc/os-release @@ -0,0 +1,5 @@ +NAME="takana" +ID=takana +PRETTY_NAME="takana" +HOME_URL="https://git.gioser.net/sergio/takana" +ANSI_COLOR="0;36"