Files
alkgit/fuzz
glm-5.3-flash 0dd5721290 chore(release): alkgit 0.1.0
The publish bump (core/w5-publish) over the green wave-5 gate:

- manifest: version 0.0.1 -> 0.1.0; the substrate's inter-crate pin
  follows (alkgit = { path = "..", version = "0.1.0" })
- the family LICENSE-MIT / LICENSE-APACHE files added (every sibling
  crate ships them; the package listing gained the two files)
- CHANGELOG: the 0.1.0 entry dated and the stale 0.0.1-note dropped
- tests: the two agent-string pins moved from the hardcoded version
  to env!(CARGO_PKG_VERSION) — the src side builds the agent string
  from the manifest version, so the pins now hold across bumps

Verification: cargo test (workspace), cargo test --all-features,
cargo test -p alkgit, both clippies (-D warnings), cargo fmt --check,
cargo doc --no-deps (0 warnings), the fuzz corpus gate (13/13),
cargo publish --dry-run --allow-dirty (77-file package) — all green.
2026-10-23 12:29:44 +00:00
..
2026-10-23 12:29:44 +00:00

alkgit fuzzing

libFuzzer targets for alkgit's ingress surfaces — the family standing rule (anything worth fuzzing gets fuzzed), landed per the plan's wave-5 charter and the alkblobs precedent: the JSON schema gate itself is alkcall's surface, family-fuzzed there; the alkgit-owned post-schema ingress is what fuzzes here.

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 (#[cfg(test)] modules; quinn's CI pattern). The fuzz binaries are nightly-only; the shared crate is stable-clean. It consumes alkgit's public API only (plus the two #[doc(hidden)] fuzz-visible exposures in src/channels.rs) and must never become a dependency of the root 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). 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.
  • gen_fuzz_seeds.py — deterministic seed generator (quiche pattern).

Targets

Target Drives Invariants
request_line parse_request_line + read_request_line (src/preamble.rs — the ADR-016 §2 pinned wire format), the reader fuzzed from a tested base (D-1) no-panic on any byte string and any frame stream; accepted lines carry one of the two services and a grammar-valid repo id; the typed decline set (Malformed / ServiceUnknown / RepoInvalid / VersionDeclined) with the decline-message band pinned; the wire reader as a differential pair against the framing oracle (header/payload/cap/UTF-8 rules re-derived per input); the io read-error arm driven via an injected failing reader (the unit rows cannot reach it over in-memory io); determinism (the parse verdict is stable per input)
pktline_framing duplex Session::read_request / Session::read_push_request + stateless StatelessRequest::read_post (src/duplex.rs, src/stateless.rs — both services, parity-selected) no-panic, no hang (per-iteration wall-clock canary), no read beyond the transport input (the consumed counters pin it); the max_request_body budget arm fires before accumulation (ADR-009 fail-closed, exercised at a 4096 drive budget); machinery-misuse defenses asserted on every drive — the raw-tail escape refuses pre-parse and is available exactly post-parse, the stop-delimiter discipline refuses the second command (ResetRequired), the quiet close caches its terminal, terminal errors re-report without re-entering the transport
command_parse parse_fetch_args (ADR-014 fetch argument grammar) + parse_push_request (ADR-013 request grammar, the push-options gate both ways) — src/fetch.rs, src/push.rs; structured feeds (arbitrary-derived lines plus the magic-marked textual seeds) no-panic; the fail-closed classification: a pure parse fails only as SubstrateError::Protocol, never another class; the nothing-to-do push shape is exactly the empty command set; want/have dedup; determinism (value arms compare, error arms class-pinned)
repo_id validate_repo_id (src/registry.rs, backend.md §repo-id grammar) accept/reject agreement with an independent from-spec oracle (one or two /-segments, lowercase alphanumerics and -/_, non-empty segments, ≤ 100 bytes) on arbitrary byte strings — the grammar rejects the hostile space, not just the sampled one; every rejection is exactly its typed RepoIdError class with the named offsets/counts true; determinism (verdict and Display text stable)
open_params the channels/git/sub establisher (make_git_establisher, the exact production establisher — #[doc(hidden)] exposure) + the production OpenParams Deserialize the plan: None handler fallback re-parses — src/channels.rs no-panic on any JSON value (raw-byte parses plus arbitrary-derived structures); the typed fail-closed classification (params parse → repo-id grammar → service enum → resolve→authorize) agrees with the recomputed expectation over a three-row stub registry realizing every posture (granted manage / granted read / grantless / unknown — the unknown ≡ unauthorized collapse, one reason, one generic message); deny_unknown_fields fail-closed; determinism

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.

Campaign cadence: the corpus gate (above) runs in every verification pass; the fuzzing sessions themselves run at the wave gate and before publish (fuzz/run-detached.sh per target, bounded runtime).