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 1373Shell 116Rust 74Markdown 641915 Definitions

⎇ 8ee258a4ded1489c7cab885497a29cbd748dd72e scripts/lab-image.sh Shell · 119 lines · 5.9 KB History raw

lab: el rootfs se ANCLA en una imagen pineada — deja de resolverse con apk 0de4bf08a · Sergio ·

1#!/usr/bin/env bash
2# lab-image.sh — empaqueta y publica el ROOTFS YA BOOTSTRAPEADO como imagen pineada por sha256.
3#
4# ── POR QUÉ EXISTE ──────────────────────────────────────────────────────────────────────────────
5# Desde el 2026-08-10 el toolchain del lab entra en `hash_inputs` (ver `hammer-core/src/lab.rs`):
6# dos máquinas con distinto `rustc` sellan en direcciones distintas. Eso cierra un agujero real
7# —antes sellaban bytes distintos en la MISMA dirección— pero abre uno operativo:
8#
9#   Los repos del rootfs apuntan a Alpine **edge**, que es RODANTE. Dos máquinas que corran
10#   `bootstrap-devfs.sh` en fechas distintas resuelven toolchains distintos ⇒ **no comparten NI UN
11#   artefacto**. Ni cosecha de granja, ni `mirror pull` entre hubs, ni cache-hit. Cada worker
12#   efímero nacería con un lab propio y reconstruiría todo desde cero.
13#
14# El `apk add` contra edge es, por diseño, irrepetible. Así que el rootfs deja de resolverse y pasa
15# a **traerse**: una imagen construida UNA vez, pineada por sha256 y compartida por todas las
16# máquinas — exactamente el trato que ya reciben `alpine-minirootfs` y `zig` en bootstrap-devfs.sh.
17#
18# ── EL TAR ES DETERMINISTA A PROPÓSITO ──────────────────────────────────────────────────────────
19# `--sort=name` + `--mtime=@1` + `--owner=0 --group=0 --numeric-owner`: sin esto el sha256 depende
20# del orden del directorio y del uid de quien empaqueta, así que dos empaquetados del MISMO rootfs
21# darían imágenes distintas y no habría forma de verificar que una imagen es la que dice ser.
22# Con esto, `--crear` sobre el mismo rootfs reproduce el mismo sha, y eso es comprobable.
23# Ojo: el uid 0 del tar es cosmético — quien extrae sin ser root se queda como dueño igual, y el
24# sandbox usa `--tmp-overlay /`, así que la propiedad de los ficheros del rootfs no influye.
25#
26# Uso:
27#   scripts/lab-image.sh --crear     # empaqueta .dev-fs/alpine, imprime el sha256 y lo sube al box
28#   scripts/lab-image.sh --sha       # sólo calcula el sha del rootfs actual (no sube nada)
29#   scripts/lab-image.sh --traer     # baja la imagen pineada y reemplaza .dev-fs/alpine
30set -euo pipefail
31
32ROOT="$(cd "$(dirname "$0")/.." && pwd)"
33cd "$ROOT"
34DEVFS="$ROOT/.dev-fs"
35ROOTFS="$DEVFS/alpine"
36
37# El sha de la imagen VIGENTE. Es el contrato compartido: todas las máquinas deben tener ésta.
38# Se actualiza a mano tras un `--crear`, igual que ALPINE_SHA256 y ZIG_SHA256 en bootstrap-devfs.sh.
39LAB_IMAGE_SHA256="${LAB_IMAGE_SHA256:-PENDIENTE}"
40
41SB_USER="${SB_USER:-u647150}"
42SB_HOST="${SB_HOST:-u647150.your-storagebox.de}"
43SB_PORT="${SB_PORT:-23}"
44KEY="${KEY:-$HOME/.ssh/github5}"
45SSH_CMD="ssh -4 -p $SB_PORT -i $KEY -o StrictHostKeyChecking=accept-new -o ServerAliveInterval=30"
46REMOTO="hammer/lab"
47
48log() { printf '\033[1;34m==>\033[0m %s\n' "$*"; }
49ok()  { printf '\033[1;32m✓\033[0m  %s\n' "$*"; }
50
51empaquetar() {  # $1 = destino
52  [ -d "$ROOTFS" ] || { echo "no existe $ROOTFS — corré bootstrap-devfs.sh primero" >&2; exit 1; }
53  tar --sort=name --mtime=@1 --owner=0 --group=0 --numeric-owner \
54      -C "$DEVFS" -cf - alpine \
55    | zstd -19 -T0 -q -o "$1" -f
56}
57
58case "${1:---sha}" in
59  --sha)
60    tmp="$(mktemp -p "$DEVFS" lab-image.XXXXXX.tar.zst)"
61    trap 'rm -f "$tmp"' EXIT
62    log "empaquetando (determinista) para calcular el sha…"
63    empaquetar "$tmp"
64    echo "sha256: $(sha256sum "$tmp" | cut -d' ' -f1)"
65    echo "tamaño: $(du -h "$tmp" | cut -f1)"
66    ;;
67
68  --crear)
69    img="$DEVFS/lab-image.tar.zst"
70    log "empaquetando $ROOTFS (determinista)…"
71    empaquetar "$img"
72    sha="$(sha256sum "$img" | cut -d' ' -f1)"
73    ok "imagen: $(du -h "$img" | cut -f1) · sha256 $sha"
74    log "subiendo a $SB_USER@$SB_HOST:$REMOTO/"
75    $SSH_CMD "$SB_USER@$SB_HOST" "mkdir $REMOTO" >/dev/null 2>&1 || true
76    # El nombre lleva el sha: las imágenes son inmutables y conviven, así que una máquina que
77    # todavía use la anterior no se queda sin su imagen cuando se publica una nueva.
78    rsync -a --partial-dir=.rsync-partial -e "$SSH_CMD" \
79      "$img" "$SB_USER@$SB_HOST:$REMOTO/lab-$sha.tar.zst"
80    ok "publicada como $REMOTO/lab-$sha.tar.zst"
81    echo
82    echo "AHORA: poné este sha en bootstrap-devfs.sh (LAB_IMAGE_SHA256) y commiteá."
83    echo "  LAB_IMAGE_SHA256=\"$sha\""
84    ;;
85
86  --traer)
87    [ "$LAB_IMAGE_SHA256" = "PENDIENTE" ] && {
88      echo "no hay imagen pineada todavía: corré --crear en la máquina de referencia" >&2; exit 1; }
89    img="$DEVFS/lab-$LAB_IMAGE_SHA256.tar.zst"
90    if [ -f "$img" ] && [ "$(sha256sum "$img" | cut -d' ' -f1)" = "$LAB_IMAGE_SHA256" ]; then
91      ok "imagen ya presente y verificada"
92    else
93      log "bajando lab-$LAB_IMAGE_SHA256.tar.zst"
94      rsync -a --partial-dir=.rsync-partial -e "$SSH_CMD" \
95        "$SB_USER@$SB_HOST:$REMOTO/lab-$LAB_IMAGE_SHA256.tar.zst" "$img"
96      real="$(sha256sum "$img" | cut -d' ' -f1)"
97      [ "$real" = "$LAB_IMAGE_SHA256" ] || {
98        echo "!! sha NO coincide: esperaba $LAB_IMAGE_SHA256, llegó $real" >&2
99        rm -f "$img"; exit 1; }
100      ok "sha verificado"
101    fi
102    # Reemplazo atómico-ish: extraer al lado y rotar. Extraer ENCIMA dejaría una mezcla de los dos
103    # rootfs si algo falla a medias, y una mezcla es justo lo que este fichero existe para evitar.
104    log "extrayendo…"
105    rm -rf "$DEVFS/alpine.nuevo"
106    mkdir -p "$DEVFS/alpine.nuevo"
107    zstd -d -q -c "$img" | tar -x -C "$DEVFS/alpine.nuevo"
108    rm -rf "$DEVFS/alpine.viejo"
109    [ -d "$ROOTFS" ] && mv "$ROOTFS" "$DEVFS/alpine.viejo"
110    mv "$DEVFS/alpine.nuevo/alpine" "$ROOTFS"
111    rmdir "$DEVFS/alpine.nuevo"
112    rm -rf "$DEVFS/alpine.viejo"
113    ok "rootfs reemplazado por la imagen pineada"
114    ;;
115
116  *)
117    sed -n '2,/^set -euo/p' "$0" | sed 's/^# \?//;$d'
118    exit 0 ;;
119esac