vaspera 2.7.0 → 2.9.0

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 (321) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/README.md +111 -7
  3. package/dist/__tests__/agents/adversary/tactics/api.test.d.ts +5 -0
  4. package/dist/__tests__/agents/adversary/tactics/api.test.d.ts.map +1 -0
  5. package/dist/__tests__/agents/adversary/tactics/api.test.js +369 -0
  6. package/dist/__tests__/agents/adversary/tactics/api.test.js.map +1 -0
  7. package/dist/__tests__/agents/adversary/tactics/llm.test.d.ts +5 -0
  8. package/dist/__tests__/agents/adversary/tactics/llm.test.d.ts.map +1 -0
  9. package/dist/__tests__/agents/adversary/tactics/llm.test.js +409 -0
  10. package/dist/__tests__/agents/adversary/tactics/llm.test.js.map +1 -0
  11. package/dist/__tests__/agents/adversary/tactics/registry.test.d.ts +7 -0
  12. package/dist/__tests__/agents/adversary/tactics/registry.test.d.ts.map +1 -0
  13. package/dist/__tests__/agents/adversary/tactics/registry.test.js +74 -0
  14. package/dist/__tests__/agents/adversary/tactics/registry.test.js.map +1 -0
  15. package/dist/__tests__/agents/adversary/tactics/web-app.test.d.ts +7 -0
  16. package/dist/__tests__/agents/adversary/tactics/web-app.test.d.ts.map +1 -0
  17. package/dist/__tests__/agents/adversary/tactics/web-app.test.js +374 -0
  18. package/dist/__tests__/agents/adversary/tactics/web-app.test.js.map +1 -0
  19. package/dist/__tests__/compliance-bundle.test.d.ts +9 -0
  20. package/dist/__tests__/compliance-bundle.test.d.ts.map +1 -0
  21. package/dist/__tests__/compliance-bundle.test.js +344 -0
  22. package/dist/__tests__/compliance-bundle.test.js.map +1 -0
  23. package/dist/__tests__/healthcare-compliance.test.d.ts +9 -0
  24. package/dist/__tests__/healthcare-compliance.test.d.ts.map +1 -0
  25. package/dist/__tests__/healthcare-compliance.test.js +233 -0
  26. package/dist/__tests__/healthcare-compliance.test.js.map +1 -0
  27. package/dist/action/diff-mode.d.ts +124 -8
  28. package/dist/action/diff-mode.d.ts.map +1 -1
  29. package/dist/action/diff-mode.js +384 -65
  30. package/dist/action/diff-mode.js.map +1 -1
  31. package/dist/action/diff-mode.test.js +3 -3
  32. package/dist/action/diff-mode.test.js.map +1 -1
  33. package/dist/action/pr-comment.test.js +1 -0
  34. package/dist/action/pr-comment.test.js.map +1 -1
  35. package/dist/action/sarif-upload.test.js +1 -0
  36. package/dist/action/sarif-upload.test.js.map +1 -1
  37. package/dist/agents/adversary/config.d.ts +113 -0
  38. package/dist/agents/adversary/config.d.ts.map +1 -0
  39. package/dist/agents/adversary/config.js +391 -0
  40. package/dist/agents/adversary/config.js.map +1 -0
  41. package/dist/agents/adversary/index.d.ts +41 -0
  42. package/dist/agents/adversary/index.d.ts.map +1 -0
  43. package/dist/agents/adversary/index.js +838 -0
  44. package/dist/agents/adversary/index.js.map +1 -0
  45. package/dist/agents/adversary/reporting/compliance-mapper.d.ts +108 -0
  46. package/dist/agents/adversary/reporting/compliance-mapper.d.ts.map +1 -0
  47. package/dist/agents/adversary/reporting/compliance-mapper.js +391 -0
  48. package/dist/agents/adversary/reporting/compliance-mapper.js.map +1 -0
  49. package/dist/agents/adversary/reporting/index.d.ts +10 -0
  50. package/dist/agents/adversary/reporting/index.d.ts.map +1 -0
  51. package/dist/agents/adversary/reporting/index.js +10 -0
  52. package/dist/agents/adversary/reporting/index.js.map +1 -0
  53. package/dist/agents/adversary/reporting/poc-generator.d.ts +44 -0
  54. package/dist/agents/adversary/reporting/poc-generator.d.ts.map +1 -0
  55. package/dist/agents/adversary/reporting/poc-generator.js +308 -0
  56. package/dist/agents/adversary/reporting/poc-generator.js.map +1 -0
  57. package/dist/agents/adversary/tactics/api.d.ts +13 -0
  58. package/dist/agents/adversary/tactics/api.d.ts.map +1 -0
  59. package/dist/agents/adversary/tactics/api.js +815 -0
  60. package/dist/agents/adversary/tactics/api.js.map +1 -0
  61. package/dist/agents/adversary/tactics/auth.d.ts +13 -0
  62. package/dist/agents/adversary/tactics/auth.d.ts.map +1 -0
  63. package/dist/agents/adversary/tactics/auth.js +676 -0
  64. package/dist/agents/adversary/tactics/auth.js.map +1 -0
  65. package/dist/agents/adversary/tactics/index.d.ts +129 -0
  66. package/dist/agents/adversary/tactics/index.d.ts.map +1 -0
  67. package/dist/agents/adversary/tactics/index.js +199 -0
  68. package/dist/agents/adversary/tactics/index.js.map +1 -0
  69. package/dist/agents/adversary/tactics/infra.d.ts +13 -0
  70. package/dist/agents/adversary/tactics/infra.d.ts.map +1 -0
  71. package/dist/agents/adversary/tactics/infra.js +827 -0
  72. package/dist/agents/adversary/tactics/infra.js.map +1 -0
  73. package/dist/agents/adversary/tactics/injection.d.ts +12 -0
  74. package/dist/agents/adversary/tactics/injection.d.ts.map +1 -0
  75. package/dist/agents/adversary/tactics/injection.js +549 -0
  76. package/dist/agents/adversary/tactics/injection.js.map +1 -0
  77. package/dist/agents/adversary/tactics/llm.d.ts +13 -0
  78. package/dist/agents/adversary/tactics/llm.d.ts.map +1 -0
  79. package/dist/agents/adversary/tactics/llm.js +767 -0
  80. package/dist/agents/adversary/tactics/llm.js.map +1 -0
  81. package/dist/agents/adversary/tactics/web-app.d.ts +13 -0
  82. package/dist/agents/adversary/tactics/web-app.d.ts.map +1 -0
  83. package/dist/agents/adversary/tactics/web-app.js +717 -0
  84. package/dist/agents/adversary/tactics/web-app.js.map +1 -0
  85. package/dist/agents/adversary/types.d.ts +407 -0
  86. package/dist/agents/adversary/types.d.ts.map +1 -0
  87. package/dist/agents/adversary/types.js +12 -0
  88. package/dist/agents/adversary/types.js.map +1 -0
  89. package/dist/agents/index.d.ts +1 -0
  90. package/dist/agents/index.d.ts.map +1 -1
  91. package/dist/agents/index.js +2 -0
  92. package/dist/agents/index.js.map +1 -1
  93. package/dist/agents/zero-day-hunter.d.ts +1 -1
  94. package/dist/agents/zero-day-hunter.d.ts.map +1 -1
  95. package/dist/analysis/data-flow.d.ts +154 -0
  96. package/dist/analysis/data-flow.d.ts.map +1 -0
  97. package/dist/analysis/data-flow.js +393 -0
  98. package/dist/analysis/data-flow.js.map +1 -0
  99. package/dist/analysis/index.d.ts +9 -0
  100. package/dist/analysis/index.d.ts.map +1 -0
  101. package/dist/analysis/index.js +9 -0
  102. package/dist/analysis/index.js.map +1 -0
  103. package/dist/badge-service/index.d.ts +144 -0
  104. package/dist/badge-service/index.d.ts.map +1 -0
  105. package/dist/badge-service/index.js +206 -0
  106. package/dist/badge-service/index.js.map +1 -0
  107. package/dist/certification/consensus.test.js +2 -0
  108. package/dist/certification/consensus.test.js.map +1 -1
  109. package/dist/certification/store.d.ts.map +1 -1
  110. package/dist/certification/store.js +4 -0
  111. package/dist/certification/store.js.map +1 -1
  112. package/dist/certification/types.d.ts +3 -3
  113. package/dist/certification/types.d.ts.map +1 -1
  114. package/dist/certification/types.js +2 -0
  115. package/dist/certification/types.js.map +1 -1
  116. package/dist/commands/certification/certify.d.ts.map +1 -1
  117. package/dist/commands/certification/certify.js +18 -4
  118. package/dist/commands/certification/certify.js.map +1 -1
  119. package/dist/compliance/attestation.d.ts +39 -0
  120. package/dist/compliance/attestation.d.ts.map +1 -0
  121. package/dist/compliance/attestation.js +364 -0
  122. package/dist/compliance/attestation.js.map +1 -0
  123. package/dist/compliance/cfr42-part2.d.ts +42 -0
  124. package/dist/compliance/cfr42-part2.d.ts.map +1 -0
  125. package/dist/compliance/cfr42-part2.js +408 -0
  126. package/dist/compliance/cfr42-part2.js.map +1 -0
  127. package/dist/compliance/compliance-bundle.d.ts +100 -0
  128. package/dist/compliance/compliance-bundle.d.ts.map +1 -0
  129. package/dist/compliance/compliance-bundle.js +210 -0
  130. package/dist/compliance/compliance-bundle.js.map +1 -0
  131. package/dist/compliance/healthcare-bundle.d.ts +68 -0
  132. package/dist/compliance/healthcare-bundle.d.ts.map +1 -0
  133. package/dist/compliance/healthcare-bundle.js +104 -0
  134. package/dist/compliance/healthcare-bundle.js.map +1 -0
  135. package/dist/compliance/hipaa.d.ts.map +1 -1
  136. package/dist/compliance/hipaa.js +14 -11
  137. package/dist/compliance/hipaa.js.map +1 -1
  138. package/dist/compliance/index.d.ts +10 -2
  139. package/dist/compliance/index.d.ts.map +1 -1
  140. package/dist/compliance/index.js +9 -3
  141. package/dist/compliance/index.js.map +1 -1
  142. package/dist/compliance/mapper.d.ts.map +1 -1
  143. package/dist/compliance/mapper.js +3 -17
  144. package/dist/compliance/mapper.js.map +1 -1
  145. package/dist/compliance/nist-800-53.d.ts +22 -6
  146. package/dist/compliance/nist-800-53.d.ts.map +1 -1
  147. package/dist/compliance/nist-800-53.js +264 -272
  148. package/dist/compliance/nist-800-53.js.map +1 -1
  149. package/dist/compliance/report.d.ts +31 -2
  150. package/dist/compliance/report.d.ts.map +1 -1
  151. package/dist/compliance/report.js +255 -4
  152. package/dist/compliance/report.js.map +1 -1
  153. package/dist/compliance/types.d.ts +1 -1
  154. package/dist/compliance/types.d.ts.map +1 -1
  155. package/dist/config/flags.d.ts +12 -12
  156. package/dist/cost/index.d.ts +1 -1
  157. package/dist/cost/index.d.ts.map +1 -1
  158. package/dist/cost/index.js +1 -1
  159. package/dist/cost/index.js.map +1 -1
  160. package/dist/cost/tracker.d.ts +64 -0
  161. package/dist/cost/tracker.d.ts.map +1 -1
  162. package/dist/cost/tracker.js +165 -0
  163. package/dist/cost/tracker.js.map +1 -1
  164. package/dist/eval/fixtures/healthcare/audit-gaps.d.ts +28 -0
  165. package/dist/eval/fixtures/healthcare/audit-gaps.d.ts.map +1 -0
  166. package/dist/eval/fixtures/healthcare/audit-gaps.js +90 -0
  167. package/dist/eval/fixtures/healthcare/audit-gaps.js.map +1 -0
  168. package/dist/eval/fixtures/healthcare/consent-bypass.d.ts +31 -0
  169. package/dist/eval/fixtures/healthcare/consent-bypass.d.ts.map +1 -0
  170. package/dist/eval/fixtures/healthcare/consent-bypass.js +61 -0
  171. package/dist/eval/fixtures/healthcare/consent-bypass.js.map +1 -0
  172. package/dist/eval/fixtures/healthcare/phi-in-logs.d.ts +24 -0
  173. package/dist/eval/fixtures/healthcare/phi-in-logs.d.ts.map +1 -0
  174. package/dist/eval/fixtures/healthcare/phi-in-logs.js +41 -0
  175. package/dist/eval/fixtures/healthcare/phi-in-logs.js.map +1 -0
  176. package/dist/evidence/collector.d.ts +21 -0
  177. package/dist/evidence/collector.d.ts.map +1 -0
  178. package/dist/evidence/collector.js +340 -0
  179. package/dist/evidence/collector.js.map +1 -0
  180. package/dist/evidence/index.d.ts +11 -0
  181. package/dist/evidence/index.d.ts.map +1 -0
  182. package/dist/evidence/index.js +12 -0
  183. package/dist/evidence/index.js.map +1 -0
  184. package/dist/evidence/store.d.ts +39 -0
  185. package/dist/evidence/store.d.ts.map +1 -0
  186. package/dist/evidence/store.js +173 -0
  187. package/dist/evidence/store.js.map +1 -0
  188. package/dist/evidence/types.d.ts +175 -0
  189. package/dist/evidence/types.d.ts.map +1 -0
  190. package/dist/evidence/types.js +9 -0
  191. package/dist/evidence/types.js.map +1 -0
  192. package/dist/exporters/checkmarx.d.ts +18 -0
  193. package/dist/exporters/checkmarx.d.ts.map +1 -0
  194. package/dist/exporters/checkmarx.js +203 -0
  195. package/dist/exporters/checkmarx.js.map +1 -0
  196. package/dist/exporters/index.d.ts +22 -0
  197. package/dist/exporters/index.d.ts.map +1 -0
  198. package/dist/exporters/index.js +41 -0
  199. package/dist/exporters/index.js.map +1 -0
  200. package/dist/exporters/snyk.d.ts +18 -0
  201. package/dist/exporters/snyk.d.ts.map +1 -0
  202. package/dist/exporters/snyk.js +119 -0
  203. package/dist/exporters/snyk.js.map +1 -0
  204. package/dist/exporters/sonarqube.d.ts +18 -0
  205. package/dist/exporters/sonarqube.d.ts.map +1 -0
  206. package/dist/exporters/sonarqube.js +125 -0
  207. package/dist/exporters/sonarqube.js.map +1 -0
  208. package/dist/exporters/types.d.ts +190 -0
  209. package/dist/exporters/types.d.ts.map +1 -0
  210. package/dist/exporters/types.js +9 -0
  211. package/dist/exporters/types.js.map +1 -0
  212. package/dist/frontier/index.d.ts +12 -0
  213. package/dist/frontier/index.d.ts.map +1 -0
  214. package/dist/frontier/index.js +12 -0
  215. package/dist/frontier/index.js.map +1 -0
  216. package/dist/frontier/orchestrator.d.ts +73 -0
  217. package/dist/frontier/orchestrator.d.ts.map +1 -0
  218. package/dist/frontier/orchestrator.js +312 -0
  219. package/dist/frontier/orchestrator.js.map +1 -0
  220. package/dist/frontier/providers/stub.d.ts +32 -0
  221. package/dist/frontier/providers/stub.d.ts.map +1 -0
  222. package/dist/frontier/providers/stub.js +66 -0
  223. package/dist/frontier/providers/stub.js.map +1 -0
  224. package/dist/frontier/types.d.ts +318 -0
  225. package/dist/frontier/types.d.ts.map +1 -0
  226. package/dist/frontier/types.js +27 -0
  227. package/dist/frontier/types.js.map +1 -0
  228. package/dist/history/index.d.ts +13 -0
  229. package/dist/history/index.d.ts.map +1 -0
  230. package/dist/history/index.js +15 -0
  231. package/dist/history/index.js.map +1 -0
  232. package/dist/history/store.d.ts +74 -0
  233. package/dist/history/store.d.ts.map +1 -0
  234. package/dist/history/store.js +399 -0
  235. package/dist/history/store.js.map +1 -0
  236. package/dist/history/types.d.ts +282 -0
  237. package/dist/history/types.d.ts.map +1 -0
  238. package/dist/history/types.js +41 -0
  239. package/dist/history/types.js.map +1 -0
  240. package/dist/history/verify.d.ts +44 -0
  241. package/dist/history/verify.d.ts.map +1 -0
  242. package/dist/history/verify.js +230 -0
  243. package/dist/history/verify.js.map +1 -0
  244. package/dist/index.d.ts.map +1 -1
  245. package/dist/index.js +431 -18
  246. package/dist/index.js.map +1 -1
  247. package/dist/multimodel/index.d.ts +1 -0
  248. package/dist/multimodel/index.d.ts.map +1 -1
  249. package/dist/multimodel/index.js +2 -0
  250. package/dist/multimodel/index.js.map +1 -1
  251. package/dist/multimodel/leaderboard.d.ts +116 -0
  252. package/dist/multimodel/leaderboard.d.ts.map +1 -0
  253. package/dist/multimodel/leaderboard.js +262 -0
  254. package/dist/multimodel/leaderboard.js.map +1 -0
  255. package/dist/observability/otel.d.ts.map +1 -1
  256. package/dist/observability/otel.js +1 -3
  257. package/dist/observability/otel.js.map +1 -1
  258. package/dist/plugins/loader.js +1 -1
  259. package/dist/plugins/loader.js.map +1 -1
  260. package/dist/sbom/provenance.test.js +2 -2
  261. package/dist/sbom/provenance.test.js.map +1 -1
  262. package/dist/scanners/agent/agent-chain-analysis.d.ts +152 -0
  263. package/dist/scanners/agent/agent-chain-analysis.d.ts.map +1 -0
  264. package/dist/scanners/agent/agent-chain-analysis.js +438 -0
  265. package/dist/scanners/agent/agent-chain-analysis.js.map +1 -0
  266. package/dist/scanners/agent/manifest-audit.d.ts.map +1 -1
  267. package/dist/scanners/agent/manifest-audit.js +30 -18
  268. package/dist/scanners/agent/manifest-audit.js.map +1 -1
  269. package/dist/scanners/agent/payloads/index.d.ts +2 -1
  270. package/dist/scanners/agent/payloads/index.d.ts.map +1 -1
  271. package/dist/scanners/agent/payloads/index.js +25 -6
  272. package/dist/scanners/agent/payloads/index.js.map +1 -1
  273. package/dist/scanners/agent/prompt-injection-fuzzer.d.ts.map +1 -1
  274. package/dist/scanners/agent/prompt-injection-fuzzer.js +14 -0
  275. package/dist/scanners/agent/prompt-injection-fuzzer.js.map +1 -1
  276. package/dist/scanners/agent/types.d.ts +5 -5
  277. package/dist/scanners/agent/types.d.ts.map +1 -1
  278. package/dist/scanners/agent/types.js.map +1 -1
  279. package/dist/scanners/cache.d.ts +156 -0
  280. package/dist/scanners/cache.d.ts.map +1 -0
  281. package/dist/scanners/cache.js +462 -0
  282. package/dist/scanners/cache.js.map +1 -0
  283. package/dist/scanners/dependencies.d.ts.map +1 -1
  284. package/dist/scanners/dependencies.js +5 -6
  285. package/dist/scanners/dependencies.js.map +1 -1
  286. package/dist/scanners/gosec.d.ts.map +1 -1
  287. package/dist/scanners/gosec.js +47 -9
  288. package/dist/scanners/gosec.js.map +1 -1
  289. package/dist/scanners/healthcare.d.ts +29 -0
  290. package/dist/scanners/healthcare.d.ts.map +1 -0
  291. package/dist/scanners/healthcare.js +526 -0
  292. package/dist/scanners/healthcare.js.map +1 -0
  293. package/dist/scanners/index.d.ts +1 -0
  294. package/dist/scanners/index.d.ts.map +1 -1
  295. package/dist/scanners/index.js +33 -0
  296. package/dist/scanners/index.js.map +1 -1
  297. package/dist/scanners/index.test.js +6 -6
  298. package/dist/scanners/index.test.js.map +1 -1
  299. package/dist/scanners/secrets.js +4 -4
  300. package/dist/scanners/secrets.js.map +1 -1
  301. package/dist/scanners/semgrep.js +5 -5
  302. package/dist/scanners/semgrep.js.map +1 -1
  303. package/dist/scanners/types.d.ts +1 -1
  304. package/dist/scanners/types.d.ts.map +1 -1
  305. package/dist/scanners/types.js +1 -0
  306. package/dist/scanners/types.js.map +1 -1
  307. package/dist/scanners/typescript.test.js +1 -1
  308. package/dist/scanners/typescript.test.js.map +1 -1
  309. package/dist/telemetry/index.d.ts +10 -0
  310. package/dist/telemetry/index.d.ts.map +1 -0
  311. package/dist/telemetry/index.js +10 -0
  312. package/dist/telemetry/index.js.map +1 -0
  313. package/dist/telemetry/registry.d.ts +178 -0
  314. package/dist/telemetry/registry.d.ts.map +1 -0
  315. package/dist/telemetry/registry.js +297 -0
  316. package/dist/telemetry/registry.js.map +1 -0
  317. package/dist/telemetry/usage.d.ts +197 -0
  318. package/dist/telemetry/usage.d.ts.map +1 -0
  319. package/dist/telemetry/usage.js +244 -0
  320. package/dist/telemetry/usage.js.map +1 -0
  321. package/package.json +11 -2
