aurora/.github/workflows/reusable-build.yml
renner 108482756a
feat(ci): preparation for ARM builds (#2275)
Co-authored-by: inffy <10782843+inffy@users.noreply.github.com>
2026-05-31 09:53:36 +03:00

471 lines
18 KiB
YAML

name: Reusable Build and Push
on:
workflow_call:
inputs:
image_flavors:
description: "JSON string of flavors to build, '[main, nvidia-open]'"
default: "['main','nvidia-open']"
type: string
brand_name:
description: "The Brand Name: aurora"
required: true
default: aurora
type: string
stream_name:
description: "The Fedora Version: stable, or latest"
required: true
type: string
kernel_pin:
description: "The full kernel version to pin"
type: string
previous_build:
description: 'Set a reference to a previous build to make updates smaller'
type: string
architecture:
description: "JSON string of architectures to build, '[aarch64, x86_64]'"
default: "['x86_64']"
required: false
type: string
env:
IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}-${{ inputs.brand_name}}-${{ inputs.stream_name }}
cancel-in-progress: true
permissions: {}
jobs:
build_container:
name: image
runs-on: ${{ matrix.architecture == 'x86_64' && 'ubuntu-24.04' || 'ubuntu-24.04-arm' }}
permissions:
contents: read
packages: write
id-token: write
attestations: write
artifact-metadata: write
continue-on-error: false
strategy:
fail-fast: false
matrix:
image_flavor: ${{ fromJson(inputs.image_flavors) }}
base_name: ["${{ inputs.brand_name }}", "${{ inputs.brand_name }}-dx"]
stream_name: ["${{ inputs.stream_name }}"]
architecture: ${{ fromJson(inputs.architecture) }}
exclude:
# DX is "legacy", don't build them for arm
- architecture: aarch64
base_name: "${{ inputs.brand_name }}-dx"
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
# mount /mnt as /var/lib/containers
- name: Mount BTRFS for podman storage
id: container-storage-action
uses: ublue-os/container-storage-action@dc1f4c8f17b672069e921f001132f7cf98a423a6
continue-on-error: true
with:
target-dir: /var/lib/containers
mount-opts: compress-force=zstd:2
loopback-free: '1'
# TODO: remove me when we have a new podman in 26.04 runners
# needed because old podman doesn't push layer annotations for
# the rpm-ostree rechunker at all
- name: Update podman and install just
shell: bash
run: |
set -eux
# Require the runner is ubuntu-24.04
IDV=$(. /usr/lib/os-release && echo ${ID}-${VERSION_ID})
test "${IDV}" = "ubuntu-24.04"
# resolute is the next release. The azure.archive.ubuntu.com mirror only carries amd64.
# Other architectures like arm64 use ports.ubuntu.com/ubuntu-ports.
if [ "$(dpkg --print-architecture)" = "amd64" ]; then
mirror="http://azure.archive.ubuntu.com/ubuntu"
else
mirror="http://ports.ubuntu.com/ubuntu-ports"
fi
echo "deb ${mirror} resolute universe main" | sudo tee /etc/apt/sources.list.d/resolute.list
/bin/time -f '%E %C' sudo apt update
# skopeo is currently older in resolute for some reason hence --allow-downgrades
/bin/time -f '%E %C' sudo apt install -y --allow-downgrades crun/resolute buildah/resolute podman/resolute skopeo/resolute just/resolute
podman --version
# FIXME: Implement retries for stuff like this
- name: Install Cosign
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
if: github.event_name != 'pull_request'
- name: Install ORAS
if: github.event_name != 'pull_request'
uses: oras-project/setup-oras@38de303aac69abb66f3e6255b7198bff35f323e3 # v2.0.0
- name: Check Just Syntax
shell: bash
run: |
just check
- name: Image Name
shell: bash
env:
MATRIX_BASE_NAME: ${{ matrix.base_name }}
MATRIX_STREAM_NAME: ${{ matrix.stream_name }}
MATRIX_IMAGE_FLAVOR: ${{ matrix.image_flavor }}
run: |
IMAGE_NAME="$(just image_name ${MATRIX_BASE_NAME} ${MATRIX_STREAM_NAME} ${MATRIX_IMAGE_FLAVOR})"
echo "IMAGE_NAME=${IMAGE_NAME}" >> $GITHUB_ENV
- name: DNF Package Cache Setup
shell: bash
id: setup-cache
env:
MATRIX_BASE_NAME: ${{ matrix.base_name }}
MATRIX_STREAM_NAME: ${{ matrix.stream_name }}
MATRIX_IMAGE_FLAVOR: ${{ matrix.image_flavor }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
run: |
CACHE="$(just setup-cache "${MATRIX_BASE_NAME}" \
"${MATRIX_STREAM_NAME}" \
"${MATRIX_IMAGE_FLAVOR}" \
"1" \
"${GITHUB_EVENT_NAME}")"
CACHE_NAME="$(echo "${CACHE}" | cut -d' ' -f 1)"
ALLOW_CACHE_WRITE="$(echo "${CACHE}" | cut -d' ' -f 2)"
echo "cache_name=${CACHE_NAME}" >> "$GITHUB_OUTPUT"
echo "allow_cache_write=${ALLOW_CACHE_WRITE}" >> "$GITHUB_OUTPUT"
- name: Restore DNF package cache
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
env:
CACHE_NAME: ${{ steps.setup-cache.outputs.cache_name }}
with:
path: /var/tmp/buildah-cache-*
key: ${{ runner.os }}-${{ matrix.architecture }}-buildah-${{ env.CACHE_NAME }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-${{ matrix.architecture }}-buildah-${{ env.CACHE_NAME }}-
${{ runner.os }}-${{ matrix.architecture }}-buildah-${{ env.CACHE_NAME }}
- name: Build Image
id: build-image
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
MATRIX_BASE_NAME: ${{ matrix.base_name }}
MATRIX_STREAM_NAME: ${{ matrix.stream_name }}
MATRIX_IMAGE_FLAVOR: ${{ matrix.image_flavor }}
INPUTS_KERNEL_PIN: ${{ inputs.kernel_pin }}
run: |
sudo -E $(command -v just) repo_organization="${{ github.repository_owner }}" \
build-ghcr "${MATRIX_BASE_NAME}" \
"${MATRIX_STREAM_NAME}" \
"${MATRIX_IMAGE_FLAVOR}" \
"${INPUTS_KERNEL_PIN}"
# https://github.com/actions/cache/issues/1533
- name: Hack around permission issue caching
shell: bash
id: cache-perms
run: |
sudo chmod 777 --recursive /var/tmp/buildah-cache-0
- name: Write new DNF package cache
if: steps.setup-cache.outputs.allow_cache_write == 'true'
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
env:
CACHE_NAME: ${{ steps.setup-cache.outputs.cache_name }}
with:
path: /var/tmp/buildah-cache-*
key: ${{ runner.os }}-${{ matrix.architecture }}-buildah-${{ env.CACHE_NAME }}-${{ github.run_id }}
- name: Rechunk Image with rpm-ostree
id: rechunker
env:
MATRIX_BASE_NAME: ${{ matrix.base_name }}
MATRIX_STREAM_NAME: ${{ matrix.stream_name }}
MATRIX_IMAGE_FLAVOR: ${{ matrix.image_flavor }}
DEFAULT_TAG: ${{ env.DEFAULT_TAG }}
PREVIOUS_BUILD: ${{ github.event_name == 'pull_request' && '0' || (github.event.inputs.previous_build || '1') }}
run: |
sudo -E $(command -v just) rechunk "${MATRIX_BASE_NAME}" \
"${MATRIX_STREAM_NAME}" \
"${MATRIX_IMAGE_FLAVOR}" \
"1" \
"0" \
"${PREVIOUS_BUILD}"
- name: Setup Syft
id: setup-syft
if: github.event_name != 'pull_request'
uses: anchore/sbom-action/download-syft@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
- name: Generate SBOM
if: github.event_name != 'pull_request'
id: generate-sbom
env:
MATRIX_BASE_NAME: ${{ matrix.base_name }}
MATRIX_STREAM_NAME: ${{ matrix.stream_name }}
MATRIX_IMAGE_FLAVOR: ${{ matrix.image_flavor }}
SYFT_CMD: ${{ steps.setup-syft.outputs.cmd }}
run: |
sudo -E $(command -v just) gen-sbom "${MATRIX_BASE_NAME}" \
"${MATRIX_STREAM_NAME}" \
"${MATRIX_IMAGE_FLAVOR}" \
"${SYFT_CMD}"
- name: Secureboot Check
id: secureboot
shell: bash
env:
MATRIX_BASE_NAME: ${{ matrix.base_name }}
MATRIX_STREAM_NAME: ${{ matrix.stream_name }}
MATRIX_IMAGE_FLAVOR: ${{ matrix.image_flavor }}
run: |
sudo -E $(command -v just) secureboot "${MATRIX_BASE_NAME}" \
"${MATRIX_STREAM_NAME}" \
"${MATRIX_IMAGE_FLAVOR}"
- name: Export to OCI Archive
if: github.event_name == 'pull_request'
id: oci-archive
env:
MATRIX_BASE_NAME: ${{ matrix.base_name }}
MATRIX_STREAM_NAME: ${{ matrix.stream_name }}
MATRIX_IMAGE_FLAVOR: ${{ matrix.image_flavor }}
run: |
sudo -E $(command -v just) export-oci "${MATRIX_BASE_NAME}" \
"${MATRIX_STREAM_NAME}" \
"${MATRIX_IMAGE_FLAVOR}"
- name: Upload OCI Archive as Artifact
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ env.IMAGE_NAME }}-${{ matrix.architecture }}.oci
path: ${{ env.IMAGE_NAME }}-${{ matrix.architecture }}.oci
archive: false
if-no-files-found: error
retention-days: 1
- name: Create Bootable Image
id: bootc-install
# doing other images is not worth it
if: github.event_name == 'pull_request' && matrix.base_name == 'aurora' && matrix.image_flavor == 'main'
# free disk space varies
continue-on-error: true
env:
MATRIX_BASE_NAME: ${{ matrix.base_name }}
MATRIX_STREAM_NAME: ${{ matrix.stream_name }}
MATRIX_IMAGE_FLAVOR: ${{ matrix.image_flavor }}
run: |
sudo -E $(command -v just) disk-image "${MATRIX_BASE_NAME}" \
"${MATRIX_STREAM_NAME}" \
"${MATRIX_IMAGE_FLAVOR}" \
1
- name: PR Testing Instructions
if: github.event_name == 'pull_request'
id: pr-summary
env:
IMAGE_NAME: ${{ env.IMAGE_NAME }}
MATRIX_STREAM_NAME: "${{ matrix.stream_name }}"
run: |
echo "Download the .oci file" >> $GITHUB_STEP_SUMMARY
echo "Rebase: sudo bootc switch --transport oci-archive /path/to/${IMAGE_NAME}".oci >> $GITHUB_STEP_SUMMARY
echo "Go back to the production image e.g.: sudo bootc switch --enforce-container-sigpolicy ${IMAGE_REGISTRY}/${IMAGE_NAME}:${MATRIX_STREAM_NAME}" >> $GITHUB_STEP_SUMMARY
- name: Generate tags
id: generate-tags
shell: bash
env:
MATRIX_BASE_NAME: "${{ matrix.base_name }}"
MATRIX_STREAM_NAME: "${{ matrix.stream_name }}"
MATRIX_IMAGE_FLAVOR: "${{ matrix.image_flavor }}"
INPUTS_KERNEL_PIN: "${{ inputs.kernel_pin }}"
IMAGE_NAME: ${{ env.IMAGE_NAME }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
GITHUB_EVENT_NUMBER: ${{ github.event.number }}
run: |
alias_tags="$(just generate-build-tags \
"${MATRIX_BASE_NAME}" \
"${MATRIX_STREAM_NAME}" \
"${MATRIX_IMAGE_FLAVOR}" \
"${INPUTS_KERNEL_PIN}" \
"1" \
"$(podman inspect ${IMAGE_NAME}:${MATRIX_STREAM_NAME} | jq -r '.[].Config.Labels["org.opencontainers.image.version"]')" \
"${GITHUB_EVENT_NAME}" \
"${GITHUB_EVENT_NUMBER}")"
echo "Tags for this Action..."
echo "$alias_tags"
echo "alias_tags=${alias_tags}" >> $GITHUB_OUTPUT
# Tag Images
- name: Tag Images
shell: bash
env:
IMAGE_NAME: ${{ env.IMAGE_NAME }}
MATRIX_STREAM_NAME: ${{ matrix.stream_name }}
ALIAS_TAGS: ${{ steps.generate-tags.outputs.alias_tags }}
run: |
set -eoux pipefail
sudo -E $(command -v just) tag-images "${IMAGE_NAME}" \
"${MATRIX_STREAM_NAME}" \
"${ALIAS_TAGS}"
- name: Login to GitHub Container Registry
if: github.event_name != 'pull_request'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_ACTOR: ${{ github.actor }}
run: |
echo "${GITHUB_TOKEN}" | podman login ghcr.io -u "${GITHUB_ACTOR}" --password-stdin
echo "${GITHUB_TOKEN}" | docker login ghcr.io -u "${GITHUB_ACTOR}" --password-stdin
# Workaround bug where capital letters in your GitHub username make it impossible to push to GHCR.
# https://github.com/macbre/push-to-ghcr/issues/12
- name: Lowercase Registry
if: github.event_name != 'pull_request'
env:
IMAGE_REGISTRY: ${{ env.IMAGE_REGISTRY }}
run: |
echo "IMAGE_REGISTRY=${IMAGE_REGISTRY,,}" >> $GITHUB_OUTPUT
# Workaround bugs caused by pushing images but not signing them because of CI flakes
# FIXME: once https://github.com/containers/podman/issues/27796 resolved
- name: Push Ephemeral Tag
if: github.event_name != 'pull_request'
id: pre-push
env:
MATRIX_BASE_NAME: "${{ matrix.base_name }}"
MATRIX_IMAGE_FLAVOR: "${{ matrix.image_flavor }}"
MATRIX_STREAM_NAME: "${{ matrix.stream_name }}"
TEMP_PUSH_TAG: "staging"
run: |
set -euox pipefail
sudo -E $(command -v just) push-image \
"${MATRIX_BASE_NAME}" \
"${MATRIX_STREAM_NAME}" \
"${MATRIX_IMAGE_FLAVOR}" \
"1" \
"${IMAGE_REGISTRY}" \
"1" \
"${TEMP_PUSH_TAG}"
digest=$(< /tmp/digestfile)
echo "digest=${digest}" >> $GITHUB_OUTPUT
- name: Sign container image
if: github.event_name != 'pull_request'
env:
DIGEST: ${{ steps.pre-push.outputs.digest }}
COSIGN_EXPERIMENTAL: false
COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }}
IMAGE_NAME: ${{ env.IMAGE_NAME }}
run: |
# use old bundle format, so we can use newer cosign 3.X.X instead of 2.X.X
# https://github.com/containers/container-libs/issues/388
# https://github.com/coreos/rpm-ostree/issues/5509
cosign sign -y --new-bundle-format=false --use-signing-config=false --key env://COSIGN_PRIVATE_KEY ${IMAGE_REGISTRY}/${IMAGE_NAME}@${DIGEST}
- name: Push to GHCR
id: push
if: github.event_name != 'pull_request'
env:
MATRIX_BASE_NAME: "${{ matrix.base_name }}"
MATRIX_STREAM_NAME: "${{ matrix.stream_name }}"
MATRIX_IMAGE_FLAVOR: "${{ matrix.image_flavor }}"
run: |
set -euox pipefail
sudo -E $(command -v just) push-image \
"${MATRIX_BASE_NAME}" \
"${MATRIX_STREAM_NAME}" \
"${MATRIX_IMAGE_FLAVOR}" \
"1" \
"${IMAGE_REGISTRY}"
- name: Login to GitHub Container Registry with ORAS
if: github.event_name != 'pull_request'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_ACTOR: ${{ github.actor }}
run: |
echo "${GITHUB_TOKEN}" | oras login ghcr.io -u "${GITHUB_ACTOR}" --password-stdin
- name: Upload SBOM
if: github.event_name != 'pull_request'
id: upload-sbom
env:
IMAGE: ${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}
DIGEST: ${{ steps.pre-push.outputs.digest }}
IMAGE_NAME: ${{ env.IMAGE_NAME }}
run: |
SBOM="sbom_out/${IMAGE_NAME}/sbom.json"
cd "$(dirname "${SBOM}")"
oras attach \
--artifact-type application/vnd.spdx+json \
--annotation filename=$(basename "$SBOM") \
"${IMAGE}@${DIGEST}" \
"$(basename ${SBOM})"
sbom_digest=$(oras discover --format json "${IMAGE}@${DIGEST}" | jq -r '.referrers[] | select(.artifactType == "application/vnd.spdx+json") | .digest')
echo "sbom_digest=${sbom_digest}" >> $GITHUB_OUTPUT
- name: Sign SBOM OCI Artifact
if: github.event_name != 'pull_request'
env:
COSIGN_EXPERIMENTAL: false
COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }}
IMAGE_NAME: ${{ env.IMAGE_NAME }}
SBOM_DIGEST: ${{ steps.upload-sbom.outputs.sbom_digest }}
run: |
cosign sign -y --use-signing-config=false --key env://COSIGN_PRIVATE_KEY ${IMAGE_REGISTRY}/${IMAGE_NAME}@${SBOM_DIGEST}
- name: Attestation
if: github.event_name != 'pull_request'
uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 #v4.1.0
with:
subject-name: ${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}
subject-digest: ${{ steps.pre-push.outputs.digest }}
# Keep this disabled, this confuses cosign verify
push-to-registry: false
- name: Disk usage summary
if: always()
run: |
echo "### Disk usage" >> "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"
df -h >> "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"
check:
name: Check all ${{ matrix.stream_name }} builds successful
if: always()
runs-on: ubuntu-latest
needs: [build_container]
steps:
- name: Check Jobs
env:
JOBS: ${{ toJson(needs) }}
run: |
echo "Job status:"
echo $JOBS | jq -r 'to_entries[] | " - \(.key): \(.value.result)"'
for i in $(echo $JOBS | jq -r 'to_entries[] | .value.result'); do
if [ "$i" != "success" ] && [ "$i" != "skipped" ]; then
echo ""
echo "Status check not okay!"
exit 1
fi
done