sbom-tools 0.1.18

Semantic SBOM diff and analysis tool
Documentation
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

permissions: read-all

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: 1

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
  # ── Fast lint pass ─────────────────────────────────────────────
  lint:
    name: Lint
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        # v6.0.2
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
      - name: Install Rust
        # 1.88 (matches rust-toolchain.toml)
        uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
        with:
          toolchain: "1.88"
          components: clippy, rustfmt
      - name: Cache
        uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2
        with:
          save-if: ${{ github.ref == 'refs/heads/main' }}
      - name: Check formatting
        run: cargo fmt --all -- --check
      - name: Clippy (default features)
        run: cargo clippy -- -D warnings
      - name: Clippy (all features)
        run: cargo clippy --all-features -- -D warnings

  # ── MSRV check ─────────────────────────────────────────────────
  msrv:
    name: MSRV (1.88)
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
      - name: Install Rust 1.88
        # 1.88
        uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
        with:
          toolchain: "1.88"
      - name: Cache
        uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2
        with:
          shared-key: msrv
          save-if: ${{ github.ref == 'refs/heads/main' }}
      - name: Check (no default features)
        run: cargo check --locked
      - name: Check (all features)
        run: cargo check --locked --all-features

  # ── Test matrix ────────────────────────────────────────────────
  test:
    name: Test (${{ matrix.os }} / ${{ matrix.toolchain }})
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        toolchain: [stable]
        include:
          - os: ubuntu-latest
            toolchain: beta
    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
      - name: Install Rust ${{ matrix.toolchain }}
        uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master
        with:
          toolchain: ${{ matrix.toolchain }}
      - name: Cache
        uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2
        with:
          shared-key: ${{ matrix.toolchain }}
          save-if: ${{ github.ref == 'refs/heads/main' }}
      - name: Test (default features)
        run: cargo test --locked --verbose
      - name: Test (all features)
        run: cargo test --locked --all-features --verbose

  # ── Dependency audit ───────────────────────────────────────────
  deny:
    name: cargo-deny (${{ matrix.checks }})
    runs-on: ubuntu-latest
    strategy:
      matrix:
        checks:
          - advisories
          - bans licenses sources
    # Advisory failures are informational — don't block PRs on surprise CVEs
    continue-on-error: ${{ matrix.checks == 'advisories' }}
    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
      - name: cargo-deny
        # v2
        uses: EmbarkStudios/cargo-deny-action@3fd3802e88374d3fe9159b834c7714ec57d6c979
        with:
          command: check ${{ matrix.checks }}
          arguments: --all-features

  # ── Security audit ────────────────────────────────────────────
  audit:
    name: Security audit
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
      - name: Install cargo-audit
        run: cargo install cargo-audit --locked
      - name: Run cargo-audit
        run: cargo audit

  # ── Status gate (single required check) ────────────────────────
  ci:
    name: CI
    if: always()
    needs: [lint, msrv, test, deny, audit]
    runs-on: ubuntu-latest
    steps:
      - name: Evaluate results
        run: |
          result="${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}"
          [[ "$result" == "false" ]] || exit 1