Build a live ISO too, and put it in releases
live/: quine-linux plus the live session and Anaconda WebUI, adapted from Aurora's live ISO (get-aurora-dev/iso); Titanoboa's script packs it into the ISO. The installer installs quine-linux:latest from inside the ISO, and plasma-setup creates the first user at first boot, as on the disk image. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
d55103a6c1
commit
79457c2a4b
7 changed files with 419 additions and 7 deletions
|
|
@ -1,12 +1,12 @@
|
||||||
name: Image, installer ISO and disk image
|
name: Image, installer ISO, disk image and live ISO
|
||||||
|
|
||||||
# Builds the quine-linux image on our Aurora build (published by
|
# Builds the quine-linux image on our Aurora build (published by
|
||||||
# quine-global-labs/aurora's workflow to this forge's registry), pushes it to
|
# quine-global-labs/aurora's workflow to this forge's registry), pushes it to
|
||||||
# forge.quinefoundation.com/quine-global-labs/quine-linux (`latest`,
|
# forge.quinefoundation.com/quine-global-labs/quine-linux (`latest`,
|
||||||
# `<date>`, the commit), then builds the installer ISO and a disk image
|
# `<date>`, the commit), then builds the installer ISO, a disk image (qcow2)
|
||||||
# (qcow2) from it and uploads them to MinIO as
|
# and a live ISO from it and uploads them to MinIO as
|
||||||
# <bucket>/installer/<commit>/install.iso, <bucket>/installer/latest/install.iso
|
# <bucket>/installer/<commit>/install.iso, <bucket>/installer/latest/install.iso,
|
||||||
# and <bucket>/disk/latest/disk.qcow2.
|
# <bucket>/disk/latest/disk.qcow2 and <bucket>/live/latest/live.iso.
|
||||||
#
|
#
|
||||||
# Runs on runner-x86-linux (host mode, root podman; petersweb-infra,
|
# Runs on runner-x86-linux (host mode, root podman; petersweb-infra,
|
||||||
# hosts/runner-x86-linux): bootc-image-builder needs an x86_64 host with
|
# hosts/runner-x86-linux): bootc-image-builder needs an x86_64 host with
|
||||||
|
|
@ -86,9 +86,11 @@ jobs:
|
||||||
- name: Vendor upstream images
|
- name: Vendor upstream images
|
||||||
# Into the forge's mirror/ (.forgejo/vendor-images.sh), which the
|
# Into the forge's mirror/ (.forgejo/vendor-images.sh), which the
|
||||||
# pulls below then read: the installer's two bases
|
# pulls below then read: the installer's two bases
|
||||||
# (installer/Containerfile) and bootc-image-builder (Taskfile.yml).
|
# (installer/Containerfile), bootc-image-builder (Taskfile.yml) and
|
||||||
|
# what Titanoboa's ISO step runs in (Taskfile.yml, FEDORA_IMAGE).
|
||||||
run: |
|
run: |
|
||||||
.forgejo/vendor-images.sh \
|
.forgejo/vendor-images.sh \
|
||||||
|
quay.io/fedora/fedora:latest \
|
||||||
quay.io/fedora/fedora-bootc:rawhide \
|
quay.io/fedora/fedora-bootc:rawhide \
|
||||||
registry.fedoraproject.org/fedora:rawhide \
|
registry.fedoraproject.org/fedora:rawhide \
|
||||||
ghcr.io/osbuild/bootc-image-builder:latest
|
ghcr.io/osbuild/bootc-image-builder:latest
|
||||||
|
|
@ -103,6 +105,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
for img in \
|
for img in \
|
||||||
"$BASE_IMAGE" \
|
"$BASE_IMAGE" \
|
||||||
|
quay.io/fedora/fedora:latest \
|
||||||
quay.io/fedora/fedora-bootc:rawhide \
|
quay.io/fedora/fedora-bootc:rawhide \
|
||||||
registry.fedoraproject.org/fedora:rawhide \
|
registry.fedoraproject.org/fedora:rawhide \
|
||||||
ghcr.io/osbuild/bootc-image-builder:latest; do
|
ghcr.io/osbuild/bootc-image-builder:latest; do
|
||||||
|
|
@ -131,6 +134,10 @@ jobs:
|
||||||
- name: Build disk image
|
- name: Build disk image
|
||||||
run: task build-disk-image CONTAINER_RUNTIME=podman BASE_IMAGE="$BASE_IMAGE"
|
run: task build-disk-image CONTAINER_RUNTIME=podman BASE_IMAGE="$BASE_IMAGE"
|
||||||
|
|
||||||
|
- name: Build live ISO
|
||||||
|
# Installs quine-linux:latest, which "Push image" just updated.
|
||||||
|
run: task build-live-iso CONTAINER_RUNTIME=podman BASE_IMAGE="$BASE_IMAGE"
|
||||||
|
|
||||||
- name: Upload to MinIO
|
- name: Upload to MinIO
|
||||||
env:
|
env:
|
||||||
MINIO_ACCESS_KEY: ${{ vars.MINIO_ACCESS_KEY || secrets.MINIO_ACCESS_KEY }}
|
MINIO_ACCESS_KEY: ${{ vars.MINIO_ACCESS_KEY || secrets.MINIO_ACCESS_KEY }}
|
||||||
|
|
@ -147,9 +154,11 @@ jobs:
|
||||||
dest="store/${MINIO_BUCKET}/installer"
|
dest="store/${MINIO_BUCKET}/installer"
|
||||||
mc cp "$iso" "${dest}/${GITHUB_SHA}/install.iso"
|
mc cp "$iso" "${dest}/${GITHUB_SHA}/install.iso"
|
||||||
mc cp "${dest}/${GITHUB_SHA}/install.iso" "${dest}/latest/install.iso"
|
mc cp "${dest}/${GITHUB_SHA}/install.iso" "${dest}/latest/install.iso"
|
||||||
# The disk image: latest only, it's as big as the ISO.
|
# The disk image and live ISO: latest only, they're as big as the ISO.
|
||||||
ls -lh output/qcow2/disk.qcow2
|
ls -lh output/qcow2/disk.qcow2
|
||||||
mc cp output/qcow2/disk.qcow2 "store/${MINIO_BUCKET}/disk/latest/disk.qcow2"
|
mc cp output/qcow2/disk.qcow2 "store/${MINIO_BUCKET}/disk/latest/disk.qcow2"
|
||||||
|
ls -lh output/live/Quine-Linux-Live.iso
|
||||||
|
mc cp output/live/Quine-Linux-Live.iso "store/${MINIO_BUCKET}/live/latest/live.iso"
|
||||||
|
|
||||||
- name: Publish the release
|
- name: Publish the release
|
||||||
if: github.ref_type == 'tag'
|
if: github.ref_type == 'tag'
|
||||||
|
|
@ -162,6 +171,7 @@ jobs:
|
||||||
mkdir -p release
|
mkdir -p release
|
||||||
ln -f "$(find output -name install.iso -print -quit)" "release/quine-linux-$tag-installer-x86_64.iso"
|
ln -f "$(find output -name install.iso -print -quit)" "release/quine-linux-$tag-installer-x86_64.iso"
|
||||||
ln -f output/qcow2/disk.qcow2 "release/quine-linux-$tag-x86_64.qcow2"
|
ln -f output/qcow2/disk.qcow2 "release/quine-linux-$tag-x86_64.qcow2"
|
||||||
|
ln -f output/live/Quine-Linux-Live.iso "release/quine-linux-$tag-live-x86_64.iso"
|
||||||
(cd release && sha256sum -- * > SHA256SUMS)
|
(cd release && sha256sum -- * > SHA256SUMS)
|
||||||
cat release/SHA256SUMS
|
cat release/SHA256SUMS
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,12 @@ list what's available. Notably:
|
||||||
stock Fedora's, landing in `output/bootiso/install.iso`. See
|
stock Fedora's, landing in `output/bootiso/install.iso`. See
|
||||||
[`docs/patched-anaconda-installer.md`](docs/patched-anaconda-installer.md)
|
[`docs/patched-anaconda-installer.md`](docs/patched-anaconda-installer.md)
|
||||||
for forking/patching Anaconda itself.
|
for forking/patching Anaconda itself.
|
||||||
|
- `task build-disk-image` — builds a ready-installed disk image (qcow2)
|
||||||
|
via `bootc-image-builder`, landing in `output/qcow2/disk.qcow2`. It has
|
||||||
|
no user: plasma-setup creates the first one at first boot.
|
||||||
|
- `task build-live-iso` — builds a live ISO (`live/`, after Aurora's):
|
||||||
|
boots into a Quine Linux session with Anaconda WebUI to install it,
|
||||||
|
landing in `output/live/Quine-Linux-Live.iso`. Podman only.
|
||||||
- `task test:stage` / `task test:boot` — stage the locally-built image as
|
- `task test:stage` / `task test:boot` — stage the locally-built image as
|
||||||
this machine's next boot target (`bootc switch`), optionally rebooting
|
this machine's next boot target (`bootc switch`), optionally rebooting
|
||||||
into it immediately. The fast way to test a change — especially the
|
into it immediately. The fast way to test a change — especially the
|
||||||
|
|
|
||||||
44
Taskfile.yml
44
Taskfile.yml
|
|
@ -3,6 +3,7 @@ version: '3'
|
||||||
vars:
|
vars:
|
||||||
IMAGE: quine-linux
|
IMAGE: quine-linux
|
||||||
INSTALLER_IMAGE: quine-installer
|
INSTALLER_IMAGE: quine-installer
|
||||||
|
LIVE_IMAGE: quine-linux-live
|
||||||
# What the Containerfile builds FROM: our Aurora fork
|
# What the Containerfile builds FROM: our Aurora fork
|
||||||
# (quine-global-labs/aurora), built and published by that repo's workflow.
|
# (quine-global-labs/aurora), built and published by that repo's workflow.
|
||||||
# Override with a local build of the fork (BASE_IMAGE=localhost/aurora:stable,
|
# Override with a local build of the fork (BASE_IMAGE=localhost/aurora:stable,
|
||||||
|
|
@ -25,6 +26,8 @@ vars:
|
||||||
PLATFORM: linux/amd64
|
PLATFORM: linux/amd64
|
||||||
TARGET_ARCH: amd64
|
TARGET_ARCH: amd64
|
||||||
SKOPEO_IMAGE: quay.io/skopeo/stable:latest
|
SKOPEO_IMAGE: quay.io/skopeo/stable:latest
|
||||||
|
# Titanoboa's ISO step runs in this (live/titanoboa-build-iso.sh).
|
||||||
|
FEDORA_IMAGE: quay.io/fedora/fedora:latest
|
||||||
# bootc-image-builder reads images from a containers-storage mounted at
|
# bootc-image-builder reads images from a containers-storage mounted at
|
||||||
# /var/lib/containers/storage. Under podman that's root's real store; docker
|
# /var/lib/containers/storage. Under podman that's root's real store; docker
|
||||||
# has no such store, so images get copied (via skopeo) into this volume.
|
# has no such store, so images get copied (via skopeo) into this volume.
|
||||||
|
|
@ -166,6 +169,47 @@ tasks:
|
||||||
generates:
|
generates:
|
||||||
- "{{.OUTPUT_DIR}}/qcow2/disk.qcow2"
|
- "{{.OUTPUT_DIR}}/qcow2/disk.qcow2"
|
||||||
|
|
||||||
|
build-live-image:
|
||||||
|
desc: >-
|
||||||
|
Build the live ISO's root filesystem (live/Containerfile): quine-linux
|
||||||
|
plus the live session and Anaconda WebUI, with PAYLOAD_IMAGE (what the
|
||||||
|
installer installs) pulled into it. Podman only.
|
||||||
|
vars:
|
||||||
|
PAYLOAD_IMAGE: '{{.PAYLOAD_IMAGE | default "forge.quinefoundation.com/quine-global-labs/quine-linux:latest"}}'
|
||||||
|
preconditions:
|
||||||
|
- sh: '[ "{{.CONTAINER_RUNTIME}}" = podman ]'
|
||||||
|
msg: The live ISO tasks need podman (they mount the image into Titanoboa's container).
|
||||||
|
cmds:
|
||||||
|
- >-
|
||||||
|
{{.SUDO}} podman build --platform {{.PLATFORM}}
|
||||||
|
--cap-add sys_admin --security-opt label=disable
|
||||||
|
--build-arg BASE_IMAGE=localhost/{{.IMAGE}}
|
||||||
|
--build-arg PAYLOAD_IMAGE={{.PAYLOAD_IMAGE}}
|
||||||
|
-t {{.LIVE_IMAGE}} -f live/Containerfile live/
|
||||||
|
|
||||||
|
build-live-iso:
|
||||||
|
desc: >-
|
||||||
|
Build the live ISO: boots into a Quine Linux session, with an installer.
|
||||||
|
Titanoboa's script (live/titanoboa-build-iso.sh) packs the live image
|
||||||
|
into it. Output lands in {{.OUTPUT_DIR}}/live/Quine-Linux-Live.iso.
|
||||||
|
PAYLOAD_IMAGE: see build-live-image.
|
||||||
|
preconditions:
|
||||||
|
- sh: '[ "{{.CONTAINER_RUNTIME}}" = podman ]'
|
||||||
|
msg: The live ISO tasks need podman (they mount the image into Titanoboa's container).
|
||||||
|
cmds:
|
||||||
|
- task: build-image
|
||||||
|
- task: build-live-image
|
||||||
|
- mkdir -p {{.OUTPUT_DIR}}/live
|
||||||
|
- >-
|
||||||
|
{{.SUDO}} podman run --rm {{.PULL_FLAG}}
|
||||||
|
--cap-add sys_admin --security-opt label=disable
|
||||||
|
-v {{.ROOT_DIR}}/live/titanoboa-build-iso.sh:/src/build_iso.sh:ro
|
||||||
|
--mount type=image,source=localhost/{{.LIVE_IMAGE}},dst=/rootfs
|
||||||
|
-v {{.OUTPUT_DIR}}/live:/output
|
||||||
|
{{.FEDORA_IMAGE}} /src/build_iso.sh
|
||||||
|
generates:
|
||||||
|
- "{{.OUTPUT_DIR}}/live/Quine-Linux-Live.iso"
|
||||||
|
|
||||||
export-to-storage:
|
export-to-storage:
|
||||||
internal: true
|
internal: true
|
||||||
desc: >-
|
desc: >-
|
||||||
|
|
|
||||||
17
live/Containerfile
Normal file
17
live/Containerfile
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# The live ISO's root filesystem: quine-linux plus what booting from an ISO
|
||||||
|
# and installing from it need (build.sh). Titanoboa's script then packs it
|
||||||
|
# into the ISO (titanoboa-build-iso.sh, task build-live-iso).
|
||||||
|
#
|
||||||
|
# Build with --cap-add sys_admin --security-opt label=disable: build.sh
|
||||||
|
# remounts /proc/sys and pulls the image the installer installs.
|
||||||
|
ARG BASE_IMAGE=localhost/quine-linux
|
||||||
|
# What the installer puts on disk, from the registry, and what installed
|
||||||
|
# systems then update from.
|
||||||
|
ARG PAYLOAD_IMAGE=forge.quinefoundation.com/quine-global-labs/quine-linux:latest
|
||||||
|
FROM ${BASE_IMAGE}
|
||||||
|
ARG PAYLOAD_IMAGE
|
||||||
|
ENV PAYLOAD_IMAGE=${PAYLOAD_IMAGE}
|
||||||
|
|
||||||
|
COPY . /src/live/
|
||||||
|
RUN --mount=type=cache,dst=/var/cache/libdnf5 \
|
||||||
|
bash /src/live/build.sh && rm -rf /src/live
|
||||||
226
live/build.sh
Normal file
226
live/build.sh
Normal file
|
|
@ -0,0 +1,226 @@
|
||||||
|
#!/usr/bin/bash
|
||||||
|
# Turns quine-linux into the live ISO's root filesystem (live/Containerfile):
|
||||||
|
# boots from the ISO into a KDE session as the live user, with Anaconda WebUI
|
||||||
|
# to install $PAYLOAD_IMAGE. Adapted from Aurora's live ISO,
|
||||||
|
# github.com/get-aurora-dev/iso (Apache-2.0), iso_files/*.sh at bee017f.
|
||||||
|
#
|
||||||
|
# Installed systems get their first user from plasma-setup at first boot, so
|
||||||
|
# the installer hides its account pages, as Aurora's does.
|
||||||
|
set -exo pipefail
|
||||||
|
|
||||||
|
SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
# Create the directory that /root is symlinked to
|
||||||
|
mkdir -p "$(realpath /root)"
|
||||||
|
# bwrap (flatpak) writes /proc/sys/user/max_user_namespaces, read-only here
|
||||||
|
mount -o remount,rw /proc/sys
|
||||||
|
|
||||||
|
# ── The image to install, and the system Flatpaks to copy over ─────────────
|
||||||
|
# Both land in this filesystem, so installing needs no network.
|
||||||
|
podman pull "$PAYLOAD_IMAGE"
|
||||||
|
|
||||||
|
grep -v '#' /usr/share/ublue-os/homebrew/system-flatpaks.Brewfile | grep '^flatpak' |
|
||||||
|
sed 's/flatpak //' | tr -d '"' >/tmp/flatpaks.list
|
||||||
|
curl --retry 3 -Lo /etc/flatpak/remotes.d/flathub.flatpakrepo https://dl.flathub.org/repo/flathub.flatpakrepo
|
||||||
|
xargs -r flatpak install -y --noninteractive </tmp/flatpaks.list || true
|
||||||
|
flatpak list --columns=runtime,app
|
||||||
|
|
||||||
|
# ── Booting from the ISO ───────────────────────────────────────────────────
|
||||||
|
dnf install -y \
|
||||||
|
dracut-live \
|
||||||
|
livesys-scripts \
|
||||||
|
anaconda-live \
|
||||||
|
anaconda-webui \
|
||||||
|
pykickstart \
|
||||||
|
jq \
|
||||||
|
rsync \
|
||||||
|
desktop-file-utils \
|
||||||
|
libblockdev-btrfs \
|
||||||
|
libblockdev-lvm \
|
||||||
|
libblockdev-dm \
|
||||||
|
grub2-efi-x64-cdboot
|
||||||
|
|
||||||
|
kernel=$(find /usr/lib/modules -maxdepth 1 -type d -printf '%P\n' | grep . | head -1)
|
||||||
|
DRACUT_NO_XATTR=1 dracut -v --force --zstd --reproducible --no-hostonly \
|
||||||
|
--add "dmsquash-live dmsquash-live-autooverlay" \
|
||||||
|
"/usr/lib/modules/$kernel/initramfs.img" "$kernel"
|
||||||
|
|
||||||
|
# The live user, logged in to KDE
|
||||||
|
sed -i 's/^livesys_session=.*/livesys_session=kde/' /etc/sysconfig/livesys
|
||||||
|
systemctl enable livesys.service livesys-late.service
|
||||||
|
|
||||||
|
# Titanoboa reads EFI from /boot/efi. The fallback entry is grub itself.
|
||||||
|
mkdir -p /boot/efi
|
||||||
|
cp -av /usr/lib/efi/*/*/EFI /boot/efi/
|
||||||
|
cp -v /boot/efi/EFI/fedora/grubx64.efi /boot/efi/EFI/BOOT/fbx64.efi
|
||||||
|
|
||||||
|
# A larger /var/tmp than the live overlay's
|
||||||
|
cat >/etc/systemd/system/var-tmp.mount <<'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=Larger tmpfs for /var/tmp on live system
|
||||||
|
|
||||||
|
[Mount]
|
||||||
|
What=tmpfs
|
||||||
|
Where=/var/tmp
|
||||||
|
Type=tmpfs
|
||||||
|
Options=size=50%,nr_inodes=1m,x-systemd.graceful-option=usrquota
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=local-fs.target
|
||||||
|
EOF
|
||||||
|
systemctl enable var-tmp.mount
|
||||||
|
|
||||||
|
rm -f /etc/localtime
|
||||||
|
systemd-firstboot --timezone UTC
|
||||||
|
|
||||||
|
mkdir -p /usr/lib/bootc-image-builder
|
||||||
|
cp "$SRC/iso.yaml" /usr/lib/bootc-image-builder/iso.yaml
|
||||||
|
|
||||||
|
# ── What a live session shouldn't do ───────────────────────────────────────
|
||||||
|
for unit in tailscaled.service brew-upgrade.timer brew-update.timer brew-setup.service \
|
||||||
|
uupd.timer ublue-system-setup.service flatpak-preinstall.service; do
|
||||||
|
systemctl disable "$unit" || true
|
||||||
|
done
|
||||||
|
systemctl --global disable podman-auto-update.timer ublue-user-setup.service || true
|
||||||
|
rm -f /usr/share/applications/dev.getaurora.system-update.desktop
|
||||||
|
rm -f /usr/lib/systemd/system/flatpak-add-fedora-repos.service
|
||||||
|
|
||||||
|
# Only the system Flatpaks above get copied to the installed system, not
|
||||||
|
# what the live user installs.
|
||||||
|
cat >/usr/lib/systemd/system/var-lib-flatpak.mount <<'EOF'
|
||||||
|
[Unit]
|
||||||
|
Description=tmpfs so only the system Flatpaks are transferred to the installed system
|
||||||
|
Conflicts=umount.target
|
||||||
|
|
||||||
|
[Mount]
|
||||||
|
Type=overlay
|
||||||
|
What=overlay
|
||||||
|
Where=/var/lib/flatpak
|
||||||
|
Options=lowerdir=/var/lib/flatpak,upperdir=/run/overlay/flatpak,workdir=/run/overlay/flatpak.work
|
||||||
|
[Install]
|
||||||
|
WantedBy=local-fs.target
|
||||||
|
EOF
|
||||||
|
cat >/usr/lib/tmpfiles.d/quine-live-flatpak.conf <<'EOF'
|
||||||
|
d /run/overlay/flatpak 0755 - - -
|
||||||
|
d /run/overlay/flatpak.work 0755 - - -
|
||||||
|
EOF
|
||||||
|
systemctl enable var-lib-flatpak.mount
|
||||||
|
|
||||||
|
# ── KDE in the live session ────────────────────────────────────────────────
|
||||||
|
# The installer in Kickoff's favourites; no wallet prompts
|
||||||
|
sed -i '2s/$/;liveinst.desktop/' /usr/share/kde-settings/kde-profile/default/xdg/kicker-extra-favoritesrc
|
||||||
|
tee -a /etc/xdg/kwalletrc <<'EOF'
|
||||||
|
[Wallet]
|
||||||
|
Enabled=false
|
||||||
|
EOF
|
||||||
|
|
||||||
|
. /etc/os-release
|
||||||
|
echo "Quine Linux $VERSION_ID" >/etc/system-release
|
||||||
|
|
||||||
|
# plasma-welcome crashes with --live-environment unless given its pages
|
||||||
|
# (github.com/ublue-os/aurora/issues/2624, bugs.kde.org/523540)
|
||||||
|
cat >/usr/bin/plasma-welcome <<'EOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
exec /usr/bin/plasma-welcome-original --pages Live,Welcome,SimpleByDefault,PowerfulWhenNeeded,Enjoy "$@"
|
||||||
|
EOF
|
||||||
|
rm -f /usr/share/plasma/plasma-welcome/intro-customization.desktop
|
||||||
|
|
||||||
|
# ── The installer ──────────────────────────────────────────────────────────
|
||||||
|
sed -i 's/ANACONDA_PRODUCTVERSION=.*/ANACONDA_PRODUCTVERSION=""/' /usr/{,s}bin/liveinst || true
|
||||||
|
|
||||||
|
# The profile matches os-release's ID (Aurora's, which quine-linux keeps).
|
||||||
|
mkdir -p /etc/anaconda/profile.d
|
||||||
|
tee /etc/anaconda/profile.d/quine-linux.conf <<EOF
|
||||||
|
[Profile]
|
||||||
|
profile_id = quine-linux
|
||||||
|
|
||||||
|
[Profile Detection]
|
||||||
|
os_id = $ID
|
||||||
|
|
||||||
|
[Network]
|
||||||
|
default_on_boot = FIRST_WIRED_WITH_LINK
|
||||||
|
|
||||||
|
[Bootloader]
|
||||||
|
efi_dir = fedora
|
||||||
|
menu_auto_hide = True
|
||||||
|
|
||||||
|
[Storage]
|
||||||
|
default_scheme = BTRFS
|
||||||
|
btrfs_compression = zstd:1
|
||||||
|
default_partitioning =
|
||||||
|
/ (min 1 GiB, max 70 GiB)
|
||||||
|
/home (min 500 MiB, free 50 GiB)
|
||||||
|
/var (btrfs)
|
||||||
|
|
||||||
|
[User Interface]
|
||||||
|
webui_web_engine = slitherer
|
||||||
|
hidden_spokes =
|
||||||
|
NetworkSpoke
|
||||||
|
PasswordSpoke
|
||||||
|
UserSpoke
|
||||||
|
hidden_webui_pages =
|
||||||
|
anaconda-screen-date-time
|
||||||
|
anaconda-network
|
||||||
|
anaconda-screen-accounts
|
||||||
|
EOF
|
||||||
|
|
||||||
|
desktop-file-edit --set-key=StartupWMClass --set-value=slitherer \
|
||||||
|
/usr/share/applications/liveinst.desktop
|
||||||
|
|
||||||
|
# Install the pulled image, then point the system at the registry for updates.
|
||||||
|
tee -a /usr/share/anaconda/interactive-defaults.ks <<EOF
|
||||||
|
ostreecontainer --url=$PAYLOAD_IMAGE --transport=containers-storage --no-signature-verification
|
||||||
|
%include /usr/share/anaconda/post-scripts/install-configure-upgrade.ks
|
||||||
|
%include /usr/share/anaconda/post-scripts/install-flatpaks.ks
|
||||||
|
%include /usr/share/anaconda/post-scripts/secureboot-enroll-key.ks
|
||||||
|
EOF
|
||||||
|
|
||||||
|
tee /usr/share/anaconda/post-scripts/install-configure-upgrade.ks <<EOF
|
||||||
|
%post --erroronfail
|
||||||
|
bootc switch --mutate-in-place --transport registry $PAYLOAD_IMAGE
|
||||||
|
%end
|
||||||
|
EOF
|
||||||
|
|
||||||
|
tee /usr/share/anaconda/post-scripts/install-flatpaks.ks <<'EOF'
|
||||||
|
%post --erroronfail --nochroot
|
||||||
|
deployment="$(ostree rev-parse --repo=/mnt/sysimage/ostree/repo ostree/0/1/0)"
|
||||||
|
target="/mnt/sysimage/ostree/deploy/default/deploy/$deployment.0/var/lib/"
|
||||||
|
mkdir -p "$target"
|
||||||
|
systemctl stop var-lib-flatpak.mount
|
||||||
|
rsync -aAXUHKP /var/lib/flatpak "$target"
|
||||||
|
sync
|
||||||
|
%end
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Queues the key Aurora's kernel modules are signed with for enrolment in
|
||||||
|
# shim's MOK manager at the next boot (password: universalblue).
|
||||||
|
tee /usr/share/anaconda/post-scripts/secureboot-enroll-key.ks <<'EOF'
|
||||||
|
%post --erroronfail --nochroot
|
||||||
|
set -oue pipefail
|
||||||
|
|
||||||
|
readonly ENROLLMENT_PASSWORD="universalblue"
|
||||||
|
readonly SECUREBOOT_KEY="/etc/pki/akmods/certs/akmods-ublue.der"
|
||||||
|
|
||||||
|
if [[ ! -d "/sys/firmware/efi" ]]; then
|
||||||
|
echo "EFI mode not detected. Skipping key enrollment."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
if [[ ! -f "$SECUREBOOT_KEY" ]]; then
|
||||||
|
echo "Secure boot key not provided: $SECUREBOOT_KEY"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
SYS_ID="$(cat /sys/devices/virtual/dmi/id/product_name)"
|
||||||
|
if [[ ":Jupiter:Galileo:" =~ ":$SYS_ID:" ]]; then
|
||||||
|
echo "Steam Deck hardware detected. Skipping key enrollment."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
mokutil --timeout -1 || :
|
||||||
|
echo -e "$ENROLLMENT_PASSWORD\n$ENROLLMENT_PASSWORD" | mokutil --import "$SECUREBOOT_KEY" || :
|
||||||
|
%end
|
||||||
|
EOF
|
||||||
|
|
||||||
|
ksflatten -c /usr/share/anaconda/interactive-defaults.ks
|
||||||
|
stat /etc/pki/akmods/certs/akmods-ublue.der
|
||||||
|
|
||||||
|
dnf clean all
|
||||||
11
live/iso.yaml
Normal file
11
live/iso.yaml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Titanoboa's ISO config: the volume label and the boot menu.
|
||||||
|
label: "Quine-Linux-Live"
|
||||||
|
grub2:
|
||||||
|
timeout: 10
|
||||||
|
entries:
|
||||||
|
- name: "Quine Linux Live"
|
||||||
|
linux: "/images/pxeboot/vmlinuz quiet rhgb root=live:CDLABEL=Quine-Linux-Live enforcing=0 rd.live.image"
|
||||||
|
initrd: "/images/pxeboot/initrd.img"
|
||||||
|
- name: "Quine Linux Live (Safe Graphics Mode)"
|
||||||
|
linux: "/images/pxeboot/vmlinuz quiet rhgb root=live:CDLABEL=Quine-Linux-Live enforcing=0 rd.live.image nomodeset"
|
||||||
|
initrd: "/images/pxeboot/initrd.img"
|
||||||
98
live/titanoboa-build-iso.sh
Executable file
98
live/titanoboa-build-iso.sh
Executable file
|
|
@ -0,0 +1,98 @@
|
||||||
|
#!/usr/bin/env -S bash -exo pipefail
|
||||||
|
#
|
||||||
|
# From github.com/ublue-os/titanoboa (Apache-2.0), build_iso.sh at 5c457c3,
|
||||||
|
# unchanged: what its main.sh runs in a Fedora container with the live image
|
||||||
|
# mounted at /rootfs and the output directory at /output.
|
||||||
|
|
||||||
|
{ export PS4='+( ${BASH_SOURCE}:${LINENO} ): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'; } 2>/dev/null
|
||||||
|
|
||||||
|
dnf install -y squashfs-tools xorriso yq mtools dosfstools
|
||||||
|
|
||||||
|
mkdir -p \
|
||||||
|
/work \
|
||||||
|
/work/iso-root \
|
||||||
|
/work/iso-root/boot/grub2 \
|
||||||
|
/work/iso-root/images/pxeboot \
|
||||||
|
/work/iso-root/LiveOS
|
||||||
|
cd /work || exit 1
|
||||||
|
|
||||||
|
# Create the squashfs image of the container image
|
||||||
|
mksquashfs /rootfs /work/iso-root/LiveOS/squashfs.img -all-root -noappend -e sysroot -e ostree -comp zstd -Xcompression-level 19
|
||||||
|
|
||||||
|
iso_config_file=/rootfs/usr/lib/bootc-image-builder/iso.yaml
|
||||||
|
if [[ ! -f $iso_config_file ]]; then
|
||||||
|
echo >&2 "ERROR: Missing /usr/lib/bootc-image-builder/iso.yaml file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
iso_label=$(yq '.label' <$iso_config_file)
|
||||||
|
|
||||||
|
# Copy initrd and kernel
|
||||||
|
cp -av /rootfs/usr/lib/modules/*/initramfs.img /work/iso-root/images/pxeboot/initrd.img
|
||||||
|
cp -av /rootfs/usr/lib/modules/*/vmlinuz /work/iso-root/images/pxeboot/vmlinuz
|
||||||
|
|
||||||
|
# Copy GRUB modules
|
||||||
|
for grub_arch in i386-pc arm64-efi; do
|
||||||
|
[ -f "/rootfs/usr/lib/grub/$grub_arch" ] || continue
|
||||||
|
echo >&2 "Found $grub_arch files, copying to /work/iso-root/boot/grub2/$grub_arch ..."
|
||||||
|
cp -avT /rootfs/usr/lib/grub/$grub_arch /work/iso-root/boot/grub2/$grub_arch
|
||||||
|
done
|
||||||
|
|
||||||
|
# Copy efi dir
|
||||||
|
cp -avT /rootfs/boot/efi/EFI /work/EFI
|
||||||
|
|
||||||
|
# Generate grub.cfg
|
||||||
|
{ grub_cfg="$(</dev/stdin)"; } <<EOF
|
||||||
|
set timeout=$(yq '.grub2.timeout // 10' <$iso_config_file)
|
||||||
|
set default="$(yq '.grub2.default // 0' <$iso_config_file)"
|
||||||
|
set menu_auto_hide=false
|
||||||
|
|
||||||
|
function load_video {
|
||||||
|
insmod all_video
|
||||||
|
}
|
||||||
|
|
||||||
|
load_video
|
||||||
|
set gfxpayload=keep
|
||||||
|
insmod gzio
|
||||||
|
insmod part_gpt
|
||||||
|
insmod chain
|
||||||
|
|
||||||
|
search --no-floppy --set=root -l '$iso_label'
|
||||||
|
|
||||||
|
EOF
|
||||||
|
for i in $(yq '.grub2.entries | keys | .[]' <"$iso_config_file"); do
|
||||||
|
entry_name=$(yq ".grub2.entries[$i].name" <"$iso_config_file")
|
||||||
|
entry_linux=$(yq ".grub2.entries[$i].linux" <"$iso_config_file")
|
||||||
|
entry_initrd=$(yq ".grub2.entries[$i].initrd" <"$iso_config_file")
|
||||||
|
{ grub_cfg+=$'\n'"$(</dev/stdin)"; } <<EOF
|
||||||
|
menuentry '$entry_name' {
|
||||||
|
linux $entry_linux
|
||||||
|
initrd $entry_initrd
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
done
|
||||||
|
|
||||||
|
for dir in /work/EFI/* /work/iso-root/boot/grub2; do
|
||||||
|
echo "$grub_cfg" >"$dir/grub.cfg"
|
||||||
|
done
|
||||||
|
|
||||||
|
# For some reason, fedora also copies EFI into /boot/EFI (?), probably because of hardcoded prefix in grub/shim
|
||||||
|
cp -avT /work/EFI /work/iso-root/EFI
|
||||||
|
|
||||||
|
# Generate uefi.img
|
||||||
|
pushd /work || exit 1
|
||||||
|
truncate -s 100M /work/uefi.img
|
||||||
|
mkfs.fat -F32 /work/uefi.img
|
||||||
|
mcopy -v -i /work/uefi.img -s /work/EFI ::
|
||||||
|
xorriso -as mkisofs \
|
||||||
|
-R \
|
||||||
|
-V "$iso_label" \
|
||||||
|
-partition_offset 16 \
|
||||||
|
-appended_part_as_gpt \
|
||||||
|
-append_partition 2 C12A7328-F81F-11D2-BA4B-00A0C93EC93B ./uefi.img \
|
||||||
|
-iso_mbr_part_type EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 \
|
||||||
|
-e --interval:appended_partition_2:all:: \
|
||||||
|
-no-emul-boot \
|
||||||
|
-iso-level 3 \
|
||||||
|
-o "/output/$iso_label.iso" \
|
||||||
|
iso-root
|
||||||
Loading…
Reference in a new issue