diff --git a/.github/workflows/bpfcompat-example-hosted.yml b/.github/workflows/bpfcompat-example-hosted.yml index 95c9e010..51a373d1 100644 --- a/.github/workflows/bpfcompat-example-hosted.yml +++ b/.github/workflows/bpfcompat-example-hosted.yml @@ -41,6 +41,10 @@ jobs: set -euo pipefail if [[ -e /dev/kvm ]]; then echo "::notice::/dev/kvm present - VM validation is hardware-accelerated." + # Some hosted images expose /dev/kvm but the runner user is not in + # the kvm group; loosen perms so QEMU can open it. + sudo chmod 0666 /dev/kvm || true + ls -l /dev/kvm || true else echo "::warning::/dev/kvm not found - falling back to TCG software emulation (slower, still correct)." fi @@ -73,22 +77,40 @@ jobs: suite: suites/dev-functional.yaml suite-out: reports/ci-dev-functional-suite.json suite-markdown: reports/ci-dev-functional-suite.md - timeout: 12m + # Short while we stabilize hosted-runner guest boot: a stuck VM fails + # in ~5m instead of burning the full budget on the SSH-ready wait. + timeout: 5m concurrency: "1" build: "true" + - name: Dump guest serial + validator output on failure + if: failure() + shell: bash + run: | + echo "===== /dev/kvm ====="; ls -l /dev/kvm || true + for f in $(find .bpfcompat -type f \( -name serial.log -o -name qemu.log -o -name validator.stderr -o -name validator-result.json \) 2>/dev/null); do + echo "===== $f =====" + tail -n 120 "$f" || true + done + - name: Upload reports if: always() uses: actions/upload-artifact@v4 with: name: bpfcompat-reports-${{ github.run_id }} if-no-files-found: warn + # Allowlist only — never `.bpfcompat/runs/**` wholesale: the per-run + # dir also holds the generated SSH private key (id_ed25519), the + # cloud-init seed, and the disk overlay, none of which belong in a + # downloadable artifact. path: | reports/ci-dev-functional-suite.json reports/ci-dev-functional-suite.md reports/suites/dev-functional/*.json reports/suites/dev-functional/*.md .bpfcompat/runs/**/targets/**/serial.log + .bpfcompat/runs/**/targets/**/qemu.log .bpfcompat/runs/**/targets/**/libbpf.log .bpfcompat/runs/**/targets/**/validator-result.json .bpfcompat/runs/**/targets/**/validator.stderr + .bpfcompat/runs/**/targets/**/validator-exit-code diff --git a/README.md b/README.md index 6056d48a..4c93e8e7 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,20 @@ CO-RE makes a `.bpf.o` *portable in principle*; it does not guarantee it will `bpfcompat` answers the empirical question CO-RE leaves open: *does it actually load and attach here?* — by running the artifact in a real kernel. -## Try it in CI — no self-hosted runner +## Try it in CI without your own KVM box GitHub-hosted Linux runners now expose `/dev/kvm`, so the full QEMU VM -compatibility gate runs on a stock `ubuntu-latest` runner. No KVM box of your -own, no self-hosted runner. See +compatibility gate runs on a stock `ubuntu-latest` runner — no self-hosted KVM +machine required. This is proven end-to-end: [`.github/workflows/bpfcompat-example-hosted.yml`](.github/workflows/bpfcompat-example-hosted.yml) -for a copy-paste workflow; if a runner ever lacks KVM, validation degrades to -TCG software emulation (correct, just slower) instead of failing. +boots a disposable VM and runs the `dev-functional` suite (load + behavioral +execve) in **under two minutes**. + +One gotcha: some hosted images expose `/dev/kvm` but the runner user isn't in +the `kvm` group, so QEMU can't open it. The example workflow runs +`sudo chmod 0666 /dev/kvm` to handle that. If a runner genuinely lacks KVM, +validation degrades to TCG software emulation (correct, just slower) instead of +failing. ## Proof: a real Falco probe catches a real regression