sbpf-linker 0.2.0

Upstream BPF linker for SBPF V0/V3 programs
name: CI

on:
  push:
    branches: [master]
  pull_request:
    branches: [master]

env:
  CARGO_TERM_COLOR: always
  RUST_TOOLCHAIN: nightly-2026-08-18

permissions:
  contents: read
  packages: read

jobs:
  fmt:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@master
        with:
          toolchain: nightly
          components: rustfmt
      - run: cargo fmt --all -- --check

  clippy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@master
        with:
          toolchain: nightly
          components: clippy
      - uses: Swatinem/rust-cache@v2
      - run: >-
          cargo clippy --no-default-features
          --features bpf-linker/llvm-23,bpf-linker/no-llvm-linking
          --all-targets -- -D warnings

  cargo-install:
    name: cargo install (${{ matrix.os }})
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os:
          - ubuntu-24.04
          - macos-15
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@master
        with:
          toolchain: ${{ env.RUST_TOOLCHAIN }}
      - uses: Swatinem/rust-cache@v2
      - name: Install from source using Rust's LLVM
        run: >-
          cargo install --path . --locked
          --root target/cargo-install
      - name: Verify installed binary
        run: |
          output=$(rustup run "$RUST_TOOLCHAIN" \
            target/cargo-install/bin/sbpf-linker --version)
          echo "$output"
          grep -F "LLVM 23" <<< "$output"
      - name: Verify LLVM is loaded through the runtime proxy
        run: |
          case "$RUNNER_OS" in
            Linux)
              ! readelf -d target/cargo-install/bin/sbpf-linker |
                grep -F libLLVM
              ;;
            macOS)
              ! otool -L target/cargo-install/bin/sbpf-linker |
                grep -F libLLVM
              ;;
          esac

  test-harness:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@master
        with:
          toolchain: ${{ env.RUST_TOOLCHAIN }}
          components: rust-src
      - uses: Swatinem/rust-cache@v2
      - name: Install FileCheck
        run: sudo apt-get update && sudo apt-get install -y llvm-18-tools
      - run: cargo test -- --nocapture
        
  coverage:
    name: coverage (nightly)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: dtolnay/rust-toolchain@master
        with:
          toolchain: ${{ env.RUST_TOOLCHAIN }}
          components: rust-src, llvm-tools-preview

      - uses: Swatinem/rust-cache@v2

      - name: Install FileCheck
        run: |
          sudo apt-get update
          sudo apt-get install -y llvm-18-tools

      - name: Install cargo-llvm-cov
        uses: taiki-e/install-action@cargo-llvm-cov

      # The harness normally builds this sysroot itself. '
      # Build it first so host coverage flags do not reach the nested bpfel Cargo build.  
      # TODO: if ci duration becomes an issue, extract sysroot creation into an xtask command to avoid running
      # the compile-test suite twice.
      - name: Build BPF sysroot
        run: cargo test --test tests compile_test -- --nocapture

      - name: Generate code coverage
        env:
          BPFEL_SYSROOT_DIR: ${{ github.workspace }}/target/sysroot
          MINIMUM_LINE_COVERAGE: 83
        run: |
          set -o pipefail

          coverage_status=0 
          cargo llvm-cov \
            --package sbpf-linker \
            --all-targets \
            --color never \
            --fail-under-lines "$MINIMUM_LINE_COVERAGE" \
            | tee coverage.txt || coverage_status=$?

          {
            echo "## Code coverage"
            echo
            echo "Required line coverage: **${MINIMUM_LINE_COVERAGE}%**"
            echo
            echo '```text'
            cat coverage.txt
            echo '```'
          } >> "$GITHUB_STEP_SUMMARY"

          exit "$coverage_status"