Metadata-Version: 2.4
Name: fuzzprep
Version: 0.1.0
Summary: Prepare software libraries for reproducible OSS-Fuzz project generation.
Author: Trail of Bits
Author-email: Trail of Bits <opensource@trailofbits.com>
License-Expression: Apache-2.0
License-File: LICENSE
License-File: THIRD_PARTY_NOTICES.md
Requires-Dist: pyyaml>=6.0
Requires-Python: >=3.13
Project-URL: Homepage, https://pypi.org/project/fuzzprep/
Project-URL: Source, https://github.com/trailofbits/fuzzprep
Project-URL: Issues, https://github.com/trailofbits/fuzzprep/issues
Description-Content-Type: text/markdown

# FuzzPrep

FuzzPrep is a CLI that takes the manual effort out of building C/C++ libraries for fuzzing
while aiming to minimize LLM token cost. It detects the build system, builds the library,
probes harness compilation to find linker dependencies, and writes artifacts that build and
link the library against a harness.

## Prerequisites

### What FuzzPrep needs

- Python 3.13 and [`uv`](https://docs.astral.sh/uv/).
- `git`, to clone the target repository.
- `clang` and `clang++`, the default compilers. `--cc` and `--cxx` select others.
- libFuzzer's runtime, which `clang` links for the default `-fsanitize=fuzzer` harness flags.
  It is a separate package: `libclang-rt-dev` on Debian and Ubuntu, `compiler-rt` elsewhere.
  A plain `apt install clang` pulls it in as a recommended package, but an install that uses
  `--no-install-recommends` does not, so name it.

```bash
sudo apt update
sudo apt install -y git clang libclang-rt-dev
```

### Common library build dependencies

A target brings its own build dependencies: the build system it uses, and the `-dev` packages
it links against. FuzzPrep reports the packages a failed run is missing. The below script also installs a set that covers many targets — the four supported build systems, the usual codegen and
archive utilities, and the libraries FuzzPrep knows how to identify from error traces:

```bash
./scripts/install_common_deps.sh
```

The list is not exhaustive. When a build fails on a dependency the script does not cover,
install that dependency and run again.

### Optional

- Docker, for `--environment oss-fuzz`.
- The `claude` or `codex` CLI, for agent repair. It is on by default; `--no-agents` turns it
  off and no CLI is then needed.
- [`bear`](https://github.com/rizsotto/Bear), for Make and Autotools targets built with
  `--environment local`. It captures `compile_commands.json`, which `extract-features` and
  `generate-yaml` read.
- `cmake`, `llvm-dev`, `libclang-20`, and `libclang-dev`, which `extract-features` builds its Clang
  LibTooling parser against. With more than one LLVM installed, point `CMAKE_PREFIX_PATH` at
  the tree the `clang` on `PATH` belongs to.

The apt packages among these:

```bash
sudo apt install -y bear cmake llvm-dev libclang-dev libclang-20
```

## Install

```bash
uv sync
```

## Quickstart

>**Best practice:** Run FuzzPrep in a container or disposable VM. FuzzPrep compiles and executes
> arbitrary build-system logic from the target library. Its agentic workflow may also write and
> execute build scripts, so it should be run in an isolated environment.

From a local checkout after `uv sync`:

```bash
# Clones the repository, builds it, verifies it, and writes `output/zlib/`.
uv run fuzzprep generate https://github.com/madler/zlib.git
```

To run FuzzPrep without cloning this repository:

```bash
uvx fuzzprep generate https://github.com/madler/zlib.git
```

Other useful flags include:

```bash
# Verify in the OSS-Fuzz Docker environment instead of on the host
uv run fuzzprep generate <REPO_URL> --environment oss-fuzz

# Turn off agent repair: a failed build then simply fails the run
uv run fuzzprep generate <REPO_URL> --no-agents

# Pass build-system configure options (repeat for more than one)
uv run fuzzprep generate <REPO_URL> --library-configure-arg=-DCARES_STATIC=ON

# Skip the from-scratch rebuild that validates an agent's repair, for a faster run
uv run fuzzprep generate <REPO_URL> --bypass-scratch-validation

# Use distinct library and final-harness instrumentation defaults
uv run fuzzprep generate <REPO_URL> --environment local \
  --cc clang --cxx clang++ \
  --library-cflags='-fsanitize=fuzzer-no-link,address' \
  --library-cxxflags='-fsanitize=fuzzer-no-link,address' \
  --harness-cflags='-fsanitize=fuzzer,address' \
  --harness-cxxflags='-fsanitize=fuzzer,address'
```

Agent repair is on by default and calls a paid network service. `--agent claude` (the
default) or `--agent codex` selects the backend; `--no-agents` turns it off.

See `uv run fuzzprep generate --help` for the full set of options (custom output
location, pinning a branch/tag/commit, a different base image, etc).

### Adaptable builds

The generated build scripts let you supply your own toolchain and flags:

```bash
CC=afl-clang-fast CXX=afl-clang-fast++ \
CFLAGS=-fsanitize=address CXXFLAGS=-fsanitize=address \
  ./build_library.sh
```

### When a run fails

FuzzPrep keeps its working state in `.fuzzprep/<project>/`: the workspace it built in,
`logs/` with the raw output of each phase, and `stats.json`. A failed run writes no output
directory, but the library build artifacts stay in `.fuzzprep/<project>/install/` if you want
to debug the link line there. Add `--log-level debug` for more detail, or `--quiet` to hide
the raw subprocess output while a phase runs.

## What it does

1. Detects the build system: CMake, Meson, Autotools, or Makefile.
2. Builds the library with a deterministic script. If that build fails, an agent repairs it.
3. Probes harness compilation to find transitive linker dependencies. If the probe fails,
   an agent repairs it.
4. Writes the output directory `<output>/<project>/`.

## Output

The output directory provides a reproducible OSS-Fuzz project and a standalone host build
tree. `docker build .` works, and so does `./setup.sh && ./build_library.sh`.

```
output/<project>/
├── Dockerfile             # OSS-Fuzz project files
├── project.yaml           # OSS-Fuzz project metadata
├── .dockerignore
├── setup.sh               # Script for repo clone + apt dependencies
├── build.sh               # Builds the library and compiles the provided harness
├── build_library.sh       # build and install the library into install/
├── compile_harness.sh     # compile and link one harness source
├── compile_harnesses.sh   # compile every source in harness_source/ into out/
├── harness_source/        # source code of all harnesses
├── install/               # the library this run built
├── compile_commands.json  # captured compile commands
├── stats.json             # what this run did: durations, agent use, status
└── README.md              # what this run verified, and how to run it
```

`harness_source/` starts with a stub — an `LLVMFuzzerTestOneInput` with a
`// TODO: Add fuzzing logic` body. FuzzPrep proves the harness *compiles and links* against
the library; writing the fuzzing logic is yours.

## Environments

`--environment` selects where this run builds and verifies. It does not change what is
generated: the output directory always holds both setups. The generated `README.md` records
which of the two this run exercised.

- `local` — build and verify on the host.
- `oss-fuzz` — build and verify in an OSS-Fuzz compatible Docker container, then prove the
  generated Dockerfile builds from scratch.

Neither environment isolates the target's build from your machine well enough to trust it.
Run both inside a VM or an isolated machine.

## Other commands

`generate` produces a `compile_commands.json` file that two follow-on commands consume, to
extract the library's API surface (`extract-features`) and to produce an OSS-Fuzz-Gen
compatible YAML input (`generate-yaml`).

```bash
uv run fuzzprep extract-features <BUILD_PATH>   # -> features.json (run this first)
uv run fuzzprep generate-yaml <BUILD_PATH>      # -> <project>.yaml
```

`extract-features` runs a Clang LibTooling-based parser over every header and source file in
`compile_commands.json`. It writes `<BUILD_PATH>/features.json`, a structured inventory of
the library's C/C++ declarations:

- `functions` — name, return type, parameters, full signature, declaring header, and
  whether it is public API (declared in a header, not `static`)
- `typedefs` — name, underlying type, declaring header
- `macros` — name, object- or function-like, parameters (if function-like), value,
  declaring header
- `enums` — name (if any), enumerators with their values, declaring header
- `records` — structs and unions: name (if any), `kind`, fields, declaring header
- `warnings` — non-fatal problems found during the parse

`generate-yaml` reads `features.json` and keeps only the public functions. To get
finer-grained output, name one or more headers and it keeps only the functions those headers
declare:

```bash
uv run fuzzprep generate-yaml <BUILD_PATH> zlib.h zconf.h
```

Run `uv run fuzzprep --help` for details.

## Security

FuzzPrep clones and builds arbitrary third-party repositories, which runs their build systems
on your machine, and it hands a repair agent write access to the run's workspace.

Run it in a VM or on a dedicated machine you can wipe, whatever `--environment` you pick. A
container shares the host kernel and is not a boundary that holds against code written to
break out of one, so `--environment oss-fuzz` reduces the blast radius of an ordinary build
but does not contain a hostile one. `--no-agents` turns agent repair off.

[SECURITY.md](SECURITY.md) has the full threat model and tells you how to report a
vulnerability.

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for the local setup, the checks a pull request must
pass, and what each pytest marker needs. Participation is governed by the
[Code of Conduct](CODE_OF_CONDUCT.md).

## License

FuzzPrep is licensed under [Apache-2.0](LICENSE).

The `feature_extractor` tool that `extract-features` builds links cJSON and the LLVM/Clang
libraries. [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) records their licenses and the
notices that apply if you redistribute that binary.

Some files under `tests/real_harnesses/` come from upstream projects and keep their own
licenses; [that directory's README](tests/real_harnesses/README.md) records the provenance of
each one.
