feat(engine): Fuzz-Harness Generator — export native AFL/honggfuzz test scaffolds - #1305
Merged
Gbangbolaoluwagbemiga merged 1 commit intoAug 1, 2026
Conversation
Implements HyperSafeD#415 — bridges static analysis to dynamic analysis by generating ready-to-build fuzz-target scaffolds from a Soroban contract's public ABI. New: - sanctifier-core::harness_spec — walks #[contractimpl] blocks and extracts every public, non-reserved function's typed parameter list (name + Rust type, e.g. Address, BytesN<32>, i128), excluding the mandatory leading Env parameter. - sanctifier-cli `harness` subcommand — for each function, generates: - a #[derive(Arbitrary)] input struct whose fields are <ParamType as SorobanArbitrary>::Prototype (the pattern documented by soroban_sdk::testutils::arbitrary for fuzzing host-managed types), - a main() that registers the contract, builds a client, converts each prototype via .into_val(&env), and calls client.try_<fn>(..), - one such target per backend (afl.rs and/or honggfuzz via --target), - a self-contained, workspace-excluded Cargo.toml per backend (mirroring the contracts/*/fuzz/Cargo.toml convention already used in this repo), auto-detecting and path-depending on the analyzed crate when a Cargo.toml is found above the source file. - docs/fuzz-harness-generator.md, linked from DOCUMENTATION_INDEX.md and the CLI reference in README.md. - Unit tests (sanctifier-core, sanctifier-cli) and end-to-end integration tests (tooling/sanctifier-cli/tests/harness_tests.rs) covering both backends, --target/--function filtering, generated file/manifest shape, crate auto-detection, and the no-fuzzable-functions case. Incidental prerequisite fixes (unrelated to HyperSafeD#415, but required for sanctifier-core/sanctifier-cli to compile at all without the optional `smt` feature, which needs libz3/libclang): - lib.rs / init.rs: SanctifyConfig's Default impls were missing the smt_timeout_ms field added in a previous change, a hard E0063 compile error present regardless of any feature flag. - noir_parser.rs: parse_function's Ok(..) tuple accidentally constructed a duplicate NoirFunction, giving a 4-element tuple where a 2-element (NoirFunction, usize) was expected — a hard E0308 error, also unconditional. - contract_discovery.rs: has_attr_named/type_to_name/RESERVED_ENTRYPOINTS changed from private to pub(crate) so harness_spec can reuse them instead of duplicating the same #[contractimpl] attribute-matching logic. Closes HyperSafeD#415
|
@dykdee is attempting to deploy a commit to the gbangbolaoluwagbemiga's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@dykdee Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
Contributor
Author
|
Hello repo maintainer, please can you approve the workflows quickly? the issue is fixed but you have not attended to the case. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Resolves #415 — "[engine] Fuzz-Harness Generator: Export native
Afl.rs/honggfuzztest scaffolds".Adds a new
sanctifier harnessCLI subcommand that bridges Sanctifier's static analysis (AST-level parsing) to dynamic analysis: given a Soroban contract source file, it generates ready-to-build native fuzz-target scaffolds forafl.rsand/orhonggfuzz, one per public contract function.How it works
sanctifier-core::harness_spec(new module) walks the same#[contractimpl]blocks thatcontract_discoveryalready knows about, but additionally extracts each public, non-reserved function's full typed parameter list (name + Rust type, e.g.Address,BytesN<32>,i128,Vec<Address>), skipping the mandatory leadingEnvparameter.sanctifier-cliharnesssubcommand turns that into code, for each requested backend:#[derive(Arbitrary)]input struct whose fields are<ParamType as SorobanArbitrary>::Prototype— the pattern documented bysoroban_sdk::testutils::arbitraryfor fuzzing host-managed Soroban types,main()that builds anEnv, registers the contract, builds a client, converts each prototype via.into_val(&env), and callsclient.try_<function>(..),Cargo.tomlper backend (mirroring thecontracts/*/fuzz/Cargo.tomlconvention already used in this repo), auto-detecting andpath-dependency-linking the analyzed crate when aCargo.tomlis found above the source file (falls back to a// TODOplaceholder otherwise).See
docs/fuzz-harness-generator.mdfor full usage, the generated-code shape, and how it relates to the existing hand-written bolero/libFuzzer harnesses documented indocs/contracts-fuzz.md(unchanged — this is a separate, additive generator, not a replacement).Testing
sanctifier-core::harness_spec(8 tests) coveringEnv-exclusion, generic/reference type rendering, reserved-entrypoint/private-function exclusion, multi-contract files, and positional-fallback naming for unpatternable parameters.sanctifier-cli::commands::harness(7 tests) covering snake-case conversion, manifest rendering (with/without crate detection), and generated source shape for both backends.tooling/sanctifier-cli/tests/harness_tests.rs(9 tests) covering: default (both backends),--target afl/--target honggfuzzselection,--functionfiltering, generated file/manifest content assertions, real crate auto-detection via a siblingCargo.toml, the "no fuzzable functions" case, and a nonexistent-path error case.contracts/amm-pool) — correctly detected the crate name/path and generated 12 valid targets.cargo clippy -p sanctifier-cli --no-deps -- -D warningsis clean for all new code.Incidental prerequisite fixes (unrelated to #415)
While getting
sanctifier-core/sanctifier-clito build in this environment (nolibclang/libz3, so the optionalsmtfeature can't be enabled), I found that both crates currently fail to compile in any feature configuration onmain— these are hard compile errors, not environment-specific:SanctifyConfig's twoDefault-equivalent constructors (sanctifier-core::lib.rsandsanctifier-cli::commands::init.rs) were missing thesmt_timeout_msfield that a previous change added to the struct (E0063).noir_parser::parse_function'sOk((...))accidentally constructed a duplicateNoirFunction, returning a 4-element tuple where(NoirFunction, usize)was expected (E0308) — clearly leftover from a bad merge.These three one-line/small fixes are included because they block compiling the very crates this feature lives in, in any configuration; they're unrelated to the harness generator itself. I did not go further and fix other pre-existing, unrelated clippy lints/test failures I noticed while investigating (e.g. a dead-code warning in
zk_verifier_skippable.rs, or an unrelated failing test inrules::z007_under_constrained) since those are out of scope for this issue.I also changed
has_attr_named/type_to_name/RESERVED_ENTRYPOINTSincontract_discovery.rsfrom private topub(crate)soharness_speccan reuse the existing#[contractimpl]-matching logic instead of duplicating it.Closes #415