truss-image 0.10.3

Image toolkit with a shared Rust core across the CLI, HTTP server, and WASM demo.
Documentation
name: Build/Test/Lint

on:
  push:
    branches:
      - main
    paths:
      - "src/**"
      - "tests/**"
      - "packages/**"
      - "scripts/**"
      - "Cargo.toml"
      - "Cargo.lock"
      - ".github/workflows/rust.yml"
  pull_request:
    paths:
      - "src/**"
      - "tests/**"
      - "packages/**"
      - "scripts/**"
      - "Cargo.toml"
      - "Cargo.lock"
      - ".github/workflows/rust.yml"

concurrency:
  group: rust-${{ github.ref }}
  cancel-in-progress: true

env:
  CARGO_TERM_COLOR: always

jobs:
  # ── Always: Ubuntu test + lint (PR and main) ────────────────────────
  test:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - name: Checkout
        uses: actions/checkout@v6

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

      - name: Cache cargo artifacts
        uses: Swatinem/rust-cache@v2

      - name: Install nextest
        uses: taiki-e/install-action@nextest

      - name: Run tests
        run: cargo nextest run --all-features --all-targets

      - name: Run doc tests
        run: cargo test --all-features --doc

  clippy:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - name: Checkout
        uses: actions/checkout@v6

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

      - name: Cache cargo artifacts
        uses: Swatinem/rust-cache@v2

      - name: Run clippy
        run: cargo clippy --all-features --all-targets -- -D warnings

  fmt:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - name: Checkout
        uses: actions/checkout@v6

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

      - name: Check formatting
        run: cargo fmt --all -- --check

  doc:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - name: Checkout
        uses: actions/checkout@v6

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

      - name: Cache cargo artifacts
        uses: Swatinem/rust-cache@v2

      - name: Build documentation
        run: cargo doc --no-deps
        env:
          RUSTDOCFLAGS: -D warnings

  wasm-package:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: wasm32-unknown-unknown

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22

      - name: Cache cargo artifacts
        uses: Swatinem/rust-cache@v2

      - name: Read Wasm package config
        id: wasm-package-config
        run: |
          version="$(node -p "require('./packages/truss-wasm/package.json').trussWasmBuild.wasmBindgenVersion")"
          echo "wasm_bindgen_version=${version}" >> "$GITHUB_OUTPUT"

      - name: Install wasm-bindgen CLI
        run: |
          version="${{ steps.wasm-package-config.outputs.wasm_bindgen_version }}"
          if [ "$(wasm-bindgen --version 2>/dev/null || true)" != "wasm-bindgen ${version}" ]; then
            cargo install wasm-bindgen-cli --version "${version}"
          fi

      - name: Pack npm Wasm package
        run: cd packages/truss-wasm && npm pack --dry-run

  # ── Cross-platform tests (PR and main) ──────────────────────────────
  test-cross-platform:
    strategy:
      matrix:
        os: [macos-latest, windows-latest]
    runs-on: ${{ matrix.os }}
    timeout-minutes: 20
    steps:
      - name: Checkout
        uses: actions/checkout@v6

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

      - name: Cache cargo artifacts
        uses: Swatinem/rust-cache@v2

      - name: Install nextest
        uses: taiki-e/install-action@nextest

      - name: Run tests
        run: cargo nextest run --all-targets

      - name: Run doc tests
        run: cargo test --doc

  # ── OpenAPI spec validation ─────────────────────────────────────────
  openapi-validate:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Install openapi-spec-validator
        run: pip install openapi-spec-validator

      - name: Validate OpenAPI spec
        run: python -m openapi_spec_validator docs/openapi.yaml

  # ── security audit ──────────────────────────────────────────────────
  security-audit:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Run security audit
        uses: rustsec/audit-check@v2
        with:
          token: ${{ secrets.GITHUB_TOKEN }}