Skip to content

Commit 4d5580d

Browse files
committed
phase 4
Signed-off-by: mrhapile <allinonegaming3456@gmail.com>
1 parent 256e7de commit 4d5580d

1 file changed

Lines changed: 290 additions & 0 deletions

File tree

.github/workflows/fuzz.yml

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
# =============================================================================
2+
# WASM Fuzzing CI Workflow
3+
# =============================================================================
4+
#
5+
# This workflow runs the WebAssembly fuzzing harness as part of CI.
6+
# It will FAIL the build if:
7+
# 1. Any panic is detected (indicates fuzzer instability)
8+
# 2. Any unclassified failure occurs (indicates missing error handling)
9+
# 3. The fuzzer itself crashes or times out
10+
#
11+
# Successful fuzzing runs (even with expected failures like invalid WASM)
12+
# will PASS - we only fail on unexpected/unhandled errors.
13+
# =============================================================================
14+
15+
name: WASM Fuzzing CI
16+
17+
on:
18+
push:
19+
branches: [main, develop]
20+
pull_request:
21+
branches: [main]
22+
# Allow manual trigger for debugging
23+
workflow_dispatch:
24+
25+
env:
26+
GO_VERSION: '1.21'
27+
WASMEDGE_VERSION: '0.13.4'
28+
29+
jobs:
30+
# ===========================================================================
31+
# Unit Tests (No WasmEdge dependency)
32+
# ===========================================================================
33+
unit-tests:
34+
name: Unit Tests & Fault Injection
35+
runs-on: ubuntu-latest
36+
37+
steps:
38+
- name: Checkout repository
39+
uses: actions/checkout@v4
40+
41+
- name: Set up Go
42+
uses: actions/setup-go@v5
43+
with:
44+
go-version: ${{ env.GO_VERSION }}
45+
cache: true
46+
47+
- name: Download dependencies
48+
run: go mod download
49+
50+
- name: Run unit tests
51+
run: |
52+
# Run fault injection tests (no WasmEdge required)
53+
# These validate error handling and panic recovery
54+
go test -v -race -coverprofile=coverage.out ./...
55+
56+
- name: Upload coverage report
57+
uses: actions/upload-artifact@v4
58+
with:
59+
name: coverage-report
60+
path: coverage.out
61+
retention-days: 7
62+
63+
# ===========================================================================
64+
# Integration Fuzzing (Requires WasmEdge)
65+
# ===========================================================================
66+
fuzz-corpus:
67+
name: Fuzz WASM Corpus
68+
runs-on: ubuntu-latest
69+
70+
steps:
71+
- name: Checkout repository
72+
uses: actions/checkout@v4
73+
74+
- name: Set up Go
75+
uses: actions/setup-go@v5
76+
with:
77+
go-version: ${{ env.GO_VERSION }}
78+
cache: true
79+
80+
# -----------------------------------------------------------------------
81+
# Install WasmEdge Runtime
82+
# -----------------------------------------------------------------------
83+
- name: Install WasmEdge
84+
run: |
85+
# Install WasmEdge using official installer
86+
curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | \
87+
bash -s -- -v ${{ env.WASMEDGE_VERSION }}
88+
89+
# Add to PATH for subsequent steps
90+
echo "$HOME/.wasmedge/bin" >> $GITHUB_PATH
91+
echo "LD_LIBRARY_PATH=$HOME/.wasmedge/lib:$LD_LIBRARY_PATH" >> $GITHUB_ENV
92+
echo "C_INCLUDE_PATH=$HOME/.wasmedge/include:$C_INCLUDE_PATH" >> $GITHUB_ENV
93+
echo "LIBRARY_PATH=$HOME/.wasmedge/lib:$LIBRARY_PATH" >> $GITHUB_ENV
94+
95+
- name: Verify WasmEdge installation
96+
run: |
97+
wasmedge --version
98+
ls -la $HOME/.wasmedge/lib/
99+
100+
# -----------------------------------------------------------------------
101+
# Build Fuzzing Corpus
102+
# -----------------------------------------------------------------------
103+
- name: Install wabt (WebAssembly Binary Toolkit)
104+
run: |
105+
sudo apt-get update
106+
sudo apt-get install -y wabt
107+
108+
- name: Build WASM corpus from WAT files
109+
run: |
110+
chmod +x build_corpus.sh
111+
./build_corpus.sh
112+
113+
- name: List corpus files
114+
run: ls -la corpus/*.wasm
115+
116+
# -----------------------------------------------------------------------
117+
# Build and Run Fuzzer
118+
# -----------------------------------------------------------------------
119+
- name: Build fuzzer
120+
run: |
121+
# Build with integration tag to include WasmEdge code
122+
go build -tags=integration -o wasm-fuzzer .
123+
124+
- name: Run fuzzing harness
125+
id: fuzz
126+
run: |
127+
# Run fuzzer and capture output
128+
# Continue on error so we can analyze the report
129+
set +e
130+
./wasm-fuzzer ./corpus > fuzzing-report.json 2>&1
131+
FUZZER_EXIT_CODE=$?
132+
set -e
133+
134+
# Display report for CI logs
135+
echo "=== Fuzzing Report ==="
136+
cat fuzzing-report.json | jq '.' || cat fuzzing-report.json
137+
echo "======================"
138+
139+
# Save exit code for later analysis
140+
echo "fuzzer_exit_code=$FUZZER_EXIT_CODE" >> $GITHUB_OUTPUT
141+
142+
# -----------------------------------------------------------------------
143+
# Analyze Results & Determine CI Status
144+
# -----------------------------------------------------------------------
145+
- name: Analyze fuzzing results
146+
id: analyze
147+
run: |
148+
# Parse the JSON report and check for CI-failing conditions
149+
#
150+
# CI FAILS if:
151+
# 1. Any result contains "panic recovered" in error message
152+
# 2. Any failure has an empty/unknown failure_stage
153+
# 3. The fuzzer crashed (non-zero exit without valid JSON)
154+
155+
echo "Analyzing fuzzing results..."
156+
157+
# Check if report is valid JSON
158+
if ! jq empty fuzzing-report.json 2>/dev/null; then
159+
echo "::error::Fuzzer output is not valid JSON - fuzzer may have crashed"
160+
echo "ci_should_fail=true" >> $GITHUB_OUTPUT
161+
echo "failure_reason=Invalid JSON output - fuzzer crashed" >> $GITHUB_OUTPUT
162+
exit 0
163+
fi
164+
165+
# Extract statistics
166+
TOTAL=$(jq '.total_files' fuzzing-report.json)
167+
PASSED=$(jq '.passed' fuzzing-report.json)
168+
FAILED=$(jq '.failed' fuzzing-report.json)
169+
170+
echo "Total files: $TOTAL"
171+
echo "Passed: $PASSED"
172+
echo "Failed: $FAILED"
173+
174+
# Check for panics (indicates fuzzer instability)
175+
PANIC_COUNT=$(jq '[.results[] | select(.error_message != null) | select(.error_message | contains("panic"))] | length' fuzzing-report.json)
176+
177+
if [ "$PANIC_COUNT" -gt 0 ]; then
178+
echo "::error::Detected $PANIC_COUNT panic(s) during fuzzing"
179+
jq '.results[] | select(.error_message != null) | select(.error_message | contains("panic"))' fuzzing-report.json
180+
echo "ci_should_fail=true" >> $GITHUB_OUTPUT
181+
echo "failure_reason=Panic detected during fuzzing" >> $GITHUB_OUTPUT
182+
exit 0
183+
fi
184+
185+
# Check for unclassified failures (empty failure_stage on failed results)
186+
UNCLASSIFIED=$(jq '[.results[] | select(.success == false) | select(.failure_stage == "" or .failure_stage == null)] | length' fuzzing-report.json)
187+
188+
if [ "$UNCLASSIFIED" -gt 0 ]; then
189+
echo "::error::Detected $UNCLASSIFIED unclassified failure(s)"
190+
jq '.results[] | select(.success == false) | select(.failure_stage == "" or .failure_stage == null)' fuzzing-report.json
191+
echo "ci_should_fail=true" >> $GITHUB_OUTPUT
192+
echo "failure_reason=Unclassified failures detected" >> $GITHUB_OUTPUT
193+
exit 0
194+
fi
195+
196+
# All failures are properly classified - this is expected behavior
197+
echo "ci_should_fail=false" >> $GITHUB_OUTPUT
198+
echo "✅ All failures are properly classified"
199+
200+
# Print failure breakdown
201+
echo ""
202+
echo "=== Failure Breakdown ==="
203+
jq '.failure_counts' fuzzing-report.json
204+
205+
- name: Generate summary
206+
run: |
207+
# Create a nice summary for the GitHub Actions UI
208+
echo "## 🔍 WASM Fuzzing Results" >> $GITHUB_STEP_SUMMARY
209+
echo "" >> $GITHUB_STEP_SUMMARY
210+
211+
TOTAL=$(jq '.total_files' fuzzing-report.json)
212+
PASSED=$(jq '.passed' fuzzing-report.json)
213+
FAILED=$(jq '.failed' fuzzing-report.json)
214+
215+
echo "| Metric | Count |" >> $GITHUB_STEP_SUMMARY
216+
echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
217+
echo "| Total Files | $TOTAL |" >> $GITHUB_STEP_SUMMARY
218+
echo "| ✅ Passed | $PASSED |" >> $GITHUB_STEP_SUMMARY
219+
echo "| ❌ Failed | $FAILED |" >> $GITHUB_STEP_SUMMARY
220+
echo "" >> $GITHUB_STEP_SUMMARY
221+
222+
echo "### Failure Breakdown" >> $GITHUB_STEP_SUMMARY
223+
echo '```json' >> $GITHUB_STEP_SUMMARY
224+
jq '.failure_counts' fuzzing-report.json >> $GITHUB_STEP_SUMMARY
225+
echo '```' >> $GITHUB_STEP_SUMMARY
226+
227+
# -----------------------------------------------------------------------
228+
# Upload Artifacts
229+
# -----------------------------------------------------------------------
230+
- name: Upload fuzzing report
231+
uses: actions/upload-artifact@v4
232+
if: always() # Upload even if previous steps failed
233+
with:
234+
name: fuzzing-report
235+
path: |
236+
fuzzing-report.json
237+
corpus/*.wasm
238+
retention-days: 30
239+
240+
# -----------------------------------------------------------------------
241+
# Final CI Status Decision
242+
# -----------------------------------------------------------------------
243+
- name: Check CI status
244+
if: always()
245+
run: |
246+
# Fail CI if analysis detected problems
247+
if [ "${{ steps.analyze.outputs.ci_should_fail }}" == "true" ]; then
248+
echo "::error::${{ steps.analyze.outputs.failure_reason }}"
249+
exit 1
250+
fi
251+
252+
# Fail CI if fuzzer crashed unexpectedly
253+
if [ "${{ steps.fuzz.outputs.fuzzer_exit_code }}" != "0" ]; then
254+
# Check if it was a controlled failure vs crash
255+
if ! jq empty fuzzing-report.json 2>/dev/null; then
256+
echo "::error::Fuzzer crashed with exit code ${{ steps.fuzz.outputs.fuzzer_exit_code }}"
257+
exit 1
258+
fi
259+
fi
260+
261+
echo "✅ Fuzzing completed successfully - all failures properly classified"
262+
263+
# ===========================================================================
264+
# Build Verification (Ensures project compiles)
265+
# ===========================================================================
266+
build:
267+
name: Build Check
268+
runs-on: ubuntu-latest
269+
270+
steps:
271+
- name: Checkout repository
272+
uses: actions/checkout@v4
273+
274+
- name: Set up Go
275+
uses: actions/setup-go@v5
276+
with:
277+
go-version: ${{ env.GO_VERSION }}
278+
cache: true
279+
280+
- name: Verify module
281+
run: |
282+
go mod verify
283+
go mod tidy
284+
git diff --exit-code go.mod go.sum
285+
286+
- name: Build (stub mode)
287+
run: go build -o wasm-fuzzer-stub .
288+
289+
- name: Run go vet
290+
run: go vet ./...

0 commit comments

Comments
 (0)