scripts v1.18.0 — R-21 slice B: firmware loader option --loader shim|mkimage (F1)
Closes N100 F1 (HIGH): cheap AMI (AN3PLUS 0.01-class) UEFI firmware can't relocate the ISO's stock signed GRUB from USB (relocation 0x0). The run's live grub-mkimage workaround is now a first-class pipeline mode. - build-felhom-iso.sh: --loader shim|mkimage (default shim, byte-for-byte unchanged; profile-settable FELHOM_LOADER; --loader wins). Loud banner + manifest loader:/grub-mkimage: fields + -mkimage filename suffix. - mkimage-surgery.sh (new): post-prepare-iso, in the assistant container. Builds a monolithic grub-mkimage loader from the ISO's own GRUB (module set from its grub.cfg; embedded search --fs-uuid -> configfile the real menu). Swaps it into the ISO9660 tree (real lowercase path) + the efi.img ESP; xorriso re-master preserves BIOS-hybrid + UEFI + GPT-ESP, drops only Apple HFS+/APM. Recipe from the N100 run evidence, not re-derived. - Dockerfile.assistant: grub-common + grub-efi-amd64-bin + mtools + dosfstools. profiles/n100.profile (new, mkimage + SB-off note). - Validated on nested VM 311 (RUNBOOK-B legs): leg1 shim boots+installs under OVMF SB-enforcing + SeaBIOS; leg2 mkimage boots+installs under SB-off; leg3 (red-proof) mkimage under SB-enforcing FAILS Access Denied (unsigned -> SB must be OFF); leg4 surgery byte-identical payload. bash -n + shellcheck clean. Physical N100 closure folds into the rehearsal (n100-safety match-nothing ISO built + sha-recorded, unbooted). PXE stays a deferred R-21 note.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
#===============================================================================
|
||||
# build-felhom-iso.sh — R-21 slice A: turn the official PVE ISO into a Felhom auto-install ISO.
|
||||
# build-felhom-iso.sh — R-21 slice A+B: turn the official PVE ISO into a Felhom auto-install ISO.
|
||||
#
|
||||
# Renders answer.toml (from answer.toml.tmpl + a profile), mints a fresh THROWAWAY root hash,
|
||||
# gates the answer through validate-answer by PARSING ITS OUTPUT (never $? — validate-answer returns
|
||||
@@ -8,15 +8,26 @@
|
||||
# script/unit/env), and runs prepare-iso --fetch-from iso --on-first-boot. Emits the ISO + sha256 +
|
||||
# a build manifest.
|
||||
#
|
||||
# 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
|
||||
# workaround PROVEN LIVE during the N100 run (VALIDATION-n100-baremetal F1: cheap AMI AN3PLUS-class
|
||||
# firmware can't relocate the ISO's signed GRUB from USB, `relocation 0x0`). The mkimage loader is
|
||||
# UNSIGNED → the target board MUST have Secure Boot OFF (documented in the n100 profile's prep). The
|
||||
# loader surgery runs AFTER prepare-iso (the assistant's answer/first-boot payload is provably
|
||||
# untouched except the loader path).
|
||||
#
|
||||
# SECRET-BEARING: if the bootstrap-env carries a retrieval passphrase (it must, for an unattended
|
||||
# install — see README "secret-bearing"), the produced ISO embeds it. Supervised/single-use only;
|
||||
# never distributed; delete after the run. The build log says so loudly.
|
||||
#
|
||||
# Runs on DooPlex; delegates validate-answer + prepare-iso to the felhom-iso-assistant container.
|
||||
# Runs on DooPlex; delegates validate-answer + prepare-iso + the mkimage surgery to the
|
||||
# felhom-iso-assistant container (which carries proxmox-auto-install-assistant, xorriso, grub-mkimage,
|
||||
# and mtools).
|
||||
#===============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
ISO_VERSION="1.16.0" # Felhom release the ISO is tagged to (aligns with felhom-host-install SCRIPT_VERSION).
|
||||
ISO_VERSION="1.18.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)"
|
||||
|
||||
@@ -32,6 +43,7 @@ log_dry() { echo -e "${CYAN}[DRY-RUN]${NC} $1"; }
|
||||
die() { log_error "$1"; exit 1; }
|
||||
|
||||
PVE_ISO=""; ISO_SHA256=""; PROFILE=""; BOOTSTRAP_ENV=""; OUT_DIR="${HOME}/felhom-iso/out"; PVE_VERSION=""; DRY_RUN=false
|
||||
LOADER_CLI="" # --loader override; empty = fall back to the profile, then the shim default.
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: build-felhom-iso.sh --pve-iso PATH --iso-sha256 SHA --profile FILE --bootstrap-env FILE [options]
|
||||
@@ -43,6 +55,10 @@ Required:
|
||||
--bootstrap-env FILE the in-ISO /etc/felhom/bootstrap.env (SECRET-BEARING: retrieval passphrase).
|
||||
Must define FELHOM_CUSTOMER_ID, FELHOM_MODE, FELHOM_RETRIEVAL_PASSPHRASE.
|
||||
Options:
|
||||
--loader shim|mkimage UEFI boot loader (default: shim, or the profile's FELHOM_LOADER; --loader wins).
|
||||
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.
|
||||
--out DIR output directory (default: \$HOME/felhom-iso/out)
|
||||
--pve-version VER override PVE version tag (default: parsed from the ISO filename)
|
||||
--dry-run print the steps without producing an ISO
|
||||
@@ -55,6 +71,7 @@ while [[ $# -gt 0 ]]; do
|
||||
--iso-sha256) ISO_SHA256="$2"; shift 2 ;;
|
||||
--profile) PROFILE="$2"; shift 2 ;;
|
||||
--bootstrap-env) BOOTSTRAP_ENV="$2"; shift 2 ;;
|
||||
--loader) LOADER_CLI="$2"; shift 2 ;;
|
||||
--out) OUT_DIR="$2"; shift 2 ;;
|
||||
--pve-version) PVE_VERSION="$2"; shift 2 ;;
|
||||
--dry-run) DRY_RUN=true; shift ;;
|
||||
@@ -62,6 +79,8 @@ while [[ $# -gt 0 ]]; do
|
||||
*) die "unknown argument: $1 (see --help)" ;;
|
||||
esac
|
||||
done
|
||||
[[ -z "$LOADER_CLI" || "$LOADER_CLI" == "shim" || "$LOADER_CLI" == "mkimage" ]] \
|
||||
|| die "--loader must be 'shim' or 'mkimage' (got '$LOADER_CLI')"
|
||||
|
||||
[[ -n "$PVE_ISO" ]] || die "--pve-iso is required"
|
||||
[[ -n "$ISO_SHA256" ]] || die "--iso-sha256 is required"
|
||||
@@ -88,7 +107,7 @@ PROFILE_NAME="$(basename "$PROFILE")"; PROFILE_NAME="${PROFILE_NAME%.profile}"
|
||||
|
||||
# --- load + validate profile ----------------------------------------------------------------------
|
||||
log_step "loading profile: $PROFILE"
|
||||
FELHOM_FQDN=""; FELHOM_DISK_SETUP=""; FELHOM_ROOT_SSH_KEY=""
|
||||
FELHOM_FQDN=""; FELHOM_DISK_SETUP=""; FELHOM_ROOT_SSH_KEY=""; FELHOM_LOADER=""
|
||||
# shellcheck disable=SC1090
|
||||
source "$PROFILE"
|
||||
[[ -n "$FELHOM_FQDN" ]] || die "profile missing FELHOM_FQDN"
|
||||
@@ -97,6 +116,20 @@ source "$PROFILE"
|
||||
ROOT_SSH_LINE=""
|
||||
[[ -n "$FELHOM_ROOT_SSH_KEY" ]] && ROOT_SSH_LINE="root-ssh-keys = [\"${FELHOM_ROOT_SSH_KEY}\"]"
|
||||
|
||||
# --- resolve the loader mode: --loader wins over the profile's FELHOM_LOADER over the shim default ---
|
||||
LOADER="${LOADER_CLI:-${FELHOM_LOADER:-shim}}"
|
||||
[[ "$LOADER" == "shim" || "$LOADER" == "mkimage" ]] \
|
||||
|| die "profile FELHOM_LOADER must be 'shim' or 'mkimage' (got '$FELHOM_LOADER')"
|
||||
if [[ "$LOADER" == "mkimage" ]]; then
|
||||
echo -e "${YELLOW}==================================================================================${NC}"
|
||||
log_warn "LOADER MODE = mkimage — the UEFI boot path is a monolithic grub-mkimage loader (F1 fix)."
|
||||
log_warn "This loader is UNSIGNED: the target board MUST have Secure Boot OFF. shim/SB is bypassed."
|
||||
log_warn "The ISO filename gains '-mkimage'; never confuse it with a shim (SB-capable) build."
|
||||
echo -e "${YELLOW}==================================================================================${NC}"
|
||||
else
|
||||
log_info "loader mode = shim (stock MS-signed chain; Secure Boot works on compliant firmware)"
|
||||
fi
|
||||
|
||||
# --- validate bootstrap-env (secret-bearing detection) --------------------------------------------
|
||||
log_step "checking bootstrap-env (secret-bearing detection)"
|
||||
( set +e
|
||||
@@ -112,7 +145,8 @@ log_warn "this ISO will be SECRET-BEARING (embeds the customer retrieval passphr
|
||||
|
||||
# --- workspace ------------------------------------------------------------------------------------
|
||||
WORK="$(mktemp -d "${TMPDIR:-/tmp}/felhom-iso.XXXXXX")"
|
||||
cleanup() { rm -rf "$WORK"; }
|
||||
# chmod first: the mkimage surgery's osirrox extract leaves read-only file modes that rm can't clear.
|
||||
cleanup() { chmod -R u+w "$WORK" 2>/dev/null || true; rm -rf "$WORK"; }
|
||||
trap cleanup EXIT
|
||||
mkdir -p "$OUT_DIR" "$WORK/tmp"
|
||||
ISO_DIR="$(cd "$(dirname "$PVE_ISO")" && pwd)"; ISO_BASE="$(basename "$PVE_ISO")"
|
||||
@@ -174,10 +208,14 @@ chmod 0755 "$STUB"
|
||||
grep -q '@@BOOTSTRAP_.*_B64@@' "$STUB" && die "stub still has unfilled markers — injection failed"
|
||||
|
||||
# --- prepare-iso ----------------------------------------------------------------------------------
|
||||
OUT_ISO="$OUT_DIR/felhom-pve-${PVE_VERSION}-v${ISO_VERSION}-${PROFILE_NAME}.iso"
|
||||
# Rule 4: the loader mode is loud in the filename — a '-mkimage' ISO implies Secure-Boot-off prep.
|
||||
LOADER_SUFFIX=""; [[ "$LOADER" != "shim" ]] && LOADER_SUFFIX="-${LOADER}"
|
||||
OUT_ISO="$OUT_DIR/felhom-pve-${PVE_VERSION}-v${ISO_VERSION}-${PROFILE_NAME}${LOADER_SUFFIX}.iso"
|
||||
GRUB_VERSION="" # populated by the mkimage surgery (the grub-mkimage build used)
|
||||
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"
|
||||
log_info "DRY-RUN: no ISO produced"
|
||||
exit 0
|
||||
fi
|
||||
@@ -187,15 +225,35 @@ docker run --rm -v "$ISO_DIR":/iso:ro -v "$WORK":/work "$IMAGE" \
|
||||
--on-first-boot /work/stub-first-boot.sh \
|
||||
--tmp /work/tmp --output /work/out.iso
|
||||
[[ -f "$WORK/out.iso" ]] || die "prepare-iso produced no output"
|
||||
cp "$WORK/out.iso" "$OUT_ISO"
|
||||
|
||||
# --- 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)"
|
||||
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})"
|
||||
else
|
||||
cp "$WORK/out.iso" "$OUT_ISO"
|
||||
fi
|
||||
|
||||
# --- sha256 + manifest ----------------------------------------------------------------------------
|
||||
OUT_SHA="$(sha256sum "$OUT_ISO" | awk '{print $1}')"
|
||||
OUT_SIZE="$(stat -c '%s' "$OUT_ISO")"
|
||||
ASSISTANT_VER="$(docker run --rm "$IMAGE" proxmox-auto-install-assistant --version 2>&1 | head -1)"
|
||||
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)"
|
||||
cat > "$OUT_ISO.manifest.txt" <<EOF
|
||||
Felhom bare-metal ISO build manifest (R-21 slice A)
|
||||
Felhom bare-metal ISO build manifest (R-21 slice A+B)
|
||||
built : $(date -Is)
|
||||
iso-version-tag : v${ISO_VERSION}
|
||||
pve-version : ${PVE_VERSION}
|
||||
@@ -204,6 +262,8 @@ source-iso-sha256 : ${ISO_SHA256}
|
||||
assistant-version : ${ASSISTANT_VER}
|
||||
profile : ${PROFILE_NAME}
|
||||
fqdn : ${FELHOM_FQDN}
|
||||
loader : ${LOADER_NOTE}
|
||||
grub-mkimage : ${GRUB_VERSION:-n/a (shim mode; loader unchanged)}
|
||||
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} (embeds the customer retrieval passphrase — supervised/single-use, delete after the run)
|
||||
output : $(basename "$OUT_ISO")
|
||||
|
||||
Reference in New Issue
Block a user