Skip to content

#383 — test: first fuzz target on the --pr-diff patch parser - #385

Merged
cmbays merged 2 commits into
mainfrom
test-383-fuzz-prdiff-parser
Jun 14, 2026
Merged

cmbays merged 2 commits into
mainfrom
test-383-fuzz-prdiff-parser

Conversation

@cmbays

@cmbays cmbays commented Jun 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Wires cute-dbt's first fuzz target (the org's named "single most valuable Q4 move") over the highest-risk untrusted-input surface: the --pr-diff unified-diff parser (cli::pr_diff::parse_unified_diff). In CI/PR-review mode arbitrary diff text is fed in, so this is the realistic adversarial surface.

Closes #383

Toolchain — bolero on STABLE Rust (no nightly, no libFuzzer)

bolero is chosen over cargo-fuzz because its DefaultEngine mimics libtest and runs under plain cargo test / cargo nextest on the crate's MSRV 1.88 — it replays the committed corpus/ and generates fresh random inputs, with no nightly, no libFuzzer, and no cargo-bolero binary required to exercise the corpus. That lowest-friction property is exactly the AC.

What lands

  • Fuzz target tests/fuzz_pr_diff_parser/main.rs (harness = false, like bdd) driving bolero::check!().for_each(|bytes: &[u8]| …). It asserts the fail-closed contract ("cute-dbt never panics on a bad diff"): for any byte sequence the parser never panics/hangs, returns Ok(PrDiff)/Err only, emits a structurally well-formed POD on success (no embedded newlines in parsed paths/bodies), and is deterministic.
  • Seam: parse_unified_diff → pub(crate) + a #[doc(hidden)] cli::fuzz_parse_unified_diff re-export (the pure parser — no @file filesystem I/O on the fuzzed path). Not public API; same internal-reach motive as the bdd target. Does not trip non-mirror-guard (that greps src/lib.rs for pub use crate::…::…; this seam lives in src/cli/mod.rs).
  • Committed seed corpus (14 inputs) under tests/fuzz_pr_diff_parser/corpus/ per the regression-files-committed rule — valid + adversarial shapes (orphan hunk header, +++ body line, pure rename, CRLF, malformed/huge ranges, prose, empty/whitespace).
  • Non-blocking CI: a separate .github/workflows/fuzz.yml (workflow_dispatch + weekly cron), NOT a merge gate and not in branch protection. Reuses only actions already in ci.yml (no new org-allowlist entry). The cheap corpus replay rides the normal Test job (cargo test builds the target; the corpus replays there).
  • testing.md: Fuzz rung aspirational — → in-progress; Q4 WEAK → improving; remaining candidates noted (manifest JSON reader, RFC-4180 CSV parser). The quality-manifest mirror in ops is a follow-up.

Bounded-run result

BOLERO_RANDOM_ITERATIONS=1000000 + the 14-input corpus → zero crashes (~277k iters/s, ~3.6s), no crashes/ or hangs/ produced. The parser was already fail-closed, so no parser fix was needed (including the @@ … +1,99999999999999999999 @@ usize-overflow path, which correctly returns Err, never panics).

Deps + gates

  • 15 new transitive crates, all MIT / MIT-OR-Apache-2.0 — already in deny.toml's allowlist. cargo deny check: advisories ok, bans ok, licenses ok, sources ok (no license change). multiple-versions stays warn per the v0.x policy.
  • cargo fmt --check, cargo clippy --all-targets --locked -- -D warnings, cargo nextest run (2052 passed), RUSTDOCFLAGS=-D warnings cargo doc --no-deps --locked — all green.
  • No render change → goldens byte-identical (git status examples/ empty). No .feature change → feature-count mirror untouched.

test: prefix → no version bump.

HELD for founder review — this adds a dev-dep + a fuzz toolchain decision. Do not merge without Christopher's sign-off.

🤖 Generated with Claude Code


Open in Stage

Summary by CodeRabbit

  • Tests

    • Added automated fuzzing test suite for the --pr-diff patch parser with validation of edge cases and malformed inputs.
    • Expanded test coverage with 14 seed scenarios covering file operations, various diff formats, unusual headers, and whitespace handling.
  • Documentation

    • Updated testing progress documentation to reflect completed fuzzing infrastructure.

Wire cute-dbt's first fuzz target (the Q4 bring-into-shape move) over the
highest-risk untrusted-input surface: the `--pr-diff` unified-diff parser
(`cli::pr_diff::parse_unified_diff`). In CI/PR-review mode arbitrary diff
text is fed in, so this is the realistic adversarial surface.

