test(vm): add test-vm.sh script for safe gameboot validation
Add test-vm.sh script for VM-based testing of gameboot and dual-boot Windows functionality. The script sets up a QEMU VM with: - UEFI firmware (OVMF) with persistent boot entries - TPM 2.0 emulation (swtpm) - 3 virtual NVMe disks (sparse qcow2 format) - Optional Windows ISO mounting for deployment testing Validates: ISO build/boot, dual-boot Windows spoke, conflict detection, fail-safe mechanisms, carving, wimlib apply, unattend injection, BCD configuration, Windows OOBE and FirstBoot, hibernation cycles. Does not validate: GPU resume, real Secure Boot activation, VANGUARD (which rejects VMs).
This commit is contained in:
Executable
+92
@@ -0,0 +1,92 @@
|
||||
#!/bin/bash
|
||||
# ============================================================
|
||||
# test-vm.sh — VM de test pour gameboot + dual-boot Windows, SANS RISQUE.
|
||||
#
|
||||
# Reproduit la machine cible : UEFI (OVMF, avec vars persistantes pour les
|
||||
# entrées de boot), TPM 2.0 (swtpm), 3 disques NVMe virtuels (vide FWS / faux
|
||||
# disque « jeux » / cible Windows). Disques qcow2 CREUX → coût disque réel = ce
|
||||
# qui est écrit, pas la taille nominale. Aucune donnée réelle touchée.
|
||||
#
|
||||
# CE QUE ÇA VALIDE : build/boot de l'ISO, spoke « Dual-boot Windows », contrôle
|
||||
# de conflit du récap, garde-fous fail-closed (choisir le disque FWS comme
|
||||
# cible Windows → doit ABORTER), carve, wimlib apply, injection unattend, BCD
|
||||
# (voie WinPE), OOBE Windows + auto-login + FirstBoot, l'aller-retour hibernate.
|
||||
# CE QUE ÇA NE VALIDE PAS (→ vrai matériel) : resume du GPU RTX 5090, activation
|
||||
# Secure Boot au firmware réel, et surtout VANGUARD (qui refuse justement la VM).
|
||||
#
|
||||
# Usage :
|
||||
# scripts/test-vm.sh [ISO_FWS] [ISO_WINDOWS]
|
||||
# ISO_FWS : défaut = la plus récente dans out/ (REBUILD d'abord : ./build-offi.sh !)
|
||||
# ISO_WINDOWS : optionnelle, montée en 2e CD pour tester le déploiement Windows.
|
||||
#
|
||||
# Prérequis (Arch) : sudo pacman -S --needed qemu-full edk2-ovmf swtpm
|
||||
# ============================================================
|
||||
set -euo pipefail
|
||||
|
||||
REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
WORK="$REPO/out/test-vm"
|
||||
mkdir -p "$WORK"
|
||||
|
||||
# --- ISO FWS (rebuild indispensable pour avoir la feature gameboot) ---------
|
||||
ISO_FWS="${1:-}"
|
||||
if [ -z "$ISO_FWS" ]; then
|
||||
ISO_FWS="$(find "$REPO/out" -name '*.iso' -not -path '*/test-vm/*' -printf '%T@ %p\n' 2>/dev/null \
|
||||
| sort -rn | head -1 | cut -d' ' -f2-)"
|
||||
fi
|
||||
[ -n "$ISO_FWS" ] && [ -f "$ISO_FWS" ] || { echo "ISO FWS introuvable — lance d'abord ./build-offi.sh"; exit 1; }
|
||||
echo "==> ISO FWS : $ISO_FWS"
|
||||
echo " (⚠ vérifie que c'est un build RÉCENT, avec gameboot — pas une vieille ISO de out/)"
|
||||
ISO_WIN="${2:-}"
|
||||
|
||||
# --- Outils ---
|
||||
command -v qemu-system-x86_64 >/dev/null || { echo "installe : sudo pacman -S --needed qemu-full edk2-ovmf swtpm"; exit 1; }
|
||||
|
||||
# --- OVMF (firmware UEFI) : code RO + vars RW par-VM ------------------------
|
||||
OVMF_CODE=""; OVMF_VARS_SRC=""
|
||||
for c in /usr/share/edk2/x64/OVMF_CODE.4m.fd /usr/share/edk2/x64/OVMF_CODE.fd \
|
||||
/usr/share/OVMF/OVMF_CODE.fd /usr/share/edk2-ovmf/x64/OVMF_CODE.fd; do
|
||||
[ -f "$c" ] && { OVMF_CODE="$c"; break; }; done
|
||||
for v in /usr/share/edk2/x64/OVMF_VARS.4m.fd /usr/share/edk2/x64/OVMF_VARS.fd \
|
||||
/usr/share/OVMF/OVMF_VARS.fd /usr/share/edk2-ovmf/x64/OVMF_VARS.fd; do
|
||||
[ -f "$v" ] && { OVMF_VARS_SRC="$v"; break; }; done
|
||||
[ -n "$OVMF_CODE" ] && [ -n "$OVMF_VARS_SRC" ] || { echo "OVMF introuvable — sudo pacman -S edk2-ovmf"; exit 1; }
|
||||
[ -f "$WORK/OVMF_VARS.fd" ] || cp "$OVMF_VARS_SRC" "$WORK/OVMF_VARS.fd"
|
||||
|
||||
# --- Disques NVMe virtuels CREUX (recréés si absents) -----------------------
|
||||
# nvme0 = FWS (install) · nvme1 = faux « jeux » (doit rester intact) ·
|
||||
# nvme2 = cible Windows (assez grand : swap 96 Gio + NTFS + ESP).
|
||||
mk(){ [ -f "$WORK/$1" ] || qemu-img create -f qcow2 "$WORK/$1" "$2" >/dev/null; }
|
||||
mk fws.qcow2 64G
|
||||
mk games.qcow2 32G
|
||||
mk win.qcow2 300G
|
||||
echo "==> Disques : $WORK/{fws,games,win}.qcow2 (creux)"
|
||||
|
||||
# --- TPM 2.0 (swtpm) --------------------------------------------------------
|
||||
TPMDIR="$WORK/tpm"; mkdir -p "$TPMDIR"
|
||||
swtpm socket --tpmstate dir="$TPMDIR" --ctrl type=unixio,path="$TPMDIR/sock" \
|
||||
--tpm2 --terminate &
|
||||
SWTPM_PID=$!
|
||||
trap 'kill "$SWTPM_PID" 2>/dev/null || true' EXIT
|
||||
sleep 1
|
||||
|
||||
# --- CD Windows optionnel ---------------------------------------------------
|
||||
WINCD=()
|
||||
if [ -n "$ISO_WIN" ] && [ -f "$ISO_WIN" ]; then
|
||||
WINCD=(-drive file="$ISO_WIN",media=cdrom,readonly=on)
|
||||
echo "==> ISO Windows montée en 2e CD (dans le live : la monter, puis la pointer dans le spoke)."
|
||||
fi
|
||||
|
||||
echo "==> Lancement de la VM (UEFI + TPM2 + 3 NVMe). Ferme la fenêtre pour quitter."
|
||||
exec qemu-system-x86_64 \
|
||||
-machine q35,smm=on,accel=kvm -cpu host -smp 4 -m 8G \
|
||||
-drive if=pflash,format=raw,readonly=on,file="$OVMF_CODE" \
|
||||
-drive if=pflash,format=raw,file="$WORK/OVMF_VARS.fd" \
|
||||
-chardev socket,id=chrtpm,path="$TPMDIR/sock" \
|
||||
-tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-crb,tpmdev=tpm0 \
|
||||
-drive file="$WORK/fws.qcow2",if=none,id=d0 -device nvme,drive=d0,serial=FWS0 \
|
||||
-drive file="$WORK/games.qcow2",if=none,id=d1 -device nvme,drive=d1,serial=GAMES1 \
|
||||
-drive file="$WORK/win.qcow2",if=none,id=d2 -device nvme,drive=d2,serial=WIN2 \
|
||||
-cdrom "$ISO_FWS" "${WINCD[@]}" \
|
||||
-boot menu=on \
|
||||
-netdev user,id=n0 -device virtio-net,netdev=n0 \
|
||||
-vga virtio -display gtk,gl=on
|
||||
Reference in New Issue
Block a user