diff options
Diffstat (limited to 'packages/meshbay-hub/tests/test_transport_contracts.py')
| -rw-r--r-- | packages/meshbay-hub/tests/test_transport_contracts.py | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/packages/meshbay-hub/tests/test_transport_contracts.py b/packages/meshbay-hub/tests/test_transport_contracts.py index f2f4372..c506ff1 100644 --- a/packages/meshbay-hub/tests/test_transport_contracts.py +++ b/packages/meshbay-hub/tests/test_transport_contracts.py @@ -452,3 +452,57 @@ def test_the_index_is_never_reported_from_a_failed_decrypt(transport): assert "catch" not in body, ( "_applyIndexMessage swallows its own failure instead of letting " "_queueIndexMessage end the session") + + +# ── One node refusing must not take a group down (2026-09-11) ──────────────── +# +# `/v1/groups/{id}/nodes` returns every node registered for the group, in hub +# registration order. GroupPage took `nodesData.nodes[0]` and stopped there, so +# a node that could not serve the group — refusing the handshake with "Group +# not hosted on this node" — made the group unopenable while the node that +# *did* host it sat second in the same list. +# +# These strip comments first. The lesson this repeats otherwise is the CSP read +# out of the comment above the meta tag, and the packaging unit whose test +# matched the comment explaining why `User=` was absent: a source-level check +# that can match prose is not a check. + +def _code_only(src: str) -> str: + """Source with // and /* */ comments removed. Crude, and enough here: no + string literal in these files carries a comment marker.""" + src = re.sub(r"/\*.*?\*/", "", src, flags=re.S) + return re.sub(r"^\s*//.*$", "", src, flags=re.M) + + +def test_the_group_page_tries_every_node_the_hub_offers(group_page): + code = _code_only(group_page) + assert "for (const n of nodesData.nodes)" in code, ( + "the connect effect must walk the list, not index into it") + assert "nodesData.nodes[0]" not in code, ( + "taking the head and stopping is the defect — one wrongly registered " + "node captured the whole group's traffic") + + +def test_a_not_hosted_refusal_moves_on_to_the_next_node(group_page): + code = _code_only(group_page) + body = code[code.index("for (const n of nodesData.nodes)"):] + body = body[:body.index("if (!transport)")] + assert "not_hosted" in body, ( + "without the code, a refusal this browser cannot act on is " + "indistinguishable from one it must stop for") + assert "throw e" in body, ( + "a refusal naming a state of this browser — a pairing code, a " + "passphrase, a device — is the same from every node and must stop here") + + +def test_the_last_refusal_is_what_the_reader_is_told(group_page): + code = _code_only(group_page) + assert "if (!transport) throw (lastErr" in code, ( + "exhausting the list must report why, not fall through silently") + + +def test_the_refusal_the_loop_keys_on_has_a_message(transport): + """A code the page routes on, with nothing to show, is a blank error.""" + refusals = transport[transport.index("const HANDSHAKE_REFUSALS"):] + refusals = refusals[:refusals.index("};")] + assert "not_hosted:" in refusals |