Skip to content

refactor: migrate fuzzing container to ContFuzzer v2 interface#22178

Draft
randyquaye wants to merge 15 commits intonextfrom
rq/contfuzzer-v2-container-compat
Draft

refactor: migrate fuzzing container to ContFuzzer v2 interface#22178
randyquaye wants to merge 15 commits intonextfrom
rq/contfuzzer-v2-container-compat

Conversation

@randyquaye
Copy link
Copy Markdown
Collaborator

Summary

  • Replaces v1 CLI-flag interface (--fuzzer, --mode, --asm) with v2 env-var contract (FUZZ_TARGET, FUZZ_MODE, FUZZ_JOBS, etc.)
  • Flattens all variant binaries into /targets/<name>[_suffix] so each variant is an independent schedulable target
  • New merge_fuzzer_manifests_v2.py outputs schema v2 manifest for ORAS discovery
  • Entrypoint handles all 4 modes: fuzz, coverage, minimize, reproduce

Files changed

File What
container-builds/fuzzing-container/src/Dockerfile v2 manifest generation, /targets/ flattening, ENTRYPOINT
container-builds/fuzzing-container/src/Dockerfile.private Same changes as above (private repo variant)
container-builds/fuzzing-container/src/entrypoint.sh Rewritten for env-var interface
container-builds/fuzzing-container/run.sh Updated local runner (--target flag, env vars)
barretenberg/cpp/scripts/merge_fuzzer_manifests_v2.py New: schema v2 manifest generator
barretenberg/cpp/scripts/merge_fuzzer_manifests.py Deleted (v1)

Test plan

  • Build image: cd container-builds/fuzzing-container && docker build src/ -t bb-fuzz
  • List targets: docker run --rm bb-fuzz ls /targets/
  • Fuzz locally: ./run.sh --target <name> --mode fuzz --timeout 60
  • Coverage: ./run.sh --target <name> --mode coverage
  • Verify manifest: docker run --rm bb-fuzz cat fuzzer_manifest.json | python3 -m json.tool

🤖 Generated with Claude Code

randyquaye and others added 2 commits April 1, 2026 10:04
Replaces the v1 CLI-flag interface (--fuzzer, --mode, --asm) with v2's
env-var contract (FUZZ_TARGET, FUZZ_MODE, FUZZ_JOBS, etc). Each variant
(asm, noasm, avm) is now an independent target under /targets/ so the
platform can schedule them as separate campaigns.

- Dockerfile: flattens all variant binaries into /targets/<name>[_suffix]
- entrypoint.sh: reads FUZZ_* env vars, dispatches fuzz/coverage/minimize/reproduce
- run.sh: updated local runner with --target flag
- merge_fuzzer_manifests_v2.py: outputs schema v2 manifest for ORAS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@randyquaye randyquaye force-pushed the rq/contfuzzer-v2-container-compat branch from 0b25eb9 to 4e49196 Compare April 1, 2026 09:04
…ulti-crash reproduce

Addresses review feedback on the v2 entrypoint:
- Decouple workers from jobs to allow memory-constrained targets to throttle concurrency
- Restore explicit verbosity=0 default to avoid log bloat
- Reproduce mode now iterates all crash files or targets a specific one via FUZZ_CRASH_FILE
@randyquaye randyquaye changed the title WIP: migrate fuzzing container to ContFuzzer v2 interface refactor: migrate fuzzing container to ContFuzzer v2 interface Apr 1, 2026
randyquaye and others added 12 commits April 1, 2026 15:16
- Collect per-job fuzz-*.log files from CWD into output dir
- Fix --list-targets broken by ENTRYPOINT (use --entrypoint ls)
- Align reproduce mode with platform: use FUZZ_REPRODUCE_DIR for batch
  input, copy confirmed crashers to FUZZ_CRASH_DIR for platform pickup
- Add libfuzzer exit code translation (77 → 137) in fuzz and reproduce
- Safe corpus merge with backup/restore on failure
- Add regress mode to manifest
…gs, restore)

- Add FUZZ_MERGE_JOBS/WORKERS/RSS_LIMIT with defaults to avoid flaky parallel merge
- Log merge output; validate swap/restore of corpus vs backup
- Fail coverage mode explicitly when coverage merge step fails

Made-with: Cursor
…fuzz-*.log

ContFuzzer runs containers with read_only=True. libFuzzer -jobs=N
creates fuzz-*.log in the CWD, which fails on a read-only rootfs.
Set CWD to $FUZZ_OUTPUT_DIR (/output, a writable bind-mount) after
env setup. All binary refs are absolute so this is safe.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace com.aztec.source-repo, com.aztec.source-branch, com.aztec.commit
with org.opencontainers.image.source, .revision.branch, .revision per
the OCI image spec. ContFuzzer v2 already reads these labels with a
fallback to com.aztec.* — the fallback will be removed after images
are rebuilt with this change.
…ython script

The Dockerfile had a 12-line shell loop cross-referencing 5 build dirs
to flatten binaries into /targets/, plus a separate merge_fuzzer_manifests_v2.py
to produce the v2 manifest. Both duplicated variant knowledge.

New flatten_and_manifest.py handles both in one pass: copies executables
with correct suffixes and generates the manifest from per-preset metadata.
Variant config lives in one VARIANTS list.

Output is identical: flat /targets/<name>[_suffix] tree + schema v2 manifest.
…rdcoded list

flatten_and_manifest.py no longer hardcodes a VARIANTS list — it reads
suffix and fuzzer metadata from per-preset manifests that CMake already
generates. Schedulable vs companion is expressed in the Dockerfile RUN
line (positional args vs --copy-only).

- generate_fuzzer_manifest.py: derive suffix from preset name, write to manifest
- CMakePresets.json: add missing FUZZER_PRESET_NAME to fuzzing-asan
- Dockerfiles: pass manifest paths to script instead of one-liner
The fuzzing-avm cmake preset rebuilds all base fuzzer targets as a side
effect of enabling FUZZING_AVM. Those 17 collateral rebuilds are
identical to the base preset and should not be scheduled as separate
jobs. Only the 14 AVM-specific fuzzers (avm_fuzzer_*, harness_*) are
now added to the manifest. Binaries are still copied to /targets/ for
the entrypoint.
Add llvm-cov export calls to do_coverage() so the container produces:
- coverage.json: summary stats (lines/functions covered/total) consumed
  by the ContFuzzer platform's coverage snapshot pipeline
- coverage.lcov: full per-file/per-line data for the granular viewer

Existing HTML report generation is preserved alongside.
…v JSON directly

The container now writes the native llvm-cov export JSON as coverage.json
instead of reshaping it with a python script. The platform handles both
the nested llvm-cov format and flat format for future engine support.
…ainer-internal

Platform now passes FUZZ_MEMORY (total budget, e.g. "2g") for containers
that want to derive per-process limits. This entrypoint leaves it
commented — sticks with its own FUZZ_RSS_LIMIT=2048 default, matching
the old next-branch behaviour.
The ContFuzzer platform runs containers with HOME=/tmp and a read-only
root filesystem. Three fuzzers (ipa, avm prover, translator_composer)
call bb_crs_path() which defaults to $HOME/.bb-crs — missing on tmpfs.
Setting CRS_PATH explicitly points them at the baked-in /root/.bb-crs.
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.

1 participant