Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions .github/workflows/fuzz.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Fuzz testing workflow for security-critical parsing code
# Addresses Issue #7: Add fuzz testing for signature parsing/validation logic

name: Fuzz Testing

on:
schedule:
# Run daily at 2 AM UTC
- cron: '0 2 * * *'
workflow_dispatch:
inputs:
duration:
description: 'Fuzzing duration per target (seconds)'
required: false
default: '300'

jobs:
fuzz:
name: Fuzz ${{ matrix.target }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
- fuzz_varint
- fuzz_keyless_signature
- fuzz_module_parsing
- fuzz_signature_data
- fuzz_public_key
- fuzz_rekor_entry

steps:
- name: Checkout repository
uses: actions/checkout@v4

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

- name: Install cargo-fuzz
run: cargo install cargo-fuzz

- name: Create corpus directory
run: mkdir -p fuzz/corpus/${{ matrix.target }}

- name: Run fuzzer
run: |
cd fuzz
DURATION=${{ github.event.inputs.duration || '300' }}
echo "Fuzzing ${{ matrix.target }} for ${DURATION} seconds..."
cargo +nightly fuzz run ${{ matrix.target }} -- -max_total_time=$DURATION
continue-on-error: true

- name: Upload crash artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: fuzz-artifacts-${{ matrix.target }}
path: fuzz/artifacts/${{ matrix.target }}/
if-no-files-found: ignore
retention-days: 30

- name: Upload corpus
if: always()
uses: actions/upload-artifact@v4
with:
name: fuzz-corpus-${{ matrix.target }}
path: fuzz/corpus/${{ matrix.target }}/
if-no-files-found: ignore
retention-days: 7

report:
name: Fuzz Report
needs: fuzz
runs-on: ubuntu-latest
if: always()

steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts

- name: Check for crashes
run: |
CRASH_COUNT=0
for dir in artifacts/fuzz-artifacts-*/; do
if [ -d "$dir" ]; then
count=$(find "$dir" -type f -name 'crash-*' 2>/dev/null | wc -l)
if [ "$count" -gt 0 ]; then
echo "Found $count crash(es) in $dir"
CRASH_COUNT=$((CRASH_COUNT + count))
fi
fi
done

if [ "$CRASH_COUNT" -gt 0 ]; then
echo "Total crashes found: $CRASH_COUNT"
echo "Please investigate the crash artifacts!"
exit 1
else
echo "No crashes found in any fuzz target."
fi
88 changes: 88 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,94 @@ jobs:
env:
RUST_LOG: debug

# Air-gapped verification end-to-end tests
airgapped-e2e:
name: Air-Gapped E2E Tests
runs-on: ubuntu-latest
permissions:
id-token: write # Required for OIDC token
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Run Air-Gapped Unit Tests
run: cargo test --test airgapped_e2e -- --nocapture
env:
RUST_LOG: info

- name: Run Air-Gapped Integration Tests (with OIDC)
run: cargo test --test airgapped_e2e -- --ignored --nocapture
env:
RUST_LOG: debug

# Example: Sign a WASM module and verify with air-gapped flow
sign-and-verify-example:
name: Sign & Verify Example
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Build CLI
run: cargo build --release

- name: Generate bundle signing keypair
run: |
./target/release/wsc keygen -k /tmp/bundle-sk.key -K /tmp/bundle-pk.key
echo "Generated bundle signing keypair"

- name: Fetch and sign trust bundle from Sigstore
run: |
./target/release/wsc bundle fetch \
-o /tmp/trust-bundle.json \
--version 1 \
--validity-days 90 \
--sign /tmp/bundle-sk.key
echo "Fetched and signed trust bundle"

- name: Inspect trust bundle
run: ./target/release/wsc bundle inspect -i /tmp/trust-bundle.json

- name: Verify trust bundle signature
run: |
./target/release/wsc bundle verify \
-i /tmp/trust-bundle.json \
-K /tmp/bundle-pk.key
echo "Trust bundle signature verified"

- name: Create test WASM module
run: |
# Create a minimal valid WASM module
printf '\x00\x61\x73\x6d\x01\x00\x00\x00' > /tmp/test.wasm
echo "Created test WASM module"

- name: Sign WASM with keyless signing
run: |
./target/release/wsc sign --keyless \
-i /tmp/test.wasm \
-o /tmp/test-signed.wasm
echo "Signed WASM module with keyless signing"

- name: Verify keyless signature
run: |
./target/release/wsc verify --keyless \
-i /tmp/test-signed.wasm
echo "Verified keyless signature"

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: signed-wasm-artifacts
path: |
/tmp/trust-bundle.json
/tmp/bundle-pk.key
/tmp/test-signed.wasm
retention-days: 7

# Rekor verification tests with fresh data
rekor-verification:
name: Rekor Verification Tests (Fresh Data)
Expand Down
129 changes: 129 additions & 0 deletions .github/workflows/wasm-signing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Example workflow for signing WASM modules with wsc
#
# This workflow demonstrates how to:
# 1. Build and sign WASM modules with Sigstore keyless signing
# 2. Generate trust bundles for air-gapped verification
# 3. Upload signed artifacts
#
# To use in your project:
# 1. Copy this file to .github/workflows/
# 2. Adjust the WASM_PATH to point to your WASM module
# 3. Store your bundle signing key as a secret (optional)

name: Sign WASM Module

on:
push:
branches: [ main ]
release:
types: [ published ]
workflow_dispatch:
inputs:
wasm_path:
description: 'Path to WASM module to sign'
required: false
default: 'target/wasm32-unknown-unknown/release/my_module.wasm'

env:
# Path to the WASM module to sign
WASM_PATH: ${{ github.event.inputs.wasm_path || 'target/wasm32-unknown-unknown/release/my_module.wasm' }}
# wsc version to use
WSC_VERSION: '0.4.0'

jobs:
sign-wasm:
name: Sign WASM Module
runs-on: ubuntu-latest
permissions:
id-token: write # Required for Sigstore OIDC
contents: read
attestations: write

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install wsc
run: |
# Install from crates.io (when published)
# cargo install wsc-cli --version ${{ env.WSC_VERSION }}

# Or build from source
cargo install --git https://github.com/aspect-build/wsc.git wsc-cli

- name: Build WASM module
run: |
# Example: Build your Rust WASM module
# cargo build --release --target wasm32-unknown-unknown

# For this example, create a minimal test module
mkdir -p $(dirname "$WASM_PATH")
printf '\x00\x61\x73\x6d\x01\x00\x00\x00' > "$WASM_PATH"

- name: Sign WASM with Sigstore keyless
id: sign
run: |
wsc sign --keyless \
-i "$WASM_PATH" \
-o "${WASM_PATH%.wasm}-signed.wasm"

echo "signed_path=${WASM_PATH%.wasm}-signed.wasm" >> $GITHUB_OUTPUT

- name: Verify signature
run: |
wsc verify --keyless \
-i "${{ steps.sign.outputs.signed_path }}"

- name: Upload signed WASM
uses: actions/upload-artifact@v4
with:
name: signed-wasm-${{ github.sha }}
path: ${{ steps.sign.outputs.signed_path }}
retention-days: 90

# Optional: Generate trust bundle for air-gapped devices
generate-trust-bundle:
name: Generate Trust Bundle
runs-on: ubuntu-latest
if: github.event_name == 'release'

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install wsc
run: cargo install --git https://github.com/aspect-build/wsc.git wsc-cli

- name: Generate bundle keypair
run: |
# In production, use a secret for the signing key
wsc keygen -k /tmp/bundle-sk.key -K bundle-verifier.pub

- name: Fetch and sign trust bundle
run: |
# Fetch current Sigstore trust material and sign it
wsc bundle fetch \
-o trust-bundle-${{ github.ref_name }}.json \
--version ${{ github.run_number }} \
--validity-days 90 \
--sign /tmp/bundle-sk.key

- name: Inspect bundle
run: wsc bundle inspect -i trust-bundle-${{ github.ref_name }}.json

- name: Upload trust bundle
uses: actions/upload-artifact@v4
with:
name: trust-bundle-${{ github.ref_name }}
path: |
trust-bundle-${{ github.ref_name }}.json
bundle-verifier.pub
retention-days: 365

- name: Attach to release
if: github.event_name == 'release'
uses: softprops/action-gh-release@v1
with:
files: |
trust-bundle-${{ github.ref_name }}.json
bundle-verifier.pub
Loading
Loading