@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.
- package/README.md +45 -0
- package/dist/application/federation-breaker-service.d.ts +182 -0
- package/dist/application/federation-breaker-service.d.ts.map +1 -0
- package/dist/application/federation-breaker-service.js +251 -0
- package/dist/application/federation-breaker-service.js.map +1 -0
- package/dist/application/federation-coordinator.d.ts +166 -0
- package/dist/application/federation-coordinator.d.ts.map +1 -0
- package/dist/application/federation-coordinator.js +412 -0
- package/dist/application/federation-coordinator.js.map +1 -0
- package/dist/application/inbound-dispatcher.d.ts +59 -0
- package/dist/application/inbound-dispatcher.d.ts.map +1 -0
- package/dist/application/inbound-dispatcher.js +96 -0
- package/dist/application/inbound-dispatcher.js.map +1 -0
- package/dist/application/policy-engine.d.ts +41 -0
- package/dist/application/policy-engine.d.ts.map +1 -0
- package/dist/application/policy-engine.js +184 -0
- package/dist/application/policy-engine.js.map +1 -0
- package/dist/application/spend-reporter.d.ts +150 -0
- package/dist/application/spend-reporter.d.ts.map +1 -0
- package/dist/application/spend-reporter.js +128 -0
- package/dist/application/spend-reporter.js.map +1 -0
- package/dist/application/trust-evaluator.d.ts +42 -0
- package/dist/application/trust-evaluator.d.ts.map +1 -0
- package/dist/application/trust-evaluator.js +132 -0
- package/dist/application/trust-evaluator.js.map +1 -0
- package/dist/bin.d.ts +13 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +189 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli-commands.d.ts +7 -0
- package/dist/cli-commands.d.ts.map +1 -0
- package/dist/cli-commands.js +198 -0
- package/dist/cli-commands.js.map +1 -0
- package/dist/domain/entities/federation-envelope.d.ts +45 -0
- package/dist/domain/entities/federation-envelope.d.ts.map +1 -0
- package/dist/domain/entities/federation-envelope.js +71 -0
- package/dist/domain/entities/federation-envelope.js.map +1 -0
- package/dist/domain/entities/federation-node.d.ts +104 -0
- package/dist/domain/entities/federation-node.d.ts.map +1 -0
- package/dist/domain/entities/federation-node.js +152 -0
- package/dist/domain/entities/federation-node.js.map +1 -0
- package/dist/domain/entities/federation-session.d.ts +55 -0
- package/dist/domain/entities/federation-session.d.ts.map +1 -0
- package/dist/domain/entities/federation-session.js +105 -0
- package/dist/domain/entities/federation-session.js.map +1 -0
- package/dist/domain/entities/trust-level.d.ts +17 -0
- package/dist/domain/entities/trust-level.d.ts.map +1 -0
- package/dist/domain/entities/trust-level.js +35 -0
- package/dist/domain/entities/trust-level.js.map +1 -0
- package/dist/domain/services/audit-service.d.ts +69 -0
- package/dist/domain/services/audit-service.d.ts.map +1 -0
- package/dist/domain/services/audit-service.js +149 -0
- package/dist/domain/services/audit-service.js.map +1 -0
- package/dist/domain/services/discovery-service.d.ts +51 -0
- package/dist/domain/services/discovery-service.d.ts.map +1 -0
- package/dist/domain/services/discovery-service.js +140 -0
- package/dist/domain/services/discovery-service.js.map +1 -0
- package/dist/domain/services/handshake-service.d.ts +48 -0
- package/dist/domain/services/handshake-service.d.ts.map +1 -0
- package/dist/domain/services/handshake-service.js +94 -0
- package/dist/domain/services/handshake-service.js.map +1 -0
- package/dist/domain/services/pii-pipeline-service.d.ts +65 -0
- package/dist/domain/services/pii-pipeline-service.d.ts.map +1 -0
- package/dist/domain/services/pii-pipeline-service.js +208 -0
- package/dist/domain/services/pii-pipeline-service.js.map +1 -0
- package/dist/domain/services/routing-service.d.ts +51 -0
- package/dist/domain/services/routing-service.d.ts.map +1 -0
- package/dist/domain/services/routing-service.js +147 -0
- package/dist/domain/services/routing-service.js.map +1 -0
- package/dist/domain/value-objects/federation-budget.d.ts +89 -0
- package/dist/domain/value-objects/federation-budget.d.ts.map +1 -0
- package/dist/domain/value-objects/federation-budget.js +165 -0
- package/dist/domain/value-objects/federation-budget.js.map +1 -0
- package/dist/domain/value-objects/federation-node-state.d.ts +92 -0
- package/dist/domain/value-objects/federation-node-state.d.ts.map +1 -0
- package/dist/domain/value-objects/federation-node-state.js +100 -0
- package/dist/domain/value-objects/federation-node-state.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-tools.d.ts +8 -0
- package/dist/mcp-tools.d.ts.map +1 -0
- package/dist/mcp-tools.js +343 -0
- package/dist/mcp-tools.js.map +1 -0
- package/dist/plugin.d.ts +18 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +376 -0
- package/dist/plugin.js.map +1 -0
- 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"}
|