From e0387f5bcb1d368449ad6fc949acb2be5911ee62 Mon Sep 17 00:00:00 2001 From: Bradley Axen Date: Fri, 11 Sep 2026 18:30:52 -0700 Subject: [PATCH] Share the guarded huddle publication seam across identity types Signed-off-by: Bradley Axen --- desktop/src-tauri/src/egress_guard_tests.rs | 14 ++++++++++---- desktop/src-tauri/src/huddle/pipeline.rs | 20 ++++---------------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/desktop/src-tauri/src/egress_guard_tests.rs b/desktop/src-tauri/src/egress_guard_tests.rs index fe053602f9..6d2eca4fa9 100644 --- a/desktop/src-tauri/src/egress_guard_tests.rs +++ b/desktop/src-tauri/src/egress_guard_tests.rs @@ -153,8 +153,8 @@ async fn boundary_submit_signed_event_with_keys_blocks_ncryptsec() { } /// Boundary 5: huddle STT publisher (`huddle/pipeline.rs`). -#[test] -fn boundary_huddle_stt_blocks_ncryptsec() { +#[tokio::test] +async fn boundary_huddle_stt_blocks_ncryptsec() { let keys = nostr::Keys::generate(); let channel = uuid::Uuid::new_v4(); let builder = crate::events::build_message( @@ -170,7 +170,9 @@ fn boundary_huddle_stt_blocks_ncryptsec() { &crate::relay::relay_api_base_url(), ) .unwrap(); - let err = crate::huddle::pipeline::sign_and_guard_stt_body(builder, &keys).unwrap_err(); + let err = crate::huddle::pipeline::sign_and_guard_stt_body(builder, &keys) + .await + .unwrap_err(); assert_guard_error(&err); // Clean transcripts pass through the same seam. @@ -187,7 +189,11 @@ fn boundary_huddle_stt_blocks_ncryptsec() { &crate::relay::relay_api_base_url(), ) .unwrap(); - assert!(crate::huddle::pipeline::sign_and_guard_stt_body(builder, &keys).is_ok()); + assert!( + crate::huddle::pipeline::sign_and_guard_stt_body(builder, &keys) + .await + .is_ok() + ); } /// Boundary 8: native websocket send loop — the single choke point for all diff --git a/desktop/src-tauri/src/huddle/pipeline.rs b/desktop/src-tauri/src/huddle/pipeline.rs index c4fdc5bdc3..cb99c6e874 100644 --- a/desktop/src-tauri/src/huddle/pipeline.rs +++ b/desktop/src-tauri/src/huddle/pipeline.rs @@ -607,13 +607,11 @@ fn should_reselect_constructed_voice(constructed_voice: &str, latest_voice: &str /// Factored out of the transcription loop so egress boundary 5 (huddle STT) /// has a directly testable seam: the NIP-49 egress guard runs here, before /// any bytes can reach the network. -pub(crate) fn sign_and_guard_stt_body( +pub(crate) async fn sign_and_guard_stt_body( builder: nostr::EventBuilder, - keys: &nostr::Keys, + identity: impl Into, ) -> Result, String> { - let event = builder - .sign_with_keys(keys) - .map_err(|e| format!("sign event: {e}"))?; + let event = identity.into().sign(builder).await?; let body_bytes = event.as_json().into_bytes(); crate::egress_guard::assert_no_key_backup_bytes(&body_bytes, "huddle STT publish")?; Ok(body_bytes) @@ -688,17 +686,7 @@ pub(crate) fn spawn_transcription_task( // the kind event and build NIP-98 auth after the wait so both // timestamps are fresh — single clean order: wait → sign → auth → send. crate::relay_admission::wait_for_rate_limit().await; - let signed_body = match &keys { - crate::enterprise_identity::SigningIdentity::Local(keys) => { - sign_and_guard_stt_body(builder, keys) - } - _ => keys.sign(builder).await.and_then(|event| { - let body = event.as_json().into_bytes(); - crate::egress_guard::assert_no_key_backup_bytes(&body, "huddle STT publish")?; - Ok(body) - }), - }; - let body_bytes = match signed_body { + let body_bytes = match sign_and_guard_stt_body(builder, &keys).await { Ok(b) => b, Err(e) => { eprintln!("buzz-desktop: STT publish: {e}");