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 1561Shell 203Rust 109Markdown 993728 Definiciones

prueba que los guardianes de la cadena wasm sirven — con CONTROL

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 con el sysroot intacto —que
tiene que PASAR— no es un extra: es la mitad de la prueba. El método lo aportó
la sesión hammer-f8 (scripts/test-atuq-politica.py hace lo mismo con el cruce
política<->XPI).

Le pone delante a la cadena las cuatro formas conocidas de romperla —sin la
sonda include/c++/v1, sin cstring, sin libc++.a, sin libc.a— y exige que las
cuatro maten, usando la invocación EXACTA del configure de firefox dentro del
lab. No construye nada, no toma work/.farm-build.lock y no escribe en el store:
trabaja sobre copias temporales de artefactos ya sellados, así que corre con la
granja a pleno.

Y el control se ganó el sueldo en su primera corrida: salió en ROJO. La causa no
era un guardián flojo sino este script, que resolvía el artefacto con
 y agarraba el VIEJO —el de antes de que la
receta creara el directorio-sonda—. Misma trampa que el cache-hit que congela
regresiones: un artefacto anterior se hace pasar por el actual y la prueba mide
otra cosa. Sin el control se habría leído como «4 en verde, guardianes ok».

Ahora el artefacto se resuelve por  de la receta, nunca por glob.
5 en verde, 0 en rojo.

4fae3ee1ff805b51eca6bfdce69f02daf77b4696 · por Sergio · (hace 1 mes) · padre 292df5909 · ver el árbol en este commit

Delta semántico

Ninguna definición cambió: el cambio es de texto, documentación o datos.

1 archivos · +100 −0

diff --git a/scripts/test-guardianes-wasm.sh b/scripts/test-guardianes-wasm.sh
new file mode 100755
index 00000000..565ca2d4
--- /dev/null
+++ b/scripts/test-guardianes-wasm.sh
@@ -0,0 +1,100 @@
+#!/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 hammer-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/hammer --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