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. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
c095edd841
commit
4a6e37379e
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:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Build live ISO
|
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
|
timeout-minutes: 90
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
@ -38,164 +41,110 @@ jobs:
|
||||||
# node24 which forgejo-runner v6.4.0 (node20) cannot exec.
|
# node24 which forgejo-runner v6.4.0 (node20) cannot exec.
|
||||||
uses: actions/checkout@v4.1.7
|
uses: actions/checkout@v4.1.7
|
||||||
|
|
||||||
- name: Free up disk
|
- name: Install build tooling (Fedora)
|
||||||
run: |
|
run: |
|
||||||
sudo rm -rf /opt/hostedtoolcache /usr/share/dotnet /usr/local/lib/android /usr/local/share/boost
|
set -euxo pipefail
|
||||||
sudo apt-get clean
|
dnf -y upgrade --refresh
|
||||||
df -h
|
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
|
- name: Vendor gum binary into overlay
|
||||||
# v3 is composite/docker-based — no node runtime in the action
|
run: |
|
||||||
# itself. Safe under node20 forgejo-runner. TODO(infra): consider
|
set -euxo pipefail
|
||||||
# SHA pinning in a follow-up sweep.
|
GUM_VERSION="0.17.0"
|
||||||
uses: addnab/docker-run-action@v3
|
GUM_URL="https://github.com/charmbracelet/gum/releases/download/v${GUM_VERSION}/gum_${GUM_VERSION}_Linux_x86_64.tar.gz"
|
||||||
with:
|
GUM_SHA256="69ee169bd6387331928864e94d47ed01ef649fbfe875baed1bbf27b5377a6fdb"
|
||||||
# Pinned to amd64 digest from `skopeo inspect --raw` on 2026-05-06.
|
mkdir -p overlay/usr/local/bin
|
||||||
# Refresh by re-running skopeo against fedora:43 and picking the amd64 entry.
|
curl -fsSL "$GUM_URL" -o /tmp/gum.tgz
|
||||||
image: registry.fedoraproject.org/fedora:43@sha256:3207ed0f3765f81675f6ce2aa04f52a6cdbb2dddddc5ab9be6e0b0441ece136d
|
echo "$GUM_SHA256 /tmp/gum.tgz" | sha256sum -c -
|
||||||
options: |
|
tar -xzf /tmp/gum.tgz -C /tmp/
|
||||||
--privileged
|
install -m 0755 "/tmp/gum_${GUM_VERSION}_Linux_x86_64/gum" overlay/usr/local/bin/gum
|
||||||
--userns=host
|
overlay/usr/local/bin/gum --version
|
||||||
-v ${{ github.workspace }}:/work
|
echo "[OK] gum ${GUM_VERSION} vendored into overlay/usr/local/bin/"
|
||||||
-v /dev:/dev
|
|
||||||
--tmpfs /tmp:rw,nosuid,nodev,exec,size=16G
|
|
||||||
run: |
|
|
||||||
set -euxo pipefail
|
|
||||||
|
|
||||||
# Update Fedora image to latest packages — guarantees pcre2 +
|
- name: Build ISO with livecd-creator
|
||||||
# libselinux + selinux-policy are matched (the local build's
|
run: |
|
||||||
# core problem). CI runners always start fresh, no version skew.
|
set -euxo pipefail
|
||||||
dnf -y upgrade --refresh
|
|
||||||
|
|
||||||
# Install build tooling
|
# PATCH: livecd-creator bug — __get_efi_image_stanza writes
|
||||||
dnf -y install \
|
# `root=live:LABEL=...` instead of `live:CDLABEL=...` for dracut.
|
||||||
lorax \
|
# Result: dracut hangs on parse-livenet looking for non-CD label.
|
||||||
livecd-tools \
|
# Fix in-place before running build.
|
||||||
pykickstart \
|
LIVE_PY=$(python3 -c 'import imgcreate, os; print(os.path.dirname(imgcreate.__file__))')/live.py
|
||||||
python3-imgcreate \
|
sed -i 's|"live:LABEL=%(fslabel)s"|"live:CDLABEL=%(fslabel)s"|g' "$LIVE_PY"
|
||||||
anaconda-tui \
|
grep -n 'CDLABEL=%(fslabel)s' "$LIVE_PY" || { echo "[ERR] patch failed"; exit 1; }
|
||||||
squashfs-tools \
|
echo "[OK] livecd-creator patched: LABEL= → CDLABEL= for EFI dracut stanza"
|
||||||
xorriso \
|
|
||||||
createrepo_c \
|
|
||||||
git \
|
|
||||||
which \
|
|
||||||
shadow-utils \
|
|
||||||
syslinux \
|
|
||||||
tar \
|
|
||||||
curl
|
|
||||||
|
|
||||||
# Vendor gum binary onto the ISO so the TTY1 installer can use
|
# CI uses ks-ci.ks (no local fix-repo line). Generated from main ks.
|
||||||
# Charm.sh TUI primitives. gum is not packaged in Fedora repos,
|
# Drop `updates` repo: previously 404'd on repodata zchunk during
|
||||||
# so pull the upstream release tarball pinned by sha256.
|
# Fedora mid-push windows. Base 43 ships the selinux-policy fix.
|
||||||
GUM_VERSION="0.17.0"
|
sed -e '/veilor-fix/d' \
|
||||||
GUM_URL="https://github.com/charmbracelet/gum/releases/download/v${GUM_VERSION}/gum_${GUM_VERSION}_Linux_x86_64.tar.gz"
|
-e '/^shutdown$/d' \
|
||||||
GUM_SHA256="69ee169bd6387331928864e94d47ed01ef649fbfe875baed1bbf27b5377a6fdb"
|
-e '/repo --name=updates/d' \
|
||||||
mkdir -p /work/overlay/usr/local/bin
|
kickstart/veilor-os.ks > kickstart/veilor-os-ci.ks
|
||||||
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/"
|
|
||||||
|
|
||||||
cd /work
|
ksvalidator kickstart/veilor-os-ci.ks
|
||||||
|
mkdir -p build/out
|
||||||
|
|
||||||
# Diagnostic: dump workspace state so a path/perm issue surfaces
|
mkdir -p /var/lmc /var/lmc-cache
|
||||||
# before commands silently no-op.
|
livecd-creator \
|
||||||
echo "=== /work diagnostic ==="
|
--verbose \
|
||||||
id
|
--config kickstart/veilor-os-ci.ks \
|
||||||
pwd
|
--fslabel "veilor-os-43" \
|
||||||
mountpoint /work || true
|
--title "veilor-os" \
|
||||||
ls -la /work | head -20
|
--product "veilor-os" \
|
||||||
ls -la /work/kickstart 2>&1 | head -10
|
--releasever "${{ github.event.inputs.releasever || '43' }}" \
|
||||||
touch /work/kickstart/.write-test && echo "[OK] /work/kickstart writable" || echo "[ERR] /work/kickstart NOT writable"
|
--tmpdir /var/lmc \
|
||||||
rm -f /work/kickstart/.write-test 2>/dev/null
|
--cache /var/lmc-cache 2>&1 | tee build/out/build.log
|
||||||
echo "=== end diagnostic ==="
|
|
||||||
|
|
||||||
# PATCH: livecd-creator bug — __get_efi_image_stanza writes
|
- name: Graft veilor source tree onto ISO
|
||||||
# `root=live:LABEL=...` instead of `live:CDLABEL=...` for dracut.
|
run: |
|
||||||
# Result: dracut hangs on parse-livenet looking for non-CD label.
|
set -euxo pipefail
|
||||||
# Fix in-place before running build.
|
ISO_FILE=$(ls ./*.iso 2>/dev/null | head -1)
|
||||||
LIVE_PY=$(python3 -c 'import imgcreate, os; print(os.path.dirname(imgcreate.__file__))')/live.py
|
[ -n "$ISO_FILE" ] || { echo "[ERR] no ISO produced by livecd-creator"; exit 1; }
|
||||||
sed -i 's|"live:LABEL=%(fslabel)s"|"live:CDLABEL=%(fslabel)s"|g' "$LIVE_PY"
|
echo "[INFO] grafting /veilor/ onto $ISO_FILE"
|
||||||
grep -n 'CDLABEL=%(fslabel)s' "$LIVE_PY" || { echo "[ERR] patch failed"; exit 1; }
|
|
||||||
echo "[OK] livecd-creator patched: LABEL= → CDLABEL= for EFI dracut stanza"
|
|
||||||
|
|
||||||
# CI uses ks-ci.ks (no local fix-repo line). Generated from main ks.
|
xorriso -indev "$ISO_FILE" -report_el_torito as_mkisofs 2>&1 | tee /tmp/iso-boot.txt || true
|
||||||
# Also strip flags livecd-creator doesn't recognize.
|
ORIG_FLAGS=$(xorriso -indev "$ISO_FILE" -report_el_torito as_mkisofs 2>/dev/null | \
|
||||||
# Drop `updates` repo: 3 consecutive builds 404'd on its
|
grep -v '^xorriso :' | grep -E '^-' | tr '\n' ' ')
|
||||||
# repodata zchunk file across all mirrors — Fedora infra issue
|
[ -n "$ORIG_FLAGS" ] || { echo "[ERR] could not extract boot stanza from $ISO_FILE"; exit 1; }
|
||||||
# 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
|
|
||||||
|
|
||||||
ksvalidator kickstart/veilor-os-ci.ks
|
mkdir -p /tmp/iso-mod
|
||||||
mkdir -p build/out
|
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.
|
eval xorriso -as mkisofs \
|
||||||
# Handles EFI/BOOT + isohybrid + grafting that livemedia-creator
|
-volid "veilor-os-43" \
|
||||||
# --make-iso --no-virt does not. Produces UEFI+BIOS bootable ISO.
|
$ORIG_FLAGS \
|
||||||
# --tmpdir /var/lmc to avoid GitHub Actions /tmp tmpfs constraints.
|
-o "${ISO_FILE}.tmp" /tmp/iso-mod
|
||||||
# /var on the runner is the host's ext4 (~80GB free post-disk-cleanup).
|
mv "${ISO_FILE}.tmp" "$ISO_FILE"
|
||||||
mkdir -p /var/lmc /var/lmc-cache
|
rm -rf /tmp/iso-mod
|
||||||
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
|
|
||||||
|
|
||||||
# Graft veilor source tree onto the ISO so the installer-generated
|
mv "$ISO_FILE" build/out/
|
||||||
# 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"
|
|
||||||
|
|
||||||
# Extract original ISO's exact boot stanza so the rebuild matches
|
ISO_NAME="veilor-os-${{ github.event.inputs.releasever || '43' }}-$(date +%Y%m%d-%H%M%S).iso"
|
||||||
# livecd-creator's layout byte-for-byte. This is immune to upstream
|
cd build/out
|
||||||
# Fedora layout changes (e.g. images/ vs isolinux/ for efiboot.img,
|
for f in *.iso; do
|
||||||
# partition geometry flags, hybrid MBR/GPT options).
|
[[ -f $f && $f != "$ISO_NAME" ]] && mv "$f" "$ISO_NAME"
|
||||||
xorriso -indev "$ISO_FILE" -report_el_torito as_mkisofs 2>&1 | tee /tmp/iso-boot.txt || true
|
done
|
||||||
ORIG_FLAGS=$(xorriso -indev "$ISO_FILE" -report_el_torito as_mkisofs 2>/dev/null | \
|
sha256sum "$ISO_NAME" > "$ISO_NAME.sha256"
|
||||||
grep -v '^xorriso :' | grep -E '^-' | tr '\n' ' ')
|
ls -lh "$ISO_NAME"
|
||||||
[ -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 publish ────────────────────────────────────────────────────
|
# ── ISO publish ────────────────────────────────────────────────────
|
||||||
# GH Release asset size limit = 2 GiB. Our ISO ~2.8 GiB. Split into
|
# 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
|
- name: Split ISO into 2GiB chunks
|
||||||
if: success() && github.ref == 'refs/heads/main'
|
if: success() && github.ref == 'refs/heads/main'
|
||||||
run: |
|
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
|
cd build/out
|
||||||
ISO=$(ls *.iso | head -1)
|
ISO=$(ls *.iso | head -1)
|
||||||
[ -n "$ISO" ] || { echo "[ERR] no ISO"; exit 1; }
|
[ -n "$ISO" ] || { echo "[ERR] no ISO"; exit 1; }
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue