Skip to content

test: add run_full_fuzz.sh deep fuzz-campaign helper - #74

Merged
Navi Bot (project-navi-bot) merged 3 commits into
mainfrom
chore/full-fuzz-script
May 26, 2026
Merged

test: add run_full_fuzz.sh deep fuzz-campaign helper#74
Navi Bot (project-navi-bot) merged 3 commits into
mainfrom
chore/full-fuzz-script

Conversation

@Fieldnote-Echo

Copy link
Copy Markdown
Member

run_full_fuzz.sh — deep fuzz-campaign helper for devs

Adds fuzz/run_full_fuzz.sh: a helper to run a deep local cargo-fuzz campaign across all seven targets. Complements the bounded CI smoke (fuzz.yml) with an exhaustive, resumable run for pre-release / ad-hoc deep fuzzing.

What it does: runs each target in libFuzzer fork mode for a per-target wall-clock budget, persists the corpus (cumulative / resumable across runs), collects any crash/oom/timeout/leak artifacts, and exits non-zero if any are found.

Safe-by-default (not just for a big workstation)

The original was tuned for a high-core box; this makes it friendly to laptops/smaller machines:

  • FORKS defaults to cores − 2 so the machine stays responsive (set FORKS=$(nproc) to use every core).
  • Prints estimated total time + peak RAM (~FORKS × RSS_LIMIT_MB) up front, so you see the commitment (the full default run is ~21h and tens of GB).
  • When run interactively, waits 5s so you can Ctrl-C and re-run with smaller knobs; skipped under nohup/redirection so detached campaigns start immediately.
  • Env knobs: SECS_PER_TARGET, FORKS, RSS_LIMIT_MB, TARGETS. Laptop-friendly quick run:
    SECS_PER_TARGET=120 FORKS=2 ./fuzz/run_full_fuzz.sh   # ~14 min, 2 cores

Also

  • fuzz/.gitignore: ignore *.log (the campaign writes fuzz/full_fuzz_run.log).
  • CONTRIBUTING.md: a Fuzzing section pointing devs at the CI smoke, ad-hoc cargo +nightly fuzz run, and this helper.

Validation

bash -n (syntax) + a config-arithmetic simulation across machine profiles (beast / laptop-quick / 2-core / 1-core) — confirms safe FORKS, sane time/RAM estimates, no arithmetic errors. Not run live in CI/locally on purpose (the core cargo +nightly fuzz build / fuzz run … -fork=… -max_total_time=… invocation is the same one already proven by a multi-hour campaign).

Adds fuzz/run_full_fuzz.sh: runs every cargo-fuzz target in libFuzzer fork
mode for a per-target budget, persisting the (resumable) corpus and collecting
crash artifacts, with a clean/dirty exit status.

Safe-by-default for any machine, not just a big workstation:
- FORKS defaults to cores-2 (machine stays responsive; FORKS=$(nproc) for all),
  and the run prints estimated total time + peak RAM (~FORKS x RSS_LIMIT_MB)
  up front.
- When run interactively it waits 5s so a heavy run can be aborted and
  re-launched with smaller knobs; skipped under nohup/redirection.
- Tunables: SECS_PER_TARGET, FORKS, RSS_LIMIT_MB, TARGETS. Quick run:
  SECS_PER_TARGET=120 FORKS=2 ./fuzz/run_full_fuzz.sh  (~14 min, 2 cores).

