build(deps): bump actions/deploy-pages from 4 to 5 #331
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Fuzzing | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| schedule: | |
| # Run fuzzing weekly on Sundays at midnight UTC | |
| - cron: "0 0 * * 0" | |
| workflow_dispatch: | |
| inputs: | |
| fuzz_duration: | |
| description: "Fuzzing duration in seconds per target (push=120, PR=300, dispatch default=600)" | |
| required: false | |
| default: "600" | |
| permissions: | |
| contents: read | |
| jobs: | |
| atheris-fuzz: | |
| name: Python Fuzzing (Atheris) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 90 | |
| env: | |
| MEOW_TEST_MODE: "1" | |
| MEOW_PRODUCTION_MODE: "0" # Required alongside MEOW_TEST_MODE to allow export_key() in tests | |
| MEOW_CRYPTO_BACKEND: rust | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - name: Set up Python | |
| uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.3.0 | |
| with: | |
| python-version: "3.12" | |
| - uses: dtolnay/rust-toolchain@d0592fe69e35bc8f12e3dbaf9ad2694d976cb8e3 # stable | |
| with: | |
| toolchain: stable | |
| - name: Install dependencies | |
| # Editable install (-e .) for local source - can't hash-pin | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| libzbar0 libgl1 libglib2.0-0 \ | |
| build-essential pkg-config libssl-dev \ | |
| libpcsclite-dev libudev-dev | |
| pip install --require-hashes -r requirements-pip.lock | |
| pip install --require-hashes -r requirements-ci.lock | |
| pip install --require-hashes -r requirements.lock | |
| pip install --require-hashes -r requirements-dev.lock || true | |
| pip install --no-deps -e . | |
| - name: Build and install Rust crypto backend | |
| run: | | |
| cd rust_crypto | |
| maturin build --release --out dist | |
| python -m pip install --force-reinstall --no-deps dist/*.whl | |
| cd .. | |
| - name: Create corpus directories | |
| run: | | |
| mkdir -p fuzz/corpus/manifest | |
| mkdir -p fuzz/corpus/qr | |
| mkdir -p fuzz/corpus/fountain | |
| mkdir -p fuzz/crashes | |
| - name: Seed corpus with valid samples | |
| run: | | |
| python fuzz/seed_corpus.py | |
| # ββ Core security targets (always run) ββββββββββββββββββββββββββββββ | |
| - name: Fuzz manifest parser | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_manifest.py fuzz/corpus/manifest || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| - name: Fuzz fountain decoder | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_fountain.py fuzz/corpus/fountain || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| - name: Fuzz crypto operations | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_crypto.py fuzz/corpus/manifest || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| - name: Fuzz guard page memory safety | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_windows_guard.py || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| - name: Fuzz mouse gesture auth | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_mouse_gesture.py || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| - name: Fuzz tamper detection | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_tamper_detection.py || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| - name: Fuzz adversarial stego rotation | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_adversarial_stego.py || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| # ββ Previously-missing security targets (FIX: audit gap #2) βββββββββ | |
| - name: Fuzz ratchet (frame encrypt/decrypt) | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_ratchet.py || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| - name: Fuzz manifest signing (Ed25519/ML-DSA) | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_manifest_signing.py || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| - name: Fuzz PQ ratchet beacon | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_pq_ratchet_beacon.py || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| - name: Fuzz master ratchet | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_master_ratchet.py || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| - name: Fuzz Schrodinger encode/decode | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_schrodinger.py || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| - name: Fuzz crypto backend (Rust FFI) | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_crypto_backend.py || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| - name: Fuzz Shamir secret sharing | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_shamir.py || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| - name: Fuzz memory guard operations | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_memory_guard.py || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| - name: Fuzz dual stream encoding | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_dual_stream.py || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| - name: Fuzz multi-layer stego | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_stego_multilayer.py || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| # ββ Audit-fix: PQXDH hybrid key exchange (was absent β Critical gap) ββ | |
| - name: Fuzz PQ hybrid PQXDH (ML-KEM-768/1024 + X25519) | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_pq_hybrid.py || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| # ββ Audit-fix: X25519 forward secrecy key agreement ββ | |
| - name: Fuzz X25519 forward secrecy | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_x25519_fs.py || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| # ββ Audit-fix: time-lock duress + content expiry ββ | |
| - name: Fuzz time-lock duress & content expiry | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_timelock_expiry.py || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| # ββ Audit-fix: forensic cleanup module ββ | |
| - name: Fuzz forensic cleanup | |
| run: | | |
| DURATION="${{ github.event_name == 'push' && '120' || github.event.inputs.fuzz_duration || '300' }}" | |
| timeout ${DURATION}s python fuzz/fuzz_forensic_cleanup.py || RC=$? | |
| RC=${RC:-0}; [ "$RC" -eq 0 ] || [ "$RC" -eq 124 ] || exit "$RC" | |
| # ββ Crash gate (MUST fail the build on any crash) βββββββββββββββββββ | |
| - name: Check for crashes | |
| run: | | |
| if [ -n "$(ls -A fuzz/crashes 2>/dev/null)" ]; then | |
| echo "π¨ Crashes found!" | |
| ls -la fuzz/crashes/ | |
| exit 1 | |
| else | |
| echo "β No crashes found" | |
| fi | |
| - name: Upload crash artifacts | |
| if: failure() | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.0 | |
| with: | |
| name: fuzz-crashes | |
| path: fuzz/crashes/ | |
| retention-days: 30 | |
| afl-fuzz: | |
| name: AFL++ Fuzzing (Native) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - name: Install AFL++ | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y afl++ python3-dev | |
| - name: Set up Python | |
| uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.3.0 | |
| with: | |
| python-version: "3.12" | |
| - uses: dtolnay/rust-toolchain@d0592fe69e35bc8f12e3dbaf9ad2694d976cb8e3 # stable | |
| with: | |
| toolchain: stable | |
| - name: Install dependencies | |
| # Editable install for local source - can't hash-pin | |
| run: | | |
| sudo apt-get install -y \ | |
| libzbar0 \ | |
| build-essential pkg-config libssl-dev \ | |
| libpcsclite-dev libudev-dev | |
| pip install --require-hashes -r requirements-pip.lock | |
| pip install --require-hashes -r requirements-ci.lock | |
| pip install --require-hashes -r requirements.lock | |
| pip install --no-deps -e ".[dev]" | |
| - name: Build and install Rust crypto backend | |
| run: | | |
| cd rust_crypto | |
| maturin build --release --out dist | |
| python -m pip install --force-reinstall --no-deps dist/*.whl | |
| cd .. | |
| - name: Create corpus | |
| run: | | |
| mkdir -p fuzz/afl-corpus | |
| mkdir -p fuzz/afl-output | |
| python fuzz/seed_corpus.py --afl | |
| - name: Run AFL++ on manifest parser | |
| run: | | |
| cd fuzz | |
| timeout ${{ github.event.inputs.fuzz_duration || '300' }}s \ | |
| py-afl-fuzz -i afl-corpus -o afl-output -m none -- \ | |
| python afl_fuzz_manifest.py || true | |
| - name: Check AFL++ results | |
| run: | | |
| if [ -d "fuzz/afl-output/default/crashes" ] && [ -n "$(ls -A fuzz/afl-output/default/crashes 2>/dev/null)" ]; then | |
| echo "π¨ AFL++ found crashes!" | |
| ls -la fuzz/afl-output/default/crashes/ | |
| exit 1 | |
| else | |
| echo "β No AFL++ crashes found" | |
| fi | |
| - name: Upload AFL++ results | |
| if: always() | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.0 | |
| with: | |
| name: afl-results | |
| path: fuzz/afl-output/ | |
| retention-days: 7 |