Fuzzing¶
RigorFoundry parses untrusted, content-addressed audit records — reports,
candidates, review ledgers, and policies — that may arrive from other tools or
adopters. Every parser is contractually fail-closed: hostile or malformed
input must raise ValueError, never crash with an unexpected exception or hang.
Coverage-guided fuzzing verifies that contract continuously.
Harness¶
The fuzz/ directory holds Atheris
coverage-guided fuzz targets, one per untrusted-input parser:
| Target | Parser under test |
|---|---|
fuzz/fuzz_audit_report.py |
AuditReport.from_dict |
fuzz/fuzz_candidate.py |
Candidate.from_dict |
fuzz/fuzz_audit_policy.py |
AuditPolicy.from_json |
fuzz/fuzz_review_record.py |
ReviewRecord.from_dict |
Each target feeds fuzzer-derived bytes across the JSON boundary through the
shared helpers in fuzz/_record_fuzz.py. The helpers tolerate only the
contractual failure modes — ValueError (its fail-closed contract, of which
UnicodeDecodeError and json.JSONDecodeError are subclasses) and
RecursionError (CPython's bounded response to deeply nested input). Any other
exception propagates so the fuzzer records it as a genuine robustness finding.
Running locally¶
Install the hash-locked fuzzing environment (Atheris ships wheels for CPython 3.12 and newer) and run a target for a bounded time:
python -m pip install --require-hashes -r requirements/fuzz.txt
python -m pip install --no-build-isolation --no-deps .
python fuzz/fuzz_audit_report.py -max_total_time=60
A crash writes a reproducer file to the working directory; replay it by passing the file as an argument.
Continuous integration¶
The Fuzz workflow (.github/workflows/fuzz.yml) runs every target for a
bounded interval on each pull request, on main, and on a weekly schedule,
failing the job on any crash. The targets are not pytest tests and are not
collected by the suite; they exercise the parsers as adversarial input handlers
rather than as behavioural unit tests.