@muxoai/sdk 1.2.3 → 1.4.2

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 (208) hide show
  1. package/.agents/plugins/marketplace.json +22 -0
  2. package/.claude-plugin/marketplace.json +32 -0
  3. package/.codex/config.toml +12 -0
  4. package/ARCHITECTURE.md +121 -0
  5. package/README.md +85 -31
  6. package/dist/clerk.d.ts +35 -0
  7. package/dist/clerk.js +201 -0
  8. package/dist/cli.d.ts +2 -0
  9. package/dist/cli.js +2380 -0
  10. package/dist/composio-catalog.d.ts +234 -0
  11. package/dist/composio-catalog.js +1894 -0
  12. package/dist/config.d.ts +36 -0
  13. package/dist/config.js +115 -0
  14. package/dist/durable-workflow.d.ts +45 -0
  15. package/dist/durable-workflow.js +90 -0
  16. package/dist/engine.d.ts +465 -0
  17. package/dist/engine.js +2560 -0
  18. package/dist/index.d.ts +7 -0
  19. package/dist/index.js +7 -0
  20. package/dist/mcp-schema.d.ts +286 -0
  21. package/dist/mcp-schema.js +2559 -0
  22. package/dist/mcp.d.ts +22 -0
  23. package/dist/mcp.js +1356 -0
  24. package/dist/memory-graph.d.ts +21 -0
  25. package/dist/memory-graph.js +173 -0
  26. package/dist/nl.d.ts +34 -0
  27. package/dist/nl.js +756 -0
  28. package/dist/oauth.d.ts +32 -0
  29. package/dist/oauth.js +134 -0
  30. package/dist/policy.d.ts +190 -0
  31. package/dist/policy.js +1597 -0
  32. package/dist/providers/composio-instant.d.ts +18 -0
  33. package/dist/providers/composio-instant.js +1169 -0
  34. package/dist/providers/composio-sdk.d.ts +162 -0
  35. package/dist/providers/composio-sdk.js +1395 -0
  36. package/dist/providers/microsoft-governance.d.ts +152 -0
  37. package/dist/providers/microsoft-governance.js +1062 -0
  38. package/dist/providers/stripe-billing.d.ts +83 -0
  39. package/dist/providers/stripe-billing.js +611 -0
  40. package/dist/providers/stripe-projects.d.ts +508 -0
  41. package/dist/providers/stripe-projects.js +3188 -0
  42. package/dist/providers/supermemory.d.ts +160 -0
  43. package/dist/providers/supermemory.js +778 -0
  44. package/dist/provisioning-managed.d.ts +50 -0
  45. package/dist/provisioning-managed.js +155 -0
  46. package/dist/sdk.d.ts +951 -0
  47. package/dist/sdk.js +748 -0
  48. package/dist/server.d.ts +10 -0
  49. package/dist/server.js +3575 -0
  50. package/dist/store.d.ts +348 -0
  51. package/dist/store.js +2323 -0
  52. package/dist/types.d.ts +593 -0
  53. package/dist/types.js +1 -0
  54. package/dist/ui/console-html.d.ts +64 -0
  55. package/dist/ui/console-html.js +3857 -0
  56. package/dist/ui/design-tokens.d.ts +177 -0
  57. package/dist/ui/design-tokens.js +210 -0
  58. package/dist/version.d.ts +1 -0
  59. package/dist/version.js +1 -0
  60. package/package.json +68 -7
  61. package/plugins/muxo/.app.json +8 -0
  62. package/plugins/muxo/.claude-plugin/plugin.json +16 -0
  63. package/plugins/muxo/.codex-plugin/plugin.json +64 -0
  64. package/plugins/muxo/.cursor-plugin/plugin.json +30 -0
  65. package/plugins/muxo/.mcp.json +8 -0
  66. package/plugins/muxo/assets/logo.png +0 -0
  67. package/plugins/muxo/assets/logo.svg +6 -0
  68. package/plugins/muxo/hooks/hooks.json +27 -0
  69. package/plugins/muxo/hooks/session-start.sh +97 -0
  70. package/plugins/muxo/hooks/user-prompt-submit.sh +58 -0
  71. package/plugins/muxo/mcp.json +28 -0
  72. package/plugins/muxo/plugin.json +116 -0
  73. package/plugins/muxo/skills/muxo/SKILL.md +153 -0
  74. package/plugins/muxo/skills/muxo/agents/openai.yaml +12 -0
  75. package/plugins/muxo/skills/muxo/references/cli.md +63 -0
  76. package/plugins/muxo/skills/muxo/references/mcp.md +37 -0
  77. package/plugins/muxo/skills/muxo-activity-summary/SKILL.md +81 -0
  78. package/plugins/muxo/skills/setup/SKILL.md +42 -0
  79. package/plugins/muxo/skills/setup/agents/openai.yaml +12 -0
  80. package/src/catalogues/stripe-projects-catalog.json +9972 -0
  81. package/vendor/microsoft-governance/README.md +363 -0
  82. package/vendor/microsoft-governance/dist/audit.d.ts +26 -0
  83. package/vendor/microsoft-governance/dist/audit.d.ts.map +1 -0
  84. package/vendor/microsoft-governance/dist/audit.js +107 -0
  85. package/vendor/microsoft-governance/dist/audit.js.map +1 -0
  86. package/vendor/microsoft-governance/dist/cascade-containment.d.ts +84 -0
  87. package/vendor/microsoft-governance/dist/cascade-containment.d.ts.map +1 -0
  88. package/vendor/microsoft-governance/dist/cascade-containment.js +387 -0
  89. package/vendor/microsoft-governance/dist/cascade-containment.js.map +1 -0
  90. package/vendor/microsoft-governance/dist/client.d.ts +34 -0
  91. package/vendor/microsoft-governance/dist/client.d.ts.map +1 -0
  92. package/vendor/microsoft-governance/dist/client.js +112 -0
  93. package/vendor/microsoft-governance/dist/client.js.map +1 -0
  94. package/vendor/microsoft-governance/dist/context-poisoning.d.ts +58 -0
  95. package/vendor/microsoft-governance/dist/context-poisoning.d.ts.map +1 -0
  96. package/vendor/microsoft-governance/dist/context-poisoning.js +410 -0
  97. package/vendor/microsoft-governance/dist/context-poisoning.js.map +1 -0
  98. package/vendor/microsoft-governance/dist/credential-vault.d.ts +213 -0
  99. package/vendor/microsoft-governance/dist/credential-vault.d.ts.map +1 -0
  100. package/vendor/microsoft-governance/dist/credential-vault.js +567 -0
  101. package/vendor/microsoft-governance/dist/credential-vault.js.map +1 -0
  102. package/vendor/microsoft-governance/dist/discovery.d.ts +80 -0
  103. package/vendor/microsoft-governance/dist/discovery.d.ts.map +1 -0
  104. package/vendor/microsoft-governance/dist/discovery.js +404 -0
  105. package/vendor/microsoft-governance/dist/discovery.js.map +1 -0
  106. package/vendor/microsoft-governance/dist/encryption/channel.d.ts +29 -0
  107. package/vendor/microsoft-governance/dist/encryption/channel.d.ts.map +1 -0
  108. package/vendor/microsoft-governance/dist/encryption/channel.js +78 -0
  109. package/vendor/microsoft-governance/dist/encryption/channel.js.map +1 -0
  110. package/vendor/microsoft-governance/dist/encryption/index.d.ts +9 -0
  111. package/vendor/microsoft-governance/dist/encryption/index.d.ts.map +1 -0
  112. package/vendor/microsoft-governance/dist/encryption/index.js +23 -0
  113. package/vendor/microsoft-governance/dist/encryption/index.js.map +1 -0
  114. package/vendor/microsoft-governance/dist/encryption/mesh-client.d.ts +267 -0
  115. package/vendor/microsoft-governance/dist/encryption/mesh-client.d.ts.map +1 -0
  116. package/vendor/microsoft-governance/dist/encryption/mesh-client.js +1001 -0
  117. package/vendor/microsoft-governance/dist/encryption/mesh-client.js.map +1 -0
  118. package/vendor/microsoft-governance/dist/encryption/ratchet.d.ts +38 -0
  119. package/vendor/microsoft-governance/dist/encryption/ratchet.d.ts.map +1 -0
  120. package/vendor/microsoft-governance/dist/encryption/ratchet.js +223 -0
  121. package/vendor/microsoft-governance/dist/encryption/ratchet.js.map +1 -0
  122. package/vendor/microsoft-governance/dist/encryption/registry-client.d.ts +136 -0
  123. package/vendor/microsoft-governance/dist/encryption/registry-client.d.ts.map +1 -0
  124. package/vendor/microsoft-governance/dist/encryption/registry-client.js +369 -0
  125. package/vendor/microsoft-governance/dist/encryption/registry-client.js.map +1 -0
  126. package/vendor/microsoft-governance/dist/encryption/x3dh.d.ts +80 -0
  127. package/vendor/microsoft-governance/dist/encryption/x3dh.d.ts.map +1 -0
  128. package/vendor/microsoft-governance/dist/encryption/x3dh.js +238 -0
  129. package/vendor/microsoft-governance/dist/encryption/x3dh.js.map +1 -0
  130. package/vendor/microsoft-governance/dist/framework-adapter.d.ts +63 -0
  131. package/vendor/microsoft-governance/dist/framework-adapter.d.ts.map +1 -0
  132. package/vendor/microsoft-governance/dist/framework-adapter.js +253 -0
  133. package/vendor/microsoft-governance/dist/framework-adapter.js.map +1 -0
  134. package/vendor/microsoft-governance/dist/identity.d.ts +124 -0
  135. package/vendor/microsoft-governance/dist/identity.d.ts.map +1 -0
  136. package/vendor/microsoft-governance/dist/identity.js +446 -0
  137. package/vendor/microsoft-governance/dist/identity.js.map +1 -0
  138. package/vendor/microsoft-governance/dist/index.d.ts +39 -0
  139. package/vendor/microsoft-governance/dist/index.d.ts.map +1 -0
  140. package/vendor/microsoft-governance/dist/index.js +95 -0
  141. package/vendor/microsoft-governance/dist/index.js.map +1 -0
  142. package/vendor/microsoft-governance/dist/kill-switch.d.ts +22 -0
  143. package/vendor/microsoft-governance/dist/kill-switch.d.ts.map +1 -0
  144. package/vendor/microsoft-governance/dist/kill-switch.js +60 -0
  145. package/vendor/microsoft-governance/dist/kill-switch.js.map +1 -0
  146. package/vendor/microsoft-governance/dist/lifecycle.d.ts +50 -0
  147. package/vendor/microsoft-governance/dist/lifecycle.d.ts.map +1 -0
  148. package/vendor/microsoft-governance/dist/lifecycle.js +113 -0
  149. package/vendor/microsoft-governance/dist/lifecycle.js.map +1 -0
  150. package/vendor/microsoft-governance/dist/mcp.d.ts +41 -0
  151. package/vendor/microsoft-governance/dist/mcp.d.ts.map +1 -0
  152. package/vendor/microsoft-governance/dist/mcp.js +233 -0
  153. package/vendor/microsoft-governance/dist/mcp.js.map +1 -0
  154. package/vendor/microsoft-governance/dist/metrics.d.ts +123 -0
  155. package/vendor/microsoft-governance/dist/metrics.d.ts.map +1 -0
  156. package/vendor/microsoft-governance/dist/metrics.js +289 -0
  157. package/vendor/microsoft-governance/dist/metrics.js.map +1 -0
  158. package/vendor/microsoft-governance/dist/oci-manifest.d.ts +49 -0
  159. package/vendor/microsoft-governance/dist/oci-manifest.d.ts.map +1 -0
  160. package/vendor/microsoft-governance/dist/oci-manifest.js +182 -0
  161. package/vendor/microsoft-governance/dist/oci-manifest.js.map +1 -0
  162. package/vendor/microsoft-governance/dist/policy-backends/cedar.d.ts +15 -0
  163. package/vendor/microsoft-governance/dist/policy-backends/cedar.d.ts.map +1 -0
  164. package/vendor/microsoft-governance/dist/policy-backends/cedar.js +88 -0
  165. package/vendor/microsoft-governance/dist/policy-backends/cedar.js.map +1 -0
  166. package/vendor/microsoft-governance/dist/policy-backends/opa.d.ts +17 -0
  167. package/vendor/microsoft-governance/dist/policy-backends/opa.d.ts.map +1 -0
  168. package/vendor/microsoft-governance/dist/policy-backends/opa.js +74 -0
  169. package/vendor/microsoft-governance/dist/policy-backends/opa.js.map +1 -0
  170. package/vendor/microsoft-governance/dist/policy.d.ts +77 -0
  171. package/vendor/microsoft-governance/dist/policy.d.ts.map +1 -0
  172. package/vendor/microsoft-governance/dist/policy.js +760 -0
  173. package/vendor/microsoft-governance/dist/policy.js.map +1 -0
  174. package/vendor/microsoft-governance/dist/prompt-defense.d.ts +37 -0
  175. package/vendor/microsoft-governance/dist/prompt-defense.d.ts.map +1 -0
  176. package/vendor/microsoft-governance/dist/prompt-defense.js +229 -0
  177. package/vendor/microsoft-governance/dist/prompt-defense.js.map +1 -0
  178. package/vendor/microsoft-governance/dist/protocol-facets.d.ts +87 -0
  179. package/vendor/microsoft-governance/dist/protocol-facets.d.ts.map +1 -0
  180. package/vendor/microsoft-governance/dist/protocol-facets.js +728 -0
  181. package/vendor/microsoft-governance/dist/protocol-facets.js.map +1 -0
  182. package/vendor/microsoft-governance/dist/rings.d.ts +17 -0
  183. package/vendor/microsoft-governance/dist/rings.d.ts.map +1 -0
  184. package/vendor/microsoft-governance/dist/rings.js +61 -0
  185. package/vendor/microsoft-governance/dist/rings.js.map +1 -0
  186. package/vendor/microsoft-governance/dist/sandbox.d.ts +61 -0
  187. package/vendor/microsoft-governance/dist/sandbox.d.ts.map +1 -0
  188. package/vendor/microsoft-governance/dist/sandbox.js +199 -0
  189. package/vendor/microsoft-governance/dist/sandbox.js.map +1 -0
  190. package/vendor/microsoft-governance/dist/surface-parity.d.ts +45 -0
  191. package/vendor/microsoft-governance/dist/surface-parity.d.ts.map +1 -0
  192. package/vendor/microsoft-governance/dist/surface-parity.js +216 -0
  193. package/vendor/microsoft-governance/dist/surface-parity.js.map +1 -0
  194. package/vendor/microsoft-governance/dist/trust.d.ts +28 -0
  195. package/vendor/microsoft-governance/dist/trust.d.ts.map +1 -0
  196. package/vendor/microsoft-governance/dist/trust.js +209 -0
  197. package/vendor/microsoft-governance/dist/trust.js.map +1 -0
  198. package/vendor/microsoft-governance/dist/types.d.ts +422 -0
  199. package/vendor/microsoft-governance/dist/types.d.ts.map +1 -0
  200. package/vendor/microsoft-governance/dist/types.js +29 -0
  201. package/vendor/microsoft-governance/dist/types.js.map +1 -0
  202. package/vendor/microsoft-governance/dist/verify.d.ts +135 -0
  203. package/vendor/microsoft-governance/dist/verify.d.ts.map +1 -0
  204. package/vendor/microsoft-governance/dist/verify.js +356 -0
  205. package/vendor/microsoft-governance/dist/verify.js.map +1 -0
  206. package/vendor/microsoft-governance/package.json +64 -0
  207. package/index.d.ts +0 -177
  208. package/index.js +0 -1
