hornet-bind9 0.1.0

Parse, write, and validate BIND9 named.conf configuration files and DNS zone files
Documentation
# Copyright (c) 2025 Erick Bourgeois, firestoned
# SPDX-License-Identifier: MIT

name: Pull Request CI

on:
  pull_request:
    branches:
      - main

permissions:
  contents: read
  id-token: write
  security-events: write

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: 1

jobs:
  changes:
    name: Detect Changed Files
    runs-on: ubuntu-latest
    outputs:
      code: ${{ steps.filter.outputs.code }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Check for changes
        uses: dorny/paths-filter@v4
        id: filter
        with:
          filters: |
            code:
              - 'src/**'
              - 'tests/**'
              - 'benches/**'
              - 'Cargo.toml'
              - 'Cargo.lock'
              - '.github/workflows/pr.yml'

  license-check:
    name: Verify SPDX License Headers
    runs-on: ubuntu-latest
    needs: changes
    if: needs.changes.outputs.code == 'true'
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Check license headers
        uses: firestoned/github-actions/security/license-check@v1.3.4
        with:
          copyright-holder: "Erick Bourgeois, firestoned"
          license-id: "MIT"

  verify-commits:
    name: Verify Signed Commits
    runs-on: ubuntu-latest
    needs: changes
    if: needs.changes.outputs.code == 'true'
    steps:
      - name: Checkout code
        uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: Verify all commits are signed
        uses: firestoned/github-actions/security/verify-signed-commits@v1.3.4
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          base-ref: origin/${{ github.base_ref }}
          verify-mode: pr

  format:
    name: Check Formatting
    runs-on: ubuntu-latest
    needs: [license-check, verify-commits]
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt

      - name: Check formatting
        run: make fmt-check

  clippy:
    name: Clippy
    runs-on: ubuntu-latest
    needs: format
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy

      - name: Cache cargo dependencies
        uses: firestoned/github-actions/rust/cache-cargo@v1.3.4

      - name: Run clippy
        run: make clippy

  build:
    name: Build - ${{ matrix.platform.name }}
    runs-on: ${{ matrix.platform.os }}
    needs: [format, clippy]
    strategy:
      fail-fast: false
      matrix:
        platform:
          - name: Linux x86_64
            os: ubuntu-latest
            target: x86_64-unknown-linux-gnu
            artifact_name: hornet-linux-amd64
            binary_name: hornet
          - name: Linux ARM64
            os: ubuntu-latest
            target: aarch64-unknown-linux-gnu
            artifact_name: hornet-linux-arm64
            binary_name: hornet
          - name: macOS ARM64
            os: macos-latest
            target: aarch64-apple-darwin
            artifact_name: hornet-macos-arm64
            binary_name: hornet
          - name: macOS x86_64
            os: macos-latest
            target: x86_64-apple-darwin
            artifact_name: hornet-macos-amd64
            binary_name: hornet
          - name: Windows x86_64
            os: windows-latest
            target: x86_64-pc-windows-msvc
            artifact_name: hornet-windows-amd64
            binary_name: hornet.exe
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      # Linux: custom action handles cross-compilation setup for ARM64
      - name: Setup Rust build environment (Linux)
        if: runner.os == 'Linux'
        uses: firestoned/github-actions/rust/setup-rust-build@v1.3.4
        with:
          target: ${{ matrix.platform.target }}

      # macOS/Windows: native build; macOS x86_64 is cross-compiled on ARM64 macos-latest runner
      - name: Setup Rust toolchain (macOS/Windows)
        if: runner.os != 'Linux'
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.platform.target }}

      - name: Add x86_64 target for cross-compilation (macOS)
        if: matrix.platform.target == 'x86_64-apple-darwin'
        run: rustup target add x86_64-apple-darwin

      - name: Cache cargo dependencies (macOS/Windows)
        if: runner.os != 'Linux'
        uses: firestoned/github-actions/rust/cache-cargo@v1.3.4

      - name: Build binary (Linux)
        if: runner.os == 'Linux'
        uses: firestoned/github-actions/rust/build-binary@v1.3.4
        with:
          target: ${{ matrix.platform.target }}

      - name: Build binary (macOS/Windows)
        if: runner.os != 'Linux'
        shell: bash
        run: cargo build --release --target ${{ matrix.platform.target }}

      - name: Generate SBOM (Linux only)
        if: runner.os == 'Linux'
        uses: firestoned/github-actions/rust/generate-sbom@v1.3.4
        with:
          target: ${{ matrix.platform.target }}

      - name: Upload binary and SBOM artifacts
        uses: actions/upload-artifact@v7
        with:
          name: ${{ matrix.platform.artifact_name }}
          path: |
            target/${{ matrix.platform.target }}/release/${{ matrix.platform.binary_name }}
            *.cdx.*
          retention-days: 1
          if-no-files-found: error

  test:
    name: Test
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo dependencies
        uses: firestoned/github-actions/rust/cache-cargo@v1.3.4

      - name: Run tests
        run: make test

  security:
    name: Security Vulnerability Scan
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Run security scan
        uses: firestoned/github-actions/rust/security-scan@v1.3.4
        with:
          cargo-audit-version: "0.22.0"

  coverage:
    name: Code Coverage
    runs-on: ubuntu-latest
    needs: test
    permissions:
      contents: write
      pull-requests: write
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo dependencies
        uses: firestoned/github-actions/rust/cache-cargo@v1.3.4

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

      - name: Generate coverage report
        run: make coverage-lcov

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v5
        with:
          files: lcov.info
          fail_ci_if_error: false
          token: ${{ secrets.CODECOV_TOKEN }}
          verbose: true

      - name: Generate HTML coverage report
        run: make coverage-html

      - name: Upload HTML coverage as artifact
        uses: actions/upload-artifact@v7
        with:
          name: coverage-report
          path: target/llvm-cov/html/
          retention-days: 7

  bench-compile:
    name: Compile Benchmarks
    runs-on: ubuntu-latest
    needs: format
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo dependencies
        uses: firestoned/github-actions/rust/cache-cargo@v1.3.4

      - name: Compile benchmarks (no run)
        run: make bench-compile