package/dist/index.js CHANGED
@@ -30,13 +30,22 @@ import { getAIFrameworkControls, AI_FRAMEWORKS_METADATA, } from "./compliance/fr
30
30
  // Evaluation harness
31
31
  import { runEvaluation, runStabilityTest, calculateMetrics, calculateStabilityMetrics, meetsTargets, generateEvaluationReport, formatReportAsMarkdown, generateCompactSummary, generateReadmeBadges, getFixtureStats, ALL_FIXTURES, TARGET_METRICS, } from "./eval/index.js";
32
32
  // Compliance frameworks
33
- import { generateComplianceReport, generateMultiFrameworkReport, formatComplianceReportAsMarkdown, formatMultiFrameworkReportAsMarkdown, generateCompactComplianceSummary, getControlsForFramework, getSOC2Categories, getISO27001Categories, } from "./compliance/index.js";
33
+ import { generateComplianceReport, generateMultiFrameworkReport, formatComplianceReportAsMarkdown, formatMultiFrameworkReportAsMarkdown, generateCompactComplianceSummary, getControlsForFramework,
34
+ // Healthcare compliance
35
+ runHealthcareComplianceAssessment, generateHealthcareComplianceSummary,
36
+ // Universal audit-defensible compliance
37
+ runSingleFrameworkAssessment, runComplianceAssessment, generateComplianceSummary, } from "./compliance/index.js";
38
+ // Evidence collection and audit trail verification
39
+ import { collectEvidence, storeEvidenceBundle, formatEvidenceBundleAsMarkdown, } from "./evidence/index.js";
40
+ import { verifyHistoryIntegrity, formatVerificationResultAsMarkdown, } from "./history/verify.js";
34
41
  // SBOM, Provenance, and Sigstore Signing (uses @sigstore/sign for real signing)
