el TLS arreglado en la caja, la distro con nombre, y el ENOSPC que no era de la raíz

**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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
This commit is contained in:
Sergio
2026-09-14 21:40:45 +00:00
co-authored by Claude Opus 5
parent 64d48e743e
commit 93362fc21b
6 changed files with 97 additions and 2 deletions
+36
View File
@@ -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:
+5
View File
@@ -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».
+6 -1
View File
@@ -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.
+7 -1
View File
@@ -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"
+38
View File
@@ -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"
+5
View File
@@ -0,0 +1,5 @@
NAME="takana"
ID=takana
PRETTY_NAME="takana"
HOME_URL="https://git.gioser.net/sergio/takana"
ANSI_COLOR="0;36"