159 lines
6.5 KiB
YAML
159 lines
6.5 KiB
YAML
#
|
|
# .gitea/workflows/ipxe-image.yaml
|
|
#
|
|
# Builds the fleet-ipxe image: the iPXE network bootloader (snponly.efi) for the
|
|
# PXE-only chainload path (firmware without UEFI HTTP boot, e.g. EliteBook 820
|
|
# G4), SIGNED with the fleet `db` key and packaged as a tiny FROM-scratch OCI
|
|
# image. The dnsmasq serving container mounts it at /ipxe and copies snponly.efi
|
|
# into its TFTP root — so the serving host never carries a loose, unsigned .efi
|
|
# and the bootloader is digest-pinned + signed exactly like the UKI.
|
|
#
|
|
# Kept separate from the (generic) dnsmasq image so the daemon image stays
|
|
# key-agnostic and this one is the only per-Secure-Boot-environment artifact.
|
|
# See scripts/build-ipxe-oci.sh, docs/secure-boot-keys.md, CLAUDE.md invariant #9.
|
|
#
|
|
# Tagging mirrors gitea-main-ci.yaml so every branch builds a uniquely tagged,
|
|
# pushed image you can test without clobbering main:
|
|
# - tag push (refs/tags/v1.2.3) -> "1.2.3" (+ :latest)
|
|
# - main push (refs/heads/main) -> "<ipxe-pkg-ver>" (+ :latest)
|
|
# - branch push (refs/heads/<x>) -> "<x>-<sha7>" (dev image, no :latest)
|
|
# - dispatch input always wins.
|
|
# Set IPXE_VERSION in serving/.env to the tag you want to run.
|
|
#
|
|
# Runs only when the iPXE inputs change (path filter) or on demand.
|
|
#
|
|
# Required Gitea repo secrets: PACKAGE_USER, PACKAGE_TOKEN (registry creds).
|
|
# Optional: SB_KEY, SB_CERT (db PRIVATE key + cert, PEM). Unset => UNSIGNED lab
|
|
# image (loud warning; Secure-Boot-enforcing hosts will reject it). PK/KEK
|
|
# never come near CI — only `db` signs (docs/secure-boot-keys.md).
|
|
#
|
|
|
|
name: Build fleet-ipxe image
|
|
run-name: ${{ gitea.actor }} builds the signed fleet-ipxe bootloader image (${{ gitea.ref_name }})
|
|
on:
|
|
push:
|
|
branches:
|
|
- "**" # every branch — dev branches get a branch-name+sha tag
|
|
tags:
|
|
- "v*" # tag push -> clean semver tag (v1.2.3 -> 1.2.3)
|
|
paths:
|
|
- "scripts/build-ipxe-oci.sh"
|
|
- ".gitea/workflows/ipxe-image.yaml"
|
|
workflow_dispatch:
|
|
inputs:
|
|
ipxe_version:
|
|
description: "Override the image tag (default: sanitized ipxe package version)"
|
|
required: false
|
|
|
|
concurrency:
|
|
group: ipxe-image-${{ gitea.ref }}
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
IPXE_IMAGE: "git.bitasylum.org/audiobuzz/fleet-ipxe"
|
|
|
|
jobs:
|
|
ipxe-build:
|
|
name: Build & push fleet-ipxe image
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: git.bitasylum.org/audiobuzz/ubuntu-act-runner-qemu:main
|
|
steps:
|
|
-
|
|
name: Checkout
|
|
uses: actions/checkout@v6
|
|
|
|
-
|
|
name: Install tooling
|
|
# buildah (OCI build), sbsigntool (sbsign/sbverify — Debian singular), and
|
|
# the ipxe package which ships the prebuilt snponly.efi.
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y --no-install-recommends buildah sbsigntool ipxe
|
|
|
|
-
|
|
name: Locate snponly.efi + derive tag
|
|
id: src
|
|
run: |
|
|
# snponly.efi: UEFI x64 iPXE that rides the firmware's NIC driver (SNP),
|
|
# so it binds where iPXE's native driver won't (e.g. I219-LM). Ubuntu's
|
|
# ipxe package installs it under /usr/lib/ipxe.
|
|
SNP=$(find /usr/lib/ipxe /usr/share/ipxe -name 'snponly.efi' 2>/dev/null | head -1)
|
|
[ -n "$SNP" ] || { echo "snponly.efi not found in the ipxe package" >&2; exit 1; }
|
|
echo "snponly=$SNP" >> "$GITHUB_OUTPUT"
|
|
# Tag scheme (same as gitea-main-ci.yaml, with the ipxe pkg version as the
|
|
# main-branch identifier). :latest moves only on main / release tags.
|
|
short_sha="$(echo "${GITHUB_SHA}" | cut -c1-7)"
|
|
RAW=$(dpkg-query -W -f='${Version}' ipxe 2>/dev/null || echo unknown)
|
|
PKGVER=$(printf '%s' "$RAW" | sed 's/[^A-Za-z0-9_.-]/-/g')
|
|
push_latest=false
|
|
if [ -n "${{ inputs.ipxe_version }}" ]; then
|
|
VER="${{ inputs.ipxe_version }}"
|
|
elif [ "${GITHUB_REF#refs/tags/}" != "$GITHUB_REF" ]; then
|
|
VER="${GITHUB_REF#refs/tags/}"; VER="${VER#v}"; push_latest=true
|
|
elif [ "${GITHUB_REF}" = "refs/heads/main" ]; then
|
|
VER="$PKGVER"; push_latest=true
|
|
else
|
|
branch="${GITHUB_REF#refs/heads/}"
|
|
safe_branch=$(printf '%s' "$branch" \
|
|
| sed -e 's#[^A-Za-z0-9._-]#-#g' -e 's#^[.-]*##' | cut -c1-80)
|
|
[ -n "$safe_branch" ] || safe_branch="branch"
|
|
VER="${safe_branch}-${short_sha}"
|
|
fi
|
|
echo "version=$VER" >> "$GITHUB_OUTPUT"
|
|
echo "push_latest=$push_latest" >> "$GITHUB_OUTPUT"
|
|
echo "Using snponly.efi=$SNP tag=$VER (ipxe pkg $RAW, latest=$push_latest)"
|
|
|
|
-
|
|
name: Materialize Secure Boot signing material
|
|
# Same db key that signs the UKI; written to a runner-temp file and passed
|
|
# to build-ipxe-oci.sh as a path. If SB_KEY is unset this no-ops and the
|
|
# build produces an UNSIGNED (lab) image with its loud warning.
|
|
if: ${{ secrets.SB_KEY != '' }}
|
|
env:
|
|
SB_KEY: ${{ secrets.SB_KEY }}
|
|
SB_CERT: ${{ secrets.SB_CERT }}
|
|
run: |
|
|
umask 077
|
|
d="$RUNNER_TEMP/sb"; mkdir -p "$d"
|
|
printf '%s\n' "$SB_KEY" > "$d/db.key"
|
|
printf '%s\n' "$SB_CERT" > "$d/db.crt"
|
|
echo "SB_KEY_FILE=$d/db.key" >> "$GITHUB_ENV"
|
|
echo "SB_CERT_FILE=$d/db.crt" >> "$GITHUB_ENV"
|
|
echo "Secure Boot signing material staged (signed fleet-ipxe build)."
|
|
|
|
-
|
|
name: Registry login
|
|
run: |
|
|
buildah login \
|
|
--username "${{ secrets.PACKAGE_USER }}" \
|
|
--password "${{ secrets.PACKAGE_TOKEN }}" \
|
|
git.bitasylum.org
|
|
|
|
-
|
|
name: Build & push
|
|
env:
|
|
STORAGE_DRIVER: vfs
|
|
run: |
|
|
VER="${{ steps.src.outputs.version }}"
|
|
bash scripts/build-ipxe-oci.sh \
|
|
"${{ steps.src.outputs.snponly }}" \
|
|
"${IPXE_IMAGE}" \
|
|
"$VER" \
|
|
"${SB_KEY_FILE:-}" \
|
|
"${SB_CERT_FILE:-}" \
|
|
true
|
|
# main / release tags also move :latest; dev branches never clobber it.
|
|
if [ "${{ steps.src.outputs.push_latest }}" = "true" ]; then
|
|
buildah tag "${IPXE_IMAGE}:${VER}" "${IPXE_IMAGE}:latest"
|
|
buildah push "${IPXE_IMAGE}:latest"
|
|
echo "Updated ${IPXE_IMAGE}:latest"
|
|
else
|
|
echo "Dev branch build — :latest left untouched (run with IPXE_VERSION=${VER})"
|
|
fi
|
|
|
|
-
|
|
name: Shred Secure Boot signing key
|
|
if: always()
|
|
run: shred -u "$RUNNER_TEMP/sb/db.key" 2>/dev/null || rm -f "$RUNNER_TEMP/sb/db.key" 2>/dev/null || true
|