fuzzrun
fuzzrun
Run every Go fuzz target of a module, in parallel within a load budget, and report crashers. Repository → Latest tag: v0.1.0; this page is written from its README at that tag.
go test -fuzz runs one target of one package at a time, so a module with thirty
targets needs thirty commands, and a run left unattended either overloads the machine
or leaves it idle. fuzzrun finds the targets, runs a few at once, waits for the
machine to be quiet enough before starting each one, keeps one log per target, and
says in a summary which target crashed and where the corpus file that reproduces it
was written.
Install
GOBIN=~/.local/bin go install github.com/go-fleettools/fuzzrun@latestfuzzrun run
fuzzrun run [--dir .] [--time 10m] [--jobs 3] [--parallel 2] \
[--max-load 0] [--logs DIR] [--package pattern...]- Targets are found by parsing the
*_test.gofiles (go/parser, not a regular expression): top-levelfunc FuzzXxx(f *testing.F)..gitandtestdataare skipped, and a test file that does not parse is an error, never silently zero targets. - Each target runs as
go test -run=^$ -fuzz=^Name$ -fuzztime=D -parallel=P ./pkgwithGOWORK=off, at most--jobsat a time, its output in<logs>/<pkg>-<Name>.log. --max-load L(L > 0): before starting each target, wait while the 1-minute load average is above L. It is read fromsysctl vm.loadavgon darwin and/proc/loadavgon linux. Where it cannot be read,runexits 2 up front instead of pretending the machine was quiet.--packagekeeps only matching packages (repeatable).- A target that fails with a
Failing input written to testdata/fuzz/<Name>/<hash>line is aCRASH, and the summary gives that path relative to the module. Any other failing exit is aFAIL, with the log to read.
PASS ./. FuzzGood 5s
CRASH ./. FuzzBad 1.2s testdata/fuzz/FuzzBad/6f1c...
2 targets: 1 PASS, 0 FAIL, 1 CRASHExit status: 0 every target passed, 1 at least one FAIL or CRASH, 2 the run
could not be made (no go.mod, no targets, go missing, bad flags, unreadable load
with --max-load).
fuzzrun wait
fuzzrun wait FILE SUBSTRING [--timeout 10m] [--interval 2s]Blocks until FILE contains SUBSTRING, for example a log written by a background
fuzzrun run. It prints found (exit 0) or timeout (exit 1); exit 2 on a read
error other than the file not existing yet.
Why
The fuzz targets of a module are a security control only if they are actually run,
all of them, for long enough, without taking the machine down. The tool came out of
the go-llmflow/gateway security audit, where thirty targets were run by hand with a
shell loop that could not tell a crash from a timeout. Its tests plant a failing
target and require run to report it with its corpus path and exit 1; the module is
copied to a temporary directory first, so the corpus a crash writes never lands in
the repository.