160 lines
6.5 KiB
YAML
160 lines
6.5 KiB
YAML
#
|
|
# .gitea/workflows/gitea-main-ci.yaml
|
|
#
|
|
# Builds the diskless fleet release: a fleet-generic UKI + erofs/dm-verity
|
|
# root, packaged as a FROM-scratch OCI artifact image (see CLAUDE.md and
|
|
# docs/diskless-fleet-design-v2.pdf). Packer kickstart-installs a throwaway
|
|
# Rocky 9 build VM (qemu), builds the --no-hostonly initramfs, then the
|
|
# shell-local post-processors extract artifacts, build the UKI (ukify), and
|
|
# build+push the OCI release image.
|
|
#
|
|
# This is an UNSIGNED (lab) build: sb_key/sb_cert are intentionally NOT passed,
|
|
# so build-oci.sh emits its loud unsigned-UKI warning. A production fleet must
|
|
# sign in CI/HSM -- see the "TODO: wire SB_KEY/SB_CERT" step below.
|
|
#
|
|
# Required Gitea repo secrets:
|
|
# REGISTRY_USERNAME - registry user for `oci_image` (oci_push=true)
|
|
# REGISTRY_TOKEN - registry password/token
|
|
# SSH_AUTHORIZED_KEY - public key for the sudo admin user; empty => no admin
|
|
# user + root left unlocked (lab). Set it to lock root.
|
|
# # SB_KEY, SB_CERT - (future) Secure Boot signing key + cert for signed UKIs
|
|
#
|
|
# Runner: needs KVM (qemu accelerator=kvm) and the build-host tooling installed
|
|
# below (libguestfs, erofs-utils, cryptsetup, jq, ukify, buildah).
|
|
#
|
|
|
|
name: Build Diskless UKI
|
|
run-name: ${{ gitea.actor }} builds the diskless fleet UKI
|
|
on:
|
|
push:
|
|
branches:
|
|
- "main"
|
|
tags:
|
|
- "v*"
|
|
|
|
env:
|
|
PRODUCT_VERSION: "1.15.4" # Packer version
|
|
PACKER_LOG: "1"
|
|
OCI_IMAGE: "git.bitasylum.org/audiobuzz/fleet-boot"
|
|
NIC_DRIVERS: "ice mlx5_core"
|
|
# NVMe/TCP discovery address baked into the (immutable) UKI cmdline
|
|
# (rd.nvmf.discover). For the open-network test this is the lab serving host's
|
|
# IP so the initramfs needs no DNS resolution. Production: switch to a
|
|
# per-environment DNS name (e.g. nvme.fleet.lab) resolved at boot so one UKI
|
|
# works across environments — the serving stack's dnsmasq resolves it.
|
|
NVMET_TRADDR: "192.168.50.10"
|
|
# ===========================================================================
|
|
# TEMPORARY: 802.1X + MACsec are DISABLED for this build (rd.dot1x=0) so the
|
|
# UKI / rootfs / NVMe-oF boot path can be validated on an OPEN switch port.
|
|
# The resulting UKI has NO link authentication or encryption — test networks
|
|
# only. Set back to "false" to restore the full secure boot chain.
|
|
# ===========================================================================
|
|
DISABLE_DOT1X: "true"
|
|
|
|
jobs:
|
|
uki-build:
|
|
name: Diskless UKI Build
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: git.bitasylum.org/audiobuzz/ubuntu-act-runner-qemu:main
|
|
options: --device /dev/kvm
|
|
steps:
|
|
-
|
|
name: Checkout
|
|
uses: actions/checkout@v6
|
|
|
|
-
|
|
name: Derive image version
|
|
id: vars
|
|
# Tag push (v1.2.3 -> 1.2.3); otherwise 0.0.0-<short-sha>.
|
|
run: |
|
|
ref="${GITHUB_REF#refs/*/}"
|
|
if [ "${GITHUB_REF#refs/tags/}" != "$GITHUB_REF" ]; then
|
|
version="${ref#v}"
|
|
else
|
|
version="0.0.0-$(echo "${GITHUB_SHA}" | cut -c1-7)"
|
|
fi
|
|
echo "image_version=${version}" >> "$GITHUB_OUTPUT"
|
|
echo "Building image_version=${version}"
|
|
|
|
-
|
|
name: Install build-host tooling
|
|
# Tools the shell-local post-processors run on the RUNNER (not the VM):
|
|
# libguestfs (virt-*), erofs-utils (mkfs.erofs), cryptsetup
|
|
# (veritysetup), jq, systemd-ukify (ukify), buildah (OCI), plus qemu +
|
|
# shellcheck for the lint gate.
|
|
#
|
|
# libguestfs builds a supermin appliance on first use, which needs a
|
|
# kernel + modules present on the runner (incl. xfs, to read the build
|
|
# VM's xfs root). The runner container ships none, so install one and
|
|
# make /boot readable (Ubuntu ships vmlinuz mode 0600).
|
|
run: |
|
|
sudo apt-get update
|
|
# systemd-boot-efi ships the UKI EFI stub
|
|
# (/usr/lib/systemd/boot/efi/linuxx64.efi.stub) that ukify wraps the
|
|
# kernel+initrd+cmdline around. It's only a *recommends* of
|
|
# systemd-ukify, so --no-install-recommends would otherwise skip it.
|
|
sudo apt-get install -y --no-install-recommends \
|
|
qemu-system-x86 qemu-utils libguestfs-tools linux-image-generic \
|
|
erofs-utils cryptsetup-bin jq systemd-ukify systemd-boot-efi \
|
|
buildah shellcheck attr
|
|
sudo chmod 0644 /boot/vmlinuz-* 2>/dev/null || true
|
|
|
|
-
|
|
name: Setup Packer
|
|
uses: hashicorp/setup-packer@main
|
|
with:
|
|
version: ${{ env.PRODUCT_VERSION }}
|
|
|
|
-
|
|
name: Shell lint gate
|
|
# Matches CLAUDE.md conventions; dracut hooks + post-processor scripts.
|
|
run: |
|
|
bash -n files/dracut/95dot1x-macsec/*.sh scripts/*.sh
|
|
# SC1091 (sourced /lib/dracut-lib.sh) and SC2154 (dracut-injected
|
|
# $moddir) are dracut-module false positives. They're also in
|
|
# .shellcheckrc, but excluded explicitly here so the gate doesn't
|
|
# depend on the runner's shellcheck finding that rc file.
|
|
shellcheck --exclude=SC1091,SC2154 files/dracut/95dot1x-macsec/*.sh scripts/*.sh
|
|
|
|
-
|
|
name: packer init
|
|
run: packer init .
|
|
|
|
-
|
|
name: packer validate
|
|
run: packer validate .
|
|
|
|
-
|
|
name: Verify libguestfs appliance (fast gate)
|
|
# Fail in ~1 min if supermin can't build/boot the appliance, instead of
|
|
# after the ~17-min VM build when extract-artifacts.sh first runs virt-ls.
|
|
env:
|
|
LIBGUESTFS_BACKEND: direct
|
|
run: libguestfs-test-tool
|
|
|
|
-
|
|
name: Registry login
|
|
# Enables oci_push=true in the build step below.
|
|
run: |
|
|
buildah login \
|
|
--username "${{ secrets.PACKAGE_USER }}" \
|
|
--password "${{ secrets.PACKAGE_TOKEN }}" \
|
|
git.bitasylum.org
|
|
|
|
-
|
|
name: packer build (UKI + OCI release image)
|
|
# UNSIGNED lab build: sb_key/sb_cert deliberately omitted.
|
|
# TODO: wire SB_KEY/SB_CERT secrets for a signed UKI:
|
|
# -var sb_key=${{ secrets.SB_KEY }} -var sb_cert=${{ secrets.SB_CERT }}
|
|
run: |
|
|
packer build -color=false -on-error=abort \
|
|
-var image_version="${{ steps.vars.outputs.image_version }}" \
|
|
-var nic_drivers="${{ env.NIC_DRIVERS }}" \
|
|
-var oci_image="${{ env.OCI_IMAGE }}" \
|
|
-var oci_push=true \
|
|
-var disable_dot1x=${{ env.DISABLE_DOT1X }} \
|
|
-var nvmet_traddr="${{ env.NVMET_TRADDR }}" \
|
|
-var ssh_authorized_key="${{ secrets.SSH_AUTHORIZED_KEY }}" \
|
|
.
|