infraweaver 0.1.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 (524) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +244 -0
  3. package/dist/agents/claude.d.ts +113 -0
  4. package/dist/agents/claudePretoolGate.d.ts +137 -0
  5. package/dist/agents/dispatchMetrics.d.ts +77 -0
  6. package/dist/agents/gateServer.d.ts +7 -0
  7. package/dist/agents/index.d.ts +6 -0
  8. package/dist/agents/nativeFsDenies.d.ts +46 -0
  9. package/dist/agents/opencode.d.ts +284 -0
  10. package/dist/agents/opencodePlugin.d.ts +96 -0
  11. package/dist/agents/opencodeShared.d.ts +40 -0
  12. package/dist/agents/postRun.d.ts +126 -0
  13. package/dist/agents/reviewer.d.ts +41 -0
  14. package/dist/agents/sessionLabeler.d.ts +97 -0
  15. package/dist/agents/shared.d.ts +246 -0
  16. package/dist/agents/subagentModels.d.ts +19 -0
  17. package/dist/agents/tokenQuota.d.ts +118 -0
  18. package/dist/agents/writeGateSource.d.ts +22 -0
  19. package/dist/agents/writePolicy.d.ts +79 -0
  20. package/dist/brand.d.ts +67 -0
  21. package/dist/cli.mjs +247846 -0
  22. package/dist/external.d.ts +227 -0
  23. package/dist/i18n/scaffolding.d.ts +59 -0
  24. package/dist/index.d.ts +6 -0
  25. package/dist/index.js +247061 -0
  26. package/dist/internal/index.d.ts +18 -0
  27. package/dist/internal.js +2398 -0
  28. package/dist/lifecycle.d.ts +2 -0
  29. package/dist/main.d.ts +8 -0
  30. package/dist/mcp/arkConfig.d.ts +1 -0
  31. package/dist/mcp/assess.d.ts +157 -0
  32. package/dist/mcp/capabilityContext.d.ts +71 -0
  33. package/dist/mcp/changeSummary.d.ts +52 -0
  34. package/dist/mcp/checkSuite.d.ts +27 -0
  35. package/dist/mcp/checkout.d.ts +92 -0
  36. package/dist/mcp/comment.d.ts +127 -0
  37. package/dist/mcp/commitInfo.d.ts +11 -0
  38. package/dist/mcp/crosswalk.d.ts +178 -0
  39. package/dist/mcp/crosswalkDigest.d.ts +1 -0
  40. package/dist/mcp/cyberEssentials.d.ts +24 -0
  41. package/dist/mcp/dashboard.d.ts +125 -0
  42. package/dist/mcp/dependencies.d.ts +12 -0
  43. package/dist/mcp/frameworks.d.ts +74 -0
  44. package/dist/mcp/geminiSanitizer.d.ts +28 -0
  45. package/dist/mcp/git.d.ts +60 -0
  46. package/dist/mcp/guardrails.d.ts +222 -0
  47. package/dist/mcp/issue.d.ts +20 -0
  48. package/dist/mcp/issueComments.d.ts +11 -0
  49. package/dist/mcp/issueEvents.d.ts +11 -0
  50. package/dist/mcp/issueInfo.d.ts +11 -0
  51. package/dist/mcp/labels.d.ts +14 -0
  52. package/dist/mcp/localContext.d.ts +26 -0
  53. package/dist/mcp/moduleExtraction.d.ts +79 -0
  54. package/dist/mcp/moduleTests.d.ts +106 -0
  55. package/dist/mcp/modules.d.ts +198 -0
  56. package/dist/mcp/output.d.ts +16 -0
  57. package/dist/mcp/pathSafety.d.ts +14 -0
  58. package/dist/mcp/policy.d.ts +50 -0
  59. package/dist/mcp/pr.d.ts +64 -0
  60. package/dist/mcp/prInfo.d.ts +11 -0
  61. package/dist/mcp/providerSchema.d.ts +52 -0
  62. package/dist/mcp/review.d.ts +212 -0
  63. package/dist/mcp/reviewComments.d.ts +245 -0
  64. package/dist/mcp/roots.d.ts +60 -0
  65. package/dist/mcp/scope.d.ts +26 -0
  66. package/dist/mcp/selectMode.d.ts +20 -0
  67. package/dist/mcp/server.d.ts +61 -0
  68. package/dist/mcp/shared.d.ts +62 -0
  69. package/dist/mcp/shell.d.ts +58 -0
  70. package/dist/mcp/staleFix.d.ts +138 -0
  71. package/dist/mcp/terraform/azurePrices.d.ts +8 -0
  72. package/dist/mcp/terraform/baseline.d.ts +57 -0
  73. package/dist/mcp/terraform/concernResult.d.ts +38 -0
  74. package/dist/mcp/terraform/cost.d.ts +55 -0
  75. package/dist/mcp/terraform/cspm.d.ts +80 -0
  76. package/dist/mcp/terraform/currency.d.ts +110 -0
  77. package/dist/mcp/terraform/decisions.d.ts +178 -0
  78. package/dist/mcp/terraform/eidas.d.ts +100 -0
  79. package/dist/mcp/terraform/evidence.d.ts +343 -0
  80. package/dist/mcp/terraform/findings.d.ts +76 -0
  81. package/dist/mcp/terraform/fixMemory.d.ts +81 -0
  82. package/dist/mcp/terraform/governance.d.ts +56 -0
  83. package/dist/mcp/terraform/hcl.d.ts +115 -0
  84. package/dist/mcp/terraform/iacLanguages.d.ts +120 -0
  85. package/dist/mcp/terraform/idleFloor.d.ts +78 -0
  86. package/dist/mcp/terraform/keyless.d.ts +68 -0
  87. package/dist/mcp/terraform/moduleDocs.d.ts +56 -0
  88. package/dist/mcp/terraform/nativeRules.d.ts +38 -0
  89. package/dist/mcp/terraform/nativeScan.d.ts +11 -0
  90. package/dist/mcp/terraform/noiseProfile.d.ts +100 -0
  91. package/dist/mcp/terraform/normalization.d.ts +52 -0
  92. package/dist/mcp/terraform/oscal.d.ts +103 -0
  93. package/dist/mcp/terraform/packs/azurerm-3-4.d.ts +2 -0
  94. package/dist/mcp/terraform/packs/cloudflare-4-5.d.ts +2 -0
  95. package/dist/mcp/terraform/paths.d.ts +28 -0
  96. package/dist/mcp/terraform/plan.d.ts +157 -0
  97. package/dist/mcp/terraform/planDrift.d.ts +199 -0
  98. package/dist/mcp/terraform/policyAuthor.d.ts +191 -0
  99. package/dist/mcp/terraform/prowlerOcsf.d.ts +136 -0
  100. package/dist/mcp/terraform/refactor.d.ts +183 -0
  101. package/dist/mcp/terraform/registry.d.ts +108 -0
  102. package/dist/mcp/terraform/risk.d.ts +41 -0
  103. package/dist/mcp/terraform/scanSession.d.ts +116 -0
  104. package/dist/mcp/terraform/scannerCache.d.ts +15 -0
  105. package/dist/mcp/terraform/scannerEgress.d.ts +72 -0
  106. package/dist/mcp/terraform/scannerJson.d.ts +13 -0
  107. package/dist/mcp/terraform/scanners.d.ts +205 -0
  108. package/dist/mcp/terraform/signing.d.ts +61 -0
  109. package/dist/mcp/terraform/stateLocking.d.ts +18 -0
  110. package/dist/mcp/terraform/subprocess.d.ts +43 -0
  111. package/dist/mcp/terraform/suppressions.d.ts +90 -0
  112. package/dist/mcp/terraform/taxonomy.d.ts +39 -0
  113. package/dist/mcp/terraform/tfquery.d.ts +47 -0
  114. package/dist/mcp/terraform/toolchainIntegrity.d.ts +82 -0
  115. package/dist/mcp/terraform/tools/authorPolicy.d.ts +59 -0
  116. package/dist/mcp/terraform/tools/detectPlanDrift.d.ts +20 -0
  117. package/dist/mcp/terraform/tools/emitCost.d.ts +11 -0
  118. package/dist/mcp/terraform/tools/emitSarif.d.ts +14 -0
  119. package/dist/mcp/terraform/tools/fixMemory.d.ts +19 -0
  120. package/dist/mcp/terraform/tools/infracostDiff.d.ts +22 -0
  121. package/dist/mcp/terraform/tools/ingestExternalFindings.d.ts +21 -0
  122. package/dist/mcp/terraform/tools/moduleLookup.d.ts +14 -0
  123. package/dist/mcp/terraform/tools/moduleSearch.d.ts +23 -0
  124. package/dist/mcp/terraform/tools/plan.d.ts +59 -0
  125. package/dist/mcp/terraform/tools/providerUpgrade.d.ts +55 -0
  126. package/dist/mcp/terraform/tools/readFindings.d.ts +17 -0
  127. package/dist/mcp/terraform/tools/scan.d.ts +114 -0
  128. package/dist/mcp/terraform/tools/validate.d.ts +31 -0
  129. package/dist/mcp/terraform/tools/verifyRemediation.d.ts +31 -0
  130. package/dist/mcp/terraform/tools/versionCurrency.d.ts +5 -0
  131. package/dist/mcp/terraform/tools.d.ts +16 -0
  132. package/dist/mcp/terraform/transformPacks.d.ts +267 -0
  133. package/dist/mcp/terraform/types.d.ts +226 -0
  134. package/dist/mcp/terraform/verification.d.ts +81 -0
  135. package/dist/mcp/terraform/vex.d.ts +115 -0
  136. package/dist/mcp/terraform/writeOnly.d.ts +67 -0
  137. package/dist/mcp/terraform.d.ts +51 -0
  138. package/dist/mcp/terratest.d.ts +85 -0
  139. package/dist/mcp/untrustedContent.d.ts +76 -0
  140. package/dist/mcp/upload.d.ts +8 -0
  141. package/dist/models.d.ts +181 -0
  142. package/dist/modes/address-reviews.d.ts +2 -0
  143. package/dist/modes/assess.d.ts +2 -0
  144. package/dist/modes/build.d.ts +2 -0
  145. package/dist/modes/compliance-audit.d.ts +2 -0
  146. package/dist/modes/cost-optimization.d.ts +2 -0
  147. package/dist/modes/drift-detect.d.ts +2 -0
  148. package/dist/modes/fix.d.ts +2 -0
  149. package/dist/modes/incremental-review.d.ts +2 -0
  150. package/dist/modes/index.d.ts +24 -0
  151. package/dist/modes/modernize-deprecated.d.ts +2 -0
  152. package/dist/modes/plan.d.ts +2 -0
  153. package/dist/modes/policy-gate.d.ts +2 -0
  154. package/dist/modes/prFormats.d.ts +3 -0
  155. package/dist/modes/refactor.d.ts +2 -0
  156. package/dist/modes/refresh-remediation.d.ts +2 -0
  157. package/dist/modes/remediate-and-refactor.d.ts +2 -0
  158. package/dist/modes/remediate.d.ts +2 -0
  159. package/dist/modes/resolve-conflicts.d.ts +2 -0
  160. package/dist/modes/review.d.ts +2 -0
  161. package/dist/modes/summarize-pr.d.ts +2 -0
  162. package/dist/modes/task.d.ts +2 -0
  163. package/dist/modes/terraform-code-review.d.ts +2 -0
  164. package/dist/modes/types.d.ts +9 -0
  165. package/dist/modes/update-dependencies.d.ts +2 -0
  166. package/dist/prep/index.d.ts +7 -0
  167. package/dist/prep/installNodeDependencies.d.ts +2 -0
  168. package/dist/prep/installPythonDependencies.d.ts +2 -0
  169. package/dist/prep/types.d.ts +31 -0
  170. package/dist/reviewQuality.d.ts +107 -0
  171. package/dist/skills/terraform-best-practices/SKILL.md +379 -0
  172. package/dist/toolState.d.ts +123 -0
  173. package/dist/utils/activity.d.ts +40 -0
  174. package/dist/utils/agent.d.ts +47 -0
  175. package/dist/utils/agentHangReport.d.ts +38 -0
  176. package/dist/utils/annotations.d.ts +17 -0
  177. package/dist/utils/apiFetch.d.ts +11 -0
  178. package/dist/utils/apiKeys.d.ts +48 -0
  179. package/dist/utils/apiUrl.d.ts +28 -0
  180. package/dist/utils/assets.d.ts +8 -0
  181. package/dist/utils/baseRefConfig.d.ts +121 -0
  182. package/dist/utils/billingErrors.d.ts +85 -0
  183. package/dist/utils/body.d.ts +34 -0
  184. package/dist/utils/buildInfraweaverFooter.d.ts +29 -0
  185. package/dist/utils/byokFallback.d.ts +85 -0
  186. package/dist/utils/changeImpact.d.ts +101 -0
  187. package/dist/utils/claudeSubscription.d.ts +30 -0
  188. package/dist/utils/cli.d.ts +10 -0
  189. package/dist/utils/cloudClient.d.ts +33 -0
  190. package/dist/utils/cloudFetchCore.d.ts +42 -0
  191. package/dist/utils/cloudReport.d.ts +114 -0
  192. package/dist/utils/codexHome.d.ts +29 -0
  193. package/dist/utils/codexOAuth.d.ts +60 -0
  194. package/dist/utils/diffCoverage.d.ts +63 -0
  195. package/dist/utils/env.d.ts +46 -0
  196. package/dist/utils/errorReport.d.ts +17 -0
  197. package/dist/utils/exitHandler.d.ts +8 -0
  198. package/dist/utils/fixDoubleEscapedString.d.ts +1 -0
  199. package/dist/utils/gitAuth.d.ts +84 -0
  200. package/dist/utils/gitAuthServer.d.ts +24 -0
  201. package/dist/utils/github.d.ts +104 -0
  202. package/dist/utils/globals.d.ts +3 -0
  203. package/dist/utils/infraweaverConfig.d.ts +56 -0
  204. package/dist/utils/install.d.ts +37 -0
  205. package/dist/utils/instructions.d.ts +48 -0
  206. package/dist/utils/keylessOidc.d.ts +28 -0
  207. package/dist/utils/leapingComment.d.ts +11 -0
  208. package/dist/utils/learnings.d.ts +62 -0
  209. package/dist/utils/learningsTruncate.d.ts +25 -0
  210. package/dist/utils/lifecycle.d.ts +57 -0
  211. package/dist/utils/log.d.ts +111 -0
  212. package/dist/utils/modelResolver.d.ts +63 -0
  213. package/dist/utils/moduleFetch.d.ts +39 -0
  214. package/dist/utils/normalizeEnv.d.ts +30 -0
  215. package/dist/utils/openCodeModels.d.ts +11 -0
  216. package/dist/utils/openaiCompatible.d.ts +26 -0
  217. package/dist/utils/opentofuMcp.d.ts +50 -0
  218. package/dist/utils/overrides.d.ts +40 -0
  219. package/dist/utils/packageManager.d.ts +49 -0
  220. package/dist/utils/patchWorkflowRunFields.d.ts +29 -0
  221. package/dist/utils/payload.d.ts +249 -0
  222. package/dist/utils/prSummary.d.ts +61 -0
  223. package/dist/utils/presets.d.ts +36 -0
  224. package/dist/utils/progressComment.d.ts +146 -0
  225. package/dist/utils/providerErrors.d.ts +31 -0
  226. package/dist/utils/proxyModel.d.ts +76 -0
  227. package/dist/utils/rangeDiff.d.ts +51 -0
  228. package/dist/utils/redact.d.ts +33 -0
  229. package/dist/utils/registryAuth.d.ts +52 -0
  230. package/dist/utils/remediationCommand.d.ts +58 -0
  231. package/dist/utils/retry.d.ts +38 -0
  232. package/dist/utils/reviewCleanup.d.ts +14 -0
  233. package/dist/utils/run.d.ts +9 -0
  234. package/dist/utils/runContext.d.ts +112 -0
  235. package/dist/utils/runContextData.d.ts +42 -0
  236. package/dist/utils/runErrorRenderer.d.ts +64 -0
  237. package/dist/utils/runLifecycle.d.ts +89 -0
  238. package/dist/utils/runStartupLog.d.ts +15 -0
  239. package/dist/utils/secrets.d.ts +34 -0
  240. package/dist/utils/setup.d.ts +90 -0
  241. package/dist/utils/shell.d.ts +44 -0
  242. package/dist/utils/skills.d.ts +10 -0
  243. package/dist/utils/subprocess.d.ts +81 -0
  244. package/dist/utils/terraformMcp.d.ts +46 -0
  245. package/dist/utils/time.d.ts +15 -0
  246. package/dist/utils/timer.d.ts +23 -0
  247. package/dist/utils/todoTracking.d.ts +16 -0
  248. package/dist/utils/token.d.ts +52 -0
  249. package/dist/utils/toolLicensing.d.ts +56 -0
  250. package/dist/utils/toolSelection.d.ts +73 -0
  251. package/dist/utils/toon.d.ts +16 -0
  252. package/dist/utils/version.d.ts +2 -0
  253. package/dist/utils/versioning.d.ts +7 -0
  254. package/dist/utils/vertex.d.ts +16 -0
  255. package/dist/utils/workflow.d.ts +13 -0
  256. package/package.json +132 -0
  257. package/src/agents/claude.ts +1588 -0
  258. package/src/agents/claudePretoolGate.ts +286 -0
  259. package/src/agents/dispatchMetrics.ts +162 -0
  260. package/src/agents/gateServer.ts +178 -0
  261. package/src/agents/index.ts +10 -0
  262. package/src/agents/nativeFsDenies.ts +164 -0
  263. package/src/agents/opencode.ts +1600 -0
  264. package/src/agents/opencodePlugin.ts +304 -0
  265. package/src/agents/opencodeShared.ts +134 -0
  266. package/src/agents/postRun.ts +615 -0
  267. package/src/agents/reviewer.ts +134 -0
  268. package/src/agents/sessionLabeler.ts +185 -0
  269. package/src/agents/shared.ts +377 -0
  270. package/src/agents/subagentModels.ts +40 -0
  271. package/src/agents/tokenQuota.ts +203 -0
  272. package/src/agents/writeGateSource.ts +148 -0
  273. package/src/agents/writePolicy.ts +132 -0
  274. package/src/brand.ts +84 -0
  275. package/src/cli.ts +117 -0
  276. package/src/commands/gha.ts +188 -0
  277. package/src/commands/mcp.ts +126 -0
  278. package/src/commands/verifyEvidence.ts +100 -0
  279. package/src/entry.ts +7 -0
  280. package/src/entryPost.ts +109 -0
  281. package/src/external.ts +308 -0
  282. package/src/i18n/scaffolding.ts +191 -0
  283. package/src/index.ts +7 -0
  284. package/src/internal/index.ts +74 -0
  285. package/src/lifecycle.ts +2 -0
  286. package/src/main.ts +815 -0
  287. package/src/mcp/__fixtures__/infraweaver-scratch-pr-49-review-3485940013.json +110 -0
  288. package/src/mcp/__fixtures__/infraweaver-scratch-pr-64-review-3531000326.json +14 -0
  289. package/src/mcp/__fixtures__/infraweaver-test-repo-pr-1.diff.json +67 -0
  290. package/src/mcp/__snapshots__/checkout.test.ts.snap +109 -0
  291. package/src/mcp/__snapshots__/reviewComments.test.ts.snap +71 -0
  292. package/src/mcp/arkConfig.ts +7 -0
  293. package/src/mcp/assess.ts +723 -0
  294. package/src/mcp/capabilityContext.ts +80 -0
  295. package/src/mcp/changeSummary.ts +145 -0
  296. package/src/mcp/checkSuite.ts +261 -0
  297. package/src/mcp/checkout.ts +1015 -0
  298. package/src/mcp/comment.ts +683 -0
  299. package/src/mcp/commitInfo.ts +57 -0
  300. package/src/mcp/crosswalk.ts +1253 -0
  301. package/src/mcp/crosswalkDigest.ts +5 -0
  302. package/src/mcp/cyberEssentials.ts +60 -0
  303. package/src/mcp/dashboard.ts +232 -0
  304. package/src/mcp/dependencies.ts +190 -0
  305. package/src/mcp/frameworks.ts +236 -0
  306. package/src/mcp/geminiSanitizer.ts +212 -0
  307. package/src/mcp/git.ts +1116 -0
  308. package/src/mcp/guardrails.ts +771 -0
  309. package/src/mcp/issue.ts +74 -0
  310. package/src/mcp/issueComments.ts +48 -0
  311. package/src/mcp/issueEvents.ts +100 -0
  312. package/src/mcp/issueInfo.ts +72 -0
  313. package/src/mcp/labels.ts +35 -0
  314. package/src/mcp/localContext.ts +65 -0
  315. package/src/mcp/localServer.ts +217 -0
  316. package/src/mcp/moduleExtraction.ts +368 -0
  317. package/src/mcp/moduleTests.ts +421 -0
  318. package/src/mcp/modules.ts +752 -0
  319. package/src/mcp/output.ts +71 -0
  320. package/src/mcp/pathSafety.ts +28 -0
  321. package/src/mcp/policy.ts +226 -0
  322. package/src/mcp/pr.ts +238 -0
  323. package/src/mcp/prInfo.ts +91 -0
  324. package/src/mcp/providerSchema.ts +175 -0
  325. package/src/mcp/review.ts +1081 -0
  326. package/src/mcp/reviewComments.ts +1137 -0
  327. package/src/mcp/roots.ts +217 -0
  328. package/src/mcp/scope.ts +82 -0
  329. package/src/mcp/selectMode.ts +207 -0
  330. package/src/mcp/server.ts +498 -0
  331. package/src/mcp/shared.ts +120 -0
  332. package/src/mcp/shell.ts +631 -0
  333. package/src/mcp/staleFix.ts +557 -0
  334. package/src/mcp/terraform/__snapshots__/moduleDocs.test.ts.snap +40 -0
  335. package/src/mcp/terraform/azurePrices.ts +38 -0
  336. package/src/mcp/terraform/baseline.ts +172 -0
  337. package/src/mcp/terraform/concernResult.ts +111 -0
  338. package/src/mcp/terraform/cost.ts +175 -0
  339. package/src/mcp/terraform/cspm.ts +326 -0
  340. package/src/mcp/terraform/currency.ts +354 -0
  341. package/src/mcp/terraform/decisions.ts +590 -0
  342. package/src/mcp/terraform/eidas.ts +134 -0
  343. package/src/mcp/terraform/evidence.ts +771 -0
  344. package/src/mcp/terraform/findings.ts +383 -0
  345. package/src/mcp/terraform/fixMemory.ts +253 -0
  346. package/src/mcp/terraform/governance.ts +231 -0
  347. package/src/mcp/terraform/hcl.ts +273 -0
  348. package/src/mcp/terraform/iacLanguages.ts +431 -0
  349. package/src/mcp/terraform/idleFloor.ts +304 -0
  350. package/src/mcp/terraform/keyless.ts +123 -0
  351. package/src/mcp/terraform/moduleDocs.ts +303 -0
  352. package/src/mcp/terraform/nativeRules.ts +152 -0
  353. package/src/mcp/terraform/nativeScan.ts +67 -0
  354. package/src/mcp/terraform/noiseProfile.ts +183 -0
  355. package/src/mcp/terraform/normalization.ts +265 -0
  356. package/src/mcp/terraform/oscal.ts +283 -0
  357. package/src/mcp/terraform/packs/azurerm-3-4.ts +382 -0
  358. package/src/mcp/terraform/packs/cloudflare-4-5.ts +114 -0
  359. package/src/mcp/terraform/paths.ts +59 -0
  360. package/src/mcp/terraform/plan.ts +377 -0
  361. package/src/mcp/terraform/planDrift.ts +520 -0
  362. package/src/mcp/terraform/policyAuthor.ts +886 -0
  363. package/src/mcp/terraform/prowlerOcsf.ts +380 -0
  364. package/src/mcp/terraform/refactor.ts +879 -0
  365. package/src/mcp/terraform/registry.ts +317 -0
  366. package/src/mcp/terraform/risk.ts +99 -0
  367. package/src/mcp/terraform/scanSession.ts +242 -0
  368. package/src/mcp/terraform/scannerCache.ts +86 -0
  369. package/src/mcp/terraform/scannerEgress.ts +141 -0
  370. package/src/mcp/terraform/scannerJson.ts +22 -0
  371. package/src/mcp/terraform/scanners.ts +1134 -0
  372. package/src/mcp/terraform/signing.ts +151 -0
  373. package/src/mcp/terraform/stateLocking.ts +106 -0
  374. package/src/mcp/terraform/subprocess.ts +102 -0
  375. package/src/mcp/terraform/suppressions.ts +551 -0
  376. package/src/mcp/terraform/taxonomy.ts +0 -0
  377. package/src/mcp/terraform/tfquery.ts +159 -0
  378. package/src/mcp/terraform/toolchainIntegrity.ts +151 -0
  379. package/src/mcp/terraform/tools/authorPolicy.ts +185 -0
  380. package/src/mcp/terraform/tools/detectPlanDrift.ts +279 -0
  381. package/src/mcp/terraform/tools/emitCost.ts +130 -0
  382. package/src/mcp/terraform/tools/emitSarif.ts +108 -0
  383. package/src/mcp/terraform/tools/fixMemory.ts +82 -0
  384. package/src/mcp/terraform/tools/infracostDiff.ts +110 -0
  385. package/src/mcp/terraform/tools/ingestExternalFindings.ts +259 -0
  386. package/src/mcp/terraform/tools/moduleLookup.ts +86 -0
  387. package/src/mcp/terraform/tools/moduleSearch.ts +46 -0
  388. package/src/mcp/terraform/tools/plan.ts +384 -0
  389. package/src/mcp/terraform/tools/providerUpgrade.ts +217 -0
  390. package/src/mcp/terraform/tools/readFindings.ts +138 -0
  391. package/src/mcp/terraform/tools/scan.ts +303 -0
  392. package/src/mcp/terraform/tools/validate.ts +160 -0
  393. package/src/mcp/terraform/tools/verifyRemediation.ts +190 -0
  394. package/src/mcp/terraform/tools/versionCurrency.ts +64 -0
  395. package/src/mcp/terraform/tools.ts +62 -0
  396. package/src/mcp/terraform/transformPacks.ts +594 -0
  397. package/src/mcp/terraform/types.ts +382 -0
  398. package/src/mcp/terraform/verification.ts +150 -0
  399. package/src/mcp/terraform/vex.ts +367 -0
  400. package/src/mcp/terraform/writeOnly.ts +252 -0
  401. package/src/mcp/terraform.ts +52 -0
  402. package/src/mcp/terratest.ts +215 -0
  403. package/src/mcp/untrustedContent.ts +126 -0
  404. package/src/mcp/upload.ts +123 -0
  405. package/src/models.ts +753 -0
  406. package/src/modes/address-reviews.ts +35 -0
  407. package/src/modes/assess.ts +27 -0
  408. package/src/modes/build.ts +86 -0
  409. package/src/modes/compliance-audit.ts +25 -0
  410. package/src/modes/cost-optimization.ts +36 -0
  411. package/src/modes/drift-detect.ts +31 -0
  412. package/src/modes/fix.ts +29 -0
  413. package/src/modes/incremental-review.ts +103 -0
  414. package/src/modes/index.ts +94 -0
  415. package/src/modes/modernize-deprecated.ts +36 -0
  416. package/src/modes/plan.ts +21 -0
  417. package/src/modes/policy-gate.ts +27 -0
  418. package/src/modes/prFormats.ts +325 -0
  419. package/src/modes/refactor.ts +74 -0
  420. package/src/modes/refresh-remediation.ts +40 -0
  421. package/src/modes/remediate-and-refactor.ts +42 -0
  422. package/src/modes/remediate.ts +78 -0
  423. package/src/modes/resolve-conflicts.ts +32 -0
  424. package/src/modes/review.ts +135 -0
  425. package/src/modes/summarize-pr.ts +42 -0
  426. package/src/modes/task.ts +26 -0
  427. package/src/modes/terraform-code-review.ts +68 -0
  428. package/src/modes/types.ts +17 -0
  429. package/src/modes/update-dependencies.ts +44 -0
  430. package/src/prep/index.ts +96 -0
  431. package/src/prep/installNodeDependencies.ts +251 -0
  432. package/src/prep/installPythonDependencies.ts +235 -0
  433. package/src/prep/types.ts +38 -0
  434. package/src/reviewQuality.ts +237 -0
  435. package/src/runCli.ts +335 -0
  436. package/src/skills/terraform-best-practices/SKILL.md +379 -0
  437. package/src/toolState.ts +241 -0
  438. package/src/utils/activity.ts +210 -0
  439. package/src/utils/agent.ts +245 -0
  440. package/src/utils/agentHangReport.ts +180 -0
  441. package/src/utils/annotations.ts +56 -0
  442. package/src/utils/apiFetch.ts +19 -0
  443. package/src/utils/apiKeys.ts +305 -0
  444. package/src/utils/apiUrl.ts +42 -0
  445. package/src/utils/assets.ts +123 -0
  446. package/src/utils/baseRefConfig.ts +254 -0
  447. package/src/utils/billingErrors.ts +210 -0
  448. package/src/utils/body.ts +168 -0
  449. package/src/utils/buildInfraweaverFooter.ts +104 -0
  450. package/src/utils/byokFallback.ts +137 -0
  451. package/src/utils/changeImpact.ts +330 -0
  452. package/src/utils/claudeSubscription.ts +93 -0
  453. package/src/utils/cli.ts +36 -0
  454. package/src/utils/cloudClient.ts +57 -0
  455. package/src/utils/cloudFetchCore.ts +139 -0
  456. package/src/utils/cloudReport.ts +316 -0
  457. package/src/utils/codexHome.ts +204 -0
  458. package/src/utils/codexOAuth.ts +154 -0
  459. package/src/utils/codexRefreshDetect.ts +36 -0
  460. package/src/utils/diffCoverage.ts +404 -0
  461. package/src/utils/env.ts +84 -0
  462. package/src/utils/errorReport.ts +94 -0
  463. package/src/utils/exitHandler.ts +35 -0
  464. package/src/utils/fixDoubleEscapedString.ts +9 -0
  465. package/src/utils/ghaCore.ts +13 -0
  466. package/src/utils/gitAuth.ts +268 -0
  467. package/src/utils/gitAuthServer.ts +186 -0
  468. package/src/utils/github.ts +676 -0
  469. package/src/utils/globals.ts +9 -0
  470. package/src/utils/humanEditCapture.ts +198 -0
  471. package/src/utils/infraweaverConfig.ts +202 -0
  472. package/src/utils/install.ts +279 -0
  473. package/src/utils/instructions.ts +640 -0
  474. package/src/utils/keylessOidc.ts +47 -0
  475. package/src/utils/leapingComment.ts +20 -0
  476. package/src/utils/learnings.ts +145 -0
  477. package/src/utils/learningsTruncate.ts +42 -0
  478. package/src/utils/lifecycle.ts +198 -0
  479. package/src/utils/log.ts +452 -0
  480. package/src/utils/modelResolver.ts +105 -0
  481. package/src/utils/moduleFetch.ts +138 -0
  482. package/src/utils/normalizeEnv.ts +106 -0
  483. package/src/utils/openCodeModels.ts +86 -0
  484. package/src/utils/openaiCompatible.ts +52 -0
  485. package/src/utils/opentofuMcp.ts +61 -0
  486. package/src/utils/overrides.ts +100 -0
  487. package/src/utils/packageManager.ts +257 -0
  488. package/src/utils/patchWorkflowRunFields.ts +173 -0
  489. package/src/utils/payload.ts +1206 -0
  490. package/src/utils/prSummary.ts +148 -0
  491. package/src/utils/presets.ts +105 -0
  492. package/src/utils/progressComment.ts +266 -0
  493. package/src/utils/providerErrors.ts +189 -0
  494. package/src/utils/proxyModel.ts +239 -0
  495. package/src/utils/rangeDiff.ts +182 -0
  496. package/src/utils/redact.ts +86 -0
  497. package/src/utils/registryAuth.ts +115 -0
  498. package/src/utils/remediationCommand.ts +144 -0
  499. package/src/utils/retry.ts +180 -0
  500. package/src/utils/reviewCleanup.ts +116 -0
  501. package/src/utils/run.ts +100 -0
  502. package/src/utils/runContext.ts +276 -0
  503. package/src/utils/runContextData.ts +121 -0
  504. package/src/utils/runErrorRenderer.ts +282 -0
  505. package/src/utils/runFixture.ts +91 -0
  506. package/src/utils/runLifecycle.ts +360 -0
  507. package/src/utils/runStartupLog.ts +67 -0
  508. package/src/utils/secrets.ts +208 -0
  509. package/src/utils/setup.ts +368 -0
  510. package/src/utils/shell.ts +132 -0
  511. package/src/utils/skills.ts +67 -0
  512. package/src/utils/subprocess.ts +474 -0
  513. package/src/utils/terraformMcp.ts +99 -0
  514. package/src/utils/time.ts +59 -0
  515. package/src/utils/timer.ts +72 -0
  516. package/src/utils/todoTracking.ts +168 -0
  517. package/src/utils/token.ts +294 -0
  518. package/src/utils/toolLicensing.ts +152 -0
  519. package/src/utils/toolSelection.ts +239 -0
  520. package/src/utils/toon.ts +76 -0
  521. package/src/utils/version.ts +10 -0
  522. package/src/utils/versioning.ts +44 -0
  523. package/src/utils/vertex.ts +94 -0
  524. package/src/utils/workflow.ts +25 -0
