feat: add inbound P2P event bridge - #2
Open
raysvitla wants to merge 2 commits into
Open
Conversation
Turns authenticated/decrypted/persisted P2P group messages into typed local events for agent runtimes to decide act | ask | ignore. - PrivateInboundMessageEvent (local, decrypted plaintext) + PublicActivityEvent (metadata-only); legacy group:message preserved. - InboundEventQueue on Agent buffers private events for MCP/CLI pollers. - New MCP tool get_pending_inbound_events with DTO that hex-encodes keys and base64-encodes plaintext so no Uint8Array leaks via JSON.stringify. - DM path remains fail-closed per PR #1; typed with kind: 'dm' for forward compatibility, no emission until DM signing lands. - 22 new tests: emission path, legacy compatibility, invalid-sig / unknown-member / failed-decrypt negatives, public-log canary, queue semantics, MCP DTO. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- canary covers stderr/debug/stdout.write/stderr.write and asserts activity-event serialization is canary-free - MCP get_pending_inbound_events description explicitly owner-private, warns against public/dashboard/census forwarding - InboundEventQueue.drain returns a copy, not the internal buffer - explicit isMember gate in handleGroupMessage (defence-in-depth alongside the implicit sender-key gate) + negative test - queue handler errors surface via queueMicrotask instead of being swallowed, without blocking delivery to other handlers Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Depends on #1.
Turns authenticated/decrypted/persisted P2P group messages into typed local events for an agent runtime to decide act | ask | ignore. This is the thinnest bridge from "secure transport" to "agent network".
Summary
@networkselfmd/core:PrivateInboundMessageEvent— local-only; carries decrypted plaintext + full context (messageId, groupId, senderPublicKey, senderFingerprint, timestamp, receivedAt).PublicActivityEvent— metadata-only (groupIdHex, senderFingerprint, timestamp, byteLength). Safe for future census/heartbeat/dashboard.GroupManager/Agent:inbound:message,activity:message. Legacygroup:messagepayload preserved unchanged — no listener regressions.InboundEventQueueonAgent— bounded FIFO (default 1000) withpush/drain/peek/on(unsubscribe). Buffers only private events; public activity is live-only.get_pending_inbound_eventsplustoInboundEventDTOhelper — hex for keys/groupId, base64 for plaintext, strict UTF-8 optional. NoUint8Arrayever reachesJSON.stringify.kind: 'dm'reserved in the type; explicit TODO marker for the DM-signing / Double Ratchet PR.Guardrails
All emissions happen after signature verification + sender-key scoping + decryption +
messageRepo.insert()succeed. Never on failed paths. Rejection branches (invalid sig, unknown member, failed decrypt, unknown group) continue toemit('error', ...)andreturnbefore any new emission.Public-log canary test ensures plaintext does not reach
console.log/info/warn.Tests
22 new tests (total 130):
inbound:messagewith expected fields + DBmessageIdround-trip;activity:messagemetadata-only (asserted absence ofplaintext/ciphertext/senderPublicKey/base64 fields).group:messagepayload preserved.InboundEventQueue: FIFO order, non-destructivepeek, overflow drops oldest,on()+ unsubscribe.JSON.stringify.Shared test harness extracted to
packages/node/src/__tests__/test-utils/group-harness.ts;group-signatures.test.tsmigrated to it.Out of scope (follow-up PRs)
activity:message).watchcommand.Verification
Test plan
pnpm testgreenpnpm buildgreenBob.inboundQueue.drain()returns onePrivateInboundMessageEventwith expected plaintext; tamper ciphertext → empty drain, noactivity:message.get_pending_inbound_eventsreturns DTO with hex keys + base64 plaintext;JSON.stringify(result)contains no numeric-keyed byte objects.group:messagestill receive the original payload shape.🤖 Generated with Claude Code