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,771 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { basename, dirname } from "node:path";
3
+ import { type } from "arktype";
4
+ import { EVIDENCE_FILE, PRODUCT_NAME, TOOL_NAME } from "#app/brand";
5
+ import {
6
+ type AssessmentScorecard,
7
+ type AssessWaiver,
8
+ runAssessmentPipeline,
9
+ } from "#app/mcp/assess";
10
+ import { CROSSWALK_DIGEST, type CrosswalkReport } from "#app/mcp/crosswalk";
11
+ import type { LocalToolContext } from "#app/mcp/localContext";
12
+ import { resolveWithinCwd } from "#app/mcp/pathSafety";
13
+ import { execute, tool, toolOk } from "#app/mcp/shared";
14
+ import { type EidasSeal, eidasSealFor } from "#app/mcp/terraform/eidas";
15
+ import {
16
+ IDLE_FLOOR_ASSERTS,
17
+ IDLE_FLOOR_DOES_NOT_ASSERT,
18
+ type IdleFloorReport,
19
+ } from "#app/mcp/terraform/idleFloor";
20
+ import {
21
+ buildInTotoStatement,
22
+ keylessBundlePath,
23
+ keylessSigningPossible,
24
+ keylessSignStatement,
25
+ } from "#app/mcp/terraform/keyless";
26
+ import type { DriftEvidenceStatement } from "#app/mcp/terraform/planDrift";
27
+ import {
28
+ collectWorkspaceProvenance,
29
+ type ModuleProvenance,
30
+ } from "#app/mcp/terraform/refactor";
31
+ import {
32
+ scanSessionOf,
33
+ upgradeStatementOf,
34
+ } from "#app/mcp/terraform/scanSession";
35
+ import {
36
+ loadSigningKey,
37
+ type SignatureMetadata,
38
+ signatureMetadata,
39
+ signBytes,
40
+ } from "#app/mcp/terraform/signing";
41
+ import { probedToolVersions } from "#app/mcp/terraform/toolchainIntegrity";
42
+ import type { UpgradeEvidenceStatement } from "#app/mcp/terraform/transformPacks";
43
+ import {
44
+ type Concern,
45
+ concernKeyOf,
46
+ type Severity,
47
+ } from "#app/mcp/terraform/types";
48
+ import {
49
+ VERIFICATION_STATUS_LABEL,
50
+ type VerificationStatus,
51
+ type VerificationSummary,
52
+ } from "#app/mcp/terraform/verification";
53
+ import { log } from "#app/utils/cli";
54
+ import { githubContext } from "#app/utils/env";
55
+ import packageJson from "#package.json" with { type: "json" };
56
+
57
+ /**
58
+ * Backend-free compliance evidence bundle (the WS4a wedge — an auditor-facing
59
+ * artifact the OSS action can emit with **zero cloud and no backend**, committed
60
+ * to a `compliance/` path). It packages the read-only assessment — posture,
61
+ * per-control statements with their five-status verdict ([[verification]]), the
62
+ * crosswalk index, and the scanner coverage — into one deterministic JSON file.
63
+ *
64
+ * SCHEMA / HONESTY: this is Infraweaver's OWN structured schema, NOT OSCAL. A
65
+ * strict OSCAL (or compliance-trestle / C2P) emitter is a deliberate follow-up,
66
+ * gated on a buyer who actually needs OSCAL — emitting OSCAL nobody consumes is
67
+ * cost without value. The bundle is INDICATIVE alignment guidance, never an audit
68
+ * verdict, and it never claims `pass` for an unfired control (absence of a
69
+ * finding is not proof). Pure builder + a thin file-writing tool.
70
+ */
71
+
72
+ // v0.2 was ADDITIVE over v0.1 (the `signature` field — Ed25519 signing metadata,
73
+ // or an explicit null when no signing key is configured — see [[signing]]).
74
+ // v0.3 is ADDITIVE over v0.2: each control statement gains `concern_key`, the
75
+ // line-independent anchor (sha1(source|rule|file)) that stays stable across a fix
76
+ // that shifts lines — the deep-link key a dashboard finding uses to locate its
77
+ // entry in this bundle. Every prior field is unchanged, so older consumers parse.
78
+ // v0.4 is ADDITIVE over v0.3: an optional `cost` block carrying the §5.19
79
+ // credential-free IDLE FLOOR (what the configuration bills at zero traffic) with
80
+ // its explicit asserts / does_not_assert pair. Present only when the cost tool
81
+ // ran; every prior field is unchanged.
82
+ // v0.6 is ADDITIVE over v0.5: an always-present `suppressions` block recording
83
+ // what the posture EXCLUDES because a human accepted it (count, per-source
84
+ // tally, never-expiring count, and every entry with its reason/expiry). The
85
+ // human-readable report always listed waivers; the signed artifact did not, so
86
+ // a repo with thirty active waivers signed identically to a clean one. Always
87
+ // present — including `count: 0` — because an omitted section is ambiguous.
88
+ // v0.7 is ADDITIVE over v0.6: an always-present `seal` block declaring the
89
+ // eIDAS electronic-seal tier the `signature` reaches — today `simple` (or
90
+ // `none` when unsigned), never `advanced`/`qualified`. Machine-readable rather
91
+ // than prose, because "signed ed25519" is easy to over-read as a legal seal in
92
+ // a procurement context and the difference is an Art. 35(2) presumption. The
93
+ // qualified seal itself (§5.16: ASiC-E/CAdES-LTA + an Art. 41 timestamp from a
94
+ // QTSP) is NOT built — it is blocked on trust-service onboarding, and this
95
+ // block is the schema slot it lands in without a breaking change.
96
+ // v0.5 was ADDITIVE over v0.4, two blocks:
97
+ // - `provenance` (always present) — WHO produced this evidence: the resolved
98
+ // model, the runtime, and the exact scanner versions the integrity gate
99
+ // observed before executing them (A.3 — the layer the Trivy compromise
100
+ // exploited; "evidence over trust" now covers the actor, not just the
101
+ // result).
102
+ // - `drift` (present only when detect_plan_drift ran) — the TC-2.1 statement:
103
+ // drift state, the `forgotten` blind-spot list, provider-noise filtering
104
+ // (auditable, field-by-field), and every coverage gap, each bound stated in
105
+ // the signed artifact itself.
106
+ // v0.8 is ADDITIVE over v0.7, one block:
107
+ // - `upgrade` (present only when terraform_provider_upgrade matched a pack) —
108
+ // the TC-2.2 statement: which provider major boundary was crossed, which
109
+ // codified transforms the configuration contained, and the plan that backs
110
+ // it. Carries the pack's own non-exhaustiveness into the signed bytes so a
111
+ // reader cannot mistake the transform list for a complete migration.
112
+ export const EVIDENCE_SCHEMA = "infraweaver-evidence/v0.8" as const;
113
+ export const DEFAULT_EVIDENCE_PATH = `compliance/${EVIDENCE_FILE}`;
114
+
115
+ export interface EvidenceControlStatement {
116
+ concern_id: string;
117
+ /** line-independent anchor (sha1(source|rule|file), see `concernKeyOf`) — the
118
+ * stable deep-link key into this bundle: a dashboard finding carries the same
119
+ * key, so its entry here is locatable even after a fix shifts line numbers.
120
+ * Absent when the backing concern wasn't supplied to the builder. */
121
+ concern_key?: string | undefined;
122
+ rule_id: string;
123
+ /** the five-status verdict for this statement (fail / not-code-verifiable). */
124
+ status: VerificationStatus;
125
+ severity?: string | undefined;
126
+ file?: string | undefined;
127
+ line?: number | null | undefined;
128
+ controls: { framework: string; control: string; title: string }[];
129
+ }
130
+
131
+ /**
132
+ * A refactor's evidence statement — emitted only for a refactor run. Carries the
133
+ * verdict, the equivalence sub-results that BACK it (when a keys-free proof ran),
134
+ * the adopted-module provenance, and — per §8 — BOTH what it asserts and what it
135
+ * explicitly does NOT. A `proposed-unproven` verdict (a b.4 third-party adoption
136
+ * shipped without a plan) asserts nothing about runtime behaviour.
137
+ */
138
+ export interface EvidenceRefactorStatement {
139
+ verdict: "equivalence-proven" | "equivalence-failed" | "proposed-unproven";
140
+ equivalence?:
141
+ | {
142
+ resource_set_preserved: boolean;
143
+ arguments_preserved: boolean;
144
+ moves_exhaustive: boolean;
145
+ moves_detected: number;
146
+ uncovered_moves: number;
147
+ validate_passed: boolean;
148
+ fmt_clean: boolean;
149
+ }
150
+ | undefined;
151
+ /** every external module the config adopts, with its pinned version (provenance
152
+ * discipline — the analog to a SHA-pinned action). */
153
+ module_provenance: ModuleProvenance[];
154
+ /** true when the change is proposed but unproven — the unmissable b.4 marker. */
155
+ proposed_unproven: boolean;
156
+ asserts: string;
157
+ does_not_assert: string;
158
+ }
159
+
160
+ /**
161
+ * The §5.19 cost statement: the credential-free IDLE FLOOR — what this
162
+ * configuration bills at zero traffic — with the same asserts/does_not_assert
163
+ * honesty pair the refactor statement carries. Deliberately NOT a monthly total:
164
+ * usage-dependent lines are not derivable from Terraform, so the floor is the
165
+ * only cost figure this bundle is willing to sign.
166
+ */
167
+ export interface EvidenceCostStatement {
168
+ /** Currency of every figure below (from the bundled price snapshot). */
169
+ currency: string;
170
+ /** Cloud region the list prices were captured for. */
171
+ region: string;
172
+ /** ISO date the bundled price snapshot was captured — makes staleness visible. */
173
+ priced_at: string;
174
+ /** Monthly cost that accrues at zero traffic. */
175
+ monthly_floor: number;
176
+ /** One entry per resource contributing to the floor. */
177
+ resources: {
178
+ address: string;
179
+ resource_type: string;
180
+ file: string;
181
+ line: number;
182
+ monthly_cost: number;
183
+ }[];
184
+ /** Catalogued resources left unpriced because their tier was not identifiable
185
+ * — the signed floor is a lower bound by exactly these. */
186
+ unpriced: {
187
+ address: string;
188
+ resource_type: string;
189
+ file: string;
190
+ line: number;
191
+ reason: string;
192
+ }[];
193
+ asserts: string;
194
+ does_not_assert: string;
195
+ }
196
+
197
+ /**
198
+ * Build the suppression summary (pure). Unlike `cost` and `drift`, this block is
199
+ * **always present** — including with `count: 0`. An omitted section would be
200
+ * ambiguous ("nothing silenced" vs "this version didn't record it"), and the
201
+ * whole point is that a reader can tell a clean repo from a quiet one without
202
+ * having to trust that we'd have mentioned it.
203
+ */
204
+ export function buildSuppressionSummary(
205
+ waivers: ReadonlyArray<AssessWaiver>,
206
+ ): EvidenceSuppressionSummary {
207
+ const by_source: Record<string, number> = {};
208
+ let never_expire = 0;
209
+ for (const w of waivers) {
210
+ by_source[w.source] = (by_source[w.source] ?? 0) + 1;
211
+ if (!w.expires) never_expire++;
212
+ }
213
+ return {
214
+ count: waivers.length,
215
+ by_source,
216
+ never_expire,
217
+ entries: waivers.map((w) => ({
218
+ rule_id: w.rule_id,
219
+ severity: w.severity,
220
+ file: w.file,
221
+ line: w.line,
222
+ reason: w.reason,
223
+ source: w.source,
224
+ expires: w.expires ?? null,
225
+ })),
226
+ asserts:
227
+ waivers.length === 0
228
+ ? "no finding was suppressed — the posture above covers everything the scanners reported."
229
+ : `${waivers.length} finding(s) were excluded from the posture above by an explicit, ` +
230
+ "reasoned suppression. Each is listed with its reason, source and expiry.",
231
+ does_not_assert:
232
+ "that a suppressed finding was fixed, or that its acceptance was correct — a waiver records " +
233
+ "a human decision, not a remediation. An expired waiver resurfaces the finding on the next " +
234
+ "run. An entry whose reason carries a `[via <tool> skip]` marker came from another scanner's " +
235
+ "own inline directive: honoured here, but neither authored nor reviewed here.",
236
+ };
237
+ }
238
+
239
+ /**
240
+ * Build the cost evidence statement (pure). Returns undefined when no cost
241
+ * analysis ran or nothing priced, so the bundle omits the section entirely
242
+ * rather than signing a zero that could be read as "this costs nothing".
243
+ */
244
+ export function buildCostStatement(
245
+ report: IdleFloorReport | undefined,
246
+ ): EvidenceCostStatement | undefined {
247
+ if (!report || report.items.length === 0) return undefined;
248
+ return {
249
+ currency: report.currency,
250
+ region: report.region,
251
+ priced_at: report.priced_at,
252
+ monthly_floor: report.monthly_floor,
253
+ resources: report.items.map((i) => ({
254
+ address: i.address,
255
+ resource_type: i.resourceType,
256
+ file: i.file,
257
+ line: i.line,
258
+ monthly_cost: i.monthly_cost,
259
+ })),
260
+ /** Catalogued resources left unpriced because their tier was not
261
+ * identifiable — the signed floor is a lower bound by exactly these. */
262
+ unpriced: report.unpriced.map((u) => ({
263
+ address: u.address,
264
+ resource_type: u.resourceType,
265
+ file: u.file,
266
+ line: u.line,
267
+ reason: u.reason,
268
+ })),
269
+ asserts: IDLE_FLOOR_ASSERTS,
270
+ does_not_assert: IDLE_FLOOR_DOES_NOT_ASSERT,
271
+ };
272
+ }
273
+
274
+ /** the equivalence sub-results buildRefactorStatement reads (the shape recorded
275
+ * in `scanSession.refactorEquivalence`). */
276
+ export interface RefactorEquivalenceInput {
277
+ equivalent: boolean;
278
+ resource_set_equivalent: boolean;
279
+ arg_names_equivalent: boolean;
280
+ moves_exhaustive: boolean;
281
+ moves_detected: number;
282
+ validate_passed: boolean;
283
+ fmt_clean: boolean;
284
+ uncovered_moves: { from: string; to: string }[];
285
+ }
286
+
287
+ /**
288
+ * Build the refactor evidence statement (pure). Returns undefined when nothing
289
+ * refactor-related happened (no equivalence proof, not a proposed-unproven b.4,
290
+ * no external module) so the bundle omits the section entirely. Infraweaver asserts
291
+ * only what the inputs prove — a failed or absent proof asserts nothing.
292
+ */
293
+ export function buildRefactorStatement(args: {
294
+ equivalence?: RefactorEquivalenceInput | undefined;
295
+ provenance: ModuleProvenance[];
296
+ proposedUnproven: boolean;
297
+ }): EvidenceRefactorStatement | undefined {
298
+ const { equivalence, provenance, proposedUnproven } = args;
299
+ if (!equivalence && !proposedUnproven && provenance.length === 0)
300
+ return undefined;
301
+
302
+ let verdict: EvidenceRefactorStatement["verdict"];
303
+ let asserts: string;
304
+ let doesNotAssert: string;
305
+ if (equivalence?.equivalent) {
306
+ verdict = "equivalence-proven";
307
+ asserts =
308
+ "structure changed, behaviour preserved — same resource set, identical arguments, every relocation covered by a `moved {}` block, terraform validate + fmt clean.";
309
+ doesNotAssert =
310
+ "that unrelated resources are correct or the configuration is otherwise optimal; completeness is never claimed.";
311
+ } else if (equivalence) {
312
+ verdict = "equivalence-failed";
313
+ asserts =
314
+ "nothing — the equivalence proof did NOT pass, so this change must not be treated as behaviour-preserving.";
315
+ doesNotAssert =
316
+ "behaviour-equivalence (the proof failed; see the run reasons).";
317
+ } else {
318
+ // proposed-unproven b.4 (or provenance recorded with no proof context).
319
+ verdict = "proposed-unproven";
320
+ asserts =
321
+ "nothing about runtime behaviour — this third-party-module adoption is PROPOSED only and was not verified against a plan.";
322
+ doesNotAssert =
323
+ "behaviour-equivalence (it alters behaviour and is not claimed equivalent); no terraform plan was run.";
324
+ }
325
+
326
+ return {
327
+ verdict,
328
+ equivalence: equivalence
329
+ ? {
330
+ resource_set_preserved: equivalence.resource_set_equivalent,
331
+ arguments_preserved: equivalence.arg_names_equivalent,
332
+ moves_exhaustive: equivalence.moves_exhaustive,
333
+ moves_detected: equivalence.moves_detected,
334
+ uncovered_moves: equivalence.uncovered_moves.length,
335
+ validate_passed: equivalence.validate_passed,
336
+ fmt_clean: equivalence.fmt_clean,
337
+ }
338
+ : undefined,
339
+ module_provenance: provenance,
340
+ proposed_unproven: verdict === "proposed-unproven",
341
+ asserts,
342
+ does_not_assert: doesNotAssert,
343
+ };
344
+ }
345
+
346
+ /**
347
+ * What this run did NOT judge, because a human had already accepted it.
348
+ *
349
+ * WHY THIS IS IN THE SIGNED BYTES. `posture` and `control_statements` describe
350
+ * the OPEN findings only — suppressed ones are excluded by design, because a
351
+ * waived finding genuinely is an accepted risk. But that means a repo with
352
+ * thirty active waivers produced a bundle byte-indistinguishable from a
353
+ * genuinely clean one, and the difference is exactly what an assessor is there
354
+ * to examine. The human-readable report has always listed waivers; the SIGNED
355
+ * artifact did not, which made the signature cover the flattering half of the
356
+ * story.
357
+ *
358
+ * Each entry is what was silenced, where it is, why (a reason is mandatory
359
+ * everywhere), by which mechanism, and until when.
360
+ *
361
+ * A note on `source`. It records the two things the suppression pipeline
362
+ * actually models: `inline` (a directive in the source file) and `policy` (the
363
+ * `.infraweaver.yml` block). A skip written for ANOTHER scanner
364
+ * (`# checkov:skip=…`) is honoured and lands under `inline`, with the pipeline's
365
+ * own `[via <tool> skip]` marker appended to its reason — so the distinction is
366
+ * visible in the entry without this block claiming a structured tally the
367
+ * concern model does not carry.
368
+ */
369
+ export interface EvidenceSuppressionRecord {
370
+ rule_id: string;
371
+ severity: string;
372
+ file: string;
373
+ line?: number | null | undefined;
374
+ /** mandatory everywhere; carries the `[via <tool> skip]` marker when the
375
+ * directive was another scanner's rather than ours. */
376
+ reason: string;
377
+ /** `inline` = a directive in the source file; `policy` = the `.infraweaver.yml` block. */
378
+ source: string;
379
+ /** ISO date the waiver lapses, or null for an open-ended one. */
380
+ expires: string | null;
381
+ }
382
+
383
+ export interface EvidenceSuppressionSummary {
384
+ /** how many findings this bundle's posture excludes. 0 ⇒ nothing silenced. */
385
+ count: number;
386
+ /** count by mechanism (`inline` / `policy`) — how the silencing was applied. */
387
+ by_source: Record<string, number>;
388
+ /** open-ended waivers — the ones with no review date. */
389
+ never_expire: number;
390
+ entries: EvidenceSuppressionRecord[];
391
+ asserts: string;
392
+ does_not_assert: string;
393
+ }
394
+
395
+ /**
396
+ * WHO produced this evidence (A.3). The bundle always named the engine; after
397
+ * the Trivy compromise that is not enough — a poisoned scanner produces
398
+ * poisoned findings under a clean engine version. This block records the whole
399
+ * acting chain: the model that drove the agent, the runtime, and the exact
400
+ * scanner builds the integrity gate observed (`toolchainIntegrity`) before
401
+ * executing them. Nothing here is fabricated: a tool that never ran this
402
+ * session is simply absent from `scanners`, and an unresolved model is null.
403
+ */
404
+ export interface EvidenceProvenance {
405
+ /** resolved model specifier that drove the agent, or null (auto/unknown —
406
+ * e.g. a local `infraweaver mcp` session has no agent of its own). */
407
+ model: string | null;
408
+ /** the Node.js runtime the engine executed on (`process.version`). */
409
+ node: string;
410
+ /** exact scanner versions probed by the integrity gate before execution —
411
+ * only tools that actually ran this session appear. */
412
+ scanners: { tool: string; version: string | null }[];
413
+ }
414
+
415
+ export interface EvidenceBundle {
416
+ /** Infraweaver's own schema id — explicitly NOT OSCAL (see module note). */
417
+ schema: typeof EVIDENCE_SCHEMA;
418
+ /** caller-supplied ISO timestamp (kept out of the builder so it stays pure). */
419
+ generated_at: string;
420
+ tool: { name: typeof TOOL_NAME; version: string };
421
+ /** who produced this evidence — model + runtime + observed scanner builds. */
422
+ provenance: EvidenceProvenance;
423
+ subject: {
424
+ scanned_dir: string;
425
+ repo?: string | undefined;
426
+ ref?: string | undefined;
427
+ commit?: string | undefined;
428
+ };
429
+ posture: AssessmentScorecard["posture"];
430
+ summary: {
431
+ total: number;
432
+ by_severity: AssessmentScorecard["by_severity"];
433
+ verification: VerificationSummary["counts"];
434
+ };
435
+ /** one statement per mapped concern, each carrying its status + controls. */
436
+ control_statements: EvidenceControlStatement[];
437
+ /** which scanners code-verified vs which were inconclusive (coverage gaps). */
438
+ coverage: VerificationSummary["coverage"];
439
+ /** what the posture above EXCLUDES because a human accepted it. Always
440
+ * present (0 when nothing was silenced) so a clean repo and a quiet one are
441
+ * distinguishable from the signed bytes alone. */
442
+ suppressions: EvidenceSuppressionSummary;
443
+ crosswalk: {
444
+ version: string;
445
+ reviewed: string;
446
+ /** sha256 of the reviewed crosswalk tables that produced these verdicts —
447
+ * binds the exact (integrity-gated) control mapping into the signed bundle. */
448
+ digest: string;
449
+ by_framework: CrosswalkReport["by_framework"];
450
+ };
451
+ /** the five-status legend, so the bundle is self-describing for an assessor. */
452
+ legend: Record<VerificationStatus, string>;
453
+ /** present only on a refactor run — the equivalence/proposed-unproven statement
454
+ * with the proof that backs it (omitted entirely otherwise). */
455
+ refactor?: EvidenceRefactorStatement | undefined;
456
+ /** present only when the credential-free cost analysis ran — the §5.19 idle
457
+ * floor (what this bills at zero traffic), never a monthly total. */
458
+ cost?: EvidenceCostStatement | undefined;
459
+ /** present only when detect_plan_drift ran — the TC-2.1 drift statement:
460
+ * signed, bounded proof of whether live infrastructure matched the committed
461
+ * configuration when the plan artifact was produced, with the `forgotten`
462
+ * blind-spot list and every coverage gap carried in the claim itself. */
463
+ drift?: DriftEvidenceStatement | undefined;
464
+ /** present only when a provider-major upgrade was detected (TC-2.2) — which
465
+ * boundary was crossed, the codified transforms found in this configuration,
466
+ * and the plan that proves (or fails to prove) the result. A `no-plan` verdict
467
+ * is recorded rather than omitted: an upgrade shipped without a plan is
468
+ * exactly the thing a reader must be able to see. */
469
+ upgrade?: UpgradeEvidenceStatement | undefined;
470
+ /** Ed25519 signing metadata (public key + fingerprint + the sibling `.sig`
471
+ * carrying the detached signature over this file's exact bytes), or an
472
+ * explicit null when no INFRAWEAVER_SIGNING_KEY is configured — never fake. */
473
+ signature: SignatureMetadata | null;
474
+ /** §5.16 always-present eIDAS assurance declaration: which electronic-seal
475
+ * tier the `signature` above actually reaches, and — the load-bearing half —
476
+ * which it does not. `signature` says HOW the bytes were signed; this says
477
+ * WHAT THAT IS WORTH legally, so a reader cannot over-read an Ed25519
478
+ * signature as a qualified seal. Present even when unsigned (`level: "none"`),
479
+ * because an omitted section is ambiguous. See [[eidas]]. */
480
+ seal: EidasSeal;
481
+ disclaimer: string;
482
+ }
483
+
484
+ const DISCLAIMER =
485
+ "Indicative alignment guidance from a deterministic starter rule-pack — NOT an " +
486
+ "audit verdict. Statuses are code-verified only; an inconclusive check is a " +
487
+ "coverage gap (not a pass) and absence of a finding is not proof of compliance.";
488
+
489
+ export interface EvidenceSubject {
490
+ scanned_dir: string;
491
+ repo?: string | undefined;
492
+ ref?: string | undefined;
493
+ commit?: string | undefined;
494
+ }
495
+
496
+ /**
497
+ * Build the evidence bundle from an assessment's scorecard + crosswalk. Pure —
498
+ * `generatedAt` and the subject identifiers are passed in so the same inputs
499
+ * always produce the same bytes (and tests don't need a clock). Control
500
+ * statements come from the crosswalk entries (which already carry the
501
+ * verification status), enriched with the concern's severity/location when the
502
+ * scanned concerns are supplied (the crosswalk entry itself carries neither).
503
+ */
504
+ export function buildEvidenceBundle(args: {
505
+ scorecard: AssessmentScorecard;
506
+ crosswalk: CrosswalkReport;
507
+ subject: EvidenceSubject;
508
+ generatedAt: string;
509
+ version?: string;
510
+ /** the scanned concerns backing the crosswalk entries — the source of each
511
+ * statement's severity/file/line enrichment. */
512
+ concerns?: Concern[];
513
+ refactor?: EvidenceRefactorStatement | undefined;
514
+ /** the §5.19 idle-floor statement; omitted when no cost analysis ran. */
515
+ cost?: EvidenceCostStatement | undefined;
516
+ /** the TC-2.1 drift statement; omitted when detect_plan_drift didn't run. */
517
+ drift?: DriftEvidenceStatement | undefined;
518
+ /** the TC-2.2 upgrade statement; omitted when no provider-major pack applied. */
519
+ upgrade?: UpgradeEvidenceStatement | undefined;
520
+ /** who produced this evidence (A.3). REQUIRED — an evidence bundle that
521
+ * doesn't name its actor is the gap this block exists to close. Callers pass
522
+ * real values (the builder stays pure; no ambient reads here). */
523
+ provenance: EvidenceProvenance;
524
+ /** signing metadata when a key is configured; omitted/null ⇒ explicit
525
+ * `"signature": null` (the honest-unsigned marker). */
526
+ signature?: SignatureMetadata | null;
527
+ }): EvidenceBundle {
528
+ const {
529
+ scorecard,
530
+ crosswalk,
531
+ subject,
532
+ generatedAt,
533
+ refactor,
534
+ cost,
535
+ drift,
536
+ upgrade,
537
+ } = args;
538
+ const concernById = new Map((args.concerns ?? []).map((c) => [c.id, c]));
539
+ const control_statements: EvidenceControlStatement[] = crosswalk.entries.map(
540
+ (e) => {
541
+ const concern = concernById.get(e.concern_id);
542
+ return {
543
+ concern_id: e.concern_id,
544
+ rule_id: e.rule_id,
545
+ status: e.status,
546
+ ...(concern
547
+ ? {
548
+ concern_key: concernKeyOf(concern),
549
+ severity: concern.severity,
550
+ file: concern.location.file,
551
+ line: concern.location.line,
552
+ }
553
+ : {}),
554
+ controls: e.controls,
555
+ };
556
+ },
557
+ );
558
+ return {
559
+ schema: EVIDENCE_SCHEMA,
560
+ generated_at: generatedAt,
561
+ tool: { name: TOOL_NAME, version: args.version ?? packageJson.version },
562
+ provenance: args.provenance,
563
+ subject,
564
+ posture: scorecard.posture,
565
+ summary: {
566
+ total: scorecard.total,
567
+ by_severity: scorecard.by_severity,
568
+ verification: scorecard.verification.counts,
569
+ },
570
+ control_statements,
571
+ coverage: scorecard.verification.coverage,
572
+ // Derived from the scorecard the report already renders, so the signed
573
+ // bundle and the human-readable report can never disagree about what was
574
+ // silenced.
575
+ suppressions: buildSuppressionSummary(scorecard.waivers),
576
+ crosswalk: {
577
+ version: crosswalk.version,
578
+ reviewed: crosswalk.reviewed,
579
+ digest: CROSSWALK_DIGEST,
580
+ by_framework: crosswalk.by_framework,
581
+ },
582
+ legend: VERIFICATION_STATUS_LABEL,
583
+ ...(refactor ? { refactor } : {}),
584
+ ...(cost ? { cost } : {}),
585
+ ...(drift ? { drift } : {}),
586
+ ...(upgrade ? { upgrade } : {}),
587
+ signature: args.signature ?? null,
588
+ // Derived from the signature actually present, never from configuration, so
589
+ // the declared level can't drift from what the bundle really carries.
590
+ seal: eidasSealFor(args.signature ?? null),
591
+ disclaimer: DISCLAIMER,
592
+ };
593
+ }
594
+
595
+ export const TerraformEmitEvidenceParams = type({
596
+ "output_path?": type.string.describe(
597
+ `where to write the evidence bundle (default: ./${DEFAULT_EVIDENCE_PATH} in the workspace). Commit it so the compliance/ path is the auditable evidence trail.`,
598
+ ),
599
+ "severity_threshold?": type(
600
+ "'critical' | 'high' | 'medium' | 'low' | 'info'",
601
+ ).describe(
602
+ "minimum severity to include (default: the run's configured threshold, else low).",
603
+ ),
604
+ "proposed_unproven?": type("boolean").describe(
605
+ "refactor b.4 only: set true when emitting evidence for a third-party-module adoption shipped WITHOUT a plan, so the bundle records the unmissable `proposed — unproven` marker (it asserts nothing about runtime behaviour). Ignored when a keys-free equivalence proof was already recorded this run.",
606
+ ),
607
+ });
608
+
609
+ export function TerraformEmitEvidenceTool(ctx: LocalToolContext) {
610
+ return tool({
611
+ name: "terraform_emit_evidence",
612
+ description:
613
+ "Emit a backend-free compliance EVIDENCE BUNDLE (auditor-facing JSON) for the workspace — the wedge that " +
614
+ "produces assessor-ready evidence with no cloud and no backend. Runs the read-only assessment and writes " +
615
+ `a deterministic bundle (default \`${DEFAULT_EVIDENCE_PATH}\`): overall \`posture\`, per-control ` +
616
+ "statements each with a five-status verdict (fail / not-code-verifiable), the scanner `coverage` " +
617
+ "(verified vs inconclusive), and the indicative crosswalk index. Commit the file so `compliance/` is the " +
618
+ `auditable trail. It NEVER modifies Terraform or opens a PR. The schema is ${PRODUCT_NAME}'s own (not OSCAL); ` +
619
+ "the bundle is indicative alignment guidance, never an audit verdict, and never claims a pass it can't " +
620
+ "code-verify. Pairs with `terraform_assess` (the human-readable report) and `terraform_emit_sarif`.",
621
+ parameters: TerraformEmitEvidenceParams,
622
+ execute: execute(
623
+ async ({ output_path, severity_threshold, proposed_unproven }) => {
624
+ const configured = ctx.payload.severityThreshold as
625
+ | Severity
626
+ | undefined;
627
+ const threshold: Severity = severity_threshold ?? configured ?? "low";
628
+ const { cwd, open, scorecard, crosswalk } = runAssessmentPipeline(
629
+ ctx,
630
+ threshold,
631
+ );
632
+
633
+ // refactor statement (omitted on a non-refactor run): the recorded keys-free
634
+ // equivalence proof + adopted-module provenance + the proposed-unproven marker.
635
+ const session = scanSessionOf(ctx.toolState);
636
+ const refactor = buildRefactorStatement({
637
+ equivalence: session.refactorEquivalence,
638
+ provenance: collectWorkspaceProvenance(cwd),
639
+ proposedUnproven: proposed_unproven ?? false,
640
+ });
641
+ // surface the proposed-unproven verdict to the Cloud report (cloudReport.ts):
642
+ // an equivalence proof, when present, takes precedence, so only record the
643
+ // flag when the statement actually resolved to proposed-unproven.
644
+ if (refactor?.proposed_unproven)
645
+ session.refactorProposedUnproven = true;
646
+ // cost statement (omitted unless terraform_emit_cost ran): the SAME idle-floor
647
+ // numbers cost.md shows, so the artifact and the signed bundle can't disagree.
648
+ const cost = buildCostStatement(session.lastIdleFloor);
649
+ // drift statement (omitted unless detect_plan_drift ran): drift — with the
650
+ // forgotten blind-spot list and any coverage gap — enters the SIGNED bundle
651
+ // instead of dying as a run verdict (TC-2.1).
652
+ const drift = session.lastDrift;
653
+ // upgrade statement (TC-2.2; omitted unless terraform_provider_upgrade
654
+ // matched a pack): binds the detected transforms to the plan that came
655
+ // after them. The plan facts are read from the session rather than taken
656
+ // from the agent, so a "proven" verdict cannot be self-reported. A run with
657
+ // no plan becomes the `no-plan` verdict rather than a silent omission.
658
+ const upgrade = upgradeStatementOf(session);
659
+
660
+ // SECURITY: confine the agent-supplied path to the workspace (same guard as
661
+ // terraform_emit_sarif) so it can't clobber arbitrary files on the runner.
662
+ const target = resolveWithinCwd(
663
+ cwd,
664
+ output_path ?? DEFAULT_EVIDENCE_PATH,
665
+ );
666
+ // Ed25519 signing (opt-in via INFRAWEAVER_SIGNING_KEY). A set-but-malformed
667
+ // key throws here — a configured signer must never silently emit unsigned.
668
+ const signingKey = loadSigningKey();
669
+ const sigPath = `${target}.sig`;
670
+ const gh = githubContext();
671
+ const bundle = buildEvidenceBundle({
672
+ scorecard,
673
+ crosswalk,
674
+ concerns: open,
675
+ subject: {
676
+ scanned_dir: cwd,
677
+ repo: gh.repository,
678
+ ref: gh.refName,
679
+ commit: gh.sha,
680
+ },
681
+ generatedAt: new Date().toISOString(),
682
+ refactor,
683
+ cost,
684
+ drift,
685
+ upgrade,
686
+ // WHO produced this evidence (A.3): the resolved model (absent on a
687
+ // local MCP session), the runtime, and the exact scanner builds the
688
+ // integrity gate observed before executing them this session.
689
+ provenance: {
690
+ model: ctx.resolvedModel ?? null,
691
+ node: process.version,
692
+ scanners: probedToolVersions(),
693
+ },
694
+ signature: signingKey
695
+ ? signatureMetadata(signingKey, basename(sigPath))
696
+ : null,
697
+ });
698
+ const bytes = `${JSON.stringify(bundle, null, 2)}\n`;
699
+ // the default compliance/ dir may not exist yet on a first run.
700
+ mkdirSync(dirname(target), { recursive: true });
701
+ writeFileSync(target, bytes);
702
+ // detached signature over the EXACT bytes written (builder is deterministic,
703
+ // so no canonicaliser) — verify with `infraweaver verify-evidence`.
704
+ if (signingKey)
705
+ writeFileSync(sigPath, `${signBytes(bytes, signingKey)}\n`);
706
+
707
+ // Second tier: keyless Sigstore attestation (opt-in via INFRAWEAVER_KEYLESS_SIGNING,
708
+ // CI-only). Best-effort — a Fulcio/Rekor failure logs and leaves the evidence
709
+ // (+ Ed25519 sig) intact rather than aborting the emit. The in-toto statement's
710
+ // subject is this file (by sha256 digest), so the attestation binds the exact
711
+ // bytes to the workflow's OIDC identity, auditable in the public Rekor log.
712
+ let keylessBundleFile: string | undefined;
713
+ if (keylessSigningPossible()) {
714
+ try {
715
+ const statement = buildInTotoStatement({
716
+ subjectName: basename(target),
717
+ artifactBytes: bytes,
718
+ predicate: {
719
+ posture: bundle.posture,
720
+ control_statements: bundle.control_statements.length,
721
+ verification: bundle.summary.verification,
722
+ tool: bundle.tool,
723
+ generated_at: bundle.generated_at,
724
+ subject: bundle.subject,
725
+ },
726
+ });
727
+ const sigstoreBundle = await keylessSignStatement(statement);
728
+ keylessBundleFile = keylessBundlePath(target);
729
+ writeFileSync(
730
+ keylessBundleFile,
731
+ `${JSON.stringify(sigstoreBundle, null, 2)}\n`,
732
+ );
733
+ log.info(
734
+ `» terraform_emit_evidence: keyless Sigstore attestation → ${keylessBundleFile}`,
735
+ );
736
+ } catch (e) {
737
+ log.warning(
738
+ `» terraform_emit_evidence: keyless signing failed (evidence still emitted): ${e instanceof Error ? e.message : String(e)}`,
739
+ );
740
+ }
741
+ }
742
+ log.info(
743
+ `» terraform_emit_evidence: ${scorecard.posture} — ${bundle.control_statements.length} control statement(s) → ${target}` +
744
+ (signingKey
745
+ ? ` (signed ed25519, key ${signingKey.fingerprint.slice(0, 16)}…)`
746
+ : " (unsigned — no INFRAWEAVER_SIGNING_KEY)"),
747
+ );
748
+ return toolOk({
749
+ output_path: target,
750
+ posture: bundle.posture,
751
+ statements: bundle.control_statements.length,
752
+ verification: bundle.summary.verification,
753
+ ...(bundle.refactor
754
+ ? { refactor_verdict: bundle.refactor.verdict }
755
+ : {}),
756
+ signed: signingKey !== null,
757
+ ...(signingKey
758
+ ? {
759
+ signature_path: sigPath,
760
+ key_fingerprint_sha256: signingKey.fingerprint,
761
+ }
762
+ : {}),
763
+ keyless_signed: keylessBundleFile !== undefined,
764
+ ...(keylessBundleFile
765
+ ? { keyless_bundle_path: keylessBundleFile }
766
+ : {}),
767
+ });
768
+ },
769
+ ),
770
+ });
771
+ }