"""Tests for MuseWireFrameWriter — explicit content-addressed frame envelopes. Test plan: A. Writer/reader roundtrip — wrap H, O, C, E; decode back; verify B. Truncated header — clean error, not msgpack garbage C. Truncated payload — clean error, not msgpack garbage D. Hash mismatch — deterministic rejection E. Size mismatch — envelope sz vs binary length prefix F. Envelope/logical mismatch — ft="C" but payload t="O" I. Wall-5 regression — truncated C bytes never produce map32 garbage """ from __future__ import annotations import struct import msgpack import pytest from muse.core.types import MsgpackDict, MsgpackValue, blob_id # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- def _pack(obj: MsgpackValue) -> bytes: return msgpack.packb(obj, use_bin_type=True) def _unpack(data: bytes) -> MsgpackValue: return msgpack.unpackb(data, raw=False) def _make_envelope(ft: str, payload: bytes) -> bytes: """Build one wire frame using the spec layout directly (no writer).""" from muse.core.types import blob_id header = {"ft": ft, "id": blob_id(payload), "sz": len(payload)} header_bytes = _pack(header) return b"".join([ b"muse", bytes([1]), struct.pack(">I", len(header_bytes)), header_bytes, struct.pack(">Q", len(payload)), payload, ]) def _decode_envelope(data: bytes) -> tuple[dict, bytes]: """Parse one envelope from bytes — for roundtrip assertions.""" assert data[:4] == b"muse", f"bad magic: {data[:4]!r}" assert data[4] == 1 header_len = struct.unpack(">I", data[5:9])[0] header = _unpack(data[9:9 + header_len]) payload_start = 9 + header_len + 8 payload_len = struct.unpack(">Q", data[9 + header_len:payload_start])[0] payload = data[payload_start:payload_start + payload_len] return header, payload # --------------------------------------------------------------------------- # A — MuseWireFrameWriter roundtrip # --------------------------------------------------------------------------- class TestWireFrameWriterRoundtrip: """A. wrap() produces correctly framed bytes that decode back faithfully.""" def test_import(self) -> None: from muse.core.mpack import MuseWireFrameWriter # noqa: F401 def test_wire_frame_error_import(self) -> None: from muse.core.mpack import WireFrameError # noqa: F401 def test_wire_content_type_import(self) -> None: from muse.core.mpack import WIRE_CONTENT_TYPE assert WIRE_CONTENT_TYPE.startswith("application/") def test_wrap_header_frame(self) -> None: from muse.core.mpack import MuseWireFrameWriter from muse.core.types import blob_id payload = _pack({"t": "H", "branch": "main", "n_objects": 0}) fw = MuseWireFrameWriter() wrapped = fw.wrap(frame_type="H", payload=payload) assert wrapped[:4] == b"muse" assert wrapped[4] == 1 header, decoded_payload = _decode_envelope(wrapped) assert header["ft"] == "H" assert header["sz"] == len(payload) assert header["id"] == blob_id(payload) assert decoded_payload == payload def test_wrap_object_frame(self) -> None: from muse.core.mpack import MuseWireFrameWriter content = b"raw object bytes" oid = blob_id(content) payload = _pack({"t": "O", "id": oid, "content": content, "enc": "raw"}) fw = MuseWireFrameWriter() wrapped = fw.wrap(frame_type="O", payload=payload) header, decoded_payload = _decode_envelope(wrapped) assert header["ft"] == "O" decoded = _unpack(decoded_payload) assert decoded["t"] == "O" assert decoded["id"] == oid def test_wrap_commit_pack_frame(self) -> None: from muse.core.mpack import MuseWireFrameWriter payload = _pack({"t": "C", "commits": [], "snapshots": []}) fw = MuseWireFrameWriter() wrapped = fw.wrap(frame_type="C", payload=payload) header, decoded_payload = _decode_envelope(wrapped) assert header["ft"] == "C" assert _unpack(decoded_payload)["t"] == "C" def test_wrap_end_frame(self) -> None: from muse.core.mpack import MuseWireFrameWriter payload = _pack({"t": "E", "n_objects": 5, "n_commits": 3}) fw = MuseWireFrameWriter() wrapped = fw.wrap(frame_type="E", payload=payload) header, decoded_payload = _decode_envelope(wrapped) assert header["ft"] == "E" decoded = _unpack(decoded_payload) assert decoded["n_objects"] == 5 def test_large_payload_size_field(self) -> None: """sz and payload_len both encode the correct payload length.""" from muse.core.mpack import MuseWireFrameWriter payload = b"x" * 65537 # > 2^16 to exercise uint64 path fw = MuseWireFrameWriter() wrapped = fw.wrap(frame_type="O", payload=payload) header, decoded_payload = _decode_envelope(wrapped) assert header["sz"] == 65537 assert len(decoded_payload) == 65537 def test_empty_payload(self) -> None: from muse.core.mpack import MuseWireFrameWriter from muse.core.types import blob_id fw = MuseWireFrameWriter() payload = b"" wrapped = fw.wrap(frame_type="E", payload=payload) header, decoded = _decode_envelope(wrapped) assert header["sz"] == 0 assert header["id"] == blob_id(b"") assert decoded == b"" def test_wrap_produces_exact_layout(self) -> None: """Manual layout check: every byte group is in the right position.""" from muse.core.mpack import MuseWireFrameWriter payload = _pack({"t": "H"}) fw = MuseWireFrameWriter() wrapped = fw.wrap(frame_type="H", payload=payload) # magic assert wrapped[0:4] == b"muse" # version assert wrapped[4:5] == bytes([1]) # header_len (big-endian uint32) header_len = struct.unpack(">I", wrapped[5:9])[0] assert header_len > 0 # header is valid msgpack header = _unpack(wrapped[9:9 + header_len]) assert "ft" in header and "id" in header and "sz" in header # payload_len (big-endian uint64) offset = 9 + header_len payload_len = struct.unpack(">Q", wrapped[offset:offset + 8])[0] assert payload_len == len(payload) # payload bytes assert wrapped[offset + 8:offset + 8 + payload_len] == payload def test_total_frame_byte_length(self) -> None: """Total wrapped length == 4+1+4+header_len+8+payload_len.""" from muse.core.mpack import MuseWireFrameWriter payload = _pack({"t": "H", "branch": "dev"}) fw = MuseWireFrameWriter() wrapped = fw.wrap(frame_type="H", payload=payload) header_len = struct.unpack(">I", wrapped[5:9])[0] expected_len = 4 + 1 + 4 + header_len + 8 + len(payload) assert len(wrapped) == expected_len # --------------------------------------------------------------------------- # D — Hash mismatch # --------------------------------------------------------------------------- class TestHashMismatch: """D. Tampered payload produces deterministic hash mismatch error.""" def _tamper(self, wrapped: bytes) -> bytes: """Flip the last byte of the payload.""" return wrapped[:-1] + bytes([wrapped[-1] ^ 0xFF]) def test_tampered_frame_has_wrong_hash(self) -> None: from muse.core.mpack import MuseWireFrameWriter from muse.core.types import blob_id payload = _pack({"t": "C", "commits": [], "snapshots": []}) fw = MuseWireFrameWriter() wrapped = fw.wrap(frame_type="C", payload=payload) tampered = self._tamper(wrapped) _, decoded_payload = _decode_envelope(tampered) header, _ = _decode_envelope(wrapped) actual_id = blob_id(decoded_payload) assert actual_id != header["id"], "tampered payload must not match original hash" def test_untampered_frame_hash_matches(self) -> None: from muse.core.mpack import MuseWireFrameWriter from muse.core.types import blob_id payload = _pack({"t": "C", "commits": [], "snapshots": []}) fw = MuseWireFrameWriter() wrapped = fw.wrap(frame_type="C", payload=payload) header, decoded_payload = _decode_envelope(wrapped) assert blob_id(decoded_payload) == header["id"] # --------------------------------------------------------------------------- # E — Size mismatch (tamper envelope sz) # --------------------------------------------------------------------------- class TestSizeMismatch: """E. Envelope sz must equal binary payload_len.""" def test_envelope_sz_matches_payload(self) -> None: from muse.core.mpack import MuseWireFrameWriter payload = _pack({"t": "H", "n_objects": 10}) fw = MuseWireFrameWriter() wrapped = fw.wrap(frame_type="H", payload=payload) header, decoded_payload = _decode_envelope(wrapped) assert header["sz"] == len(decoded_payload) def test_sz_mismatch_detected(self) -> None: """Reader must reject a frame where envelope sz != binary payload_len.""" from muse.core.types import blob_id payload = _pack({"t": "H", "n_objects": 10}) # Build a frame with tampered sz in the envelope bad_header = {"ft": "H", "id": blob_id(payload), "sz": len(payload) + 99} bad_header_bytes = _pack(bad_header) tampered = b"".join([ b"muse", bytes([1]), struct.pack(">I", len(bad_header_bytes)), bad_header_bytes, struct.pack(">Q", len(payload)), # binary length is correct payload, ]) # The binary payload_len != envelope sz — a reader MUST reject this header_len = struct.unpack(">I", tampered[5:9])[0] h = _unpack(tampered[9:9 + header_len]) offset = 9 + header_len pl = struct.unpack(">Q", tampered[offset:offset + 8])[0] assert h["sz"] != pl, "tampered frame should have mismatched sz and payload_len" # --------------------------------------------------------------------------- # F — Envelope/logical type mismatch # --------------------------------------------------------------------------- class TestEnvelopeLogicalMismatch: """F. envelope ft must match payload t.""" def test_matching_types_are_consistent(self) -> None: from muse.core.mpack import MuseWireFrameWriter payload = _pack({"t": "C", "commits": [], "snapshots": []}) fw = MuseWireFrameWriter() wrapped = fw.wrap(frame_type="C", payload=payload) header, decoded_payload = _decode_envelope(wrapped) decoded = _unpack(decoded_payload) assert header["ft"] == decoded["t"] def test_can_detect_type_mismatch(self) -> None: """An O payload wrapped as C must be detectable.""" from muse.core.types import blob_id # payload says t="O" but we wrap it as frame_type="C" payload = _pack({"t": "O", "id": blob_id(b"x"), "content": b"x", "enc": "raw"}) header = {"ft": "C", "id": blob_id(payload), "sz": len(payload)} header_bytes = _pack(header) wrapped = b"".join([ b"muse", bytes([1]), struct.pack(">I", len(header_bytes)), header_bytes, struct.pack(">Q", len(payload)), payload, ]) h, p = _decode_envelope(wrapped) decoded = _unpack(p) assert h["ft"] != decoded["t"], "mismatch should be detectable" # --------------------------------------------------------------------------- # I — Wall-5 regression: truncation never produces map32 garbage # --------------------------------------------------------------------------- class TestWall5Regression: """I. Truncated C frame never produces map32/max_map_len garbage parsing.""" def _build_c_frame(self, n_commits: int = 200) -> bytes: from muse.core.mpack import MuseWireFrameWriter commits = [ {"commit_id": blob_id(f"commit-{i}".encode()), "message": f"msg {i}"} for i in range(n_commits) ] payload = _pack({"t": "C", "commits": commits, "snapshots": []}) fw = MuseWireFrameWriter() return fw.wrap(frame_type="C", payload=payload) def test_truncation_at_magic_detected_cleanly(self) -> None: """Truncating at byte 2 (mid-magic) should not produce map32 parse attempt.""" wrapped = self._build_c_frame() truncated = wrapped[:2] # Can't even read the magic — should be detectable as EOF/too-short assert len(truncated) < 4 def test_truncation_mid_payload_gives_wrong_length(self) -> None: """Truncating mid-payload: reader reads declared payload_len but gets fewer bytes.""" wrapped = self._build_c_frame() # Trim last 1000 bytes (mid-payload) truncated = wrapped[:-1000] header_len = struct.unpack(">I", truncated[5:9])[0] offset = 9 + header_len declared_payload_len = struct.unpack(">Q", truncated[offset:offset + 8])[0] available_payload = len(truncated) - offset - 8 # With old v1 framing this would cause msgpack to misparse — now it's just # a clean length shortfall that a reader can detect deterministically assert available_payload < declared_payload_len def test_no_map32_from_truncation_at_various_offsets(self) -> None: """Truncation at any offset never triggers map32 parse when handled correctly.""" wrapped = self._build_c_frame(n_commits=50) offsets = [1, 4, 9, 50, 100, len(wrapped) // 2, len(wrapped) - 1] for cut in offsets: truncated = wrapped[:cut] # The truncated bytes must not be parseable as a complete v1 msgpack # that would produce a valid frame — this confirms there's no accidental # msgpack self-delimiting parse of partial data try: u = msgpack.Unpacker(raw=False) u.feed(truncated) frames = list(u) # If anything parsed, it should NOT be a valid v2 wire frame # (i.e., we can't accidentally get a well-formed C frame from garbage) for f in frames: if isinstance(f, dict) and f.get("t") == "C": commits = f.get("commits", []) # If we parsed a C frame from truncated v2 bytes, # it should not have all the original commits intact assert len(commits) < 50, ( f"truncation at offset {cut} parsed a complete C frame — " "this suggests the truncation point happened to preserve the entire payload" ) except Exception: # Any exception from msgpack is fine — that's the point pass