producto: E2E del base-system integrado al producto, booteado in-VM (front c productionizado)
product-base-system-boot-test.sh: hidrata los 26 paquetes del base-system sobre el product-rootfs sellado (cp -an, preserva /etc/passwd/shadow/ssh del producto), lo bootea en QEMU y verifica DENTRO del guest por SSH que corren. VERDE: arje-zero PID1 + sshd + bash 5.3/git 2.54/gpg 2.4.9/useradd/ vim 9.2/119 CA certs. Nota: MEM=6144 (rootfs aumentado ~1.1G en tmpfs). Caveat conocido: ps/ip/sed resuelven a busybox por precedencia de PATH (los binarios full están, a sus rutas) — mismo patrón 'adelgazar busybox' que el producto ya aplica a coreutils; refinamiento de empaque pendiente.
Semantic delta
No definition changed: this change is text, documentation or data.
1 files · +89 −0
diff --git a/scripts/product-base-system-boot-test.sh b/scripts/product-base-system-boot-test.sh
new file mode 100755
index 00000000..33b0b60b
--- /dev/null
+++ b/scripts/product-base-system-boot-test.sh
@@ -0,0 +1,89 @@
+#!/usr/bin/env bash
+# product-base-system-boot-test.sh — E2E de la INTEGRACIÓN del userland foundational (base-system) al
+# producto: toma el product-rootfs sellado (arje-zero PID1 + sshd + userland Rust), le HIDRATA encima
+# los ~26 paquetes C del base-system (bash/git/sudo/util-linux/shadow/red/disco/TLS/gpg/proceso/editor)
+# desde sus artefactos sellados del store, lo bootea en QEMU y verifica —DENTRO del guest booteado, por
+# SSH— que esos binarios están presentes y CORREN. Es la prueba de que "el sistema instalado los trae".
+#
+# La hidratación usa `cp -an` (no-clobber): añade binarios/ficheros nuevos pero PRESERVA los configs del
+# producto (/etc/passwd, /etc/shadow, /etc/ssh/*, la seed card) ⇒ el login SSH y arje-zero intactos.
+#
+# Uso: ./scripts/product-base-system-boot-test.sh
+# Vars: PRODUCT (hash del product-rootfs; def el más reciente) KERNEL MEM (def 2048) KVM (def 1)
+# PORT (def 2224) DEADLINE (def 150)
+set -euo pipefail
+ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT"
+KERNEL="${KERNEL:-$(ls store/*-linux/boot/bzImage 2>/dev/null | head -1)}"
+MEM="${MEM:-2048}"; KVM="${KVM:-1}"; PORT="${PORT:-2224}"; DEADLINE="${DEADLINE:-150}"
+WORK="$ROOT/work/product-base-system"; RFS="$WORK/rootfs"; LOG="$WORK/console.log"
+
+if [ -n "${PRODUCT:-}" ]; then PDIR=$(ls -d store/"${PRODUCT#b3:}"*-product-rootfs 2>/dev/null | head -1)
+else PDIR=$(ls -dt store/*-product-rootfs 2>/dev/null | head -1); fi
+[ -n "$PDIR" ] && [ -d "$PDIR" ] || { echo "no encuentro product-rootfs"; exit 1; }
+[ -n "$KERNEL" ] && [ -e "$KERNEL" ] || { echo "no encuentro kernel"; exit 1; }
+echo "==> product-rootfs base: $PDIR"
+
+rm -rf "$WORK"; mkdir -p "$WORK"
+cp -a "$PDIR"/. "$RFS"/; chmod -R u+w "$RFS"; rm -rf "$RFS/.hammer"
+
+# --- hidratar el base-system encima (no-clobber: preserva configs del producto) ---
+BASE_SYSTEM="bash git sudo doas util-linux shadow kbd procps-ng iproute2 iputils dhcpcd e2fsprogs dosfstools parted rsync sed tzdata vim dbus ca-certificates gnupg lsof strace pciutils usbutils mandoc"
+echo "==> hidratando base-system encima del producto (cp -an, preserva /etc del producto)"
+hyd=0
+for n in $BASE_SYSTEM; do
+ d=$(ls -dt store/*-"$n" 2>/dev/null | head -1)
+ [ -n "$d" ] && [ -d "$d" ] || { echo " !! $n sin artefacto"; continue; }
+ for top in bin sbin lib usr etc; do
+ [ -e "$d/$top" ] && cp -an "$d/$top" "$RFS/" 2>/dev/null || true
+ done
+ hyd=$((hyd+1))
+done
+echo " $hyd/26 paquetes hidratados"
+
+# provisión de admin (authorized_keys de prueba), igual que product-boot-test
+"$(ls store/*-openssh/usr/bin/ssh-keygen | head -1)" -t ed25519 -N '' -f "$WORK/clientkey" -q
+install -d -m 0700 "$RFS/root/.ssh"; cat "$WORK/clientkey.pub" > "$RFS/root/.ssh/authorized_keys"
+chmod 0600 "$RFS/root/.ssh/authorized_keys"
+
+# sanity local: los binarios del base-system llegaron al árbol
+echo "==> chequeo local del árbol aumentado:"
+for f in bin/bash usr/bin/git usr/bin/sudo usr/sbin/useradd bin/ps sbin/ip usr/bin/gpg usr/bin/vim etc/ssl/certs/ca-certificates.crt; do
+ [ -e "$RFS/$f" ] && echo " ok $f" || { echo " FALTA $f"; exit 1; }
+done
+# no clobbereamos el login del producto
+grep -q '^root:' "$RFS/etc/passwd" && echo " ok /etc/passwd del producto intacto"
+
+( cd "$RFS" && find . -print0 | cpio --null -o -H newc -R 0:0 2>/dev/null | gzip -1 ) > "$WORK/initramfs.cpio.gz"
+accel=(-cpu Broadwell); { [ "$KVM" = 1 ] && [ -w /dev/kvm ]; } && accel=(-enable-kvm -cpu host)
+echo "==> boot QEMU (mem ${MEM}), hostfwd :$PORT->:22"
+qemu-system-x86_64 -m "$MEM" -no-reboot -nographic "${accel[@]}" \
+ -kernel "$KERNEL" -initrd "$WORK/initramfs.cpio.gz" -append "console=ttyS0 rdinit=/sbin/init" \
+ -netdev "user,id=n0,hostfwd=tcp::$PORT-:22" -device e1000,netdev=n0 > "$LOG" 2>&1 &
+QPID=$!; trap 'kill $QPID 2>/dev/null || true' EXIT
+
+SSHOPTS=(-p "$PORT" -i "$WORK/clientkey" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
+ -o GlobalKnownHostsFile=/dev/null -o PasswordAuthentication=no -o ConnectTimeout=4 -o LogLevel=ERROR)
+echo "==> esperando handshake + verificación del base-system (deadline ${DEADLINE}s)…"
+start=$(date +%s); ok=0
+while [ $(( $(date +%s) - start )) -lt "$DEADLINE" ]; do
+ kill -0 $QPID 2>/dev/null || { echo "!! QEMU murió"; break; }
+ if out=$(ssh "${SSHOPTS[@]}" root@localhost '
+ echo BASE_SYSTEM_OK uid=$(id -u); uname -sr
+ /bin/bash -c "echo bash=\$BASH_VERSION"
+ echo "git=$(git --version)"
+ echo "gpg=$(gpg --version | head -1)"
+ echo "ps=$(ps --version 2>&1 | head -1)"
+ echo "ip=$(ip -V 2>&1)"
+ echo "useradd=$(useradd --help 2>&1 | head -1)"
+ echo "sed=$(sed --version | head -1)"
+ echo "vim=$(vim --version | head -1)"
+ echo "certs=$(grep -c "BEGIN CERT" /etc/ssl/certs/ca-certificates.crt) CA"
+ ' 2>/dev/null); then
+ echo "============== GUEST BASE-SYSTEM =============="; echo "$out"; echo "=============================================="
+ echo "$out" | grep -q BASE_SYSTEM_OK && ok=1; break
+ fi
+ sleep 3
+done
+kill $QPID 2>/dev/null || true
+if [ "$ok" = 1 ]; then echo "✓✓ base-system integrado + booteado: el producto trae y corre el userland foundational"; exit 0
+else echo "✗ no hubo handshake/verificación; console:"; tail -25 "$LOG"; exit 1; fi