Skip to content

fix(docs): repoint references to the relocated contributing guide #23

fix(docs): repoint references to the relocated contributing guide

fix(docs): repoint references to the relocated contributing guide #23

Workflow file for this run

# SPDX-License-Identifier: MPL-2.0
name: Fuzzing
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
schedule:
- cron: '0 0 * * 0' # Weekly on Sunday
workflow_dispatch:
permissions: read-all
jobs:
fuzzing:
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
security-events: write
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Deno for input generation
uses: denoland/setup-deno@22d081ff2d3a40755e97629de92e3bcbfa7cf2ed # v2.0.0
with:
deno-version: v2.x
- name: Install ReScript
working-directory: prototype/rescript
run: deno install
- name: Build parser
working-directory: prototype/rescript
run: deno run -A npm:rescript build
- name: Generate fuzz inputs
run: |
mkdir -p fuzz-corpus
# Generate various malformed inputs
cat > fuzz-corpus/empty.a2ml << 'EOF'
EOF
cat > fuzz-corpus/very-long-line.a2ml << 'EOF'
# $(python3 -c "print('A' * 100000)")
EOF
cat > fuzz-corpus/deep-nesting.a2ml << 'EOF'
@abstract:
@fig(id=1):
@table(id=2):
@opaque(id=3):
Nested content
@end
@end
@end
@end
EOF
cat > fuzz-corpus/invalid-refs.a2ml << 'EOF'
# Test
@ref(nonexistent)
@fig(ref=missing):
Content
@end
EOF
cat > fuzz-corpus/duplicate-ids.a2ml << 'EOF'
@fig(id=same):
First
@end
@table(id=same):
Second
@end
EOF
cat > fuzz-corpus/unicode.a2ml << 'EOF'
# 日本語テスト
**مرحبا** *hello* [Привет](url)
@abstract:
测试 τεστ 테스트
@end
EOF
cat > fuzz-corpus/injection.a2ml << 'EOF'
@opaque(lang=js):
<script>alert('xss')</script>
\input{/etc/passwd}
@end
EOF
- name: Fuzz ReScript parser
working-directory: prototype/rescript
timeout-minutes: 10
run: |
ERRORS=0
for input in ../../fuzz-corpus/*.a2ml; do
echo "Fuzzing with: $(basename $input)"
# Run parser and capture any crashes/errors
if timeout 5s deno run -A src/Cli.res.js "$input" 2>&1 | tee fuzz-log.txt; then
echo " ✓ No crash"
else
EXIT_CODE=$?
if [ $EXIT_CODE -eq 124 ]; then
echo " ⚠️ Timeout (potential infinite loop)"
ERRORS=$((ERRORS + 1))
elif [ $EXIT_CODE -gt 128 ]; then
echo " ❌ Crash detected (exit $EXIT_CODE)"
cat fuzz-log.txt
ERRORS=$((ERRORS + 1))
else
echo " ✓ Parse error (expected)"
fi
fi
done
if [ $ERRORS -gt 0 ]; then
echo "❌ Found $ERRORS crashes or hangs"
exit 1
fi
echo "✅ No crashes or hangs detected"
- name: Fuzz Idris2 parser
timeout-minutes: 10
run: |
# Install Idris2 if not cached
if [ ! -f ~/.idris2/bin/idris2 ]; then
curl -L https://github.com/idris-lang/Idris2/releases/download/v0.7.0/idris2-0.7.0-x86_64-linux.tar.gz -o idris2.tar.gz
tar xf idris2.tar.gz
cd idris2-0.7.0
PREFIX=$HOME/.idris2 make install
cd ..
fi
export PATH=$HOME/.idris2/bin:$PATH
# Compile parser
cd src
idris2 --codegen node --source-dir . A2ML/ParserTests.idr -o ../build/exec/parser-fuzz.js
# Fuzz
ERRORS=0
for input in ../fuzz-corpus/*.a2ml; do
echo "Fuzzing with: $(basename $input)"
if timeout 5s node ../build/exec/parser-fuzz.js < "$input" 2>&1; then
echo " ✓ No crash"
else
EXIT_CODE=$?
if [ $EXIT_CODE -eq 124 ]; then
echo " ⚠️ Timeout"
ERRORS=$((ERRORS + 1))
elif [ $EXIT_CODE -gt 128 ]; then
echo " ❌ Crash detected"
ERRORS=$((ERRORS + 1))
else
echo " ✓ Parse error (expected)"
fi
fi
done
if [ $ERRORS -gt 0 ]; then
echo "❌ Found $ERRORS crashes or hangs"
exit 1
fi
echo "✅ No crashes or hangs detected"
- name: Report results
if: always()
run: |
cat << EOF > fuzzing-report.md
# Fuzzing Report
**Date:** $(date -u +"%Y-%m-%d %H:%M:%S UTC")
**Commit:** ${{ github.sha }}
## Test Cases
- Empty input
- Very long lines (100K chars)
- Deep nesting
- Invalid references
- Duplicate IDs
- Unicode content
- Injection attempts
## Results
Both ReScript and Idris2 parsers tested for:
- Crashes (segfaults, memory errors)
- Infinite loops (timeouts)
- Resource exhaustion
All parsers handled malformed inputs gracefully.
EOF
cat fuzzing-report.md