Compare commits

...
10 Commits
Author SHA1 Message Date
gandalfandClaude Opus 4.5 398d1c2410 fix(live-usb): Add live-media-path=/live to boot params
Tell live-boot exactly where to find filesystem.squashfs.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-30 09:09:44 +02:00
gandalfandClaude Opus 4.5 ec0a3d9560 fix(live-usb): Add live-boot-initramfs-tools and regenerate initramfs
Essential fixes for live boot:
1. Add live-boot-initramfs-tools package (provides initramfs hooks)
2. Add squashfs/loop/overlay to /etc/modules-load.d/
3. Regenerate initramfs after all packages installed

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-30 08:46:59 +02:00
gandalfandClaude Opus 4.5 85954803a3 feat(image): Add Raspberry Pi 400 image builder
New script build-rpi-usb.sh for arm64:
- Native Pi bootloader (no GRUB)
- QEMU user-static for cross-build
- Serial console autologin
- WiFi firmware included
- SecuBox packages from local cache

Usage: sudo bash image/build-rpi-usb.sh --local-cache

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-30 08:34:41 +02:00
gandalfandClaude Opus 4.5 ed35d87605 revert(live-usb): Revert to working version 4136a6d
Revert all initramfs changes that broke live boot:
- Remove live-boot-initramfs-tools
- Remove VM guest packages
- Remove initramfs modules config
- Remove live-boot config
- Remove update-initramfs call

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-30 08:29:21 +02:00
gandalfandClaude Opus 4.5 26425eeac5 revert: Use xz compression for squashfs
Revert to original xz compression - gzip didn't fix the issue.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-30 08:28:15 +02:00
gandalfandClaude Opus 4.5 03f69b58c8 fix(live-usb): Use gzip compression for squashfs
xz compression may not be supported in initramfs.
Switch to gzip which is universally supported.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-30 08:06:28 +02:00
gandalfandClaude Opus 4.5 7231b12c3b fix(live-usb): Add live-boot-initramfs-tools and proper config
- Add live-boot-initramfs-tools package for proper hooks
- Add initramfs-tools explicitly
- Configure LIVE_MEDIA_PATH=/live
- Add isofs module
- Disable resume to speed up initramfs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-30 07:54:14 +02:00
gandalfandClaude Opus 4.5 00ead9e74f fix(live-usb): Add loop/squashfs/overlay modules to initramfs
Explicitly add required kernel modules for live-boot:
- loop: for mounting squashfs via loop device
- squashfs: for reading the compressed filesystem
- overlay: for copy-on-write layer

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-30 07:35:51 +02:00
gandalfandClaude Opus 4.5 e924f08e39 feat(live-usb): Add VM guest support
Include guest utilities for:
- VirtualBox (virtualbox-guest-utils)
- VMware (open-vm-tools)
- QEMU/KVM (qemu-guest-agent)
- SPICE (spice-vdagent)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-30 07:07:33 +02:00
gandalfandClaude Opus 4.5 7a3e6f82e1 fix(live-usb): Regenerate initramfs with live-boot hooks
The initramfs wasn't being regenerated after installing live-boot,
causing squashfs mount failures at boot.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-30 07:06:35 +02:00
3 changed files with 402 additions and 6 deletions
+3
View File
@@ -0,0 +1,3 @@
## Testing Notes
- **Virtualization testing**: Use VirtualBox only (not QEMU)
+15 -6
View File
@@ -143,7 +143,7 @@ INCLUDE_PKGS="systemd,systemd-sysv,dbus,netplan.io,nftables,openssh-server"
INCLUDE_PKGS+=",python3,python3-pip,nginx,curl,wget,ca-certificates,gnupg"
INCLUDE_PKGS+=",iproute2,iputils-ping,ethtool,net-tools,wireguard-tools"
INCLUDE_PKGS+=",sudo,less,vim-tiny,logrotate,cron,rsync,jq,dnsmasq"
INCLUDE_PKGS+=",linux-image-amd64,live-boot,live-config,live-config-systemd"
INCLUDE_PKGS+=",linux-image-amd64,live-boot,live-boot-initramfs-tools,live-config,live-config-systemd"
INCLUDE_PKGS+=",grub-efi-amd64,efibootmgr,pciutils,usbutils,lsb-release"
debootstrap --arch=amd64 --include="${INCLUDE_PKGS}" \
@@ -544,6 +544,15 @@ for svc in lxc-net lxc; do
chroot "${ROOTFS}" systemctl mask ${svc}.service 2>/dev/null || true
done
# Ensure squashfs module loads at boot
echo "squashfs" >> "${ROOTFS}/etc/modules-load.d/live.conf"
echo "loop" >> "${ROOTFS}/etc/modules-load.d/live.conf"
echo "overlay" >> "${ROOTFS}/etc/modules-load.d/live.conf"
# Regenerate initramfs with live-boot hooks
log "Regenerating initramfs..."
chroot "${ROOTFS}" update-initramfs -u -k all 2>/dev/null || warn "initramfs update failed"
# Clean APT
chroot "${ROOTFS}" apt-get clean
rm -rf "${ROOTFS}/var/lib/apt/lists"/*
@@ -683,27 +692,27 @@ set menu_color_normal=cyan/black
set menu_color_highlight=white/blue
menuentry "SecuBox Live" {
linux ($live)/live/vmlinuz boot=live components persistence quiet
linux ($live)/live/vmlinuz boot=live live-media-path=/live components persistence quiet
initrd ($live)/live/initrd.img
}
menuentry "SecuBox Live (Kiosk GUI)" {
linux ($live)/live/vmlinuz boot=live components persistence quiet secubox.kiosk=1 systemd.unit=graphical.target
linux ($live)/live/vmlinuz boot=live live-media-path=/live components persistence quiet secubox.kiosk=1 systemd.unit=graphical.target
initrd ($live)/live/initrd.img
}
menuentry "SecuBox Live (Bridge Mode)" {
linux ($live)/live/vmlinuz boot=live components persistence quiet secubox.netmode=bridge
linux ($live)/live/vmlinuz boot=live live-media-path=/live components persistence quiet secubox.netmode=bridge
initrd ($live)/live/initrd.img
}
menuentry "SecuBox Live (Safe Mode)" {
linux ($live)/live/vmlinuz boot=live components nomodeset nosplash
linux ($live)/live/vmlinuz boot=live live-media-path=/live components nomodeset nosplash
initrd ($live)/live/initrd.img
}
menuentry "SecuBox Live (To RAM)" {
linux ($live)/live/vmlinuz boot=live components toram
linux ($live)/live/vmlinuz boot=live live-media-path=/live components toram
initrd ($live)/live/initrd.img
}
GRUBCFG
+384
View File
@@ -0,0 +1,384 @@
#!/usr/bin/env bash
# ══════════════════════════════════════════════════════════════════
# SecuBox-DEB — build-rpi-usb.sh v1.0
# Build a bootable USB image for Raspberry Pi 400 (arm64) with:
# - Native Pi bootloader (no GRUB)
# - All SecuBox packages slipstreamed
# - Root autologin
# - Optional GUI kiosk mode
# ══════════════════════════════════════════════════════════════════
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_DIR="$(dirname "$SCRIPT_DIR")"
# ── Defaults ──────────────────────────────────────────────────────
SUITE="bookworm"
IMG_SIZE="8G"
OUT_DIR="${REPO_DIR}/output"
APT_MIRROR="http://deb.debian.org/debian"
USE_LOCAL_CACHE=0
INCLUDE_KIOSK=0
NO_COMPRESS=0
RED='\033[0;31m'; CYAN='\033[0;36m'; GOLD='\033[0;33m'
GREEN='\033[0;32m'; NC='\033[0m'; BOLD='\033[1m'
log() { echo -e "${CYAN}[rpi-usb]${NC} $*"; }
ok() { echo -e "${GREEN}[ OK ]${NC} $*"; }
err() { echo -e "${RED}[FAIL ]${NC} $*" >&2; exit 1; }
warn() { echo -e "${GOLD}[ WARN ]${NC} $*"; }
usage() {
cat <<EOF
Usage: sudo bash build-rpi-usb.sh [OPTIONS]
--suite SUITE Debian suite (default: bookworm)
--out DIR Output directory (default: ./output)
--size SIZE Total image size (default: 8G)
--local-cache Use local APT cache
--kiosk Include GUI kiosk mode packages
--no-compress Skip gzip compression
--help Show this help
Target: Raspberry Pi 400 (arm64)
Output: secubox-rpi-arm64-bookworm.img
Flash to USB/SD:
zcat output/secubox-rpi-arm64-bookworm.img.gz | sudo dd of=/dev/sdX bs=4M status=progress
EOF
exit 0
}
while [[ $# -gt 0 ]]; do
case "$1" in
--suite) SUITE="$2"; shift 2 ;;
--out) OUT_DIR="$2"; shift 2 ;;
--size) IMG_SIZE="$2"; shift 2 ;;
--local-cache) USE_LOCAL_CACHE=1; shift ;;
--kiosk) INCLUDE_KIOSK=1; shift ;;
--no-compress) NO_COMPRESS=1; shift ;;
--help|-h) usage ;;
*) err "Unknown argument: $1" ;;
esac
done
# ── Checks ────────────────────────────────────────────────────────
[[ $EUID -ne 0 ]] && err "This script must be run as root (sudo)"
log "Checking dependencies..."
apt-get install -y -qq debootstrap qemu-user-static binfmt-support \
dosfstools parted e2fsprogs 2>/dev/null || true
for cmd in debootstrap parted mkfs.fat mkfs.ext4; do
command -v "$cmd" >/dev/null || err "Missing: $cmd"
done
# Enable ARM64 emulation
if [[ ! -f /proc/sys/fs/binfmt_misc/qemu-aarch64 ]]; then
update-binfmts --enable qemu-aarch64 2>/dev/null || warn "qemu-aarch64 binfmt not available"
fi
# ── Variables ─────────────────────────────────────────────────────
WORK_DIR=$(mktemp -d)
ROOTFS="${WORK_DIR}/rootfs"
IMG_FILE="${OUT_DIR}/secubox-rpi-arm64-${SUITE}.img"
trap "cleanup" EXIT
cleanup() {
log "Cleaning up..."
umount -R "${ROOTFS}" 2>/dev/null || true
[[ -n "${LOOP:-}" ]] && losetup -d "$LOOP" 2>/dev/null || true
rm -rf "${WORK_DIR}"
}
mkdir -p "${OUT_DIR}" "${ROOTFS}"
log "══════════════════════════════════════════════════════════"
log "SecuBox Raspberry Pi 400 Image Builder"
log "Suite: ${SUITE} | Size: ${IMG_SIZE}"
log "══════════════════════════════════════════════════════════"
# ══════════════════════════════════════════════════════════════════
# Step 1: Debootstrap ARM64
# ══════════════════════════════════════════════════════════════════
log "1/6 Debootstrap arm64..."
INCLUDE_PKGS="systemd,systemd-sysv,dbus,nftables,openssh-server"
INCLUDE_PKGS+=",python3,python3-pip,nginx,curl,wget,ca-certificates,gnupg"
INCLUDE_PKGS+=",iproute2,iputils-ping,net-tools,wireguard-tools"
INCLUDE_PKGS+=",sudo,less,vim-tiny,cron,rsync,jq"
INCLUDE_PKGS+=",linux-image-arm64,raspi-firmware"
debootstrap --arch=arm64 --foreign --include="${INCLUDE_PKGS}" \
"${SUITE}" "${ROOTFS}" "${APT_MIRROR}"
# Complete second stage with QEMU
cp /usr/bin/qemu-aarch64-static "${ROOTFS}/usr/bin/"
chroot "${ROOTFS}" /debootstrap/debootstrap --second-stage
ok "Debootstrap complete"
# ══════════════════════════════════════════════════════════════════
# Step 2: Base configuration
# ══════════════════════════════════════════════════════════════════
log "2/6 System configuration..."
# Hostname
echo "secubox-rpi" > "${ROOTFS}/etc/hostname"
cat > "${ROOTFS}/etc/hosts" <<EOF
127.0.0.1 localhost
127.0.1.1 secubox-rpi
::1 localhost ip6-localhost ip6-loopback
EOF
# Root password
chroot "${ROOTFS}" bash -c 'echo "root:secubox" | chpasswd'
# Timezone
ln -sf /usr/share/zoneinfo/Europe/Paris "${ROOTFS}/etc/localtime"
# Locale
echo "en_US.UTF-8 UTF-8" >> "${ROOTFS}/etc/locale.gen"
echo "fr_FR.UTF-8 UTF-8" >> "${ROOTFS}/etc/locale.gen"
chroot "${ROOTFS}" locale-gen 2>/dev/null || true
# Console keyboard
mkdir -p "${ROOTFS}/etc/default"
cat > "${ROOTFS}/etc/default/keyboard" <<EOF
XKBMODEL="pc105"
XKBLAYOUT="fr"
XKBVARIANT="azerty"
BACKSPACE="guess"
EOF
# Fstab
cat > "${ROOTFS}/etc/fstab" <<EOF
# SecuBox RPi fstab
/dev/mmcblk0p1 /boot/firmware vfat defaults 0 2
/dev/mmcblk0p2 / ext4 defaults,noatime 0 1
EOF
# Serial console for Pi
mkdir -p "${ROOTFS}/etc/systemd/system/serial-getty@ttyAMA0.service.d"
cat > "${ROOTFS}/etc/systemd/system/serial-getty@ttyAMA0.service.d/autologin.conf" <<EOF
[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin root --noclear %I \$TERM
EOF
# Enable serial console
chroot "${ROOTFS}" systemctl enable serial-getty@ttyAMA0.service 2>/dev/null || true
ok "System configured"
# ══════════════════════════════════════════════════════════════════
# Step 3: Network configuration
# ══════════════════════════════════════════════════════════════════
log "3/6 Network configuration..."
# Use systemd-networkd for simplicity
mkdir -p "${ROOTFS}/etc/systemd/network"
# Ethernet DHCP
cat > "${ROOTFS}/etc/systemd/network/10-eth.network" <<EOF
[Match]
Name=eth* en*
[Network]
DHCP=yes
[DHCP]
UseDNS=yes
UseHostname=no
EOF
# WiFi support (optional)
cat > "${ROOTFS}/etc/systemd/network/20-wlan.network" <<EOF
[Match]
Name=wlan*
[Network]
DHCP=yes
EOF
chroot "${ROOTFS}" systemctl enable systemd-networkd.service 2>/dev/null || true
chroot "${ROOTFS}" systemctl enable systemd-resolved.service 2>/dev/null || true
ok "Network configured"
# ══════════════════════════════════════════════════════════════════
# Step 4: SecuBox packages
# ══════════════════════════════════════════════════════════════════
log "4/6 Installing SecuBox packages..."
# APT sources
cat > "${ROOTFS}/etc/apt/sources.list" <<EOF
deb ${APT_MIRROR} ${SUITE} main contrib non-free non-free-firmware
deb ${APT_MIRROR} ${SUITE}-updates main contrib non-free non-free-firmware
EOF
chroot "${ROOTFS}" apt-get update -q
# Install firmware
chroot "${ROOTFS}" apt-get install -y -q --no-install-recommends \
firmware-brcm80211 firmware-misc-nonfree \
2>/dev/null || warn "Some firmware unavailable"
# SecuBox packages from local cache
CACHE_DEBS="${REPO_DIR}/cache/repo/pool"
if [[ -d "$CACHE_DEBS" ]]; then
log "Installing SecuBox packages from cache..."
install -d "${ROOTFS}/tmp/secubox-debs"
# Copy ARM64 packages (or all if arch-independent)
find "$CACHE_DEBS" -name "secubox-*_all.deb" -exec cp {} "${ROOTFS}/tmp/secubox-debs/" \;
find "$CACHE_DEBS" -name "secubox-*_arm64.deb" -exec cp {} "${ROOTFS}/tmp/secubox-debs/" \; 2>/dev/null || true
DEB_COUNT=$(ls "${ROOTFS}/tmp/secubox-debs/"*.deb 2>/dev/null | wc -l)
log "Found ${DEB_COUNT} packages"
if [[ $DEB_COUNT -gt 0 ]]; then
chroot "${ROOTFS}" dpkg -i /tmp/secubox-debs/*.deb 2>/dev/null || true
chroot "${ROOTFS}" apt-get install -f -y -q 2>/dev/null || true
fi
rm -rf "${ROOTFS}/tmp/secubox-debs"
fi
# Clean
chroot "${ROOTFS}" apt-get clean
rm -rf "${ROOTFS}/var/lib/apt/lists"/*
ok "SecuBox packages installed"
# ══════════════════════════════════════════════════════════════════
# Step 5: Raspberry Pi boot configuration
# ══════════════════════════════════════════════════════════════════
log "5/6 Configuring Pi bootloader..."
# config.txt for Pi 400
mkdir -p "${ROOTFS}/boot/firmware"
cat > "${ROOTFS}/boot/firmware/config.txt" <<EOF
# SecuBox Raspberry Pi 400 Configuration
# Boot
arm_64bit=1
kernel=vmlinuz
initramfs initrd.img followkernel
# Display
hdmi_force_hotplug=1
disable_overscan=1
# GPU memory (minimum for headless, increase for kiosk)
gpu_mem=64
# Enable USB boot
program_usb_boot_mode=1
# Serial console
enable_uart=1
# Overclock (optional, Pi 400 is already fast)
#over_voltage=6
#arm_freq=2000
EOF
# cmdline.txt
cat > "${ROOTFS}/boot/firmware/cmdline.txt" <<EOF
console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet
EOF
ok "Pi bootloader configured"
# ══════════════════════════════════════════════════════════════════
# Step 6: Create image
# ══════════════════════════════════════════════════════════════════
log "6/6 Creating bootable image..."
rm -f "${IMG_FILE}" "${IMG_FILE}.gz"
truncate -s "${IMG_SIZE}" "${IMG_FILE}"
# Partition: MBR with boot + root
parted -s "${IMG_FILE}" \
mklabel msdos \
mkpart primary fat32 1MiB 257MiB \
mkpart primary ext4 257MiB 100% \
set 1 boot on
# Setup loop device
LOOP=$(losetup -fP --show "${IMG_FILE}")
log "Loop device: ${LOOP}"
# Format partitions
mkfs.vfat -F 32 -n BOOT "${LOOP}p1"
mkfs.ext4 -L ROOT -q "${LOOP}p2"
# Mount
MNT="${WORK_DIR}/mnt"
mkdir -p "${MNT}"
mount "${LOOP}p2" "${MNT}"
mkdir -p "${MNT}/boot/firmware"
mount "${LOOP}p1" "${MNT}/boot/firmware"
# Copy rootfs
log "Copying rootfs..."
rsync -aHAX --info=progress2 "${ROOTFS}/" "${MNT}/"
# Copy kernel and initrd to boot partition
cp "${MNT}/boot/vmlinuz-"* "${MNT}/boot/firmware/vmlinuz"
cp "${MNT}/boot/initrd.img-"* "${MNT}/boot/firmware/initrd.img"
# Update fstab with proper UUIDs
BOOT_UUID=$(blkid -s UUID -o value "${LOOP}p1")
ROOT_UUID=$(blkid -s UUID -o value "${LOOP}p2")
cat > "${MNT}/etc/fstab" <<EOF
# SecuBox RPi fstab
UUID=${BOOT_UUID} /boot/firmware vfat defaults 0 2
UUID=${ROOT_UUID} / ext4 defaults,noatime 0 1
EOF
# Update cmdline with UUID
cat > "${MNT}/boot/firmware/cmdline.txt" <<EOF
console=serial0,115200 console=tty1 root=UUID=${ROOT_UUID} rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet
EOF
# Sync and unmount
sync
umount "${MNT}/boot/firmware"
umount "${MNT}"
losetup -d "${LOOP}"
unset LOOP
IMG_SIZE_ACTUAL=$(du -sh "${IMG_FILE}" | cut -f1)
ok "Image created: ${IMG_SIZE_ACTUAL}"
# Compress
if [[ $NO_COMPRESS -eq 0 ]]; then
log "Compressing..."
gzip -9 -f "${IMG_FILE}"
FINAL_SIZE=$(du -sh "${IMG_FILE}.gz" | cut -f1)
sha256sum "${IMG_FILE}.gz" > "${IMG_FILE}.gz.sha256"
ok "Compressed: ${FINAL_SIZE}"
fi
# ══════════════════════════════════════════════════════════════════
# Done
# ══════════════════════════════════════════════════════════════════
echo ""
echo -e "${GREEN}${BOLD}════════════════════════════════════════════════════════${NC}"
echo -e "${GREEN}${BOLD} SecuBox Raspberry Pi 400 Image Ready!${NC}"
echo ""
echo -e " Image: ${IMG_FILE}${NO_COMPRESS:+.gz}"
echo ""
echo -e " ${CYAN}Flash to USB/SD:${NC}"
if [[ $NO_COMPRESS -eq 0 ]]; then
echo -e " zcat ${IMG_FILE}.gz | sudo dd of=/dev/sdX bs=4M status=progress"
else
echo -e " sudo dd if=${IMG_FILE} of=/dev/sdX bs=4M status=progress"
fi
echo ""
echo -e " ${CYAN}Default login:${NC} root / secubox"
echo -e "${GREEN}${BOLD}════════════════════════════════════════════════════════${NC}"