Skip to content

Commit fed3431

Browse files
Jonathan D.A. Jewellclaude
andcommitted
ci: add ClusterFuzzLite fuzzing for OpenSSF FuzzingID
- Add .clusterfuzzlite/ config (project.yaml, Dockerfile, build.sh) - Add fuzz/ with cargo-fuzz targets: - fuzz_sql_policy: Tests PolicyEngine SQL parsing - fuzz_integrity: Tests manifest JSON deserialization - Add cflite_pr.yml: 5-min fuzzing on PRs - Add cflite_batch.yml: 30-min weekly batch fuzzing Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 905a61b commit fed3431

8 files changed

Lines changed: 188 additions & 0 deletions

File tree

.clusterfuzzlite/Dockerfile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# SPDX-License-Identifier: PMPL-1.0
2+
# SPDX-FileCopyrightText: 2025 Jonathan D. A. Jewell <hyperpolymath>
3+
#
4+
# ClusterFuzzLite Dockerfile for Rust fuzzing
5+
6+
FROM gcr.io/oss-fuzz-base/base-builder-rust
7+
8+
COPY . $SRC/project-wharf
9+
WORKDIR $SRC/project-wharf
10+
11+
COPY .clusterfuzzlite/build.sh $SRC/

.clusterfuzzlite/build.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/bin/bash -eu
2+
# SPDX-License-Identifier: PMPL-1.0
3+
# SPDX-FileCopyrightText: 2025 Jonathan D. A. Jewell <hyperpolymath>
4+
#
5+
# ClusterFuzzLite build script for Rust fuzzing
6+
7+
cd $SRC/project-wharf
8+
9+
# Install nightly for fuzzing
10+
rustup install nightly
11+
rustup default nightly
12+
13+
# Build fuzz targets
14+
cargo +nightly fuzz build
15+
16+
# Copy fuzz targets to output
17+
for target in fuzz/target/x86_64-unknown-linux-gnu/release/fuzz_*; do
18+
if [ -f "$target" ] && [ -x "$target" ]; then
19+
cp "$target" $OUT/
20+
fi
21+
done

.clusterfuzzlite/project.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# SPDX-License-Identifier: PMPL-1.0
2+
# SPDX-FileCopyrightText: 2025 Jonathan D. A. Jewell <hyperpolymath>
3+
#
4+
# ClusterFuzzLite project configuration
5+
6+
language: rust

.github/workflows/cflite_batch.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# SPDX-License-Identifier: PMPL-1.0
2+
# SPDX-FileCopyrightText: 2025 Jonathan D. A. Jewell <hyperpolymath>
3+
#
4+
# ClusterFuzzLite batch fuzzing workflow
5+
# Runs extended fuzzing on a weekly schedule
6+
7+
name: ClusterFuzzLite batch fuzzing
8+
9+
on:
10+
schedule:
11+
- cron: '0 0 * * 0' # Weekly on Sunday at midnight UTC
12+
workflow_dispatch:
13+
14+
permissions: read-all
15+
16+
jobs:
17+
BatchFuzzing:
18+
runs-on: ubuntu-latest
19+
permissions:
20+
security-events: write
21+
steps:
22+
- name: Build Fuzzers
23+
id: build
24+
uses: google/clusterfuzzlite/actions/build_fuzzers@884713a6c30a92e5e8544c39945cd7cb630abcd1 # v1
25+
with:
26+
language: rust
27+
github-token: ${{ secrets.GITHUB_TOKEN }}
28+
sanitizer: address
29+
30+
- name: Run Fuzzers
31+
id: run
32+
uses: google/clusterfuzzlite/actions/run_fuzzers@884713a6c30a92e5e8544c39945cd7cb630abcd1 # v1
33+
with:
34+
github-token: ${{ secrets.GITHUB_TOKEN }}
35+
fuzz-seconds: 1800
36+
mode: batch
37+
sanitizer: address

