From 64e0168dbfa829049c14ee5ca9eeec216e269302 Mon Sep 17 00:00:00 2001 From: Eric Wendland Date: Thu, 21 May 2026 01:43:45 +0200 Subject: [PATCH] Test Unix pipe forwarding exchange --- crates/geth-node/src/lib.rs | 78 +++++++++++++++++++++++++++++++++++++ docs/roadmap.md | 2 +- 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/crates/geth-node/src/lib.rs b/crates/geth-node/src/lib.rs index 034c561..49ceeac 100644 --- a/crates/geth-node/src/lib.rs +++ b/crates/geth-node/src/lib.rs @@ -8195,6 +8195,84 @@ mod tests { .expect("pipe tcp forward"); echo_task.await.expect("join tcp echo"); + #[cfg(unix)] + { + let unix_target = right_home.path().join("echo.sock"); + let unix_echo = UnixListener::bind(&unix_target).expect("bind unix echo"); + let unix_target_display = unix_target.display().to_string(); + handle_request( + &right, + ControlRequest::AuthGrant { + subject: left.node_id.clone(), + resource: format!("resource:pipe-unix:{unix_target_display}"), + capability: "pipe.forward".to_owned(), + grant_id: Some("grant:left-pipe-unix-forward".to_owned()), + }, + ) + .expect("grant left pipe unix forward"); + let unix_echo_task = tokio::spawn(async move { + let (mut socket, _) = unix_echo.accept().await.expect("accept unix echo"); + let mut buf = [0_u8; 5]; + socket.read_exact(&mut buf).await.expect("read unix echo"); + assert_eq!(&buf, b"hello"); + socket.write_all(b"world").await.expect("write unix echo"); + socket.shutdown().await.expect("shutdown unix echo"); + }); + let (unix_forward_client, unix_forward_daemon) = + UnixStream::pair().expect("unix stream pair for unix forward"); + let right_node_id = right_card.node_id.to_string(); + let left_for_forward = left.clone(); + let unix_target_for_forward = unix_target.clone(); + let unix_forward_task = tokio::spawn(async move { + handle_local_pipe_unix_stream( + left_for_forward, + &right_node_id, + unix_target_for_forward, + None, + unix_forward_daemon, + ) + .await + }); + let mut unix_forward_reader = BufReader::new(unix_forward_client); + let mut unix_line = String::new(); + unix_forward_reader + .read_line(&mut unix_line) + .await + .expect("read pipe unix response"); + match geth_control::decode_response(&unix_line).expect("decode pipe unix response") { + ControlResponse::PipeRemoteConnected { + allowed, + connection, + .. + } => { + assert!(allowed); + assert_eq!(connection.target, unix_target_display); + } + other => panic!("unexpected pipe Unix stream response: {other:?}"), + } + let stream = unix_forward_reader.into_inner(); + let (mut unix_forward_read, mut unix_forward_write) = stream.into_split(); + unix_forward_write + .write_all(b"hello") + .await + .expect("write through pipe unix forward"); + unix_forward_write + .shutdown() + .await + .expect("shutdown pipe unix forward write"); + let mut unix_forwarded = Vec::new(); + unix_forward_read + .read_to_end(&mut unix_forwarded) + .await + .expect("read through pipe unix forward"); + assert_eq!(unix_forwarded, b"world"); + unix_forward_task + .await + .expect("join pipe unix forward") + .expect("pipe unix forward"); + unix_echo_task.await.expect("join unix echo"); + } + let allowed = handle_request_async( &left, ControlRequest::PeerAuthCheck { diff --git a/docs/roadmap.md b/docs/roadmap.md index 58377a8..c3b7d53 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -404,7 +404,7 @@ Goal: add authorized stream-oriented management workflows over Iroh. components. - `[x]` Tests cover Unix path validation and pipe wire request serialization. - `[ ]` Unsupported platforms return clear errors. - - `[ ]` Tests cover a full two-node Unix socket forwarding exchange. + - `[x]` Tests cover a full two-node Unix socket forwarding exchange. - `[~]` SSH proxy over Iroh. Acceptance criteria: