From a8738c589745b207010d43dcaed93ef2f7d1bf2f Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Sat, 11 Jul 2026 11:10:27 +0200 Subject: [PATCH] ci: Add virtio-villain test suite job Add a GitHub Actions job that runs the virtio-villain suite against cloud-hypervisor, giving continuous coverage of how the virtio device model responds to guest input that violates the driver side rules of the virtio specification. The suite drives the device model from the guest side with out of spec virtqueue input, malformed descriptor chains, transport register abuse, and device specific requests, then checks that each violation is handled without crashing the device or leaving it wedged. This makes a class of guest triggered failures a signal that shows up on every relevant change rather than found by chance. The job builds cloud-hypervisor with the kvm feature, clones virtio-villain at a pinned tag, builds its initramfs, and runs the tests in short lived VMs, rerunning a wedged batch in isolation so a failure is attributed to the offending test. Results reach the run summary page, and the JUnit report plus per test logs upload as an artifact. The compiled harness, the initramfs, and the fetched guest kernel are cached under the resolved villain commit, so an unchanged pin skips the rebuild. Signed-off-by: Anatol Belski Assisted-by: Claude:Opus-4.8 Signed-off-by: Anatol Belski --- .github/workflows/ci.yaml | 78 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 49a8055e7..e4fb15c4b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -846,6 +846,84 @@ jobs: # - name: Run rate-limiter integration tests # timeout-minutes: 20 # run: scripts/dev_cli.sh tests --integration-rate-limiter + virtio-villain: + name: virtio-villain + needs: [preflight, dco, quality, build] + if: needs.preflight.outputs.full == 'true' + timeout-minutes: 60 + runs-on: ubuntu-latest + env: + VILLAIN_REPO: https://github.com/weltling/virtio-villain.git + VILLAIN_REF: v0.5.0 + steps: + - name: Code checkout + uses: actions/checkout@v7 + with: + fetch-depth: 0 + - name: Verify KVM is available + run: | + set -eufo pipefail + test -e /dev/kvm || { echo "::error::/dev/kvm missing on runner"; exit 1; } + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + - name: Install dependencies + run: | + set -eufo pipefail + sudo apt-get update + sudo apt-get install -y musl-tools cpio gzip python3 + sudo apt-get install -y virtiofsd || true + - name: Build cloud-hypervisor (kvm) + run: cargo build --locked --release --bin cloud-hypervisor --no-default-features --features kvm + - name: Clone virtio-villain + id: villain-src + run: | + set -eufo pipefail + git clone "$VILLAIN_REPO" virtio-villain + git -C virtio-villain checkout "$VILLAIN_REF" + echo "sha=$(git -C virtio-villain rev-parse HEAD)" >> "$GITHUB_OUTPUT" + - name: Cache virtio-villain build + id: villain-cache + uses: actions/cache@v4 + with: + path: virtio-villain/target + key: virtio-villain-${{ runner.os }}-${{ runner.arch }}-${{ steps.villain-src.outputs.sha }} + - name: Build virtio-villain initramfs + if: steps.villain-cache.outputs.cache-hit != 'true' + run: make -C virtio-villain -j"$(nproc)" initramfs + - name: Run virtio-villain suite + working-directory: virtio-villain + run: | + set -eufo pipefail + mkdir -p villain-logs + sudo ./run \ + --vmm "${GITHUB_WORKSPACE}/target/release/cloud-hypervisor" \ + --blk-queues 2 --net-queues 2 --cpus 2 --memory 256M \ + --order=fast \ + --jobs 4 --batch 10 --timeout 45 --log-dir villain-logs \ + --format junit --output villain-logs/results.xml \ + | tee villain-logs/run.out + - name: Publish results to run summary + if: always() + working-directory: virtio-villain + run: | + set -eufo pipefail + { + echo '## virtio-villain' + echo '```' + if [ -f villain-logs/run.out ]; then + sed -n '/tests passed/,$p' villain-logs/run.out + else + echo 'no results (suite did not produce output)' + fi + echo '```' + } >> "$GITHUB_STEP_SUMMARY" + - name: Upload virtio-villain logs + if: always() + uses: actions/upload-artifact@v7 + with: + name: virtio-villain-logs + path: virtio-villain/villain-logs + if-no-files-found: ignore # The single required-status check. Branch protection requires this one job. all-green: name: all-green