Files
takana/scripts/qorpa/pressure-vessel-probe.sh
T
Sergio 1c3e185167 takana: las variables de entorno leen las dos formas, gana la nueva
TAKANA_X con caída a HAMMER_X (ADR 0016). No es un sed: estas variables son
contrato de usuario —knobs del instalador, el entorno del worker, mirror-env.sh—
y viven en perfiles de shell y units FUERA del repo, así que un renombre duro no
falla ruidosamente: la variable no aparece, se toma el default y el build se
comporta distinto sin que nada lo diga.

Rust: takana_core::env::{var,var_os} toma el nombre canónico y deriva el viejo
cambiando el prefijo — se le pasa TAKANA_* para que un grep del nombre nuevo
encuentre todas las lecturas. 5 tests, con DOS controles negativos: sin ninguna
de las dos no hay valor, y un nombre sin prefijo no inventa una caída.
Migrados los 17 sitios directos y los indirectos que el grep no mostraba
(bases_de_mirror, las constantes de kernel_cmd, ROOT_ENV de qorpa, env_path de
recover). takana-recover lleva la caída inline: es un mini-binario que se copia
a /usr/sbin y no vale arrastrarle una dep entera por dos líneas.

Scripts: 30 lecturas pasan a default, manteniendo el
nombre INTERNO de la variable para no tocar sus 190 usos.

Y donde el script EXPORTA en vez de leer, se ponen LAS DOS (mirror-env.sh y el
fragmento in-VM de bootstrap): ahí el lector puede ser un binario viejo —worker
sin recompilar, el /usr/bin/hammer pinado del baseline— que sólo conoce HAMMER_*.
La caída sirve para lectores nuevos; los viejos necesitan que la vieja siga puesta.

Verificado de punta a punta con el binario, no sólo con unit tests: HAMMER_LAB
sigue surtiendo efecto, TAKANA_LAB hace lo mismo, y con las dos gana TAKANA_LAB.
605 tests en verde y el hash de zlib sigue en b3:dc363f26… , intacto.

Cambio de comportamiento que va aparte y hay que decir: el hostname por defecto
de una instalación nueva pasa de 'hammer' a 'takana' (sólo si no se fija ninguna
de las dos variables).

NO se tocan: las rutas /var/lib/hammer de sistemas instalados, el volid
HAMMER_LIVE del ISO, ni el namespace HARKAQ_*, que es de otro subsistema.
2026-09-09 19:14:49 +00:00

99 lines
5.8 KiB
Bash
Executable File

