@claude-flow/plugin-agent-federation 1.0.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +45 -0
  2. package/dist/application/federation-breaker-service.d.ts +182 -0
  3. package/dist/application/federation-breaker-service.d.ts.map +1 -0
  4. package/dist/application/federation-breaker-service.js +251 -0
  5. package/dist/application/federation-breaker-service.js.map +1 -0
  6. package/dist/application/federation-coordinator.d.ts +166 -0
  7. package/dist/application/federation-coordinator.d.ts.map +1 -0
  8. package/dist/application/federation-coordinator.js +412 -0
  9. package/dist/application/federation-coordinator.js.map +1 -0
  10. package/dist/application/inbound-dispatcher.d.ts +59 -0
  11. package/dist/application/inbound-dispatcher.d.ts.map +1 -0
  12. package/dist/application/inbound-dispatcher.js +96 -0
  13. package/dist/application/inbound-dispatcher.js.map +1 -0
  14. package/dist/application/policy-engine.d.ts +41 -0
  15. package/dist/application/policy-engine.d.ts.map +1 -0
  16. package/dist/application/policy-engine.js +184 -0
  17. package/dist/application/policy-engine.js.map +1 -0
  18. package/dist/application/spend-reporter.d.ts +150 -0
  19. package/dist/application/spend-reporter.d.ts.map +1 -0
  20. package/dist/application/spend-reporter.js +128 -0
  21. package/dist/application/spend-reporter.js.map +1 -0
  22. package/dist/application/trust-evaluator.d.ts +42 -0
  23. package/dist/application/trust-evaluator.d.ts.map +1 -0
  24. package/dist/application/trust-evaluator.js +132 -0
  25. package/dist/application/trust-evaluator.js.map +1 -0
  26. package/dist/bin.d.ts +13 -0
  27. package/dist/bin.d.ts.map +1 -0
  28. package/dist/bin.js +189 -0
  29. package/dist/bin.js.map +1 -0
  30. package/dist/cli-commands.d.ts +7 -0
  31. package/dist/cli-commands.d.ts.map +1 -0
  32. package/dist/cli-commands.js +198 -0
  33. package/dist/cli-commands.js.map +1 -0
  34. package/dist/domain/entities/federation-envelope.d.ts +45 -0
  35. package/dist/domain/entities/federation-envelope.d.ts.map +1 -0
  36. package/dist/domain/entities/federation-envelope.js +71 -0
  37. package/dist/domain/entities/federation-envelope.js.map +1 -0
  38. package/dist/domain/entities/federation-node.d.ts +104 -0
  39. package/dist/domain/entities/federation-node.d.ts.map +1 -0
  40. package/dist/domain/entities/federation-node.js +152 -0
  41. package/dist/domain/entities/federation-node.js.map +1 -0
  42. package/dist/domain/entities/federation-session.d.ts +55 -0
  43. package/dist/domain/entities/federation-session.d.ts.map +1 -0
  44. package/dist/domain/entities/federation-session.js +105 -0
  45. package/dist/domain/entities/federation-session.js.map +1 -0
  46. package/dist/domain/entities/trust-level.d.ts +17 -0
  47. package/dist/domain/entities/trust-level.d.ts.map +1 -0
  48. package/dist/domain/entities/trust-level.js +35 -0
  49. package/dist/domain/entities/trust-level.js.map +1 -0
  50. package/dist/domain/services/audit-service.d.ts +69 -0
  51. package/dist/domain/services/audit-service.d.ts.map +1 -0
  52. package/dist/domain/services/audit-service.js +149 -0
  53. package/dist/domain/services/audit-service.js.map +1 -0
  54. package/dist/domain/services/discovery-service.d.ts +51 -0
  55. package/dist/domain/services/discovery-service.d.ts.map +1 -0
  56. package/dist/domain/services/discovery-service.js +140 -0
  57. package/dist/domain/services/discovery-service.js.map +1 -0
  58. package/dist/domain/services/handshake-service.d.ts +48 -0
  59. package/dist/domain/services/handshake-service.d.ts.map +1 -0
  60. package/dist/domain/services/handshake-service.js +94 -0
  61. package/dist/domain/services/handshake-service.js.map +1 -0
  62. package/dist/domain/services/pii-pipeline-service.d.ts +65 -0
  63. package/dist/domain/services/pii-pipeline-service.d.ts.map +1 -0
  64. package/dist/domain/services/pii-pipeline-service.js +208 -0
  65. package/dist/domain/services/pii-pipeline-service.js.map +1 -0
  66. package/dist/domain/services/routing-service.d.ts +51 -0
  67. package/dist/domain/services/routing-service.d.ts.map +1 -0
  68. package/dist/domain/services/routing-service.js +147 -0
  69. package/dist/domain/services/routing-service.js.map +1 -0
  70. package/dist/domain/value-objects/federation-budget.d.ts +89 -0
  71. package/dist/domain/value-objects/federation-budget.d.ts.map +1 -0
  72. package/dist/domain/value-objects/federation-budget.js +165 -0
  73. package/dist/domain/value-objects/federation-budget.js.map +1 -0
  74. package/dist/domain/value-objects/federation-node-state.d.ts +92 -0
  75. package/dist/domain/value-objects/federation-node-state.d.ts.map +1 -0
  76. package/dist/domain/value-objects/federation-node-state.js +100 -0
  77. package/dist/domain/value-objects/federation-node-state.js.map +1 -0
  78. package/dist/index.d.ts +17 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +17 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/mcp-tools.d.ts +8 -0
  83. package/dist/mcp-tools.d.ts.map +1 -0
  84. package/dist/mcp-tools.js +343 -0
  85. package/dist/mcp-tools.js.map +1 -0
  86. package/dist/plugin.d.ts +18 -0
  87. package/dist/plugin.d.ts.map +1 -0
  88. package/dist/plugin.js +376 -0
  89. package/dist/plugin.js.map +1 -0
  90. package/package.json +44 -0
