Skip to content

build(deps): bump actions/deploy-pages from 4 to 5 #331

build(deps): bump actions/deploy-pages from 4 to 5

build(deps): bump actions/deploy-pages from 4 to 5 #331

Workflow file for this run

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