alice-analytics 0.3.0

High-performance telemetry & probabilistic statistical estimation — HyperLogLog++, DDSketch, Count-Min Sketch, local differential privacy, streaming anomaly detection
Documentation
name: Fuzz

# Runs each fuzz target for a bounded time: telemetry values chosen by an
# attacker (NaN / ±Inf / subnormal / extreme counts) must not panic or exhaust
# memory. cargo-fuzz needs a nightly toolchain.

on:
  push:
    branches: [main]
    paths:
      - 'src/**'
      - 'fuzz/**'
      - '.github/workflows/fuzz.yml'
  pull_request:
    branches: [main]
    paths:
      - 'src/**'
      - 'fuzz/**'
      - '.github/workflows/fuzz.yml'
  schedule:
    # every day 03:00 UTC
    - cron: '0 3 * * *'
  workflow_dispatch:
    inputs:
      duration_seconds:
        description: 'Per-target fuzz duration (seconds)'
        required: false
        default: '60'
        type: string

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

env:
  CARGO_TERM_COLOR: always

jobs:
  fuzz:
    name: Fuzz — ${{ matrix.target }}
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        target:
          - fuzz_event_parse
          - fuzz_metric_aggregate
          - fuzz_sketch_insert
    steps:
      - uses: actions/checkout@v5

      - name: Install nightly toolchain
        uses: dtolnay/rust-toolchain@nightly

      - uses: Swatinem/rust-cache@v2
        with:
          workspaces: fuzz

      - name: Install cargo-fuzz
        # built from source: the prebuilt cargo-fuzz binary targets musl by
        # default, which the sanitizer build cannot use
        run: cargo install cargo-fuzz --locked

      # the build blocks: a target that does not compile must not pass
      - name: Build fuzz target
        run: |
          cd fuzz
          cargo +nightly fuzz build "${{ matrix.target }}"

      - name: Set fuzz duration
        id: dur
        run: |
          DURATION="${{ github.event.inputs.duration_seconds }}"
          if [ -z "$DURATION" ]; then
            DURATION=60
          fi
          echo "seconds=$DURATION" >> "$GITHUB_OUTPUT"

      # the run is informational: a crash is uploaded for triage, not blocking
      - name: Run fuzz target (time-boxed)
        id: run
        continue-on-error: true
        run: |
          cd fuzz
          cargo +nightly fuzz run "${{ matrix.target }}" -- \
            -max_total_time=${{ steps.dur.outputs.seconds }}

      - name: Upload crash artifacts (if any)
        if: steps.run.outcome == 'failure'
        uses: actions/upload-artifact@v6
        with:
          name: fuzz-crash-${{ matrix.target }}
          path: fuzz/artifacts/${{ matrix.target }}
          if-no-files-found: ignore
          retention-days: 14

      - name: Report crash (informational)
        if: steps.run.outcome == 'failure'
        run: echo "::warning::fuzz target ${{ matrix.target }} found a crash — see fuzz-crash-${{ matrix.target }} artifact"