scripts v1.22.0 — ISO boot screen + single-entry GRUB menu (R-38 GRUB slice)
Two jobs, one repack pass. BRANDING. Every ISO now carries a Felhom boot screen built from the website's og-image_2.png at repack time (ImageMagick in the assistant container), so the boot card has ONE source and not a second pre-rendered copy in the repo to drift. The card is scaled onto a 1024x768 gfxterm canvas, top-centered, and the card's own subtle background grid is continued across the letterbox fill PHASE-LOCKED to where the card's grid lands — the fill is seamless rather than a square of grid floating in flat navy. Menu positioning needs a gfxmenu theme (plain background_image cannot move the menu off the wordmark), so the stock pvetheme is replaced by felhomtheme, which puts the menu in the lower third the layout deliberately leaves empty. SAFETY — the half that matters. The stock PVE menu offers Graphical, Terminal UI and serial installers plus an Advanced Options submenu (nomodeset x2, three debug variants, Rescue Boot, memtest, UEFI settings). Every one of them reaches the MANUAL installer, whose first question is which disk to wipe. A customer, or their helpful nephew, must not be able to get there from a boot menu. They are not hidden and not password-gated: they are NOT EMITTED. What ships is one entry, 'Felhom telepítés', default, 5s. Boot behavior is unchanged. The kernel/append and initrd lines are lifted VERBATIM from the ISO's own 'Install Proxmox VE (Automated)' entry rather than frozen into a copy here, so a PVE bump tracks automatically; the build fails if they cannot be found, if the append line has lost proxmox-start-auto-installer, or if auto-installer-mode.toml is absent (which would mean the one Felhom- labelled entry boots a manual installer). The rendered menu is then gated for exactly 1 entry, 0 submenus, and zero references to proxtui/proxdebug/nomodeset/ Rescue Boot/memtest/fwsetup — and re-verified by reading the menu back OUT of the finished ISO, not merely out of the extract tree. mkimage-surgery.sh -> iso-repack.sh: branding and the slice-B loader swap need the same extract -> modify -> re-master cycle, so they share one pass instead of re-mastering twice. The mkimage recipe is untouched. The embedded module list is still derived from the STOCK grub.cfg (snapshotted before branding rewrites it), plus gfxmenu's bitmap/bitmap_scale/trig renderer deps. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nn3VgQk9iwEGgyx6QJ2NvE
This commit is contained in:
@@ -13,6 +13,15 @@
|
||||
# script/unit/env), and runs prepare-iso --fetch-from iso --on-first-boot. Emits the ISO + sha256 +
|
||||
# a build manifest.
|
||||
#
|
||||
# R-38 GRUB SLICE (v1.22.0) — every ISO is now REPACKED after prepare-iso to carry the Felhom boot
|
||||
# screen and, more importantly, a menu with exactly ONE entry ("Felhom telepítés", default, 5s). The
|
||||
# stock PVE menu offers Graphical/Terminal-UI/serial installers plus an Advanced Options submenu with
|
||||
# debug/nomodeset/rescue entries — every one of them a route into the MANUAL installer, whose first
|
||||
# question is which disk to wipe. A customer, or their helpful nephew, must not be able to reach it
|
||||
# from a boot menu; those entries are not hidden, they are not emitted. The kernel/append line is
|
||||
# lifted verbatim from the ISO's own automated entry, so boot behavior is unchanged. See iso-repack.sh.
|
||||
# (--no-brand exists for debugging the stock menu; it is not a shipping mode.)
|
||||
#
|
||||
# SLICE B — --loader shim|mkimage (default shim). shim = the stock output (MS-signed shim→GRUB chain,
|
||||
# keeps Secure Boot working on compliant firmware, spike S2b). mkimage = replace the ISO's UEFI boot
|
||||
# path with a monolithic grub-mkimage-built BOOTX64.EFI built from the ISO's OWN GRUB modules — the
|
||||
@@ -32,7 +41,7 @@
|
||||
#===============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
ISO_VERSION="1.21.0" # Felhom release the ISO is tagged to (aligns with felhom-host-install SCRIPT_VERSION).
|
||||
ISO_VERSION="1.22.0" # Felhom release the ISO is tagged to (aligns with felhom-host-install SCRIPT_VERSION).
|
||||
IMAGE="${FELHOM_ISO_ASSISTANT_IMAGE:-felhom-iso-assistant:trixie}"
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
@@ -50,6 +59,8 @@ die() { log_error "$1"; exit 1; }
|
||||
PVE_ISO=""; ISO_SHA256=""; PROFILE=""; BOOTSTRAP_ENV=""; OUT_DIR="${FELHOM_ISO_OUT:-/mnt/5_hdd/felhom.eu/felhom-iso/out}"; PVE_VERSION=""; DRY_RUN=false
|
||||
LOADER_CLI="" # --loader override; empty = fall back to the profile, then the shim default.
|
||||
PAIRING=false # --pairing: build the GENERIC secret-free ISO (slice C); no --bootstrap-env.
|
||||
BRAND=true # R-38: Felhom boot screen + single-entry menu. --no-brand is a debugging escape only.
|
||||
BRAND_IMAGE="" # --brand-image override; empty = the website's og-image_2.png (the single source).
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage (direct): build-felhom-iso.sh --pve-iso PATH --iso-sha256 SHA --profile FILE --bootstrap-env FILE [options]
|
||||
@@ -72,6 +83,9 @@ Options:
|
||||
shim = stock MS-signed chain (Secure Boot OK on compliant firmware).
|
||||
mkimage = monolithic grub-mkimage loader for cheap AMI boards that can't boot
|
||||
the ISO's GRUB from USB (F1). UNSIGNED -> the target board needs Secure Boot OFF.
|
||||
--no-brand DEBUG ONLY: keep the stock PVE boot menu (all installer entries reachable).
|
||||
Shipping ISOs are always branded: Felhom boot screen + exactly ONE entry.
|
||||
--brand-image FILE override the boot-screen card (default: website/assets/og-image_2.png)
|
||||
--out DIR output directory (default: the DooPlex build root
|
||||
/mnt/5_hdd/felhom.eu/felhom-iso/out; override via \$FELHOM_ISO_OUT for other hosts)
|
||||
--pve-version VER override PVE version tag (default: parsed from the ISO filename)
|
||||
@@ -87,6 +101,8 @@ while [[ $# -gt 0 ]]; do
|
||||
--bootstrap-env) BOOTSTRAP_ENV="$2"; shift 2 ;;
|
||||
--pairing) PAIRING=true; shift ;;
|
||||
--loader) LOADER_CLI="$2"; shift 2 ;;
|
||||
--no-brand) BRAND=false; shift ;;
|
||||
--brand-image) BRAND_IMAGE="$2"; shift 2 ;;
|
||||
--out) OUT_DIR="$2"; shift 2 ;;
|
||||
--pve-version) PVE_VERSION="$2"; shift 2 ;;
|
||||
--dry-run) DRY_RUN=true; shift ;;
|
||||
@@ -150,6 +166,21 @@ else
|
||||
log_info "loader mode = shim (stock MS-signed chain; Secure Boot works on compliant firmware)"
|
||||
fi
|
||||
|
||||
# --- resolve the boot-screen card (R-38) ------------------------------------------------------------
|
||||
# Single source of truth: the website asset. NOT copied into scripts/iso/ — a second copy of a brand
|
||||
# asset is a second thing to forget to update.
|
||||
if $BRAND; then
|
||||
[[ -n "$BRAND_IMAGE" ]] || BRAND_IMAGE="$HERE/../../website/assets/og-image_2.png"
|
||||
[[ -f "$BRAND_IMAGE" ]] || die "brand image not found: $BRAND_IMAGE (pass --brand-image, or run from the repo checkout)"
|
||||
log_info "boot-screen card = $BRAND_IMAGE (menu: exactly ONE entry, 'Felhom telepítés')"
|
||||
else
|
||||
echo -e "${YELLOW}==================================================================================${NC}"
|
||||
log_warn "--no-brand — the STOCK PVE boot menu ships: Graphical/Terminal-UI/serial installers and"
|
||||
log_warn "the Advanced Options submenu are all reachable, i.e. a manual 'which disk do I wipe'"
|
||||
log_warn "installer is one keypress away. DEBUGGING ONLY — never hand this ISO to a customer."
|
||||
echo -e "${YELLOW}==================================================================================${NC}"
|
||||
fi
|
||||
|
||||
# --- mode: DIRECT validates the secret-bearing env; PAIRING is secret-free (env generated below) -----
|
||||
if $PAIRING; then
|
||||
SECRET_BEARING="no"
|
||||
@@ -260,7 +291,9 @@ GRUB_VERSION="" # populated by the mkimage surgery (the grub-mkimage build use
|
||||
log_step "building ISO: $(basename "$OUT_ISO")"
|
||||
if $DRY_RUN; then
|
||||
log_dry "docker run … prepare-iso /iso/$ISO_BASE --fetch-from iso --answer-file /work/answer.toml --on-first-boot /work/stub-first-boot.sh --output /work/out.iso"
|
||||
[[ "$LOADER" == "mkimage" ]] && log_dry "docker run … (mkimage surgery) grub-mkimage from the ISO's own modules → swap BOOTX64.EFI in the EFI tree + efi.img → xorriso re-master → /work/final.iso"
|
||||
$BRAND && log_dry "docker run … (repack/brand) generate 1024x768 boot card from $(basename "$BRAND_IMAGE") → install felhomtheme → rewrite grub.cfg to ONE entry ('Felhom telepítés', 5s), kernel line lifted from the stock automated entry"
|
||||
[[ "$LOADER" == "mkimage" ]] && log_dry "docker run … (repack/mkimage) grub-mkimage from the ISO's own modules → swap BOOTX64.EFI in the EFI tree + efi.img"
|
||||
( $BRAND || [[ "$LOADER" == "mkimage" ]] ) && log_dry "docker run … (repack) xorriso re-master → /work/final.iso"
|
||||
log_info "DRY-RUN: no ISO produced"
|
||||
exit 0
|
||||
fi
|
||||
@@ -271,21 +304,31 @@ docker run --rm -v "$ISO_DIR":/iso:ro -v "$WORK":/work "$IMAGE" \
|
||||
--tmp /work/tmp --output /work/out.iso
|
||||
[[ -f "$WORK/out.iso" ]] || die "prepare-iso produced no output"
|
||||
|
||||
# --- SLICE B: mkimage loader surgery (post-prepare; the assistant payload is untouched but the EFI
|
||||
# boot path). The recipe is the N100 run's proven workaround (VALIDATION F1) — do NOT re-derive it:
|
||||
# grub-mkimage from the ISO's OWN x86_64-efi modules (2.12-9+pmx2), embedding the module set the
|
||||
# ISO's grub.cfg needs + an embedded config that `search --fs-uuid`es the ISO and `configfile`s its
|
||||
# real menu; then swap BOOTX64.EFI in the ISO9660 EFI/BOOT tree AND inside efi.img, and re-master
|
||||
# with xorriso preserving BOTH the hybrid BIOS boot and the injected answer/first-boot payload. ---
|
||||
if [[ "$LOADER" == "mkimage" ]]; then
|
||||
log_step "applying mkimage UEFI loader (F1 firmware fix; recipe from the N100 run evidence)"
|
||||
[[ -f "$HERE/mkimage-surgery.sh" ]] || die "mkimage-surgery.sh not found next to build-felhom-iso.sh"
|
||||
cp "$HERE/mkimage-surgery.sh" "$WORK/mkimage-surgery.sh"
|
||||
docker run --rm -v "$WORK":/work "$IMAGE" bash /work/mkimage-surgery.sh 2>&1 | sed 's/^/ [surgery] /'
|
||||
[[ -f "$WORK/final.iso" ]] || die "mkimage surgery produced no output (see [surgery] log above)"
|
||||
# --- REPACK: R-38 GRUB branding + single-entry menu, and (slice B) the mkimage loader surgery. Both
|
||||
# need the same extract -> modify -> re-master cycle, so iso-repack.sh does them in ONE pass. The
|
||||
# assistant's answer/first-boot payload is untouched; only the GRUB menu/theme and (mkimage) the
|
||||
# EFI boot path change. The mkimage recipe is the N100 run's proven workaround (VALIDATION F1) —
|
||||
# do NOT re-derive it. See iso-repack.sh for the full rationale. -----------------------------------
|
||||
if $BRAND || [[ "$LOADER" == "mkimage" ]]; then
|
||||
REPACK_WHAT=""
|
||||
$BRAND && REPACK_WHAT="branding"
|
||||
[[ "$LOADER" == "mkimage" ]] && REPACK_WHAT="${REPACK_WHAT:+$REPACK_WHAT + }mkimage loader"
|
||||
log_step "repacking ISO ($REPACK_WHAT)"
|
||||
[[ -f "$HERE/iso-repack.sh" ]] || die "iso-repack.sh not found next to build-felhom-iso.sh"
|
||||
cp "$HERE/iso-repack.sh" "$WORK/iso-repack.sh"
|
||||
if $BRAND; then
|
||||
mkdir -p "$WORK/brand"
|
||||
cp "$HERE/grub/grub.cfg.tmpl" "$HERE/grub/felhom-theme.txt" \
|
||||
"$HERE/grub/generate-grub-background.sh" "$WORK/brand/"
|
||||
cp "$BRAND_IMAGE" "$WORK/brand/card.png"
|
||||
fi
|
||||
docker run --rm -v "$WORK":/work \
|
||||
-e FELHOM_LOADER="$LOADER" -e FELHOM_BRAND="$($BRAND && echo 1 || echo 0)" \
|
||||
"$IMAGE" bash /work/iso-repack.sh 2>&1 | sed 's/^/ [repack] /'
|
||||
[[ -f "$WORK/final.iso" ]] || die "repack produced no output (see [repack] log above)"
|
||||
GRUB_VERSION="$(cat "$WORK/grub-version.txt" 2>/dev/null || echo unknown)"
|
||||
cp "$WORK/final.iso" "$OUT_ISO"
|
||||
log_success "mkimage loader applied (grub-mkimage: ${GRUB_VERSION})"
|
||||
log_success "repack applied ($REPACK_WHAT)"
|
||||
else
|
||||
cp "$WORK/out.iso" "$OUT_ISO"
|
||||
fi
|
||||
@@ -297,6 +340,8 @@ ASSISTANT_VER="$(docker run --rm "$IMAGE" proxmox-auto-install-assistant --versi
|
||||
echo "$OUT_SHA $(basename "$OUT_ISO")" > "$OUT_ISO.sha256"
|
||||
LOADER_NOTE="shim (stock MS-signed chain; Secure Boot OK on compliant firmware)"
|
||||
[[ "$LOADER" == "mkimage" ]] && LOADER_NOTE="mkimage (monolithic grub-mkimage UEFI loader, F1 fix — UNSIGNED; target board MUST have Secure Boot OFF)"
|
||||
BRAND_NOTE="FELHOM (single entry 'Felhom telepítés', default, 5s; stock installer entries not emitted)"
|
||||
$BRAND || BRAND_NOTE="STOCK PVE menu (--no-brand; DEBUG BUILD — manual installer reachable, do not ship)"
|
||||
MODE_NOTE="direct (env-baked customer-id + retrieval passphrase; secret-bearing)"
|
||||
$PAIRING && MODE_NOTE="pairing (GENERIC secret-free universal ISO — box self-registers, operator binds, hub delivers once)"
|
||||
cat > "$OUT_ISO.manifest.txt" <<EOF
|
||||
@@ -312,6 +357,8 @@ fqdn : ${FELHOM_FQDN}
|
||||
mode : ${MODE_NOTE}
|
||||
loader : ${LOADER_NOTE}
|
||||
grub-mkimage : ${GRUB_VERSION:-n/a (shim mode; loader unchanged)}
|
||||
boot-menu : ${BRAND_NOTE}
|
||||
$( $BRAND && cat "$WORK/brand-report.txt" 2>/dev/null || true )
|
||||
host-install-url : $(grep -oE 'FELHOM_INSTALL_URL=[^ ]*' "$BOOTSTRAP_ENV" 2>/dev/null || echo 'https://felhom.eu/scripts/felhom-host-install.sh (default)')
|
||||
secret-bearing : ${SECRET_BEARING}$( $PAIRING && echo ' (GENERIC ISO — carries NO customer secret)' || echo ' (embeds the customer retrieval passphrase — supervised/single-use, delete after the run)')
|
||||
output : $(basename "$OUT_ISO")
|
||||
|
||||
Reference in New Issue
Block a user