Files
takana/scripts/test-guardianes-wasm.sh
Sergio 476168bb07 takana etapa 5c: comentarios de scripts, MOTD, y un BUG que introdujo la etapa 4
250 líneas de comentario en 151 scripts. Control verificado: el diff no toca
NI UNA línea que no empiece por #, y la sintaxis de los 151 pasa.

El barrido saltea heredocs y cadenas triples, y el guardián DISPARÓ 3 veces:
las tres eran el MOTD que el script escribe DENTRO de la imagen construida —
texto del producto, no comentario del script. Se cambiaron aparte y a
propósito, que es rebranding, no limpieza.

Y el hallazgo caro:  casaba contra ,
que es el TARGET de tracing — o sea el module_path!, o sea el nombre del crate.
La etapa 4 lo movió a  y el script quedó casando NADA. No fallaba:
imprimía cero atribuciones, indistinguible de un log sin problemas. Comprobado
con el binario (RUST_LOG=info sobre zlib), no deducido. Ahora acepta las dos, y
tiene que seguir aceptándolas porque los logs viejos en disco dicen la vieja.

Además 14 rutas de módulo  en docs, que el barrido anterior no tocó
porque  no es frontera de palabra.
2026-09-09 19:28:48 +00:00

101 lines
4.3 KiB
Bash
Executable File

#!/usr/bin/env sh
# test-guardianes-wasm.sh — le pone delante a los guardianes de la cadena wasm las formas conocidas
# de romperla y exige que las maten. Y corre un CONTROL con el sysroot intacto que tiene que PASAR.
#
# POR QUÉ EXISTE. Un guardián que nunca falló no se sabe si sirve, y uno que falla SIEMPRE se ve
# idéntico a uno que funciona: por eso el control no es un extra, es la mitad de la prueba. El
# método lo aportó la sesión takana-f8 (su scripts/test-atuq-politica.py hace lo mismo con el cruce
# política↔XPI).
#
# NO CONSTRUYE NADA, NO TOMA EL LOCK Y NO ESCRIBE EN EL STORE: trabaja sobre copias temporales de
# artefactos ya sellados, así que se puede correr con la granja a pleno.
#
# ./scripts/test-guardianes-wasm.sh [--store DIR]
set -u
STORE="./store"
[ "${1:-}" = "--store" ] && STORE="$2"
LAB="./.dev-fs/alpine"
TMP="${TMPDIR:-/tmp}/guardianes-wasm.$$"
ok=0; mal=0
di() { printf '%s\n' "$*"; }
fin() { rm -rf "$TMP"; }
trap fin EXIT
# ⚠ EL ARTEFACTO SE RESUELVE POR EL HASH DE LA RECETA, NUNCA POR GLOB. La primera versión de este
# script hacía `ls -d "$STORE"/*-wasi-libcxx | head -1` y agarró el artefacto VIEJO —el de antes de
# que la receta creara el directorio-sonda— así que el CONTROL falló y los cuatro sabotajes
# "pasaron". Es la misma trampa que el cache-hit que congela regresiones: un artefacto anterior se
# hace pasar por el actual y la prueba mide otra cosa. Y es, además, la demostración de para qué
# sirve el control: sin él eso se habría leído como "4 en verde, guardianes ok".
art() {
h=$(./target/release/takana --store "$STORE" hash "recipes/$1.toml" 2>/dev/null | tail -1)
h=${h#b3:}
[ -n "$h" ] && [ -d "$STORE/$h-$1" ] && printf '%s' "$STORE/$h-$1"
}
libc=$(art wasi-libc)
cxx=$(art wasi-libcxx)
[ -n "$libc" ] && [ -n "$cxx" ] || { di "el store no tiene el artefacto VIGENTE de wasi-libc/wasi-libcxx (¿sin construir?) — nada que probar"; exit 77; }
di "artefactos vigentes: $(basename "$libc" | cut -c1-12)… / $(basename "$cxx" | cut -c1-12)…"
[ -d "$LAB" ] || { di "sin lab en $LAB"; exit 77; }
# Arma un sysroot fusionado como el que ve firefox, y le aplica el sabotaje que se le pida.
armar() {
rm -rf "$TMP/s"; mkdir -p "$TMP/s"
cp -a "$libc"/usr/share/wasi-sysroot/. "$TMP/s"/
cp -a "$cxx"/usr/share/wasi-sysroot/. "$TMP/s"/
case "${1:-}" in
sin-sonda) rm -rf "$TMP/s/include/c++/v1" ;;
sin-libcxx) rm -f "$TMP/s"/lib/*/libc++.a ;;
sin-libc) rm -f "$TMP/s"/lib/*/libc.a ;;
sin-cstring) find "$TMP/s/include" -name cstring -delete ;;
intacto) : ;;
esac
}
# La prueba EXACTA que hace el configure de firefox, dentro del lab.
probar_cxx() {
bwrap --overlay-src "$LAB" --tmp-overlay / --proc /proc --dev /dev --tmpfs /tmp \
--ro-bind "$TMP/s" /sysroot --unshare-all --die-with-parent \
/bin/sh -c 'echo "#include <cstring>" > /tmp/p.cpp
clang++ -std=gnu++20 --target=wasm32-wasip1 /tmp/p.cpp --sysroot=/sysroot -c -o /tmp/p.o' \
>/dev/null 2>&1
}
# --- EL CONTROL. Va PRIMERO a propósito: si esto no pasa, los demás resultados no significan nada,
# porque un guardián que mata todo se ve igual que uno que discrimina.
armar intacto
if probar_cxx; then
di "✓ CONTROL sysroot intacto -> compila (el guardián NO es un «mata siempre»)"; ok=$((ok+1))
else
di "✗ CONTROL sysroot intacto -> NO compila. El resto de esta prueba no vale nada."; mal=$((mal+1))
fi
# --- LOS SABOTAJES. Cada uno es una forma conocida de romper la cadena; todos tienen que matar.
for caso in sin-sonda sin-cstring; do
armar "$caso"
if probar_cxx; then
di "✗ SABOTAJE $caso -> compiló igual. El guardián NO cubre este caso."; mal=$((mal+1))
else
di "✓ SABOTAJE $caso -> muere, como debe"; ok=$((ok+1))
fi
done
# --- Los de presencia pura, que son los que el caso `sin-sonda` demostró insuficientes por sí solos.
for caso in sin-libcxx sin-libc; do
armar "$caso"
falta=0
for t in wasm32-wasip1 wasm32-wasip1-threads; do
[ -s "$TMP/s/lib/$t/libc++.a" ] && [ -s "$TMP/s/lib/$t/libc.a" ] || falta=1
done
if [ "$falta" = 1 ]; then
di "✓ SABOTAJE $caso -> el test de presencia lo caza"; ok=$((ok+1))
else
di "✗ SABOTAJE $caso -> el test de presencia NO lo caza"; mal=$((mal+1))
fi
done
di ""
di "resumen: $ok en verde, $mal en rojo"
[ "$mal" = 0 ] || exit 1