feat: custom boot branding, MBR fix, Plymouth theme, CI smoke tests

Boot fix:
- Ship proven Debian Live MBR (4552) as branding/isohdpfx.bin — the
  ISOLINUX package MBR (33ed) doesn't boot on all hardware. This was
  the root cause of "machine doesn't pick up the USB".

Branding:
- Custom GRUB background: pixel-art floating island (1024x574)
- Archipelago pixel-art logo for Plymouth boot splash
- GRUB theme: dark background, orange selected item, no broken font refs
- Plymouth theme: script-based with progress bar, LUKS prompt support
- Plymouth + splash added to target rootfs packages
- GRUB theme installed on both installer ISO and target system
- Serial console (ttyS0) added to kernel params for QEMU debugging

CI improvements:
- Smoke test step: mounts ISO, verifies all critical files, checks
  initrd has live-boot, confirms boot=live in grub.cfg. Fails build
  before copying to Builds if any check fails.

Dev workflow:
- dev-branding.sh: extract ISO, swap branding, repackage, boot in QEMU
  (~10 seconds vs 20 min full rebuild)
- generate-grub-background.py: procedural cyberpunk background generator
- generate-plymouth-logo.py: procedural logo generator
- Improved test-iso-qemu.sh: --bios/--nographic flags, serial logging

Build:
- Simplified live-boot install (clean chroot, no complex fallbacks)
- Static branding images preferred, generators as fallback

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-27 22:26:56 +00:00
parent e8c80263f3
commit f3f7b8b72f
11 changed files with 888 additions and 43 deletions

View File

