ci: run build directly in Fedora job container, drop addnab nest
forgejo-runner labels nullstone -> fedora:43 image. Switching runs-on: ubuntu-24.04 -> nullstone makes the job container itself the build environment, eliminating the docker-in-docker workspace bind-mount problem (host path != act-container path). Build now runs as root in fedora:43, installs livecd-tools directly via dnf, and writes outputs to $GITHUB_WORKSPACE which is the natural runner workdir on host. No nested docker, no userns juggling, no explicit -v workspace bind needed.
This commit is contained in:
parent
6f4842a75c
commit
ac5c29df42
1 changed files with 95 additions and 149 deletions
244
.github/workflows/build-iso.yml
vendored
244
.github/workflows/build-iso.yml
vendored
|
|
@ -29,7 +29,10 @@ permissions:
|
|||
jobs:
|
||||
build:
|
||||
name: Build live ISO
|
||||
runs-on: ubuntu-24.04
|
||||
# nullstone label resolves to a privileged Fedora 43 container per
|
||||
# the runner's RUNNER_LABELS map. Build runs directly in this job
|
||||
# container — no nested docker-run-action, no bind-mount juggling.
|
||||
runs-on: nullstone
|
||||
timeout-minutes: 90
|
||||
|
||||
steps:
|
||||
|
|
@ -38,164 +41,110 @@ jobs:
|
|||
# node24 which forgejo-runner v6.4.0 (node20) cannot exec.
|
||||
uses: actions/checkout@v4.1.7
|
||||
|
||||
- name: Free up disk
|
||||
- name: Install build tooling (Fedora)
|
||||
run: |
|
||||
sudo rm -rf /opt/hostedtoolcache /usr/share/dotnet /usr/local/lib/android /usr/local/share/boost
|
||||
sudo apt-get clean
|
||||
df -h
|
||||
set -euxo pipefail
|
||||
dnf -y upgrade --refresh
|
||||
dnf -y install \
|
||||
lorax \
|
||||
livecd-tools \
|
||||
pykickstart \
|
||||
python3-imgcreate \
|
||||
anaconda-tui \
|
||||
squashfs-tools \
|
||||
xorriso \
|
||||
createrepo_c \
|
||||
git \
|
||||
which \
|
||||
shadow-utils \
|
||||
syslinux \
|
||||
tar \
|
||||
curl \
|
||||
sudo
|
||||
|
||||
- name: Run build inside Fedora 43 container
|
||||
# v3 is composite/docker-based — no node runtime in the action
|
||||
# itself. Safe under node20 forgejo-runner. TODO(infra): consider
|
||||
# SHA pinning in a follow-up sweep.
|
||||
uses: addnab/docker-run-action@v3
|
||||
with:
|
||||
# Pinned to amd64 digest from `skopeo inspect --raw` on 2026-05-06.
|
||||
# Refresh by re-running skopeo against fedora:43 and picking the amd64 entry.
|
||||
image: registry.fedoraproject.org/fedora:43@sha256:3207ed0f3765f81675f6ce2aa04f52a6cdbb2dddddc5ab9be6e0b0441ece136d
|
||||
options: |
|
||||
--privileged
|
||||
--userns=host
|
||||
-v ${{ github.workspace }}:/work
|
||||
-v /dev:/dev
|
||||
--tmpfs /tmp:rw,nosuid,nodev,exec,size=16G
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
- name: Vendor gum binary into overlay
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
GUM_VERSION="0.17.0"
|
||||
GUM_URL="https://github.com/charmbracelet/gum/releases/download/v${GUM_VERSION}/gum_${GUM_VERSION}_Linux_x86_64.tar.gz"
|
||||
GUM_SHA256="69ee169bd6387331928864e94d47ed01ef649fbfe875baed1bbf27b5377a6fdb"
|
||||
mkdir -p overlay/usr/local/bin
|
||||
curl -fsSL "$GUM_URL" -o /tmp/gum.tgz
|
||||
echo "$GUM_SHA256 /tmp/gum.tgz" | sha256sum -c -
|
||||
tar -xzf /tmp/gum.tgz -C /tmp/
|
||||
install -m 0755 "/tmp/gum_${GUM_VERSION}_Linux_x86_64/gum" overlay/usr/local/bin/gum
|
||||
overlay/usr/local/bin/gum --version
|
||||
echo "[OK] gum ${GUM_VERSION} vendored into overlay/usr/local/bin/"
|
||||
|
||||
# Update Fedora image to latest packages — guarantees pcre2 +
|
||||
# libselinux + selinux-policy are matched (the local build's
|
||||
# core problem). CI runners always start fresh, no version skew.
|
||||
dnf -y upgrade --refresh
|
||||
- name: Build ISO with livecd-creator
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
|
||||
# Install build tooling
|
||||
dnf -y install \
|
||||
lorax \
|
||||
livecd-tools \
|
||||
pykickstart \
|
||||
python3-imgcreate \
|
||||
anaconda-tui \
|
||||
squashfs-tools \
|
||||
xorriso \
|
||||
createrepo_c \
|
||||
git \
|
||||
which \
|
||||
shadow-utils \
|
||||
syslinux \
|
||||
tar \
|
||||
curl
|
||||
# PATCH: livecd-creator bug — __get_efi_image_stanza writes
|
||||
# `root=live:LABEL=...` instead of `live:CDLABEL=...` for dracut.
|
||||
# Result: dracut hangs on parse-livenet looking for non-CD label.
|
||||
# Fix in-place before running build.
|
||||
LIVE_PY=$(python3 -c 'import imgcreate, os; print(os.path.dirname(imgcreate.__file__))')/live.py
|
||||
sed -i 's|"live:LABEL=%(fslabel)s"|"live:CDLABEL=%(fslabel)s"|g' "$LIVE_PY"
|
||||
grep -n 'CDLABEL=%(fslabel)s' "$LIVE_PY" || { echo "[ERR] patch failed"; exit 1; }
|
||||
echo "[OK] livecd-creator patched: LABEL= → CDLABEL= for EFI dracut stanza"
|
||||
|
||||
# Vendor gum binary onto the ISO so the TTY1 installer can use
|
||||
# Charm.sh TUI primitives. gum is not packaged in Fedora repos,
|
||||
# so pull the upstream release tarball pinned by sha256.
|
||||
GUM_VERSION="0.17.0"
|
||||
GUM_URL="https://github.com/charmbracelet/gum/releases/download/v${GUM_VERSION}/gum_${GUM_VERSION}_Linux_x86_64.tar.gz"
|
||||
GUM_SHA256="69ee169bd6387331928864e94d47ed01ef649fbfe875baed1bbf27b5377a6fdb"
|
||||
mkdir -p /work/overlay/usr/local/bin
|
||||
curl -fsSL "$GUM_URL" -o /tmp/gum.tgz
|
||||
echo "$GUM_SHA256 /tmp/gum.tgz" | sha256sum -c -
|
||||
tar -xzf /tmp/gum.tgz -C /tmp/
|
||||
install -m 0755 "/tmp/gum_${GUM_VERSION}_Linux_x86_64/gum" /work/overlay/usr/local/bin/gum
|
||||
/work/overlay/usr/local/bin/gum --version
|
||||
echo "[OK] gum ${GUM_VERSION} vendored into overlay/usr/local/bin/"
|
||||
# CI uses ks-ci.ks (no local fix-repo line). Generated from main ks.
|
||||
# Drop `updates` repo: previously 404'd on repodata zchunk during
|
||||
# Fedora mid-push windows. Base 43 ships the selinux-policy fix.
|
||||
sed -e '/veilor-fix/d' \
|
||||
-e '/^shutdown$/d' \
|
||||
-e '/repo --name=updates/d' \
|
||||
kickstart/veilor-os.ks > kickstart/veilor-os-ci.ks
|
||||
|
||||
cd /work
|
||||
ksvalidator kickstart/veilor-os-ci.ks
|
||||
mkdir -p build/out
|
||||
|
||||
# Diagnostic: dump workspace state so a path/perm issue surfaces
|
||||
# before commands silently no-op.
|
||||
echo "=== /work diagnostic ==="
|
||||
id
|
||||
pwd
|
||||
mountpoint /work || true
|
||||
ls -la /work | head -20
|
||||
ls -la /work/kickstart 2>&1 | head -10
|
||||
touch /work/kickstart/.write-test && echo "[OK] /work/kickstart writable" || echo "[ERR] /work/kickstart NOT writable"
|
||||
rm -f /work/kickstart/.write-test 2>/dev/null
|
||||
echo "=== end diagnostic ==="
|
||||
mkdir -p /var/lmc /var/lmc-cache
|
||||
livecd-creator \
|
||||
--verbose \
|
||||
--config kickstart/veilor-os-ci.ks \
|
||||
--fslabel "veilor-os-43" \
|
||||
--title "veilor-os" \
|
||||
--product "veilor-os" \
|
||||
--releasever "${{ github.event.inputs.releasever || '43' }}" \
|
||||
--tmpdir /var/lmc \
|
||||
--cache /var/lmc-cache 2>&1 | tee build/out/build.log
|
||||
|
||||
# PATCH: livecd-creator bug — __get_efi_image_stanza writes
|
||||
# `root=live:LABEL=...` instead of `live:CDLABEL=...` for dracut.
|
||||
# Result: dracut hangs on parse-livenet looking for non-CD label.
|
||||
# Fix in-place before running build.
|
||||
LIVE_PY=$(python3 -c 'import imgcreate, os; print(os.path.dirname(imgcreate.__file__))')/live.py
|
||||
sed -i 's|"live:LABEL=%(fslabel)s"|"live:CDLABEL=%(fslabel)s"|g' "$LIVE_PY"
|
||||
grep -n 'CDLABEL=%(fslabel)s' "$LIVE_PY" || { echo "[ERR] patch failed"; exit 1; }
|
||||
echo "[OK] livecd-creator patched: LABEL= → CDLABEL= for EFI dracut stanza"
|
||||
- name: Graft veilor source tree onto ISO
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
ISO_FILE=$(ls ./*.iso 2>/dev/null | head -1)
|
||||
[ -n "$ISO_FILE" ] || { echo "[ERR] no ISO produced by livecd-creator"; exit 1; }
|
||||
echo "[INFO] grafting /veilor/ onto $ISO_FILE"
|
||||
|
||||
# CI uses ks-ci.ks (no local fix-repo line). Generated from main ks.
|
||||
# Also strip flags livecd-creator doesn't recognize.
|
||||
# Drop `updates` repo: 3 consecutive builds 404'd on its
|
||||
# repodata zchunk file across all mirrors — Fedora infra issue
|
||||
# mid-push window. Original reason for `updates` (selinux-policy
|
||||
# 43.7 pcre2 fix) is no longer needed; base 43 ships fixed.
|
||||
sed -e '/veilor-fix/d' \
|
||||
-e '/^shutdown$/d' \
|
||||
-e '/repo --name=updates/d' \
|
||||
kickstart/veilor-os.ks > kickstart/veilor-os-ci.ks
|
||||
xorriso -indev "$ISO_FILE" -report_el_torito as_mkisofs 2>&1 | tee /tmp/iso-boot.txt || true
|
||||
ORIG_FLAGS=$(xorriso -indev "$ISO_FILE" -report_el_torito as_mkisofs 2>/dev/null | \
|
||||
grep -v '^xorriso :' | grep -E '^-' | tr '\n' ' ')
|
||||
[ -n "$ORIG_FLAGS" ] || { echo "[ERR] could not extract boot stanza from $ISO_FILE"; exit 1; }
|
||||
|
||||
ksvalidator kickstart/veilor-os-ci.ks
|
||||
mkdir -p build/out
|
||||
mkdir -p /tmp/iso-mod
|
||||
xorriso -osirrox on -indev "$ISO_FILE" -extract / /tmp/iso-mod
|
||||
chmod -R u+w /tmp/iso-mod
|
||||
mkdir -p /tmp/iso-mod/veilor
|
||||
cp -a overlay scripts assets /tmp/iso-mod/veilor/
|
||||
|
||||
# livecd-creator (livecd-tools) — purpose-built for live ISOs.
|
||||
# Handles EFI/BOOT + isohybrid + grafting that livemedia-creator
|
||||
# --make-iso --no-virt does not. Produces UEFI+BIOS bootable ISO.
|
||||
# --tmpdir /var/lmc to avoid GitHub Actions /tmp tmpfs constraints.
|
||||
# /var on the runner is the host's ext4 (~80GB free post-disk-cleanup).
|
||||
mkdir -p /var/lmc /var/lmc-cache
|
||||
livecd-creator \
|
||||
--verbose \
|
||||
--config kickstart/veilor-os-ci.ks \
|
||||
--fslabel "veilor-os-43" \
|
||||
--title "veilor-os" \
|
||||
--product "veilor-os" \
|
||||
--releasever "${{ github.event.inputs.releasever || '43' }}" \
|
||||
--tmpdir /var/lmc \
|
||||
--cache /var/lmc-cache 2>&1 | tee build/out/build.log
|
||||
eval xorriso -as mkisofs \
|
||||
-volid "veilor-os-43" \
|
||||
$ORIG_FLAGS \
|
||||
-o "${ISO_FILE}.tmp" /tmp/iso-mod
|
||||
mv "${ISO_FILE}.tmp" "$ISO_FILE"
|
||||
rm -rf /tmp/iso-mod
|
||||
|
||||
# Graft veilor source tree onto the ISO so the installer-generated
|
||||
# kickstart's `%post --nochroot` can find SRC at
|
||||
# /run/install/repo/veilor/{overlay,scripts,assets}/ when the user
|
||||
# promotes the live ISO into a real install.
|
||||
ISO_FILE=$(ls /work/*.iso 2>/dev/null | head -1)
|
||||
[ -n "$ISO_FILE" ] || { echo "[ERR] no ISO produced by livecd-creator"; exit 1; }
|
||||
echo "[INFO] grafting /veilor/ onto $ISO_FILE"
|
||||
mv "$ISO_FILE" build/out/
|
||||
|
||||
# Extract original ISO's exact boot stanza so the rebuild matches
|
||||
# livecd-creator's layout byte-for-byte. This is immune to upstream
|
||||
# Fedora layout changes (e.g. images/ vs isolinux/ for efiboot.img,
|
||||
# partition geometry flags, hybrid MBR/GPT options).
|
||||
xorriso -indev "$ISO_FILE" -report_el_torito as_mkisofs 2>&1 | tee /tmp/iso-boot.txt || true
|
||||
ORIG_FLAGS=$(xorriso -indev "$ISO_FILE" -report_el_torito as_mkisofs 2>/dev/null | \
|
||||
grep -v '^xorriso :' | grep -E '^-' | tr '\n' ' ')
|
||||
[ -n "$ORIG_FLAGS" ] || { echo "[ERR] could not extract boot stanza from $ISO_FILE"; exit 1; }
|
||||
echo "[INFO] re-pack flags from original ISO: $ORIG_FLAGS"
|
||||
|
||||
mkdir -p /tmp/iso-mod
|
||||
xorriso -osirrox on -indev "$ISO_FILE" -extract / /tmp/iso-mod
|
||||
chmod -R u+w /tmp/iso-mod
|
||||
mkdir -p /tmp/iso-mod/veilor
|
||||
cp -a /work/overlay /work/scripts /work/assets /tmp/iso-mod/veilor/
|
||||
|
||||
# Replay the exact stanza captured above. eval is needed because
|
||||
# ORIG_FLAGS contains multiple flag/value pairs that must word-split.
|
||||
eval xorriso -as mkisofs \
|
||||
-volid "veilor-os-43" \
|
||||
$ORIG_FLAGS \
|
||||
-o "${ISO_FILE}.tmp" /tmp/iso-mod
|
||||
mv "${ISO_FILE}.tmp" "$ISO_FILE"
|
||||
rm -rf /tmp/iso-mod
|
||||
echo "[OK] /veilor/ grafted onto $ISO_FILE"
|
||||
|
||||
# Move output ISO to expected dir
|
||||
mv ./veilor-os-43.iso build/out/ 2>/dev/null || mv ./*.iso build/out/ 2>/dev/null || true
|
||||
|
||||
# Rename + checksum
|
||||
ISO_NAME="veilor-os-${{ github.event.inputs.releasever || '43' }}-$(date +%Y%m%d-%H%M%S).iso"
|
||||
cd build/out
|
||||
for f in *.iso; do
|
||||
[[ -f $f && $f != $ISO_NAME ]] && mv "$f" "$ISO_NAME"
|
||||
done
|
||||
sha256sum "$ISO_NAME" > "$ISO_NAME.sha256"
|
||||
ls -lh "$ISO_NAME"
|
||||
ISO_NAME="veilor-os-${{ github.event.inputs.releasever || '43' }}-$(date +%Y%m%d-%H%M%S).iso"
|
||||
cd build/out
|
||||
for f in *.iso; do
|
||||
[[ -f $f && $f != "$ISO_NAME" ]] && mv "$f" "$ISO_NAME"
|
||||
done
|
||||
sha256sum "$ISO_NAME" > "$ISO_NAME.sha256"
|
||||
ls -lh "$ISO_NAME"
|
||||
|
||||
# ── ISO publish ────────────────────────────────────────────────────
|
||||
# GH Release asset size limit = 2 GiB. Our ISO ~2.8 GiB. Split into
|
||||
|
|
@ -205,9 +154,6 @@ jobs:
|
|||
- name: Split ISO into 2GiB chunks
|
||||
if: success() && github.ref == 'refs/heads/main'
|
||||
run: |
|
||||
# ISO + sidecars created by Fedora container as root. Reclaim
|
||||
# ownership so this step (running as runner user) can write.
|
||||
sudo chown -R "$(id -u):$(id -g)" build/out
|
||||
cd build/out
|
||||
ISO=$(ls *.iso | head -1)
|
||||
[ -n "$ISO" ] || { echo "[ERR] no ISO"; exit 1; }
|
||||
|
|
|
|||
Loading…
Reference in a new issue