Also gitignores fuzz/*.log (campaign logs) and adds a CONTRIBUTING "Fuzzing"
section pointing devs at the CI smoke (fuzz.yml), ad-hoc cargo-fuzz, and this
helper.

Validated with `bash -n` and a config-arithmetic simulation across machine
profiles; not run live (leaving the CPU free).

Signed-off-by: Nelson Spence <nelson@projectnavi.ai>
@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

Add deep fuzz campaign helper script and fuzzing documentation

🧪 Tests 📝 Documentation

Grey Divider

Walkthroughs

Description
• Add run_full_fuzz.sh script for deep fuzzing campaigns across all targets
• Script runs libFuzzer in fork mode with configurable per-target budgets
• Safe-by-default tuning: FORKS defaults to cores−2, estimates time/RAM upfront
• Interactive abort window and environment knobs for laptop-friendly runs
• Document fuzzing workflow in CONTRIBUTING.md with script usage examples
Diagram
flowchart LR
  A["Developer"] -->|runs| B["run_full_fuzz.sh"]
  B -->|builds| C["cargo fuzz targets"]
  C -->|runs fork mode| D["libFuzzer per-target"]
  D -->|collects| E["Corpus & Artifacts"]
  E -->|reports| F["Campaign Summary"]
  G["CONTRIBUTING.md"] -->|documents| B

Loading

Grey Divider

File Changes

1. fuzz/run_full_fuzz.sh 🧪 Tests +110/-0

Deep fuzz campaign helper with safe defaults

• New executable script for running deep fuzzing campaigns across all seven cargo-fuzz targets
• Implements libFuzzer fork mode with per-target wall-clock budgets and corpus persistence
• Configurable via environment variables: SECS_PER_TARGET, FORKS, RSS_LIMIT_MB, TARGETS
• Includes safety features: interactive abort window, machine-responsive defaults (cores−2), upfront
 time/RAM estimates
• Collects crash/oom/timeout/leak artifacts and exits with appropriate status code

fuzz/run_full_fuzz.sh


2. CONTRIBUTING.md 📝 Documentation +18/-0

Document fuzzing workflow and script usage

• Add new "Fuzzing" section documenting local fuzzing workflow
• Explain CI smoke testing via fuzz.yml and ad-hoc cargo-fuzz usage
• Reference the new run_full_fuzz.sh script with example invocation
• Document environment knobs for laptop-friendly runs and link to script header for full options

CONTRIBUTING.md


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented May 26, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Ignores fuzz-run failures ✓ Resolved 🐞 Bug ≡ Correctness
Description
run_full_fuzz.sh does not accumulate/propagate non-zero exit codes from cargo +nightly fuzz run,
so the script can exit 0 and print a CLEAN summary even when one or more targets failed to execute
successfully.
Code

fuzz/run_full_fuzz.sh[R85-93]

Evidence
The script runs each target and prints the libFuzzer return code, but the final exit status is
computed solely from whether artifact files exist, so run failures without artifacts are not
reflected in the script’s exit code.

fuzz/run_full_fuzz.sh[85-93]
fuzz/run_full_fuzz.sh[95-110]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`cargo +nightly fuzz run` exit codes are printed but not used to determine the script’s final exit status. This can produce a false-green "CLEAN" run even if targets failed (e.g., invocation/build/runtime failure without producing artifacts).

### Issue Context
The final `status` is currently derived only from a filesystem scan of `fuzz/artifacts`, ignoring whether any fuzz runs returned non-zero.

### Fix Focus Areas
- fuzz/run_full_fuzz.sh[80-110]

### Suggested fix
- Add a `had_failure=0` before the loop.
- After each `cargo +nightly fuzz run ...`, capture `rc=$?` and set `had_failure=1` if `rc != 0`.
- At the end, set `status=1` if `had_failure=1` OR artifacts are found (keep artifacts-based detection as-is).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Linux-only nproc/date usage ✓ Resolved 🐞 Bug ☼ Reliability
Description
The script uses nproc and date -Is, which are not available on macOS by default; since the
repo’s CI explicitly targets macOS, many contributors will be unable to run this script as
documented.
Code

fuzz/run_full_fuzz.sh[R44-58]

Evidence
run_full_fuzz.sh hard-depends on nproc and date -Is. The repo’s CI runs a test matrix on
macOS, so this non-portability is likely to impact contributors who follow CONTRIBUTING’s fuzzing
instructions on macOS.

fuzz/run_full_fuzz.sh[44-60]
.github/workflows/ci.yml[69-76]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`nproc` and GNU `date -Is` are used for CPU count and timestamps. On macOS (BSD userland), `nproc` typically doesn’t exist and `date` doesn’t support `-Is`, causing the script to fail early.

### Issue Context
The project runs CI on `macos-latest`, indicating macOS is a supported dev/test platform.

### Fix Focus Areas
- fuzz/run_full_fuzz.sh[44-60]
- .github/workflows/ci.yml[69-76]

### Suggested fix
- Compute CPU count with a portable fallback chain, e.g.:
 - `NCPU=$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null)`
 - If still empty, default to `1` with a clear error message.
- Replace `date -Is` with a portable format string, e.g. `date "+%Y-%m-%dT%H:%M:%S%z"` (or document GNU coreutils requirement if you prefer).
- Apply the same timestamp helper for all `date -Is` call sites.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. TARGETS globbing in loop ✓ Resolved 🐞 Bug ☼ Reliability
Description
The loop uses for t in ${TARGETS}; do, which performs word-splitting and pathname expansion on
user-provided TARGETS, potentially turning patterns (e.g. load_*) into filenames and causing
incorrect/failed target execution.
Code

fuzz/run_full_fuzz.sh[R80-81]

Evidence
The script already tokenizes TARGETS into _targets, but the actual loop iterates over
${TARGETS} directly, meaning bash will apply its usual splitting/globbing rules to the raw string
instead of using the safe array elements.

fuzz/run_full_fuzz.sh[47-50]
fuzz/run_full_fuzz.sh[80-86]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The script parses `TARGETS` into an array (`read -ra _targets`) but then ignores it and iterates over the unquoted string `${TARGETS}`. This allows glob expansion if the user provides patterns (e.g. `TARGETS='load_*'`).

### Issue Context
Default `TARGETS` is safe; the issue triggers when users customize `TARGETS`.

### Fix Focus Areas
- fuzz/run_full_fuzz.sh[47-50]
- fuzz/run_full_fuzz.sh[80-85]

### Suggested fix
- Replace `for t in ${TARGETS}; do` with `for t in "${_targets[@]}"; do`.
- Optionally disable globbing for extra safety (`set -f` / `set -o noglob`) around the loop if desired.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive fuzzing script, fuzz/run_full_fuzz.sh, to run deep fuzzing campaigns across all cargo-fuzz targets, along with updated documentation in CONTRIBUTING.md and gitignore rules. The feedback focuses on improving the script's portability and usability, specifically by adding fallbacks for macOS/BSD systems that lack nproc and the GNU-specific date -Is flag, and by ensuring that interrupting the script (e.g., via Ctrl-C) correctly aborts the entire sequential loop rather than skipping to the next target.

Comment thread fuzz/run_full_fuzz.sh Outdated
Comment thread fuzz/run_full_fuzz.sh Outdated
Comment thread fuzz/run_full_fuzz.sh Outdated
@codecov

codecov Bot commented May 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Comment thread fuzz/run_full_fuzz.sh
Comment thread fuzz/run_full_fuzz.sh Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f8baafd2bf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "Codex (@codex) review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "Codex (@codex) address that feedback".

Comment thread fuzz/run_full_fuzz.sh Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a developer-facing helper for running an exhaustive, resumable local cargo-fuzz campaign across all ordvec fuzz targets, and documents the recommended fuzzing workflow (CI smoke vs. local deep runs).

Changes:

  • Add fuzz/run_full_fuzz.sh to run all seven fuzz targets sequentially with libFuzzer fork mode, persistent corpus/artifacts, and an end-of-run artifact summary.
  • Update fuzz/.gitignore to ignore campaign log files.
  • Extend CONTRIBUTING.md with a Fuzzing section pointing to CI smoke runs and the new local helper.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
fuzz/run_full_fuzz.sh New deep fuzz-campaign runner script with configurable budgets/forks/RSS caps and crash artifact reporting.
fuzz/.gitignore Ignore *.log produced by the full campaign helper.
CONTRIBUTING.md Document fuzzing workflow and how to run the full local campaign.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread fuzz/run_full_fuzz.sh Outdated
Comment thread fuzz/run_full_fuzz.sh Outdated
Comment thread fuzz/run_full_fuzz.sh
Comment thread fuzz/run_full_fuzz.sh Outdated
Addresses PR #74 review (gemini/qodo/copilot/codex):
- Portable CPU count: nproc -> getconf -> BSD/macOS sysctl -> 1, so a missing
  nproc on macOS no longer leaves NCPU empty under set -u.
- Portable timestamps: GNU 'date -Is' -> 'date -u +%Y-%m-%dT%H:%M:%SZ' (a
  now() helper), which BSD/macOS date supports.
- Ctrl-C trap (SIGINT): stops the whole campaign instead of killing one
  target's fuzzer and marching to the next.
- Propagate exit codes: each target's rc is captured; a non-zero run sets
  any_fail and the final status is non-zero (was only logged before, Codex P1).
- Iterate the parsed array (for t in "${_targets[@]}") instead of unquoted
  word-splitting over $TARGETS.
Validated: bash -n, now(), nproc fallback, and the propagate-on-failure logic.

Signed-off-by: Nelson Spence <nelson@projectnavi.ai>
@project-navi-bot
Navi Bot (project-navi-bot) merged commit 66813fe into main May 26, 2026
24 checks passed
@project-navi-bot
Navi Bot (project-navi-bot) deleted the chore/full-fuzz-script branch May 26, 2026 15:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants