summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortranch <tranch.xiao@gmail.com>2026-07-17 06:56:56 +0800
committertranch <tranch.xiao@gmail.com>2026-07-17 08:09:37 +0800
commit4fc0c9bfe42b5d0e543c5ca44c86d25a19f5e1d9 (patch)
tree19217b1e64cf32bdf2cd0d6e5aae2660cd8b0966
parent04e27e0b977826b475b969f19783c1aad300b560 (diff)
downloadAeroCore-OS-4fc0c9bfe42b5d0e543c5ca44c86d25a19f5e1d9.tar.gz
AeroCore-OS-4fc0c9bfe42b5d0e543c5ca44c86d25a19f5e1d9.zip
Fix live installer ISO build
Build the live installer from the requested local AeroCore image, use a separate Fedora live base, pass the payload through rootful container storage, and write reproducible checksum entries without host paths.
-rw-r--r--.github/workflows/build-live-installer.yml17
-rw-r--r--Justfile6
-rw-r--r--disk_config/iso-gnome.toml7
-rw-r--r--disk_config/iso-kde.toml7
-rw-r--r--installer/Containerfile4
-rwxr-xr-xinstaller/build.sh13
-rwxr-xr-xjust_scripts/build-live-installer.sh84
7 files changed, 105 insertions, 33 deletions
diff --git a/.github/workflows/build-live-installer.yml b/.github/workflows/build-live-installer.yml
index 870699e..b5fedb3 100644
--- a/.github/workflows/build-live-installer.yml
+++ b/.github/workflows/build-live-installer.yml
@@ -13,6 +13,7 @@ on:
branches:
- main
paths:
+ - "Justfile"
- "installer/**"
- "just_scripts/build-live-installer.sh"
- ".github/workflows/build-live-installer.yml"
@@ -34,7 +35,7 @@ jobs:
env:
IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
IMAGE_TAG: ${{ inputs.image_tag || 'latest' }}
- BASE_IMAGE: ghcr.io/ublue-os/bazzite:stable
+ LIVE_BASE_IMAGE: quay.io/fedora/fedora-kinoite:43
FEDORA_VERSION: "44"
steps:
@@ -76,11 +77,21 @@ jobs:
- name: Build live installer payload
run: |
+ mkdir -p output
+ sudo podman tag \
+ "${IMAGE_REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}" \
+ localhost/aerocore-live-payload:latest
+ sudo podman save \
+ --format oci-archive \
+ --output output/install-payload.oci \
+ localhost/aerocore-live-payload:latest
+
sudo podman build \
--cap-add sys_admin \
--security-opt label=disable \
- --build-arg "BASE_IMAGE=${BASE_IMAGE}" \
- --build-arg "INSTALL_IMAGE_PAYLOAD=${IMAGE_REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}" \
+ --build-arg "BASE_IMAGE=${LIVE_BASE_IMAGE}" \
+ --build-arg "INSTALL_IMAGE_PAYLOAD=localhost/aerocore-live-payload:latest" \
+ --build-arg "INSTALL_IMAGE_PAYLOAD_ARCHIVE=/install-payload.oci" \
--tag localhost/aerocore-live-payload:latest \
--file installer/Containerfile \
.
diff --git a/Justfile b/Justfile
index 5e73752..b65d2c9 100644
--- a/Justfile
+++ b/Justfile
@@ -9,6 +9,8 @@ export image_logo_url := env_var("IMAGE_LOGO_URL")
export default_tag := env_var("DEFAULT_TAG")
export bib_image := env_var("BIB_IMAGE")
export BASE_IMAGE := env_var_or_default("BASE_IMAGE", "ghcr.io/ublue-os/bazzite-deck:stable")
+export LIVE_BASE_IMAGE := env_var_or_default("LIVE_BASE_IMAGE", "quay.io/fedora/fedora-kinoite:43")
+export INSTALLER_BUILDER_IMAGE := env_var_or_default("INSTALLER_BUILDER_IMAGE", "ghcr.io/jasonn3/build-container-installer:v1.5.0")
export FLATPAK_REMOTE_URL := env_var_or_default("FLATPAK_REMOTE_URL", "")
export HOMEBREW_BOTTLE_DOMAIN := env_var_or_default("HOMEBREW_BOTTLE_DOMAIN", "")
export HOMEBREW_API_DOMAIN := env_var_or_default("HOMEBREW_API_DOMAIN", "")
@@ -28,8 +30,8 @@ default:
@just --list
# Build a Bazzite-style live installer ISO
-build-live-installer:
- @./just_scripts/build-live-installer.sh
+build-live-installer $target_image=("localhost/" + image_name) $tag=default_tag:
+ @IMAGE_NAME="{{ target_image }}" IMAGE_TAG="{{ tag }}" ./just_scripts/build-live-installer.sh
# Boot the live installer ISO with QEMU
run-live-installer:
diff --git a/disk_config/iso-gnome.toml b/disk_config/iso-gnome.toml
index 0fa5652..33cf931 100644
--- a/disk_config/iso-gnome.toml
+++ b/disk_config/iso-gnome.toml
@@ -1,10 +1,3 @@
-[customizations.installer.kickstart]
-contents = """
-%post
-bootc switch --mutate-in-place --transport registry ghcr.io/aerocore-io/aerocore-bazzite-image:latest
-%end
-"""
-
[customizations.installer.modules]
enable = [
"org.fedoraproject.Anaconda.Modules.Storage",
diff --git a/disk_config/iso-kde.toml b/disk_config/iso-kde.toml
index e6e15a0..7f6c80d 100644
--- a/disk_config/iso-kde.toml
+++ b/disk_config/iso-kde.toml
@@ -1,10 +1,3 @@
-[customizations.installer.kickstart]
-contents = """
-%post
-bootc switch --mutate-in-place --transport registry ghcr.io/aerocore-io/aerocore-bazzite-image:latest
-%end
-"""
-
[customizations.installer.modules]
enable = [
"org.fedoraproject.Anaconda.Modules.Storage",
diff --git a/installer/Containerfile b/installer/Containerfile
index fa817b6..50579e6 100644
--- a/installer/Containerfile
+++ b/installer/Containerfile
@@ -3,13 +3,17 @@
ARG BASE_IMAGE=ghcr.io/ublue-os/bazzite:stable
ARG INSTALL_IMAGE_PAYLOAD=ghcr.io/AeroCore-IO/aerocore-bazzite-image:stable
+ARG INSTALL_IMAGE_PAYLOAD_ARCHIVE=/install-payload.oci
FROM ${BASE_IMAGE}
ARG BASE_IMAGE
ARG INSTALL_IMAGE_PAYLOAD
+ARG INSTALL_IMAGE_PAYLOAD_ARCHIVE
RUN --mount=type=bind,source=.,target=/src \
+ --mount=type=bind,source=output/install-payload.oci,target=/install-payload.oci,ro \
env BASE_IMAGE="${BASE_IMAGE}" \
INSTALL_IMAGE_PAYLOAD="${INSTALL_IMAGE_PAYLOAD}" \
+ INSTALL_IMAGE_PAYLOAD_ARCHIVE="${INSTALL_IMAGE_PAYLOAD_ARCHIVE}" \
/src/installer/build.sh
diff --git a/installer/build.sh b/installer/build.sh
index 7532df8..033fe9b 100755
--- a/installer/build.sh
+++ b/installer/build.sh
@@ -5,10 +5,14 @@ set -euxo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BASE_IMAGE=${BASE_IMAGE:?}
INSTALL_IMAGE_PAYLOAD=${INSTALL_IMAGE_PAYLOAD:?}
+INSTALL_IMAGE_PAYLOAD_ARCHIVE=${INSTALL_IMAGE_PAYLOAD_ARCHIVE:-}
# The installer is a live KDE environment. Keep the installed system payload
# separate: it is the AeroCore image, while BASE_IMAGE provides the live UI.
-dnf install -y \
+# Bazzite excludes some base packages from normal transactions. The live
+# installer needs Anaconda's exact NetworkManager dependencies, so clear the
+# excludes only for this dependency install.
+dnf --setopt=excludepkgs= install -y \
anaconda-live \
libblockdev-btrfs \
libblockdev-dm \
@@ -22,9 +26,10 @@ if [[ -d /src/system_files ]]; then
cp -a /src/system_files/. /
fi
-# Make the install payload available to Anaconda. When the build is running
-# with the host container store mounted, this avoids a second registry pull.
-if mountpoint -q /usr/lib/containers/storage; then
+# Make the install payload available to Anaconda.
+if [[ -n "${INSTALL_IMAGE_PAYLOAD_ARCHIVE}" && -f "${INSTALL_IMAGE_PAYLOAD_ARCHIVE}" ]]; then
+ podman load --storage-opt additionalimagestore='' < "${INSTALL_IMAGE_PAYLOAD_ARCHIVE}"
+elif mountpoint -q /usr/lib/containers/storage; then
podman save --format oci-archive "${INSTALL_IMAGE_PAYLOAD}" | \
podman load --storage-opt additionalimagestore=''
else
diff --git a/just_scripts/build-live-installer.sh b/just_scripts/build-live-installer.sh
index 16b371e..45335cb 100755
--- a/just_scripts/build-live-installer.sh
+++ b/just_scripts/build-live-installer.sh
@@ -5,41 +5,98 @@ set -euo pipefail
project_root="$(git rev-parse --show-toplevel)"
cd "${project_root}"
-image_name="${IMAGE_NAME:-$(just image_name)}"
+image_name="${IMAGE_NAME:-localhost/$(just image_name)}"
image_tag="${IMAGE_TAG:-$(just generate-default-tag)}"
-base_image="${BASE_IMAGE:-ghcr.io/ublue-os/bazzite:stable}"
-payload="localhost/${image_name}:live-payload"
+live_base_image="${LIVE_BASE_IMAGE:-quay.io/fedora/fedora-kinoite:43}"
+installer_builder_image="${INSTALLER_BUILDER_IMAGE:-ghcr.io/jasonn3/build-container-installer:v1.5.0}"
+source_image="${image_name}:${image_tag}"
+payload="localhost/aerocore-live-payload:latest"
output_dir="${project_root}/output"
+payload_archive="${output_dir}/install-payload.oci"
+iso="${output_dir}/aerocore-os-${image_tag}-amd64.iso"
+checksum="${iso}-CHECKSUM"
api_socket="${PODMAN_SOCKET:-/run/podman/podman.sock}"
if [[ "${EUID}" -eq 0 ]]; then
podman_cmd=(podman)
+ socket_test=(test -S "${api_socket}")
else
podman_cmd=(sudo podman)
+ socket_test=(sudo test -S "${api_socket}")
fi
-if [[ ! -S "${api_socket}" ]]; then
+if ! "${socket_test[@]}"; then
echo "Podman API socket not found: ${api_socket}" >&2
echo "Set PODMAN_SOCKET to the rootful Podman socket and retry." >&2
exit 1
fi
+ensure_rootful_image() {
+ local root_image_id user_image_id user_name user_uid copy_tmp
+
+ root_image_id="$("${podman_cmd[@]}" images \
+ --filter "reference=${source_image}" \
+ --format "{{.ID}}" | head -n1)"
+
+ if [[ -n "${root_image_id}" ]]; then
+ return 0
+ fi
+
+ if [[ "${EUID}" -ne 0 ]]; then
+ just _rootful_load_image "${image_name}" "${image_tag}"
+ return
+ fi
+
+ if [[ -z "${SUDO_USER:-}" ]]; then
+ return
+ fi
+
+ user_name="${SUDO_USER}"
+ user_uid="$(id -u "${user_name}")"
+ user_image_id="$(sudo -u "${user_name}" \
+ env XDG_RUNTIME_DIR="/run/user/${user_uid}" \
+ podman images \
+ --filter "reference=${source_image}" \
+ --format "{{.ID}}" | head -n1)"
+
+ if [[ -z "${user_image_id}" ]]; then
+ return
+ fi
+
+ copy_tmp="$(mktemp -p "${project_root}" -d -t _build_podman_scp.XXXXXXXXXX)"
+ TMPDIR="${copy_tmp}" podman image scp \
+ "${user_uid}@localhost::${source_image}" \
+ "root@localhost::${source_image}"
+ rm -rf "${copy_tmp}"
+}
+
mkdir -p "${output_dir}"
-"${podman_cmd[@]}" tag "${image_name}:${image_tag}" "${payload}"
+ensure_rootful_image
+
+"${podman_cmd[@]}" tag "${source_image}" "${payload}"
+"${podman_cmd[@]}" save --format oci-archive --output "${payload_archive}" "${payload}"
"${podman_cmd[@]}" build \
--cap-add sys_admin \
--security-opt label=disable \
- --build-arg "BASE_IMAGE=${base_image}" \
+ --build-arg "BASE_IMAGE=${live_base_image}" \
--build-arg "INSTALL_IMAGE_PAYLOAD=${payload}" \
- --tag localhost/aerocore-live-payload:latest \
+ --build-arg "INSTALL_IMAGE_PAYLOAD_ARCHIVE=/install-payload.oci" \
+ --tag "${payload}" \
--file installer/Containerfile \
.
+if [[ "${EUID}" -eq 0 ]]; then
+ rm -f "${iso}" "${checksum}"
+else
+ sudo rm -f "${iso}" "${checksum}"
+fi
+
"${podman_cmd[@]}" run --rm --privileged \
--volume "${api_socket}:/var/run/docker.sock" \
+ --volume /var/lib/containers/storage:/var/lib/containers/storage \
--volume "${project_root}/output:/build-container-installer/build" \
--volume "${project_root}/installer/lorax_templates:/additional_lorax_templates:ro" \
- docker.io/jasonn3/build-container-installer:latest \
+ "${installer_builder_image}" \
ADDITIONAL_TEMPLATES="/additional_lorax_templates/remove_root_password_prompt.tmpl /additional_lorax_templates/set_default_user.tmpl" \
ARCH="x86_64" \
ENABLE_CACHE_DNF="false" \
@@ -47,12 +104,19 @@ mkdir -p "${output_dir}"
ENABLE_FLATPAK_DEPENDENCIES="false" \
IMAGE_NAME="aerocore-live-payload" \
IMAGE_REPO="localhost" \
+ IMAGE_SRC="containers-storage:${payload}" \
IMAGE_TAG="latest" \
ISO_NAME="build/aerocore-os-${image_tag}-amd64.iso" \
VARIANT="Kinoite" \
VERSION="${FEDORA_VERSION:-44}"
-iso="${output_dir}/aerocore-os-${image_tag}-amd64.iso"
if [[ -f "${iso}" ]]; then
- sha256sum "${iso}" | tee "${iso}-CHECKSUM"
+ if [[ "${EUID}" -ne 0 ]]; then
+ sudo chown "$(id -u):$(id -g)" "${iso}"
+ sudo rm -f "${checksum}"
+ (cd "${output_dir}" && sha256sum "$(basename "${iso}")") | sudo tee "${checksum}"
+ sudo chown "$(id -u):$(id -g)" "${checksum}"
+ else
+ (cd "${output_dir}" && sha256sum "$(basename "${iso}")") | tee "${checksum}"
+ fi
fi