Harness: bolero on STABLE Rust (MSRV 1.88) — its DefaultEngine mimics
libtest and runs under plain `cargo test`/`cargo nextest`, replaying the
committed corpus AND generating fresh random inputs, with no nightly, no
libFuzzer, and no `cargo-bolero` binary required. Chosen over cargo-fuzz
for exactly that lowest-friction property.

The target asserts the fail-closed contract ("cute-dbt never panics on a
bad diff"): for any byte sequence the parser never panics/hangs, returns
Ok(PrDiff) or Err only, emits a structurally well-formed POD on success
(no embedded newlines in parsed paths/bodies), and is deterministic. A
bounded in-session run of 1,000,000 random iterations + the 14-input seed
corpus surfaced zero crashes — the parser was already fail-closed, so no
parser fix was needed.

- Expose `parse_unified_diff` as `pub(crate)` + a `#[doc(hidden)]`
  `cli::fuzz_parse_unified_diff` seam (the pure parser, no `@file` I/O on
  the fuzzed path). Not public API; same internal-reach motive as `bdd`.
- Seed corpus committed (regression-files-committed rule) under
  tests/fuzz_pr_diff_parser/corpus/ — valid + adversarial shapes (orphan
  hunk header, `+++` body line, pure rename, CRLF, malformed/huge ranges,
  prose, empty/whitespace).
- All 15 new transitive crates are MIT / MIT-OR-Apache-2.0 (already in
  deny.toml's allowlist) — `cargo deny check` stays green, no license
  change. multiple-versions stays "warn" per the v0.x policy.
- Non-blocking CI: a separate `fuzz.yml` (workflow_dispatch + weekly cron),
  NOT a merge gate and not in branch protection; reuses only actions
  already in ci.yml. The cheap corpus replay rides the normal Test job.
- testing.md: Fuzz rung aspirational -> in-progress; Q4 WEAK -> improving;
  remaining candidates noted (manifest JSON reader, RFC-4180 CSV parser).
  The quality-manifest mirror in ops is a follow-up.

Closes #383

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jun 14, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fdc255ce-96aa-4572-8f52-124ca0d27669

📥 Commits

Reviewing files that changed from the base of the PR and between f67a393 and e2a2907.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (20)
  • .claude/rules/testing.md
  • .github/workflows/fuzz.yml
  • Cargo.toml
  • src/cli/mod.rs
  • src/cli/pr_diff.rs
  • tests/fuzz_pr_diff_parser/corpus/seed_bad_hunk_header
  • tests/fuzz_pr_diff_parser/corpus/seed_bad_old_range
  • tests/fuzz_pr_diff_parser/corpus/seed_bare_at
  • tests/fuzz_pr_diff_parser/corpus/seed_crlf
  • tests/fuzz_pr_diff_parser/corpus/seed_deleted_file
  • tests/fuzz_pr_diff_parser/corpus/seed_empty
  • tests/fuzz_pr_diff_parser/corpus/seed_huge_range
  • tests/fuzz_pr_diff_parser/corpus/seed_new_file
  • tests/fuzz_pr_diff_parser/corpus/seed_orphan_hunk
  • tests/fuzz_pr_diff_parser/corpus/seed_plus_body
  • tests/fuzz_pr_diff_parser/corpus/seed_prose
  • tests/fuzz_pr_diff_parser/corpus/seed_pure_rename
  • tests/fuzz_pr_diff_parser/corpus/seed_simple_edit
  • tests/fuzz_pr_diff_parser/corpus/seed_whitespace
  • tests/fuzz_pr_diff_parser/main.rs

📝 Walkthrough

Walkthrough

A Bolero-based fuzz harness is wired for the --pr-diff unified-diff parser. parse_unified_diff gains pub(crate) visibility and a public fuzz_parse_unified_diff seam; Cargo.toml registers the bolero dependency, a harness = false test target, and a [profile.fuzz] build profile. Thirteen seed corpus files are committed, and a GitHub Actions workflow runs bounded fuzz campaigns on schedule and manual dispatch.

Changes

--pr-diff fuzz pilot

Layer / File(s) Summary
Cargo wiring and parser fuzz seam
src/cli/pr_diff.rs, src/cli/mod.rs, Cargo.toml
parse_unified_diff is made pub(crate); a #[doc(hidden)] fuzz_parse_unified_diff public wrapper is added to src/cli/mod.rs; bolero = "0.13.4" is added as a dependency; a fuzz_pr_diff_parser test target with harness = false and a [profile.fuzz] are registered.
Bolero harness and committed seed corpus
tests/fuzz_pr_diff_parser/main.rs, tests/fuzz_pr_diff_parser/corpus/*
The harness converts fuzzed bytes to lossy UTF-8, calls fuzz_parse_unified_diff, and on Ok asserts no embedded \n in file paths/hunk lines/rename fields, plus parse idempotence. Thirteen seed files cover simple edits, new/deleted files, pure rename, CRLF, orphan hunk, bad hunk headers, malformed ranges, huge ranges, bare @@, whitespace, and prose.
CI workflow and testing docs
.github/workflows/fuzz.yml, .claude/rules/testing.md
New fuzz.yml runs cargo test --test fuzz_pr_diff_parser --locked with BOLERO_RANDOM_ITERATIONS validated from input, on weekly schedule and workflow_dispatch. testing.md marks the --pr-diff bolero target as Done, upgrades Q4 status from WEAK to improving, and identifies CSV and manifest JSON parsers as next fuzz targets.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • breezy-bays-labs/cute-dbt#184: Extends parse_unified_diff in src/cli/pr_diff.rs to record rename from/rename to pairs into PrDiff::renames, the same parser function now exposed as a fuzz seam and exercised by the new seed_pure_rename corpus entry.

Poem

🐇 Hop hop, I throw garbage bytes at the diff,
The parser stays steady — no panic, no cliff.
Seeds of bad hunks and bare @@ I toss,
Bolero counts millions, I'm never at loss.
✨ Fuzzing is done (well, the first bit at least),
Next up: the CSV parser, a quite different beast!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: introducing the first fuzz target for the --pr-diff patch parser, which aligns with the primary objective of the PR.
Linked Issues check ✅ Passed All acceptance criteria from issue #383 are met: fuzz target created over --pr-diff parser with bolero on stable Rust, fail-closed verification passed, corpus committed, testing.md updated, and CI workflow documented as non-blocking.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing the fuzz target infrastructure and documentation: no unrelated refactoring, cleanup, or feature creep is present.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test-383-fuzz-prdiff-parser

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ghost

ghost commented Jun 14, 2026 •

Copy link
Copy Markdown

Ready to review this PR? Stage has broken it down into 7 individual chapters for you:

Title
1 Add bolero dependency and fuzzing profile
2 Expose internal parser via fuzzing seam
3 Implement the pr-diff parser fuzz target
4 Add initial seed corpus for fuzzing
5 Configure scheduled fuzzing workflow
6 Update testing documentation and status
7 Other changes
Open in Stage

Chapters generated by Stage for commit e5ac304 on Jun 14, 2026 1:09am UTC.

@github-actions

github-actions Bot commented Jun 14, 2026 •

Copy link
Copy Markdown
Contributor

📄 Rendered report preview

All golden examples regenerated cleanly.

🟡 Golden examples

Committed to examples/ and byte-identity gated — the canonical reports contributors and consumers browse. Stable across PRs.

Report View Download
jaffle-shop-report.html ▶ Open ↗ ⬇ Download
diff-showcase-report.html ▶ Open ↗ ⬇ Download
macro-heavy-report.html ▶ Open ↗ ⬇ Download
playground-report.html ▶ Open ↗ ⬇ Download

🐶 Live dogfood preview

This PR doesn't touch dbt-project/, so there's no live dogfood preview.

🧭 Explore preview

The two-page cute-dbt explore explorer — dag.html (model lineage) + tests.html (unit-test viewer). Same golden/live split as the report.

🟡 Golden explore

The committed examples/explore/ playground golden (the full synthetic playground manifest). Byte-identity gated in Example report check. Stable across PRs.

Page View Download
explore/dag.html ▶ Open ↗ ⬇ Download
explore/tests.html ▶ Open ↗ ⬇ Download

🐶 Live explore

This PR doesn't touch dbt-project/, so there's no live explore preview.

▶ Open ↗ opens the report or explorer in your browser in one
click — published to this repo's GitHub Pages under
/pr-385/.
⬇ Download fetches the same self-contained HTML as a workflow
artifact (auth-gated; works fully offline). Either way the report
makes zero external resource requests.

The Pages preview may take ~1 min to update after this comment
posts. On PRs from forks the Open link is unavailable (read-only
token) — use Download.

Alternative: GitHub CLI
# gh CLI >= 2.63 extracts into ./report-preview-playground/.
gh run download 27484340693 -R breezy-bays-labs/cute-dbt -n report-preview-playground
open report-preview-playground/playground-report.html

Posted by report-preview.yml for e5ac3049fb373e418dfcdd3fc0286ca89ef61117. Affordance only — never blocks merge.

@cmbays
cmbays merged commit 468d3f0 into main Jun 14, 2026
39 checks passed
@cmbays
cmbays deleted the test-383-fuzz-prdiff-parser branch June 14, 2026 01:19
github-actions Bot added a commit that referenced this pull request Jun 14, 2026
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.

test: first fuzz target — --pr-diff patch parser (Q4 bring-into-shape)

1 participant