@@ -265,6 +265,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
unclutter \
fonts-liberation \
xfonts-base \
plymouth \
plymouth-themes \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
@@ -464,51 +466,27 @@ linux-image-${DEB_ARCH},grub-efi-${DEB_ARCH},grub-pc-bin,\
pciutils,usbutils,less,nano \
bookworm /installer http://deb.debian.org/debian
# Install live-boot separately — debootstrap minbase resolver cannot handle it.
# Use apt-get with explicit root dir instead of chroot (avoids /proc issues in containers).
# Install live-boot via chroot — debootstrap minbase resolver cannot handle it.
# The chroot approach works (confirmed in CI run 90) — just needs proc/sys/dev mounts.
echo " [container] Installing live-boot for squashfs root support..."
cp /etc/resolv.conf /installer/etc/resolv.conf 2>/dev/null || true
apt-get -o Dir=/installer -o Dir::State::status=/installer/var/lib/dpkg/status \
-o Dir::Etc::SourceList=/installer/etc/apt/sources.list \
-o Dir::Cache=/installer/var/cache/apt \
update -qq 2>/dev/null || {
# Fallback: copy host apt lists and install directly
echo " [container] apt-get Dir method failed, using dpkg extraction..."
apt-get update -qq
apt-get download live-boot live-boot-initramfs-tools 2>/dev/null
for deb in live-boot*.deb; do
dpkg-deb -x "$deb" /installer/ 2>/dev/null || true
done
rm -f live-boot*.deb
}
# Try chroot install if apt-get Dir method populated the lists
if [ -f /installer/var/lib/apt/lists/*_Packages 2>/dev/null ]; then
mount --bind /proc /installer/proc 2>/dev/null || true
mount --bind /sys /installer/sys 2>/dev/null || true
mount --bind /dev /installer/dev 2>/dev/null || true
chroot /installer apt-get install -y --no-install-recommends live-boot live-boot-initramfs-tools 2>/dev/null || true
chroot /installer apt-get clean 2>/dev/null || true
umount /installer/dev 2>/dev/null || true
umount /installer/sys 2>/dev/null || true
umount /installer/proc 2>/dev/null || true
fi
mount --bind /proc /installer/proc
mount --bind /sys /installer/sys
mount --bind /dev /installer/dev
chroot /installer apt-get update -qq
chroot /installer apt-get install -y --no-install-recommends live-boot live-boot-initramfs-tools
chroot /installer apt-get clean
umount /installer/dev 2>/dev/null || true
umount /installer/sys 2>/dev/null || true
umount /installer/proc 2>/dev/null || true
# Verify live-boot hooks are in place
# Verify live-boot hooks are in place (scripts/live is a FILE not a directory)
if [ -e /installer/usr/share/initramfs-tools/scripts/live ]; then
echo " [container] live-boot initramfs hooks: OK"
else
echo " [container] WARNING: live-boot hooks missing, trying dpkg extraction..."
apt-get download live-boot live-boot-initramfs-tools 2>/dev/null || true
for deb in live-boot*.deb; do
dpkg-deb -x "$deb" /installer/ 2>/dev/null || true
done
rm -f live-boot*.deb 2>/dev/null || true
if [ -e /installer/usr/share/initramfs-tools/scripts/live ]; then
echo " [container] live-boot hooks installed via dpkg extraction: OK"
else
echo " [container] FATAL: Could not install live-boot hooks!"
exit 1
fi
echo " [container] FATAL: live-boot hooks not found after install!"
ls -la /installer/usr/share/initramfs-tools/scripts/ 2>/dev/null
exit 1
fi
echo " [container] Configuring installer environment..."
@@ -725,6 +703,16 @@ if [ -d "$WORK_DIR/grub-fonts" ]; then
# Also copy unicode font for GRUB to load
cp "$WORK_DIR/grub-fonts/dejavu_16.pf2" "$INSTALLER_ISO/boot/grub/font.pf2"
fi
# Copy GRUB background image (static asset or generate if missing)
GRUB_BG="$SCRIPT_DIR/branding/grub-theme/background.png"
if [ -f "$GRUB_BG" ]; then
cp "$GRUB_BG" "$THEME_DST/background.png"
echo " Installed GRUB background"
elif [ -f "$SCRIPT_DIR/branding/generate-grub-background.py" ]; then
echo " Generating GRUB background..."
python3 "$SCRIPT_DIR/branding/generate-grub-background.py" "$THEME_DST/background.png" 2>/dev/null || \
echo " WARNING: Could not generate GRUB background"
fi
echo " Installer squashfs: $(du -h "$INSTALLER_ISO/live/filesystem.squashfs" | cut -f1)"
echo " Kernel: $(du -h "$INSTALLER_ISO/live/vmlinuz" | cut -f1)"
@@ -858,6 +846,14 @@ if [ -d "$SCRIPT_DIR/../apps" ]; then
cp -r "$SCRIPT_DIR/../apps" "$ARCH_DIR/"
fi
# Copy Plymouth theme files for installation on target
PLYMOUTH_SRC="$SCRIPT_DIR/branding/plymouth-theme"
if [ -d "$PLYMOUTH_SRC" ]; then
mkdir -p "$ARCH_DIR/plymouth-theme"
cp "$PLYMOUTH_SRC/"* "$ARCH_DIR/plymouth-theme/"
echo " Included Plymouth theme"
fi
# =============================================================================
# STEP 3b: Bundle container images for offline installation
# =============================================================================
@@ -2117,6 +2113,23 @@ if [ -d "$BOOT_MEDIA/boot/grub/themes/archipelago" ]; then
echo " Installed Archipelago GRUB theme on target"
fi
# Install Archipelago Plymouth theme on target system
if [ -d "$BOOT_MEDIA/archipelago/plymouth-theme" ]; then
PLYMOUTH_DIR="/mnt/target/usr/share/plymouth/themes/archipelago"
mkdir -p "$PLYMOUTH_DIR"
cp "$BOOT_MEDIA/archipelago/plymouth-theme/"* "$PLYMOUTH_DIR/"
# Set as default Plymouth theme
chroot /mnt/target plymouth-set-default-theme archipelago 2>/dev/null || \
ln -sf /usr/share/plymouth/themes/archipelago/archipelago.plymouth \
/mnt/target/etc/alternatives/default.plymouth 2>/dev/null || true
# Enable splash in GRUB
if ! grep -q "splash" /mnt/target/etc/default/grub; then
sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT="\(.*\)"/GRUB_CMDLINE_LINUX_DEFAULT="\1 splash"/' \
/mnt/target/etc/default/grub 2>/dev/null || true
fi
echo " Installed Archipelago Plymouth theme on target"
fi
# Regenerate initramfs — the one from Docker export is corrupt/incomplete
# (Docker builds have limited /proc, /sys, /dev so initramfs generation fails silently)
echo " Regenerating initramfs..."
@@ -2513,7 +2526,7 @@ else
fi
menuentry "Install Archipelago" --hotkey=i {
linux /live/vmlinuz boot=live components quiet
linux /live/vmlinuz boot=live components quiet console=ttyS0,115200 console=tty0
initrd /live/initrd.img
}
@@ -2546,7 +2559,7 @@ DEFAULT install
LABEL install
MENU LABEL Install Archipelago
KERNEL /live/vmlinuz
APPEND initrd=/live/initrd.img boot=live components quiet
APPEND initrd=/live/initrd.img boot=live components quiet console=ttyS0,115200 console=tty0
MENU DEFAULT
LABEL install-verbose
@@ -2573,8 +2586,13 @@ else
OUTPUT_ISO="$OUTPUT_DIR/archipelago-installer-${ARCH}.iso"
fi
# Use ISOLINUX isohdpfx.bin for hybrid USB boot (built in Step 2)
ISOHDPFX="$WORK_DIR/isohdpfx.bin"
# Use the proven MBR code for hybrid USB boot
# The ISOLINUX package's isohdpfx.bin (33 ed) doesn't boot on all hardware.
# We ship the Debian Live MBR (45 52) which is known to work with Balena Etcher.
ISOHDPFX="$SCRIPT_DIR/branding/isohdpfx.bin"
if [ ! -f "$ISOHDPFX" ]; then
ISOHDPFX="$WORK_DIR/isohdpfx.bin"
fi
if [ ! -f "$ISOHDPFX" ]; then
# Fallback to system-installed copy
for path in \