Contents
Fuzzing
Fuzz targets live under fuzz/ and focus on parser, renderer, loader, mmap,
and candidate-mask boundaries that accept untrusted or SQL-visible input.
Targets
| Target | Boundary | Release checklist coverage | Seed corpus |
|---|---|---|---|
filter_json |
JSON filter parser and filter-budget enforcement | filter JSON; JSONB path handling | fuzz/corpus/filter_json |
sql_predicate |
resolved filter SQL rendering and placeholder accounting | SQL predicate rendering | fuzz/corpus/sql_predicate |
vector_text |
dense, half, sparse, and bit vector text round trips | vector text | fuzz/corpus/vector_text |
segment_loader |
segment decode, mmap validation, and encode/decode checks | segment loading; mmap views | fuzz/corpus/segment_loader |
candidate_mask |
HNSW candidate-mask budget validation | candidate masks | fuzz/corpus/candidate_mask |
Seed corpora should include the minimized input for every fuzz-found panic, crash, timeout, or sanitizer finding before the fix lands. Keep corpora small and focused; use comments in the commit message or report to explain large generated seeds instead of committing noisy bulk output.
Quick Build Check
The fuzz crate can be type-checked on the stable project toolchain:
cargo check --manifest-path fuzz/Cargo.toml --bins
This does not run libFuzzer. It only proves the targets compile.
Campaigns
Actual fuzz campaigns require a nightly Rust toolchain because cargo fuzz
enables sanitizer flags that use unstable -Z options. Release candidates
should use the campaign runner so every target writes a log, Markdown report,
and TSV summary under target/fuzz-campaigns/:
scripts/run-fuzz-campaigns.sh
The release-gates workflow exposes the same runner as a manual
workflow_dispatch path. Set run_fuzz_campaign=true and leave
fuzz_duration_seconds=86400 for release-candidate evidence; use fuzz_jobs
only to control how many targets run concurrently. The workflow uploads the
report as release-fuzz-campaign-report from
target/fuzz-campaigns/release-candidate.
The default duration is 24 hours per target. Use --duration SECONDS only for
smoke checks or explicitly approved shorter low-risk patch-release campaigns.
Use --target NAME to rerun one target after a fix, --jobs N to run multiple
targets concurrently while preserving per-target logs and artifact directories,
and --dry-run to verify the target list and report wiring without starting
libFuzzer.
Each report records the command, target, corpus path, commit SHA, host OS,
boundary, status, exit code, requested duration, measured elapsed duration, and
per-target log path. It also lists the release checklist boundary coverage and
counts any files left in the libFuzzer artifact directories. The report approval
is complete only when all default targets pass from a clean worktree with no
dry-run rows, no failures, no short elapsed rows, no crash artifacts, and at
least the default 24-hour duration per target. Short runs, target subsets, dirty
worktrees, dry-runs, and partial target runs are useful diagnostics, but their
reports stay incomplete and cannot satisfy the release-candidate fuzz gate.
--jobs only changes scheduling; it does not lower duration, target, clean-tree,
or artifact requirements. Non-dry-run campaigns refuse dirty worktrees unless
--allow-dirty is used for diagnostic evidence, and that override also keeps
approval incomplete.
A campaign is incomplete until every crash artifact is either fixed with a committed corpus seed or tracked as a release-blocking finding.