From 835eb7aa4a5e6d387a8c3e44c9995d32c42b37fb Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 17 Sep 2026 07:54:56 -0400 Subject: [PATCH 1/2] bootc-host-setup: Add distro-aware host action Provide the shared prerequisite for moving bootc CI to stock RHEL 10 while retaining the Ubuntu runner behavior already relied upon by callers. Keep the old entry point as a deprecated compatibility layer so downstream callers can migrate independently. Assisted-by: AI --- .github/actionlint.yaml | 4 + .github/workflows/test-actions-pr.yml | 48 +++- .github/workflows/test-actions-published.yml | 16 +- bootc-host-setup/AGENTS.md | 5 + bootc-host-setup/action.yml | 25 ++ bootc-host-setup/ci/install-deps.sh | 122 ++++++++ bootc-host-setup/ci/test-environment.sh | 26 ++ bootc-host-setup/ci/workarounds.sh | 106 +++++++ bootc-host-setup/packages/rhel-base | 8 + bootc-host-setup/packages/rhel-libvirt | 14 + bootc-host-setup/packages/ubuntu-24.04-base | 5 + .../packages/ubuntu-26.04-libvirt | 2 + bootc-host-setup/packages/ubuntu-base | 2 + bootc-host-setup/packages/ubuntu-libvirt | 8 + bootc-ubuntu-setup/action.yml | 272 +----------------- test/bootc-host-setup.sh | 50 ++++ 16 files changed, 437 insertions(+), 276 deletions(-) create mode 100644 .github/actionlint.yaml create mode 100644 bootc-host-setup/AGENTS.md create mode 100644 bootc-host-setup/action.yml create mode 100644 bootc-host-setup/ci/install-deps.sh create mode 100644 bootc-host-setup/ci/test-environment.sh create mode 100644 bootc-host-setup/ci/workarounds.sh create mode 100644 bootc-host-setup/packages/rhel-base create mode 100644 bootc-host-setup/packages/rhel-libvirt create mode 100644 bootc-host-setup/packages/ubuntu-24.04-base create mode 100644 bootc-host-setup/packages/ubuntu-26.04-libvirt create mode 100644 bootc-host-setup/packages/ubuntu-base create mode 100644 bootc-host-setup/packages/ubuntu-libvirt create mode 100644 test/bootc-host-setup.sh diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml new file mode 100644 index 0000000..fd63735 --- /dev/null +++ b/.github/actionlint.yaml @@ -0,0 +1,4 @@ +self-hosted-runner: + labels: + - rhel10-x86_64-16c-64g + - ubuntu-26.04 diff --git a/.github/workflows/test-actions-pr.yml b/.github/workflows/test-actions-pr.yml index 0d889f9..60916fa 100644 --- a/.github/workflows/test-actions-pr.yml +++ b/.github/workflows/test-actions-pr.yml @@ -8,15 +8,15 @@ permissions: contents: read jobs: - test-bootc-ubuntu-setup: - name: Test bootc-ubuntu-setup + test-bootc-host-setup: + name: Test bootc-host-setup runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@v7 - - name: Run bootc-ubuntu-setup - uses: ./bootc-ubuntu-setup + - name: Run bootc-host-setup + uses: ./bootc-host-setup - name: Verify setup run: | @@ -26,15 +26,15 @@ jobs: - name: Verify basic requirements uses: ./.github/actions/verify-basic-requirements - test-bootc-ubuntu-setup-2604: - name: Test bootc-ubuntu-setup (26.04) + test-bootc-host-setup-2604: + name: Test bootc-host-setup (26.04) runs-on: ubuntu-26.04 steps: - name: Checkout uses: actions/checkout@v7 - - name: Run bootc-ubuntu-setup - uses: ./bootc-ubuntu-setup + - name: Run bootc-host-setup + uses: ./bootc-host-setup - name: Verify setup run: | @@ -78,6 +78,34 @@ jobs: test "$(stat -c %u:%g /bwrap-tmp/child)" = 1:1 ' CONTAINER + + test-bootc-ubuntu-setup-compatibility: + name: Test bootc-ubuntu-setup compatibility entry point + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v7 + - uses: ./bootc-ubuntu-setup + - run: test -n "$ARCH" + + test-bootc-host-setup-rhel10: + name: Test bootc-host-setup (RHEL 10) + runs-on: rhel10-x86_64-16c-64g + steps: + - uses: actions/checkout@v7 + - uses: ./bootc-host-setup + with: + libvirt: 'true' + - run: | + rustc --version + cargo --version + test "$(getenforce)" = Enforcing + + test-bootc-host-setup-scripts: + name: Test bootc-host-setup scripts + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v7 + - run: bash test/bootc-host-setup.sh test-setup-rust: name: Test setup-rust runs-on: ubuntu-latest @@ -117,7 +145,7 @@ jobs: uses: actions/checkout@v7 - name: Setup host - uses: ./bootc-ubuntu-setup + uses: ./bootc-host-setup - name: Create test Containerfile shell: bash @@ -156,7 +184,7 @@ jobs: uses: actions/checkout@v7 - name: Setup host - uses: ./bootc-ubuntu-setup + uses: ./bootc-host-setup - name: Build image manually shell: bash diff --git a/.github/workflows/test-actions-published.yml b/.github/workflows/test-actions-published.yml index ff5c28c..18989a4 100644 --- a/.github/workflows/test-actions-published.yml +++ b/.github/workflows/test-actions-published.yml @@ -8,12 +8,12 @@ permissions: contents: read jobs: - test-bootc-ubuntu-setup: - name: Test bootc-ubuntu-setup@main + test-bootc-host-setup: + name: Test bootc-host-setup@main runs-on: ubuntu-24.04 steps: - - name: Run bootc-ubuntu-setup - uses: bootc-dev/actions/bootc-ubuntu-setup@main + - name: Run bootc-host-setup + uses: bootc-dev/actions/bootc-host-setup@main - name: Verify setup run: | @@ -23,12 +23,12 @@ jobs: - name: Verify basic requirements uses: bootc-dev/actions/.github/actions/verify-basic-requirements@main - test-bootc-ubuntu-setup-2604: - name: Test bootc-ubuntu-setup@main (26.04) + test-bootc-host-setup-2604: + name: Test bootc-host-setup@main (26.04) runs-on: ubuntu-26.04 steps: - - name: Run bootc-ubuntu-setup - uses: bootc-dev/actions/bootc-ubuntu-setup@main + - name: Run bootc-host-setup + uses: bootc-dev/actions/bootc-host-setup@main - name: Verify setup run: | diff --git a/bootc-host-setup/AGENTS.md b/bootc-host-setup/AGENTS.md new file mode 100644 index 0000000..89788df --- /dev/null +++ b/bootc-host-setup/AGENTS.md @@ -0,0 +1,5 @@ +# Dependencies + +Downloaded or versioned dependencies in this action must be managed by +Renovate. Do not leave a dependency forever-pinned: add a Renovate annotation +and update any paired checksum in the same change. diff --git a/bootc-host-setup/action.yml b/bootc-host-setup/action.yml new file mode 100644 index 0000000..65fefbd --- /dev/null +++ b/bootc-host-setup/action.yml @@ -0,0 +1,25 @@ +name: 'Bootc Host Setup' +description: 'Set up a supported GitHub-hosted bootc build host' +inputs: + libvirt: + description: 'Install libvirt and virtualization stack' + required: false + default: 'false' +runs: + using: 'composite' + steps: + - name: Install host dependencies + shell: bash + env: + BOOTC_HOST_LIBVIRT: ${{ inputs.libvirt }} + run: bash "${GITHUB_ACTION_PATH}/ci/install-deps.sh" + - name: Apply host workarounds + shell: bash + env: + BOOTC_HOST_LIBVIRT: ${{ inputs.libvirt }} + run: bash "${GITHUB_ACTION_PATH}/ci/workarounds.sh" + - name: Test host environment + shell: bash + env: + BOOTC_HOST_LIBVIRT: ${{ inputs.libvirt }} + run: bash "${GITHUB_ACTION_PATH}/ci/test-environment.sh" diff --git a/bootc-host-setup/ci/install-deps.sh b/bootc-host-setup/ci/install-deps.sh new file mode 100644 index 0000000..d57bfc8 --- /dev/null +++ b/bootc-host-setup/ci/install-deps.sh @@ -0,0 +1,122 @@ +#!/usr/bin/env bash +# shellcheck shell=bash +set -euo pipefail + +action_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +packages_dir="${action_dir}/packages" +libvirt=${BOOTC_HOST_LIBVIRT:-false} + +read_packages() { + local file=$1 line + while IFS= read -r line || [ -n "$line" ]; do + line=${line%%#*} + [ -n "$line" ] && packages+=("$line") + done < "$file" +} + +load_os_release() { + # shellcheck disable=SC1091 + . /etc/os-release + case "${ID}:${VERSION_ID}" in + ubuntu:24.04|ubuntu:26.04|rhel:10|rhel:10.*) ;; + *) printf 'Unsupported host: ID=%s VERSION_ID=%s\n' "$ID" "$VERSION_ID" >&2; exit 1 ;; + esac +} + +free_ubuntu_disk() { + local package dir n=0 + local -a unwanted_packages=(aspnetcore-* dotnet-* llvm-* php* mongodb-* mysql-* azure-cli google-chrome-stable firefox mono-devel) + local -a unwanted_dirs=(/usr/share/dotnet /opt/ghc /usr/local/lib/android /opt/hostedtoolcache/CodeQL) + sudo df -h + run_cleanup() { sudo systemd-run -r -u "action-cleanup-${n}" -- "$@"; n=$((n + 1)); } + run_cleanup docker image prune --all --force + for dir in "${unwanted_dirs[@]}"; do run_cleanup rm -rf "$dir"; done + for package in "${unwanted_packages[@]}"; do + if dpkg -l "$package" >/dev/null 2>&1; then + /bin/time -f '%E %C' sudo apt-get remove -y "$package" + fi + done +} + +ubuntu_mirror() { + if [ "$(dpkg --print-architecture)" = amd64 ]; then + [ -f /etc/apt/apt-mirrors.txt ] && printf '%s' 'mirror+file:/etc/apt/apt-mirrors.txt' || printf '%s' 'http://archive.ubuntu.com/ubuntu' + else + printf '%s' 'http://ports.ubuntu.com/ubuntu-ports' + fi +} + +install_bcvk() { + [ "$libvirt" = true ] && [ "$(uname -m)" = x86_64 ] || return 0 + # renovate: datasource=github-releases depName=bootc-dev/bcvk + local bcvk_version=0.19.0 target tmpdir + target="bcvk-$(uname -m)-unknown-linux-gnu" + tmpdir=$(mktemp -d) + curl --fail --show-error --location --retry 5 --retry-delay 10 --retry-max-time 300 --output "${tmpdir}/${target}.tar.gz" "https://github.com/bootc-dev/bcvk/releases/download/v${bcvk_version}/${target}.tar.gz" + tar -xzf "${tmpdir}/${target}.tar.gz" -C "$tmpdir" + sudo install -m 0755 "${tmpdir}/${target}" /usr/local/bin/bcvk + rm -rf "$tmpdir" + if [ "$ID" = ubuntu ]; then + sudo sed -i -e 's,^\* hard nofile 65536,* hard nofile 524288,' /etc/security/limits.conf + fi + printf 'LIBVIRT_DEFAULT_URI=qemu:///session\n' >> "$GITHUB_ENV" +} + +install_ubuntu() { + local -a packages=() + free_ubuntu_disk + if [ "$VERSION_ID" = 24.04 ]; then + printf 'deb %s plucky universe main\n' "$(ubuntu_mirror)" | sudo tee /etc/apt/sources.list.d/plucky.list >/dev/null + printf '%s\n' 'Acquire::Retries "5";' | sudo tee /etc/apt/apt.conf.d/80-retries >/dev/null + fi + read_packages "${packages_dir}/ubuntu-base" + /bin/time -f '%E %C' sudo apt-get update + /bin/time -f '%E %C' sudo apt-get install -y "${packages[@]}" + if [ "$VERSION_ID" = 24.04 ]; then + packages=() + read_packages "${packages_dir}/ubuntu-24.04-base" + /bin/time -f '%E %C' sudo apt-get install -y --allow-downgrades "${packages[@]/%//plucky}" + fi + if [ "$libvirt" = true ]; then + packages=() + read_packages "${packages_dir}/ubuntu-libvirt" + if [ "$VERSION_ID" = 26.04 ]; then + read_packages "${packages_dir}/ubuntu-26.04-libvirt" + packages+=(ovmf-amdsev-) + fi + /bin/time -f '%E %C' sudo apt-get install -y "${packages[@]}" + fi +} + +install_rhel_just() { + if sudo dnf install -y just; then return; fi + # TODO: Remove this fallback once the stock partner image reliably exposes a current EPEL just package. + # renovate: datasource=github-releases depName=casey/just + local just_version=1.58.0 just_sha256=4a5cc2f53e6f0f8c59092a6cc38291eb729d46a7dd95d3ae582008881b84931d tmpdir + tmpdir=$(mktemp -d) + curl --fail --show-error --location --retry 5 --output "${tmpdir}/just.tar.gz" "https://github.com/casey/just/releases/download/${just_version}/just-${just_version}-x86_64-unknown-linux-musl.tar.gz" + printf '%s %s\n' "$just_sha256" "${tmpdir}/just.tar.gz" | sha256sum --check + tar -xzf "${tmpdir}/just.tar.gz" -C "$tmpdir" just + sudo install -m 0755 "${tmpdir}/just" /usr/local/bin/just + rm -rf "$tmpdir" +} + +install_rhel() { + local -a packages=() + read_packages "${packages_dir}/rhel-base" + [ "$libvirt" = true ] && read_packages "${packages_dir}/rhel-libvirt" + sudo dnf install -y "${packages[@]}" + install_rhel_just +} + +main() { + load_os_release + case "$ID" in + ubuntu) install_ubuntu ;; + rhel) install_rhel ;; + esac + install_bcvk + printf 'ARCH=%s\n' "$(arch)" >> "$GITHUB_ENV" +} + +if [ "${BASH_SOURCE[0]}" = "$0" ]; then main "$@"; fi diff --git a/bootc-host-setup/ci/test-environment.sh b/bootc-host-setup/ci/test-environment.sh new file mode 100644 index 0000000..1b81f20 --- /dev/null +++ b/bootc-host-setup/ci/test-environment.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail + +libvirt=${BOOTC_HOST_LIBVIRT:-false} +# shellcheck disable=SC1091 +. /etc/os-release +case "$ID" in ubuntu|rhel) ;; *) exit 1 ;; esac +podman --version +just --version +test -n "${GITHUB_ENV:-}" + +if [ "$libvirt" = true ]; then + test -x "$(command -v virsh)" + test -x "$(command -v virt-fw-vars)" + virtiofsd=$(command -v virtiofsd || true) + test -x "${virtiofsd:-/usr/lib/qemu/virtiofsd}" + if [ "$ID" = rhel ]; then + test "$(getenforce)" = Enforcing + test -r /dev/kvm && test -w /dev/kvm + test -x /usr/sbin/virtstoraged + qemu_config="${XDG_CONFIG_HOME:-$HOME/.config}/libvirt/qemu.conf" + printf '%s\n' 'security_driver = "none"' | cmp --silent - "$qemu_config" + dbus-run-session -- virsh -c qemu:///session list --all + dbus-run-session -- virsh -c qemu:///session pool-list --all + fi +fi diff --git a/bootc-host-setup/ci/workarounds.sh b/bootc-host-setup/ci/workarounds.sh new file mode 100644 index 0000000..c394c5d --- /dev/null +++ b/bootc-host-setup/ci/workarounds.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash +# shellcheck shell=bash +set -euo pipefail + +libvirt=${BOOTC_HOST_LIBVIRT:-false} +# shellcheck disable=SC1091 +. /etc/os-release + +setup_ubuntu_kvm() { + [ "$libvirt" = true ] && [ -c /dev/kvm ] || return 0 + printf '%s\n' 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules >/dev/null + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm +} + +setup_ubuntu_apparmor() { + if sudo test -r /etc/apparmor.d/bwrap-userns-restrict && sudo test -r /sys/kernel/security/apparmor/profiles && sudo grep -qx 'bwrap (enforce)' /sys/kernel/security/apparmor/profiles; then + sudo tee /etc/apparmor.d/local/bwrap-userns-restrict >/dev/null <<'EOF' +priority=100 allow file rwlkm /**, +priority=100 allow ix /**, +EOF + sudo apparmor_parser -Q /etc/apparmor.d/bwrap-userns-restrict + sudo apparmor_parser -r /etc/apparmor.d/bwrap-userns-restrict + fi +} + +setup_ubuntu_qemu() { + [ "$libvirt" = true ] && [ "$VERSION_ID" = 24.04 ] || return 0 + local architecture mirror qemu_package qemu_binary + architecture=$(dpkg --print-architecture) + case "$architecture" in + amd64) qemu_package=qemu-system-x86 ;; + arm64) qemu_package=qemu-system-arm ;; + *) printf 'Unsupported architecture for Resolute QEMU: %s\n' "$architecture" >&2; return 1 ;; + esac + qemu_binary="qemu-system-$(uname -m)" + printf '%s\n' 'Package: *' 'Pin: release n=resolute' 'Pin-Priority: 50' | sudo tee /etc/apt/preferences.d/resolute-qemu >/dev/null + if [ "$architecture" = amd64 ]; then + [ -f /etc/apt/apt-mirrors.txt ] && mirror='mirror+file:/etc/apt/apt-mirrors.txt' || mirror='http://archive.ubuntu.com/ubuntu' + else + mirror='http://ports.ubuntu.com/ubuntu-ports' + fi + printf 'deb %s resolute main universe\n' "$mirror" | sudo tee /etc/apt/sources.list.d/resolute-qemu.list >/dev/null + timeout --foreground --signal=TERM --kill-after=30s 5m sudo apt-get update + timeout --foreground --signal=TERM --kill-after=30s 5m sudo apt-get -t resolute install -y --no-install-recommends "$qemu_package" qemu-system-common qemu-system-data qemu-utils ipxe-qemu + "$qemu_binary" --version +} + +repair_rhel_openssh_policy() { + local policy=/etc/crypto-policies/back-ends/openssh.config + local expected_target=/usr/share/crypto-policies/DEFAULT/openssh.txt target diagnostic expected_diagnostic + expected_diagnostic="Bad owner or permissions on ${policy}" + diagnostic=$(mktemp) + if ssh -G localhost >/dev/null 2>"$diagnostic"; then + printf '%s\n' 'OpenSSH crypto policy is already valid; skipping partner-image repair.' + rm -f "$diagnostic" + return + fi + # The partner image's OpenSSH emits CRLF here. Normalize only line endings + # before retaining an exact match for the known broken-policy diagnostic. + if ! tr -d '\r' < "$diagnostic" | grep -Fqx "$expected_diagnostic"; then + printf '%s\n' 'Unexpected ssh -G failure; refusing to mask it:' >&2 + cat "$diagnostic" >&2 + rm -f "$diagnostic" + return 1 + fi + target=$(sudo readlink -e -- "$policy") + test "$target" = "$expected_target" + test "$(sudo rpm -qf --qf '%{NAME}' "$target")" = crypto-policies + sudo chown root:root -- "$target" + sudo chmod 0644 -- "$target" + sudo restorecon -- "$target" + test "$(sudo stat -c '%u:%g:%a' -- "$target")" = 0:0:644 + ssh -G localhost >/dev/null + rm -f "$diagnostic" +} + +setup_rhel_libvirt() { + [ "$libvirt" = true ] || return 0 + repair_rhel_openssh_policy + [ -c /dev/kvm ] && sudo setfacl -m "u:$(id -un):rw" /dev/kvm + local config_dir="${XDG_CONFIG_HOME:-$HOME/.config}/libvirt" + mkdir -p "$config_dir" + # On the RHEL hosted runner, sVirt labeling conflicts with the readonly + # virtiofs export of rootless Podman storage. This only disables per-domain + # sVirt for this ephemeral, unprivileged libvirt session; the host SELinux + # policy remains enforcing. + cat > "$config_dir/qemu.conf" <<'EOF' +security_driver = "none" +EOF + local virtiofsd + virtiofsd=$(rpm -ql virtiofsd | { grep '/virtiofsd$' || :; } | head -n 1) + test -n "$virtiofsd" + sudo ln -sfn "$virtiofsd" /usr/local/bin/virtiofsd + for firmware in /usr/share/qemu/firmware/*amdsev*.json; do + [ -e "$firmware" ] || continue + sudo mv "$firmware" "${firmware}.disabled" + done + printf 'LIBVIRT_DEFAULT_URI=qemu:///session\n' >> "$GITHUB_ENV" +} + +case "$ID" in + ubuntu) setup_ubuntu_kvm; setup_ubuntu_qemu; setup_ubuntu_apparmor ;; + rhel) setup_rhel_libvirt ;; + *) printf 'Unsupported host ID: %s\n' "$ID" >&2; exit 1 ;; +esac diff --git a/bootc-host-setup/packages/rhel-base b/bootc-host-setup/packages/rhel-base new file mode 100644 index 0000000..5db6128 --- /dev/null +++ b/bootc-host-setup/packages/rhel-base @@ -0,0 +1,8 @@ +git-core +podman +curl +tar +gzip +gcc +rust +cargo diff --git a/bootc-host-setup/packages/rhel-libvirt b/bootc-host-setup/packages/rhel-libvirt new file mode 100644 index 0000000..3e55820 --- /dev/null +++ b/bootc-host-setup/packages/rhel-libvirt @@ -0,0 +1,14 @@ +libvirt-client +libvirt-daemon +libvirt-devel +libvirt-daemon-driver-qemu +libvirt-daemon-driver-storage-core +qemu-kvm-core +qemu-img +edk2-ovmf +virtiofsd +dbus-daemon +acl +swtpm +swtpm-tools +python3-virt-firmware diff --git a/bootc-host-setup/packages/ubuntu-24.04-base b/bootc-host-setup/packages/ubuntu-24.04-base new file mode 100644 index 0000000..d3b14c2 --- /dev/null +++ b/bootc-host-setup/packages/ubuntu-24.04-base @@ -0,0 +1,5 @@ +# Ubuntu 24.04 takes these from the temporary Plucky source. +crun +buildah +podman +skopeo diff --git a/bootc-host-setup/packages/ubuntu-26.04-libvirt b/bootc-host-setup/packages/ubuntu-26.04-libvirt new file mode 100644 index 0000000..653e0fc --- /dev/null +++ b/bootc-host-setup/packages/ubuntu-26.04-libvirt @@ -0,0 +1,2 @@ +# Generic OVMF is needed for bcvk's insecure UEFI mode. +ovmf-generic diff --git a/bootc-host-setup/packages/ubuntu-base b/bootc-host-setup/packages/ubuntu-base new file mode 100644 index 0000000..53554ad --- /dev/null +++ b/bootc-host-setup/packages/ubuntu-base @@ -0,0 +1,2 @@ +# Packages which are installed on every supported Ubuntu host. +just diff --git a/bootc-host-setup/packages/ubuntu-libvirt b/bootc-host-setup/packages/ubuntu-libvirt new file mode 100644 index 0000000..e460842 --- /dev/null +++ b/bootc-host-setup/packages/ubuntu-libvirt @@ -0,0 +1,8 @@ +libkrb5-dev +pkg-config +libvirt-dev +genisoimage +qemu-utils +virtiofsd +libvirt-daemon-system +python3-virt-firmware diff --git a/bootc-ubuntu-setup/action.yml b/bootc-ubuntu-setup/action.yml index 044351c..9e446c8 100644 --- a/bootc-ubuntu-setup/action.yml +++ b/bootc-ubuntu-setup/action.yml @@ -1,5 +1,5 @@ -name: 'Bootc Ubuntu Setup' -description: 'Default host setup' +name: 'Bootc Ubuntu Setup (deprecated)' +description: 'Deprecated compatibility entry point; use bootc-host-setup' inputs: libvirt: description: 'Install libvirt and virtualization stack' @@ -8,262 +8,18 @@ inputs: runs: using: 'composite' steps: - # The default runners have TONS of crud on them... - - name: Free up disk space on runner + - name: Install host dependencies shell: bash - run: | - set -xeuo pipefail - sudo df -h - # Use globs for package patterns (apt and dpkg both support fnmatch globs) - unwanted_pkgs=('aspnetcore-*' 'dotnet-*' 'llvm-*' 'php*' 'mongodb-*' 'mysql-*' - azure-cli google-chrome-stable firefox mono-devel) - unwanted_dirs=(/usr/share/dotnet /opt/ghc /usr/local/lib/android /opt/hostedtoolcache/CodeQL) - # Start background removal operations as systemd units; if this causes - # races in the future around disk space we can look at waiting for cleanup - # before starting further jobs, but right now we spent a lot of time waiting - # on the network and scripts and such below, giving these plenty of time to run. - n=0 - runcleanup() { - sudo systemd-run -r -u action-cleanup-${n} -- "$@" - n=$(($n + 1)) - } - runcleanup docker image prune --all --force - for x in ${unwanted_dirs[@]}; do - runcleanup rm -rf "$x" - done - # Apt removals in foreground, as we can't parallelize these. - # Only attempt removal if matching packages are installed. - for x in ${unwanted_pkgs[@]}; do - if dpkg -l "$x" >/dev/null 2>&1; then - /bin/time -f '%E %C' sudo apt-get remove -y "$x" - fi - done - # We really want support for heredocs - - name: Install required packages + env: + BOOTC_HOST_LIBVIRT: ${{ inputs.libvirt }} + run: bash "${GITHUB_ACTION_PATH}/../bootc-host-setup/ci/install-deps.sh" + - name: Apply host workarounds shell: bash - run: | - set -eux - IDV=$(. /usr/lib/os-release && echo ${ID}-${VERSION_ID}) - case "${IDV}" in - ubuntu-24.04) - # 24.04's podman is too old (no heredoc support, manifest bugs); - # pull newer packages from plucky (25.04). - # plucky is the next release. Historically we pointed straight at - # azure.archive.ubuntu.com, but that single Azure-regional mirror suffers - # chronic connection timeouts on GitHub Actions runners. This is a - # widespread, long-standing issue, not specific to us: - # https://github.com/actions/runner-images/issues/7048 - # https://github.com/actions/runner-images/issues/12949 - # https://github.com/orgs/community/discussions/205332 - # A plain http(s) URL is a single endpoint as far as apt is concerned: if - # it's unreachable, apt just retries the *same* host rather than trying an - # alternative (only the mirror:/mirror+file: URI scheme gives apt genuine - # client-side fallback across multiple mirrors, per sources.list(5)). So - # reuse the mirrorlist-with-fallback that Ubuntu's own cloud-init already - # sets up for the base OS sources on these runners (Azure mirror first, - # falling back to the global archive), instead of hardcoding one host with - # no fallback at all. Fall back to the plain global archive if that - # mirrorlist isn't present, e.g. on a non-standard runner. - # Non-amd64 architectures (e.g. arm64) use ports.ubuntu.com/ubuntu-ports, - # which isn't affected by this since it has no azure-specific variant. - if [ "$(dpkg --print-architecture)" = "amd64" ]; then - if [ -f /etc/apt/apt-mirrors.txt ]; then - mirror="mirror+file:/etc/apt/apt-mirrors.txt" - else - mirror="http://archive.ubuntu.com/ubuntu" - fi - else - mirror="http://ports.ubuntu.com/ubuntu-ports" - fi - echo "deb ${mirror} plucky universe main" | sudo tee /etc/apt/sources.list.d/plucky.list - # Raise apt retries slightly above the compiled-in default of 3 to tolerate - # transient network blips (covers ~2-3 min of cumulative retry delay with - # apt's exponential backoff, capped at 30s/attempt). This used to be set to - # 35 (~15 min) specifically to ride out azure.archive.ubuntu.com outages; - # now that we no longer use that mirror, a much smaller value suffices. - echo 'Acquire::Retries "5";' | sudo tee /etc/apt/apt.conf.d/80-retries - /bin/time -f '%E %C' sudo apt update - # skopeo is currently older in plucky for some reason hence --allow-downgrades - /bin/time -f '%E %C' sudo apt install -y --allow-downgrades crun/plucky buildah/plucky podman/plucky skopeo/plucky just - ;; - ubuntu-26.04) - # 26.04 ships a sufficiently modern podman with heredoc support; - # no PPA or package upgrades needed — just install extras. - /bin/time -f '%E %C' sudo apt update - /bin/time -f '%E %C' sudo apt install -y just - ;; - *) - echo "Unsupported runner: ${IDV}" >&2 - exit 1 - ;; - esac - # This is the default on e.g. Fedora derivatives, but not Debian. - # Only needed when libvirt/virtualization is requested. - - name: Enable unprivileged /dev/kvm access - if: ${{ inputs.libvirt == 'true' }} + env: + BOOTC_HOST_LIBVIRT: ${{ inputs.libvirt }} + run: bash "${GITHUB_ACTION_PATH}/../bootc-host-setup/ci/workarounds.sh" + - name: Test host environment shell: bash - run: | - set -xeuo pipefail - if [ -c /dev/kvm ]; then - echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules - sudo udevadm control --reload-rules - sudo udevadm trigger --name-match=kvm - ls -l /dev/kvm - else - printf 'No /dev/kvm character device; skipping KVM permission setup.\n' - fi - # Used by a few workflows, but generally useful - - name: Set architecture variable - id: set_arch - shell: bash - run: echo "ARCH=$(arch)" >> $GITHUB_ENV - # Install libvirt stack if requested - - name: Install libvirt and virtualization stack - if: ${{ inputs.libvirt == 'true' }} - shell: bash - run: | - set -xeuo pipefail - idv=$(. /usr/lib/os-release && printf '%s-%s' "$ID" "$VERSION_ID") - firmware_packages=() - if [ "$idv" = ubuntu-26.04 ]; then - # Unsealed bootc tests request bcvk's uefi-insecure mode: - # https://github.com/bootc-dev/bootc/blob/12f03a042b868f40ec850c2496babda1d66775d5/crates/xtask/src/bcvk.rs#L113-L120 - # This becomes a libvirt secure=no firmware request. Resolute's - # stateless AMD-SEV descriptor satisfies that request and may win - # auto-selection, but without NVRAM it cannot restore the installed - # GRUB boot entry. Keep generic OVMF and the other recommendations - # while removing that descriptor by excluding its package. - # https://libvirt.org/formatdomain.html#guest-firmware - firmware_packages=(ovmf-generic ovmf-amdsev-) - fi - # Let libvirt select its QEMU dependency; qemu-kvm has ambiguous - # providers on Ubuntu 26.04 when requested explicitly. - # see https://github.com/bootc-dev/bcvk/issues/176 - /bin/time -f '%E %C' sudo apt install -y libkrb5-dev pkg-config libvirt-dev genisoimage qemu-utils virtiofsd libvirt-daemon-system python3-virt-firmware "${firmware_packages[@]}" - - # bcvk requires KVM and v0.19.0 has no arm64 release asset. - - name: Install bcvk - if: ${{ inputs.libvirt == 'true' && runner.arch == 'X64' }} - shell: bash - run: | - set -xeuo pipefail - # renovate: datasource=github-releases depName=bootc-dev/bcvk - export BCVK_VERSION=0.19.0 - # Something in the stack is overriding this, but we want session right now for bcvk - echo LIBVIRT_DEFAULT_URI=qemu:///session >> $GITHUB_ENV - td=$(mktemp -d) - cd $td - # Install bcvk - target=bcvk-$(arch)-unknown-linux-gnu - /bin/time -f '%E %C' curl --fail --show-error --location --retry 35 --retry-delay 30 --retry-max-time 1200 --output "${target}.tar.gz" "https://github.com/bootc-dev/bcvk/releases/download/v${BCVK_VERSION}/${target}.tar.gz" - tar xzf "${target}.tar.gz" - sudo install -T "${target}" /usr/bin/bcvk - cd - - rm -rf "$td" - - # Also bump the default fd limit as a workaround for https://github.com/bootc-dev/bcvk/issues/65 - sudo sed -i -e 's,^\* hard nofile 65536,* hard nofile 524288,' /etc/security/limits.conf - # Ubuntu 24.04's QEMU loses virtiofs IRQ notifications. Use the fixed - # package from Resolute on Ubuntu 24.04 for the disposable CI host; the - # Ubuntu 26.04 setup may provide its own native stack. This is the same - # race investigated in https://github.com/bootc-dev/bootc/pull/2290: - # https://github.com/qemu/qemu/commit/1ba9a5220325dd5260a0c37b6299ce38364a5120 - - name: Install fixed QEMU from Ubuntu Resolute - if: ${{ inputs.libvirt == 'true' }} - shell: bash - run: | - set -xeuo pipefail - idv=$(. /usr/lib/os-release && printf '%s-%s' "$ID" "$VERSION_ID") - if [ "$idv" != ubuntu-24.04 ]; then - printf 'Skipping Resolute QEMU setup on %s\n' "$idv" - exit 0 - fi - case "$(dpkg --print-architecture)" in - amd64) - qemu_package=qemu-system-x86 - ;; - arm64) - qemu_package=qemu-system-arm - ;; - *) - printf 'Unsupported architecture for Resolute QEMU: %s\n' \ - "$(dpkg --print-architecture)" >&2 - exit 1 - ;; - esac - qemu_binary="qemu-system-$(uname -m)" - - # Keep Resolute below the normal candidate for every package. The - # explicitly requested QEMU packages still bring their dependency - # closure (including glibc 2.43); that is acceptable on this - # disposable CI runner; copying just the executable would leave its - # runtime libraries behind. - printf '%s\n' \ - 'Package: *' \ - 'Pin: release n=resolute' \ - 'Pin-Priority: 50' | sudo tee /etc/apt/preferences.d/resolute-qemu >/dev/null - - if [ "$(dpkg --print-architecture)" = amd64 ]; then - if [ -f /etc/apt/apt-mirrors.txt ]; then - mirror='mirror+file:/etc/apt/apt-mirrors.txt' - else - mirror='http://archive.ubuntu.com/ubuntu' - fi - else - mirror='http://ports.ubuntu.com/ubuntu-ports' - fi - printf 'deb %s resolute main universe\n' "$mirror" | \ - sudo tee /etc/apt/sources.list.d/resolute-qemu.list >/dev/null - timeout --foreground --signal=TERM --kill-after=30s 5m sudo apt-get update - - # Keep ipxe-qemu in this explicit target transaction: its ROM must - # match the QEMU userspace rather than the older package from Plucky. - timeout --foreground --signal=TERM --kill-after=30s 5m \ - sudo apt-get -t resolute install -y --no-install-recommends \ - "$qemu_package" qemu-system-common qemu-system-data qemu-utils ipxe-qemu - - printf 'Selected QEMU: %s\n' "$qemu_binary" - "$qemu_binary" --version - dpkg-query -W -f='${binary:Package} ${Version}\n' \ - "$qemu_package" qemu-system-common qemu-system-data qemu-utils ipxe-qemu - rom= - if [ "$(dpkg --print-architecture)" = amd64 ]; then - rom_names=(efi-virtio.rom) - else - rom_names=(efi-aa64.rom efi-virtio.rom) - fi - for rom_name in "${rom_names[@]}"; do - for candidate in "/usr/share/qemu/$rom_name" "/usr/lib/ipxe/qemu/$rom_name"; do - if [ -f "$candidate" ]; then - rom=$candidate - break - fi - done - [ -n "$rom" ] && break - done - if [ -n "$rom" ]; then - printf 'EFI ROM: %s (%s)\n' "$rom" "$(dpkg-query -S "$rom")" - sha256sum "$rom" - else - printf 'No expected EFI ROM found after installing ipxe-qemu\n' >&2 - exit 1 - fi - - name: Keep CI bwrap children in the parent AppArmor profile - shell: bash - run: | - if sudo test -r /etc/apparmor.d/bwrap-userns-restrict && - sudo test -r /sys/kernel/security/apparmor/profiles && - sudo grep -qx 'bwrap (enforce)' /sys/kernel/security/apparmor/profiles; then - sudo tee /etc/apparmor.d/local/bwrap-userns-restrict >/dev/null <<'EOF' - priority=100 allow file rwlkm /**, - priority=100 allow ix /**, - EOF - sudo apparmor_parser -Q /etc/apparmor.d/bwrap-userns-restrict - sudo apparmor_parser -r /etc/apparmor.d/bwrap-userns-restrict - fi - - name: Cleanup status - shell: bash - run: | - set -xeuo pipefail - systemctl list-units 'action-cleanup*' - df -h + env: + BOOTC_HOST_LIBVIRT: ${{ inputs.libvirt }} + run: bash "${GITHUB_ACTION_PATH}/../bootc-host-setup/ci/test-environment.sh" diff --git a/test/bootc-host-setup.sh b/test/bootc-host-setup.sh new file mode 100644 index 0000000..f5e410b --- /dev/null +++ b/test/bootc-host-setup.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -euo pipefail + +action_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")/../bootc-host-setup" && pwd) +# shellcheck source=../bootc-host-setup/ci/install-deps.sh +# shellcheck disable=SC1091 +. "${action_dir}/ci/install-deps.sh" + +packages=() +read_packages "${action_dir}/packages/rhel-base" +test "${packages[*]}" = 'git-core podman curl tar gzip gcc rust cargo' + +packages=() +read_packages "${action_dir}/packages/ubuntu-libvirt" +test "${packages[0]}" = libkrb5-dev +test "${packages[-1]}" = python3-virt-firmware + +packages=() +read_packages "${action_dir}/packages/rhel-libvirt" +test "${packages[2]}" = libvirt-devel +test "${packages[4]}" = libvirt-daemon-driver-storage-core +test "${packages[-1]}" = python3-virt-firmware + +# These literals are deliberately static assertions against the narrowly +# confined partner-image workaround. +# shellcheck disable=SC2016 +grep -Fqx ' local expected_target=/usr/share/crypto-policies/DEFAULT/openssh.txt target diagnostic expected_diagnostic' "${action_dir}/ci/workarounds.sh" +# shellcheck disable=SC2016 +grep -Fqx ' test "$(sudo rpm -qf --qf '\''%{NAME}'\'' "$target")" = crypto-policies' "${action_dir}/ci/workarounds.sh" +# shellcheck disable=SC2016 +grep -Fqx ' test "$(sudo stat -c '\''%u:%g:%a'\'' -- "$target")" = 0:0:644' "${action_dir}/ci/workarounds.sh" +# shellcheck disable=SC2016 +grep -Fqx ' test "$(getenforce)" = Enforcing' "${action_dir}/ci/test-environment.sh" +# shellcheck disable=SC2016 +grep -Fqx ' test -x /usr/sbin/virtstoraged' "${action_dir}/ci/test-environment.sh" +# shellcheck disable=SC2016 +grep -Fqx ' dbus-run-session -- virsh -c qemu:///session pool-list --all' "${action_dir}/ci/test-environment.sh" + +# The per-user libvirt configuration must be installed before the session +# daemon starts, without changing the host SELinux enforcement mode. +# shellcheck disable=SC2016 +grep -Fqx ' local config_dir="${XDG_CONFIG_HOME:-$HOME/.config}/libvirt"' "${action_dir}/ci/workarounds.sh" +# shellcheck disable=SC2016 +grep -Fqx ' cat > "$config_dir/qemu.conf" <<'"'"'EOF'"'"'' "${action_dir}/ci/workarounds.sh" +# shellcheck disable=SC2016 +grep -Fqx 'security_driver = "none"' "${action_dir}/ci/workarounds.sh" +# shellcheck disable=SC2016 +grep -Fqx ' qemu_config="${XDG_CONFIG_HOME:-$HOME/.config}/libvirt/qemu.conf"' "${action_dir}/ci/test-environment.sh" +# shellcheck disable=SC2016 +grep -Fqx ' printf '\''%s\n'\'' '\''security_driver = "none"'\'' | cmp --silent - "$qemu_config"' "${action_dir}/ci/test-environment.sh" From 067abe632f67c7a92073446308b6a2810d44aa3a Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 17 Sep 2026 07:55:01 -0400 Subject: [PATCH 2/2] actions: Use bootc-host-setup internally Exercise the distro-aware entry point in this repository so its supported Ubuntu behavior remains covered while consumers migrate from the deprecated name. Assisted-by: AI --- .github/workflows/test-container-integration.yml | 4 ++-- .github/workflows/test-ubuntu-2604-ovmf.yml | 4 ++-- .github/workflows/test-virtualization.yml | 4 ++-- build-push-image/action.yml | 4 ++-- create-manifest/action.yml | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test-container-integration.yml b/.github/workflows/test-container-integration.yml index 0856f38..5ec90f8 100644 --- a/.github/workflows/test-container-integration.yml +++ b/.github/workflows/test-container-integration.yml @@ -42,7 +42,7 @@ jobs: uses: actions/checkout@v7 - name: Setup host - uses: ./bootc-ubuntu-setup + uses: ./bootc-host-setup - name: Create test Containerfile shell: bash @@ -74,7 +74,7 @@ jobs: uses: actions/checkout@v7 - name: Setup host - uses: ./bootc-ubuntu-setup + uses: ./bootc-host-setup - name: Extract metadata id: meta diff --git a/.github/workflows/test-ubuntu-2604-ovmf.yml b/.github/workflows/test-ubuntu-2604-ovmf.yml index 3f14552..41ef080 100644 --- a/.github/workflows/test-ubuntu-2604-ovmf.yml +++ b/.github/workflows/test-ubuntu-2604-ovmf.yml @@ -16,8 +16,8 @@ jobs: steps: - uses: actions/checkout@v7 - - name: Run bootc-ubuntu-setup - uses: ./bootc-ubuntu-setup + - name: Run bootc-host-setup + uses: ./bootc-host-setup with: libvirt: true diff --git a/.github/workflows/test-virtualization.yml b/.github/workflows/test-virtualization.yml index 1feeecb..58cf74e 100644 --- a/.github/workflows/test-virtualization.yml +++ b/.github/workflows/test-virtualization.yml @@ -3,7 +3,7 @@ name: Test virtualization setup on: pull_request: paths: - - bootc-ubuntu-setup/action.yml + - bootc-host-setup/** - .github/workflows/test-virtualization.yml workflow_dispatch: @@ -38,7 +38,7 @@ jobs: persist-credentials: false - name: Set up Ubuntu host - uses: ./bootc-ubuntu-setup + uses: ./bootc-host-setup with: libvirt: true diff --git a/build-push-image/action.yml b/build-push-image/action.yml index 69b36d9..9da4739 100644 --- a/build-push-image/action.yml +++ b/build-push-image/action.yml @@ -4,7 +4,7 @@ # images into a multi-arch manifest list afterwards. # # Prerequisites: -# Use bootc-dev/actions/bootc-ubuntu-setup first to get an up-to-date +# Use bootc-dev/actions/bootc-host-setup first to get an up-to-date # podman. The version shipped with ubuntu-24.04 is too old and has # known bugs with manifest handling and push-by-digest. # @@ -22,7 +22,7 @@ # runs-on: ${{ matrix.runner }} # steps: # - uses: actions/checkout@v6 -# - uses: bootc-dev/actions/bootc-ubuntu-setup@main +# - uses: bootc-dev/actions/bootc-host-setup@main # - uses: bootc-dev/actions/build-push-image@main # with: # image: ghcr.io/${{ github.repository }} diff --git a/create-manifest/action.yml b/create-manifest/action.yml index fa8b577..8f640a4 100644 --- a/create-manifest/action.yml +++ b/create-manifest/action.yml @@ -2,7 +2,7 @@ # multi-arch manifest list and push it with the desired tags. # # Prerequisites: -# Use bootc-dev/actions/bootc-ubuntu-setup first to get an up-to-date +# Use bootc-dev/actions/bootc-host-setup first to get an up-to-date # podman. The version shipped with ubuntu-24.04 is too old and has # known bugs with manifest handling. # @@ -16,7 +16,7 @@ # needs: build # runs-on: ubuntu-24.04 # steps: -# - uses: bootc-dev/actions/bootc-ubuntu-setup@main +# - uses: bootc-dev/actions/bootc-host-setup@main # - uses: docker/metadata-action@v5 # id: meta # with: