docs(research): fuzzing steps 1-3 complete; 10-min campaigns clean on all five targets
\u00a77.8 campaign results: manager_routing 1.06M execs (exact-counter and parked-bytes invariants held across every adversarial sequence), envelope_semantic 2.44M execs (coverage saturated, all event kinds round-trip), spec_parse 10.8M execs (registry compiled every attacker-shaped schema or rejected cleanly). All exited 0, zero artifacts. Also records the two harness-model defects the fuzzer caught in the interim (per-receiver EOF-sentinel latch; odd/even Adopt range per ADR-047 \u00a75). Doc-only + harness fixes; no crate changes.
This commit is contained in:
1 parent
a1f257757b
commit
77f7006e2e
3 files changed
+97
-33
No files matched your search
@@ -28,10 +28,28 @@ pub const MAX_CHUNK_LEN: u32 = 16 * 1024 * 1024;
|
||||
|
||||
#[derive(Debug, arbitrary::Arbitrary, Clone)]
|
||||
pub enum ManagerOp {
|
||||
Route { channel_id: u32, len: u16, byte: u8 },
|
||||
Open { alpn_idx: u8, opener_idx: u8 },
|
||||
Adopt { channel_id: u32 },
|
||||
Teardown { channel_id: u32 },
|
||||
Route {
|
||||
channel_id: u32,
|
||||
len: u16,
|
||||
byte: u8,
|
||||
},
|
||||
Open {
|
||||
alpn_idx: u8,
|
||||
opener_idx: u8,
|
||||
},
|
||||
/// Adopt a channel whose id the REMOTE side allocated. The
|
||||
/// harness manager is `ChannelSide::Accept`, so the peer is the
|
||||
/// Connect side and its allocated ids are odd (ADR-047 §5) — the
|
||||
/// op masks the fuzzer's arbitrary id into the legal range.
|
||||
Adopt {
|
||||
channel_id: u32,
|
||||
},
|
||||
/// Teardown an arbitrary channel id (any live id — teardown is
|
||||
/// local, not range-constrained).
|
||||
Teardown {
|
||||
channel_id: u32,
|
||||
},
|
||||
/// Transport EOF — clear everything.
|
||||
ClearAll,
|
||||
}
|
||||
|
||||
@@ -98,7 +116,11 @@ struct ManagerHarness {
|
||||
/// Byte totals for drainers that ended mid-sequence (sender drop
|
||||
/// on adopt-over-adopt) — reconciled into the post-sequence total.
|
||||
retired_drainer_bytes: u64,
|
||||
/// Channels whose stream latched EOF (sentinel routed while known).
|
||||
/// Whether the CURRENT receiver for each id latched an EOF
|
||||
/// sentinel — per-receiver state, not per-id: a fresh adopt
|
||||
/// installs a fresh reassembled stream with no latched EOF, while
|
||||
/// a sentinel inside a drained early-arrival queue latches the
|
||||
/// NEW receiver too (`drain_early_arrivals` delivers it into it).
|
||||
sentinel_seen: HashMap<u32, bool>,
|
||||
/// (channel_id, bytes-read counter, drainer task).
|
||||
drainers: Vec<(u32, Arc<AtomicU64>, tokio::task::JoinHandle<()>)>,
|
||||
@@ -169,22 +191,31 @@ impl ManagerHarness {
|
||||
}
|
||||
}
|
||||
ManagerOp::Adopt { channel_id } => {
|
||||
// The harness manager is the Accept side; the peer
|
||||
// (Connect side) allocates odd ids, so only odd ids
|
||||
// arrive for adoption (ADR-047 §5 odd/even split).
|
||||
let channel_id = (*channel_id | 1).max(1);
|
||||
match self
|
||||
.manager
|
||||
.adopt_channel(*channel_id, "alk/tty", None)
|
||||
.adopt_channel(channel_id, "alk/tty", None)
|
||||
.await
|
||||
{
|
||||
Ok((_send, recv)) => {
|
||||
// Adoption drains the parked queue FIFO into
|
||||
// the receiver — readable until a sentinel.
|
||||
if let Some(queue) = self.model.parked.remove(channel_id) {
|
||||
// Fresh receiver (no latched EOF), then
|
||||
// supersede the id's prior drainer (retire its
|
||||
// model, reset its sentinel latch), THEN fold
|
||||
// the drained parked queue into the new
|
||||
// receiver's model — `drain_early_arrivals`
|
||||
// delivers it into the new receiver, sentinel
|
||||
// included.
|
||||
self.spawn_drainer(channel_id, recv);
|
||||
if let Some(queue) = self.model.parked.remove(&channel_id) {
|
||||
let drained_readable = ParkModel::readable_bytes_until_sentinel(&queue);
|
||||
*self.readable.entry(*channel_id).or_insert(0) += drained_readable;
|
||||
*self.readable.entry(channel_id).or_insert(0) += drained_readable;
|
||||
if queue.contains(&0) {
|
||||
self.sentinel_seen.insert(*channel_id, true);
|
||||
self.sentinel_seen.insert(channel_id, true);
|
||||
}
|
||||
}
|
||||
self.spawn_drainer(*channel_id, recv);
|
||||
}
|
||||
Err(ManagerError::ChannelExists(_)) => {}
|
||||
Err(ManagerError::TooManyChannels { .. }) => {}
|
||||
@@ -233,7 +264,12 @@ impl ManagerHarness {
|
||||
// A fresh drainer for an id supersedes any earlier one: the
|
||||
// earlier stream's sender was dropped (teardown) or routed
|
||||
// past an EOF sentinel, so its readable-byte model is retired
|
||||
// into the reconciled total and the id's model restarts.
|
||||
// into the reconciled total and the id's model restarts. The
|
||||
// id's sentinel latch also resets — the new receiver is a
|
||||
// fresh reassembled stream (any sentinel in the drained
|
||||
// early-arrival queue is re-applied by the adopt arm AFTER
|
||||
// this, since `drain_early_arrivals` delivers it into the new
|
||||
// receiver too).
|
||||
if let Some(bytes) = self.readable.remove(&channel_id) {
|
||||
self.retired_drainer_bytes += bytes;
|
||||
}
|
||||
|
||||
@@ -68,11 +68,14 @@ pub fn fuzz_spec_parse(data: &[u8]) {
|
||||
// Layer 3: the rebuilt spec serializes back to the wire shape.
|
||||
// (Structural equality with the input is NOT asserted — the wire
|
||||
// shape is a projection of the spec, and rebuild normalizes; the
|
||||
// round-trip invariant is that `spec_to_json_pub` output re-parses
|
||||
// to the same spec.)
|
||||
// round-trip invariant is that the full op/register payload built
|
||||
// from `spec_to_json_pub` output re-parses to the same spec.)
|
||||
let wire = alkcall::registry::discovery::spec_to_json_pub(&request.spec);
|
||||
let reparsed = OpRegisterRequest::from_json(&wire)
|
||||
.expect("spec_to_json_pub output must re-parse through op/register");
|
||||
let reparsed = OpRegisterRequest::from_json(&serde_json::json!({
|
||||
"spec": wire,
|
||||
"replace": request.replace,
|
||||
}))
|
||||
.expect("spec_to_json_pub output must re-parse through op/register");
|
||||
assert_eq!(
|
||||
reparsed.spec, request.spec,
|
||||
"spec_to_json_pub → from_json round-trips the rebuilt spec"
|
||||
|
||||
Reference in new issue
Block a user