- GatewayDispatch now refuses (FORBIDDEN, pre-dispatch) any op whose spec gates on access_control.resource_type when no ownership provider is wired — invoke, invoke_streaming, and invoke_sink alike - Predicate is resource_type, not resource_id_path as review 012 first drafted: AccessControl::check consults the provider whenever the resource type is set, including the list/owns_any case; the refusal message is operator-directed and names both opt-ins - Exemptions: resource_action-only ACLs (no provider is consulted on the wire either) and Internal-visibility ops (spec-404, no acknowledgment leak) - with_static_ownership_fallback(): declared opt-out to the ADR-011 static fallback for deployments with no runtime ownership model — the door contract becomes enforceable, not just documented - Superseded the pre-ruling pin gateway_without_provider_admits_only_the_static_claim with refusal/ opt-out/exemption tests (all three entry points covered) - ADR-048 amendment records the ruling; review 012 status updated Blast-radius survey: alkhttp is the only live GatewayDispatch consumer (unpublished, three unwired sites); alkblobs the only live resource_type op producer (serves native-wire, providers wired); no published 0.9.0 consumer relies on the silent fallback for such ops. Ships in the same unreleased batch as the review-012 amendment. Verification: cargo test (697 pass), cargo test --features gateway (720 pass), cargo clippy --all-features --all-targets -- -D warnings, cargo fmt --check, fuzz corpus replay (5 pass)
alkcall fuzzing
libFuzzer targets for alkcall's wire formats (see
docs/research/fuzzing.md for the full rationale and campaign plan).
Layout
fuzz_targets/— one binary per target; thinfuzz_target!wrappers.shared/— the invariant logic, as a plain library so normalcargo 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.corpus/<target>/— committed hand-made seeds (regenerate withpython3 fuzz/gen_fuzz_seeds.pyfrom the repo root). Grown corpora and artifacts are gitignored.run-detached.sh— mandatory runner for agent sessions: wrapscargo fuzz runinsetsid+nohup+ log redirection so an OOM in a target can never take down the agent host (research doc §7.6).json.dict— JSON token dictionary for the envelope targets.
Targets
| Target | Drives | Invariants |
|---|---|---|
chunk_header |
parse_header / write_header (channels/wire.rs) |
no-panic; round-trip identity; TooLarge iff length > MAX_CHUNK_LEN; consumption accounting (8 bytes); input never mutated |
envelope_frame |
FrameFramedReader::new(Cursor).read_frame() on a current-thread runtime |
no-panic; never allocates > MAX_FRAME_SIZE; clean FrameError on truncation/oversize/zero-length; exact consumption; structural write_frame round-trip |
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 chunk_header
FUZZ_RUNTIME_SECS=600 fuzz/run-detached.sh envelope_frame -max_len=65536 -dict=json.dict
# 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 and from the
published package (exclude in the root Cargo.toml); it pins its own
nightly toolchain via rust-toolchain.toml and does not affect the
crate's stable MSRV.