producer: the explicit bind-policy gate + the builder-register pin (review-002 C-3, D-2, S-1, N-2)
- C-3: Socks5ProducerBuilder.bind_policy(bool) — the substrate-free entry's explicit BIND gate, defaulting to the accept seam's presence; seam presence is never the sole gate - D-2: RegisterMode::ProducerBuilder + an integration test wiring the full builder through .register(...) serving all three commands - S-1: run_datagram_stage's doc names the hot-Ok(None) residual - N-2: wire.md §UDP ASSOCIATE carries the inline-send backpressure line Verified: cargo test (352 green), clippy/fmt/doc clean, wasm checks clean.
This commit is contained in:
1 parent
53739b20cb
commit
ff81f2d27b
5 files changed
+393
-17
No files matched your search
@@ -1011,3 +1011,49 @@ async fn readiness_contract_holds_under_concurrent_load() {
|
||||
.await
|
||||
.expect("fresh associate after the hot-egress load");
|
||||
}
|
||||
|
||||
/// The spec'd assembly shape end to end (review 002 D-2): the full
|
||||
/// `Socks5Producer::builder()` chain — `dial` + `egress` + `accept` —
|
||||
/// through `.register(...)` (the builder's delegated registration, not
|
||||
/// the free function), serving all three commands over the harness
|
||||
/// topology. The one assembly path producer.md §Wiring documents is
|
||||
/// the one this test pins: a signature drift or a delegation bug in
|
||||
/// `register` can no longer pass the suite.
|
||||
#[tokio::test]
|
||||
async fn producer_builder_registers_and_serves_all_three_commands() {
|
||||
let topo = wire_with(
|
||||
RegisterMode::ProducerBuilder {
|
||||
dial: echo_dial(),
|
||||
egress: Some(echo_egress()),
|
||||
accept: Some(echo_accept()),
|
||||
bind_policy: None,
|
||||
},
|
||||
Some(both_scopes_identity()),
|
||||
None,
|
||||
Arc::new(alkcall::core::auth::NoopIdentityProvider),
|
||||
)
|
||||
.await;
|
||||
|
||||
// CONNECT over the builder's dial seam.
|
||||
connect_round_trip(&topo, "builder.test".into(), "tcp".into())
|
||||
.await
|
||||
.expect("CONNECT serves through the builder registration");
|
||||
|
||||
// ASSOCIATE over the builder's egress seam.
|
||||
associate_round_trip(&topo, 60, b"udp")
|
||||
.await
|
||||
.expect("ASSOCIATE serves through the builder registration");
|
||||
|
||||
// BIND over the builder's accept seam (reply#1 + reply#2 +
|
||||
// pass-through — the full phase model).
|
||||
bind_round_trip(&topo, "builder.test", b"bind")
|
||||
.await
|
||||
.expect("BIND serves through the builder registration");
|
||||
|
||||
// The registration is the spec'd one: the establisher rode it
|
||||
// (the witness is the builder-delegated registration's probe).
|
||||
assert_eq!(
|
||||
topo.identity_witness.lock().await.as_deref(),
|
||||
Some("consumer-both")
|
||||
);
|
||||
}
|
||||
@@ -442,6 +442,17 @@ pub enum RegisterMode {
|
||||
egress: Option<EgressFactory>,
|
||||
accept: Option<BindAcceptFactory>,
|
||||
},
|
||||
/// The spec'd assembly shape (producer.md §Wiring): the
|
||||
/// registration rides [`alksocks::producer::Socks5Producer::
|
||||
/// builder`] + [`alksocks::producer::Socks5Producer::register`]
|
||||
/// (the builder's `dial`/`egress`/`accept` setters and the
|
||||
/// delegated registration — the surface D-2 guards).
|
||||
ProducerBuilder {
|
||||
dial: DialFn,
|
||||
egress: Option<EgressFactory>,
|
||||
accept: Option<BindAcceptFactory>,
|
||||
bind_policy: Option<bool>,
|
||||
},
|
||||
/// No socks5 openable — only the generic channel ops (the
|
||||
/// unknown-op / registry-gate probe's shape).
|
||||
NoSocks5,
|
||||
@@ -660,6 +671,37 @@ pub async fn wire_with(
|
||||
)
|
||||
.expect("register socks5 openable (the real producer)");
|
||||
}
|
||||
if let RegisterMode::ProducerBuilder {
|
||||
dial,
|
||||
egress,
|
||||
accept,
|
||||
bind_policy,
|
||||
} = &mode
|
||||
{
|
||||
let core = ChannelCore::new(
|
||||
producer_client.manager().clone(),
|
||||
alkcall::channels::policy::default_policy(),
|
||||
);
|
||||
let mut producer = alksocks::producer::Socks5Producer::builder().dial(Arc::clone(dial));
|
||||
if let Some(egress) = egress {
|
||||
producer = producer.egress(egress.clone());
|
||||
}
|
||||
if let Some(accept) = accept {
|
||||
producer = producer.accept(accept.clone());
|
||||
}
|
||||
if let Some(can_bind) = bind_policy {
|
||||
producer = producer.bind_policy(*can_bind);
|
||||
}
|
||||
producer
|
||||
.build()
|
||||
.register(
|
||||
&core,
|
||||
&producer_op_registry,
|
||||
AuthContext::anonymous(b"alk/socks5"),
|
||||
Some(Arc::clone(&identity_witness)),
|
||||
)
|
||||
.expect("register socks5 openable (the spec'd builder shape)");
|
||||
}
|
||||
|
||||
// --- consumer pieces (captured from the hook) -----------------------
|
||||
let consumer_call = consumer_call_rx.recv().await.expect("consumer call conn");
|
||||
|
||||
Reference in new issue
Block a user