diff options
Diffstat (limited to 'packages/meshbay-node/tests/test_security_regressions.py')
| -rw-r--r-- | packages/meshbay-node/tests/test_security_regressions.py | 48 |
1 files changed, 38 insertions, 10 deletions
diff --git a/packages/meshbay-node/tests/test_security_regressions.py b/packages/meshbay-node/tests/test_security_regressions.py index 1a318f7..fa821d9 100644 --- a/packages/meshbay-node/tests/test_security_regressions.py +++ b/packages/meshbay-node/tests/test_security_regressions.py @@ -743,20 +743,48 @@ def test_pre_handshake_message_budget_is_small(): list(buf.messages()) -def test_stream_segment_is_not_synchronous(): +def test_no_transport_ships_media_outside_the_aead(): """ - H6: _do_stream_segment ran subprocess.run(timeout=30) inside the event loop, - stalling every peer on the node for up to thirty seconds per request. + `stream_seg` served an MPEG-TS segment as base64 with no encryption at all + — the one content-plane message that never went through a GEK-derived key, + on both transports, answering any authenticated member. Its browser caller + was defined and never invoked. Removed in MNP 2.0 rather than repaired: + `stream_data` already does the job under `chunk_ciphertext`. - Asserts the property (the worker is a coroutine, ffmpeg is spawned through - asyncio) rather than grepping for "subprocess.run" — which also matches the - comment that documents the old behaviour. + Asserted as the property, not as "the function is gone": what matters is + that no transport has a field carrying media bytes past the AEAD. The old + H6 test lived here — it pinned `_do_stream_segment_async` to a coroutine so + ffmpeg could not block the event loop — and the handler outliving that + concern is exactly what this replaces. """ - import ast - import inspect - from meshbay_node.transport.webrtc_server import WebRTCPeerSession + import re + + from meshbay_common.protocol import MNP + + assert not hasattr(MNP, "STREAM_SEGMENT"), ( + "the constant outliving the handlers is how a deleted endpoint keeps " + "looking like part of the wire contract") + + root = Path(__file__).parent.parent / "src" / "meshbay_node" / "transport" + for name in ("webrtc_server.py", "quic_server.py", "quic_client.py"): + source = (root / name).read_text(encoding="utf-8") + # Word boundaries: `_stream_segments` and `STREAM_SEGMENT_SIZE` belong + # to the live `stream_data` path, which is encrypted and stays. + assert not re.search(r"\bstream_seg\b", source), ( + f"{name} still speaks stream_seg") + assert not re.search(r"\bSTREAM_SEGMENT\b", source), ( + f"{name} still names the removed type") + assert "data_b64" not in source, ( + f"{name} carries a base64 media field — media leaves this node " + "encrypted or not at all") - assert inspect.iscoroutinefunction(WebRTCPeerSession._do_stream_segment_async) + +def test_ffmpeg_never_blocks_the_event_loop(): + """ + H6, the half that survives `stream_seg`: the live streaming path still + spawns ffmpeg, and a synchronous spawn stalls every peer on the node. + """ + import ast source = (Path(__file__).parent.parent / "src" / "meshbay_node" / "transport" / "webrtc_server.py").read_text(encoding="utf-8") |