aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-common/tests/test_js_python_parity.py
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-07 18:03:52 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-07 18:03:52 +0200
commite1383e1d545b994f4ad61694f868339defb0bdef (patch)
tree67a3b1933f2a9c5caf107d01d9ff91c44a975df6 /packages/meshbay-common/tests/test_js_python_parity.py
parent36cebf25d0e0f24cf63be4380ccb5d03da726a74 (diff)
parent8980a8e42d94ab7c0bc9739283d39f938f8402b0 (diff)
downloadmeshbay-e1383e1d545b994f4ad61694f868339defb0bdef.tar.gz
Merge origin/main into the chat encryption work
Both sides landed a breaking MNP change and both called it 2.0, which is right: the sealed upload, the removal of `stream_seg` and mandatory chat encryption share one flag day. They are recorded as one version in `__init__.py` rather than as a race between two. The resolutions that were decisions rather than mechanics: * **`MNP_MIN_SUPPORTED` moves to "2.0".** The sealed upload alone was a *confined* break — a 1.x peer could still connect, browse, download, stream and chat, with only its uploads refused by `upload_not_sealed` — so the floor deliberately stayed at "1.0". Mandatory chat encryption ends that confinement: a 1.x peer can neither produce a sealed chat message nor read one, so it would connect, look fine, and be unable to say anything. Refusing it at the handshake is the honest form. The per-message `upload_not_sealed` path is untouched and still right if the floor is ever lowered. * **`sendChat` throws on an `error` reply**, from origin, applied to the sealed send. It matters more after this change, not less: the node now refuses a stale epoch, a malformed envelope and a device claim that is not the connection's own, so there are three new ways for a message to be rejected and none of them may look like a message that was sent. * **`req_id` supersedes the per-type routing** this branch added for `chat_keys_resp` and `device_hello_ack`. Both blocks are kept beside the existing `chat_hist_resp` one, for the same stated reason — a node too old to stamp — and their comments no longer claim to be the mechanism that closes the class. `req_id` is. * **`chat_send_probe.py` is rebuilt on origin's structure**, not beside it: two scenarios, a stub that stamps `req_id`, `music_meta_req` as the older pending request. The encrypted path is layered on — a real Ed25519 device key generated in the page, and a `chat_keys_resp` sealed by the shipped Python, because a payload the page built itself would prove only that the page agrees with the page. * **`test_reply_correlation.py` now sends a sealed message.** Its subject is which of the two messages leaving that handler carries the id; plaintext chat was only the fixture, and the node refuses one now. * `groupbox` keeps both new purposes (`upload`, `chat_keys`); `protocol.py` keeps origin's removal of `STREAM_SEGMENT` and this branch's correction of the "Double Ratchet message" comment on `CHAT_MESSAGE`, which was wrong when it was written and is wrong differently now. Full suite on the merged tree: 1993 passed, 11 failed — the same 11 that fail on a pristine checkout (2 Windows service tests, 1 apps-enabled policy, 7 transcode tests that pass in isolation, and the WebRTC invite test that hangs on its own). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TZZxYjz8YeWRz13xDi8LJr
Diffstat (limited to 'packages/meshbay-common/tests/test_js_python_parity.py')
-rw-r--r--packages/meshbay-common/tests/test_js_python_parity.py13
1 files changed, 10 insertions, 3 deletions
diff --git a/packages/meshbay-common/tests/test_js_python_parity.py b/packages/meshbay-common/tests/test_js_python_parity.py
index dffee36..9893a9f 100644
--- a/packages/meshbay-common/tests/test_js_python_parity.py
+++ b/packages/meshbay-common/tests/test_js_python_parity.py
@@ -259,6 +259,11 @@ GROUPBOX_VECTORS = [
("index", "index_sync", "groupe-café-日本"),
# A '|' inside the group id, which is the AAD's own separator.
("index", "index_sync", "a|b"),
+ # MNP 2.0 — the upload, and the only purpose the *browser* seals in
+ # production. A disagreement here means no file can be uploaded from any
+ # browser to any node, and the node reports only "it did not open".
+ ("upload", "file_upload", "g" * 32),
+ ("upload", "file_upload_ack", "g" * 32),
]
GROUPBOX_GEK = bytes.fromhex("5a" * 32)
@@ -350,9 +355,11 @@ def test_browser_opens_what_python_sealed(idx, vector, groupbox_js):
@pytest.mark.parametrize("idx,vector", list(enumerate(GROUPBOX_VECTORS)))
def test_python_opens_what_the_browser_sealed(idx, vector, groupbox_js):
"""
- The other direction. Nothing in the SPA seals today — `sealGroup` exists for
- the chat plan, which needs the same primitive — but a codec that only ever
- runs one way is a codec whose encoder is untested.
+ The other direction, and since MNP 2.0 it is a shipping path rather than a
+ precaution: `uploadFile` seals every chunk under `upload`, and the node
+ opens it with `unseal`. The index vectors above still only ever run one way
+ in production, and are kept because a codec whose encoder is untested is a
+ codec with half a test.
"""
from meshbay_common.groupbox import unseal