35
42
  import { generateSBOM, generateSBOMSummary, generateProvenance, generateProvenanceSummary, verifyProvenance, signContent, isSigningAvailable, generateSigningSummary, detectCIEnvironment, } from "./sbom/index.js";
36
43
  // Cost tracking
37
44
  import { getTracker, formatCost, formatTokens, estimateCost, getSupportedModels, MODEL_PRICING, } from "./cost/index.js";
38
45
  // Multi-model consensus
39
46
  import { getRunner, DEFAULT_MODELS, formatProvider, } from "./multimodel/index.js";
47
+ // Path validation utilities
48
+ import { validateProjectPath, PathValidationError } from "./util/paths.js";
40
49
  // ---------------------------------------------------------------------------
41
50
  // Config
42
51
  // ---------------------------------------------------------------------------
@@ -221,7 +230,17 @@ server.registerTool("hardening_install", {
221
230
  openWorldHint: false,
222
231
  },
223
232
  }, async ({ project_path }) => {
224
- if (!(await dirExists(project_path))) {
233
+ // Validate path to prevent traversal attacks
234
+ let validatedPath;
235
+ try {
236
+ validatedPath = await validateProjectPath(project_path);
237
+ }
238
+ catch (error) {
239
+ if (error instanceof PathValidationError) {
240
+ return {
241
+ content: [{ type: "text", text: `Error: ${error.message}` }],
242
+ };
243
+ }
225
244
  return {
226
245
  content: [
227
246
  {
@@ -232,7 +251,7 @@ server.registerTool("hardening_install", {
232
251
  };
233
252
  }
234
253
  try {
235
- const commandsDir = join(project_path, ".claude", "commands");
254
+ const commandsDir = join(validatedPath, ".claude", "commands");
236
255
  await mkdir(commandsDir, { recursive: true });
237
256
  const installed = [];
238
257
  const errors = [];
@@ -248,7 +267,7 @@ server.registerTool("hardening_install", {
248
267
  }
249
268
  }
250
269
  const output = {
251
- project: project_path,
270
+ project: validatedPath,
252
271
  commands_dir: commandsDir,
253
272
  installed_commands: installed,
254
273
  errors: errors.length > 0 ? errors : undefined,
@@ -295,7 +314,17 @@ server.registerTool("hardening_install_all", {
295
314
  },
296
315
  }, async ({ base_dir, dry_run = true }) => {
297
316
  const dir = base_dir || DEFAULT_PROJECTS_DIR;
298
- if (!(await dirExists(dir))) {
317
+ // Validate path to prevent traversal attacks
318
+ let validatedDir;
319
+ try {
320
+ validatedDir = await validateProjectPath(dir);
321
+ }
322
+ catch (error) {
323
+ if (error instanceof PathValidationError) {
324
+ return {
325
+ content: [{ type: "text", text: `Error: ${error.message}` }],
326
+ };
327
+ }
299
328
  return {
300
329
  content: [
301
330
  {
@@ -306,7 +335,7 @@ server.registerTool("hardening_install_all", {
306
335
  };
307
336
  }
308
337
  try {
309
- const projects = await discoverProjects(dir);
338
+ const projects = await discoverProjects(validatedDir);
310
339
  const commandCount = Object.keys(COMMANDS).length;
311
340
  const results = [];
312
341
  for (const projectPath of projects) {
@@ -347,7 +376,7 @@ server.registerTool("hardening_install_all", {
347
376
  }
348
377
  const output = {
349
378
  mode: dry_run ? "dry-run" : "applied",
350
- base_dir: dir,
379
+ base_dir: validatedDir,
351
380
  projects_scanned: projects.length,
352
381
  commands_per_project: commandCount,
353
382
  projects_updated: dry_run ? 0 : results.filter((r) => !r.error && r.commands_installed).length,
@@ -1247,6 +1276,87 @@ server.registerTool("agent_complete", {
1247
1276
  };
1248
1277
  });
1249
1278
  // ---------------------------------------------------------------------------
1279
+ // Tool: Batch Submit Findings (for subagent JSON output)
1280
+ // ---------------------------------------------------------------------------
1281
+ server.registerTool("agent_batch_submit", {
1282
+ title: "Batch Submit Agent Findings",
1283
+ description: `Submit multiple findings from a subagent's JSON output. Use this when certification agents run as subagents (via Task tool) and output JSON instead of calling agent_submit_finding directly. Parses the agent's JSON output and submits all findings at once.`,
1284
+ inputSchema: {
1285
+ project_path: z.string().describe("Absolute path to the project root"),
1286
+ certification_id: z.string().describe("Certification ID"),
1287
+ agent: z.enum(["security", "reliability", "typesafety", "performance", "quality", "redteam"]),
1288
+ findings: z.array(z.object({
1289
+ id: z.string().describe("Finding ID (e.g., sec-001)"),
1290
+ severity: z.enum(["critical", "high", "medium", "low", "info"]),
1291
+ category: z.string().describe("Category of the finding"),
1292
+ file: z.string().optional().describe("File path where issue found"),
1293
+ line: z.number().optional().describe("Line number"),
1294
+ description: z.string().describe("Description of the issue"),
1295
+ evidence: z.string().describe("Evidence supporting the finding"),
1296
+ confidence: z.number().min(0).max(100).describe("Confidence score 0-100"),
1297
+ })).describe("Array of findings from subagent JSON output"),
1298
+ summary: z.object({
1299
+ total_findings: z.number(),
1300
+ by_severity: z.object({
1301
+ critical: z.number(),
1302
+ high: z.number(),
1303
+ medium: z.number(),
1304
+ low: z.number(),
1305
+ info: z.number(),
1306
+ }),
1307
+ confidence_score: z.number().min(0).max(100),
1308
+ coverage_areas: z.array(z.string()),
1309
+ notes: z.string().optional(),
1310
+ }).optional().describe("Optional summary to complete the agent run"),
1311
+ },
1312
+ annotations: {
1313
+ readOnlyHint: false,
1314
+ destructiveHint: false,
1315
+ idempotentHint: false,
1316
+ openWorldHint: false,
1317
+ },
1318
+ }, async ({ project_path, certification_id, agent, findings, summary }) => {
1319
+ const certLogger = createChildLogger({ certId: certification_id, agent });
1320
+ // Ensure agent is started
1321
+ let agentFindings = await getAgentFindings(project_path, certification_id, agent);
1322
+ if (!agentFindings) {
1323
+ certLogger.info("agent.started");
1324
+ agentFindings = await startAgent(project_path, certification_id, agent);
1325
+ }
1326
+ // Submit all findings
1327
+ const submitted = [];
1328
+ for (const finding of findings) {
1329
+ await submitFinding(project_path, certification_id, agent, finding);
1330
+ submitted.push({ id: finding.id, severity: finding.severity });
1331
+ certLogger.info("finding.submitted", {
1332
+ findingId: finding.id,
1333
+ severity: finding.severity,
1334
+ confidence: finding.confidence,
1335
+ });
1336
+ }
1337
+ // Complete agent if summary provided
1338
+ let completionResult = null;
1339
+ if (summary) {
1340
+ completionResult = await completeAgent(project_path, certification_id, agent, summary);
1341
+ certLogger.info("agent.completed", {
1342
+ totalFindings: summary.total_findings,
1343
+ confidenceScore: summary.confidence_score,
1344
+ });
1345
+ }
1346
+ return {
1347
+ content: [{
1348
+ type: "text",
1349
+ text: JSON.stringify({
1350
+ agent,
1351
+ findingsSubmitted: submitted.length,
1352
+ findings: submitted,
1353
+ completed: !!summary,
1354
+ summary: completionResult?.summary,
1355
+ }, null, 2),
1356
+ }],
1357
+ };
1358
+ });
1359
+ // ---------------------------------------------------------------------------
1250
1360
  // Tool: Cross-Verify Finding
1251
1361
  // ---------------------------------------------------------------------------
1252
1362
  server.registerTool("agent_cross_verify", {
@@ -2142,13 +2252,17 @@ server.registerTool("certification_eval_fixtures", {
2142
2252
  // ---------------------------------------------------------------------------
2143
2253
  server.registerTool("compliance_report", {
2144
2254
  title: "Generate Compliance Report",
2145
- description: `Generate a compliance report mapping certification findings to framework controls (SOC 2, ISO 27001). Shows which controls are at risk or non-compliant based on security findings.`,
2255
+ description: `Generate a compliance report mapping certification findings to framework controls. Supports all major frameworks (SOC 2, ISO 27001, PCI-DSS, HIPAA, 42 CFR Part 2, GDPR, NIST 800-53, CIS). Enable audit-defensibility options for evidence collection and audit trail verification.`,
2146
2256
  inputSchema: {
2147
2257
  project_path: z.string().describe("Absolute path to the project root"),
2148
2258
  certification_id: z.string().describe("Certification ID to assess"),
2149
2259
  framework: z
2150
- .enum(["SOC2", "ISO27001"])
2260
+ .enum(["SOC2", "ISO27001", "PCI-DSS", "HIPAA", "42-CFR-PART-2", "GDPR", "NIST-800-53", "CIS"])
2151
2261
  .describe("Compliance framework to assess"),
2262
+ collect_evidence: z.boolean().optional().describe("Collect evidence bundle for audit defensibility. Default: false"),
2263
+ verify_audit_trail: z.boolean().optional().describe("Verify audit trail integrity. Default: false"),
2264
+ store_evidence: z.boolean().optional().describe("Store evidence bundle to disk. Default: true if collecting"),
2265
+ include_attestation: z.boolean().optional().describe("Include attestation section with methodology and scope. Default: true when audit features enabled"),
2152
2266
  output_format: z
2153
2267
  .enum(["markdown", "json", "summary"])
2154
2268
  .optional()
@@ -2160,7 +2274,7 @@ server.registerTool("compliance_report", {
2160
2274
  idempotentHint: true,
2161
2275
  openWorldHint: false,
2162
2276
  },
2163
- }, async ({ project_path, certification_id, framework, output_format }) => {
2277
+ }, async ({ project_path, certification_id, framework, collect_evidence, verify_audit_trail, store_evidence, include_attestation, output_format }) => {
2164
2278
  const certification = await getCertification(project_path, certification_id);
2165
2279
  if (!certification) {
2166
2280
  return errorResponse(`Certification ${certification_id} not found`);
@@ -2172,6 +2286,46 @@ server.registerTool("compliance_report", {
2172
2286
  if (allFindings.length === 0) {
2173
2287
  return errorResponse("No findings to assess. Run certification agents first.");
2174
2288
  }
2289
+ // Check if audit-defensibility features are requested
2290
+ const useAuditFeatures = collect_evidence || verify_audit_trail;
2291
+ if (useAuditFeatures) {
2292
+ // Use the full compliance bundle for audit-defensible reports
2293
+ const result = await runSingleFrameworkAssessment({
2294
+ projectPath: project_path,
2295
+ findings: allFindings,
2296
+ framework: framework,
2297
+ certificationId: certification_id,
2298
+ collectEvidence: collect_evidence ?? false,
2299
+ verifyAuditTrail: verify_audit_trail ?? false,
2300
+ storeEvidence: store_evidence !== false,
2301
+ includeAttestation: include_attestation !== false,
2302
+ });
2303
+ if (output_format === "json") {
2304
+ return jsonResponse({
2305
+ status: result.status,
2306
+ complianceScore: result.report.status.complianceScore,
2307
+ riskScore: result.report.status.riskScore,
2308
+ auditVerification: result.auditVerification ? {
2309
+ verified: result.auditVerification.verified,
2310
+ chainIntegrity: result.auditVerification.chainIntegrity,
2311
+ } : undefined,
2312
+ evidenceBundle: result.evidenceBundle ? {
2313
+ id: result.evidenceBundle.id,
2314
+ bundleDigest: result.evidenceBundle.bundleDigest,
2315
+ signed: !!result.evidenceBundle.signature,
2316
+ } : undefined,
2317
+ evidencePath: result.evidencePath,
2318
+ report: result.report,
2319
+ });
2320
+ }
2321
+ else if (output_format === "summary") {
2322
+ return textResponse(generateCompactComplianceSummary(result.report));
2323
+ }
2324
+ else {
2325
+ return textResponse(result.markdownReport);
2326
+ }
2327
+ }
2328
+ // Standard report without audit features
2175
2329
  const report = generateComplianceReport(allFindings, framework, project_path, certification_id);
2176
2330
  if (output_format === "json") {
2177
2331
  return jsonResponse(report);
@@ -2188,16 +2342,20 @@ server.registerTool("compliance_report", {
2188
2342
  // ---------------------------------------------------------------------------
2189
2343
  server.registerTool("compliance_multi_report", {
2190
2344
  title: "Multi-Framework Compliance Report",
2191
- description: `Generate a compliance report across multiple frameworks (SOC 2 and ISO 27001). Shows comparative status and prioritized recommendations.`,
2345
+ description: `Generate a compliance report across multiple frameworks. Supports all major frameworks (SOC 2, ISO 27001, PCI-DSS, HIPAA, 42 CFR Part 2, GDPR, NIST 800-53, CIS). Shows comparative status and prioritized recommendations. Enable audit-defensibility options for evidence collection and audit trail verification.`,
2192
2346
  inputSchema: {
2193
2347
  project_path: z.string().describe("Absolute path to the project root"),
2194
2348
  certification_id: z.string().describe("Certification ID to assess"),
2195
2349
  frameworks: z
2196
- .array(z.enum(["SOC2", "ISO27001"]))
2350
+ .array(z.enum(["SOC2", "ISO27001", "PCI-DSS", "HIPAA", "42-CFR-PART-2", "GDPR", "NIST-800-53", "CIS"]))
2197
2351
  .optional()
2198
- .describe("Frameworks to assess. Default: both"),
2352
+ .describe("Frameworks to assess. Default: SOC2, ISO27001"),
2353
+ collect_evidence: z.boolean().optional().describe("Collect evidence bundle for audit defensibility. Default: false"),
2354
+ verify_audit_trail: z.boolean().optional().describe("Verify audit trail integrity. Default: false"),
2355
+ store_evidence: z.boolean().optional().describe("Store evidence bundle to disk. Default: true if collecting"),
2356
+ include_attestation: z.boolean().optional().describe("Include attestation section with methodology and scope. Default: true when audit features enabled"),
2199
2357
  output_format: z
2200
- .enum(["markdown", "json"])
2358
+ .enum(["markdown", "json", "summary"])
2201
2359
  .optional()
2202
2360
  .describe("Output format. Default: markdown"),
2203
2361
  },
@@ -2207,7 +2365,7 @@ server.registerTool("compliance_multi_report", {
2207
2365
  idempotentHint: true,
2208
2366
  openWorldHint: false,
2209
2367
  },
2210
- }, async ({ project_path, certification_id, frameworks, output_format }) => {
2368
+ }, async ({ project_path, certification_id, frameworks, collect_evidence, verify_audit_trail, store_evidence, include_attestation, output_format }) => {
2211
2369
  const certification = await getCertification(project_path, certification_id);
2212
2370
  if (!certification) {
2213
2371
  return errorResponse(`Certification ${certification_id} not found`);
@@ -2219,6 +2377,53 @@ server.registerTool("compliance_multi_report", {
2219
2377
  return errorResponse("No findings to assess. Run certification agents first.");
2220
2378
  }
2221
2379
  const selectedFrameworks = (frameworks || ["SOC2", "ISO27001"]);
2380
+ // Check if audit-defensibility features are requested
2381
+ const useAuditFeatures = collect_evidence || verify_audit_trail;
2382
+ if (useAuditFeatures) {
2383
+ // Use the full compliance bundle for audit-defensible reports
2384
+ const result = await runComplianceAssessment({
2385
+ projectPath: project_path,
2386
+ findings: allFindings,
2387
+ frameworks: selectedFrameworks,
2388
+ certificationId: certification_id,
2389
+ collectEvidence: collect_evidence ?? false,
2390
+ verifyAuditTrail: verify_audit_trail ?? false,
2391
+ storeEvidence: store_evidence !== false,
2392
+ includeAttestation: include_attestation !== false,
2393
+ });
2394
+ if (output_format === "json") {
2395
+ return jsonResponse({
2396
+ status: result.status,
2397
+ combinedScore: result.combinedScore,
2398
+ frameworks: Object.fromEntries(Object.entries(result.reports).map(([fw, report]) => [
2399
+ fw,
2400
+ report ? {
2401
+ complianceScore: report.status.complianceScore,
2402
+ riskScore: report.status.riskScore,
2403
+ controlsNonCompliant: report.status.controlsNonCompliant,
2404
+ } : null,
2405
+ ])),
2406
+ auditVerification: result.auditVerification ? {
2407
+ verified: result.auditVerification.verified,
2408
+ chainIntegrity: result.auditVerification.chainIntegrity,
2409
+ } : undefined,
2410
+ evidenceBundle: result.evidenceBundle ? {
2411
+ id: result.evidenceBundle.id,
2412
+ bundleDigest: result.evidenceBundle.bundleDigest,
2413
+ signed: !!result.evidenceBundle.signature,
2414
+ } : undefined,
2415
+ evidencePath: result.evidencePath,
2416
+ multiFrameworkReport: result.multiFrameworkReport,
2417
+ });
2418
+ }
2419
+ else if (output_format === "summary") {
2420
+ return textResponse(generateComplianceSummary(result));
2421
+ }
2422
+ else {
2423
+ return textResponse(result.markdownReport);
2424
+ }
2425
+ }
2426
+ // Standard report without audit features
2222
2427
  const report = generateMultiFrameworkReport(allFindings, selectedFrameworks, project_path, certification_id);
2223
2428
  if (output_format === "json") {
2224
2429
  return jsonResponse(report);
@@ -2232,10 +2437,10 @@ server.registerTool("compliance_multi_report", {
2232
2437
  // ---------------------------------------------------------------------------
2233
2438
  server.registerTool("compliance_controls", {
2234
2439
  title: "List Compliance Controls",
2235
- description: `List available compliance controls for a framework. Use to understand what controls are assessed and their mapping to finding categories.`,
2440
+ description: `List available compliance controls for a framework. Use to understand what controls are assessed and their mapping to finding categories. Supports all major frameworks.`,
2236
2441
  inputSchema: {
2237
2442
  framework: z
2238
- .enum(["SOC2", "ISO27001"])
2443
+ .enum(["SOC2", "ISO27001", "PCI-DSS", "HIPAA", "42-CFR-PART-2", "GDPR", "NIST-800-53", "CIS"])
2239
2444
  .describe("Compliance framework"),
2240
2445
  category: z
2241
2446
  .string()
@@ -2253,7 +2458,8 @@ server.registerTool("compliance_controls", {
2253
2458
  if (category) {
2254
2459
  controls = controls.filter((c) => c.category === category);
2255
2460
  }
2256
- const categories = framework === "SOC2" ? getSOC2Categories() : getISO27001Categories();
2461
+ // Get unique categories from controls
2462
+ const categories = [...new Set(controls.map((c) => c.category))].sort();
2257
2463
  return jsonResponse({
2258
2464
  framework,
2259
2465
  totalControls: controls.length,
@@ -2269,6 +2475,213 @@ server.registerTool("compliance_controls", {
2269
2475
  });
2270
2476
  });
2271
2477
  // ---------------------------------------------------------------------------
2478
+ // Tool: Healthcare Compliance Scan (HIPAA + 42 CFR Part 2)
2479
+ // ---------------------------------------------------------------------------
2480
+ server.registerTool("healthcare_compliance_scan", {
2481
+ title: "Healthcare Compliance Assessment",
2482
+ description: `Run a combined HIPAA and 42 CFR Part 2 compliance assessment. Generates audit-defensible reports with evidence collection and audit trail verification. Designed for SUD (Substance Use Disorder) and healthcare applications.`,
2483
+ inputSchema: {
2484
+ project_path: z.string().describe("Absolute path to the project root"),
2485
+ certification_id: z.string().optional().describe("Certification ID to use findings from"),
2486
+ collect_evidence: z.boolean().optional().describe("Collect evidence bundle. Default: true"),
2487
+ verify_audit_trail: z.boolean().optional().describe("Verify audit trail integrity. Default: true"),
2488
+ store_evidence: z.boolean().optional().describe("Store evidence bundle to disk. Default: true"),
2489
+ output_format: z.enum(["markdown", "json", "summary"]).optional().describe("Output format. Default: markdown"),
2490
+ },
2491
+ annotations: {
2492
+ readOnlyHint: true,
2493
+ destructiveHint: false,
2494
+ idempotentHint: true,
2495
+ openWorldHint: false,
2496
+ },
2497
+ }, async ({ project_path, certification_id, collect_evidence, verify_audit_trail, store_evidence, output_format }) => {
2498
+ try {
2499
+ const validatedPath = await validateProjectPath(project_path);
2500
+ const allFindings = [];
2501
+ const certId = certification_id || undefined;
2502
+ let certificationToUse;
2503
+ if (certId) {
2504
+ certificationToUse = await getCertification(validatedPath, certId);
2505
+ }
2506
+ else {
2507
+ certificationToUse = await getLatestCertification(validatedPath);
2508
+ }
2509
+ if (certificationToUse) {
2510
+ const agents = Object.keys(certificationToUse.agents);
2511
+ for (const agent of agents) {
2512
+ const agentData = certificationToUse.agents[agent];
2513
+ if (agentData?.findings) {
2514
+ // Cast to any to avoid type conflicts between local and imported types
2515
+ allFindings.push(...agentData.findings);
2516
+ }
2517
+ }
2518
+ }
2519
+ // Run healthcare compliance assessment
2520
+ const result = await runHealthcareComplianceAssessment({
2521
+ projectPath: validatedPath,
2522
+ // Healthcare bundle expects Finding[] from certification/types
2523
+ findings: allFindings,
2524
+ certificationId: certificationToUse?.metadata.id,
2525
+ collectEvidence: collect_evidence !== false,
2526
+ verifyAuditTrail: verify_audit_trail !== false,
2527
+ storeEvidence: store_evidence !== false,
2528
+ });
2529
+ if (output_format === "json") {
2530
+ return jsonResponse({
2531
+ status: result.status,
2532
+ combinedScore: result.combinedScore,
2533
+ hipaaScore: result.hipaaReport.status.complianceScore,
2534
+ cfr42Score: result.cfr42Report.status.complianceScore,
2535
+ hipaaControls: {
2536
+ total: result.hipaaReport.status.totalControls,
2537
+ compliant: result.hipaaReport.status.controlsCovered,
2538
+ atRisk: result.hipaaReport.status.controlsAtRisk,
2539
+ nonCompliant: result.hipaaReport.status.controlsNonCompliant,
2540
+ },
2541
+ cfr42Controls: {
2542
+ total: result.cfr42Report.status.totalControls,
2543
+ compliant: result.cfr42Report.status.controlsCovered,
2544
+ atRisk: result.cfr42Report.status.controlsAtRisk,
2545
+ nonCompliant: result.cfr42Report.status.controlsNonCompliant,
2546
+ },
2547
+ auditTrailVerified: result.auditVerification?.verified,
2548
+ evidenceBundleId: result.evidenceBundle?.id,
2549
+ evidencePath: result.evidencePath,
2550
+ });
2551
+ }
2552
+ else if (output_format === "summary") {
2553
+ return textResponse(generateHealthcareComplianceSummary(result));
2554
+ }
2555
+ return textResponse(result.markdownReport);
2556
+ }
2557
+ catch (error) {
2558
+ if (error instanceof PathValidationError) {
2559
+ return errorResponse(error.message);
2560
+ }
2561
+ return errorResponse(`Healthcare compliance scan failed: ${error instanceof Error ? error.message : String(error)}`);
2562
+ }
2563
+ });
2564
+ // ---------------------------------------------------------------------------
2565
+ // Tool: Verify Audit Trail
2566
+ // ---------------------------------------------------------------------------
2567
+ server.registerTool("verify_audit_trail", {
2568
+ title: "Verify Audit Trail Integrity",
2569
+ description: `Verify the tamper-evident audit trail by checking hash chains. Detects if any historical entries have been modified. Critical for healthcare compliance (HIPAA, 42 CFR Part 2) audit defensibility.`,
2570
+ inputSchema: {
2571
+ project_path: z.string().describe("Absolute path to the project root"),
2572
+ output_format: z.enum(["markdown", "json"]).optional().describe("Output format. Default: markdown"),
2573
+ },
2574
+ annotations: {
2575
+ readOnlyHint: true,
2576
+ destructiveHint: false,
2577
+ idempotentHint: true,
2578
+ openWorldHint: false,
2579
+ },
2580
+ }, async ({ project_path, output_format }) => {
2581
+ try {
2582
+ const validatedPath = await validateProjectPath(project_path);
2583
+ const result = await verifyHistoryIntegrity(validatedPath);
2584
+ if (output_format === "json") {
2585
+ return jsonResponse({
2586
+ verified: result.verified,
2587
+ projectPath: result.projectPath,
2588
+ verifiedAt: result.verifiedAt,
2589
+ totalEntries: result.totalEntries,
2590
+ entriesVerified: result.entriesVerified,
2591
+ entriesPassed: result.entriesPassed,
2592
+ entriesFailed: result.entriesFailed,
2593
+ chainIntegrity: result.chainIntegrity,
2594
+ genesisHash: result.genesisHash,
2595
+ headHash: result.headHash,
2596
+ failures: result.failures,
2597
+ });
2598
+ }
2599
+ return textResponse(formatVerificationResultAsMarkdown(result));
2600
+ }
2601
+ catch (error) {
2602
+ if (error instanceof PathValidationError) {
2603
+ return errorResponse(error.message);
2604
+ }
2605
+ return errorResponse(`Audit trail verification failed: ${error instanceof Error ? error.message : String(error)}`);
2606
+ }
2607
+ });
2608
+ // ---------------------------------------------------------------------------
2609
+ // Tool: Collect Evidence Bundle
2610
+ // ---------------------------------------------------------------------------
2611
+ server.registerTool("collect_evidence_bundle", {
2612
+ title: "Collect Evidence Bundle",
2613
+ description: `Collect and package audit evidence for compliance. Creates a cryptographically attested bundle of scan results, compliance reports, SBOM, and history snapshots. Essential for audit defensibility.`,
2614
+ inputSchema: {
2615
+ project_path: z.string().describe("Absolute path to the project root"),
2616
+ certification_id: z.string().optional().describe("Certification ID to associate with"),
2617
+ frameworks: z
2618
+ .array(z.enum(["HIPAA", "42-CFR-PART-2", "SOC2", "ISO27001", "PCI-DSS", "GDPR", "NIST-800-53", "CIS"]))
2619
+ .optional()
2620
+ .describe("Compliance frameworks to include reports for"),
2621
+ include_sbom: z.boolean().optional().describe("Include SBOM. Default: true"),
2622
+ include_history: z.boolean().optional().describe("Include history snapshot. Default: true"),
2623
+ include_scans: z.boolean().optional().describe("Include scan results. Default: true"),
2624
+ store: z.boolean().optional().describe("Store bundle to disk. Default: true"),
2625
+ output_format: z.enum(["markdown", "json"]).optional().describe("Output format. Default: markdown"),
2626
+ },
2627
+ annotations: {
2628
+ readOnlyHint: true,
2629
+ destructiveHint: false,
2630
+ idempotentHint: true,
2631
+ openWorldHint: false,
2632
+ },
2633
+ }, async ({ project_path, certification_id, frameworks, include_sbom, include_history, include_scans, store, output_format }) => {
2634
+ try {
2635
+ const validatedPath = await validateProjectPath(project_path);
2636
+ const result = await collectEvidence({
2637
+ projectPath: validatedPath,
2638
+ certificationId: certification_id,
2639
+ frameworks: frameworks,
2640
+ includeSbom: include_sbom !== false,
2641
+ includeHistory: include_history !== false,
2642
+ includeScanResults: include_scans !== false,
2643
+ });
2644
+ if (!result.success || !result.bundle) {
2645
+ return errorResponse(result.error || "Evidence collection failed");
2646
+ }
2647
+ let storedPath;
2648
+ if (store !== false) {
2649
+ storedPath = await storeEvidenceBundle(validatedPath, result.bundle);
2650
+ }
2651
+ if (output_format === "json") {
2652
+ return jsonResponse({
2653
+ success: true,
2654
+ bundleId: result.bundle.id,
2655
+ createdAt: result.bundle.createdAt,
2656
+ artifactCount: result.bundle.artifacts.length,
2657
+ bundleDigest: result.bundle.bundleDigest,
2658
+ storedPath,
2659
+ warnings: result.warnings,
2660
+ artifacts: result.bundle.artifacts.map((a) => ({
2661
+ type: a.type,
2662
+ name: a.name,
2663
+ sizeBytes: a.sizeBytes,
2664
+ digest: a.contentDigest,
2665
+ })),
2666
+ });
2667
+ }
2668
+ let output = formatEvidenceBundleAsMarkdown(result.bundle);
2669
+ if (storedPath) {
2670
+ output += `\n\n**Stored at:** \`${storedPath}\``;
2671
+ }
2672
+ if (result.warnings.length > 0) {
2673
+ output += `\n\n**Warnings:**\n${result.warnings.map((w) => `- ${w}`).join("\n")}`;
2674
+ }
2675
+ return textResponse(output);
2676
+ }
2677
+ catch (error) {
2678
+ if (error instanceof PathValidationError) {
2679
+ return errorResponse(error.message);
2680
+ }
2681
+ return errorResponse(`Evidence collection failed: ${error instanceof Error ? error.message : String(error)}`);
2682
+ }
2683
+ });
2684
+ // ---------------------------------------------------------------------------
2272
2685
  // Tool: Generate SBOM
2273
2686
  // ---------------------------------------------------------------------------
2274
2687
  server.registerTool("sbom_generate", {