3.6 KiB
3.6 KiB
id, name, status, depends_on, scope, risk, impact, level, tags
| id | name | status | depends_on | scope | risk | impact | level | tags | |||
|---|---|---|---|---|---|---|---|---|---|---|---|
| fuzz-target-payload-codec | Fuzz target — `payload_codec` (core payload encode/decode invariants) | pending |
|
moderate | low | component | implementation |
|
Description
The §3.1 target: payload_codec, driving core's payload surface
(alkstore/src/payload.rs — encode_payload, payload_as::<T>) —
already-pub API, no exposure needed.
fuzz_targets/payload_codec.rs— the thinfuzz_target!wrapper (3-line pattern) delegating toalkstore_fuzz_shared::payload_codec::fuzz_payload_codec(data); the[[bin]]entry lands infuzz/Cargo.toml.shared/src/payload_codec.rs— the invariant logic, with the#[cfg(test)]corpus-replay module (the gate). Input: raw&[u8]plusarbitrary-derivedserde_json::Values (theJsonValuebounded-depth helper from the scaffold). Invariants (§3.1, verbatim):- no-panic on any byte sequence (the baseline);
- typed-failure partition: every decode failure is
Error::Codec— no other variant, no panic (the ADR-023 §1 fallibility pin, demonstrated across the input space); - deep-input loudness: serde_json's recursion limit surfaces as
typed
Codec, never a stack overflow; - Value round-trip:
encode_payload(v)→payload_as::<Value>yieldsvfor every arbitraryValue(canonicalization is serde_json's, pinned-not-regressed); - typed round-trip: for a representative typed-payload set,
encode(Value::from(t))decodes back tot(the ADR-020 §4 decode side).
- Seeds (§3.1's list, via
gen_fuzz_seeds.pygaining thepayload_codecfunction): valid JSON of every Value variant, truncations, deep nesting at and past the recursion limit, non-UTF-8 bytes, trailing garbage, oversized numbers, duplicate keys, theNull-decode shape (ADR-023 §1's empty-byte-store corruption note). Corpus committed underfuzz/corpus/payload_codec/; thefuzz/.gitignoregains the!corpus/payload_codecnegation. fuzz/README.mdtargets-table row.shared's manifest gainsalkstore(path) if the scaffold didn't already carry it, plusserde_json+arbitrary.
Campaign flags are the campaign task's concern (-max_len=65536 -dict=json.dict starting point, §7); this task lands target + seeds +
replay.
Acceptance Criteria
fuzz_targets/payload_codec.rs+shared/src/payload_codec.rsexist;cargo fuzz buildbuilds the target (nightly, ASAN)- All five §3.1 invariants implemented in
sharedand exercised by both the fuzz path and the#[cfg(test)]replay module - Seed corpus committed (
fuzz/corpus/payload_codec/), generated bypython3 fuzz/gen_fuzz_seeds.py(deterministic — re-running is a no-op diff); gitignore negation in place cargo test --manifest-path fuzz/shared/Cargo.tomlgreen (replays the committed corpus through the invariants)sharedclippy/fmt gates green (cargo clippy --manifest-path fuzz/shared/Cargo.toml --all-targets -- -D warnings,fmt --check)- Root workspace gates still green
References
- docs/research/fuzzing.md §3.1 (target spec), §4 (wave-1 scope), §7 (flags)
- docs/architecture/decisions/020-payload-encoding.md §4 (the encoding posture the round-trips pin)
- docs/architecture/decisions/023-fourth-review-round.md §1 (encode fallibility)
- /workspace/@alkdev/alksocks/fuzz/shared/src/datagram_codec.rs (the invariant-module + replay-test pattern)
Notes
To be filled by implementation agent
Summary
To be filled on completion