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.
194 lines
9.5 KiB
Bash
Executable File
194 lines
9.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ssh-e2e-test.sh — SPIKE de validación (sucio, temporal) del Paso 1: probar el handshake SSH REAL
|
|
# contra un takana booteado en QEMU, con sshd supervisado por arje-zero como genesis card.
|
|
#
|
|
# Esto NO es plomería de producto: arma un `work/rootfs-ssh-test` desechable = el 4/4 limpio del
|
|
# store + openssh + netup (todos PRECOMPILADOS de la caché del lab, no rebuild) + una seed con un
|
|
# card `sshd`, y lo bootea como initramfs. La red es QEMU slirp con hostfwd :2222->:22, así que el
|
|
# host hace `ssh -p 2222 root@localhost` SIN tocar firewall/bridge (la lección de netup). El chroot
|
|
# de privsep —que el bwrap anidado no pudo— acá corre como root REAL del guest.
|
|
#
|
|
# Quema tres incógnitas que el sandbox de bwrap dejó abiertas:
|
|
# 1. el handshake completo (post-chroot, post-setuid sshd-user) ocurre,
|
|
# 2. arje maneja el ciclo de vida del daemon (Restart) como cualquier card Native,
|
|
# 3. los fds de red de sshd no segfaultean contra el musl del target.
|
|
#
|
|
# Variables: KERNEL (def store/*-linux/boot/bzImage) MEM (def 2048) KVM (1 si /dev/kvm)
|
|
# PORT (hostfwd, def 2222) DEADLINE (def 150s)
|
|
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:-2222}"
|
|
DEADLINE="${DEADLINE:-150}"
|
|
WORK="$ROOT/work/ssh-e2e"
|
|
RFS="$ROOT/work/rootfs-ssh-test"
|
|
LOG="$WORK/console.log"
|
|
|
|
pick() { ls -d store/*-"$1" 2>/dev/null | head -1; }
|
|
MUSL=$(pick musl); BB=$(pick busybox); ARJE="store/69e2cab8ac00c33cde7680eb393952e2c7f9ae9af24c180c6593d7a86482efb9-arje-zero"
|
|
NETUP=$(pick netup); OSSH=$(pick openssh)
|
|
for v in KERNEL MUSL BB ARJE NETUP OSSH; do
|
|
p="${!v}"; [ -n "$p" ] && [ -e "$p" ] || { echo "falta $v ($p)"; exit 1; }
|
|
done
|
|
echo "==> kernel $KERNEL"
|
|
echo "==> componentes: musl busybox arje-zero netup openssh (precompilados del store)"
|
|
|
|
# ── 1) ensamblar el rootfs desechable ───────────────────────────────────────────────────────────
|
|
rm -rf "$RFS" "$WORK"; mkdir -p "$RFS" "$WORK"
|
|
for src in "$MUSL" "$BB" "$ARJE" "$NETUP" "$OSSH"; do
|
|
cp -a "$src"/. "$RFS"/ 2>/dev/null || true
|
|
done
|
|
chmod -R u+w "$RFS" # el store está sellado read-only; el staging debe ser escribible
|
|
rm -rf "$RFS/.hammer"
|
|
mkdir -p "$RFS"/{proc,sys,dev,dev/pts,run,tmp,etc,etc/ssh,root,root/.ssh,var,var/empty,ente,sbin,bin,usr/bin}
|
|
chmod 0711 "$RFS/var/empty"
|
|
ln -sf /usr/bin/arje-zero "$RFS/sbin/init"
|
|
# busybox a /bin/sh + applets que la getty/seed necesitan (por si el cp no dejó symlinks en /bin)
|
|
[ -e "$RFS/bin/busybox" ] || cp -a "$BB"/bin/busybox "$RFS/bin/busybox"
|
|
for a in sh getty; do ln -sf busybox "$RFS/bin/$a"; done
|
|
|
|
# usuarios: root (login por llave) + sshd (privsep). shells reales para que sshd ejecute el comando.
|
|
cat > "$RFS/etc/passwd" <<'EOF'
|
|
root:x:0:0:root:/root:/bin/sh
|
|
sshd:x:74:74:sshd privsep:/var/empty:/bin/false
|
|
EOF
|
|
cat > "$RFS/etc/group" <<'EOF'
|
|
root:x:0:
|
|
sshd:x:74:
|
|
EOF
|
|
cat > "$RFS/etc/ssh/sshd_config" <<'EOF'
|
|
Port 22
|
|
ListenAddress 0.0.0.0
|
|
PermitRootLogin yes
|
|
PubkeyAuthentication yes
|
|
PasswordAuthentication no
|
|
AuthorizedKeysFile /root/.ssh/authorized_keys
|
|
StrictModes no
|
|
Subsystem sftp /usr/libexec/sftp-server
|
|
EOF
|
|
|
|
# ── 2) llave de cliente desechable (host) → authorized_keys del guest ────────────────────────────
|
|
"$OSSH/usr/bin/ssh-keygen" -t ed25519 -N '' -f "$WORK/clientkey" -q
|
|
cat "$WORK/clientkey.pub" > "$RFS/root/.ssh/authorized_keys"
|
|
chmod 0600 "$RFS/root/.ssh/authorized_keys"
|
|
|
|
# ── 3) seed card: console-getty + un card `sshd` (Native, Restart) ───────────────────────────────
|
|
# El card sshd arranca la red (netup, DHCP slirp), genera host keys (ssh-keygen -A) y exec sshd -D.
|
|
# Mismo esquema validado de STAGE1_SEED_CARD (takana-bootstrap); ULIDs nuevos A10/A11/A12.
|
|
SSHD_CMD='/usr/bin/netup; /usr/bin/ssh-keygen -A; exec /usr/sbin/sshd -D -e'
|
|
cat > "$RFS/ente/seed.card.json" <<EOF
|
|
{
|
|
"schema_version": 1,
|
|
"id": "01HQAR53D4M2NBV8KZTYXFQA10",
|
|
"lineage": null,
|
|
"label": "hammer-ssh-spike",
|
|
"provides": ["Spawn", "Journal"],
|
|
"requires": [],
|
|
"permissions": { "networking": "full", "filesystem": "read-write", "ipc": { "allow": [] }, "processes": true },
|
|
"soma": {
|
|
"namespaces": { "mount": false, "pid": false, "net": false, "uts": false, "ipc": false, "user": false, "cgroup": false },
|
|
"rlimits": { "mem_bytes": null, "nproc": null, "nofile": null },
|
|
"cgroup": { "path": "arje.slice/hammer", "cpu_weight": null, "io_weight": null },
|
|
"cpu_affinity": null
|
|
},
|
|
"payload": "Virtual",
|
|
"supervision": "OneShot",
|
|
"lifecycle": "daemon",
|
|
"priority": "normal",
|
|
"flow": { "input": [], "output": [] },
|
|
"genesis": [
|
|
{
|
|
"schema_version": 1,
|
|
"id": "01HQAR53D4M2NBV8KZTYXFQA11",
|
|
"lineage": null,
|
|
"label": "console-getty",
|
|
"provides": [],
|
|
"requires": [],
|
|
"permissions": { "networking": "none", "filesystem": "read-write", "ipc": { "allow": [] }, "processes": true },
|
|
"soma": {
|
|
"namespaces": { "mount": false, "pid": false, "net": false, "uts": false, "ipc": false, "user": false, "cgroup": false },
|
|
"rlimits": { "mem_bytes": null, "nproc": null, "nofile": null },
|
|
"cgroup": { "path": "arje.slice/getty", "cpu_weight": null, "io_weight": null },
|
|
"cpu_affinity": null
|
|
},
|
|
"payload": { "Native": { "exec": "/bin/busybox", "argv": ["getty", "-n", "-l", "/bin/sh", "115200", "console"], "envp": [] }},
|
|
"supervision": { "Restart": { "initial": 200, "max": 10000 } },
|
|
"lifecycle": "daemon",
|
|
"priority": "normal",
|
|
"flow": { "input": [], "output": [] },
|
|
"genesis": []
|
|
},
|
|
{
|
|
"schema_version": 1,
|
|
"id": "01HQAR53D4M2NBV8KZTYXFQA12",
|
|
"lineage": null,
|
|
"label": "sshd",
|
|
"provides": [],
|
|
"requires": [],
|
|
"permissions": { "networking": "full", "filesystem": "read-write", "ipc": { "allow": [] }, "processes": true },
|
|
"soma": {
|
|
"namespaces": { "mount": false, "pid": false, "net": false, "uts": false, "ipc": false, "user": false, "cgroup": false },
|
|
"rlimits": { "mem_bytes": null, "nproc": null, "nofile": null },
|
|
"cgroup": { "path": "arje.slice/sshd", "cpu_weight": null, "io_weight": null },
|
|
"cpu_affinity": null
|
|
},
|
|
"payload": { "Native": { "exec": "/bin/busybox", "argv": ["sh", "-c", "${SSHD_CMD}"], "envp": [["HOME", "/root"]] }},
|
|
"supervision": { "Restart": { "initial": 500, "max": 20000 } },
|
|
"lifecycle": "daemon",
|
|
"priority": "normal",
|
|
"flow": { "input": [], "output": [] },
|
|
"genesis": []
|
|
}
|
|
]
|
|
}
|
|
EOF
|
|
|
|
# ── 4) empaquetar initramfs ──────────────────────────────────────────────────────────────────────
|
|
# -R 0:0: el cpio corre como uid no-root; sin esto el rootfs queda con nuestro uid y sshd rechaza
|
|
# /var/empty ("must be owned by root"). Reasigna todo a root:root dentro del archivo.
|
|
( cd "$RFS" && find . -print0 | cpio --null -o -H newc -R 0:0 2>/dev/null | gzip -1 ) > "$WORK/initramfs.cpio.gz"
|
|
echo "==> initramfs $(du -h "$WORK/initramfs.cpio.gz" | cut -f1)"
|
|
|
|
# ── 5) boot QEMU (slirp + hostfwd) en background ─────────────────────────────────────────────────
|
|
accel=(-cpu Broadwell)
|
|
if [ "$KVM" = 1 ] && [ -w /dev/kvm ]; then accel=(-enable-kvm -cpu host); fi
|
|
echo "==> boot QEMU (mem ${MEM}, kvm $([ "${accel[0]}" = -enable-kvm ] && echo sí || echo no)), 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
|
|
|
|
# ── 6) esperar a sshd y hacer el handshake real ──────────────────────────────────────────────────
|
|
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 (deadline ${DEADLINE}s)…"
|
|
start=$(date +%s); ok=0
|
|
while [ $(( $(date +%s) - start )) -lt "$DEADLINE" ]; do
|
|
if ! kill -0 $QPID 2>/dev/null; then echo "!! QEMU murió"; break; fi
|
|
if out=$(ssh "${SSHOPTS[@]}" root@localhost \
|
|
'echo HANDSHAKE_OK uid=$(id -u) user=$(id -un); uname -srm; cat /etc/os-release 2>/dev/null | head -1' 2>/dev/null); then
|
|
echo "================ RESPUESTA DEL GUEST ================"
|
|
echo "$out"
|
|
echo "===================================================="
|
|
echo "$out" | grep -q HANDSHAKE_OK && ok=1
|
|
break
|
|
fi
|
|
sleep 3
|
|
done
|
|
|
|
# ── 7) veredicto + diagnóstico ───────────────────────────────────────────────────────────────────
|
|
echo "---- consola (cola) ----"; tail -25 "$LOG" 2>/dev/null
|
|
if [ "$ok" = 1 ]; then
|
|
echo; echo "*** SSH E2E OK — handshake real contra hammer+arje, sshd como card ***"; exit 0
|
|
else
|
|
echo; echo "*** SSH E2E FALLÓ — ver $LOG ***"; exit 1
|
|
fi
|