@muxoai/sdk 1.3.0 → 1.4.3

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 (76) hide show
  1. package/.agents/plugins/marketplace.json +2 -2
  2. package/.claude-plugin/marketplace.json +19 -4
  3. package/.codex/config.toml +9 -2
  4. package/ARCHITECTURE.md +16 -6
  5. package/README.md +69 -24
  6. package/dist/clerk.d.ts +35 -0
  7. package/dist/clerk.js +201 -0
  8. package/dist/cli.js +1677 -103
  9. package/dist/composio-catalog.d.ts +234 -0
  10. package/dist/composio-catalog.js +1894 -0
  11. package/dist/config.d.ts +16 -0
  12. package/dist/config.js +27 -1
  13. package/dist/durable-workflow.d.ts +112 -0
  14. package/dist/durable-workflow.js +284 -0
  15. package/dist/engine.d.ts +377 -6
  16. package/dist/engine.js +1919 -94
  17. package/dist/index.d.ts +3 -0
  18. package/dist/index.js +3 -0
  19. package/dist/mcp-schema.d.ts +286 -0
  20. package/dist/mcp-schema.js +2580 -0
  21. package/dist/mcp.d.ts +2 -25
  22. package/dist/mcp.js +1008 -507
  23. package/dist/memory-graph.d.ts +45 -0
  24. package/dist/memory-graph.js +293 -0
  25. package/dist/nl.js +214 -35
  26. package/dist/oauth.d.ts +32 -0
  27. package/dist/oauth.js +134 -0
  28. package/dist/oss-suite.d.ts +217 -0
  29. package/dist/oss-suite.js +836 -0
  30. package/dist/policy.d.ts +190 -0
  31. package/dist/policy.js +1597 -0
  32. package/dist/providers/composio-instant.d.ts +4 -0
  33. package/dist/providers/composio-instant.js +890 -535
  34. package/dist/providers/composio-sdk.d.ts +126 -5
  35. package/dist/providers/composio-sdk.js +902 -79
  36. package/dist/providers/microsoft-governance.d.ts +89 -3
  37. package/dist/providers/microsoft-governance.js +673 -26
  38. package/dist/providers/stripe-billing.d.ts +42 -0
  39. package/dist/providers/stripe-billing.js +244 -5
  40. package/dist/providers/stripe-projects.d.ts +459 -4
  41. package/dist/providers/stripe-projects.js +2674 -122
  42. package/dist/providers/supermemory.d.ts +102 -6
  43. package/dist/providers/supermemory.js +609 -55
  44. package/dist/provisioning-managed.d.ts +50 -0
  45. package/dist/provisioning-managed.js +155 -0
  46. package/dist/sdk.d.ts +728 -7
  47. package/dist/sdk.js +539 -10
  48. package/dist/server.js +2744 -321
  49. package/dist/store.d.ts +138 -6
  50. package/dist/store.js +932 -58
  51. package/dist/types.d.ts +330 -4
  52. package/dist/ui/console-html.d.ts +62 -0
  53. package/dist/ui/console-html.js +3742 -2228
  54. package/dist/ui/design-tokens.d.ts +177 -0
  55. package/dist/ui/design-tokens.js +210 -0
  56. package/dist/version.d.ts +1 -0
  57. package/dist/version.js +1 -0
  58. package/package.json +6 -5
  59. package/plugins/muxo/.app.json +1 -1
  60. package/plugins/muxo/.claude-plugin/plugin.json +3 -3
  61. package/plugins/muxo/.codex-plugin/plugin.json +19 -10
  62. package/plugins/muxo/.cursor-plugin/plugin.json +30 -0
  63. package/plugins/muxo/.mcp.json +1 -33
  64. package/plugins/muxo/assets/logo.png +0 -0
  65. package/plugins/muxo/hooks/session-start.sh +16 -4
  66. package/plugins/muxo/hooks/user-prompt-submit.sh +14 -1
  67. package/plugins/muxo/mcp.json +0 -10
  68. package/plugins/muxo/plugin.json +65 -8
  69. package/plugins/muxo/skills/muxo/SKILL.md +142 -14
  70. package/plugins/muxo/skills/muxo/agents/openai.yaml +12 -0
  71. package/plugins/muxo/skills/muxo/references/cli.md +9 -3
  72. package/plugins/muxo/skills/muxo/references/mcp.md +22 -10
  73. package/plugins/muxo/skills/muxo-activity-summary/SKILL.md +81 -0
  74. package/plugins/muxo/skills/setup/SKILL.md +17 -3
  75. package/plugins/muxo/skills/setup/agents/openai.yaml +12 -0
  76. package/src/catalogues/stripe-projects-catalog.json +140 -0
@@ -1,7 +1,29 @@
1
1
  import crypto from "node:crypto";
2
- import { AgentIdentity, AuditLogger, McpSecurityScanner, PolicyEngine, } from "../../vendor/microsoft-governance/dist/index.js";
2
+ import { AgentIdentity, AuditLogger, ContextPoisoningDetector, ExecutionRing, FacetRegistry, KillSwitch, McpSecurityScanner, PolicyEngine, RingEnforcer, TrustManager, extractK8sFacets, extractProtocolFacets, extractSqlFacets, } from "../../vendor/microsoft-governance/dist/index.js";
3
+ import { describePolicyInPlainEnglish, evaluateParameterPolicyRules, formatHumanFriendlyExplanation, } from "../policy.js";
3
4
  const SDK_VERSION = "5.0.0";
4
5
  const POLICY_ID = "muxo-microsoft-agent-governance-v5";
6
+ export const RING_LABELS = {
7
+ [ExecutionRing.Ring0]: "Ring 0 (Kernel / Destructive & Root Boundary)",
8
+ [ExecutionRing.Ring1]: "Ring 1 (Supervisor / Provisioning, Financial & Admin)",
9
+ [ExecutionRing.Ring2]: "Ring 2 (Standard Agent / Governed Write)",
10
+ [ExecutionRing.Ring3]: "Ring 3 (Unprivileged Sandbox / Read-Only)",
11
+ };
12
+ function requiredRingForRisk(riskLevel) {
13
+ switch (riskLevel) {
14
+ case "destructive":
15
+ return ExecutionRing.Ring0;
16
+ case "admin":
17
+ case "financial":
18
+ case "provisioning":
19
+ return ExecutionRing.Ring1;
20
+ case "write":
21
+ return ExecutionRing.Ring2;
22
+ case "read":
23
+ default:
24
+ return ExecutionRing.Ring3;
25
+ }
26
+ }
5
27
  // PKCS#8 DER prefix for a 32-byte Ed25519 private key seed (OID 1.3.101.112)
