Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/monetize

fuzz/README.md

monetize's fuzz targets

The parsers of monetize's open crates that read bytes someone else chose, one cargo-fuzz target each. Every target calls one entry function in src/lib.rs, the same function tests/seeds.rs drives on a plain cargo test.

target what it reads monetize code
pay_callback a payment vendor's callback (POST /callback/<kind>/<instance>): headers and body monetize-pay sandbox (JSON, signature header, signup arm), invoice (import token, BgMax/KTL bank file, OCR check digits), time
feed_config the operator's feed (PUT /feed, a JSON object of strings) and monetize.toml monetize-front intake (plugins, blocks, prices, secrets, vendors, principals, clouds, guests), monetize-server config (the whole config and its checks, product and vendor blocks), monetize-estate-side FleetConfig::from_feed, ShopDoor::from_feed
signed_facts what a product checks before it believes monetize monetize-embed EntitlementCache::refresh / push, verify_go_ahead, verify_estate_growth, ticket::verify_ticket
fleet_door a box's signed call (protobuf FleetSigned) monetize-guardian first_call, report, orders, ask (the old sold-estate door folded into Fleet.Ask)
fleet_orders the orders a box pulls (protobuf FleetOrdersAnswer) and a front's ask answers monetize-estate-side Puller::pull / check, the order bodies (GrowGoAhead, SignInAgain, Refeed, a restated snapshot)

The vendors in the private monetize-impl (Stripe, Klarna, Swish) are fuzzed in that repository's own fuzz crate. monetize reads no RON.

Modes. The first byte of an input picks a mode. Even: the rest goes to the code exactly as it came (the refusal paths: framing, envelope, signature). Odd: the harness signs what the rest says with the throwaway key the code under test trusts, so mutations also reach the parsers that only run on a verified input. No check of the code under test is skipped.

corpus/<target>/ holds the seeds src/lib.rs seeds() makes from throwaway keys. A seed named ok-* must be accepted by its target, a refused-* one must not (tests/seeds.rs fails otherwise), so the fuzzer starts at the deep end of each parser. cargo test --manifest-path fuzz/Cargo.toml --no-default-features -- --ignored write_seeds regenerates them. The grown corpus and any crash files stay out of git.

Running

With cargo-fuzz and a nightly toolchain: cargo fuzz run <target> from the repository root.

With plain stable cargo (what the dwarves forge does every night, cargo ci-verbs fuzz):

RUSTFLAGS="--cfg fuzzing -Cpasses=sancov-module -Cllvm-args=-sanitizer-coverage-level=4 \
  -Cllvm-args=-sanitizer-coverage-inline-8bit-counters -Cllvm-args=-sanitizer-coverage-pc-table \
  -Cllvm-args=-sanitizer-coverage-trace-compares -Cdebug-assertions -Coverflow-checks" \
  cargo build --release --locked --manifest-path fuzz/Cargo.toml --bins --target x86_64-unknown-linux-gnu
mkdir -p /tmp/corpus/fleet_door && cp fuzz/corpus/fleet_door/* /tmp/corpus/fleet_door/
fuzz/target/x86_64-unknown-linux-gnu/release/fleet_door -max_total_time=600 -artifact_prefix=/tmp/crashes/ /tmp/corpus/fleet_door

--target matters: without it the instrumentation flags reach build scripts and proc-macros too, and those do not link. The crate needs the siblings monetize's root needs (edda, Skidbladnir) beside the checkout. A crash becomes a regression test in the crate that owns the parser, with the crashing input, before the fix.