@@ -0,0 +1,412 @@
1
+ import { TrustLevel } from '../domain/entities/trust-level.js';
2
+ import { FederationNodeState, } from '../domain/value-objects/federation-node-state.js';
3
+ import { enforceBudget, validateBudget, } from '../domain/value-objects/federation-budget.js';
4
+ export class FederationCoordinator {
5
+ config;
6
+ discovery;
7
+ handshake;
8
+ routing;
9
+ audit;
10
+ piiPipeline;
11
+ trustEvaluator;
12
+ policyEngine;
13
+ sessions;
14
+ initialized;
15
+ spendReporter;
16
+ breakerService;
17
+ constructor(config, discovery, handshake, routing, audit, piiPipeline, trustEvaluator, policyEngine, integrations = {}) {
18
+ this.config = config;
19
+ this.discovery = discovery;
20
+ this.handshake = handshake;
21
+ this.routing = routing;
22
+ this.audit = audit;
23
+ this.piiPipeline = piiPipeline;
24
+ this.trustEvaluator = trustEvaluator;
25
+ this.policyEngine = policyEngine;
26
+ this.sessions = new Map();
27
+ this.initialized = false;
28
+ this.spendReporter = integrations.spendReporter;
29
+ this.breakerService = integrations.breakerService;
30
+ }
31
+ async initialize(manifest) {
32
+ await this.discovery.publishManifest(manifest);
33
+ this.discovery.startPeriodicDiscovery();
34
+ this.initialized = true;
35
+ await this.audit.log('peer_manifest_published', {
36
+ metadata: { endpoint: this.config.endpoint },
37
+ });
38
+ }
39
+ async shutdown() {
40
+ this.discovery.stopPeriodicDiscovery();
41
+ for (const [sessionId, session] of this.sessions) {
42
+ session.terminate();
43
+ await this.audit.log('session_terminated', {
44
+ sessionId,
45
+ targetNodeId: session.remoteNodeId,
46
+ });
47
+ }
48
+ this.sessions.clear();
49
+ await this.audit.flush();
50
+ this.initialized = false;
51
+ }
52
+ async joinPeer(endpoint) {
53
+ this.ensureInitialized();
54
+ const node = await this.discovery.addStaticPeer(endpoint);
55
+ await this.audit.log('peer_discovered', {
56
+ targetNodeId: node.nodeId,
57
+ metadata: { endpoint },
58
+ });
59
+ return this.establishSession(node);
60
+ }
61
+ async leavePeer(nodeId) {
62
+ this.ensureInitialized();
63
+ const session = this.findSessionByNodeId(nodeId);
64
+ if (session) {
65
+ session.terminate();
66
+ this.sessions.delete(session.sessionId);
67
+ await this.audit.log('session_terminated', {
68
+ sessionId: session.sessionId,
69
+ targetNodeId: nodeId,
70
+ });
71
+ }
72
+ this.discovery.removePeer(nodeId);
73
+ }
74
+ async sendMessage(targetNodeId, messageType, payload, options = {}) {
75
+ this.ensureInitialized();
76
+ // ADR-097 Phase 2.b: outbound short-circuit on tripped breaker. If the
77
+ // peer is SUSPENDED or EVICTED we refuse the send before doing any work,
78
+ // and emit a constant-string error (no remaining-budget echo per the
79
+ // anti-oracle posture inherited from Phase 1). The check fires *before*
80
+ // session lookup so an evicted peer cannot consume cycles even on a
81
+ // dangling session reference.
82
+ const peer = this.discovery.getPeer(targetNodeId);
83
+ if (peer && !peer.isActive) {
84
+ const reason = peer.isEvicted ? 'PEER_EVICTED' : 'PEER_SUSPENDED';
85
+ await this.audit.log('message_rejected', {
86
+ targetNodeId,
87
+ metadata: { reason },
88
+ });
89
+ return {
90
+ success: false,
91
+ mode: 'direct',
92
+ envelopeId: '',
93
+ targetNodeIds: [targetNodeId],
94
+ error: reason,
95
+ };
96
+ }
97
+ const session = this.findSessionByNodeId(targetNodeId);
98
+ if (!session) {
99
+ return {
100
+ success: false,
101
+ mode: 'direct',
102
+ envelopeId: '',
103
+ targetNodeIds: [targetNodeId],
104
+ error: `No active session with node ${targetNodeId}`,
105
+ };
106
+ }
107
+ const policyResult = this.policyEngine.evaluateMessage(messageType, session.trustLevel, JSON.stringify(payload).length, this.config.nodeId);
108
+ if (!policyResult.allowed) {
109
+ await this.audit.log('message_rejected', {
110
+ targetNodeId,
111
+ sessionId: session.sessionId,
112
+ metadata: { reason: policyResult.reason },
113
+ });
114
+ return {
115
+ success: false,
116
+ mode: 'direct',
117
+ envelopeId: '',
118
+ targetNodeIds: [targetNodeId],
119
+ error: policyResult.reason,
120
+ };
121
+ }
122
+ // ADR-097 Phase 1: validate caller-supplied budget + enforce hop limit
123
+ // and cumulative spend BEFORE outbound dispatch. Synchronous & atomic —
124
+ // no awaits between validate and enforce, so concurrent sends cannot
125
+ // both pass a single-hop budget. Errors are constant strings so a
126
+ // malicious caller cannot use the response as a budget oracle.
127
+ const budgetResult = validateBudget(options.budget, options.maxHops);
128
+ if (!budgetResult.ok) {
129
+ await this.audit.log('message_rejected', {
130
+ targetNodeId,
131
+ sessionId: session.sessionId,
132
+ metadata: { reason: 'INVALID_BUDGET', detail: budgetResult.error },
133
+ });
134
+ return {
135
+ success: false,
136
+ mode: 'direct',
137
+ envelopeId: '',
138
+ targetNodeIds: [targetNodeId],
139
+ error: 'INVALID_BUDGET',
140
+ };
141
+ }
142
+ const enforcement = enforceBudget(budgetResult.budget, options.hopCount ?? 0, {
143
+ tokens: options.spent?.tokens ?? 0,
144
+ usd: options.spent?.usd ?? 0,
145
+ });
146
+ if (!enforcement.ok) {
147
+ await this.audit.log('message_rejected', {
148
+ targetNodeId,
149
+ sessionId: session.sessionId,
150
+ metadata: { reason: enforcement.reason },
151
+ });
152
+ return {
153
+ success: false,
154
+ mode: 'direct',
155
+ envelopeId: '',
156
+ targetNodeIds: [targetNodeId],
157
+ error: enforcement.reason, // constant string — no oracle leak
158
+ };
159
+ }
160
+ const result = await this.routing.send(session, messageType, payload);
161
+ await this.audit.log(result.success ? 'message_sent' : 'message_rejected', {
162
+ targetNodeId,
163
+ sessionId: session.sessionId,
164
+ latencyMs: result.latencyMs,
165
+ metadata: {
166
+ messageType,
167
+ mode: result.mode,
168
+ hopCount: enforcement.nextHopCount,
169
+ },
170
+ });
171
+ return result;
172
+ }
173
+ /**
174
+ * Re-export the budget primitives so external callers (e.g. follow-up
175
+ * iterations adding receive-side decrement) can reuse them without
176
+ * dipping into domain/value-objects directly.
177
+ */
178
+ static budget = { validate: validateBudget, enforce: enforceBudget };
179
+ async broadcastMessage(messageType, payload) {
180
+ this.ensureInitialized();
181
+ return this.routing.broadcast(messageType, payload);
182
+ }
183
+ handleThreatDetection(nodeId) {
184
+ const exceedsThreshold = this.trustEvaluator.recordThreatDetection(nodeId);
185
+ const node = this.discovery.getPeer(nodeId);
186
+ if (node && exceedsThreshold) {
187
+ this.trustEvaluator.downgrade(node, 'repeated-threat-detection');
188
+ const session = this.findSessionByNodeId(nodeId);
189
+ if (session) {
190
+ session.terminate();
191
+ this.sessions.delete(session.sessionId);
192
+ }
193
+ this.audit.log('threat_blocked', {
194
+ sourceNodeId: nodeId,
195
+ trustLevel: TrustLevel.UNTRUSTED,
196
+ threatDetected: true,
197
+ metadata: { reason: 'repeated-threat-detection' },
198
+ });
199
+ }
200
+ }
201
+ handleHmacFailure(nodeId) {
202
+ const node = this.discovery.getPeer(nodeId);
203
+ if (node) {
204
+ this.trustEvaluator.downgrade(node, 'hmac-verification-failure');
205
+ const session = this.findSessionByNodeId(nodeId);
206
+ if (session) {
207
+ session.terminate();
208
+ this.sessions.delete(session.sessionId);
209
+ }
210
+ this.audit.log('threat_blocked', {
211
+ sourceNodeId: nodeId,
212
+ trustLevel: TrustLevel.UNTRUSTED,
213
+ metadata: { reason: 'hmac-verification-failure' },
214
+ });
215
+ }
216
+ }
217
+ getStatus() {
218
+ const peers = this.discovery.listPeers();
219
+ const trustLevels = {};
220
+ for (const peer of peers) {
221
+ trustLevels[peer.nodeId] = peer.trustLevel;
222
+ }
223
+ return {
224
+ nodeId: this.config.nodeId,
225
+ activeSessions: Array.from(this.sessions.values()).filter(s => s.active).length,
226
+ knownPeers: peers.length,
227
+ trustLevels,
228
+ healthy: this.initialized,
229
+ };
230
+ }
231
+ /**
232
+ * ADR-097 Phase 4: per-peer breaker state snapshot for the doctor
233
+ * surface and `federation_breaker_status` MCP tool.
234
+ *
235
+ * Returns one entry per known peer with the entity's stateRecord —
236
+ * what state, when it changed, why, and which caller's correlation
237
+ * key triggered it. Pure read; does not mutate.
238
+ */
239
+ getPeerStates() {
240
+ return this.discovery.listPeers().map((peer) => ({
241
+ nodeId: peer.nodeId,
242
+ ...peer.stateRecord,
243
+ }));
244
+ }
245
+ /**
246
+ * Aggregated counts for the doctor surface — `{ active: N, suspended: M,
247
+ * evicted: K }`. Cheap O(peers) sweep; safe to call from a status line.
248
+ */
249
+ getPeerStateCounts() {
250
+ let active = 0;
251
+ let suspended = 0;
252
+ let evicted = 0;
253
+ for (const peer of this.discovery.listPeers()) {
254
+ switch (peer.state) {
255
+ case FederationNodeState.ACTIVE:
256
+ active++;
257
+ break;
258
+ case FederationNodeState.SUSPENDED:
259
+ suspended++;
260
+ break;
261
+ case FederationNodeState.EVICTED:
262
+ evicted++;
263
+ break;
264
+ }
265
+ }
266
+ return { active, suspended, evicted };
267
+ }
268
+ /**
269
+ * Operator-initiated evict. Returns true on transition, false if the
270
+ * peer was already EVICTED or unknown. Logs to audit either way.
271
+ *
272
+ * Does NOT remove the peer from the discovery registry — `leavePeer`
273
+ * is the registry-removal API. Eviction is the breaker layer; the peer
274
+ * remains queryable so the operator can later reactivate.
275
+ */
276
+ async evictPeer(nodeId, reason = 'MANUAL_EVICT', correlationId) {
277
+ this.ensureInitialized();
278
+ const peer = this.discovery.getPeer(nodeId);
279
+ if (!peer)
280
+ return false;
281
+ const ok = peer.evict({ reason, correlationId });
282
+ await this.audit.log('threat_blocked', {
283
+ targetNodeId: nodeId,
284
+ metadata: {
285
+ reason,
286
+ correlationId: correlationId ?? null,
287
+ state: peer.state,
288
+ applied: ok,
289
+ },
290
+ });
291
+ if (ok) {
292
+ const session = this.findSessionByNodeId(nodeId);
293
+ if (session) {
294
+ session.terminate();
295
+ this.sessions.delete(session.sessionId);
296
+ }
297
+ }
298
+ return ok;
299
+ }
300
+ /**
301
+ * ADR-097 Phase 3 upstream: report the actual cost of a federated
302
+ * call. Federation doesn't own model pricing, so the integrator calls
303
+ * this after the downstream agent completes.
304
+ *
305
+ * Fans out to:
306
+ * - spendReporter (if injected) — persists to integrator's backend
307
+ * - breakerService.recordOutcome (if injected) — feeds the breaker's
308
+ * in-memory rolling buffer for cost/failure-ratio thresholds
309
+ *
310
+ * Both are no-ops if the corresponding integration isn't wired, so
311
+ * callers don't need to branch on configuration. Negative tokens/usd
312
+ * are clamped to 0 at the breaker layer (anti-credit-inflation); the
313
+ * spend reporter receives the raw values so backends can audit them.
314
+ *
315
+ * Auto-fills `ts` if the caller omits it.
316
+ */
317
+ async reportSpend(input) {
318
+ const event = {
319
+ peerId: input.peerId,
320
+ taskId: input.taskId,
321
+ tokensUsed: input.tokensUsed,
322
+ usdSpent: input.usdSpent,
323
+ success: input.success,
324
+ ts: input.ts ?? new Date().toISOString(),
325
+ };
326
+ // Fan out in parallel — neither side blocks the other. Reporter
327
+ // failures bubble up (integrator's responsibility); breaker is
328
+ // sync-internally so its branch is fire-and-forget safe.
329
+ const tasks = [];
330
+ if (this.spendReporter) {
331
+ tasks.push(this.spendReporter.reportSpend(event));
332
+ }
333
+ if (this.breakerService) {
334
+ this.breakerService.recordOutcome({
335
+ nodeId: event.peerId,
336
+ success: event.success,
337
+ tokensUsed: event.tokensUsed,
338
+ usdSpent: event.usdSpent,
339
+ at: new Date(event.ts),
340
+ });
341
+ }
342
+ if (tasks.length > 0)
343
+ await Promise.all(tasks);
344
+ }
345
+ /**
346
+ * Operator-initiated reactivate. Used after an integrator-supplied
347
+ * health probe confirms a SUSPENDED peer is healthy, OR as an
348
+ * operator-override escape from EVICTED. Returns true on transition.
349
+ */
350
+ async reactivatePeer(nodeId, correlationId) {
351
+ this.ensureInitialized();
352
+ const peer = this.discovery.getPeer(nodeId);
353
+ if (!peer)
354
+ return false;
355
+ const ok = peer.reactivate(correlationId);
356
+ await this.audit.log('trust_level_changed', {
357
+ targetNodeId: nodeId,
358
+ metadata: {
359
+ action: 'reactivate',
360
+ correlationId: correlationId ?? null,
361
+ state: peer.state,
362
+ applied: ok,
363
+ },
364
+ });
365
+ return ok;
366
+ }
367
+ getSession(sessionId) {
368
+ return this.sessions.get(sessionId);
369
+ }
370
+ getActiveSessions() {
371
+ return Array.from(this.sessions.values()).filter(s => s.active && !s.isExpired());
372
+ }
373
+ async establishSession(node) {
374
+ await this.audit.log('handshake_initiated', { targetNodeId: node.nodeId });
375
+ const challenge = await this.handshake.initiateHandshake(node);
376
+ const response = await this.handshake.respondToHandshake(challenge);
377
+ const result = await this.handshake.verifyChallenge(response, node);
378
+ if (!result.success || !result.session) {
379
+ await this.audit.log('handshake_failed', {
380
+ targetNodeId: node.nodeId,
381
+ metadata: { error: result.error },
382
+ });
383
+ throw new Error(`Handshake failed: ${result.error}`);
384
+ }
385
+ this.sessions.set(result.session.sessionId, result.session);
386
+ await this.audit.log('handshake_completed', {
387
+ targetNodeId: node.nodeId,
388
+ sessionId: result.session.sessionId,
389
+ trustLevel: result.session.trustLevel,
390
+ });
391
+ await this.audit.log('session_created', {
392
+ sessionId: result.session.sessionId,
393
+ targetNodeId: node.nodeId,
394
+ trustLevel: result.session.trustLevel,
395
+ });
396
+ return result.session;
397
+ }
398
+ findSessionByNodeId(nodeId) {
399
+ for (const session of this.sessions.values()) {
400
+ if (session.remoteNodeId === nodeId && session.active) {
401
+ return session;
402
+ }
403
+ }
404
+ return undefined;
405
+ }
406
+ ensureInitialized() {
407
+ if (!this.initialized) {
408
+ throw new Error('FederationCoordinator is not initialized. Call initialize() first.');
409
+ }
410
+ }
411
+ }
412
+ //# sourceMappingURL=federation-coordinator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"federation-coordinator.js","sourceRoot":"","sources":["../../src/application/federation-coordinator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Inbound message dispatcher (ADR-109).
3
+ *
4
+ * The federation plugin's `transport.listen()` accepts inbound bytes
5
+ * but until this module landed, the bytes had no consumer — they sat
6
+ * in the transport's per-address message queue with no one polling.
7
+ *
8
+ * `dispatchInbound()` is what the plugin registers as the
9
+ * transport.onMessage handler. For each received message it:
10
+ *
11
+ * 1. Resolves the sender via `sourceNodeId` in metadata
12
+ * 2. Verifies the peer is in the discovery registry (unknown → reject)
13
+ * 3. Verifies peer is ACTIVE (SUSPENDED/EVICTED → reject defense-in-depth)
14
+ * 4. Audits success or rejection
15
+ * 5. Emits a typed event on the eventBus for the integrator to handle
16
+ *
17
+ * Anti-coupling: dispatcher does NOT actually execute inbound tasks.
18
+ * That's the integrator's job. The dispatcher's contract is "deliver
19
+ * an envelope to the integrator's handler IFF it passes safety gates."
20
+ */
21
+ import type { AgentMessage } from 'agentic-flow/transport/loader';
22
+ import type { DiscoveryService } from '../domain/services/discovery-service.js';
23
+ import type { AuditService } from '../domain/services/audit-service.js';
24
+ /** What gets emitted on the event bus per messageType. */
25
+ export declare const FEDERATION_INBOUND_EVENT_PREFIX = "federation:inbound";
26
+ /** Reasons we reject an inbound message — constant strings, no oracle leak. */
27
+ export type InboundRejectionReason = 'PEER_UNKNOWN' | 'PEER_SUSPENDED' | 'PEER_EVICTED' | 'MISSING_METADATA' | 'INVALID_PAYLOAD';
28
+ /** Dispatch dependencies (kept narrow for testability). */
29
+ export interface InboundDispatchDeps {
30
+ readonly discovery: Pick<DiscoveryService, 'getPeer'>;
31
+ readonly audit: Pick<AuditService, 'log'>;
32
+ readonly eventBus: {
33
+ emit: (event: string, data: unknown) => void;
34
+ };
35
+ readonly logger: {
36
+ debug: (m: string) => void;
37
+ warn: (m: string) => void;
38
+ };
39
+ }
40
+ /** Outcome reported to the caller (mostly for tests + observability). */
41
+ export type InboundDispatchOutcome = {
42
+ readonly accepted: true;
43
+ readonly sourceNodeId: string;
44
+ readonly messageType: string;
45
+ } | {
46
+ readonly accepted: false;
47
+ readonly reason: InboundRejectionReason;
48
+ };
49
+ /**
50
+ * Process one received message. Pure-ish: no side effects beyond audit
51
+ * + event emission, both injected.
52
+ *
53
+ * `address` is the wire-level remote (e.g. `192.168.1.42:54321`).
54
+ * `message.metadata.sourceNodeId` is the cryptographic identity claim.
55
+ * The two MAY differ (e.g. behind NAT) — we trust `sourceNodeId` for
56
+ * peer lookup since it's bound to the Ed25519 keypair.
57
+ */
58
+ export declare function dispatchInbound(address: string, message: AgentMessage, deps: InboundDispatchDeps): Promise<InboundDispatchOutcome>;
59
+ //# sourceMappingURL=inbound-dispatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbound-dispatcher.d.ts","sourceRoot":"","sources":["../../src/application/inbound-dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAChF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AAGxE,0DAA0D;AAC1D,eAAO,MAAM,+BAA+B,uBAAuB,CAAC;AAEpE,+EAA+E;AAC/E,MAAM,MAAM,sBAAsB,GAC9B,cAAc,GACd,gBAAgB,GAChB,cAAc,GACd,kBAAkB,GAClB,iBAAiB,CAAC;AAEtB,2DAA2D;AAC3D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;IACtD,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE;QAAE,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;KAAE,CAAC;IACpE,QAAQ,CAAC,MAAM,EAAE;QACf,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;QAC3B,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;KAC3B,CAAC;CACH;AAED,yEAAyE;AACzE,MAAM,MAAM,sBAAsB,GAC9B;IAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACxF;IAAE,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,CAAC;AAE1E;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,YAAY,EACrB,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,sBAAsB,CAAC,CAuEjC"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Inbound message dispatcher (ADR-109).
3
+ *
4
+ * The federation plugin's `transport.listen()` accepts inbound bytes
5
+ * but until this module landed, the bytes had no consumer — they sat
6
+ * in the transport's per-address message queue with no one polling.
7
+ *
8
+ * `dispatchInbound()` is what the plugin registers as the
9
+ * transport.onMessage handler. For each received message it:
10
+ *
11
+ * 1. Resolves the sender via `sourceNodeId` in metadata
12
+ * 2. Verifies the peer is in the discovery registry (unknown → reject)
13
+ * 3. Verifies peer is ACTIVE (SUSPENDED/EVICTED → reject defense-in-depth)
14
+ * 4. Audits success or rejection
15
+ * 5. Emits a typed event on the eventBus for the integrator to handle
16
+ *
17
+ * Anti-coupling: dispatcher does NOT actually execute inbound tasks.
18
+ * That's the integrator's job. The dispatcher's contract is "deliver
19
+ * an envelope to the integrator's handler IFF it passes safety gates."
20
+ */
21
+ import { FederationNodeState } from '../domain/value-objects/federation-node-state.js';
22
+ /** What gets emitted on the event bus per messageType. */
23
+ export const FEDERATION_INBOUND_EVENT_PREFIX = 'federation:inbound';
24
+ /**
25
+ * Process one received message. Pure-ish: no side effects beyond audit
26
+ * + event emission, both injected.
27
+ *
28
+ * `address` is the wire-level remote (e.g. `192.168.1.42:54321`).
29
+ * `message.metadata.sourceNodeId` is the cryptographic identity claim.
30
+ * The two MAY differ (e.g. behind NAT) — we trust `sourceNodeId` for
31
+ * peer lookup since it's bound to the Ed25519 keypair.
32
+ */
33
+ export async function dispatchInbound(address, message, deps) {
34
+ const meta = (message.metadata ?? {});
35
+ const sourceNodeId = typeof meta.sourceNodeId === 'string' ? meta.sourceNodeId : null;
36
+ if (!sourceNodeId) {
37
+ await deps.audit.log('message_rejected', {
38
+ sourceNodeId: undefined,
39
+ metadata: { address, reason: 'MISSING_METADATA' },
40
+ });
41
+ deps.logger.warn(`Inbound rejected: no sourceNodeId in metadata (from ${address})`);
42
+ return { accepted: false, reason: 'MISSING_METADATA' };
43
+ }
44
+ const peer = deps.discovery.getPeer(sourceNodeId);
45
+ if (!peer) {
46
+ await deps.audit.log('message_rejected', {
47
+ sourceNodeId,
48
+ metadata: { address, reason: 'PEER_UNKNOWN' },
49
+ });
50
+ deps.logger.warn(`Inbound rejected: ${sourceNodeId} not in discovery (from ${address})`);
51
+ return { accepted: false, reason: 'PEER_UNKNOWN' };
52
+ }
53
+ if (peer.state === FederationNodeState.SUSPENDED) {
54
+ await deps.audit.log('message_rejected', {
55
+ sourceNodeId,
56
+ metadata: { address, reason: 'PEER_SUSPENDED' },
57
+ });
58
+ return { accepted: false, reason: 'PEER_SUSPENDED' };
59
+ }
60
+ if (peer.state === FederationNodeState.EVICTED) {
61
+ await deps.audit.log('message_rejected', {
62
+ sourceNodeId,
63
+ metadata: { address, reason: 'PEER_EVICTED' },
64
+ });
65
+ return { accepted: false, reason: 'PEER_EVICTED' };
66
+ }
67
+ // Touch lastSeen on every successful inbound — drives the
68
+ // discovery service's stale-peer detection.
69
+ peer.markSeen();
70
+ // Audit accepted delivery
71
+ await deps.audit.log('message_received', {
72
+ sourceNodeId,
73
+ metadata: {
74
+ address,
75
+ messageType: message.type,
76
+ messageId: message.id,
77
+ },
78
+ });
79
+ // Emit typed event for the integrator
80
+ // Examples: federation:inbound:task, federation:inbound:memory-query
81
+ const eventName = `${FEDERATION_INBOUND_EVENT_PREFIX}:${message.type}`;
82
+ try {
83
+ deps.eventBus.emit(eventName, {
84
+ address,
85
+ sourceNodeId,
86
+ message,
87
+ peer,
88
+ });
89
+ }
90
+ catch (err) {
91
+ // EventBus throw should not crash the receive loop.
92
+ deps.logger.warn(`EventBus emit failed for ${eventName}: ${err instanceof Error ? err.message : err}`);
93
+ }
94
+ return { accepted: true, sourceNodeId, messageType: message.type };
95
+ }
96
+ //# sourceMappingURL=inbound-dispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbound-dispatcher.js","sourceRoot":"","sources":["../../src/application/inbound-dispatcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { TrustLevel } from '../domain/entities/trust-level.js';
2
+ import { type PIIAction, type PIIDetection, type PIIPolicyConfig } from '../domain/services/pii-pipeline-service.js';
3
+ import { type FederationMessageType } from '../domain/entities/federation-envelope.js';
4
+ export type FederationClaimType = 'federation:discover' | 'federation:connect' | 'federation:read' | 'federation:write' | 'federation:admin' | 'federation:memory' | 'federation:spawn';
5
+ export interface SecurityPolicy {
6
+ readonly maxMessageSizeBytes: number;
7
+ readonly maxMessagesPerMinute: number;
8
+ readonly allowedMessageTypes: readonly FederationMessageType[];
9
+ readonly requirePiiScan: boolean;
10
+ readonly requireAiDefenceScan: boolean;
11
+ readonly minTrustLevelForWrite: TrustLevel;
12
+ readonly minTrustLevelForMemory: TrustLevel;
13
+ readonly minTrustLevelForSpawn: TrustLevel;
14
+ }
15
+ export interface PolicyEvaluationResult {
16
+ readonly allowed: boolean;
17
+ readonly reason: string;
18
+ readonly requiredClaims: readonly FederationClaimType[];
19
+ readonly trustLevelSufficient: boolean;
20
+ readonly piiAction?: PIIAction;
21
+ }
22
+ export interface PolicyEngineDeps {
23
+ checkClaim: (claim: FederationClaimType) => boolean;
24
+ }
25
+ export declare class PolicyEngine {
26
+ private readonly deps;
27
+ private readonly securityPolicy;
28
+ private readonly piiPolicy;
29
+ private readonly rateLimitCounters;
30
+ constructor(deps: PolicyEngineDeps, securityPolicy?: Partial<SecurityPolicy>, piiPolicy?: PIIPolicyConfig);
31
+ evaluateMessage(messageType: FederationMessageType, trustLevel: TrustLevel, messageSizeBytes: number, sourceNodeId: string): PolicyEvaluationResult;
32
+ evaluatePiiDetection(detection: PIIDetection, trustLevel: TrustLevel): PIIAction;
33
+ evaluateTrustChange(currentLevel: TrustLevel, proposedLevel: TrustLevel): {
34
+ allowed: boolean;
35
+ requiresHumanApproval: boolean;
36
+ reason: string;
37
+ };
38
+ private checkRateLimit;
39
+ private getOperationForMessageType;
40
+ }
41
+ //# sourceMappingURL=policy-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-engine.d.ts","sourceRoot":"","sources":["../../src/application/policy-engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,mCAAmC,CAAC;AACnF,OAAO,EAAE,KAAK,SAAS,EAAgB,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,MAAM,4CAA4C,CAAC;AACnI,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,2CAA2C,CAAC;AAEvF,MAAM,MAAM,mBAAmB,GAC3B,qBAAqB,GACrB,oBAAoB,GACpB,iBAAiB,GACjB,kBAAkB,GAClB,kBAAkB,GAClB,mBAAmB,GACnB,kBAAkB,CAAC;AAEvB,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,mBAAmB,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC/D,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC;IACvC,QAAQ,CAAC,qBAAqB,EAAE,UAAU,CAAC;IAC3C,QAAQ,CAAC,sBAAsB,EAAE,UAAU,CAAC;IAC5C,QAAQ,CAAC,qBAAqB,EAAE,UAAU,CAAC;CAC5C;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACxD,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC;IACvC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;CAChC;AA4CD,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC;CACrD;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmB;IACxC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkB;IAC5C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAsD;gBAGtF,IAAI,EAAE,gBAAgB,EACtB,cAAc,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,EACxC,SAAS,CAAC,EAAE,eAAe;IAc7B,eAAe,CACb,WAAW,EAAE,qBAAqB,EAClC,UAAU,EAAE,UAAU,EACtB,gBAAgB,EAAE,MAAM,EACxB,YAAY,EAAE,MAAM,GACnB,sBAAsB;IAyDzB,oBAAoB,CAAC,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,GAAG,SAAS;IAWhF,mBAAmB,CACjB,YAAY,EAAE,UAAU,EACxB,aAAa,EAAE,UAAU,GACxB;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,qBAAqB,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;IAgCvE,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,0BAA0B;CAyBnC"}