6
28
  const ED25519_PKCS8_PREFIX = Buffer.from([
7
29
  0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70,
@@ -39,12 +61,41 @@ function deriveDeterministicIdentity(seedMaterial, agentId, capabilities, opts)
39
61
  }
40
62
  export class MicrosoftGovernanceAdapter {
41
63
  scanner;
64
+ contextPoisoningDetector;
65
+ facetRegistry;
66
+ trustManager;
67
+ killSwitch;
68
+ activeKillSwitches = new Map();
42
69
  seedMaterial;
43
70
  auditLoggers = new Map();
44
71
  identities = new Map();
45
72
  defaultIdentity;
46
73
  constructor(seed) {
47
74
  this.scanner = new McpSecurityScanner();
75
+ this.contextPoisoningDetector = new ContextPoisoningDetector({
76
+ maxContextSizeBytes: 100_000,
77
+ maxEntriesPerSession: 250,
78
+ entropyThreshold: 5.5,
79
+ similarityThreshold: 0.92,
80
+ enableIsolation: true,
81
+ });
82
+ this.facetRegistry = new FacetRegistry();
83
+ this.facetRegistry.register("sql", extractSqlFacets);
84
+ this.facetRegistry.register("k8s", extractK8sFacets);
85
+ this.facetRegistry.register("infra", (sub) => ({
86
+ provider: String(sub.provider ?? "").toLowerCase(),
87
+ service: String(sub.service ?? "").toLowerCase(),
88
+ action: String(sub.action ?? "read").toLowerCase(),
89
+ destructive: Boolean(sub.destructive),
90
+ }));
91
+ this.trustManager = new TrustManager({
92
+ initialScore: 0.75,
93
+ decayFactor: 0.98,
94
+ });
95
+ this.killSwitch = new KillSwitch({
96
+ enabled: true,
97
+ defaultSubstituteAgentId: "muxo-safe-mode-guardian",
98
+ });
48
99
  this.seedMaterial = Buffer.isBuffer(seed)
49
100
  ? seed
50
101
  : Buffer.from(String(seed ||
@@ -94,12 +145,273 @@ export class MicrosoftGovernanceAdapter {
94
145
  }
95
146
  return logger;
96
147
  }
148
+ /**
149
+ * Scans memory or prompt context for OWASP ASI-06 Context Poisoning (prompt injection,
150
+ * roleplay overrides, delimiter injection, high-entropy exfiltration payloads, and session isolation).
151
+ */
152
+ scanMemoryContent(params) {
153
+ const safeAgentKey = params.workspaceId.replace(/[^a-zA-Z0-9_-]/g, "_");
154
+ const safeSessionKey = (params.sessionId || "default").replace(/[^a-zA-Z0-9_-]/g, "_");
155
+ const entryId = params.entryId || `mem_${crypto.randomBytes(6).toString("hex")}`;
156
+ const entry = {
157
+ id: entryId,
158
+ entryId,
159
+ agentId: safeAgentKey,
160
+ sessionId: safeSessionKey,
161
+ role: params.role || "user",
162
+ content: String(params.content || ""),
163
+ timestamp: new Date().toISOString(),
164
+ };
165
+ const findings = this.contextPoisoningDetector.scanEntry(entry);
166
+ // Augment with credential/secret exfiltration detection in memory content
167
+ if (/(cat|curl|wget)\s+.*(\/etc\/passwd|\.env|id_rsa|AWS_SECRET_ACCESS_KEY)/i.test(entry.content) ||
168
+ /send\s+(all\s+)?(api\s+keys|secrets|tokens|credentials)\s+to\s+https?:\/\//i.test(entry.content)) {
169
+ findings.push({
170
+ entryId: entry.id,
171
+ patternId: "MEMORY_EXFILTRATION_DIRECTIVE",
172
+ patternName: "Persistent Memory Credential Exfiltration Directive",
173
+ severity: "critical",
174
+ description: "Memory payload attempts to persist credential or file exfiltration instructions across agent runs",
175
+ matchedText: entry.content.slice(0, 100),
176
+ timestamp: Date.now(),
177
+ });
178
+ }
179
+ const hasCritical = findings.some((f) => f.severity === "critical");
180
+ const hasHigh = findings.some((f) => f.severity === "high");
181
+ const hasMedium = findings.some((f) => f.severity === "medium");
182
+ const riskLevel = hasCritical
183
+ ? "critical"
184
+ : hasHigh
185
+ ? "high"
186
+ : hasMedium
187
+ ? "medium"
188
+ : findings.length > 0
189
+ ? "low"
190
+ : "none";
191
+ const safe = !hasCritical && !hasHigh;
192
+ if (params.recordInDetector !== false && safe) {
193
+ try {
194
+ this.contextPoisoningDetector.addEntry(entry);
195
+ }
196
+ catch {
197
+ // Ignore session capacity overflow in long-running processes
198
+ }
199
+ }
200
+ const integrity = this.contextPoisoningDetector.verifyIntegrity(safeAgentKey, safeSessionKey);
201
+ const integrityValid = typeof integrity === "boolean" ? integrity : Boolean(integrity?.valid ?? true);
202
+ return {
203
+ safe,
204
+ riskLevel,
205
+ findingsCount: findings.length,
206
+ findings: findings.map((f) => ({
207
+ patternId: String(f.patternId || ""),
208
+ patternName: String(f.patternName || ""),
209
+ severity: String(f.severity || ""),
210
+ description: String(f.description || ""),
211
+ })),
212
+ integrityValid,
213
+ };
214
+ }
215
+ getContextPoisoningReport(workspaceId, sessionId = "default") {
216
+ const safeAgentKey = workspaceId.replace(/[^a-zA-Z0-9_-]/g, "_");
217
+ const safeSessionKey = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
218
+ return this.contextPoisoningDetector.scan(safeAgentKey, safeSessionKey);
219
+ }
220
+ /**
221
+ * Extracts structured SQL, Kubernetes, and Infrastructure protocol facets from tool input.
222
+ */
223
+ extractActionFacets(tool, input) {
224
+ const rawContext = {};
225
+ // Detect SQL payload in input
226
+ const candidateSql = typeof input.sql === "string"
227
+ ? input.sql
228
+ : typeof input.statement === "string"
229
+ ? input.statement
230
+ : typeof input.query === "string" &&
231
+ (tool.slug.includes("sql") ||
232
+ tool.slug.includes("postgres") ||
233
+ tool.slug.includes("neon") ||
234
+ tool.slug.includes("turso") ||
235
+ tool.slug.includes("supabase") ||
236
+ tool.slug.includes("db") ||
237
+ /^\s*(SELECT|INSERT|UPDATE|DELETE|DROP|TRUNCATE|ALTER|CREATE|WITH)\b/i.test(input.query))
238
+ ? input.query
239
+ : null;
240
+ if (candidateSql) {
241
+ rawContext.sql = { query: candidateSql };
242
+ }
243
+ // Detect Kubernetes payload in input
244
+ const candidateK8sPath = typeof input.k8s_path === "string"
245
+ ? input.k8s_path
246
+ : typeof input.path === "string" &&
247
+ (input.path.startsWith("/api/v1/") ||
248
+ input.path.startsWith("/apis/"))
249
+ ? input.path
250
+ : null;
251
+ if (candidateK8sPath) {
252
+ rawContext.k8s = {
253
+ method: typeof input.method === "string" ? input.method : "GET",
254
+ path: candidateK8sPath,
255
+ };
256
+ }
257
+ else if (input.k8s &&
258
+ typeof input.k8s === "object" &&
259
+ !Array.isArray(input.k8s)) {
260
+ rawContext.k8s = input.k8s;
261
+ }
262
+ // Detect Infrastructure / Resource provisioning facets
263
+ if (tool.lane === "stripe_projects" ||
264
+ tool.slug.startsWith("resource.") ||
265
+ tool.riskLevel === "provisioning" ||
266
+ tool.riskLevel === "destructive") {
267
+ rawContext.infra = {
268
+ provider: tool.providerSlug,
269
+ service: tool.upstreamSlug,
270
+ action: tool.riskLevel,
271
+ destructive: tool.riskLevel === "destructive" ||
272
+ tool.slug.includes("delete") ||
273
+ tool.slug.includes("destroy"),
274
+ };
275
+ }
276
+ const extracted = extractProtocolFacets(rawContext, this.facetRegistry);
277
+ const result = {};
278
+ if (extracted.sql) {
279
+ const sqlVerb = String(extracted.sql.verb || "UNKNOWN").toUpperCase();
280
+ const isDestructiveSql = sqlVerb === "DROP" ||
281
+ sqlVerb === "TRUNCATE" ||
282
+ (sqlVerb === "UNKNOWN" && Boolean(candidateSql?.includes(";"))) ||
283
+ (sqlVerb === "DELETE" &&
284
+ Boolean(candidateSql) &&
285
+ !/\bWHERE\b/i.test(candidateSql || ""));
286
+ result.sql = {
287
+ verb: sqlVerb,
288
+ target: String(extracted.sql.target || ""),
289
+ tables: String(extracted.sql.tables || ""),
290
+ functions: String(extracted.sql.functions || ""),
291
+ destructive: isDestructiveSql,
292
+ };
293
+ }
294
+ if (extracted.k8s) {
295
+ result.k8s = {
296
+ verb: String(extracted.k8s.verb || ""),
297
+ resource: String(extracted.k8s.resource || ""),
298
+ namespace: String(extracted.k8s.namespace || ""),
299
+ name: String(extracted.k8s.name || ""),
300
+ subresource: String(extracted.k8s.subresource || ""),
301
+ };
302
+ }
303
+ if (extracted.infra) {
304
+ result.infra = {
305
+ provider: String(extracted.infra.provider || tool.providerSlug),
306
+ service: String(extracted.infra.service || tool.upstreamSlug),
307
+ action: String(extracted.infra.action || tool.riskLevel),
308
+ destructive: Boolean(extracted.infra.destructive),
309
+ };
310
+ }
311
+ return result;
312
+ }
313
+ /**
314
+ * Evaluates hardware-style privilege rings (Ring 0..Ring 3) via Microsoft RingEnforcer.
315
+ */
316
+ evaluateRingEnforcement(workspace, tool, ownerApproved) {
317
+ const requiredRing = requiredRingForRisk(tool.riskLevel);
318
+ const policy = workspace.policy;
319
+ const requiresApproval = policy.mode === "enforce" &&
320
+ (policy.requireApprovalFor || []).includes(tool.riskLevel);
321
+ const agentRing = ownerApproved
322
+ ? ExecutionRing.Ring0
323
+ : policy.executionRing !== undefined
324
+ ? policy.executionRing
325
+ : requiresApproval
326
+ ? ExecutionRing.Ring2
327
+ : requiredRing;
328
+ const enforcer = new RingEnforcer({
329
+ agentRing,
330
+ defaultRing: ExecutionRing.Ring3,
331
+ actionRings: {
332
+ "read:*": ExecutionRing.Ring3,
333
+ "write:*": ExecutionRing.Ring2,
334
+ "admin:*": ExecutionRing.Ring1,
335
+ "financial:*": ExecutionRing.Ring1,
336
+ "provisioning:*": ExecutionRing.Ring1,
337
+ "destructive:*": ExecutionRing.Ring0,
338
+ },
339
+ });
340
+ const actionKey = `${tool.riskLevel}:${tool.slug}`;
341
+ const allowed = enforcer.canExecute(actionKey);
342
+ return {
343
+ agentRing,
344
+ requiredRing,
345
+ allowed,
346
+ ringLabel: RING_LABELS[requiredRing] || `Ring ${requiredRing}`,
347
+ };
348
+ }
349
+ /**
350
+ * Records an agent execution outcome in the Bayesian TrustManager and returns the updated TrustScore.
351
+ */
352
+ recordAgentOutcome(workspaceId, succeeded, weight = 0.05) {
353
+ if (succeeded) {
354
+ this.trustManager.recordSuccess(workspaceId, weight);
355
+ }
356
+ else {
357
+ this.trustManager.recordFailure(workspaceId, weight * 2);
358
+ }
359
+ return this.trustManager.getTrustScore(workspaceId);
360
+ }
361
+ /**
362
+ * Returns the current Bayesian TrustScore for a workspace agent boundary.
363
+ */
364
+ getWorkspaceTrustScore(workspaceId) {
365
+ const score = this.trustManager.getTrustScore(workspaceId);
366
+ return {
367
+ overall: Number(score.overall.toFixed(4)),
368
+ tier: score.tier,
369
+ reliability: Number(score.dimensions.reliability.toFixed(4)),
370
+ consistency: Number(score.dimensions.consistency.toFixed(4)),
371
+ };
372
+ }
373
+ /**
374
+ * Activates the emergency KillSwitch for a workspace agent boundary.
375
+ */
376
+ async activateKillSwitch(workspaceId, reason, action = "quarantine") {
377
+ const result = await this.killSwitch.kill(workspaceId, {
378
+ action,
379
+ reason: reason || "Emergency kill-switch activated by workspace operator",
380
+ });
381
+ this.activeKillSwitches.set(workspaceId, result);
382
+ this.trustManager.recordFailure(workspaceId, 0.25);
383
+ return result;
384
+ }
385
+ /**
386
+ * Resumes a workspace agent boundary after a KillSwitch quarantine/suspension.
387
+ */
388
+ resumeKillSwitch(workspaceId) {
389
+ const existed = this.activeKillSwitches.delete(workspaceId);
390
+ return {
391
+ resumed: existed,
392
+ workspaceId,
393
+ resumedAt: new Date().toISOString(),
394
+ };
395
+ }
396
+ isKillSwitchActive(workspaceId) {
397
+ return this.activeKillSwitches.get(workspaceId) || null;
398
+ }
97
399
  /**
98
400
  * Compiles the workspace's GovernancePolicy into a declarative Microsoft PolicyEngine instance.
99
401
  */
100
402
  createPolicyEngine(policy) {
101
403
  const engine = new PolicyEngine();
102
404
  const rules = [];
405
+ if (policy.killSwitchActive) {
406
+ rules.push({
407
+ name: "deny-kill-switch-active",
408
+ ruleAction: "deny",
409
+ priority: 200,
410
+ condition: {
411
+ workspace_active: true,
412
+ },
413
+ });
414
+ }
103
415
  for (const blockedSlug of policy.blockedToolSlugs || []) {
104
416
  const normalized = blockedSlug.trim();
105
417
  if (!normalized)
@@ -113,6 +425,44 @@ export class MicrosoftGovernanceAdapter {
113
425
  },
114
426
  });
115
427
  }
428
+ if (policy.mode === "enforce" && policy.blockDestructiveSql !== false) {
429
+ rules.push({
430
+ name: "deny-multi-statement-sql-injection",
431
+ ruleAction: "deny",
432
+ priority: 96,
433
+ condition: {
434
+ "sql.verb": "UNKNOWN",
435
+ "sql.destructive": true,
436
+ },
437
+ });
438
+ rules.push({
439
+ name: "require-approval-destructive-sql-drop",
440
+ ruleAction: "require_approval",
441
+ priority: 94,
442
+ condition: {
443
+ "sql.verb": "DROP",
444
+ owner_approved: false,
445
+ },
446
+ });
447
+ rules.push({
448
+ name: "require-approval-destructive-sql-truncate",
449
+ ruleAction: "require_approval",
450
+ priority: 94,
451
+ condition: {
452
+ "sql.verb": "TRUNCATE",
453
+ owner_approved: false,
454
+ },
455
+ });
456
+ rules.push({
457
+ name: "deny-k8s-delete-kube-system",
458
+ ruleAction: "deny",
459
+ priority: 95,
460
+ condition: {
461
+ "k8s.verb": "delete",
462
+ "k8s.namespace": "kube-system",
463
+ },
464
+ });
465
+ }
116
466
  if (policy.mode === "enforce") {
117
467
  for (const risk of policy.requireApprovalFor || []) {
118
468
  rules.push({
@@ -147,24 +497,38 @@ export class MicrosoftGovernanceAdapter {
147
497
  }
148
498
  /**
149
499
  * Runs the full Microsoft Agent Governance pipeline:
150
- * Agent ──► McpSecurityScanner ──► PolicyEngine ──► AgentIdentity (Ed25519 DID) ──► AuditLogger ──► DecisionRecord
500
+ * Agent ──► KillSwitch ──► McpSecurityScanner & ContextPoisoningDetector (ASI-06) ──► ProtocolFacets (SQL/K8s/Infra) ──► RingEnforcer ──► PolicyEngine ──► TrustManager ──► AgentIdentity (Ed25519 DID) ──► AuditLogger ──► DecisionRecord
151
501
  */
152
502
  evaluateAction(params) {
153
503
  const { workspace, actorId, tool, input, reason, stage } = params;
154
504
  const ownerApproved = Boolean(params.ownerApproved);
155
505
  const decidedAt = new Date().toISOString();
156
- // 1. McpSecurityScanner: inspect tool definition + input arguments for prompt injection / exfiltration
506
+ // 1. McpSecurityScanner + ContextPoisoningDetector (OWASP ASI-06): inspect tool definition + input arguments
157
507
  const serializedInput = JSON.stringify(input || {});
158
508
  const scanResult = this.scanner.scan({
159
509
  name: tool.slug,
160
510
  description: `${tool.description}\nReason: ${reason}\nArgs: ${serializedInput}`,
161
511
  parameters: tool.inputSchema,
162
512
  });
163
- const extraFindings = (scanResult.threats || []).map((t) => ({
164
- category: String(t.type || "mcp_scan"),
165
- severity: String(t.severity || "medium"),
166
- description: String(t.description || "Security scanner finding"),
167
- }));
513
+ const contextPoisoning = this.scanMemoryContent({
514
+ workspaceId: workspace.id,
515
+ sessionId: stage,
516
+ role: "user",
517
+ content: `${reason}\n${serializedInput}`,
518
+ recordInDetector: false,
519
+ });
520
+ const extraFindings = [
521
+ ...(scanResult.threats || []).map((t) => ({
522
+ category: String(t.type || "mcp_scan"),
523
+ severity: String(t.severity || "medium"),
524
+ description: String(t.description || "Security scanner finding"),
525
+ })),
526
+ ...contextPoisoning.findings.map((f) => ({
527
+ category: `asi06_${f.patternId.toLowerCase()}`,
528
+ severity: f.severity,
529
+ description: `${f.patternName}: ${f.description}`,
530
+ })),
531
+ ];
168
532
  // Additional argument-level prompt-injection / secret-exfiltration heuristics
169
533
  const suspiciousPatterns = [
170
534
  {
@@ -190,8 +554,29 @@ export class MicrosoftGovernanceAdapter {
190
554
  }
191
555
  }
192
556
  const highSeverityFinding = extraFindings.some((f) => f.severity === "high" || f.severity === "critical");
193
- // 2. PolicyEngine: evaluate declarative rules against tool slug, risk level, and approval state
557
+ // 2. Protocol Facets Extraction (SQL, Kubernetes, Infrastructure)
558
+ const protocolFacets = this.extractActionFacets(tool, input);
559
+ // 3. PolicyEngine + KillSwitch + Parameter Guardrail evaluation
194
560
  const policy = workspace.policy;
561
+ const paramRuleCheck = evaluateParameterPolicyRules({
562
+ policy,
563
+ toolSlug: tool.slug,
564
+ input,
565
+ });
566
+ if (paramRuleCheck.violated && paramRuleCheck.reason) {
567
+ extraFindings.push({
568
+ category: "parameter_policy_rule",
569
+ severity: paramRuleCheck.action === "block" ? "high" : "medium",
570
+ description: paramRuleCheck.reason,
571
+ });
572
+ }
573
+ const effectiveApproved = ownerApproved ||
574
+ Boolean(paramRuleCheck.explicitAllow && paramRuleCheck.action === "auto_approve");
575
+ // 4. Hardware-style Execution Ring Enforcement (Ring 0..Ring 3)
576
+ const ringEnforcement = this.evaluateRingEnforcement(workspace, tool, effectiveApproved);
577
+ const activeKill = this.isKillSwitchActive(workspace.id);
578
+ const killSwitchActive = Boolean(activeKill || policy.killSwitchActive);
579
+ const killSwitchReason = activeKill?.reason || policy.killSwitchReason || null;
195
580
  const policyEngine = this.createPolicyEngine(policy);
196
581
  const identity = this.getWorkspaceIdentity(workspace);
197
582
  const policyDecision = policyEngine.evaluatePolicy(identity.did, {
@@ -199,20 +584,55 @@ export class MicrosoftGovernanceAdapter {
199
584
  risk_level: tool.riskLevel,
200
585
  lane: tool.lane,
201
586
  stage,
202
- owner_approved: ownerApproved,
587
+ owner_approved: effectiveApproved,
203
588
  workspace_active: true,
589
+ ...(protocolFacets.sql ? { sql: protocolFacets.sql } : {}),
590
+ ...(protocolFacets.k8s ? { k8s: protocolFacets.k8s } : {}),
591
+ ...(protocolFacets.infra ? { infra: protocolFacets.infra } : {}),
204
592
  });
205
593
  let finalDecision = policyDecision.action === "deny"
206
594
  ? "deny"
207
595
  : policyDecision.action === "require_approval"
208
596
  ? "require_approval"
209
597
  : "allow";
210
- // Block explicitly blocked tools even in monitor mode, or high-severity injection findings in enforce mode
211
- if ((policy.blockedToolSlugs || []).includes(tool.slug) ||
212
- (highSeverityFinding && policy.mode === "enforce")) {
598
+ let matchedRule = paramRuleCheck.explicitAllow &&
599
+ paramRuleCheck.action === "auto_approve" &&
600
+ finalDecision === "allow"
601
+ ? paramRuleCheck.matchedRule?.id || "auto-approve-parameter-policy-rule"
602
+ : policyDecision.matchedRule ?? null;
603
+ // Enforce KillSwitch, blocked tools, parameter rules, high-severity scanner/context-poisoning findings, or Ring breach
604
+ if (killSwitchActive) {
605
+ finalDecision = "deny";
606
+ matchedRule = "kill-switch-emergency-quarantine";
607
+ }
608
+ else if ((policy.blockedToolSlugs || []).includes(tool.slug)) {
609
+ finalDecision = "deny";
610
+ matchedRule = matchedRule || `deny-blocked-tool-${tool.slug}`;
611
+ }
612
+ else if (paramRuleCheck.violated &&
613
+ paramRuleCheck.action === "block" &&
614
+ policy.mode === "enforce") {
615
+ finalDecision = "deny";
616
+ matchedRule = paramRuleCheck.matchedRule?.id || "deny-parameter-policy-rule";
617
+ }
618
+ else if (paramRuleCheck.violated &&
619
+ paramRuleCheck.action === "require_approval" &&
620
+ !ownerApproved &&
621
+ policy.mode === "enforce") {
622
+ finalDecision = "require_approval";
623
+ matchedRule = paramRuleCheck.matchedRule?.id || "approval-parameter-policy-rule";
624
+ }
625
+ else if (highSeverityFinding && policy.mode === "enforce") {
213
626
  finalDecision = "deny";
627
+ matchedRule = "mcp-security-scanner-high-severity";
628
+ this.trustManager.recordFailure(workspace.id, 0.1);
214
629
  }
215
- // 3. AuditLogger: append tamper-evident SHA-256 hash-chained log entry
630
+ else if (!ringEnforcement.allowed && finalDecision === "allow" && policy.mode === "enforce") {
631
+ finalDecision = "require_approval";
632
+ matchedRule = `ring-enforcer-requires-ring-${ringEnforcement.requiredRing}`;
633
+ }
634
+ const trustScore = this.getWorkspaceTrustScore(workspace.id);
635
+ // 5. AuditLogger: append tamper-evident SHA-256 hash-chained log entry
216
636
  const auditLogger = this.getWorkspaceAuditLogger(workspace.id);
217
637
  const auditDecision = finalDecision === "deny" ? "deny" : "allow";
218
638
  const auditEntry = auditLogger.log({
@@ -222,11 +642,13 @@ export class MicrosoftGovernanceAdapter {
222
642
  skillAuditMetadata: {
223
643
  skillName: tool.slug,
224
644
  skillOrigin: tool.lane,
225
- provenanceSourceTrust: "trusted",
645
+ provenanceSourceTrust: trustScore.tier === "Verified" || trustScore.tier === "Trusted"
646
+ ? "trusted"
647
+ : undefined,
226
648
  },
227
649
  });
228
650
  const chainVerified = auditLogger.verify();
229
- // 4. AgentIdentity (Ed25519 DID): cryptographically sign the decision record
651
+ // 6. AgentIdentity (Ed25519 DID): cryptographically sign the decision record
230
652
  const bindingHash = crypto
231
653
  .createHash("sha256")
232
654
  .update(JSON.stringify({
@@ -259,13 +681,19 @@ export class MicrosoftGovernanceAdapter {
259
681
  const publicKeyHex = Buffer.from(identity.publicKey).toString("hex");
260
682
  const verdict = finalDecision === "require_approval" ? "escalate" : finalDecision;
261
683
  const decisionReason = finalDecision === "deny"
262
- ? highSeverityFinding
263
- ? `Blocked by McpSecurityScanner: ${extraFindings.map((f) => f.description).join("; ")}`
264
- : `Denied by policy rule ${policyDecision.matchedRule || "default"}`
684
+ ? killSwitchActive
685
+ ? `Blocked by Emergency KillSwitch: ${killSwitchReason || "Workspace agent boundary is quarantined"}`
686
+ : paramRuleCheck.violated && paramRuleCheck.reason
687
+ ? paramRuleCheck.reason
688
+ : highSeverityFinding
689
+ ? `Blocked by McpSecurityScanner / ContextPoisoningDetector: ${extraFindings.map((f) => f.description).join("; ")}`
690
+ : `Denied by policy rule ${matchedRule || "default"}`
265
691
  : finalDecision === "require_approval"
266
- ? `Escalated for human owner approval (${tool.riskLevel} risk lane)`
267
- : `Allowed by Microsoft Agent Governance (${policyDecision.matchedRule || "allow-governed-action"})`;
268
- return {
692
+ ? paramRuleCheck.violated && paramRuleCheck.reason
693
+ ? paramRuleCheck.reason
694
+ : `Escalated for human owner approval (${tool.riskLevel} risk lane, ${ringEnforcement.ringLabel})`
695
+ : `Allowed by Microsoft Agent Governance (${matchedRule || "allow-governed-action"})`;
696
+ const record = {
269
697
  id: `dec_${crypto.randomBytes(8).toString("hex")}`,
270
698
  sdk: "@microsoft/agent-governance-sdk",
271
699
  sdkVersion: SDK_VERSION,
@@ -280,12 +708,12 @@ export class MicrosoftGovernanceAdapter {
280
708
  decision: finalDecision,
281
709
  verdict,
282
710
  reason: decisionReason,
283
- matchedRule: policyDecision.matchedRule ?? null,
711
+ matchedRule,
284
712
  securityScan: {
285
- safe: scanResult.safe && !highSeverityFinding,
713
+ safe: scanResult.safe && !highSeverityFinding && contextPoisoning.safe,
286
714
  riskLevel: highSeverityFinding
287
715
  ? "high"
288
- : scanResult.risk_score > 50
716
+ : scanResult.risk_score > 50 || contextPoisoning.findingsCount > 0
289
717
  ? "medium"
290
718
  : "low",
291
719
  findingsCount: extraFindings.length,
@@ -300,11 +728,27 @@ export class MicrosoftGovernanceAdapter {
300
728
  previousHash: auditEntry.previousHash,
301
729
  chainVerified,
302
730
  },
731
+ protocolFacets,
732
+ ringEnforcement,
733
+ trustScore,
734
+ contextPoisoning: {
735
+ safe: contextPoisoning.safe,
736
+ riskLevel: contextPoisoning.riskLevel,
737
+ findingsCount: contextPoisoning.findingsCount,
738
+ findings: contextPoisoning.findings,
739
+ },
740
+ killSwitch: {
741
+ active: killSwitchActive,
742
+ killedAt: activeKill?.killedAt || null,
743
+ reason: killSwitchReason,
744
+ },
303
745
  ed25519Signature,
304
746
  signature: ed25519Signature,
305
747
  bindingHash,
306
748
  decidedAt,
307
749
  };
750
+ record.explanation = explainDecisionRecord(record, policy);
751
+ return record;
308
752
  }
309
753
  evaluatePlan(params) {
310
754
  return this.evaluateAction({
@@ -369,6 +813,112 @@ export class MicrosoftGovernanceAdapter {
369
813
  const auditChainVerified = auditLogger.verify();
370
814
  return ed25519Verified && auditChainVerified;
371
815
  }
816
+ /**
817
+ * Builds a portable Ed25519-signed AgenticReceipt envelope (compatible with the `agentic-receipts` spec)
818
+ * so external verifiers can validate input/output SHA-256 hashes, hash chaining, and Ed25519 signature
819
+ * using only the workspace's public key and DID without needing the internal vault HMAC key.
820
+ */
821
+ buildPortableAgenticReceipt(params) {
822
+ const { receipt, run, workspace } = params;
823
+ const identity = workspace
824
+ ? this.getWorkspaceIdentity(workspace)
825
+ : this.identities.get(receipt.workspaceId) || this.defaultIdentity;
826
+ const actionType = receipt.lane === "stripe_projects" ? "ApiCall" : "ToolCall";
827
+ const startedAt = run?.startedAt || receipt.issuedAt;
828
+ const completedAt = run?.completedAt || receipt.issuedAt;
829
+ const latencyMs = Math.max(0, Number(run?.durationMs ?? 0));
830
+ const nonce = crypto
831
+ .createHash("sha256")
832
+ .update(`muxo-agentic-receipt-nonce:${receipt.id}:${receipt.runId}`)
833
+ .digest("hex")
834
+ .slice(0, 32);
835
+ const previousReceiptHash = receipt.prevReceiptHash || "genesis_0000000000000000";
836
+ const canonicalPayload = [
837
+ "0.1.0",
838
+ receipt.id,
839
+ identity.did,
840
+ receipt.runId,
841
+ actionType,
842
+ receipt.toolSlug || "",
843
+ receipt.inputHash,
844
+ receipt.outputHash,
845
+ startedAt,
846
+ completedAt,
847
+ String(latencyMs),
848
+ nonce,
849
+ previousReceiptHash || "genesis",
850
+ receipt.receiptHash,
851
+ ].join("|");
852
+ const sigBytes = identity.sign(Buffer.from(canonicalPayload, "utf8"));
853
+ const signatureHex = Buffer.from(sigBytes).toString("hex");
854
+ const publicKeyHex = Buffer.from(identity.publicKey).toString("hex");
855
+ return {
856
+ version: "0.1.0",
857
+ receipt_id: receipt.id,
858
+ agent_id: identity.did,
859
+ task_id: receipt.runId,
860
+ action_type: actionType,
861
+ tool_name: receipt.toolSlug,
862
+ model_id: null,
863
+ input_hash: receipt.inputHash,
864
+ output_hash: receipt.outputHash,
865
+ started_at: startedAt,
866
+ completed_at: completedAt,
867
+ latency_ms: latencyMs,
868
+ nonce,
869
+ previous_receipt_hash: previousReceiptHash,
870
+ receipt_hash: receipt.receiptHash,
871
+ signature_algorithm: "Ed25519",
872
+ public_key_hex: publicKeyHex,
873
+ signature_hex: signatureHex,
874
+ };
875
+ }
876
+ /**
877
+ * Verifies a PortableAgenticReceipt's Ed25519 signature over its canonical hash-chained payload.
878
+ */
879
+ verifyPortableAgenticReceipt(agenticReceipt, workspace) {
880
+ if (!agenticReceipt || !agenticReceipt.signature_hex || !agenticReceipt.public_key_hex) {
881
+ return false;
882
+ }
883
+ const canonicalPayload = [
884
+ agenticReceipt.version || "0.1.0",
885
+ agenticReceipt.receipt_id,
886
+ agenticReceipt.agent_id,
887
+ agenticReceipt.task_id,
888
+ agenticReceipt.action_type,
889
+ agenticReceipt.tool_name || "",
890
+ agenticReceipt.input_hash,
891
+ agenticReceipt.output_hash,
892
+ agenticReceipt.started_at,
893
+ agenticReceipt.completed_at,
894
+ String(agenticReceipt.latency_ms ?? 0),
895
+ agenticReceipt.nonce,
896
+ agenticReceipt.previous_receipt_hash || "genesis",
897
+ agenticReceipt.receipt_hash,
898
+ ].join("|");
899
+ try {
900
+ const identity = workspace ? this.getWorkspaceIdentity(workspace) : null;
901
+ if (identity && identity.did === agenticReceipt.agent_id) {
902
+ return identity.verify(Buffer.from(canonicalPayload, "utf8"), Buffer.from(agenticReceipt.signature_hex, "hex"));
903
+ }
904
+ const pubKeyBytes = Buffer.from(agenticReceipt.public_key_hex, "hex");
905
+ const spkiKey = pubKeyBytes.length === 32
906
+ ? Buffer.concat([
907
+ Buffer.from("302a300506032b6570032100", "hex"),
908
+ pubKeyBytes,
909
+ ])
910
+ : pubKeyBytes;
911
+ const pubKeyObj = crypto.createPublicKey({
912
+ key: spkiKey,
913
+ format: "der",
914
+ type: "spki",
915
+ });
916
+ return crypto.verify(null, Buffer.from(canonicalPayload, "utf8"), pubKeyObj, Buffer.from(agenticReceipt.signature_hex, "hex"));
917
+ }
918
+ catch {
919
+ return false;
920
+ }
921
+ }
372
922
  getStatus(workspace) {
373
923
  const identity = workspace
374
924
  ? this.getWorkspaceIdentity(workspace)
@@ -398,18 +948,115 @@ export class MicrosoftGovernanceAdapter {
398
948
  const identity = this.getWorkspaceIdentity(workspace);
399
949
  const auditLogger = this.getWorkspaceAuditLogger(workspace.id);
400
950
  const entries = auditLogger.getEntries();
951
+ const activeKill = this.isKillSwitchActive(workspace.id);
952
+ const killSwitchActive = Boolean(activeKill || workspace.policy.killSwitchActive);
953
+ const contextPoisoningReport = this.getContextPoisoningReport(workspace.id, "default");
401
954
  return {
402
955
  sdk: "@microsoft/agent-governance-sdk",
403
956
  sdkVersion: SDK_VERSION,
404
957
  policyId: POLICY_ID,
405
- pipeline: "Agent ──► McpSecurityScanner ──► PolicyEngine ──► AgentIdentity (Ed25519 DID) ──► AuditLogger ──► DecisionRecord",
958
+ pipeline: "Agent ──► KillSwitch ──► McpSecurityScanner & ContextPoisoningDetector (ASI-06) ──► ProtocolFacets (SQL/K8s/Infra) ──► RingEnforcer ──► PolicyEngine ──► TrustManager ──► AgentIdentity (Ed25519 DID) ──► AuditLogger ──► DecisionRecord",
959
+ modules: [
960
+ "McpSecurityScanner",
961
+ "ContextPoisoningDetector",
962
+ "ProtocolFacets",
963
+ "RingEnforcer",
964
+ "PolicyEngine",
965
+ "TrustManager",
966
+ "KillSwitch",
967
+ "AgentIdentity",
968
+ "AuditLogger",
969
+ ],
406
970
  agentIdentity: identity.toJSON(),
407
971
  policy: workspace.policy,
972
+ trustScore: this.getWorkspaceTrustScore(workspace.id),
973
+ killSwitch: {
974
+ active: killSwitchActive,
975
+ killedAt: activeKill?.killedAt || null,
976
+ reason: activeKill?.reason || workspace.policy.killSwitchReason || null,
977
+ historyCount: this.killSwitch.getHistory().length,
978
+ },
979
+ contextPoisoning: {
980
+ poisoned: Boolean(contextPoisoningReport.poisoned ??
981
+ (contextPoisoningReport.findings?.length > 0)),
982
+ riskScore: Number(contextPoisoningReport.riskScore ?? 0),
983
+ findingsCount: contextPoisoningReport.findings.length,
984
+ findings: contextPoisoningReport.findings.slice(-10),
985
+ },
408
986
  auditChain: {
409
987
  entriesCount: entries.length,
410
988
  chainVerified: auditLogger.verify(),
411
989
  recentEntries: entries.slice(-15).reverse(),
412
990
  },
991
+ plainEnglishPolicy: describePolicyInPlainEnglish(workspace.policy),
992
+ explanation: explainGovernanceStatus({
993
+ workspace,
994
+ agentDid: identity.did,
995
+ trustScore: this.getWorkspaceTrustScore(workspace.id),
996
+ killSwitchActive,
997
+ killSwitchReason: activeKill?.reason || workspace.policy.killSwitchReason || null,
998
+ poisoned: Boolean(contextPoisoningReport.poisoned ??
999
+ (contextPoisoningReport.findings?.length > 0)),
1000
+ findingsCount: contextPoisoningReport.findings.length,
1001
+ auditEntriesCount: entries.length,
1002
+ chainVerified: auditLogger.verify(),
1003
+ }),
413
1004
  };
414
1005
  }
415
1006
  }
1007
+ export function explainDecisionRecord(record, policy, languageMode) {
1008
+ const toolSlug = record.action.includes(":")
1009
+ ? record.action.split(":").slice(1).join(":")
1010
+ : record.action;
1011
+ const stage = record.action.startsWith("execute.") ? "Execution" : "Plan";
1012
+ const headline = record.decision === "allow"
1013
+ ? `${stage} allowed: ${toolSlug} passed all workspace safety checks.`
1014
+ : record.decision === "require_approval"
1015
+ ? `Approval needed: ${toolSlug} (${record.riskLevel}) is paused until you approve it.`
1016
+ : `Action blocked: ${toolSlug} was stopped by your workspace safety rules.`;
1017
+ const scanPlain = record.securityScan.safe
1018
+ ? "Safety scan: Clean (no prompt injection, data exfiltration, or destructive command patterns detected)."
1019
+ : `Safety warning: Flagged ${record.securityScan.findingsCount} security issue(s) (${record.securityScan.findings.map((f) => f.description).join("; ")}).`;
1020
+ const whyPlain = record.decision === "allow"
1021
+ ? `This ${record.riskLevel}-level action is permitted under your active guardrails.`
1022
+ : record.decision === "require_approval"
1023
+ ? `Your guardrails require human sign-off before running ${record.riskLevel} actions.`
1024
+ : record.killSwitch?.active
1025
+ ? `Your workspace Emergency Pause is active (${record.killSwitch.reason || "all agents paused"}).`
1026
+ : `Stopped because: ${record.reason}.`;
1027
+ const trustPct = record.trustScore
1028
+ ? `${Math.round(record.trustScore.overall * 100)}% (${record.trustScore.tier})`
1029
+ : "75% (Provisional)";
1030
+ const nonTechnical = `${headline} ${whyPlain} ${scanPlain} Agent reliability score: ${trustPct}. Recorded in your tamper-proof audit log.`;
1031
+ const technical = `decisionId=${record.id} | decision=${record.decision} (verdict=${record.verdict}) | matchedRule=${record.matchedRule || "none"} | mode=${record.mode} | ring=${record.ringEnforcement?.agentRing ?? "?"}->${record.ringEnforcement?.requiredRing ?? "?"} (${record.ringEnforcement?.ringLabel || "Ring"}) | securityScan=(safe=${record.securityScan.safe}, risk=${record.securityScan.riskLevel}, findings=${record.securityScan.findingsCount}) | asi06Poisoning=(safe=${record.contextPoisoning?.safe ?? true}, risk=${record.contextPoisoning?.riskLevel || "none"}) | trustScore=${record.trustScore?.overall ?? 0.75} (${record.trustScore?.tier || "Provisional"}) | agentDid=${record.agentDid} | auditHash=${record.auditEntry.hash.slice(0, 16)}... (prev=${record.auditEntry.previousHash.slice(0, 16)}..., chainVerified=${record.auditEntry.chainVerified}) | bindingHash=${record.bindingHash.slice(0, 16)}... | ed25519Sig=${record.ed25519Signature.slice(0, 16)}...`;
1032
+ return formatHumanFriendlyExplanation({
1033
+ headline,
1034
+ nonTechnical,
1035
+ technical,
1036
+ policy,
1037
+ languageMode,
1038
+ });
1039
+ }
1040
+ export function explainGovernanceStatus(params) {
1041
+ const plainPolicy = describePolicyInPlainEnglish(params.workspace.policy);
1042
+ const trustPct = Math.round((params.trustScore.overall || 0.75) * 100);
1043
+ const headline = params.killSwitchActive
1044
+ ? `Emergency Pause Active: All agent actions are paused (${params.killSwitchReason || "operator pause"}).`
1045
+ : `Governance Active: 9 safety modules protecting ${params.workspace.name} (${params.trustScore.tier} trust, ${trustPct}% score).`;
1046
+ const nonTechnical = [
1047
+ headline,
1048
+ `Current posture: ${plainPolicy.headline}`,
1049
+ params.poisoned
1050
+ ? `Prompt-injection scanner: ${params.findingsCount} suspicious pattern(s) flagged and isolated.`
1051
+ : "Prompt-injection & memory scanner: Clean (0 threats detected).",
1052
+ `Tamper-proof audit log: ${params.auditEntriesCount} action${params.auditEntriesCount === 1 ? "" : "s"} verified (${params.chainVerified ? "intact" : "check required"}).`,
1053
+ ].join(" ");
1054
+ const technical = `sdk=@microsoft/agent-governance-sdk@${SDK_VERSION} | policyId=${POLICY_ID} | agentDid=${params.agentDid} | killSwitchActive=${params.killSwitchActive} | trustScore=${params.trustScore.overall} (tier=${params.trustScore.tier}, reliability=${params.trustScore.reliability}, consistency=${params.trustScore.consistency}) | asi06Poisoned=${params.poisoned} (findings=${params.findingsCount}) | auditChain=(entries=${params.auditEntriesCount}, verified=${params.chainVerified}) | ${plainPolicy.technical}`;
1055
+ return formatHumanFriendlyExplanation({
1056
+ headline,
1057
+ nonTechnical,
1058
+ technical,
1059
+ policy: params.workspace.policy,
1060
+ languageMode: params.languageMode,
1061
+ });
1062
+ }