From 3f7496d580f185c0974c5edc107570c471d0cdde Mon Sep 17 00:00:00 2001 From: tranch Date: Mon, 28 Sep 2026 11:14:04 +0800 Subject: Align Live and installer ISO commands Use build-live-iso for the Titanoboa Live ISO workflow and build-installer-iso for bootc-image-builder installer ISO images. Rename the associated workflow and build script, and update local run instructions accordingly. --- just_scripts/build-installer-iso.sh | 174 ------------------------------------ just_scripts/build-live-iso.sh | 174 ++++++++++++++++++++++++++++++++++++ just_scripts/run-installer-iso.sh | 2 +- 3 files changed, 175 insertions(+), 175 deletions(-) delete mode 100755 just_scripts/build-installer-iso.sh create mode 100755 just_scripts/build-live-iso.sh (limited to 'just_scripts') diff --git a/just_scripts/build-installer-iso.sh b/just_scripts/build-installer-iso.sh deleted file mode 100755 index 5d40a05..0000000 --- a/just_scripts/build-installer-iso.sh +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -project_root="$(git rev-parse --show-toplevel)" -cd "${project_root}" - -image_name="${IMAGE_NAME:-localhost/$(just image_name)}" -image_tag="${IMAGE_TAG:-$(just generate-default-tag)}" -live_base_image="${LIVE_BASE_IMAGE:-quay.io/fedora/fedora-kinoite:44}" -titanoboa_repository="${TITANOBOA_REPOSITORY:-https://github.com/Zeglius/titanoboa.git}" -titanoboa_revision="${TITANOBOA_REVISION:-7737f4748458252ac827dca14b3d6dd09298472a}" -source_image="${image_name}:${image_tag}" -# Keep the payload in local container storage, but use the public update -# reference as its local tag so Anaconda writes that reference as the boot -# origin instead of persisting the temporary localhost name. OSTREE_IMAGE_REF -# is intentionally tagless, matching the image-info contract. -image_basename="${image_name##*/}" -registry_organization="${REPO_ORGANIZATION:-aerocore-io}" -registry_organization="${registry_organization,,}" -ostree_image_ref="${OSTREE_IMAGE_REF:-ostree-image-signed:docker://ghcr.io/${registry_organization}/${image_basename}}" -ostree_image_ref="${ostree_image_ref,,}" -install_image_ref="${ostree_image_ref#ostree-image-signed:docker://}" -install_image_ref="${install_image_ref#ostree-unverified-registry:docker://}" -install_image_ref="${install_image_ref#docker://}" -payload="${install_image_ref}:${image_tag}" -output_dir="${project_root}/output" -payload_archive="${output_dir}/install-payload.oci" -iso="${output_dir}/aerocore-os-${image_tag}-live-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 ! "${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}" -} - -validate_install_payload() { - # Run on the build host rather than from installer/Containerfile. Nested - # Podman has no /dev/fuse in the build sandbox, while this check needs to - # mount the payload rootfs to inspect the bootupd label source. - "${podman_cmd[@]}" run --rm --network none --entrypoint /usr/bin/bash \ - "${source_image}" -ceu ' - system_release_target=$(readlink -f /etc/system-release) - if od -An -v -tx1 "$system_release_target" | awk '\''{ for (i = 1; i <= NF; i++) if ($i == "00") found = 1 } END { exit(found ? 0 : 1) }'\''; then - echo "Install payload has a NUL byte in ${system_release_target}" >&2 - exit 1 - fi - case "$(<"$system_release_target")" in - "AeroCore OS release $(rpm -E %fedora) ("*) ;; - *) - echo "Unexpected system-release: $(<"$system_release_target")" >&2 - exit 1 - ;; - esac - jq -e '\''.["image-name"] == "aerocore-os" and .["image-vendor"] == "aerocore-io"'\'' \ - /usr/share/ublue-os/image-info.json >/dev/null - ' -} - -mkdir -p "${output_dir}" -ensure_rootful_image -validate_install_payload - -"${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=${live_base_image}" \ - --build-arg "INSTALL_IMAGE_PAYLOAD=${payload}" \ - --build-arg "INSTALL_IMAGE_PAYLOAD_ARCHIVE=/install-payload.oci" \ - --build-arg "INSTALL_IMAGE_TAG=${image_tag}" \ - --build-arg "OSTREE_IMAGE_REF=${ostree_image_ref}" \ - --tag "${payload}" \ - --file installer/Containerfile \ - . - -if [[ "${EUID}" -eq 0 ]]; then - rm -f "${iso}" "${checksum}" -else - sudo rm -f "${iso}" "${checksum}" -fi - -tmp_titanoboa="$(mktemp -d -t aerocore-titanoboa.XXXXXXXXXX)" -trap 'rm -rf "${tmp_titanoboa}"' EXIT - -git clone --quiet --filter=blob:none --no-checkout \ - "${titanoboa_repository}" "${tmp_titanoboa}" -git -C "${tmp_titanoboa}" fetch --quiet origin "${titanoboa_revision}" -git -C "${tmp_titanoboa}" checkout --quiet "${titanoboa_revision}" - -# Keep this invocation aligned with the pinned revision's GitHub Action. -# This revision exposes main.sh rather than a Justfile. -( - cd "${tmp_titanoboa}" - env \ - CI=1 \ - TITANOBOA_CTR_IMAGE="${payload}" \ - TITANOBOA_OUTPUT_DIR="${tmp_titanoboa}/output" \ - "${tmp_titanoboa}/main.sh" -) - -titanoboa_iso="$(find "${tmp_titanoboa}/output" -maxdepth 1 -type f -name '*.iso' -print -quit)" -if [[ ! -f "${titanoboa_iso}" ]]; then - echo "Titanoboa did not produce an ISO in ${tmp_titanoboa}/output" >&2 - exit 1 -fi -if [[ "${EUID}" -eq 0 ]]; then - rm -f "${iso}" "${checksum}" - mv "${titanoboa_iso}" "${iso}" -else - sudo rm -f "${iso}" "${checksum}" - sudo mv "${titanoboa_iso}" "${iso}" -fi - -if [[ -f "${iso}" ]]; then - 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 diff --git a/just_scripts/build-live-iso.sh b/just_scripts/build-live-iso.sh new file mode 100755 index 0000000..5d40a05 --- /dev/null +++ b/just_scripts/build-live-iso.sh @@ -0,0 +1,174 @@ +#!/usr/bin/env bash + +set -euo pipefail + +project_root="$(git rev-parse --show-toplevel)" +cd "${project_root}" + +image_name="${IMAGE_NAME:-localhost/$(just image_name)}" +image_tag="${IMAGE_TAG:-$(just generate-default-tag)}" +live_base_image="${LIVE_BASE_IMAGE:-quay.io/fedora/fedora-kinoite:44}" +titanoboa_repository="${TITANOBOA_REPOSITORY:-https://github.com/Zeglius/titanoboa.git}" +titanoboa_revision="${TITANOBOA_REVISION:-7737f4748458252ac827dca14b3d6dd09298472a}" +source_image="${image_name}:${image_tag}" +# Keep the payload in local container storage, but use the public update +# reference as its local tag so Anaconda writes that reference as the boot +# origin instead of persisting the temporary localhost name. OSTREE_IMAGE_REF +# is intentionally tagless, matching the image-info contract. +image_basename="${image_name##*/}" +registry_organization="${REPO_ORGANIZATION:-aerocore-io}" +registry_organization="${registry_organization,,}" +ostree_image_ref="${OSTREE_IMAGE_REF:-ostree-image-signed:docker://ghcr.io/${registry_organization}/${image_basename}}" +ostree_image_ref="${ostree_image_ref,,}" +install_image_ref="${ostree_image_ref#ostree-image-signed:docker://}" +install_image_ref="${install_image_ref#ostree-unverified-registry:docker://}" +install_image_ref="${install_image_ref#docker://}" +payload="${install_image_ref}:${image_tag}" +output_dir="${project_root}/output" +payload_archive="${output_dir}/install-payload.oci" +iso="${output_dir}/aerocore-os-${image_tag}-live-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 ! "${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}" +} + +validate_install_payload() { + # Run on the build host rather than from installer/Containerfile. Nested + # Podman has no /dev/fuse in the build sandbox, while this check needs to + # mount the payload rootfs to inspect the bootupd label source. + "${podman_cmd[@]}" run --rm --network none --entrypoint /usr/bin/bash \ + "${source_image}" -ceu ' + system_release_target=$(readlink -f /etc/system-release) + if od -An -v -tx1 "$system_release_target" | awk '\''{ for (i = 1; i <= NF; i++) if ($i == "00") found = 1 } END { exit(found ? 0 : 1) }'\''; then + echo "Install payload has a NUL byte in ${system_release_target}" >&2 + exit 1 + fi + case "$(<"$system_release_target")" in + "AeroCore OS release $(rpm -E %fedora) ("*) ;; + *) + echo "Unexpected system-release: $(<"$system_release_target")" >&2 + exit 1 + ;; + esac + jq -e '\''.["image-name"] == "aerocore-os" and .["image-vendor"] == "aerocore-io"'\'' \ + /usr/share/ublue-os/image-info.json >/dev/null + ' +} + +mkdir -p "${output_dir}" +ensure_rootful_image +validate_install_payload + +"${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=${live_base_image}" \ + --build-arg "INSTALL_IMAGE_PAYLOAD=${payload}" \ + --build-arg "INSTALL_IMAGE_PAYLOAD_ARCHIVE=/install-payload.oci" \ + --build-arg "INSTALL_IMAGE_TAG=${image_tag}" \ + --build-arg "OSTREE_IMAGE_REF=${ostree_image_ref}" \ + --tag "${payload}" \ + --file installer/Containerfile \ + . + +if [[ "${EUID}" -eq 0 ]]; then + rm -f "${iso}" "${checksum}" +else + sudo rm -f "${iso}" "${checksum}" +fi + +tmp_titanoboa="$(mktemp -d -t aerocore-titanoboa.XXXXXXXXXX)" +trap 'rm -rf "${tmp_titanoboa}"' EXIT + +git clone --quiet --filter=blob:none --no-checkout \ + "${titanoboa_repository}" "${tmp_titanoboa}" +git -C "${tmp_titanoboa}" fetch --quiet origin "${titanoboa_revision}" +git -C "${tmp_titanoboa}" checkout --quiet "${titanoboa_revision}" + +# Keep this invocation aligned with the pinned revision's GitHub Action. +# This revision exposes main.sh rather than a Justfile. +( + cd "${tmp_titanoboa}" + env \ + CI=1 \ + TITANOBOA_CTR_IMAGE="${payload}" \ + TITANOBOA_OUTPUT_DIR="${tmp_titanoboa}/output" \ + "${tmp_titanoboa}/main.sh" +) + +titanoboa_iso="$(find "${tmp_titanoboa}/output" -maxdepth 1 -type f -name '*.iso' -print -quit)" +if [[ ! -f "${titanoboa_iso}" ]]; then + echo "Titanoboa did not produce an ISO in ${tmp_titanoboa}/output" >&2 + exit 1 +fi +if [[ "${EUID}" -eq 0 ]]; then + rm -f "${iso}" "${checksum}" + mv "${titanoboa_iso}" "${iso}" +else + sudo rm -f "${iso}" "${checksum}" + sudo mv "${titanoboa_iso}" "${iso}" +fi + +if [[ -f "${iso}" ]]; then + 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 diff --git a/just_scripts/run-installer-iso.sh b/just_scripts/run-installer-iso.sh index c495215..dc75c42 100755 --- a/just_scripts/run-installer-iso.sh +++ b/just_scripts/run-installer-iso.sh @@ -9,7 +9,7 @@ image_tag="${IMAGE_TAG:-$(just generate-default-tag)}" iso="${project_root}/output/aerocore-os-${image_tag}-live-amd64.iso" if [[ ! -f "${iso}" ]]; then - just build-installer-iso + just build-live-iso fi podman run --rm --cap-add NET_ADMIN \ -- cgit v1.2.3