.github/workflows/cflite_pr.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# SPDX-License-Identifier: PMPL-1.0
2+
# SPDX-FileCopyrightText: 2025 Jonathan D. A. Jewell <hyperpolymath>
3+
#
4+
# ClusterFuzzLite PR fuzzing workflow
5+
# Runs quick fuzzing on pull requests
6+
7+
name: ClusterFuzzLite PR fuzzing
8+
9+
on:
10+
pull_request:
11+
branches: [main, master, develop]
12+
13+
permissions: read-all
14+
15+
jobs:
16+
PR:
17+
runs-on: ubuntu-latest
18+
permissions:
19+
security-events: write
20+
steps:
21+
- name: Build Fuzzers
22+
id: build
23+
uses: google/clusterfuzzlite/actions/build_fuzzers@884713a6c30a92e5e8544c39945cd7cb630abcd1 # v1
24+
with:
25+
language: rust
26+
github-token: ${{ secrets.GITHUB_TOKEN }}
27+
sanitizer: address
28+
29+
- name: Run Fuzzers
30+
id: run
31+
uses: google/clusterfuzzlite/actions/run_fuzzers@884713a6c30a92e5e8544c39945cd7cb630abcd1 # v1
32+
with:
33+
github-token: ${{ secrets.GITHUB_TOKEN }}
34+
fuzz-seconds: 300
35+
mode: code-change
36+
sanitizer: address

fuzz/Cargo.toml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# SPDX-License-Identifier: PMPL-1.0
2+
# SPDX-FileCopyrightText: 2025 Jonathan D. A. Jewell <hyperpolymath>
3+
4+
[package]
5+
name = "project-wharf-fuzz"
6+
version = "0.0.0"
7+
publish = false
8+
edition = "2021"
9+
10+
[package.metadata]
11+
cargo-fuzz = true
12+
13+
[dependencies]
14+
libfuzzer-sys = "0.4"
15+
16+
[dependencies.wharf-core]
17+
path = "../crates/wharf-core"
18+
19+
[[bin]]
20+
name = "fuzz_sql_policy"
21+
path = "fuzz_targets/fuzz_sql_policy.rs"
22+
test = false
23+
doc = false
24+
bench = false
25+
26+
[[bin]]
27+
name = "fuzz_integrity"
28+
path = "fuzz_targets/fuzz_integrity.rs"
29+
test = false
30+
doc = false
31+
bench = false
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// SPDX-License-Identifier: PMPL-1.0
2+
// SPDX-FileCopyrightText: 2025 Jonathan D. A. Jewell <hyperpolymath>
3+
//
4+
//! Fuzz target for integrity manifest parsing
5+
//! Tests handling of arbitrary manifest JSON input
6+
7+
#![no_main]
8+
9+
use libfuzzer_sys::fuzz_target;
10+
use wharf_core::integrity::Manifest;
11+
12+
fuzz_target!(|data: &[u8]| {
13+
// Try to interpret fuzzer input as JSON manifest
14+
if let Ok(json_str) = std::str::from_utf8(data) {
15+
// Attempt to deserialize - should handle any input gracefully
16+
let _: Result<Manifest, _> = serde_json::from_str(json_str);
17+
}
18+
});
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// SPDX-License-Identifier: PMPL-1.0
2+
// SPDX-FileCopyrightText: 2025 Jonathan D. A. Jewell <hyperpolymath>
3+
//
4+
//! Fuzz target for SQL policy engine
5+
//! Tests the PolicyEngine's ability to handle arbitrary SQL input
6+
7+
#![no_main]
8+
9+
use libfuzzer_sys::fuzz_target;
10+
use wharf_core::db_policy::{PolicyConfig, PolicyEngine, TableZone};
11+
12+
fuzz_target!(|data: &[u8]| {
13+
// Try to interpret fuzzer input as UTF-8 SQL
14+
if let Ok(sql) = std::str::from_utf8(data) {
15+
// Create a basic policy config for testing
16+
let config = PolicyConfig {
17+
mutable_tables: vec!["wp_comments".to_string(), "wp_posts".to_string()],
18+
immutable_tables: vec!["wp_users".to_string(), "wp_options".to_string()],
19+
hybrid_tables: vec![],
20+
default_zone: TableZone::Mutable,
21+
};
22+
23+
let engine = PolicyEngine::new(config);
24+
25+
// Fuzz the evaluate function - it should handle any input gracefully
26+
let _ = engine.evaluate(sql);
27+
}
28+
});

0 commit comments

Comments
 (0)