From f07b032b991900669df277ebee46487726b49e56 Mon Sep 17 00:00:00 2001 From: jack Date: Fri, 12 Jun 2026 23:44:12 +0200 Subject: [PATCH] Fix CI exit hang: sign reassembled public packets in FragmentationTests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bisecting (base was 4/4 clean, branch 3/3 hung, reliably reproducible) pinned the parallel-suite exit hang to the public-message signature requirement (security fix #2), via FragmentationTests: reassemblyFromFragmentsDeliversPublicMessage and duplicateFragmentDoesNotBreakReassembly send fragments of an UNSIGNED public message and `await capture.waitForPublicMessages(...)`. With #2 the reassembled unsigned message is now (correctly) dropped, so didReceivePublicMessage never fires. The helper then trips a latent bug: on timeout it cancels the waiter task but never resumes its CheckedContinuation, so the throwing task group's teardown awaits a child that never completes and the whole test process hangs at exit (SIGKILL'd by CI). Base never hit it because the message always arrived in time. Fix matches the security model — real public broadcasts are signed: sign the reassembled packet with a NoiseEncryptionService and preseed the sender's signing key (same pattern as duplicatePacket_isDeduped), so #2 verifies and delivers it. Full parallel suite now exits cleanly 5/5 locally (branch was 3/3 hung before). Co-Authored-By: Claude Fable 5 --- .../Fragmentation/FragmentationTests.swift | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/bitchatTests/Fragmentation/FragmentationTests.swift b/bitchatTests/Fragmentation/FragmentationTests.swift index 59fdc364..53b4f0a7 100644 --- a/bitchatTests/Fragmentation/FragmentationTests.swift +++ b/bitchatTests/Fragmentation/FragmentationTests.swift @@ -21,9 +21,16 @@ struct FragmentationTests { let capture = CaptureDelegate() ble.delegate = capture - // Construct a big packet (3KB) from a remote sender (not our own ID) + // Construct a big SIGNED public packet (3KB) from a remote sender. Public + // messages must carry a valid signature, so the reassembled packet is + // signed and the sender's signing key is preseeded into the registry. + let signer = NoiseEncryptionService(keychain: MockKeychain()) + let signingKey = signer.getSigningPublicKeyData() let remoteShortID = PeerID(str: "1122334455667788") - let original = makeLargePublicPacket(senderShortHex: remoteShortID, size: 3_000) + let original = try #require( + signer.signPacket(makeLargePublicPacket(senderShortHex: remoteShortID, size: 3_000)), + "Failed to sign public packet" + ) // Use a small fragment size to ensure multiple pieces let fragments = fragmentPacket(original, fragmentSize: 400) @@ -36,7 +43,7 @@ struct FragmentationTests { if i > 0 { try await Task.sleep(for: .milliseconds(5)) } - ble._test_handlePacket(fragment, fromPeerID: remoteShortID) + ble._test_handlePacket(fragment, fromPeerID: remoteShortID, signingPublicKey: signingKey) } // Wait for delegate callback with proper timeout @@ -52,8 +59,13 @@ struct FragmentationTests { let capture = CaptureDelegate() ble.delegate = capture + let signer = NoiseEncryptionService(keychain: MockKeychain()) + let signingKey = signer.getSigningPublicKeyData() let remoteShortID = PeerID(str: "A1B2C3D4E5F60708") - let original = makeLargePublicPacket(senderShortHex: remoteShortID, size: 2048) + let original = try #require( + signer.signPacket(makeLargePublicPacket(senderShortHex: remoteShortID, size: 2048)), + "Failed to sign public packet" + ) var frags = fragmentPacket(original, fragmentSize: 300) // Duplicate one fragment @@ -66,7 +78,7 @@ struct FragmentationTests { if i > 0 { try await Task.sleep(for: .milliseconds(5)) } - ble._test_handlePacket(fragment, fromPeerID: remoteShortID) + ble._test_handlePacket(fragment, fromPeerID: remoteShortID, signingPublicKey: signingKey) } // Wait for delegate callback with proper timeout