@@ -0,0 +1,1253 @@
1
+ import { createHash } from "node:crypto";
2
+ import { type } from "arktype";
3
+ import { EXPECTED_CROSSWALK_DIGEST } from "#app/mcp/crosswalkDigest";
4
+ import { FRAMEWORKS } from "#app/mcp/frameworks";
5
+ import type { LocalToolContext } from "#app/mcp/localContext";
6
+ import { execute, tool, toolOk } from "#app/mcp/shared";
7
+ import type { Concern } from "#app/mcp/terraform/types";
8
+ import {
9
+ type ConcernVerificationStatus,
10
+ concernVerificationStatus,
11
+ } from "#app/mcp/terraform/verification";
12
+ import { log } from "#app/utils/cli";
13
+
14
+ /**
15
+ * Compliance crosswalk ("explain like I'm the auditor", the
16
+ * seed of the moat). Maps a best-practice concern → the control families
17
+ * it touches across UK public-sector + general frameworks, so a remediation can
18
+ * be narrated to an assessor in their own language ("this closes NCSC Cloud
19
+ * Principle 2 / Cyber Essentials Secure Configuration") rather than as a raw
20
+ * scanner rule id.
21
+ *
22
+ * SCOPE / HONESTY: this is a deterministic STARTER rule-pack keyed on the
23
+ * defect's THEME (encryption, public exposure, least-privilege, logging, …),
24
+ * not a certified control-by-control mapping. The durable product is a
25
+ * versioned, framework-revision-pinned crosswalk — so every mapping
26
+ * carries the pack version + date and is labelled indicative, never an audit
27
+ * verdict. No open crosswalk to UK frameworks exists; this is the wedge.
28
+ */
29
+
30
+ export const CROSSWALK_VERSION = "0.6.0";
31
+ /** the date this rule-pack's framework references were last reviewed (absolute). */
32
+ export const CROSSWALK_REVIEWED = "2026-07-26";
33
+
34
+ export interface ControlRef {
35
+ /** the framework, e.g. "NCSC Cloud Security Principles". */
36
+ framework: string;
37
+ /** the control id within that framework, e.g. "Principle 2". */
38
+ control: string;
39
+ /** the control's short title. */
40
+ title: string;
41
+ }
42
+
43
+ /** a theme of defect, the signals that identify it, and the controls it maps to. */
44
+ interface CrosswalkRule {
45
+ theme: string;
46
+ /** lowercased substrings that, if any appears in the rule_id/evidence, match. */
47
+ signals: string[];
48
+ controls: ControlRef[];
49
+ }
50
+
51
+ // The starter rule-pack. Themes are matched against the concern's rule_id +
52
+ // evidence (lowercased). Ordered most-specific first; a concern can match
53
+ // several themes (their controls are unioned). Kept deliberately small and
54
+ // auditable — each control ref is a real, citable control family.
55
+ const CROSSWALK: CrosswalkRule[] = [
56
+ {
57
+ theme: "encryption-at-rest",
58
+ // NB avoid the bare token "sse" — it's a substring of "essential"/"asset"
59
+ // and would false-match; use the explicit phrases instead.
60
+ signals: [
61
+ "encrypt",
62
+ "kms",
63
+ "server-side encryption",
64
+ "server_side_encryption",
65
+ "sse_algorithm",
66
+ "at rest",
67
+ "at-rest",
68
+ "unencrypted",
69
+ ],
70
+ controls: [
71
+ {
72
+ framework: "NCSC Cloud Security Principles",
73
+ control: "Principle 1",
74
+ title: "Data in transit protection",
75
+ },
76
+ {
77
+ framework: "Cyber Essentials",
78
+ control: "Secure Configuration",
79
+ title: "Secure configuration",
80
+ },
81
+ {
82
+ framework: "CIS Controls v8",
83
+ control: "3.11",
84
+ title: "Encrypt sensitive data at rest",
85
+ },
86
+ {
87
+ framework: "NHS DSPT",
88
+ control: "Standard 1",
89
+ title: "Personal confidential data protected",
90
+ },
91
+ ],
92
+ },
93
+ {
94
+ theme: "encryption-in-transit",
95
+ signals: [
96
+ "tls",
97
+ "ssl",
98
+ "https",
99
+ "in transit",
100
+ "in-transit",
101
+ "insecure protocol",
102
+ "http ",
103
+ ],
104
+ controls: [
105
+ {
106
+ framework: "NCSC Cloud Security Principles",
107
+ control: "Principle 1",
108
+ title: "Data in transit protection",
109
+ },
110
+ {
111
+ framework: "CIS Controls v8",
112
+ control: "3.10",
113
+ title: "Encrypt sensitive data in transit",
114
+ },
115
+ ],
116
+ },
117
+ {
118
+ theme: "public-exposure",
119
+ signals: [
120
+ "public",
121
+ "0.0.0.0/0",
122
+ "publicly",
123
+ "anonymous",
124
+ "open to the internet",
125
+ "ingress",
126
+ ],
127
+ controls: [
128
+ {
129
+ framework: "NCSC Cloud Security Principles",
130
+ control: "Principle 9",
131
+ title: "Secure user management / network separation",
132
+ },
133
+ {
134
+ framework: "Cyber Essentials",
135
+ control: "Firewalls",
136
+ title: "Boundary firewalls and internet gateways",
137
+ },
138
+ {
139
+ framework: "CIS Controls v8",
140
+ control: "4.4",
141
+ title: "Implement and manage a firewall on servers",
142
+ },
143
+ {
144
+ framework: "Secure by Design",
145
+ control: "SbD-7",
146
+ title: "Protect data in transit and at rest",
147
+ },
148
+ ],
149
+ },
150
+ {
151
+ theme: "least-privilege",
152
+ signals: [
153
+ "iam",
154
+ "wildcard",
155
+ "least privilege",
156
+ "least-privilege",
157
+ "policy",
158
+ "admin",
159
+ "privilege",
160
+ "*:*",
161
+ "role",
162
+ ],
163
+ controls: [
164
+ {
165
+ framework: "NCSC Cloud Security Principles",
166
+ control: "Principle 9",
167
+ title: "Secure user management",
168
+ },
169
+ {
170
+ framework: "Cyber Essentials",
171
+ control: "User Access Control",
172
+ title: "User access control",
173
+ },
174
+ {
175
+ framework: "CIS Controls v8",
176
+ control: "6.8",
177
+ title: "Define and maintain role-based access control",
178
+ },
179
+ {
180
+ framework: "NHS DSPT",
181
+ control: "Standard 4",
182
+ title: "Managing access",
183
+ },
184
+ ],
185
+ },
186
+ {
187
+ theme: "logging-audit",
188
+ // NB avoid the bare token "log" — it's a substring of "catalog"/"blog" and
189
+ // would false-match; use the explicit phrases/longer tokens instead.
190
+ signals: [
191
+ "logging",
192
+ "log group",
193
+ "audit",
194
+ "cloudtrail",
195
+ "flow log",
196
+ "access log",
197
+ "monitoring",
198
+ "cloudwatch",
199
+ ],
200
+ controls: [
201
+ {
202
+ framework: "NCSC Cloud Security Principles",
203
+ control: "Principle 13",
204
+ title: "Audit information and alerting",
205
+ },
206
+ {
207
+ framework: "CIS Controls v8",
208
+ control: "8.2",
209
+ title: "Collect audit logs",
210
+ },
211
+ {
212
+ framework: "NHS DSPT",
213
+ control: "Standard 7",
214
+ title: "Continuity planning / monitoring",
215
+ },
216
+ { framework: "SOC 2", control: "CC7.2", title: "Security monitoring" },
217
+ ],
218
+ },
219
+ {
220
+ theme: "backup-resilience",
221
+ signals: [
222
+ "versioning",
223
+ "backup",
224
+ "snapshot",
225
+ "retention",
226
+ "deletion protection",
227
+ "multi-az",
228
+ ],
229
+ controls: [
230
+ {
231
+ framework: "NCSC Cloud Security Principles",
232
+ control: "Principle 2",
233
+ title: "Asset protection and resilience",
234
+ },
235
+ {
236
+ framework: "NHS DSPT",
237
+ control: "Standard 7",
238
+ title: "Continuity planning",
239
+ },
240
+ {
241
+ framework: "CIS Controls v8",
242
+ control: "11.2",
243
+ title: "Perform automated backups",
244
+ },
245
+ ],
246
+ },
247
+ {
248
+ theme: "secrets-management",
249
+ signals: [
250
+ "secret",
251
+ "credential",
252
+ "password",
253
+ "hardcoded",
254
+ "plaintext",
255
+ "access key",
256
+ "token",
257
+ ],
258
+ controls: [
259
+ {
260
+ framework: "NCSC Cloud Security Principles",
261
+ control: "Principle 10",
262
+ title: "Identity and authentication",
263
+ },
264
+ {
265
+ framework: "CIS Controls v8",
266
+ control: "16.4",
267
+ title: "Securely store credentials",
268
+ },
269
+ {
270
+ framework: "Cyber Essentials",
271
+ control: "Secure Configuration",
272
+ title: "Secure configuration",
273
+ },
274
+ ],
275
+ },
276
+ {
277
+ theme: "network-segmentation",
278
+ // internal segmentation (vs the internet-facing "public-exposure" theme):
279
+ // NB avoid the bare token "tag"/"acl" — use explicit phrases.
280
+ signals: [
281
+ "security group",
282
+ "network acl",
283
+ "nacl",
284
+ "subnet",
285
+ "vpc peering",
286
+ "unrestricted egress",
287
+ "egress to 0.0.0.0/0",
288
+ ],
289
+ controls: [
290
+ {
291
+ framework: "NCSC Cloud Security Principles",
292
+ control: "Principle 9",
293
+ title: "Network separation",
294
+ },
295
+ {
296
+ framework: "CIS Controls v8",
297
+ control: "12.2",
298
+ title: "Establish and maintain a secure network architecture",
299
+ },
300
+ {
301
+ framework: "Secure by Design",
302
+ control: "SbD-5",
303
+ title: "Segment networks",
304
+ },
305
+ ],
306
+ },
307
+ {
308
+ theme: "mfa-strong-auth",
309
+ signals: [
310
+ "mfa",
311
+ "multi-factor",
312
+ "multi factor",
313
+ "password policy",
314
+ "root account",
315
+ "root user",
316
+ "console access",
317
+ ],
318
+ controls: [
319
+ {
320
+ framework: "Cyber Essentials",
321
+ control: "User Access Control",
322
+ title: "User access control",
323
+ },
324
+ {
325
+ framework: "CIS Controls v8",
326
+ control: "6.5",
327
+ title: "Require MFA for administrative access",
328
+ },
329
+ {
330
+ framework: "NCSC Cloud Security Principles",
331
+ control: "Principle 10",
332
+ title: "Identity and authentication",
333
+ },
334
+ {
335
+ framework: "NHS DSPT",
336
+ control: "Standard 4",
337
+ title: "Managing access",
338
+ },
339
+ ],
340
+ },
341
+ {
342
+ theme: "patch-currency",
343
+ signals: [
344
+ "deprecated",
345
+ "outdated",
346
+ "end of life",
347
+ "end-of-life",
348
+ "unsupported",
349
+ "legacy runtime",
350
+ ],
351
+ controls: [
352
+ {
353
+ framework: "Cyber Essentials",
354
+ control: "Security Update Management",
355
+ title: "Security update management",
356
+ },
357
+ {
358
+ framework: "CIS Controls v8",
359
+ control: "7.3",
360
+ title: "Perform automated operating system patch management",
361
+ },
362
+ {
363
+ framework: "NCSC Cloud Security Principles",
364
+ control: "Principle 5",
365
+ title: "Operational security",
366
+ },
367
+ ],
368
+ },
369
+ {
370
+ theme: "container-hardening",
371
+ // Covers Terraform ECS/EKS AND the multi-language Assess formats — Kubernetes
372
+ // manifests, Helm charts, and Dockerfiles (trivy/checkov emit these prose
373
+ // strings). NB "root user" is deliberately NOT here (it's an AWS-root signal
374
+ // under mfa-strong-auth); dockerfile "runs as root" uses "run as root" /
375
+ // "runasnonroot" instead so the two don't cross-match.
376
+ signals: [
377
+ "privileged",
378
+ "container",
379
+ "ecs task",
380
+ "fargate",
381
+ "kubernetes",
382
+ "pod security",
383
+ "host network",
384
+ "hostpath",
385
+ "runasnonroot",
386
+ "run as root",
387
+ "running as root",
388
+ "allowprivilegeescalation",
389
+ "privilege escalation",
390
+ "readonlyrootfilesystem",
391
+ "securitycontext",
392
+ "security context",
393
+ "linux capabilities",
394
+ "add capabilities",
395
+ "healthcheck",
396
+ "latest tag",
397
+ "image tag",
398
+ "seccomp",
399
+ "apparmor",
400
+ ],
401
+ controls: [
402
+ {
403
+ framework: "NCSC Cloud Security Principles",
404
+ control: "Principle 5",
405
+ title: "Operational security",
406
+ },
407
+ {
408
+ framework: "CIS Controls v8",
409
+ control: "4.1",
410
+ title: "Establish and maintain a secure configuration process",
411
+ },
412
+ {
413
+ framework: "Secure by Design",
414
+ control: "SbD-3",
415
+ title: "Minimise the attack surface",
416
+ },
417
+ ],
418
+ },
419
+ {
420
+ theme: "resource-governance",
421
+ // governance / asset hygiene (tagging, naming) — matches real scanner prose
422
+ // ("resource is not tagged") without the bare token "tag" (substring of "stage").
423
+ signals: [
424
+ "not tagged",
425
+ "untagged",
426
+ "tagging",
427
+ "missing tag",
428
+ "required tags",
429
+ "naming convention",
430
+ ],
431
+ controls: [
432
+ {
433
+ framework: "NCSC Cloud Security Principles",
434
+ control: "Principle 2",
435
+ title: "Asset protection and resilience",
436
+ },
437
+ {
438
+ framework: "CIS Controls v8",
439
+ control: "1.1",
440
+ title: "Establish and maintain detailed enterprise asset inventory",
441
+ },
442
+ {
443
+ framework: "GDS Service Standard",
444
+ control: "Point 14",
445
+ title: "Operate a reliable service",
446
+ },
447
+ ],
448
+ },
449
+ {
450
+ // The governance band of the native rule pack ([[nativeRules]]): imperative
451
+ // side-effects and input-bound destroy protection are change-control facts,
452
+ // not misconfigurations. Signals are the exact HCL constructs, so this theme
453
+ // can only fire on a finding that named one — no prose match, no drift into
454
+ // the other eleven themes.
455
+ theme: "change-control",
456
+ signals: [
457
+ "action_trigger",
458
+ "imperative-action-trigger",
459
+ "provider action",
460
+ "prevent_destroy",
461
+ "dynamic-destroy-protection",
462
+ "destroy protection",
463
+ // drift findings ([[planDrift]] `drift-<kind>-<address>` rule tokens): an
464
+ // out-of-band change to live infrastructure is the change-control failure
465
+ // mode itself. Exact rule tokens, same discipline as the rest of this
466
+ // theme — prose like "drift" alone must not match (tflint has fmt-drift
467
+ // rule names that are style, not change control).
468
+ "drift-modified",
469
+ "drift-deleted",
470
+ "drift-recreated",
471
+ "drift-replaced",
472
+ ],
473
+ controls: [
474
+ {
475
+ framework: "NCSC Cloud Security Principles",
476
+ control: "Principle 5",
477
+ title: "Operational security (change management)",
478
+ },
479
+ {
480
+ framework: "CIS Controls v8",
481
+ control: "4.2",
482
+ title:
483
+ "Establish and maintain a secure configuration process for network infrastructure",
484
+ },
485
+ {
486
+ framework: "GDS Service Standard",
487
+ control: "Point 14",
488
+ title: "Operate a reliable service",
489
+ },
490
+ ],
491
+ },
492
+ ];
493
+
494
+ // ── §5.14 crosswalk hub: NIST SP 800-53 rev 5 spine + CSF 2.0 pivot ────────────
495
+ // The hub keys THEMES (not findings) to 800-53 — one curated table — after which
496
+ // every further framework layer is scheme-requirement-id → 800-53 → themes: one
497
+ // mechanical, auditable hop. 800-53 is the only candidate whose full text is
498
+ // embeddable forever at zero cost (CC0 OSCAL, usnistgov/oscal-content), and its
499
+ // enhancement granularity (SC-28(1), SC-7(5)) fits IaC findings far better than
500
+ // clause-level frameworks. CSF 2.0 is the EU-facing pivot (CyFun/Ireland are
501
+ // CSF-2.0-shaped); its subcategories attach through their NIST-published 800-53
502
+ // informative references, so both layers stay coherent for free.
503
+
504
+ const NIST_800_53_NAME = "NIST SP 800-53";
505
+ const NIST_CSF_NAME = "NIST CSF 2.0";
506
+ const DORA_RTS_NAME = "DORA RTS (EU) 2024/1774";
507
+ const NCSC_CAF_NAME = "NCSC Cyber Assessment Framework";
508
+
509
+ /**
510
+ * Titles of every 800-53 control the hub references, keyed by display id
511
+ * ("SC-28(1)" — OSCAL id "sc-28.1"). Transcribed from the CC0 OSCAL rev 5.2.0
512
+ * catalog (public domain worldwide), so embedding is unconditionally lawful.
513
+ */
514
+ const NIST_800_53_TITLES: Record<string, string> = {
515
+ "AC-3": "Access Enforcement",
516
+ "AC-4": "Information Flow Enforcement",
517
+ "AC-6": "Least Privilege",
518
+ "AC-6(1)": "Authorize Access to Security Functions",
519
+ "AC-6(10)":
520
+ "Prohibit Non-privileged Users from Executing Privileged Functions",
521
+ "AC-17(2)": "Protection of Confidentiality and Integrity Using Encryption",
522
+ "AU-2": "Event Logging",
523
+ "AU-11": "Audit Record Retention",
524
+ "AU-12": "Audit Record Generation",
525
+ "CM-2": "Baseline Configuration",
526
+ "CM-3": "Configuration Change Control",
527
+ "CM-4": "Impact Analyses",
528
+ "CM-5": "Access Restrictions for Change",
529
+ "CM-6": "Configuration Settings",
530
+ "CM-7": "Least Functionality",
531
+ "CM-8": "System Component Inventory",
532
+ "CM-12": "Information Location",
533
+ "CP-6": "Alternate Storage Site",
534
+ "CP-9": "System Backup",
535
+ "CP-10": "System Recovery and Reconstitution",
536
+ "IA-2": "Identification and Authentication (Organizational Users)",
537
+ "IA-2(1)": "Multi-factor Authentication to Privileged Accounts",
538
+ "IA-2(2)": "Multi-factor Authentication to Non-privileged Accounts",
539
+ "IA-5": "Authenticator Management",
540
+ "IA-5(1)": "Password-based Authentication",
541
+ "IA-5(7)": "No Embedded Unencrypted Static Authenticators",
542
+ "SA-22": "Unsupported System Components",
543
+ "SC-7": "Boundary Protection",
544
+ "SC-7(3)": "Access Points",
545
+ "SC-7(5)": "Deny by Default — Allow by Exception",
546
+ "SC-8": "Transmission Confidentiality and Integrity",
547
+ "SC-8(1)": "Cryptographic Protection",
548
+ "SC-12": "Cryptographic Key Establishment and Management",
549
+ "SC-13": "Cryptographic Protection",
550
+ "SC-28": "Protection of Information at Rest",
551
+ "SC-28(1)": "Cryptographic Protection",
552
+ "SC-39": "Process Isolation",
553
+ "SI-2": "Flaw Remediation",
554
+ "SI-4": "System Monitoring",
555
+ };
556
+
557
+ /**
558
+ * THE HUB TABLE (§5.14 step 2): defect theme → the 800-53 rev 5 controls it
559
+ * evidences. Hand-curated to the technically-enforceable band an IaC scan can
560
+ * honestly speak to (crypto, IAM, segmentation, logging, secure-config, backup
561
+ * topology) — never the organisational/process/physical bands. The theme layer
562
+ * insulates every downstream framework from an 800-53 rev 6 restructure.
563
+ */
564
+ export const THEME_TO_NIST: Record<string, string[]> = {
565
+ "encryption-at-rest": ["SC-28", "SC-28(1)", "SC-12", "SC-13"],
566
+ "encryption-in-transit": ["SC-8", "SC-8(1)", "SC-13", "AC-17(2)"],
567
+ "public-exposure": ["SC-7", "SC-7(3)", "SC-7(5)", "AC-3", "CM-7"],
568
+ "least-privilege": ["AC-3", "AC-6", "AC-6(1)", "AC-6(10)"],
569
+ "logging-audit": ["AU-2", "AU-11", "AU-12", "SI-4"],
570
+ "backup-resilience": ["CP-6", "CP-9", "CP-10"],
571
+ "secrets-management": ["IA-5", "IA-5(7)", "SC-12", "SC-28"],
572
+ "network-segmentation": ["AC-4", "SC-7", "SC-7(5)"],
573
+ "mfa-strong-auth": ["IA-2", "IA-2(1)", "IA-2(2)", "IA-5(1)"],
574
+ "patch-currency": ["SI-2", "SA-22"],
575
+ "container-hardening": ["CM-2", "CM-6", "CM-7", "SC-39"],
576
+ "resource-governance": ["CM-8", "CM-12"],
577
+ "change-control": ["CM-2", "CM-3", "CM-4", "CM-5"],
578
+ };
579
+
580
+ /** One requirement of a hub-anchored framework layer. */
581
+ interface HubRequirement {
582
+ /** The requirement id as the Cloud pack and evidence bundle cite it. */
583
+ id: string;
584
+ /** Short label for `ControlRef.title` (the pack carries the full wording). */
585
+ title: string;
586
+ /** The 800-53 spine ids this requirement is anchored to. A requirement
587
+ * attaches to a theme exactly when one of these appears in that theme's
588
+ * `THEME_TO_NIST` row — the single mechanical, auditable hop. */
589
+ nist: string[];
590
+ }
591
+
592
+ /** A framework layer that rides the 800-53 spine rather than being hand-themed. */
593
+ interface HubLayer {
594
+ /** Display name — MUST equal a `FrameworkDef.name` in the registry. */
595
+ framework: string;
596
+ requirements: HubRequirement[];
597
+ }
598
+
599
+ /**
600
+ * NIST CSF 2.0 — the EU-facing pivot (CyFun and Ireland's baseline are
601
+ * CSF-2.0-shaped). Anchors are NIST's own CSF↔800-53 informative references
602
+ * (OLIR/CPRT), trimmed to the ids the spine carries. References that would
603
+ * create dishonest joins are deliberately omitted (PR.PS-01 keeps CM-2/CM-6 but
604
+ * not CM-7, so a public-exposure finding never claims "configuration
605
+ * management practices").
606
+ */
607
+ const CSF_2_0_LAYER: HubLayer = {
608
+ framework: NIST_CSF_NAME,
609
+ requirements: [
610
+ {
611
+ id: "PR.DS-01",
612
+ title: "Data-at-rest protected",
613
+ nist: ["SC-28", "SC-28(1)"],
614
+ },
615
+ {
616
+ id: "PR.DS-02",
617
+ title: "Data-in-transit protected",
618
+ nist: ["SC-8", "SC-8(1)"],
619
+ },
620
+ {
621
+ id: "PR.DS-11",
622
+ title: "Backups created, protected, and tested",
623
+ nist: ["CP-6", "CP-9", "CP-10"],
624
+ },
625
+ {
626
+ id: "PR.AA-01",
627
+ title: "Identities and credentials managed",
628
+ nist: ["IA-5", "IA-5(7)"],
629
+ },
630
+ {
631
+ id: "PR.AA-03",
632
+ title: "Users, services, and hardware authenticated",
633
+ nist: ["IA-2", "IA-2(1)", "IA-2(2)"],
634
+ },
635
+ {
636
+ id: "PR.AA-05",
637
+ title: "Least-privilege access permissions enforced",
638
+ nist: ["AC-3", "AC-6", "AC-6(1)"],
639
+ },
640
+ {
641
+ id: "PR.PS-01",
642
+ title: "Configuration management practices applied",
643
+ nist: ["CM-2", "CM-6"],
644
+ },
645
+ {
646
+ id: "PR.PS-02",
647
+ title: "Software maintained and replaced by risk",
648
+ nist: ["SI-2", "SA-22"],
649
+ },
650
+ {
651
+ id: "PR.PS-04",
652
+ title: "Log records generated for monitoring",
653
+ nist: ["AU-2", "AU-12"],
654
+ },
655
+ {
656
+ id: "PR.IR-01",
657
+ title: "Networks protected from unauthorized access",
658
+ nist: ["SC-7", "SC-7(5)", "AC-4"],
659
+ },
660
+ {
661
+ id: "DE.CM-09",
662
+ title: "Computing resources monitored for adverse events",
663
+ nist: ["SI-4"],
664
+ },
665
+ {
666
+ id: "ID.AM-02",
667
+ title: "Software and system inventories maintained",
668
+ nist: ["CM-8"],
669
+ },
670
+ ],
671
+ };
672
+
673
+ /**
674
+ * DORA technical layer (§5.15) — Commission Delegated Regulation (EU) 2024/1774,
675
+ * the RTS on ICT risk-management tools, methods, processes and policies. It is
676
+ * the RTS that gives concrete technical form to DORA (Reg. (EU) 2022/2554)
677
+ * **Art. 9 "Protection and prevention"** and **Art. 10 "Detection"**; the
678
+ * requirement ids below are RTS articles, not DORA Level-1 articles (RTS Art. 9
679
+ * is "Capacity and performance management" and RTS Art. 10 is "Vulnerability and
680
+ * patch management" — different instruments, same numbers, so we cite the RTS
681
+ * explicitly and never write a bare "Article 9").
682
+ *
683
+ * Surface: RTS Section 4 (Encryption and cryptography, Arts 6–7), Section 5 (ICT
684
+ * operations security, Arts 8–12), Section 6 (Network security, Arts 13–14) and
685
+ * Chapter II access control (Arts 20–21) — precisely the config-band articles.
686
+ *
687
+ * HONESTY: this is "evidence toward the DORA technical controls", never "DORA
688
+ * compliant". Roughly half of DORA — governance, business-continuity testing,
689
+ * third-party risk and the Register of Information, TLPT, physical security — is
690
+ * outside anything an IaC scan can observe; the Cloud pack carries those
691
+ * articles as scanner-less rows so the published coverage % states the gap.
692
+ * EUR-Lex text is reusable commercially under Commission Decision 2011/833/EU.
693
+ */
694
+ const DORA_RTS_LAYER: HubLayer = {
695
+ framework: DORA_RTS_NAME,
696
+ requirements: [
697
+ {
698
+ id: "RTS-6(2)",
699
+ title: "Encryption of data at rest, in transit, and in use",
700
+ nist: ["SC-28", "SC-28(1)", "SC-8", "SC-8(1)", "SC-13"],
701
+ },
702
+ {
703
+ id: "RTS-7(1)",
704
+ title: "Cryptographic key lifecycle management",
705
+ nist: ["SC-12"],
706
+ },
707
+ {
708
+ id: "RTS-8(2)(b)",
709
+ title: "Backup, restore, and environment separation",
710
+ nist: ["CP-6", "CP-9", "CP-10"],
711
+ },
712
+ {
713
+ id: "RTS-10(4)",
714
+ title: "Patch identification and deployment",
715
+ nist: ["SI-2", "SA-22"],
716
+ },
717
+ {
718
+ id: "RTS-11(2)(a)",
719
+ title: "Access restrictions by data classification",
720
+ nist: ["AC-3"],
721
+ },
722
+ {
723
+ id: "RTS-11(2)(b)",
724
+ title: "Secure configuration baselines minimising exposure",
725
+ nist: ["CM-2", "CM-6"],
726
+ },
727
+ {
728
+ id: "RTS-12(2)(a)",
729
+ title: "Log event scope and retention periods",
730
+ nist: ["AU-11"],
731
+ },
732
+ {
733
+ id: "RTS-12(2)(c)",
734
+ title: "Logging of access, ICT operations, and network traffic",
735
+ nist: ["AU-2", "AU-12"],
736
+ },
737
+ {
738
+ id: "RTS-13(a)",
739
+ title: "Network segregation and segmentation",
740
+ nist: ["AC-4", "SC-7"],
741
+ },
742
+ {
743
+ id: "RTS-13(d)",
744
+ title: "Network access controls on unauthorised connections",
745
+ nist: ["SC-7", "SC-7(5)"],
746
+ },
747
+ {
748
+ id: "RTS-13(e)",
749
+ title: "Encryption of network communications",
750
+ nist: ["SC-8", "SC-8(1)", "AC-17(2)"],
751
+ },
752
+ {
753
+ id: "RTS-13(g)",
754
+ title: "Securing traffic to internet and external connections",
755
+ nist: ["SC-7", "SC-7(3)"],
756
+ },
757
+ {
758
+ id: "RTS-13(h)",
759
+ title: "Firewall rule specification and review",
760
+ nist: ["SC-7(5)"],
761
+ },
762
+ {
763
+ id: "RTS-14(1)",
764
+ title: "Securing information in transit",
765
+ nist: ["SC-8", "SC-8(1)"],
766
+ },
767
+ {
768
+ id: "RTS-20(2)(a)",
769
+ title: "Unique identity and user account",
770
+ nist: ["IA-2"],
771
+ },
772
+ {
773
+ id: "RTS-21(a)",
774
+ title: "Least-privilege and need-to-know access rights",
775
+ nist: ["AC-6", "AC-6(1)"],
776
+ },
777
+ {
778
+ id: "RTS-21(d)",
779
+ title: "Access restriction controls on ICT assets",
780
+ nist: ["AC-3"],
781
+ },
782
+ {
783
+ id: "RTS-21(f)",
784
+ title: "Strong authentication for privileged and remote access",
785
+ nist: ["IA-2(1)", "IA-2(2)", "IA-5(1)"],
786
+ },
787
+ ],
788
+ };
789
+
790
+ /**
791
+ * NCSC Cyber Assessment Framework v4.0 (B.2) — the UK layer that matters for
792
+ * the Cyber Security and Resilience Bill, NIS-regulated operators and the
793
+ * public-sector buyers who assess against GovAssure.
794
+ *
795
+ * ⚠️ READ THIS BEFORE EDITING. The CAF is **not** the framework the legacy
796
+ * `ncsc-caf` slug names — that slug belongs to the NCSC *Cloud Security
797
+ * Principles*, and for a while five product surfaces advertised "NCSC CAF"
798
+ * while mapping to the Principles. This layer is the real thing; its registry
799
+ * slug is `ncsc-caf-v4` precisely so the two can never merge.
800
+ *
801
+ * Authored against the published v4.0 PDF, not from recall — v4.0 restructured
802
+ * the contributing outcomes substantially (A2.b became "Understanding Threat",
803
+ * A4.b "Secure Software Development and Support" is new, C1 lost an outcome to
804
+ * consolidation, C2 collapsed to a single "Threat Hunting"), so a v3.2-shaped
805
+ * mapping would cite outcomes that no longer exist.
806
+ *
807
+ * HONESTY. The CAF is an **outcome-based** framework assessed on Indicators of
808
+ * Good Practice, most of which describe organisational behaviour — governance,
809
+ * risk process, supply chain, staff training, incident response. Of its 37
810
+ * contributing outcomes, the 13 below are the only ones an IaC scan can speak
811
+ * to at all, and even those it evidences *partially*: CAF asks whether a
812
+ * practice is working, and we can only show what the code declares. The Cloud
813
+ * pack carries all 37 rows so the published coverage % states that gap rather
814
+ * than hiding it. This is "evidence toward CAF outcomes", never "CAF achieved"
815
+ * — the CAF's own achievement levels (Not / Partially / Achieved) are an
816
+ * assessor's judgement and nothing here may present as one.
817
+ */
818
+ const NCSC_CAF_LAYER: HubLayer = {
819
+ framework: NCSC_CAF_NAME,
820
+ requirements: [
821
+ { id: "A3.a", title: "Asset Management", nist: ["CM-8", "CM-12"] },
822
+ {
823
+ id: "B2.a",
824
+ title: "Identity Verification, Authentication and Authorisation",
825
+ nist: ["IA-2", "IA-2(1)", "IA-2(2)", "IA-5(1)"],
826
+ },
827
+ {
828
+ id: "B2.c",
829
+ title: "Privileged User Management",
830
+ nist: ["AC-6", "AC-6(1)", "AC-6(10)"],
831
+ },
832
+ {
833
+ id: "B2.d",
834
+ title: "Identity and Access Management (IdAM)",
835
+ nist: ["AC-3", "IA-5", "IA-5(7)"],
836
+ },
837
+ {
838
+ id: "B3.b",
839
+ title: "Data in Transit",
840
+ nist: ["SC-8", "SC-8(1)", "AC-17(2)"],
841
+ },
842
+ {
843
+ id: "B3.c",
844
+ title: "Stored Data",
845
+ nist: ["SC-28", "SC-28(1)", "SC-12", "SC-13"],
846
+ },
847
+ // CM-7 (least functionality) is deliberately omitted, exactly as CSF
848
+ // PR.PS-01 omits it: it would make every public-exposure finding claim
849
+ // "Secure Configuration", a join the evidence does not support.
850
+ { id: "B4.b", title: "Secure Configuration", nist: ["CM-2", "CM-6"] },
851
+ { id: "B4.c", title: "Secure Management", nist: ["CM-3", "CM-4", "CM-5"] },
852
+ { id: "B4.d", title: "Vulnerability Management", nist: ["SI-2", "SA-22"] },
853
+ { id: "B5.a", title: "Resilience Preparation", nist: ["CP-9", "CP-10"] },
854
+ { id: "B5.b", title: "Design for Resilience", nist: ["CP-6", "AC-4"] },
855
+ {
856
+ id: "C1.a",
857
+ title: "Sources and Tools for Logging and Monitoring",
858
+ nist: ["AU-2", "AU-12", "SI-4"],
859
+ },
860
+ // Retention only (AU-11). The access half of C1.b would need AC-3, which
861
+ // would drag every least-privilege finding into a logging claim.
862
+ { id: "C1.b", title: "Securing Logs", nist: ["AU-11"] },
863
+ ],
864
+ };
865
+
866
+ /**
867
+ * Every hub-anchored layer, in citation order. Adding a framework wave is one
868
+ * more entry here plus the matching Cloud pack rows — no engine logic changes.
869
+ */
870
+ const HUB_LAYERS: HubLayer[] = [CSF_2_0_LAYER, DORA_RTS_LAYER, NCSC_CAF_LAYER];
871
+
872
+ /**
873
+ * The hub-derived control refs for a set of themes: the 800-53 spine controls
874
+ * (sorted) plus every hub-layer requirement whose anchors intersect those spine
875
+ * ids. Deterministic + pure. Conservative fan-out is by design — an exposure
876
+ * finding lights all boundary controls rather than risk a false pass on a
877
+ * related one.
878
+ */
879
+ export function hubControlsForThemes(themes: string[]): ControlRef[] {
880
+ const nistIds = new Set<string>();
881
+ for (const theme of themes) {
882
+ for (const id of THEME_TO_NIST[theme] ?? []) nistIds.add(id);
883
+ }
884
+ const refs: ControlRef[] = [];
885
+ for (const id of [...nistIds].sort()) {
886
+ refs.push({
887
+ framework: NIST_800_53_NAME,
888
+ control: id,
889
+ title: NIST_800_53_TITLES[id] ?? id,
890
+ });
891
+ }
892
+ for (const layer of HUB_LAYERS) {
893
+ for (const req of layer.requirements) {
894
+ if (!req.nist.some((id) => nistIds.has(id))) continue;
895
+ refs.push({
896
+ framework: layer.framework,
897
+ control: req.id,
898
+ title: req.title,
899
+ });
900
+ }
901
+ }
902
+ return refs;
903
+ }
904
+
905
+ /**
906
+ * Map a single concern to the indicative control references it touches. Matches
907
+ * the concern's `rule_id` + `evidence` (and an optional `category`) against the
908
+ * crosswalk themes; unions the controls of every theme that fires. Pure.
909
+ * Returns an empty array when nothing matches (honest — better than a forced
910
+ * mapping). De-duplicates identical control refs.
911
+ */
912
+ export function mapConcernToControls(concern: {
913
+ rule_id: string;
914
+ evidence: string;
915
+ category?: string;
916
+ }): { themes: string[]; controls: ControlRef[] } {
917
+ assertCrosswalkIntegrity();
918
+ const haystack = `${concern.rule_id} ${concern.evidence}`.toLowerCase();
919
+ const themes: string[] = [];
920
+ const controls: ControlRef[] = [];
921
+ const seen = new Set<string>();
922
+ for (const rule of CROSSWALK) {
923
+ if (!rule.signals.some((s) => haystack.includes(s))) continue;
924
+ themes.push(rule.theme);
925
+ for (const c of rule.controls) {
926
+ const key = `${c.framework}|${c.control}`;
927
+ if (seen.has(key)) continue;
928
+ seen.add(key);
929
+ controls.push(c);
930
+ }
931
+ }
932
+ // The §5.14 hub layers ride behind the theme layer: 800-53 spine + CSF pivot.
933
+ for (const c of hubControlsForThemes(themes)) {
934
+ const key = `${c.framework}|${c.control}`;
935
+ if (seen.has(key)) continue;
936
+ seen.add(key);
937
+ controls.push(c);
938
+ }
939
+ return { themes, controls };
940
+ }
941
+
942
+ /**
943
+ * Authored mapping from a defect THEME → the maintained Cloud crosswalk PACK
944
+ * control ids it evidences (infraweaver-ui `src/features/crosswalk/pack.ts`). This
945
+ * is the engine⇄Cloud JOIN KEY: a reported finding carries these ids in its
946
+ * `compliance[]`, so the Cloud `/compliance` verdicts and the required-control
947
+ * violation detection bind to REAL findings (without it they keyed on engine
948
+ * control names and never joined the pack's ids — the C1 divergence).
949
+ *
950
+ * HAND-SYNCED with pack.ts, exactly like the report wire schema — every id here
951
+ * must exist there. The engine themes are coarser than the pack's controls, so a
952
+ * theme fans out to every control it plausibly evidences (conservative: an
953
+ * exposure finding lights all boundary/exposure controls rather than risk a false
954
+ * pass on a related one). A theme with no honest pack control maps to `[]` — we
955
+ * emit NOTHING rather than mis-attribute (vuln-management, key-rotation and
956
+ * malware controls have no code-verifiable theme and stay unmapped).
957
+ */
958
+ const THEME_TO_PACK_CONTROLS: Record<string, string[]> = {
959
+ // encryption at rest → CE A2.1, ISO A.8.24, NCSC P2.
960
+ "encryption-at-rest": ["A2.1", "A.8.24", "P2"],
961
+ // in-transit has no CE/ISO-pinned control here → NCSC P1 only.
962
+ "encryption-in-transit": ["P1"],
963
+ // boundary + public storage exposure across all three frameworks.
964
+ "public-exposure": ["A1.1", "A1.2", "A2.3", "A.8.20", "A.5.23", "P5"],
965
+ "least-privilege": ["A4.1", "A.5.15", "P9"],
966
+ // secure configuration & logging (CE A2.2 explicitly covers logging).
967
+ "logging-audit": ["A2.2", "A.8.16", "P13"],
968
+ // resilience maps onto NCSC P2 (asset protection & resilience).
969
+ "backup-resilience": ["P2"],
970
+ // hardcoded secrets are a secure-configuration failure (CE A2.2).
971
+ "secrets-management": ["A2.2"],
972
+ // internal segmentation lights the boundary-firewall + network controls.
973
+ "network-segmentation": ["A1.1", "A1.2", "P5"],
974
+ // MFA / strong auth maps onto user-access control + identity.
975
+ "mfa-strong-auth": ["A4.1", "P9"],
976
+ // privileged/over-broad container config is a secure-configuration failure.
977
+ "container-hardening": ["A2.2"],
978
+ // patch-currency + governance/tagging have no honest UK-pack control → no UK
979
+ // ids here. Since the §5.14 hub they DO emit their 800-53/CSF pack ids (SI-2,
980
+ // SA-22, CM-8, … via `packControlsForThemes`) — real homes, not mis-attribution.
981
+ "patch-currency": [],
982
+ "resource-governance": [],
983
+ // change-control is a governance band no UK starter-pack control speaks to
984
+ // honestly (CE and the NCSC principles are technical-configuration frameworks).
985
+ // Its 800-53/CSF/DORA ids still flow through `packControlsForThemes` via the
986
+ // hub, which is where a change-control claim actually belongs.
987
+ "change-control": [],
988
+ };
989
+
990
+ // ── Integrity gate (LLM04) ──────────────────────────────────────────────────────
991
+ // The crosswalk drives compliance verdicts, so a poisoned control mapping would
992
+ // yield a false "compliant" — the worst failure for an attestation product. We pin a
993
+ // sha256 of the reviewed tables and verify it before any verdict is produced; a
994
+ // mismatch fail-closes. Regenerate the pin with `pnpm run gen:crosswalk-digest` after
995
+ // an intended crosswalk edit. The digest also rides in the (Ed25519-signed) evidence
996
+ // bundle, so the exact table that produced each attestation is cryptographically bound.
997
+
998
+ /** Deterministic, key-sorted serialization — the exact bytes the digest covers. */
999
+ function stableStringify(value: unknown): string {
1000
+ if (value === null || typeof value !== "object")
1001
+ return JSON.stringify(value) ?? "null";
1002
+ if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
1003
+ const obj = value as Record<string, unknown>;
1004
+ return `{${Object.keys(obj)
1005
+ .sort()
1006
+ .map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`)
1007
+ .join(",")}}`;
1008
+ }
1009
+
1010
+ /** The canonical payload of the curated crosswalk tables + version stamps. Pure. */
1011
+ export function canonicalCrosswalkPayload(): string {
1012
+ return stableStringify({
1013
+ version: CROSSWALK_VERSION,
1014
+ reviewed: CROSSWALK_REVIEWED,
1015
+ crosswalk: CROSSWALK,
1016
+ themeToPackControls: THEME_TO_PACK_CONTROLS,
1017
+ // §5.14 hub layers — a poisoned spine or layer table would mis-verdict every
1018
+ // downstream framework, so the digest covers them (and the registry) too.
1019
+ frameworks: FRAMEWORKS,
1020
+ themeToNist: THEME_TO_NIST,
1021
+ nistTitles: NIST_800_53_TITLES,
1022
+ hubLayers: HUB_LAYERS,
1023
+ });
1024
+ }
1025
+
1026
+ /** sha256 (hex) of the canonical crosswalk payload. Pure. */
1027
+ export function crosswalkDigest(): string {
1028
+ return createHash("sha256").update(canonicalCrosswalkPayload()).digest("hex");
1029
+ }
1030
+
1031
+ /** The digest of the crosswalk actually loaded in this build (computed once). */
1032
+ export const CROSSWALK_DIGEST = crosswalkDigest();
1033
+
1034
+ /**
1035
+ * Fail-closed integrity gate. Throws when the loaded crosswalk doesn't match the
1036
+ * pinned, reviewed digest — so no compliance verdict can be produced from a tampered
1037
+ * or poisoned table. Every verdict-producing entry calls this. The args are injectable
1038
+ * so a test can exercise the mismatch path without corrupting the real module.
1039
+ */
1040
+ export function assertCrosswalkIntegrity(
1041
+ actual: string = CROSSWALK_DIGEST,
1042
+ expected: string = EXPECTED_CROSSWALK_DIGEST,
1043
+ ): void {
1044
+ if (actual !== expected) {
1045
+ throw new Error(
1046
+ `crosswalk integrity check failed: loaded digest ${actual} does not match the pinned ${expected}. ` +
1047
+ "The compliance crosswalk was modified without re-pinning — run `pnpm run gen:crosswalk-digest` if the " +
1048
+ "change is intended, otherwise treat this as tampering (LLM04).",
1049
+ );
1050
+ }
1051
+ }
1052
+
1053
+ /** The maintained-pack control ids a concern's themes evidence (deduped, sorted).
1054
+ * Empty when nothing maps. Pure. See {@link THEME_TO_PACK_CONTROLS}. */
1055
+ export function packControlsForThemes(themes: string[]): string[] {
1056
+ const ids = new Set<string>();
1057
+ for (const theme of themes) {
1058
+ for (const id of THEME_TO_PACK_CONTROLS[theme] ?? []) ids.add(id);
1059
+ }
1060
+ // The hub layers (800-53 + CSF 2.0) exist in the Cloud pack under the SAME
1061
+ // control ids the hub tables carry, so the join needs no second hand-synced
1062
+ // table — one source (THEME_TO_NIST / HUB_LAYERS) feeds both the narrated
1063
+ // crosswalk and the pack join key.
1064
+ for (const ref of hubControlsForThemes(themes)) ids.add(ref.control);
1065
+ return [...ids].sort();
1066
+ }
1067
+
1068
+ /**
1069
+ * The maintained Cloud-pack control ids a single concern maps to — the values
1070
+ * the cloud report puts in each finding's `compliance[]` so the dashboard's
1071
+ * control verdicts and required-control gate join on real findings. Pure.
1072
+ */
1073
+ export function packControlsForConcern(concern: {
1074
+ rule_id: string;
1075
+ evidence: string;
1076
+ category?: string;
1077
+ }): string[] {
1078
+ return packControlsForThemes(mapConcernToControls(concern).themes);
1079
+ }
1080
+
1081
+ export interface ConcernForCrosswalk {
1082
+ id: string;
1083
+ rule_id: string;
1084
+ evidence: string;
1085
+ category?: string;
1086
+ severity?: string;
1087
+ location?: { file: string; line: number | null };
1088
+ }
1089
+
1090
+ export interface CrosswalkEntry {
1091
+ concern_id: string;
1092
+ rule_id: string;
1093
+ themes: string[];
1094
+ controls: ControlRef[];
1095
+ /** the five-status verdict for this control statement: `fail` (code-verified
1096
+ * violation) or `not-code-verifiable` (a human-decision control the engine can
1097
+ * flag but not prove). Lets an assessor read the crosswalk honestly. */
1098
+ status: ConcernVerificationStatus;
1099
+ }
1100
+
1101
+ export interface CrosswalkReport {
1102
+ version: string;
1103
+ reviewed: string;
1104
+ /** per-concern control mappings (only concerns that mapped to ≥1 control). */
1105
+ entries: CrosswalkEntry[];
1106
+ /** framework → the distinct controls this scan touched, for an auditor index. */
1107
+ by_framework: Record<string, { control: string; title: string }[]>;
1108
+ /** concerns that did not map to any control (honest coverage signal). */
1109
+ unmapped_concern_ids: string[];
1110
+ }
1111
+
1112
+ /**
1113
+ * Build the auditor crosswalk for a set of concerns: per-concern control refs
1114
+ * plus a `by_framework` index (which controls this scan touched, deduped) and an
1115
+ * honest `unmapped` list. Pure + deterministic. Carries the pack version + date
1116
+ * so the report is reproducible and clearly indicative.
1117
+ */
1118
+ export function buildCrosswalkReport(
1119
+ concerns: ConcernForCrosswalk[],
1120
+ ): CrosswalkReport {
1121
+ assertCrosswalkIntegrity();
1122
+ const entries: CrosswalkEntry[] = [];
1123
+ const unmapped: string[] = [];
1124
+ const byFramework = new Map<string, Map<string, string>>();
1125
+ for (const c of concerns) {
1126
+ const { themes, controls } = mapConcernToControls(c);
1127
+ if (controls.length === 0) {
1128
+ unmapped.push(c.id);
1129
+ continue;
1130
+ }
1131
+ entries.push({
1132
+ concern_id: c.id,
1133
+ rule_id: c.rule_id,
1134
+ themes,
1135
+ controls,
1136
+ status: concernVerificationStatus(c).status,
1137
+ });
1138
+ for (const ctl of controls) {
1139
+ const map = byFramework.get(ctl.framework) ?? new Map<string, string>();
1140
+ if (!map.has(ctl.control)) map.set(ctl.control, ctl.title);
1141
+ byFramework.set(ctl.framework, map);
1142
+ }
1143
+ }
1144
+ const by_framework: Record<string, { control: string; title: string }[]> = {};
1145
+ for (const [framework, controls] of [...byFramework.entries()].sort((a, b) =>
1146
+ a[0].localeCompare(b[0]),
1147
+ )) {
1148
+ by_framework[framework] = [...controls.entries()]
1149
+ .map(([control, title]) => ({ control, title }))
1150
+ .sort((a, b) => a.control.localeCompare(b.control));
1151
+ }
1152
+ return {
1153
+ version: CROSSWALK_VERSION,
1154
+ reviewed: CROSSWALK_REVIEWED,
1155
+ entries,
1156
+ by_framework,
1157
+ unmapped_concern_ids: unmapped,
1158
+ };
1159
+ }
1160
+
1161
+ /**
1162
+ * The tokens a `required_controls` policy can match a concern on (lower-cased):
1163
+ * each mapped control's framework, control id, `framework|control` key and title,
1164
+ * the defect themes, AND the maintained-pack control ids the concern evidences.
1165
+ * So a policy entry can require a whole framework ("Cyber Essentials"), a single
1166
+ * control ("Secure Configuration" or "Cyber Essentials|Secure Configuration"), a
1167
+ * theme ("encryption-at-rest"), or a Cloud-pack control id ("A2.1") — the last is
1168
+ * what the Cloud "required controls" policy sends down via run-context. Pure.
1169
+ */
1170
+ export function controlMatchTokens(concern: {
1171
+ rule_id: string;
1172
+ evidence: string;
1173
+ category?: string;
1174
+ }): string[] {
1175
+ const { themes, controls } = mapConcernToControls(concern);
1176
+ const tokens = new Set<string>();
1177
+ for (const t of themes) tokens.add(t.toLowerCase());
1178
+ for (const c of controls) {
1179
+ tokens.add(c.framework.toLowerCase());
1180
+ tokens.add(c.control.toLowerCase());
1181
+ tokens.add(`${c.framework}|${c.control}`.toLowerCase());
1182
+ tokens.add(c.title.toLowerCase());
1183
+ }
1184
+ // The Cloud pack control ids (e.g. "A2.1") so an org's dashboard required-control
1185
+ // policy, delivered as pack ids over run-context, enforces in the CI gate.
1186
+ for (const id of packControlsForThemes(themes)) tokens.add(id.toLowerCase());
1187
+ return [...tokens];
1188
+ }
1189
+
1190
+ /**
1191
+ * The OPEN concerns that map to at least one REQUIRED compliance control — these
1192
+ * fail the CI gate regardless of severity (the 2g-vi "required control" policy:
1193
+ * a CISO marks the controls that MUST stay clean, e.g. encryption-at-rest for
1194
+ * SOC 2). `required` is matched case-insensitively against each concern's
1195
+ * framework / control / `framework|control` / title / theme (see
1196
+ * `controlMatchTokens`). Suppressed (accepted) concerns never count. Pure.
1197
+ */
1198
+ export function requiredControlViolations(
1199
+ concerns: Concern[],
1200
+ required: string[],
1201
+ ): Concern[] {
1202
+ assertCrosswalkIntegrity();
1203
+ const wanted = new Set(
1204
+ required.map((r) => r.trim().toLowerCase()).filter(Boolean),
1205
+ );
1206
+ if (wanted.size === 0) return [];
1207
+ return concerns.filter(
1208
+ (c) =>
1209
+ !c.suppression &&
1210
+ controlMatchTokens(c).some((token) => wanted.has(token)),
1211
+ );
1212
+ }
1213
+
1214
+ export const ComplianceCrosswalkParams = type({
1215
+ concerns: type({
1216
+ id: type.string,
1217
+ rule_id: type.string,
1218
+ evidence: type.string,
1219
+ "category?": type.string,
1220
+ "severity?": type.string,
1221
+ })
1222
+ .array()
1223
+ .describe(
1224
+ "the concerns to map (pass the `concerns` array from terraform_scan/read_findings).",
1225
+ ),
1226
+ });
1227
+
1228
+ export function ComplianceCrosswalkTool(ctx: LocalToolContext) {
1229
+ void ctx;
1230
+ return tool({
1231
+ name: "terraform_compliance_crosswalk",
1232
+ description:
1233
+ "Map a scan's concerns to the UK public-sector + general compliance controls they touch — NCSC " +
1234
+ "Cloud Security Principles, Cyber Essentials, NHS DSPT, Secure by Design, CIS Controls, SOC 2, plus the " +
1235
+ "NIST SP 800-53 rev 5 spine, NIST CSF 2.0 pivot, DORA RTS (EU) 2024/1774 and the NCSC Cyber " +
1236
+ "Assessment Framework v4.0 (§5.14 crosswalk hub) — so a " +
1237
+ "remediation PR can be narrated to an ASSESSOR in their own framework. Pass the `concerns` from " +
1238
+ "terraform_scan/read_findings; returns a per-concern control mapping plus a `by_framework` index and an " +
1239
+ "honest `unmapped_concern_ids` list. The mapping is an INDICATIVE starter rule-pack (version + review " +
1240
+ "date included) keyed on the defect theme — cite it as 'indicative alignment', never an audit verdict.",
1241
+ parameters: ComplianceCrosswalkParams,
1242
+ execute: execute(async ({ concerns }) => {
1243
+ const report = buildCrosswalkReport(concerns as ConcernForCrosswalk[]);
1244
+ log.info(
1245
+ `» terraform_compliance_crosswalk: ${report.entries.length} mapped / ${report.unmapped_concern_ids.length} unmapped across ${Object.keys(report.by_framework).length} framework(s)`,
1246
+ );
1247
+ return toolOk({
1248
+ ...report,
1249
+ note: `Indicative crosswalk v${report.version} (reviewed ${report.reviewed}) — alignment guidance, not an audit verdict.`,
1250
+ });
1251
+ }),
1252
+ });
1253
+ }