#!/bin/sh
# Prueba que pressure-vessel —el contenedor con el que Valve corre los juegos— arranca ANIDADO
# dentro de una instancia qorpa enjaulada. ADR 0015 §Orden 6 / D6.
#
# ── POR QUÉ ESTE GUARDIÁN ───────────────────────────────────────────────────────────────────────
# El paso 6 del ADR quedó PARCIAL con esta frase: «pressure-vessel con un juego real sigue sin
# ejercitarse», porque el runtime sniper sólo se baja al instalar un juego y eso pide credenciales.
# Falso techo: el depot está publicado y pineado (`docs/state/qorpa-imagenes.toml`), así que se
# coloca a mano y **no hace falta cuenta, ni juego, ni pantalla** para responder la pregunta que
# ordenaba el diseño — ¿nuestra jaula deja anidar la de Valve?
#
# ── QUÉ MIDE, Y POR QUÉ ESO Y NO OTRA COSA ──────────────────────────────────────────────────────
# El veredicto es `/etc/os-release` dentro del contenedor: si dice «Steam Runtime 3 (sniper)», el
# runtime REAL se montó. NO se mide con `ldd --version`, que es la comprobación que uno escribiría
# primero y sale mal: pressure-vessel **importa la libc del host cuando es más nueva** que la del
# runtime, así que ver la glibc de la instancia adentro es lo correcto y no prueba nada.
#
# Y mide la contraparte: con `nesting = false` el mismo comando tiene que MORIR. Una concesión que
# no se puede apagar no es una concesión — sin este segundo tramo, el guardián diría «anida» aunque
# la jaula no estuviera haciendo nada.
set -eu
QORPA_ROOT="${HAMMER_QORPA_ROOT:-/var/lib/hammer/qorpa}"
HAMMER="${TAKANA_BIN:-${HAMMER_BIN:-./target/release/takana}}"
ID="${1:-sniper-probe}"
UBUNTU_URL="https://cdimage.ubuntu.com/ubuntu-base/releases/24.04/release/ubuntu-base-24.04.3-base-amd64.tar.gz"
UBUNTU_SHA="6bc2cde3930ad088b3bb46fa45279e96d25bc3810f209850ecbe4722711874f9"
DEPOT_URL="https://repo.steampowered.com/steamrt-images-sniper/snapshots/3.0.20260805.254768/SteamLinuxRuntime_sniper.tar.xz"
DEPOT_SHA="e264f0639ab775338311036f207b35cebe99bc417b016b53931ebca8b30b3d94"
export HAMMER_QORPA_ROOT="$QORPA_ROOT"
echo "== qorpa root: $QORPA_ROOT"
# 1. Las dos piezas, por digest. `pull` verifica ANTES de desempacar y es idempotente.
"$HAMMER" qorpa pull "$UBUNTU_URL" --sha256 "$UBUNTU_SHA" --label ubuntu-base-24.04.3
# El depot NO es un rootfs (trae `run`, `pressure-vessel/` y la imagen adentro): se trae verificado
# y sin desempacar. Traerlo a secas FALLA el anclaje por estructura, que es lo que tiene que hacer.
"$HAMMER" qorpa pull "$DEPOT_URL" --sha256 "$DEPOT_SHA" --label steamlinuxruntime-sniper --verify-only
INST="$QORPA_ROOT/instances/$ID"
if [ ! -f "$INST/instance.toml" ]; then
"$HAMMER" qorpa create "$ID" --base "$UBUNTU_SHA" --distro ubuntu-24.04
fi
# 2. El depot va al `upper`, que es caché por D3: si esto se pierde, se rehace con este script.
# `--delay-directory-restore` no es un adorno — sin él, tar sin ser root no puede terminar de
# llenar un directorio cuyo modo final es de sólo lectura.
if [ ! -x "$INST/upper/opt/SteamLinuxRuntime_sniper/run" ]; then
mkdir -p "$INST/upper/opt"
tar -xf "$QORPA_ROOT/images/$DEPOT_SHA/archive" --delay-directory-restore -C "$INST/upper/opt"
fi
DENTRO='cd /opt/SteamLinuxRuntime_sniper && ./run -- /bin/sh -c "grep ^PRETTY_NAME= /etc/os-release; readlink /proc/self/ns/mnt"'
LOG=$(mktemp -d)
trap 'rm -rf "$LOG"' EXIT
# ── LA SALIDA VA A FICHERO, NO A `$( )` ─────────────────────────────────────────────────────────
# MEDIDO acá, y cuesta una hora si no se sabe: `SALIDA=$(timeout … hammer qorpa run …)` **se cuelga
# para siempre** aunque `timeout` mate al hijo. La sustitución de comandos no espera al PROCESO,
# espera a que se cierre el PIPE, y pressure-vessel deja descendientes (su logger) con el fd
# abierto. Con redirección a fichero el mismo comando termina y devuelve su código. Es la misma
# familia que la cicatriz del preflight: el guardián que se cuelga o miente es peor que no tenerlo.
corre() { # corre <fichero-de-salida> <segundos>
timeout -k 5 "$2" "$HAMMER" qorpa run "$ID" -- /bin/sh -c "$DENTRO" > "$1" 2>&1 < /dev/null || true
}
# 3. Con la concesión: tiene que aparecer el runtime de Valve.
sed -i 's/^nesting = false/nesting = true/' "$INST/instance.toml"
echo "== con nesting = true"
corre "$LOG/si" 300
grep -E "PRETTY_NAME|mnt:" "$LOG/si" || true
if ! grep -q "Steam Runtime 3 (sniper)" "$LOG/si"; then
tail -20 "$LOG/si"
echo "FALLA: pressure-vessel no montó el runtime sniper" >&2
exit 1
fi
# 4. Sin la concesión: tiene que MORIR. Si esto pasa, la jaula no está haciendo nada.
sed -i 's/^nesting = true/nesting = false/' "$INST/instance.toml"
echo "== con nesting = false (tiene que fallar)"
corre "$LOG/no" 120
sed -i 's/^nesting = false/nesting = true/' "$INST/instance.toml"
if grep -q "Steam Runtime 3 (sniper)" "$LOG/no"; then
echo "FALLA: anidó SIN la concesión — \`nesting\` no está conteniendo nada" >&2
exit 1
fi
# NO alcanza con «no salió sniper»: un cuelgue, un timeout o una ruta mal escrita también dejan un
# log sin esa línea, y el guardián diría OK sin haber probado nada. Se exige la EVIDENCIA POSITIVA
# de la denegación — el mismo criterio de evidencia negativa de harkaq.
if ! grep -q "Creating new namespace failed" "$LOG/no"; then
tail -20 "$LOG/no"
echo "FALLA: sin \`nesting\` no salió el rechazo esperado del kernel — no se probó nada" >&2
exit 1
fi
grep -o "bwrap: Creating new namespace failed.*" "$LOG/no" | head -1
echo "OK: pressure-vessel anida bajo la jaula con \`nesting\`, y NO anida sin ella"