Files
alkstore/fuzz
glm-5.3-flash a9b6cf0c86 adopt the tracing log facade, engine crates only (review 004 item 7's family-level decision, ADR-025): the family precedent checked and unanimous (alkcall/alktunnels/alksocks/alktty all on tracing = "0.1" facade-only, tracing-subscriber env-filter a dev-dep where present, silent by default); user sign-off taken in-session (2026-10-11, adopt-tracing option chosen) and recorded in the ADR's status; core stays dep- and emit-free (the explicit core-dep answer — the payload serde deps remain the sole core deps, the ADR states the ADR-020-§4 reading explicitly); all 19 library-path eprintln! sites migrated to tracing::warn!/error! with message text + the alkstore: prefix + the secret-free discipline unchanged (17 at review time, +2 from the review's own inline tick/lease restructures — re-grepped, sqlite 10 / pg 9, zero remainder, tests' harness-skip prints untouched); levels: warn = retried/degraded ops, error = unrecoverable loss (watcher death, discarded pooled clients, panic-path rollback failures); the four substrate-lineage files ride PROVENANCE delta D-41 (message-identical macro swap); deployment.md gains the diagnostics-posture section (operator recipe RUST_LOG=warn/error at the consuming binary; listener application_name diagnosability joins it), ADR index + design-decisions table carry the 025 row, CHANGELOG's 0.1.0 body states the facade; pg-fix-forwarder-diagnosability's output form now pinned (warn on failed reconnect connects with attempt/backoff context, error on the loop-exit poll error); gates green: build, workspace tests server-less, clippy -D warnings, fmt, doc gate zero warnings, fuzz corpus replay 6/6; task -> completed
2026-10-11 14:19:07 +00:00
..
adopt the tracing log facade, engine crates only (review 004 item 7's family-level decision, ADR-025): the family precedent checked and unanimous (alkcall/alktunnels/alksocks/alktty all on tracing = "0.1" facade-only, tracing-subscriber env-filter a dev-dep where present, silent by default); user sign-off taken in-session (2026-10-11, adopt-tracing option chosen) and recorded in the ADR's status; core stays dep- and emit-free (the explicit core-dep answer — the payload serde deps remain the sole core deps, the ADR states the ADR-020-§4 reading explicitly); all 19 library-path eprintln! sites migrated to tracing::warn!/error! with message text + the alkstore: prefix + the secret-free discipline unchanged (17 at review time, +2 from the review's own inline tick/lease restructures — re-grepped, sqlite 10 / pg 9, zero remainder, tests' harness-skip prints untouched); levels: warn = retried/degraded ops, error = unrecoverable loss (watcher death, discarded pooled clients, panic-path rollback failures); the four substrate-lineage files ride PROVENANCE delta D-41 (message-identical macro swap); deployment.md gains the diagnostics-posture section (operator recipe RUST_LOG=warn/error at the consuming binary; listener application_name diagnosability joins it), ADR index + design-decisions table carry the 025 row, CHANGELOG's 0.1.0 body states the facade; pg-fix-forwarder-diagnosability's output form now pinned (warn on failed reconnect connects with attempt/backoff context, error on the loop-exit poll error); gates green: build, workspace tests server-less, clippy -D warnings, fmt, doc gate zero warnings, fuzz corpus replay 6/6; task -> completed
2026-10-11 14:19:07 +00:00

alkstore fuzzing

libFuzzer targets for alkstore's parse/codec surfaces (see docs/research/fuzzing.md for the full rationale and campaign plan).

Layout

  • fuzz_targets/ — one binary per target; thin fuzz_target! wrappers.
  • shared/ — the invariant logic, as a plain library so normal cargo test (stable toolchain) can replay the committed corpora through the same invariants (fuzz/shared/src/*.rs #[cfg(test)] modules; quinn's CI pattern). The fuzz binaries are nightly-only; the shared crate is stable-clean. It consumes alkstore's public API only and must never become a dependency of any workspace crate.
  • corpus/<target>/ — committed hand-made seeds (regenerate with python3 fuzz/gen_fuzz_seeds.py from the repo root — must be a no-op diff on the committed set) plus promoted campaign crash inputs (seed-900+ numbering). Only seed-* files are tracked; grown corpora (SHA-named units), artifacts, and coverage output are gitignored and are not merged back into the committed seeds.
  • run-detached.sh — mandatory runner for agent sessions: wraps cargo fuzz run in setsid + nohup + log redirection so an OOM in a target can never take down the agent host (research doc §5).
  • json.dict — JSON token dictionary for the structured targets.
  • gen_fuzz_seeds.py — deterministic seed generator (quiche pattern).

Targets

Target Drives Invariants
payload_codec encode_payload / payload_as::<T> (alkstore/src/payload.rs) no-panic on any byte sequence; every decode failure typed Error::Codec; deep nesting loud at serde_json's recursion limit; Value round-trip closes exactly outside Number float leaves, float leaves pinned to serde_json's default-parse drift bound (1–2 ULPs, see the research doc's implementation log — ADR-020 §4 pins default serde_json, not the float_roundtrip flavor); decode deterministic over stored bytes; typed round-trip for a representative payload set
every_parse the three parse_every_interval implementations (differential, through the engines' #[doc(hidden)] re-exports) + each engine's skip_forward boundary arithmetic no-panic on any UTF-8-lossy string (each parser, each boundary path); typed rejection (Error::InvalidSpec on pg/mem, the substrate's error under its mapping on SQLite); three-way agreement on the Ok/Err partition and the Ok interval value (error identity not pinned — the SQLite Result<i64, String> vs InvalidSpec asymmetry is known); overflow posture: skip_forward over adversarial (next_fire_at, now, interval) triples rejects-or-saturates, never wraps or panics; the n <= 0 and giant-n arms (leading zeros, digit overflow at exactly i64::MAX/86400, positive-zero rejection)
name_validation validate_name / validate_shared_name / validate_local_name (alkstore/src/validation.rs) no-panic on any byte sequence (lossy-decoded and arbitrary-structured strings); deterministic accept/reject (double-invocation-pinned); rejection only via the typed taxonomy — Error::InvalidName for empty/whitespace-only on both kinds, Error::ReservedName for the leading byte-exact __alkstore_ prefix on the shared kind only (the local kind takes the non-empty rule only, so a leading reserved prefix is legal there); the reserved-prefix rule exact in every casing/boundary form (casing deviations, missing trailing underscore, embedded and whitespace-led forms accept); the rejection carries the supplied name verbatim (names are not trimmed); verdict-class length-independence across the probed neighborhoods (0↔1, 11↔12, 63↔64, 4095↔4096, 65536) — no length cap is pinned (ADR-008 §4), so no length is ever a rejection cause

Commands

cargo fuzz build and cargo fuzz run must be executed with fuzz/ (or deeper) as the working directory so rustup selects the pinned nightly toolchain — the detached runner handles that itself.

# build (nightly, pinned by rust-toolchain.toml inside fuzz/; run from fuzz/)
cargo fuzz build

# agent sessions: detached campaign (never foreground; CWD-independent)
FUZZ_RUNTIME_SECS=600 fuzz/run-detached.sh <target> [extra libfuzzer args...]

# corpus replay through the invariants (stable toolchain, no nightly)
cargo test --manifest-path fuzz/shared/Cargo.toml

# coverage
cargo fuzz coverage <target>

The fuzz workspace is excluded from the main workspace (exclude in the root Cargo.toml); it pins its own nightly toolchain via rust-toolchain.toml and does not affect the root workspace's stable toolchain or MSRV.