quantum-shield 0.3.1

Hybrid post-quantum cryptography: X25519 + ML-KEM-1024 encryption and Ed25519 + ML-DSA-87 signatures
Documentation
name: CI

on:
  push:
    branches: [main, "claude/**"]
  pull_request:
  workflow_dispatch:
  schedule:
    # Weekly, for the non-gating constant-time job.
    - cron: "0 6 * * 1"

env:
  CARGO_TERM_COLOR: always
  RUSTFLAGS: -D warnings

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

jobs:
  test:
    name: test (${{ matrix.os }})
    strategy:
      fail-fast: false
      matrix:
        # macos-15 runners are Apple Silicon (arm64): this job is the
        # aarch64-apple-darwin acceptance gate.
        os: [ubuntu-latest, macos-15]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy
      - uses: Swatinem/rust-cache@v2
      - name: Print target
        run: rustc -vV
      - name: Format
        run: cargo fmt --all --check
      - name: Clippy
        run: cargo clippy --all-targets --all-features
      - name: Test (default features)
        run: cargo test
      - name: Test (all features)
        run: cargo test --all-features
      - name: Build (no default features, no_std)
        run: cargo build --no-default-features
      - name: Docs
        run: cargo doc --all-features --no-deps
        env:
          RUSTDOCFLAGS: -D warnings
        if: matrix.os == 'ubuntu-latest'

  msrv:
    name: MSRV (1.85)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@master
        with:
          toolchain: "1.85"
      - uses: Swatinem/rust-cache@v2
      - run: cargo check --all-targets --all-features

  no-std:
    name: no_std (thumbv7em-none-eabi)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: thumbv7em-none-eabi
      - uses: Swatinem/rust-cache@v2
      # Compiles the library for a bare-metal target with no OS and a custom
      # randomness backend — the honest no_std gate.
      - run: cargo check --manifest-path ci/no_std_check/Cargo.toml

  deny:
    name: cargo-deny
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: EmbarkStudios/cargo-deny-action@v2
        with:
          command: check advisories bans licenses sources

  semver:
    name: semver-checks
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # need history + tags for the baseline
      - uses: obi1kenobi/cargo-semver-checks-action@v2
        with:
          # Compare the current API against the 0.2.0 release commit. (A commit
          # SHA rather than a tag because this environment's git remote does not
          # accept tag pushes.) The wire types are byte-serialized, so this also
          # guards the wire format.
          baseline-rev: 358796ca20ed060b9537dd7cfcb4f5e2c7b3eeba

  coverage:
    name: coverage
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: llvm-tools-preview
      - uses: taiki-e/install-action@cargo-llvm-cov
      - uses: Swatinem/rust-cache@v2
      - name: Coverage
        run: cargo llvm-cov --all-features --lcov --output-path lcov.info
      - uses: codecov/codecov-action@v4
        with:
          files: lcov.info
          fail_ci_if_error: false
        continue-on-error: true

  constant-time:
    name: constant-time (dudect, non-gating)
    # Noisy statistical harness: run on demand and on a schedule, never as a
    # PR gate. A large/growing t-value is a signal to investigate, not a
    # hard failure.
    if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - run: cargo run --release --example dudect
        continue-on-error: true

  fuzz:
    name: fuzz (smoke)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@nightly
      - uses: Swatinem/rust-cache@v2
      - uses: taiki-e/install-action@v2
        with:
          tool: cargo-fuzz
      - name: Smoke-run each target
        # The prebuilt cargo-fuzz is musl-linked and would otherwise default its
        # build target to x86_64-unknown-linux-musl (whose std isn't installed);
        # pin the gnu host target explicitly.
        run: |
          for t in envelope_from_bytes signature_from_bytes \
                   public_bundle_from_bytes secret_from_bytes \
                   public_bundle_from_pem \
                   multi_from_bytes rotation_from_bytes stream_parse \
                   roundtrip_seal_open roundtrip_sign_verify; do
            echo "::group::$t"
            cargo fuzz run --target x86_64-unknown-linux-gnu "$t" \
              -- -max_total_time=30 -print_final_stats=1
            echo "::endgroup::"
          done