@@ -0,0 +1,1062 @@
1
+ import crypto from "node:crypto";
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";
4
+ const SDK_VERSION = "5.0.0";
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
+ }
27
+ // PKCS#8 DER prefix for a 32-byte Ed25519 private key seed (OID 1.3.101.112)
28
+ const ED25519_PKCS8_PREFIX = Buffer.from([
29
+ 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70,
30
+ 0x04, 0x22, 0x04, 0x20,
31
+ ]);
32
+ function deriveDeterministicIdentity(seedMaterial, agentId, capabilities, opts) {
33
+ const rawSeed = crypto
34
+ .createHmac("sha256", seedMaterial)
35
+ .update(`muxo-ed25519-agent-identity:${agentId}`)
36
+ .digest();
37
+ const pkcs8Der = Buffer.concat([ED25519_PKCS8_PREFIX, rawSeed]);
38
+ const privateKeyObj = crypto.createPrivateKey({
39
+ key: pkcs8Der,
40
+ format: "der",
41
+ type: "pkcs8",
42
+ });
43
+ const publicKeyObj = crypto.createPublicKey(privateKeyObj);
44
+ const pubDer = Buffer.from(publicKeyObj.export({ type: "spki", format: "der" }));
45
+ const privDer = Buffer.from(privateKeyObj.export({ type: "pkcs8", format: "der" }));
46
+ const fingerprint = crypto
47
+ .createHash("sha256")
48
+ .update(pubDer)
49
+ .digest("hex")
50
+ .slice(0, 16);
51
+ const did = `did:agentmesh:${agentId}:${fingerprint}`;
52
+ return AgentIdentity.fromJSON({
53
+ did,
54
+ publicKey: pubDer.toString("base64"),
55
+ privateKey: privDer.toString("base64"),
56
+ capabilities,
57
+ name: opts.name || agentId,
58
+ organization: opts.organization || "muxo.ai",
59
+ createdAt: opts.createdAt || new Date().toISOString(),
60
+ });
61
+ }
62
+ export class MicrosoftGovernanceAdapter {
63
+ scanner;
64
+ contextPoisoningDetector;
65
+ facetRegistry;
66
+ trustManager;
67
+ killSwitch;
68
+ activeKillSwitches = new Map();
69
+ seedMaterial;
70
+ auditLoggers = new Map();
71
+ identities = new Map();
72
+ defaultIdentity;
73
+ constructor(seed) {
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
+ });
99
+ this.seedMaterial = Buffer.isBuffer(seed)
100
+ ? seed
101
+ : Buffer.from(String(seed ||
102
+ process.env.MUXO_VAULT_SECRET ||
103
+ process.env.COMPOSIO_API_KEY ||
104
+ "muxo-governance-ed25519-seed-v5"), "utf8");
105
+ this.defaultIdentity = deriveDeterministicIdentity(this.seedMaterial, "muxo-control-plane", [
106
+ "instant.*",
107
+ "app.*",
108
+ "resource.*",
109
+ "mcp.execute",
110
+ "governance.verify",
111
+ ], {
112
+ name: "Muxo Control Plane Agent",
113
+ organization: "muxo.ai",
114
+ });
115
+ }
116
+ /**
117
+ * Returns (or deterministically derives) the Ed25519 AgentIdentity (`did:agentmesh:...`) for a workspace.
118
+ */
119
+ getWorkspaceIdentity(workspace) {
120
+ let identity = this.identities.get(workspace.id);
121
+ if (!identity) {
122
+ identity = deriveDeterministicIdentity(this.seedMaterial, `muxo-workspace-${workspace.slug || workspace.id}`, [
123
+ "instant.*",
124
+ "app.*",
125
+ "resource.*",
126
+ "mcp.execute",
127
+ "governance.verify",
128
+ ], {
129
+ name: `${workspace.name} Agent Boundary`,
130
+ organization: workspace.id,
131
+ createdAt: workspace.createdAt,
132
+ });
133
+ this.identities.set(workspace.id, identity);
134
+ }
135
+ return identity;
136
+ }
137
+ /**
138
+ * Returns (or lazily initializes) the SHA-256 hash-chained AuditLogger for a workspace.
139
+ */
140
+ getWorkspaceAuditLogger(workspaceId) {
141
+ let logger = this.auditLoggers.get(workspaceId);
142
+ if (!logger) {
143
+ logger = new AuditLogger();
144
+ this.auditLoggers.set(workspaceId, logger);
145
+ }
146
+ return logger;
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
+ }
399
+ /**
400
+ * Compiles the workspace's GovernancePolicy into a declarative Microsoft PolicyEngine instance.
401
+ */
402
+ createPolicyEngine(policy) {
403
+ const engine = new PolicyEngine();
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
+ }
415
+ for (const blockedSlug of policy.blockedToolSlugs || []) {
416
+ const normalized = blockedSlug.trim();
417
+ if (!normalized)
418
+ continue;
419
+ rules.push({
420
+ name: `deny-blocked-tool-${normalized.replace(/[^a-zA-Z0-9_-]/g, "_")}`,
421
+ ruleAction: "deny",
422
+ priority: 100,
423
+ condition: {
424
+ tool_slug: normalized,
425
+ },
426
+ });
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
+ }
466
+ if (policy.mode === "enforce") {
467
+ for (const risk of policy.requireApprovalFor || []) {
468
+ rules.push({
469
+ name: `require-owner-approval-for-${risk}`,
470
+ ruleAction: "require_approval",
471
+ priority: 80,
472
+ condition: {
473
+ risk_level: risk,
474
+ owner_approved: false,
475
+ },
476
+ });
477
+ }
478
+ }
479
+ rules.push({
480
+ name: "allow-governed-action",
481
+ ruleAction: "allow",
482
+ priority: 10,
483
+ condition: {
484
+ workspace_active: true,
485
+ },
486
+ });
487
+ engine.loadJson(JSON.stringify({
488
+ apiVersion: "governance.toolkit/v1",
489
+ name: POLICY_ID,
490
+ version: "5.0.0",
491
+ description: "Muxo Unified Execution Boundary Policy",
492
+ scope: "tenant",
493
+ default_action: "deny",
494
+ rules,
495
+ }));
496
+ return engine;
497
+ }
498
+ /**
499
+ * Runs the full Microsoft Agent Governance pipeline:
500
+ * Agent ──► KillSwitch ──► McpSecurityScanner & ContextPoisoningDetector (ASI-06) ──► ProtocolFacets (SQL/K8s/Infra) ──► RingEnforcer ──► PolicyEngine ──► TrustManager ──► AgentIdentity (Ed25519 DID) ──► AuditLogger ──► DecisionRecord
501
+ */
502
+ evaluateAction(params) {
503
+ const { workspace, actorId, tool, input, reason, stage } = params;
504
+ const ownerApproved = Boolean(params.ownerApproved);
505
+ const decidedAt = new Date().toISOString();
506
+ // 1. McpSecurityScanner + ContextPoisoningDetector (OWASP ASI-06): inspect tool definition + input arguments
507
+ const serializedInput = JSON.stringify(input || {});
508
+ const scanResult = this.scanner.scan({
509
+ name: tool.slug,
510
+ description: `${tool.description}\nReason: ${reason}\nArgs: ${serializedInput}`,
511
+ parameters: tool.inputSchema,
512
+ });
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
+ ];
532
+ // Additional argument-level prompt-injection / secret-exfiltration heuristics
533
+ const suspiciousPatterns = [
534
+ {
535
+ regex: /ignore\s+(all\s+)?previous\s+instructions/i,
536
+ category: "prompt_injection",
537
+ severity: "high",
538
+ description: "Detected prompt injection override phrase in tool arguments or reason",
539
+ },
540
+ {
541
+ regex: /(cat|curl|wget)\s+.*(\/etc\/passwd|\.env|id_rsa|AWS_SECRET_ACCESS_KEY)/i,
542
+ category: "credential_exfiltration",
543
+ severity: "high",
544
+ description: "Detected credential or sensitive file exfiltration pattern in arguments",
545
+ },
546
+ ];
547
+ for (const pat of suspiciousPatterns) {
548
+ if (pat.regex.test(serializedInput) || pat.regex.test(reason)) {
549
+ extraFindings.push({
550
+ category: pat.category,
551
+ severity: pat.severity,
552
+ description: pat.description,
553
+ });
554
+ }
555
+ }
556
+ const highSeverityFinding = extraFindings.some((f) => f.severity === "high" || f.severity === "critical");
557
+ // 2. Protocol Facets Extraction (SQL, Kubernetes, Infrastructure)
558
+ const protocolFacets = this.extractActionFacets(tool, input);
559
+ // 3. PolicyEngine + KillSwitch + Parameter Guardrail evaluation
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;
580
+ const policyEngine = this.createPolicyEngine(policy);
581
+ const identity = this.getWorkspaceIdentity(workspace);
582
+ const policyDecision = policyEngine.evaluatePolicy(identity.did, {
583
+ tool_slug: tool.slug,
584
+ risk_level: tool.riskLevel,
585
+ lane: tool.lane,
586
+ stage,
587
+ owner_approved: effectiveApproved,
588
+ workspace_active: true,
589
+ ...(protocolFacets.sql ? { sql: protocolFacets.sql } : {}),
590
+ ...(protocolFacets.k8s ? { k8s: protocolFacets.k8s } : {}),
591
+ ...(protocolFacets.infra ? { infra: protocolFacets.infra } : {}),
592
+ });
593
+ let finalDecision = policyDecision.action === "deny"
594
+ ? "deny"
595
+ : policyDecision.action === "require_approval"
596
+ ? "require_approval"
597
+ : "allow";
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") {
626
+ finalDecision = "deny";
627
+ matchedRule = "mcp-security-scanner-high-severity";
628
+ this.trustManager.recordFailure(workspace.id, 0.1);
629
+ }
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
636
+ const auditLogger = this.getWorkspaceAuditLogger(workspace.id);
637
+ const auditDecision = finalDecision === "deny" ? "deny" : "allow";
638
+ const auditEntry = auditLogger.log({
639
+ agentId: identity.did,
640
+ action: `${stage}.${tool.riskLevel}:${tool.slug}`,
641
+ decision: auditDecision,
642
+ skillAuditMetadata: {
643
+ skillName: tool.slug,
644
+ skillOrigin: tool.lane,
645
+ provenanceSourceTrust: trustScore.tier === "Verified" || trustScore.tier === "Trusted"
646
+ ? "trusted"
647
+ : undefined,
648
+ },
649
+ });
650
+ const chainVerified = auditLogger.verify();
651
+ // 6. AgentIdentity (Ed25519 DID): cryptographically sign the decision record
652
+ const bindingHash = crypto
653
+ .createHash("sha256")
654
+ .update(JSON.stringify({
655
+ workspaceId: workspace.id,
656
+ actorId,
657
+ toolSlug: tool.slug,
658
+ riskLevel: tool.riskLevel,
659
+ stage,
660
+ input,
661
+ finalDecision,
662
+ auditHash: auditEntry.hash,
663
+ decidedAt,
664
+ }))
665
+ .digest("hex");
666
+ const signaturePayload = [
667
+ POLICY_ID,
668
+ identity.did,
669
+ workspace.id,
670
+ actorId,
671
+ tool.slug,
672
+ tool.riskLevel,
673
+ finalDecision,
674
+ auditEntry.hash,
675
+ auditEntry.previousHash,
676
+ bindingHash,
677
+ decidedAt,
678
+ ].join("|");
679
+ const sigBytes = identity.sign(Buffer.from(signaturePayload, "utf8"));
680
+ const ed25519Signature = Buffer.from(sigBytes).toString("hex");
681
+ const publicKeyHex = Buffer.from(identity.publicKey).toString("hex");
682
+ const verdict = finalDecision === "require_approval" ? "escalate" : finalDecision;
683
+ const decisionReason = finalDecision === "deny"
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"}`
691
+ : finalDecision === "require_approval"
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 = {
697
+ id: `dec_${crypto.randomBytes(8).toString("hex")}`,
698
+ sdk: "@microsoft/agent-governance-sdk",
699
+ sdkVersion: SDK_VERSION,
700
+ policyId: POLICY_ID,
701
+ mode: policy.mode,
702
+ agentDid: identity.did,
703
+ agentPublicKey: publicKeyHex,
704
+ actorId,
705
+ workspaceId: workspace.id,
706
+ action: `${stage}.${tool.riskLevel}:${tool.slug}`,
707
+ riskLevel: tool.riskLevel,
708
+ decision: finalDecision,
709
+ verdict,
710
+ reason: decisionReason,
711
+ matchedRule,
712
+ securityScan: {
713
+ safe: scanResult.safe && !highSeverityFinding && contextPoisoning.safe,
714
+ riskLevel: highSeverityFinding
715
+ ? "high"
716
+ : scanResult.risk_score > 50 || contextPoisoning.findingsCount > 0
717
+ ? "medium"
718
+ : "low",
719
+ findingsCount: extraFindings.length,
720
+ findings: extraFindings,
721
+ },
722
+ auditEntry: {
723
+ timestamp: auditEntry.timestamp,
724
+ agentId: auditEntry.agentId,
725
+ action: auditEntry.action,
726
+ decision: auditDecision,
727
+ hash: auditEntry.hash,
728
+ previousHash: auditEntry.previousHash,
729
+ chainVerified,
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
+ },
745
+ ed25519Signature,
746
+ signature: ed25519Signature,
747
+ bindingHash,
748
+ decidedAt,
749
+ };
750
+ record.explanation = explainDecisionRecord(record, policy);
751
+ return record;
752
+ }
753
+ evaluatePlan(params) {
754
+ return this.evaluateAction({
755
+ ...params,
756
+ stage: "plan",
757
+ });
758
+ }
759
+ evaluateExecution(params) {
760
+ return this.evaluateAction({
761
+ workspace: params.workspace,
762
+ actorId: params.actorId,
763
+ tool: params.tool,
764
+ input: params.plan.input,
765
+ reason: params.plan.reason,
766
+ stage: "execute",
767
+ ownerApproved: params.plan.approvalStatus === "approved" ||
768
+ params.plan.approvalStatus === "auto_approved",
769
+ });
770
+ }
771
+ /**
772
+ * Verifies a DecisionRecord's Ed25519 signature and the workspace's SHA-256 audit hash chain.
773
+ */
774
+ verifyDecisionRecord(workspaceOrRecord, maybeRecord) {
775
+ const record = maybeRecord || workspaceOrRecord;
776
+ const workspace = maybeRecord ? workspaceOrRecord : undefined;
777
+ const identity = workspace
778
+ ? this.getWorkspaceIdentity(workspace)
779
+ : this.identities.get(record.workspaceId) || this.defaultIdentity;
780
+ const stagePrefix = record.action.split(":")[0] || "";
781
+ const toolSlug = record.action.slice(stagePrefix.length + 1);
782
+ const signaturePayload = [
783
+ record.policyId,
784
+ record.agentDid,
785
+ record.workspaceId,
786
+ record.actorId,
787
+ toolSlug,
788
+ record.riskLevel,
789
+ record.decision,
790
+ record.auditEntry.hash,
791
+ record.auditEntry.previousHash,
792
+ record.bindingHash,
793
+ record.decidedAt,
794
+ ].join("|");
795
+ let ed25519Verified = false;
796
+ try {
797
+ if (identity.did === record.agentDid) {
798
+ ed25519Verified = identity.verify(Buffer.from(signaturePayload, "utf8"), Buffer.from(record.ed25519Signature, "hex"));
799
+ }
800
+ else if (record.agentPublicKey && record.ed25519Signature) {
801
+ const pubKeyObj = crypto.createPublicKey({
802
+ key: Buffer.from(record.agentPublicKey, "hex"),
803
+ format: "der",
804
+ type: "spki",
805
+ });
806
+ ed25519Verified = crypto.verify(null, Buffer.from(signaturePayload, "utf8"), pubKeyObj, Buffer.from(record.ed25519Signature, "hex"));
807
+ }
808
+ }
809
+ catch {
810
+ ed25519Verified = false;
811
+ }
812
+ const auditLogger = this.getWorkspaceAuditLogger(record.workspaceId);
813
+ const auditChainVerified = auditLogger.verify();
814
+ return ed25519Verified && auditChainVerified;
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
+ }
922
+ getStatus(workspace) {
923
+ const identity = workspace
924
+ ? this.getWorkspaceIdentity(workspace)
925
+ : this.identities.values().next().value || this.defaultIdentity;
926
+ let totalEntries = 0;
927
+ let allVerified = true;
928
+ for (const logger of this.auditLoggers.values()) {
929
+ totalEntries += logger.length;
930
+ if (!logger.verify())
931
+ allVerified = false;
932
+ }
933
+ return {
934
+ sdk: "@microsoft/agent-governance-sdk",
935
+ sdkVersion: SDK_VERSION,
936
+ policyId: POLICY_ID,
937
+ pipeline: "Agent ──► McpSecurityScanner ──► PolicyEngine ──► AgentIdentity (Ed25519 DID) ──► AuditLogger ──► DecisionRecord",
938
+ agentDid: identity.did,
939
+ publicKeyHex: Buffer.from(identity.publicKey).toString("hex"),
940
+ auditEntriesCount: totalEntries,
941
+ auditChainIntegrity: allVerified,
942
+ };
943
+ }
944
+ /**
945
+ * Returns a live governance status report for a workspace.
946
+ */
947
+ getGovernanceStatus(workspace) {
948
+ const identity = this.getWorkspaceIdentity(workspace);
949
+ const auditLogger = this.getWorkspaceAuditLogger(workspace.id);
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");
954
+ return {
955
+ sdk: "@microsoft/agent-governance-sdk",
956
+ sdkVersion: SDK_VERSION,
957
+ policyId: POLICY_ID,
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
+ ],
970
+ agentIdentity: identity.toJSON(),
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
+ },
986
+ auditChain: {
987
+ entriesCount: entries.length,
988
+ chainVerified: auditLogger.verify(),
989
+ recentEntries: entries.slice(-15).reverse(),
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
+ }),
1004
+ };
1005
+ }
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
+ }