156 lines
8.1 KiB
Markdown
156 lines
8.1 KiB
Markdown
---
|
|
id: fuzz-scaffold
|
|
name: Fuzz sidecar scaffold — `fuzz/` workspace, runner, dict, seed generator, shared-crate skeleton
|
|
status: completed
|
|
depends_on: []
|
|
scope: moderate
|
|
risk: low
|
|
impact: phase
|
|
level: implementation
|
|
tags: [wave-7, fuzzing]
|
|
---
|
|
|
|
## Description
|
|
|
|
The wave-7 scaffold ([docs/research/fuzzing.md](../research/fuzzing.md)
|
|
§2 — the layout is inherited wholesale from the four upstream siblings,
|
|
not re-decided): the `fuzz/` sidecar workspace and its stable-toolchain
|
|
gate crate, copied from alksocks' working edition with only naming
|
|
substitutions.
|
|
|
|
- **`fuzz/` sidecar workspace**: `fuzz/Cargo.toml` (`alkstore-fuzz`,
|
|
`publish = false`, own `[workspace]` table, `libfuzzer-sys` +
|
|
`alkstore-fuzz-shared` path dep; `[[bin]]` entries land with the
|
|
target tasks, not here), `fuzz/rust-toolchain.toml` pinning
|
|
`channel = "nightly"` + `llvm-tools-preview` **inside `fuzz/` only**
|
|
— the crates themselves stay on stable, and the root workspace's
|
|
toolchain behavior must be unaffected.
|
|
- **`fuzz/shared/`** — `alkstore-fuzz-shared`, the STABLE-toolchain
|
|
library whose `#[cfg(test)]` corpus-replay modules are the fuzz gate
|
|
(§6): skeleton `lib.rs` with the crate doc carrying the quinn-CI
|
|
pattern rationale, plus the `arbitrary_value.rs` `JsonValue`
|
|
bounded-depth helper copied from alksocks (the structured-generation
|
|
path §3.1's targets share). Dependencies: `alkstore` (path), plus
|
|
`serde_json` + `arbitrary` (derive feature). Engine-crate deps land
|
|
with the targets that need them. `shared` consumes public API only —
|
|
it must never become a dependency of any workspace crate (the wasm
|
|
note, §2).
|
|
- **`fuzz/run-detached.sh`** — copied verbatim from alksocks
|
|
(CWD-independent, `setsid` + `nohup` + full redirection, `pid=` echo,
|
|
`FUZZ_RUNTIME_SECS` override). The §5 isolation rule is inherited
|
|
unchanged: campaigns never run as a foreground child of an agent
|
|
session.
|
|
- **`fuzz/json.dict`** — copied from a sibling (alksocks has it at
|
|
`fuzz/json.dict`).
|
|
- **`fuzz/gen_fuzz_seeds.py`** — the deterministic seed generator
|
|
(quiche pattern): alksocks' script as the structural template,
|
|
alkstore's own seed functions land per-target. Skeleton lands here
|
|
with the shared `seed_name`/`write_seed` plumbing and an empty
|
|
target registry.
|
|
- **`fuzz/.gitignore`** — the alksocks pattern: `target`, `artifacts`,
|
|
`coverage`, and `corpus/*` with `!`-negations for the committed seed
|
|
dirs (each target task adds its negation line when its corpus lands).
|
|
- **`fuzz/README.md`** — skeleton modeled on alksocks' (layout, targets
|
|
table filled by the target tasks, commands incl. the
|
|
run-from-`fuzz/`-so-rustup-selects-nightly rule).
|
|
- **Root `Cargo.toml`**: add `exclude = ["fuzz"]` to the `[workspace]`
|
|
table — defensive insurance against auto-discovery (the alkcall §2
|
|
lesson; this repo's explicit-members list already prevents it, the
|
|
exclude makes it structural). The publish-exclusion *verification*
|
|
stays wave 8's (§2); this task lands the mechanism.
|
|
- **Corpus dirs**: `fuzz/corpus/<target>/` scaffolding lands per-target
|
|
with the seeds; nothing to commit here.
|
|
|
|
Toolchain prerequisites verified present in the dev environment
|
|
(2026-10-10): nightly + `cargo-fuzz` 0.13.2 installed; alksocks'
|
|
`fuzz/Cargo.lock` exists as the copy reference.
|
|
|
|
## Acceptance Criteria
|
|
|
|
- [x] `fuzz/` exists with the §2 layout: sidecar `Cargo.toml` (own
|
|
`[workspace]`, `publish = false`), `rust-toolchain.toml`
|
|
(nightly + llvm-tools-preview), `shared/` crate, `run-detached.sh`
|
|
(executable), `json.dict`, `gen_fuzz_seeds.py`, `README.md`,
|
|
`fuzz/.gitignore`
|
|
- [x] `fuzz/shared` compiles and tests green on **stable** via
|
|
`cargo test --manifest-path fuzz/shared/Cargo.toml` (the gate
|
|
command works from the wave's first task onward)
|
|
- [x] `cargo fuzz build` succeeds from `fuzz/` (nightly selected by the
|
|
pin; **cargo-fuzz does NOT tolerate zero targets** here — a
|
|
bins-only package with no `[[bin]]` fails manifest parse, which
|
|
also blocks the shared gate's workspace discovery; a placeholder
|
|
target `fuzz_targets/placeholder.rs` documents the check and is
|
|
replaced by the wave-1 target tasks — recorded, as this AC asked)
|
|
- [x] Root workspace unaffected: `cargo build` / `cargo test` /
|
|
`clippy -D warnings` / `fmt --check` green from the root, and the
|
|
root toolchain is still stable (the pin did not leak upward)
|
|
- [x] `exclude = ["fuzz"]` present on the root `[workspace]` table
|
|
- [x] `run-detached.sh` is byte-identical to alksocks' modulo the
|
|
usage-line naming (`cmp` clean — the usage line is already
|
|
repo-agnostic, so no diff at all)
|
|
- [x] `shared` is not referenced by any workspace crate manifest
|
|
(only the root's `exclude = ["fuzz"]` mentions fuzz at all;
|
|
`cargo check --target wasm32-unknown-unknown -p alkstore-mem`
|
|
clean)
|
|
|
|
## References
|
|
|
|
- docs/research/fuzzing.md §2 (layout + toolchain), §5 (runner), §6
|
|
(no-CI / replay gate)
|
|
- /workspace/@alkdev/alksocks/fuzz/ (the copy source: Cargo.toml,
|
|
rust-toolchain.toml, run-detached.sh, json.dict, gen_fuzz_seeds.py,
|
|
.gitignore, README.md)
|
|
- docs/plans/implementation.md §Wave 7
|
|
|
|
## Notes
|
|
|
|
- **Zero targets are NOT tolerated by cargo-fuzz / cargo here** — the
|
|
AC's "if tolerated" branch failed: a bins-only package with no
|
|
`[[bin]]` entries cannot manifest-parse ("no targets specified"),
|
|
and that parse failure also breaks the shared gate's workspace
|
|
discovery (`cargo test --manifest-path fuzz/shared/Cargo.toml`
|
|
resolves the workspace root at `fuzz/`). Placeholder route taken
|
|
(as the AC's otherwise-branch prescribed): `fuzz_targets/placeholder.rs`
|
|
— a minimal `fuzz_target!` stub with a doc comment saying the wave-1
|
|
target tasks replace it — plus its `[[bin]]` entry in `fuzz/Cargo.toml`.
|
|
- **Repo-layout substitution beyond naming:** alksocks has its package
|
|
at the repo root (`alksocks = { path = "../.." }`); alkstore is the
|
|
ADR-001 workspace split, so the core crate sits in the `alkstore/`
|
|
subdir — shared's dep is `alkstore = { path = "../../alkstore" }`
|
|
and the fuzz package's is `path = "../alkstore"`.
|
|
- **`json.dict`** is byte-identical across alkcall / alktunnels /
|
|
alksocks (md5-verified), so it was copied verbatim (alkcall-envelope
|
|
tokens). Whether any alkstore-specific tokens should be added is a
|
|
target-task concern, not scaffold scope.
|
|
- `fuzz/Cargo.lock` is committed (alksocks pattern); generated
|
|
fresh — alksocks' lock is not portable across dep sets.
|
|
- `arbitrary_value.rs` copied verbatim except one intra-comment stale
|
|
reference: alksocks' `envelope_frame` → "the payload targets".
|
|
- `fuzz/.gitignore` has no `!corpus/<target>` negation lines yet —
|
|
each target task adds its own when its corpus lands (task spec).
|
|
- `gen_fuzz_seeds.py` is the plumbing-only skeleton (`seed_name` /
|
|
`write_seed`, empty `main()` registry); runs clean as a no-op.
|
|
|
|
## Summary
|
|
|
|
Landed the wave-7 scaffold: `fuzz/` sidecar workspace
|
|
(`alkstore-fuzz`, `publish = false`, own `[workspace]`, libfuzzer-sys +
|
|
path-dep shared crate) with `rust-toolchain.toml` pinning
|
|
nightly + llvm-tools-preview inside `fuzz/` only; stable-toolchain
|
|
`fuzz/shared` (`alkstore-fuzz-shared`) with the quinn-CI-pattern crate
|
|
doc and the alksocks `arbitrary_value.rs` `JsonValue` bounded-depth
|
|
helper; `run-detached.sh` (byte-identical to alksocks', executable);
|
|
`json.dict`; `gen_fuzz_seeds.py` skeleton; `.gitignore` (no corpus
|
|
negations yet); `README.md` skeleton; `exclude = ["fuzz"]` on the root
|
|
workspace; and the placeholder fuzz target so the toolchain check and
|
|
the shared gate work before the real targets land.
|
|
|
|
Verified: `cargo test --manifest-path fuzz/shared/Cargo.toml` green on
|
|
stable from the root; `cargo fuzz build` green from `fuzz/` (nightly
|
|
pin selected; placeholder + shared + alkstore compile under ASAN);
|
|
shared clippy `-D warnings` + `fmt --check` green; root `cargo build` /
|
|
`cargo test` (all suites pass) / clippy `-D warnings` / `fmt --check`
|
|
green with the stable toolchain still active at the root (rustc 1.99.0
|
|
stable; no upward pin leak); `cargo check -p alkstore-mem --target
|
|
wasm32-unknown-unknown` clean; no workspace manifest references
|
|
`alkstore-fuzz-shared` (only the root `exclude` mentions `fuzz`). |