Skip to content

v0.9.0-rc.30

Choose a tag to compare

@github-actions github-actions released this 01 Jun 00:19
· 44 commits to main since this release
v0.9.0-rc.30
a08a6de

Airgap-safe peer dial + accept-side initial-sync push — unblocks ephemeral consumers (peat-cli) joining established sidecar meshes. Single landed PR (peat-mesh#206) closes peat-mesh#205. Two fixes ship together because they share the same surface (the MeshSyncTransport connect path + SyncProtocolHandler::accept) and were uncovered as adjacent bugs while debugging peat-node PR #114's QUICKSTART CI: a fresh-empty-store CLI dialing an established sidecar would (a) consult iroh's address_lookup chain even with the address in hand, then (b) authenticate cleanly but never observe the sidecar's existing docs. End-to-end validated against peat-node kp/quickstart-docs quickstart-compose + cross-cluster Tests 1–6.

Added

  • MeshSyncTransport::connect_and_authenticate_with_addr(EndpointAddr) (peat-mesh#206, closes peat-mesh#205). Surgical-caller variant alongside the existing EndpointId-only connect_and_authenticate. When the caller already has a populated EndpointAddr (peat-cli's join::connect_peer, peat-node sidecars' dial_and_attach, any out-of-band address-exchange path), this passes the address straight to endpoint.connect(addr, ALPN) so iroh sees ip_addresses=[Ip(…)] instead of [] — no address_lookup chain consultation, no DNS attempt, no chain-dispatch race. Guards against the obvious misuse (empty addrs set) with a loud anyhow::bail! at the call site rather than silently re-introducing the bug. Substantial doc-comments on both methods spell out when to prefer which variant.

Fixed

  • SyncProtocolHandler::accept now spawns initial-sync push on every inbound connection. Pre-fix, only the dial side called sync_all_documents_with_peer (via peat-node::start_sync and peat-cli::join::connect_peer). The accept side registered the connection and spawned the sync-receiver loop but never proactively pushed its own docs. That worked fine for sidecar-pair bootstrap because the dialer typically had docs too; it broke the moment an empty-store ephemeral consumer (peat-cli) dialed an established sidecar — the dialer's push iterated zero local docs, the acceptor never reciprocated, and the dialer's store stayed empty even though the connection was authenticated and idle. Accept side now symmetric with dial: spawns a one-shot sync_all_documents_with_peer(peer) after start_sync_connection, on a tokio task so iroh's ProtocolHandler::accept contract is preserved. Latent pre-existing bug surfaced by peat-node PR #114; not specific to the airgapped dial fix above.

  • DataSyncBackend::connect_to_peer honors the addresses it already accepts. Pre-fix the implementation had let _ = addresses; and silently dropped the address hints consumers passed through this trait method — exactly the information that makes the airgap-safe path possible. Non-empty addresses now routes through connect_and_authenticate_with_addr (the new method above), preserving the legacy bare-id connect_and_authenticate path for the "caller only has the id, rely on registered lookup source" case. Consumer-surface half of the peat-mesh#205 fix.

Added — regression tests

  • tests/connect_with_addr_airgapped.rs (5 in-tree pins, all run on every CI build):
    • old_method_requires_chain_new_method_bypasses_it — side-by-side proof on a single dialer endpoint with an empty address_lookup chain: the old EndpointId-only method fails (No addressing information available); the new EndpointAddr method succeeds. The chain-dependency is isolated as the only variable.
    • connect_with_addr_rejects_empty_addrs — pins the misuse-rejection guard: EndpointAddr::new(id) (sentinel-empty addrs) hits a loud anyhow::bail! instead of silently falling back to the chain.
    • connect_with_addr_empty_guard_fails_before_any_io — timing pin (elapsed < 50 ms) that catches a future refactor that moves the guard after endpoint.connect(...).await.
    • sync_round_trip_via_with_addr_adapter_path — full Automerge sync round-trip through DataSyncBackend::connect_to_peer's new with-addr branch with no MemoryLookup population. Proves the adapter actually establishes a sync-capable connection, not just a connect+auth handshake.
    • accept_side_pushes_existing_docs_to_fresh_dialer — pins the accept-side spawn introduced above: backend B upserts a doc before A connects, A connects fresh-empty via connect_and_authenticate_with_addr + start_sync_connection, A's document_store observes B's doc within 10 s. Pre-fix (verified by reverting the spawn while keeping the test) the test times out at the 10 s deadline. If the accept-side spawn ever regresses, this test catches it deterministically — A has zero local docs to push, so the accept-side path is the only way the doc can reach A.

Refs

  • peat-node PR #114 QUICKSTART CI on kp/quickstart-docs: all four gates (CI, Quickstart compose, cross-cluster sync, QA Review) confirmed green against rev cfa9023 and forward. Receipt thread on peat-mesh#205.