Skip to content

Workflow (by @smitesh-sutaria via push) #52

Workflow (by @smitesh-sutaria via push)

Workflow (by @smitesh-sutaria via push) #52

---
# SPDX-FileCopyrightText: (C) 2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
name: "QEMU & Kubevirt: Build, Trivy & ClamAV Scan"
run-name: "Workflow (by @${{ github.actor }} via ${{ github.event_name }})"
# Only run at most 1 workflow concurrently per PR, unlimited for branches
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
on:
pull_request:
branches:
- main
push:
branches:
- main
tags:
- "*"
jobs:
qemu-build-and-scan:
permissions:
contents: read
runs-on: ubuntu-24.04
outputs:
qemu-artifact-id: ${{ steps.upload-qemu.outputs.artifact-id }}
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
persist-credentials: false
fetch-depth: 0 # All history, not just latest commit
ref: ${{ github.event.pull_request.head.sha }} # Check out the actual commit, not a fake merge commit
- name: Setup Tools & Common Variables
uses: ./.github/actions/setup-tools
with:
go: "false"
- name: Cache QEMU source & build directory
id: cache-qemu
uses: actions/cache@v4
env:
cache-name: cache-qemu
with:
path: workspace/qemu-8.2.1
# Use the hash of the document this workflow is based on to decide whether the build should be re-run or not
key: qemu-binary-${{ hashFiles('kubevirt-patch/README.md') }}
- name: Build and patch QEMU
if: ${{ steps.cache-qemu.outputs.cache-hit != 'true' }}
# Each logical block here is copied exactly from a code block in kubevirt-patch/README.md
run: |
mkdir -p workspace
cd workspace
wget -N --no-check-certificate https://download.01.org/intel-linux-overlay/ubuntu/pool/main/q/qemu/qemu_8.2.1+ppa1-noble9.debian.tar.xz
mkdir qemu_8.2.1+ppa1-noble9.debian
tar -xf 'qemu_8.2.1+ppa1-noble9.debian.tar.xz' -C 'qemu_8.2.1+ppa1-noble9.debian'
wget -N --no-check-certificate https://download.qemu.org/qemu-8.2.1.tar.xz
tar -xf qemu-8.2.1.tar.xz
cd qemu-8.2.1
cp -r ../qemu_8.2.1+ppa1-noble9.debian/debian/patches/sriov/ .
git apply ./sriov/*.patch
./tests/lcitool/libvirt-ci/bin/lcitool --data-dir ./tests/lcitool dockerfile centos-stream-9 qemu > Dockerfile.centos-stream9
perl -p -i -e 's|zstd &&|zstd libslirp-devel liburing-devel libbpf-devel libblkio-devel &&|g' Dockerfile.centos-stream9
docker build -t qemu_build:centos-stream9 -f Dockerfile.centos-stream9 .
cat <<EOF > buildscript.sh
#!/bin/bash
set -x
set -e
cd /src
rm -rf build
./configure --prefix=/usr --enable-kvm --disable-xen --enable-libusb --enable-debug-info --enable-debug --enable-sdl --enable-vhost-net --enable-spice --disable-debug-tcg --enable-opengl --enable-gtk --enable-virtfs --target-list=x86_64-softmmu --audio-drv-list=pa --firmwarepath=/usr/share/qemu-firmware:/usr/share/ipxe/qemu:/usr/share/seavgabios:/usr/share/seabios:/usr/share/qemu-kvm/ --disable-spice
mkdir -p build
cd build
ninja
ninja install
EOF
chmod +x buildscript.sh
docker run \
-v $(pwd):/src:Z \
-w /src \
--entrypoint=/src/buildscript.sh \
--security-opt label=disable \
qemu_build:centos-stream9
ls -la build/qemu-system-x86_64
sha256sum build/qemu-system-x86_64
- name: Upload qemu-system-x86_64 artifact
id: upload-qemu
uses: actions/upload-artifact@v4
with:
name: qemu-artifact
path: |
workspace/qemu-8.2.1/build/qemu-system-x86_64
- name: trivy qemu source scan
continue-on-error: true
shell: bash
run: |
cd workspace/qemu-8.2.1
trivy --version
which trivy
trivy image --download-db-only
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/html.tpl -o trivy-html.tpl
# Use the downloaded template
trivy fs . --format template --template "@trivy-html.tpl" --exit-code 1 --severity MEDIUM,HIGH,CRITICAL -o "trivy_code_scan_qemu.html"
- name: Upload trivy reports
uses: actions/upload-artifact@v4
with:
name: trivy-code-scan-results-core
path: |
workspace/qemu-8.2.1/trivy_code_scan_qemu.html
- name: ClamAV QEMU Antivirus Scan
continue-on-error: true
shell: bash
run: |
echo "Starting ClamAV scan on workspace/qemu-8.2.1/build/..."
docker run --rm \
--mount type=bind,source=./workspace/qemu-8.2.1/build/,target=/scandir \
clamav/clamav:stable \
clamscan --recursive --log=/scandir/clamav-scan-report.log \
/scandir
SCAN_EXIT_CODE=$?
sudo chown $USER:$USER workspace/qemu-8.2.1/build/clamav-scan-report.log 2>/dev/null || true
if [ $SCAN_EXIT_CODE -ne 0 ]; then
echo "ClamAV scan failed or found issues"
exit 1
fi
- name: Upload QEMU Antivirus Report
uses: actions/upload-artifact@v4
with:
name: antivirus-qemu
path: workspace/qemu-8.2.1/build/clamav-scan-report.log
kubevirt-build-and-scan:
needs: qemu-build-and-scan
permissions:
contents: read
runs-on: ubuntu-24.04
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
persist-credentials: false
fetch-depth: 0 # All history, not just latest commit
ref: ${{ github.event.pull_request.head.sha }} # Check out the actual commit, not a fake merge commit
- name: Setup Tools & Common Variables
uses: ./.github/actions/setup-tools
with:
go: "false"
- name: Cache Kubevirt output artifacts
id: cache-kubevirt
uses: actions/cache@v4
env:
cache-name: cache-kubevirt
with:
path: workspace/kubevirt-artifacts
# Use the hash of the document this workflow is based on to decide whether the build should be re-run or not
# NOTE: This must be a superset of the qemu cache hashFiles above. In other words if qemu needs to be rebuilt, so does kubevirt
key: kubevirt-binary-${{ hashFiles('kubevirt-patch/0001-Bump-dependency-versions-for-kubevirt-v1.5.0.patch', 'kubevirt-patch/0001-Patching-Kubevirt-with-GTK-libraries_v1.patch', 'kubevirt-patch/README.md') }}
######################################################################################################3
# The kubevirt workflow requires 30+ GB of free space to run successfully
# These steps delete many unnecessary files from the actions runner so that enough space is available
# These pieces are only run if a kubevirt build needs to be done
- name: Disable man-db to make package install and removal faster
if: ${{ steps.cache-kubevirt.outputs.cache-hit != 'true' }}
run: |
echo 'set man-db/auto-update false' | sudo debconf-communicate >/dev/null
sudo dpkg-reconfigure man-db
- name: Free Disk Space (Ubuntu)
if: ${{ steps.cache-kubevirt.outputs.cache-hit != 'true' }}
# This is a fork of the popular jlumbroso/free-disk-space@main with faster performance
# @byron-marohn reviewed all the code in this specific commit on Jun 19 2025
uses: xc2/free-disk-space@fbe203b3788f2bebe2c835a15925da303eaa5efe
with:
tool-cache: true
android: true
dotnet: true
haskell: true
large-packages: true
swap-storage: false # Retain swap file for improved build performance
######################################################################################################3
- name: Run local docker registry
if: ${{ steps.cache-kubevirt.outputs.cache-hit != 'true' }}
run: |
# Run a local registry
docker run -d -p 5000:5000 --name registry registry:2.7
- name: Download QEMU artifact
if: ${{ steps.cache-kubevirt.outputs.cache-hit != 'true' }}
uses: actions/download-artifact@v4
with:
artifact-ids: ${{ needs.qemu-build-and-scan.outputs.qemu-artifact-id }}
path: . # Will unpack into a folder with the name used in upload-artifact, containing the binary
- name: Build and patch kubevirt
if: ${{ steps.cache-kubevirt.outputs.cache-hit != 'true' }}
# Each logical block here is copied exactly from a code block in kubevirt-patch/README.md
run: |
mkdir -p $EDV_HOME/workspace
cd $EDV_HOME/workspace
git clone https://github.com/kubevirt/kubevirt.git
cd kubevirt
git checkout v1.5.0
git apply $EDV_HOME/kubevirt-patch/0001-Bump-dependency-versions-for-kubevirt-v1.5.0.patch
git apply $EDV_HOME/kubevirt-patch/0001-Patching-Kubevirt-with-GTK-libraries_v1.patch
mkdir build
cp $EDV_HOME/qemu-artifact/qemu-system-x86_64 build/qemu-system-x86_64
QEMU_SHA256="$(sha256sum ./build/qemu-system-x86_64 | cut -d ' ' -f 1)"
echo "QEMU_SHA256=$QEMU_SHA256"
perl -p -i -e "s|<SHA256SUM_OF_PATCHED_QEMU>|$QEMU_SHA256|g" WORKSPACE
export DOCKER_PREFIX=localhost:5000
export DOCKER_TAG=$EDV_VERSION
make rpm-deps
make all
make bazel-build-images
make push
make manifests
echo "Partition sizes & free space following build:"
df -h
- name: Export kubevirt build artifacts to output directory
if: ${{ steps.cache-kubevirt.outputs.cache-hit != 'true' }}
shell: bash
run: |
mkdir -p $EDV_HOME/workspace/kubevirt-artifacts
cd $EDV_HOME/workspace/kubevirt-artifacts
cp $EDV_HOME/workspace/kubevirt/_out/manifests/release/kubevirt-operator.yaml .
cp $EDV_HOME/workspace/kubevirt/_out/manifests/release/kubevirt-cr.yaml .
# Modify the generated operator yaml to specify images by tag, rather than sha256
cat kubevirt-operator.yaml | sed '/name: VIRT_API_SHASUM/,/name: KUBEVIRT_VERSION/ { /name: KUBEVIRT_VERSION/!d }' > kubevirt-operator.new.yaml
perl -p -i -e "s|virt-operator\@sha256.*\$|virt-operator:$EDV_VERSION|g" kubevirt-operator.new.yaml
mv -f kubevirt-operator.new.yaml kubevirt-operator.yaml
docker image pull localhost:5000/sidecar-shim:$EDV_VERSION
docker image pull localhost:5000/virt-api:$EDV_VERSION
docker image pull localhost:5000/virt-handler:$EDV_VERSION
docker image pull localhost:5000/virt-launcher:$EDV_VERSION
docker image pull localhost:5000/virt-operator:$EDV_VERSION
docker image pull localhost:5000/virt-controller:$EDV_VERSION
docker save -o sidecar-shim.tar localhost:5000/sidecar-shim:$EDV_VERSION
docker save -o virt-api.tar localhost:5000/virt-api:$EDV_VERSION
docker save -o virt-controller.tar localhost:5000/virt-controller:$EDV_VERSION
docker save -o virt-handler.tar localhost:5000/virt-handler:$EDV_VERSION
docker save -o virt-launcher.tar localhost:5000/virt-launcher:$EDV_VERSION
docker save -o virt-operator.tar localhost:5000/virt-operator:$EDV_VERSION
tar cvzf intel-idv-kubevirt-$EDV_VERSION.tar.gz *.tar *.yaml
echo "Contents of $(pwd):"
ls -hal
echo "Partition sizes & free space following export:"
df -h
# If the cache was loaded, then the artifacts folder contains valid images which are still valid for this version
# (i.e. nothing changed about kubevirt or qemu, so there was no need to rebuild the images)
# However, they will have the old tag - whatever the tag was when they were built last
# Need to re-tag them and import them into docker so they're usable by subsequent steps
- name: Reload and re-tag cached images
if: ${{ steps.cache-kubevirt.outputs.cache-hit == 'true' }}
shell: bash
run: |
cd $EDV_HOME/workspace/kubevirt-artifacts
# Extract the old version from the kubevirt-operator file
OLD_VERSION="$(cat kubevirt-operator.yaml | grep -A 1 KUBEVIRT_VERSION | grep value: | perl -p -e 's|^.*value: (.*)$|\1|g')"
# Replace exactly OLD_VERSION with EDV_VERSION, even if they somehow contain regular expression metacharacters
perl -p -i -e "s|\\Q$OLD_VERSION\\E|$EDV_VERSION|g" kubevirt-operator.yaml
docker image load -i $EDV_HOME/workspace/kubevirt-artifacts/sidecar-shim.tar
docker image load -i $EDV_HOME/workspace/kubevirt-artifacts/virt-api.tar
docker image load -i $EDV_HOME/workspace/kubevirt-artifacts/virt-controller.tar
docker image load -i $EDV_HOME/workspace/kubevirt-artifacts/virt-handler.tar
docker image load -i $EDV_HOME/workspace/kubevirt-artifacts/virt-launcher.tar
docker image load -i $EDV_HOME/workspace/kubevirt-artifacts/virt-operator.tar
docker tag localhost:5000/sidecar-shim:$OLD_VERSION localhost:5000/sidecar-shim:$EDV_VERSION
docker tag localhost:5000/virt-api:$OLD_VERSION localhost:5000/virt-api:$EDV_VERSION
docker tag localhost:5000/virt-controller:$OLD_VERSION localhost:5000/virt-controller:$EDV_VERSION
docker tag localhost:5000/virt-handler:$OLD_VERSION localhost:5000/virt-handler:$EDV_VERSION
docker tag localhost:5000/virt-launcher:$OLD_VERSION localhost:5000/virt-launcher:$EDV_VERSION
docker tag localhost:5000/virt-operator:$OLD_VERSION localhost:5000/virt-operator:$EDV_VERSION
docker save -o sidecar-shim.tar localhost:5000/sidecar-shim:$EDV_VERSION
docker save -o virt-api.tar localhost:5000/virt-api:$EDV_VERSION
docker save -o virt-controller.tar localhost:5000/virt-controller:$EDV_VERSION
docker save -o virt-handler.tar localhost:5000/virt-handler:$EDV_VERSION
docker save -o virt-launcher.tar localhost:5000/virt-launcher:$EDV_VERSION
docker save -o virt-operator.tar localhost:5000/virt-operator:$EDV_VERSION
rm intel-idv-kubevirt*.tar.gz
tar cvzf intel-idv-kubevirt-$EDV_VERSION.tar.gz *.tar *.yaml
echo "Contents of $(pwd):"
ls -hal
- name: Upload kubevirt artifacts
uses: actions/upload-artifact@v4
with:
name: kubevirt-artifacts
path: |
workspace/kubevirt-artifacts/intel-idv-kubevirt-${{ env.EDV_VERSION }}.tar.gz
- name: Trivy Image Scan
continue-on-error: true
shell: bash
run: |
mkdir -p workspace/kubevirt-trivy
cd workspace/kubevirt-trivy
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/html.tpl -o trivy-html.tpl
trivy image "localhost:5000/sidecar-shim:$EDV_VERSION" --ignore-unfixed --format template --template "@trivy-html.tpl" -o trivy_sidecar-shim.html
trivy image "localhost:5000/virt-api:$EDV_VERSION" --ignore-unfixed --format template --template "@trivy-html.tpl" -o trivy_virt-api.html
trivy image "localhost:5000/virt-controller:$EDV_VERSION" --ignore-unfixed --format template --template "@trivy-html.tpl" -o trivy_virt-controller.html
trivy image "localhost:5000/virt-handler:$EDV_VERSION" --ignore-unfixed --format template --template "@trivy-html.tpl" -o trivy_virt-handler.html
trivy image "localhost:5000/virt-launcher:$EDV_VERSION" --ignore-unfixed --format template --template "@trivy-html.tpl" -o trivy_virt-launcher.html
trivy image "localhost:5000/virt-operator:$EDV_VERSION" --ignore-unfixed --format template --template "@trivy-html.tpl" -o trivy_virt-operator.html
trivy image --quiet --format spdx-json --output trivy_sidecar-shim.spdx.json "localhost:5000/sidecar-shim:$EDV_VERSION"
trivy image --quiet --format spdx-json --output trivy_virt-api.spdx.json "localhost:5000/virt-api:$EDV_VERSION"
trivy image --quiet --format spdx-json --output trivy_virt-controller.spdx.json "localhost:5000/virt-controller:$EDV_VERSION"
trivy image --quiet --format spdx-json --output trivy_virt-handler.spdx.json "localhost:5000/virt-handler:$EDV_VERSION"
trivy image --quiet --format spdx-json --output trivy_virt-launcher.spdx.json "localhost:5000/virt-launcher:$EDV_VERSION"
trivy image --quiet --format spdx-json --output trivy_virt-operator.spdx.json "localhost:5000/virt-operator:$EDV_VERSION"
- name: Upload Trivy Image Report
uses: actions/upload-artifact@v4
with:
name: Trivy kubevirt image scan
path: |
workspace/kubevirt-trivy/trivy_sidecar-shim.html
workspace/kubevirt-trivy/trivy_virt-api.html
workspace/kubevirt-trivy/trivy_virt-controller.html
workspace/kubevirt-trivy/trivy_virt-handler.html
workspace/kubevirt-trivy/trivy_virt-launcher.html
workspace/kubevirt-trivy/trivy_virt-operator.html
workspace/kubevirt-trivy/trivy_sidecar-shim.spdx.json
workspace/kubevirt-trivy/trivy_virt-api.spdx.json
workspace/kubevirt-trivy/trivy_virt-controller.spdx.json
workspace/kubevirt-trivy/trivy_virt-handler.spdx.json
workspace/kubevirt-trivy/trivy_virt-launcher.spdx.json
workspace/kubevirt-trivy/trivy_virt-operator.spdx.json