feat(adapters): from_wss consumer adapter behind the wss feature (ADR-070)
- FromWss: dial wss:// -> split_tungstenite_to_bytes (client-side twin of the axum WS byte-adapter; one seam, both directions, OQ-01) -> Connection::from_bidi(b"alk/channels") -> alkcall ChannelClient (channel 0 install + dispatch loop) -> alkcall from_call importer. No protocol fork: specs mirror the remote, provenance FromCall. - Drop semantics (OQ-03 v1): session drop -> monitor fails all in-flight pendings retryable CONNECTION_CLOSED (WsPumps::read_eof Notify); no 30s-deadline hang. - Bearer token via constructor/assembly layer (ADR-014 no-env-vars). Production fix in the WS server half (upgrade.rs): the upgrade identity now propagates to channel 0's CallConnection (was AuthContext::anonymous -> dispatcher saw no identity, ACL checks ran unauthenticated; services/list filtered scoped ops for all callers). 9 in-module tests incl. full round-trip consumer<->server (both halves of the adapter together), ACL end-to-end, drop-no-hang. Verified: cargo test (227 lib default), --all-features (227 lib + 5 MCP + 10 WS integration), clippy -D warnings (both), fmt.
This commit is contained in:
@@ -35,10 +35,15 @@ pub async fn run_channels_session(
|
||||
) {
|
||||
let (byte_stream, _pumps) = split_ws_to_bytes(socket);
|
||||
let conn = Connection::from_bidi(byte_stream, b"alk/channels".to_vec(), None);
|
||||
let _ = conn.set_identity(identity);
|
||||
let _ = conn.set_identity(identity.clone());
|
||||
|
||||
let adapter = ChannelsAdapter::new(install_channel_zero(registry), policy);
|
||||
let auth = AuthContext::anonymous(b"alk/channels");
|
||||
let auth = AuthContext {
|
||||
identity: Some(identity),
|
||||
alpn: b"alk/channels".to_vec(),
|
||||
remote_addr: None,
|
||||
tls_client_fingerprint: None,
|
||||
};
|
||||
if let Err(e) = ProtocolHandler::handle(&adapter, conn, &auth).await {
|
||||
tracing::warn!(error = %e, "channels session ended");
|
||||
}
|
||||
@@ -57,9 +62,18 @@ pub async fn run_channels_session(
|
||||
fn install_channel_zero(
|
||||
registry: Arc<OperationRegistry>,
|
||||
) -> alkcall::channels::adapter::InstallChannelZero {
|
||||
Arc::new(move |_manager, channel0_conn, _auth| {
|
||||
Arc::new(move |_manager, channel0_conn, auth| {
|
||||
let registry = Arc::clone(®istry);
|
||||
tokio::spawn(async move {
|
||||
// The WS identity rides the upgrade request; propagate it to
|
||||
// channel 0's `CallConnection` so the dispatcher's
|
||||
// `resolve_identity` (and thus `AccessControl::check` on
|
||||
// `services/list` and every operation) sees it. Without this
|
||||
// the freshly constructed channel-0 `Connection` carries no
|
||||
// identity and all ACL-restricted ops look unauthenticated.
|
||||
if let Some(identity) = auth.identity.clone() {
|
||||
let _ = channel0_conn.set_identity(identity);
|
||||
}
|
||||
let channel0_bidi = match channel0_conn.accept_bi().await {
|
||||
Ok(s) => s,
|
||||
Err(_) => return,
|
||||
|
||||
Reference in New Issue
Block a user