diff --git a/.github/workflows/build-fsync-40.yml b/.github/workflows/build-fsync-40.yml new file mode 100644 index 0000000..e76b886 --- /dev/null +++ b/.github/workflows/build-fsync-40.yml @@ -0,0 +1,24 @@ +name: Build Fsync 40 + +on: + pull_request: + +jobs: + generate_metadata: + uses: ./.github/workflows/reusable-generate-metadata.yml + with: + fedora-version: 40 + image-registry: ghcr.io/ublue-os + image-name: multiarch-test-fsync-kernel + + build: + uses: ./.github/workflows/reusable-build.yml + needs: generate_metadata + secrets: inherit + with: + image-registry: ${{ needs.generate_metadata.outputs.image-registry }} + image-name: ${{ needs.generate_metadata.outputs.image-name }} + platforms: amd64, arm64 + build-args: ${{ needs.generate_metadata.outputs.build-args }} + tags: ${{ needs.generate_metadata.outputs.tags }} + validate-secureboot: true diff --git a/.github/workflows/reusable-build.yml b/.github/workflows/reusable-build.yml index 70ed3f2..35f2c54 100644 --- a/.github/workflows/reusable-build.yml +++ b/.github/workflows/reusable-build.yml @@ -1,369 +1,258 @@ -name: Cache Kernels +name: Build Image + on: - merge_group: - schedule: - - cron: "5 0 * * *" # 0005 UTC everyday - workflow_dispatch: - pull_request: - branches: - - main - paths-ignore: - - '.github/workflows/cleanup*.yml' - -env: - IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }} + workflow_call: + inputs: + image-registry: + description: "The registry to push the image to. E.G. ghcr.io/ublue-os" + required: true + type: string + image-name: + description: "The name of the image to build. E.G. main" + required: true + type: string + platforms: + description: "The platforms to build for. E.G. aarch64, x86_64 etc" + required: true + type: string + tags: + description: "The tags to apply to the image" + required: true + type: string + build-args: + description: "The build arguments to pass to the build" + required: false + type: string + validate-secureboot: + description: "Whether to validate secureboot" + required: false + type: boolean + outputs: + manifest-digest: + description: "The digest of the remote manifest" + value: ${{ jobs.manifest.outputs.manifest-digest }} concurrency: - group: ${{ github.workflow }}-${{ github.ref || github.run_id }}-${{ inputs.fedora_version }} + group: ${{ github.workflow }}-${{ github.ref || github.run_id }}-${{ inputs.fedora_version }}-${{ inputs.fedora_edition }}-${{ inputs.platforms }} cancel-in-progress: true jobs: + generate_matrix: + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + steps: + - name: Set Matrix + id: set-matrix + env: + PLATFORMS: ${{ inputs.platforms }} + run: | + MATRIX='{"include":[]}' + # Split platforms string by comma and iterate over each platform + for platform in $(echo $PLATFORMS | tr ',' '\n'); do + MATRIX=$(echo $MATRIX | jq ".include += [{\"platform\": \"${platform}\"}]") + done + + echo "matrix=$(echo $MATRIX | jq -c '.')" >> $GITHUB_OUTPUT + build: - name: kernel-cache - runs-on: ubuntu-24.04 - permissions: - contents: read - packages: write - id-token: write + runs-on: ${{ matrix.platform == 'amd64' && 'ubuntu-24.04' || 'ubuntu-24.04-arm' }} + needs: generate_matrix strategy: - fail-fast: false - matrix: - kernel_flavor: - - asus - - fsync - - fsync-ba - - bazzite - - surface - - main - - coreos-stable - - coreos-testing - fedora_version: - - 40 - - 41 - exclude: - - fedora_version: 40 - kernel_flavor: asus - - fedora_version: 41 - kernel_flavor: fsync - - fedora_version: 41 - kernel_flavor: fsync-ba - - fedora_version: 40 - kernel_flavor: bazzite - - fedora_version: 40 - kernel_flavor: coreos-testing - + matrix: ${{fromJson(needs.generate_matrix.outputs.matrix)}} steps: - - name: Checkout Push to Registry action + - name: Checkout uses: actions/checkout@v4 - - name: Pull Image - uses: Wandalen/wretry.action@v3.7.3 - with: - attempt_limit: 3 - attempt_delay: 15000 - command: | - build_image="quay.io/fedora/fedora:${{ matrix.fedora_version }}" - echo "build_image=$build_image" >> "$GITHUB_ENV" - podman pull "$build_image" - - - name: Get Kernel Version - id: Version - uses: Wandalen/wretry.action@v3.7.3 - with: - attempt_limit: 3 - attempt_delay: 15000 - command: | - if [[ ${{ matrix.kernel_flavor }} =~ asus|fsync|fsync-ba|surface ]]; then - container_name="fq-$(uuidgen)" - dnf="podman exec $container_name dnf" - - podman run --entrypoint /bin/bash --name "$container_name" -dt "${{ env.build_image }}" - $dnf install -y dnf-plugins-core - fi - - coreos_kernel () { - coreos_version=${1} - image_linux=$(skopeo inspect docker://quay.io/fedora/fedora-coreos:${coreos_version} | jq -r '.Labels["ostree.linux"]') - # Pin a kernel here, gross workaround TODO: Make this cleaner - # if [[ "${{ matrix.kernel_flavor }}" == "coreos-stable" ]]; then - # image_linux="6.11.3-300.fc41.x86_64" - # fi - major_minor_patch=$(echo $image_linux | grep -oP '^\d+\.\d+\.\d+') - kernel_rel_part=$(echo $image_linux | grep -oP '^\d+\.\d+\.\d+\-\K([123][0]{2})') - arch=$(echo $image_linux | grep -oP 'fc\d+\.\K.*$') - - kernel_rel="$kernel_rel_part.fc${{ matrix.fedora_version }}" - kernel_version="$major_minor_patch-$kernel_rel.$arch" - URL="https://kojipkgs.fedoraproject.org/packages/kernel/"$major_minor_patch"/"$kernel_rel"/"$arch"/kernel-"$kernel_version".rpm" - echo "Querying koji for ${coreos_version} kernel: $kernel_version" - echo "$URL" - HTTP_RESP=$(curl -sI "$URL" | grep ^HTTP) - linux="" - if grep -qv "200 OK" <<< "${HTTP_RESP}"; then - echo "Koji failed to find $coreos_version kernel: $kernel_version" - case "$kernel_rel_part" in - "300") - kernel_rel_part="200" - ;; - "200") - kernel_rel_part="100" - ;; - "100") - ;; - *) - echo "unexpected kernel_rel_part ${kernel_rel_part}" - ;; - esac - kernel_rel="$kernel_rel_part.fc${{ matrix.fedora_version }}" - kernel_version="$major_minor_patch-$kernel_rel.$arch" - URL="https://kojipkgs.fedoraproject.org/packages/kernel/"$major_minor_patch"/"$kernel_rel"/"$arch"/kernel-"$kernel_version".rpm" - echo "Re-querying koji for ${coreos_version} kernel: $kernel_version" - echo "$URL" - HTTP_RESP=$(curl -sI "$URL" | grep ^HTTP) - if grep -qv "200 OK" <<< "${HTTP_RESP}"; then - echo "Koji failed to find $coreos_version kernel: $kernel_version" - fi - fi - if grep -q "200 OK" <<< "${HTTP_RESP}"; then - linux=$kernel_version - fi - } - - case ${{ matrix.kernel_flavor }} in - "asus") - $dnf copr enable -y lukenukem/asus-kernel - linux=$($dnf repoquery --repoid copr:copr.fedorainfracloud.org:lukenukem:asus-kernel --whatprovides kernel | sort -V | tail -n1 | sed 's/.*://') - ;; - "fsync") - $dnf copr enable -y sentry/kernel-fsync - linux=$($dnf repoquery --repoid copr:copr.fedorainfracloud.org:sentry:kernel-fsync --whatprovides kernel | sort -V | tail -n1 | sed 's/.*://') - ;; - "fsync-ba") - $dnf copr enable -y sentry/kernel-ba - linux=$($dnf repoquery --repoid copr:copr.fedorainfracloud.org:sentry:kernel-ba --whatprovides kernel | sort -V | tail -n1 | sed 's/.*://') - ;; - "bazzite") - latest="$(curl "https://api.github.com/repos/hhd-dev/kernel-bazzite/releases/latest" )" - linux=$(echo -E "$latest" | jq -r '.assets[].name' | grep -E 'kernel-.*.rpm' | grep "fc${{ matrix.fedora_version }}.x86_64" | head -1 | sed "s/kernel-//g" | sed "s/.rpm//g" ) - build_tag=$(echo -E $latest | jq -r '.tag_name') - ;; - "surface") - if [[ "${{ matrix.fedora_version }}" < 41 ]]; then - $dnf config-manager --add-repo=https://pkg.surfacelinux.com/fedora/linux-surface.repo - else - $dnf config-manager addrepo --from-repofile=https://pkg.surfacelinux.com/fedora/linux-surface.repo - fi - linux=$($dnf repoquery --repoid linux-surface --whatprovides kernel-surface | sort -V | tail -n1 | sed 's/.*://') - - ;; - "main") - base_image_name="base" - if [[ ${{ matrix.fedora_version }} > 40 ]]; then - base_image_name+="-atomic" - fi - linux=$(skopeo inspect docker://quay.io/fedora-ostree-desktops/$base_image_name:${{ matrix.fedora_version }} | jq -r '.Labels["ostree.linux"]' ) - ;; - "coreos-stable") - coreos_kernel stable - ;; - "coreos-testing") - coreos_kernel testing - ;; - *) - echo "unexpected kernel_flavor '${{ matrix.kernel_flavor }}' for query" - ;; - esac - if [ -z "$linux" ] || [ "null" = "$linux" ]; then - echo "inspected image linux version must not be empty or null" - exit 1 - fi - major=$(echo "$linux" | cut -d '.' -f 1) - minor=$(echo "$linux" | cut -d '.' -f 2) - patch=$(echo "$linux" | cut -d '.' -f 3) - kernel_major_minor_patch="${major}.${minor}.${patch}" - echo "Kernel Version is ${linux}" - echo "kernel_release=${linux}" >> $GITHUB_ENV - echo "kernel_build_tag=${build_tag}" >> $GITHUB_ENV - echo "kernel_major_minor_patch=${kernel_major_minor_patch}" >> $GITHUB_ENV - - - name: Generate Tags - id: generate_tags - shell: bash + - name: Login to GHCR + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + + - name: Setup Dependencies (ARM64) + if: ${{ matrix.platform == 'arm64' }} run: | - tag="${{ env.kernel_release }}" - short_tag=$(echo ${{ env.kernel_major_minor_patch }} | cut -d "-" -f 1) - COMMIT_TAGS=() - COMMIT_TAGS+=("pr-${{ github.event.number }}-${{ matrix.fedora_version }}") - COMMIT_TAGS+=("pr-${{ github.event.number }}-${{ matrix.fedora_version }}-${short_tag}") - COMMIT_TAGS+=("pr-${{ github.event.number }}-${{ matrix.fedora_version }}-${tag}") - COMMIT_TAGS+=("pr-${{ github.event.number }}-${tag}") - COMMIT_TAGS+=("${GITHUB_SHA::7}-${{ matrix.fedora_version }}") - COMMIT_TAGS+=("${GITHUB_SHA::7}-${{ matrix.fedora_version }}-${short_tag}") - COMMIT_TAGS+=("${GITHUB_SHA::7}-${{ matrix.fedora_version }}-${tag}") - COMMIT_TAGS+=("${GITHUB_SHA::7}-${tag}") - - BUILD_TAGS=() - BUILD_TAGS+=("${{ matrix.fedora_version }}") - BUILD_TAGS+=(${{ matrix.fedora_version }}-${short_tag}) - BUILD_TAGS+=(${{ matrix.fedora_version }}-${tag}) - BUILD_TAGS+=(${tag}) - if [[ "${{ github.event_name }}" == "pull_request" ]]; then - # echo "Generated the following commit tags: " - # for TAG in "${COMMIT_TAGS[@]}"; do - # echo "${TAG}" - # done - alias_tags=("${COMMIT_TAGS[@]}") - else - alias_tags=("${BUILD_TAGS[@]}") - fi + sudo apt update + sudo apt install -y podman sqlite3 - echo "Generated the following tags: " - for TAG in "${alias_tags[@]}"; do - echo "${TAG}" - done + sudo mkdir -p /etc/containers + echo -e "[storage]\ndriver = \"overlay\"\nrunroot = \"/run/containers/storage\"\ngraphroot = \"/var/lib/containers/storage\"" \ + | sudo tee /etc/containers/storage.conf - echo "alias_tags=${alias_tags[*]}" >> $GITHUB_OUTPUT - echo "date=$(date '+%Y%m%d.0')" >> $GITHUB_ENV + # workaround https://github.com/containers/podman/issues/21683 + echo "update DBConfig set GraphDriver = 'overlay' where GraphDriver = '';" | sudo sh -c '(cd /var/lib/containers/storage && sqlite3 db.sql)' - - name: Build Metadata - uses: docker/metadata-action@v5 - id: meta - with: - images: | - ${{ matrix.kernel_flavor }}-kernel - labels: | - org.opencontainers.image.title=${{ matrix.kernel_flavor }} cached kernel - org.opencontainers.image.description=A caching layer for kernels. Contains ${{ matrix.kernel_flavor }} kernel. - org.opencontainers.image.version=${{ env.kernel_release}}.${{ env.date }} - ostree.linux=${{ env.kernel_release }} - io.artifacthub.package.readme-url=https://raw.githubusercontent.com/${{ github.repository }}/main/README.md - io.artifacthub.package.logo-url=https://avatars.githubusercontent.com/u/1728152?s=200&v=4 - - - name: Retrieve Signing Key - if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || github.event_name == 'merge_group' - shell: bash + - name: Build Image + id: build-image + env: + IMAGE_REGISTRY: ${{ inputs.image-registry }} + IMAGE_NAME: ${{ inputs.image-name }} + BUILD_ARGS: ${{ inputs.build-args }} + PLATFORM: ${{ matrix.platform }} run: | - mkdir -p certs - if [[ "${{ github.event_name }}" == 'pull_request' ]]; then - echo "This should not have run... exiting..." - exit 1 - else - echo "${{ secrets.KERNEL_PRIVKEY }}" > certs/private_key.priv - echo "${{ secrets.AKMOD_PRIVKEY_20230518 }}" > certs/private_key_2.priv - # DEBUG: get character count of key - wc -c certs/private_key.priv - wc -c certs/private_key_2.priv - fi + BUILD_ARGS_FLAGS=() + for arg in $(echo $BUILD_ARGS | tr ',' '\n'); do + BUILD_ARGS_FLAGS+=("--build-arg" "$arg") + done - - name: Build Image - id: build_image - uses: redhat-actions/buildah-build@v2 - with: - containerfiles: | - ./Containerfile - image: ${{ matrix.kernel_flavor }}-kernel - tags: ${{ steps.generate_tags.outputs.alias_tags }} - build-args: | - FEDORA_VERSION=${{ matrix.fedora_version }} - KERNEL_VERSION=${{ env.kernel_release }} - KERNEL_BUILD_TAG=${{ env.kernel_build_tag }} - KERNEL_FLAVOR=${{ matrix.kernel_flavor }} - DUAL_SIGN=true - labels: ${{ steps.meta.outputs.labels }} - oci: false - - - name: Check Secureboot Signatures - shell: bash + sudo podman build \ + --arch $PLATFORM \ + --iidfile /tmp/iidfile \ + -t ${IMAGE_REGISTRY}/${IMAGE_NAME}:local \ + "${BUILD_ARGS_FLAGS[@]}" \ + . + + IMAGE_ID=$(cat /tmp/iidfile) + IMAGE_DIGEST=$(sudo podman inspect --format '{{.Digest}}' $IMAGE_ID) + + echo "IMAGE_DIGEST=${IMAGE_DIGEST}" >> $GITHUB_OUTPUT + + - name: Check Secureboot + if: ${{ inputs.validate-secureboot }} + env: + IMAGE_REGISTRY: ${{ inputs.image-registry }} + IMAGE_NAME: ${{ inputs.image-name }} + IMAGE_DIGEST: ${{ steps.build-image.outputs.IMAGE_DIGEST }} run: | - set -x - if [[ ! $(command -v sbverify) || ! $(command -v curl) || ! $(command -v openssl) || ! $(command -v rpm2cpio) ]]; then + set -euxo pipefail + + if [[ ! $(command -v sbverify) || ! $(command -v curl) || ! $(command -v openssl) ]]; then sudo apt update - sudo apt install sbsigntool curl openssl rpm2cpio - fi - podman create --name "${{ matrix.kernel_flavor}}"-kernel-"$(echo "${{ steps.generate_tags.outputs.alias_tags }}" | cut -d " " -f 1)" "${{ matrix.kernel_flavor}}"-kernel:$(echo "${{ steps.generate_tags.outputs.alias_tags }}" | cut -d " " -f 1) sh - podman export "${{ matrix.kernel_flavor}}"-kernel-"$(echo "${{ steps.generate_tags.outputs.alias_tags }}" | cut -d " " -f 1)" > /tmp/"${{ matrix.kernel_flavor}}"-kernel-"$(echo "${{ steps.generate_tags.outputs.alias_tags }}" | cut -d " " -f 1)".tar - tar xvf /tmp/"${{ matrix.kernel_flavor}}"-kernel-"$(echo "${{ steps.generate_tags.outputs.alias_tags }}" | cut -d " " -f 1)".tar -C /tmp - cd /tmp/tmp/rpms/ - if [[ "${{ matrix.kernel_flavor }}" == "surface" ]]; then - rpm2cpio kernel-surface-core-"${{ env.kernel_release }}".rpm | cpio -idmv - else - rpm2cpio kernel-core-"${{ env.kernel_release }}".rpm | cpio -idmv + sudo apt install sbsigntool curl openssl fi - cd ./lib/modules/"${{ env.kernel_release }}"/ + sudo podman run -d --rm --name ${IMAGE_NAME} ${IMAGE_REGISTRY}/${IMAGE_NAME}@${IMAGE_DIGEST} sleep 1000 + KERNEL_VERSION=$(sudo podman exec ${IMAGE_NAME} rpm -q --qf "%{VERSION}-%{RELEASE}.%{ARCH}\n" kernel | tail -n 1) + sudo podman cp ${IMAGE_NAME}:/usr/lib/modules/${KERNEL_VERSION}/vmlinuz . + sudo podman rm -f ${IMAGE_NAME} sbverify --list vmlinuz - if [[ "${{ github.event_name }}" == "pull_request" ]]; then - curl --retry 3 -Lo kernel-sign.der https://github.com/ublue-os/kernel-cache/raw/main/certs/public_key.der.test - curl --retry 3 -Lo akmods.der https://github.com/ublue-os/kernel-cache/raw/main/certs/public_key_2.der.test - else - curl --retry 3 -Lo kernel-sign.der https://github.com/ublue-os/kernel-cache/raw/main/certs/public_key.der - curl --retry 3 -Lo akmods.der https://github.com/ublue-os/kernel-cache/raw/main/certs/public_key_2.der - fi + curl --retry 3 -Lo kernel-sign.der https://github.com/ublue-os/kernel-cache/raw/main/certs/public_key.der + curl --retry 3 -Lo akmods.der https://github.com/ublue-os/kernel-cache/raw/main/certs/public_key_2.der openssl x509 -in kernel-sign.der -out kernel-sign.crt openssl x509 -in akmods.der -out akmods.crt sbverify --cert kernel-sign.crt vmlinuz || exit 1 sbverify --cert akmods.crt vmlinuz || exit 1 - cd $HOME - - name: Lowercase Registry - id: registry_case - uses: ASzc/change-string-case-action@v6 - with: - string: ${{ env.IMAGE_REGISTRY }} + - name: Push Image + id: push-image + env: + IMAGE_REGISTRY: ${{ inputs.image-registry }} + IMAGE_NAME: ${{ inputs.image-name }} + IMAGE_DIGEST: ${{ steps.build-image.outputs.IMAGE_DIGEST }} + run: | + for i in {1..3}; do + sudo podman push --digestfile=/tmp/digestfile ${IMAGE_REGISTRY}/${IMAGE_NAME}@${IMAGE_DIGEST} && break || sleep $((10 ** i)) + done - - name: Push to GHCR - uses: Wandalen/wretry.action@v3.7.3 - id: push - if: github.event_name != 'pull_request' + IMAGE_DIGEST=$(cat /tmp/digestfile) + echo "IMAGE_DIGEST=${IMAGE_DIGEST}" >> $GITHUB_OUTPUT + + - name: Generate Outputs env: - REGISTRY_USER: ${{ github.actor }} - REGISTRY_PASSWORD: ${{ github.token }} + IMAGE_NAME: ${{ inputs.image-name }} + IMAGE_DIGEST: ${{ steps.push-image.outputs.IMAGE_DIGEST }} + PLATFORM: ${{ matrix.platform }} + run: | + mkdir -p /tmp/outputs/digests + echo "$IMAGE_DIGEST" > /tmp/outputs/digests/${IMAGE_NAME}-${PLATFORM}.txt + + - name: Upload Output Artifacts + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4 with: - action: redhat-actions/push-to-registry@v2 - attempt_limit: 3 - attempt_delay: 15000 - with: | - image: ${{ steps.build_image.outputs.image }} - tags: ${{ steps.build_image.outputs.tags }} - registry: ${{ steps.registry_case.outputs.lowercase }} - username: ${{ env.REGISTRY_USER }} - password: ${{ env.REGISTRY_PASSWORD }} - extra-args: | - --disable-content-trust - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - if: github.event_name != 'pull_request' + name: ${{ inputs.image-name }}-${{ matrix.platform }} + retention-days: 1 + if-no-files-found: error + path: | + /tmp/outputs/digests/*.txt + + manifest: + runs-on: ubuntu-latest + needs: build + outputs: + manifest-digest: ${{ steps.push-manifest.outputs.DIGEST }} + steps: + - name: Fetch Build Outputs + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4 with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + pattern: ${{ inputs.image-name }}-* + merge-multiple: true + path: /tmp/artifacts - # Sign container - - uses: sigstore/cosign-installer@v3.7.0 - if: github.event_name != 'pull_request' + - name: Load Outputs + id: load-outputs + run: | + # Initialize an empty JSON object using jq + DIGESTS_JSON=$(jq -n '{}') + + # Loop through digest files and construct the JSON + for digest_file in /tmp/artifacts/*.txt; do + # Extract the platform from the file name + PLATFORM=$(basename $digest_file | rev | cut -d'-' -f1 | rev | cut -d'.' -f1) + DIGEST=$(cat $digest_file) + + # Add the platform and digest to the JSON object + DIGESTS_JSON=$(echo "$DIGESTS_JSON" | jq --arg key "$PLATFORM" --arg value "$DIGEST" '. + {($key): $value}') + done - - name: Sign container image - if: github.event_name != 'pull_request' + echo "DIGESTS_JSON: $DIGESTS_JSON" + DIGESTS_JSON=$(echo "$DIGESTS_JSON" | jq -c '.') + echo "DIGESTS_JSON=$DIGESTS_JSON" >> $GITHUB_OUTPUT + + - name: Create Manifest + id: create-manifest + env: + IMAGE_REGISTRY: ${{ inputs.image-registry }} + IMAGE_NAME: ${{ inputs.image-name }} run: | - cosign sign -y --key env://COSIGN_PRIVATE_KEY ${{ steps.registry_case.outputs.lowercase }}/${{ steps.build_image.outputs.image }}@${TAGS} + podman manifest create ${IMAGE_REGISTRY}/${IMAGE_NAME} + echo "MANIFEST=${IMAGE_REGISTRY}/${IMAGE_NAME}" >> $GITHUB_OUTPUT + + - name: Populate Manifest env: - TAGS: ${{ steps.push.outputs.outputs && fromJSON(steps.push.outputs.outputs).digest }} - COSIGN_EXPERIMENTAL: false - COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }} + IMAGE_REGISTRY: ${{ inputs.image-registry }} + IMAGE_NAME: ${{ inputs.image-name }} + MANIFEST: ${{ steps.create-manifest.outputs.MANIFEST }} + PLATFORMS: ${{ inputs.platforms }} + DIGESTS_JSON: ${{ steps.load-outputs.outputs.DIGESTS_JSON }} + run: | + DIGESTS=$(echo "$DIGESTS_JSON" | jq -c '.') + for platform in $(echo $PLATFORMS | tr ',' '\n'); do + echo "Adding platform: $platform" + # Get the digest for the platform + DIGEST=$(echo "$DIGESTS" | jq -r ".$platform") + + podman manifest add $MANIFEST \ + --arch $platform \ + $IMAGE_REGISTRY/$IMAGE_NAME@$DIGEST + done - - name: Echo outputs - if: github.event_name != 'pull_request' + - name: Login to GHCR + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + + - name: Push Manifest + id: push-manifest + env: + TAGS: ${{ inputs.tags }} + MANIFEST: ${{ steps.create-manifest.outputs.MANIFEST }} + IMAGE_REGISTRY: ${{ inputs.image-registry }} + IMAGE_NAME: ${{ inputs.image-name }} run: | - echo "${{ toJSON(steps.push.outputs) }}" + for tag in $(echo $TAGS | tr ',' '\n'); do + podman manifest push --digestfile=/tmp/digestfile --all=false $MANIFEST $IMAGE_REGISTRY/$IMAGE_NAME:$tag + done - check: - name: Check all builds successful - runs-on: ubuntu-latest - needs: [build] - steps: - - name: Exit on failure - if: ${{ needs.build.result == 'failure' }} - shell: bash - run: exit 1 - - name: Exit - shell: bash - run: exit 0 + # Temporarily populate the digest file with a dummy value + echo "dummy-digest" > /tmp/digestfile + + echo "DIGEST=$(cat /tmp/digestfile)" >> $GITHUB_OUTPUT + + - name: Setup Cosign + if: false + uses: sigstore/cosign-installer@v3.7.0 + + - name: Sign Image + if: false + env: + COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }} + IMAGE_REGISTRY: ${{ inputs.image-registry }} + IMAGE_NAME: ${{ inputs.image-name }} + DIGEST: ${{ steps.push-manifest.outputs.DIGEST }} + run: | + cosign sign -y --key env://COSIGN_PRIVATE_KEY ${IMAGE_REGISTRY}/${IMAGE_NAME}:${DIGEST} diff --git a/.github/workflows/reusable-generate-metadata.yml b/.github/workflows/reusable-generate-metadata.yml new file mode 100644 index 0000000..2c33381 --- /dev/null +++ b/.github/workflows/reusable-generate-metadata.yml @@ -0,0 +1,209 @@ +name: Generate Metadata + +on: + workflow_call: + inputs: + fedora-version: + description: "The version of Fedora to build" + required: true + type: string + image-registry: + description: "The registry to push the image to" + required: true + type: string + image-name: + description: "The name of the image to build" + required: true + type: string + kernel-flavor: + description: "The kernel to build" + required: true + type: string + is-latest: + description: "Is this the latest version" + required: false + type: boolean + default: false + outputs: + image-registry: + description: "The registry to push the image to" + value: ${{ jobs.generate_metadata.outputs.image-registry }} + image-name: + description: "The name of the image to build" + value: ${{ jobs.generate_metadata.outputs.image-name }} + build-args: + description: "The build arguments to pass to the build" + value: ${{ jobs.generate_metadata.outputs.build-args }} + tags: + description: "The tags to apply to the image" + value: ${{ jobs.generate_metadata.outputs.tags }} + +jobs: + generate_metadata: + runs-on: ubuntu-latest + outputs: + image-registry: ${{ inputs.image-registry }} + image-name: ${{ inputs.image-name }} + build-args: ${{ steps.set-metadata.outputs.BUILD_ARGS }} + tags: ${{ steps.set-metadata.outputs.TAGS }} + steps: + - name: Get Kernel Version + id: Version + uses: Wandalen/wretry.action@v3.7.3 + with: + attempt_limit: 3 + attempt_delay: 15000 + command: | + if [[ ${{ input.kernel-flavor }} =~ asus|fsync|fsync-ba|surface ]]; then + container_name="fq-$(uuidgen)" + dnf="podman exec $container_name dnf" + + podman run --entrypoint /bin/bash --name "$container_name" -dt "${{ env.build_image }}" + $dnf install -y dnf-plugins-core + fi + + coreos_kernel () { + coreos_version=${1} + image_linux=$(skopeo inspect docker://quay.io/fedora/fedora-coreos:${coreos_version} | jq -r '.Labels["ostree.linux"]') + # Pin a kernel here, gross workaround TODO: Make this cleaner + # if [[ "${{ input.kernel-flavor }}" == "coreos-stable" ]]; then + # image_linux="6.11.3-300.fc41.x86_64" + # fi + major_minor_patch=$(echo $image_linux | grep -oP '^\d+\.\d+\.\d+') + kernel_rel_part=$(echo $image_linux | grep -oP '^\d+\.\d+\.\d+\-\K([123][0]{2})') + arch=$(echo $image_linux | grep -oP 'fc\d+\.\K.*$') + + kernel_rel="$kernel_rel_part.fc${{ input.fedora-version }}" + kernel_version="$major_minor_patch-$kernel_rel.$arch" + URL="https://kojipkgs.fedoraproject.org/packages/kernel/"$major_minor_patch"/"$kernel_rel"/"$arch"/kernel-"$kernel_version".rpm" + echo "Querying koji for ${coreos_version} kernel: $kernel_version" + echo "$URL" + HTTP_RESP=$(curl -sI "$URL" | grep ^HTTP) + linux="" + if grep -qv "200 OK" <<< "${HTTP_RESP}"; then + echo "Koji failed to find $coreos_version kernel: $kernel_version" + case "$kernel_rel_part" in + "300") + kernel_rel_part="200" + ;; + "200") + kernel_rel_part="100" + ;; + "100") + ;; + *) + echo "unexpected kernel_rel_part ${kernel_rel_part}" + ;; + esac + kernel_rel="$kernel_rel_part.fc${{ inputs.fedora-version }}" + kernel_version="$major_minor_patch-$kernel_rel.$arch" + URL="https://kojipkgs.fedoraproject.org/packages/kernel/"$major_minor_patch"/"$kernel_rel"/"$arch"/kernel-"$kernel_version".rpm" + echo "Re-querying koji for ${coreos_version} kernel: $kernel_version" + echo "$URL" + HTTP_RESP=$(curl -sI "$URL" | grep ^HTTP) + if grep -qv "200 OK" <<< "${HTTP_RESP}"; then + echo "Koji failed to find $coreos_version kernel: $kernel_version" + fi + fi + if grep -q "200 OK" <<< "${HTTP_RESP}"; then + linux=$kernel_version + fi + } + + case ${{ inputs.kernel-flavor }} in + "asus") + $dnf copr enable -y lukenukem/asus-kernel + linux=$($dnf repoquery --repoid copr:copr.fedorainfracloud.org:lukenukem:asus-kernel --whatprovides kernel | sort -V | tail -n1 | sed 's/.*://') + ;; + "fsync") + $dnf copr enable -y sentry/kernel-fsync + linux=$($dnf repoquery --repoid copr:copr.fedorainfracloud.org:sentry:kernel-fsync --whatprovides kernel | sort -V | tail -n1 | sed 's/.*://') + ;; + "fsync-ba") + $dnf copr enable -y sentry/kernel-ba + linux=$($dnf repoquery --repoid copr:copr.fedorainfracloud.org:sentry:kernel-ba --whatprovides kernel | sort -V | tail -n1 | sed 's/.*://') + ;; + "bazzite") + latest="$(curl "https://api.github.com/repos/hhd-dev/kernel-bazzite/releases/latest" )" + linux=$(echo -E "$latest" | jq -r '.assets[].name' | grep -E 'kernel-.*.rpm' | grep "fc${{ inputs.fedora-version }}.x86_64" | head -1 | sed "s/kernel-//g" | sed "s/.rpm//g" ) + build_tag=$(echo -E $latest | jq -r '.tag_name') + ;; + "surface") + if [[ "${{ inputs.fedora-version }}" < 41 ]]; then + $dnf config-manager --add-repo=https://pkg.surfacelinux.com/fedora/linux-surface.repo + else + $dnf config-manager addrepo --from-repofile=https://pkg.surfacelinux.com/fedora/linux-surface.repo + fi + linux=$($dnf repoquery --repoid linux-surface --whatprovides kernel-surface | sort -V | tail -n1 | sed 's/.*://') + + ;; + "main") + base_image_name="base" + if [[ ${{ inputs.fedora-version }} > 40 ]]; then + base_image_name+="-atomic" + fi + linux=$(skopeo inspect docker://quay.io/fedora-ostree-desktops/$base_image_name:${{ inputs.fedora-version }} | jq -r '.Labels["ostree.linux"]' ) + ;; + "coreos-stable") + coreos_kernel stable + ;; + "coreos-testing") + coreos_kernel testing + ;; + *) + echo "unexpected kernel_flavor '${{ inputs.kernel-flavor }}' for query" + ;; + esac + if [ -z "$linux" ] || [ "null" = "$linux" ]; then + echo "inspected image linux version must not be empty or null" + exit 1 + fi + major=$(echo "$linux" | cut -d '.' -f 1) + minor=$(echo "$linux" | cut -d '.' -f 2) + patch=$(echo "$linux" | cut -d '.' -f 3) + kernel_major_minor_patch="${major}.${minor}.${patch}" + echo "Kernel Version is ${linux}" + echo "kernel_release=${linux}" >> $GITHUB_ENV + echo "kernel_build_tag=${build_tag}" >> $GITHUB_ENV + echo "kernel_major_minor_patch=${kernel_major_minor_patch}" >> $GITHUB_ENV + + - name: Generate Tags + id: generate-tags + run: | + tag="${{ env.kernel_release }}" + short_tag=$(echo ${{ env.kernel_major_minor_patch }} | cut -d "-" -f 1) + + BUILD_TAGS=() + BUILD_TAGS+=("${{ inputs.fedora-version }}") + BUILD_TAGS+=(${{ inputs.fedora-version }}-${short_tag}) + BUILD_TAGS+=(${{ inputs.fedora-version }}-${tag}) + BUILD_TAGS+=(${tag}) + + alias_tags=("${BUILD_TAGS[@]}") + + echo "Generated the following tags: " + for TAG in "${alias_tags[@]}"; do + echo "${TAG}" + done + + echo "TAGS=$(IFS=,; echo "${alias_tags[*]}")" >> $GITHUB_ENV + echo "date=$(date '+%Y%m%d.0')" >> $GITHUB_ENV + + - name: Generate Build Args + id: generate-build-args + run: | + BUILD_ARGS=() + + BUILD_ARGS+=("FEDORA_VERSION=${inputs.fedora-version}") + BUILD_ARGS+=("KERNEL_VERSION=${{ env.kernel_release }}") + BUILD_ARGS+=("KERNEL_BUILD_TAG=$${{ env.kernel_build_tag }}") + BUILD_ARGS+=("KERNEL_FLAVOR=${{ matrix.kernel_flavor }}") + BUILD_ARGS+=("DUAL_SIGN=true") + + echo "BUILD_ARGS=$(IFS=,; echo "${BUILD_ARGS[*]}")" >> $GITHUB_ENV + + - name: Set Metadata + id: set-metadata + run: | + echo "BUILD_ARGS=${{ env.BUILD_ARGS }}" >> $GITHUB_OUTPUT + echo "TAGS=${{ env.TAGS }}" >> $GITHUB_OUTPUT