name: eBPF Reachability Determinism on: pull_request: paths: - 'src/Signals/__Libraries/StellaOps.Signals.Ebpf/**' - 'src/Signals/__Tests/StellaOps.Signals.Ebpf.Tests/**' - 'tests/reachability/**' - '.gitea/workflows/ebpf-reachability-determinism.yml' - 'scripts/ebpf/**' push: branches: [ main ] paths: - 'src/Signals/__Libraries/StellaOps.Signals.Ebpf/**' - 'src/Signals/__Tests/StellaOps.Signals.Ebpf.Tests/**' - 'tests/reachability/**' - '.gitea/workflows/ebpf-reachability-determinism.yml' - 'scripts/ebpf/**' workflow_dispatch: {} jobs: # ============================================================================ # Multi-Kernel eBPF CO-RE Testing (3 major kernel versions) # ============================================================================ multi-kernel-tests: strategy: fail-fast: false matrix: include: # Kernel 5.4 LTS (Ubuntu 20.04) - kernel_version: "5.4" distro: "focal" image: "ubuntu:20.04" dotnet_install: "true" runner: ${{ vars.KERNEL_5_4_RUNNER || 'ubuntu-latest' }} # Kernel 5.15 LTS (Ubuntu 22.04) - kernel_version: "5.15" distro: "jammy" image: "ubuntu:22.04" dotnet_install: "true" runner: ${{ vars.KERNEL_5_15_RUNNER || 'ubuntu-22.04' }} # Kernel 6.x (Ubuntu 24.04) - kernel_version: "6.x" distro: "noble" image: "ubuntu:24.04" dotnet_install: "true" runner: ${{ vars.KERNEL_6_X_RUNNER || 'ubuntu-24.04' }} runs-on: ${{ matrix.runner }} name: "Kernel ${{ matrix.kernel_version }} (${{ matrix.distro }})" env: DOTNET_NOLOGO: 1 DOTNET_CLI_TELEMETRY_OPTOUT: 1 DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: 1 TZ: UTC STELLAOPS_UPDATE_FIXTURES: "false" steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Report kernel version run: | echo "==============================================" echo "Kernel ${{ matrix.kernel_version }} Test (${{ matrix.distro }})" echo "==============================================" uname -a cat /etc/os-release | head -5 echo "" echo "BTF availability:" if [ -f /sys/kernel/btf/vmlinux ]; then echo " Built-in BTF: YES" ls -la /sys/kernel/btf/vmlinux else echo " Built-in BTF: NO (external BTF may be required)" fi echo "" echo "eBPF kernel config:" if [ -f /boot/config-$(uname -r) ]; then grep -E "CONFIG_BPF|CONFIG_DEBUG_INFO_BTF" /boot/config-$(uname -r) 2>/dev/null || echo " Config not readable" else echo " Kernel config not available" fi - name: Setup .NET 10 uses: actions/setup-dotnet@v4 with: dotnet-version: 10.0.x - name: Cache NuGet packages uses: actions/cache@v4 with: path: | ~/.nuget/packages .nuget/packages key: ebpf-${{ matrix.distro }}-nuget-${{ hashFiles('src/Signals/**/*.csproj') }} - name: Restore run: dotnet restore src/Signals/__Tests/StellaOps.Signals.Ebpf.Tests/StellaOps.Signals.Ebpf.Tests.csproj --configfile nuget.config - name: Build run: dotnet build src/Signals/__Tests/StellaOps.Signals.Ebpf.Tests/StellaOps.Signals.Ebpf.Tests.csproj -c Release --no-restore - name: Run all eBPF tests run: | echo "Running all eBPF tests on kernel ${{ matrix.kernel_version }}..." dotnet test src/Signals/__Tests/StellaOps.Signals.Ebpf.Tests/StellaOps.Signals.Ebpf.Tests.csproj \ -c Release --no-build \ --logger "trx;LogFileName=ebpf-tests-${{ matrix.distro }}.trx" \ --logger "console;verbosity=minimal" - name: Record kernel compatibility run: | echo "Kernel ${{ matrix.kernel_version }} (${{ matrix.distro }}): PASSED" >> $GITHUB_STEP_SUMMARY echo "Host kernel: $(uname -r)" >> $GITHUB_STEP_SUMMARY - name: Upload test results if: always() uses: actions/upload-artifact@v4 with: name: ebpf-test-results-kernel-${{ matrix.kernel_version }} path: | **/ebpf-tests-${{ matrix.distro }}.trx retention-days: 7 # ============================================================================ # Docker-based Multi-Kernel Tests (for environments without native runners) # ============================================================================ docker-kernel-tests: strategy: fail-fast: false matrix: include: # Ubuntu 20.04 (Kernel 5.4 compatible) - kernel_version: "5.4" distro: "focal" base_image: "ubuntu:20.04" # Ubuntu 22.04 (Kernel 5.15 compatible) - kernel_version: "5.15" distro: "jammy" base_image: "ubuntu:22.04" # Ubuntu 24.04 (Kernel 6.x compatible) - kernel_version: "6.x" distro: "noble" base_image: "ubuntu:24.04" runs-on: ubuntu-latest name: "Docker: Kernel ${{ matrix.kernel_version }} (${{ matrix.distro }})" steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Build and test in Docker run: | chmod +x scripts/ebpf/docker-kernel-test.sh scripts/ebpf/docker-kernel-test.sh "${{ matrix.base_image }}" "${{ matrix.kernel_version }}" "${{ matrix.distro }}" - name: Upload test results if: always() uses: actions/upload-artifact@v4 with: name: docker-test-results-${{ matrix.distro }} path: | out/ebpf-tests-${{ matrix.distro }}.trx retention-days: 7 # ============================================================================ # Cross-Distribution Tests (glibc vs musl) # ============================================================================ cross-distro-tests: strategy: fail-fast: false matrix: include: - image: "mcr.microsoft.com/dotnet/sdk:10.0" distro: "ubuntu-glibc" libc: "glibc" - image: "mcr.microsoft.com/dotnet/sdk:10.0-alpine" distro: "alpine-musl" libc: "musl" runs-on: ubuntu-latest container: image: ${{ matrix.image }} name: "Distro: ${{ matrix.distro }} (${{ matrix.libc }})" env: DOTNET_NOLOGO: 1 DOTNET_CLI_TELEMETRY_OPTOUT: 1 DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: 1 TZ: UTC STELLAOPS_UPDATE_FIXTURES: "false" steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Report environment run: | echo "==============================================" echo "Cross-distribution test: ${{ matrix.distro }}" echo "==============================================" uname -a cat /etc/os-release | head -3 echo "libc: ${{ matrix.libc }}" dotnet --version - name: Restore run: dotnet restore src/Signals/__Tests/StellaOps.Signals.Ebpf.Tests/StellaOps.Signals.Ebpf.Tests.csproj --configfile nuget.config - name: Build run: dotnet build src/Signals/__Tests/StellaOps.Signals.Ebpf.Tests/StellaOps.Signals.Ebpf.Tests.csproj -c Release --no-restore - name: Run all tests run: | dotnet test src/Signals/__Tests/StellaOps.Signals.Ebpf.Tests/StellaOps.Signals.Ebpf.Tests.csproj \ -c Release --no-build \ --logger "trx;LogFileName=tests-${{ matrix.distro }}.trx" \ --logger "console;verbosity=minimal" - name: Upload test results if: always() uses: actions/upload-artifact@v4 with: name: distro-test-results-${{ matrix.distro }} path: | **/tests-${{ matrix.distro }}.trx retention-days: 7 # ============================================================================ # Determinism Tests # ============================================================================ determinism-tests: runs-on: ubuntu-latest env: DOTNET_NOLOGO: 1 DOTNET_CLI_TELEMETRY_OPTOUT: 1 DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: 1 TZ: UTC STELLAOPS_UPDATE_FIXTURES: "false" steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup .NET 10 uses: actions/setup-dotnet@v4 with: dotnet-version: 10.0.x - name: Restore run: dotnet restore src/Signals/__Tests/StellaOps.Signals.Ebpf.Tests/StellaOps.Signals.Ebpf.Tests.csproj --configfile nuget.config - name: Build run: dotnet build src/Signals/__Tests/StellaOps.Signals.Ebpf.Tests/StellaOps.Signals.Ebpf.Tests.csproj -c Release --no-restore - name: Run determinism tests run: | dotnet test src/Signals/__Tests/StellaOps.Signals.Ebpf.Tests/StellaOps.Signals.Ebpf.Tests.csproj \ -c Release --no-build \ --filter "Category=Determinism" \ --logger "trx;LogFileName=determinism-tests.trx" \ --logger "console;verbosity=normal" - name: Verify golden file integrity run: | if git diff --exit-code tests/reachability/fixtures/ebpf/golden/; then echo "Golden files unchanged - determinism verified" else echo "ERROR: Golden files were modified during test run!" exit 1 fi # ============================================================================ # Golden File Validation # ============================================================================ golden-file-validation: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Validate golden files run: | for file in tests/reachability/fixtures/ebpf/golden/*.ndjson; do if [ -f "$file" ]; then echo "Checking $file..." while IFS= read -r line || [ -n "$line" ]; do if [ -n "$line" ]; then echo "$line" | jq -e . > /dev/null 2>&1 || { echo "Invalid JSON in $file"; exit 1; } fi done < "$file" fi done echo "All golden files valid" # ============================================================================ # Summary # ============================================================================ summary: needs: [multi-kernel-tests, docker-kernel-tests, cross-distro-tests, determinism-tests, golden-file-validation] runs-on: ubuntu-latest if: always() steps: - name: Check results run: | echo "==============================================" echo "eBPF Reachability Test Summary" echo "==============================================" echo "" echo "Multi-kernel tests (native): ${{ needs.multi-kernel-tests.result }}" echo "Multi-kernel tests (Docker): ${{ needs.docker-kernel-tests.result }}" echo "Cross-distro tests: ${{ needs.cross-distro-tests.result }}" echo "Determinism tests: ${{ needs.determinism-tests.result }}" echo "Golden file validation: ${{ needs.golden-file-validation.result }}" if [[ "${{ needs.multi-kernel-tests.result }}" != "success" ]] || \ [[ "${{ needs.docker-kernel-tests.result }}" != "success" ]] || \ [[ "${{ needs.cross-distro-tests.result }}" != "success" ]] || \ [[ "${{ needs.determinism-tests.result }}" != "success" ]] || \ [[ "${{ needs.golden-file-validation.result }}" != "success" ]]; then echo "ERROR: One or more test jobs failed!" exit 1 fi echo "All tests passed across kernel versions 5.4, 5.15, and 6.x!"