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,676 @@
1
+ import { createSign } from "node:crypto";
2
+ import { rename, writeFile } from "node:fs/promises";
3
+ import { dirname, join } from "node:path";
4
+ import * as core from "@actions/core";
5
+ import { throttling } from "@octokit/plugin-throttling";
6
+ import { Octokit } from "@octokit/rest";
7
+ import { DOCS_URL, PRODUCT_NAME, PRODUCT_SLUG } from "#app/brand";
8
+ import { apiFetch } from "#app/utils/apiFetch";
9
+ import { cloudOidcAudience } from "#app/utils/apiUrl";
10
+ import { retry } from "#app/utils/retry";
11
+
12
+ function isObject(value: unknown) {
13
+ return typeof value === "object" && value !== null;
14
+ }
15
+
16
+ // we don't get access to the actual class from @octokit/rest
17
+ // it's reachable from @octokit/request-error but we'd have to add a dependency on it
18
+ // and it would pose a risk of accidentally pulling a different version of that class (node_modules dep graphs ❤️)
19
+ // so it's safer to ducktype this
20
+ interface OctokitResponseShim {
21
+ headers: Record<string, string | number | undefined>;
22
+ }
23
+
24
+ export interface InstallationToken {
25
+ token: string;
26
+ expires_at: string;
27
+ installation_id: number;
28
+ repository: string;
29
+ ref: string;
30
+ runner_environment: string;
31
+ owner?: string;
32
+ }
33
+
34
+ interface GitHubAppConfig {
35
+ appId: string;
36
+ privateKey: string;
37
+ repoOwner: string;
38
+ repoName: string;
39
+ }
40
+
41
+ interface Installation {
42
+ id: number;
43
+ account: {
44
+ login: string;
45
+ type: string;
46
+ };
47
+ }
48
+
49
+ interface Repository {
50
+ owner: {
51
+ login: string;
52
+ };
53
+ name: string;
54
+ }
55
+
56
+ interface InstallationTokenResponse {
57
+ token: string;
58
+ expires_at: string;
59
+ }
60
+
61
+ interface RepositoriesResponse {
62
+ repositories: Repository[];
63
+ }
64
+
65
+ function isOIDCAvailable(): boolean {
66
+ // OIDC requires both env vars to be set (only in real GitHub Actions with id-token permission)
67
+ return Boolean(
68
+ process.env.ACTIONS_ID_TOKEN_REQUEST_URL &&
69
+ process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN,
70
+ );
71
+ }
72
+
73
+ /**
74
+ * Snapshot the GHA OIDC request creds from the env. Returns undefined off-CI or
75
+ * once they have been scrubbed. Call this BEFORE main.ts's restricted-mode env
76
+ * scrub so a mid-run token re-mint can still fetch a fresh OIDC JWT afterwards.
77
+ */
78
+ export function readOidcCreds(): OidcCreds | undefined {
79
+ const requestUrl = process.env.ACTIONS_ID_TOKEN_REQUEST_URL;
80
+ const requestToken = process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN;
81
+ return requestUrl && requestToken ? { requestUrl, requestToken } : undefined;
82
+ }
83
+
84
+ /**
85
+ * Fetch a fresh OIDC JWT from the GHA token service using stashed creds — the
86
+ * env-independent equivalent of `core.getIDToken(audience)` (same
87
+ * `${url}&audience=` shape + bearer request token). Lets a re-mint succeed after
88
+ * the ACTIONS_ID_TOKEN_REQUEST_* env vars `core.getIDToken` reads are scrubbed.
89
+ */
90
+ export async function fetchOidcIdToken(
91
+ creds: OidcCreds,
92
+ audience: string,
93
+ ): Promise<string> {
94
+ const res = await fetch(
95
+ `${creds.requestUrl}&audience=${encodeURIComponent(audience)}`,
96
+ {
97
+ headers: {
98
+ Authorization: `Bearer ${creds.requestToken}`,
99
+ Accept: "application/json",
100
+ },
101
+ signal: AbortSignal.timeout(10_000),
102
+ },
103
+ );
104
+ if (!res.ok) {
105
+ throw new Error(
106
+ `OIDC token request failed: ${res.status} ${res.statusText}`,
107
+ );
108
+ }
109
+ const body = (await res.json()) as { value?: unknown };
110
+ if (typeof body.value !== "string" || !body.value) {
111
+ throw new Error("OIDC token response missing 'value'");
112
+ }
113
+ return body.value;
114
+ }
115
+
116
+ type ReadWrite = "read" | "write";
117
+ type WriteOnly = "write";
118
+
119
+ /**
120
+ * GitHub App installation access token permissions.
121
+ * passed to `POST /app/installations/{id}/access_tokens` to scope the token.
122
+ * fields and allowed values come from the `app-permissions` OpenAPI schema.
123
+ * @see https://docs.github.com/en/rest/apps/installations#create-an-installation-access-token-for-an-app
124
+ * @see https://github.com/github/rest-api-description — components.schemas.app-permissions
125
+ */
126
+ type GitHubAppPermissions = {
127
+ actions?: ReadWrite;
128
+ artifact_metadata?: ReadWrite;
129
+ attestations?: ReadWrite;
130
+ checks?: ReadWrite;
131
+ contents?: ReadWrite;
132
+ deployments?: ReadWrite;
133
+ discussions?: ReadWrite;
134
+ issues?: ReadWrite;
135
+ packages?: ReadWrite;
136
+ pages?: ReadWrite;
137
+ pull_requests?: ReadWrite;
138
+ security_events?: ReadWrite;
139
+ statuses?: ReadWrite;
140
+ workflows?: WriteOnly;
141
+ };
142
+
143
+ /**
144
+ * Stashed GitHub Actions OIDC request credentials (`ACTIONS_ID_TOKEN_REQUEST_URL`
145
+ * + `_TOKEN`). Captured by {@link readOidcCreds} while the env vars are still
146
+ * present so a mid-run token re-mint can fetch a fresh OIDC JWT even after main.ts
147
+ * scrubs those vars from the env (which it does in every shell mode).
148
+ */
149
+ export type OidcCreds = { requestUrl: string; requestToken: string };
150
+
151
+ type AcquireTokenOptions = {
152
+ repos?: string[];
153
+ permissions?: GitHubAppPermissions;
154
+ /** when set, mint via OIDC using these stashed creds instead of reading the
155
+ * (possibly already-scrubbed) ACTIONS_ID_TOKEN_REQUEST_* env vars. */
156
+ oidc?: OidcCreds;
157
+ };
158
+
159
+ /**
160
+ * Thrown when our token-exchange endpoint returns a non-2xx response.
161
+ * The retry policy in `acquireNewToken` looks for this concrete type to
162
+ * skip retries — 4xx is terminal user state (not-installed, not-authorized)
163
+ * and 5xx is rare enough that re-running the workflow is the right escape
164
+ * hatch. Genuine network failures throw plain `Error` and stay retryable.
165
+ */
166
+ class TokenExchangeError extends Error {
167
+ readonly status: number;
168
+ constructor(status: number, message: string) {
169
+ super(message);
170
+ this.name = "TokenExchangeError";
171
+ this.status = status;
172
+ }
173
+ }
174
+
175
+ async function acquireTokenViaOIDC(
176
+ opts?: AcquireTokenOptions,
177
+ ): Promise<string> {
178
+ const oidcToken = opts?.oidc
179
+ ? await fetchOidcIdToken(opts.oidc, cloudOidcAudience())
180
+ : await core.getIDToken(cloudOidcAudience());
181
+
182
+ const repos = [...(opts?.repos ?? [])];
183
+ const targetRepo = process.env.GITHUB_REPOSITORY?.split("/")[1];
184
+ if (targetRepo) {
185
+ repos.push(targetRepo);
186
+ }
187
+ const reposParam = repos.length ? `?repos=${repos.join(",")}` : "";
188
+
189
+ const timeoutMs = 30000;
190
+ const controller = new AbortController();
191
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
192
+
193
+ try {
194
+ const tokenResponse = await apiFetch({
195
+ path: `/api/github/installation-token${reposParam}`,
196
+ method: "POST",
197
+ headers: {
198
+ Authorization: `Bearer ${oidcToken}`,
199
+ "Content-Type": "application/json",
200
+ },
201
+ body: opts?.permissions
202
+ ? JSON.stringify({ permissions: opts.permissions })
203
+ : undefined,
204
+ signal: controller.signal,
205
+ });
206
+
207
+ clearTimeout(timeoutId);
208
+
209
+ if (!tokenResponse.ok) {
210
+ // prefer the server-side `error` field — it's the single source of
211
+ // truth for the install URL (uses GITHUB_APP_INSTALL_URL, or the
212
+ // slug from NEXT_PUBLIC_GITHUB_APP_SLUG, which vary per env). fall back
213
+ // to a generic message if the body isn't JSON or has no `error` field.
214
+ let serverMessage: string | undefined;
215
+ try {
216
+ const body = (await tokenResponse.json()) as { error?: unknown };
217
+ if (typeof body.error === "string") serverMessage = body.error;
218
+ } catch {
219
+ // body wasn't JSON — fall through to the generic message
220
+ }
221
+ throw new TokenExchangeError(
222
+ tokenResponse.status,
223
+ serverMessage ??
224
+ `Token exchange failed: ${tokenResponse.status} ${tokenResponse.statusText}`,
225
+ );
226
+ }
227
+
228
+ const tokenData = (await tokenResponse.json()) as InstallationToken;
229
+ return tokenData.token;
230
+ } catch (error) {
231
+ clearTimeout(timeoutId);
232
+
233
+ if (error instanceof Error && error.name === "AbortError") {
234
+ throw new Error(`Token exchange timed out after ${timeoutMs}ms`);
235
+ }
236
+ throw error;
237
+ }
238
+ }
239
+
240
+ const base64UrlEncode = (str: string): string => {
241
+ return Buffer.from(str)
242
+ .toString("base64")
243
+ .replace(/\+/g, "-")
244
+ .replace(/\//g, "_")
245
+ .replace(/=/g, "");
246
+ };
247
+
248
+ const generateJWT = (appId: string, privateKey: string): string => {
249
+ const now = Math.floor(Date.now() / 1000);
250
+ const payload = {
251
+ iat: now - 60,
252
+ exp: now + 5 * 60,
253
+ iss: appId,
254
+ };
255
+
256
+ const header = {
257
+ alg: "RS256",
258
+ typ: "JWT",
259
+ };
260
+
261
+ const encodedHeader = base64UrlEncode(JSON.stringify(header));
262
+ const encodedPayload = base64UrlEncode(JSON.stringify(payload));
263
+ const signaturePart = `${encodedHeader}.${encodedPayload}`;
264
+
265
+ const signature = createSign("RSA-SHA256")
266
+ .update(signaturePart)
267
+ .sign(privateKey, "base64")
268
+ .replace(/\+/g, "-")
269
+ .replace(/\//g, "_")
270
+ .replace(/=/g, "");
271
+
272
+ return `${signaturePart}.${signature}`;
273
+ };
274
+
275
+ const githubRequest = async <T>(
276
+ path: string,
277
+ options: {
278
+ method?: string;
279
+ headers?: Record<string, string>;
280
+ body?: string;
281
+ } = {},
282
+ ): Promise<T> => {
283
+ const { method = "GET", headers = {}, body } = options;
284
+
285
+ const url = `https://api.github.com${path}`;
286
+ const requestHeaders = {
287
+ Accept: "application/vnd.github.v3+json",
288
+ "User-Agent": `${PRODUCT_NAME}-Installation-Token-Generator/1.0`,
289
+ ...headers,
290
+ };
291
+
292
+ const response = await fetch(url, {
293
+ method,
294
+ headers: requestHeaders,
295
+ ...(body && { body }),
296
+ signal: AbortSignal.timeout(30_000),
297
+ });
298
+
299
+ if (!response.ok) {
300
+ const errorText = await response.text();
301
+ throw new Error(
302
+ `GitHub API request failed: ${response.status} ${response.statusText}\n${errorText}`,
303
+ );
304
+ }
305
+
306
+ return response.json() as T;
307
+ };
308
+
309
+ const checkRepositoryAccess = async (
310
+ token: string,
311
+ repoOwner: string,
312
+ repoName: string,
313
+ ): Promise<boolean> => {
314
+ try {
315
+ const response = await githubRequest<RepositoriesResponse>(
316
+ "/installation/repositories",
317
+ {
318
+ headers: { Authorization: `token ${token}` },
319
+ },
320
+ );
321
+
322
+ const ownerLower = repoOwner.toLowerCase();
323
+ const nameLower = repoName.toLowerCase();
324
+ return response.repositories.some(
325
+ (repo) =>
326
+ repo.owner.login.toLowerCase() === ownerLower &&
327
+ repo.name.toLowerCase() === nameLower,
328
+ );
329
+ } catch {
330
+ return false;
331
+ }
332
+ };
333
+
334
+ const createInstallationToken = async (
335
+ jwt: string,
336
+ installationId: number,
337
+ permissions?: GitHubAppPermissions,
338
+ ): Promise<string> => {
339
+ const requestOpts: {
340
+ method: string;
341
+ headers: Record<string, string>;
342
+ body?: string;
343
+ } = {
344
+ method: "POST",
345
+ headers: { Authorization: `Bearer ${jwt}` },
346
+ };
347
+ if (permissions) {
348
+ requestOpts.body = JSON.stringify({ permissions });
349
+ }
350
+ const response = await githubRequest<InstallationTokenResponse>(
351
+ `/app/installations/${installationId}/access_tokens`,
352
+ requestOpts,
353
+ );
354
+
355
+ return response.token;
356
+ };
357
+
358
+ const findInstallationId = async (
359
+ jwt: string,
360
+ repoOwner: string,
361
+ repoName: string,
362
+ ): Promise<number> => {
363
+ const installations = await githubRequest<Installation[]>(
364
+ "/app/installations",
365
+ {
366
+ headers: { Authorization: `Bearer ${jwt}` },
367
+ },
368
+ );
369
+
370
+ // Probing each installation is best-effort — one that legitimately can't mint a
371
+ // token (suspended, revoked) must not abort the search. But swallowing the error
372
+ // entirely made a systemic failure (a malformed App private key, a clock skew
373
+ // rejecting every JWT) surface as the misleading "no installation found", which
374
+ // sends the reader to reinstall an App that is in fact installed correctly. Keep
375
+ // the last error and surface it alongside the diagnosis.
376
+ let lastError: unknown;
377
+ for (const installation of installations) {
378
+ try {
379
+ const tempToken = await createInstallationToken(jwt, installation.id);
380
+ const hasAccess = await checkRepositoryAccess(
381
+ tempToken,
382
+ repoOwner,
383
+ repoName,
384
+ );
385
+
386
+ if (hasAccess) {
387
+ return installation.id;
388
+ }
389
+ } catch (error) {
390
+ lastError = error;
391
+ }
392
+ }
393
+
394
+ const detail =
395
+ lastError === undefined
396
+ ? ""
397
+ : ` Last error while probing ${installations.length} installation(s): ${
398
+ lastError instanceof Error ? lastError.message : String(lastError)
399
+ }`;
400
+ throw new Error(
401
+ `No installation found with access to ${repoOwner}/${repoName}. ` +
402
+ `Ensure the GitHub App is installed on the target repository.${detail}`,
403
+ );
404
+ };
405
+
406
+ // for local development only
407
+ async function acquireTokenViaGitHubApp(
408
+ opts?: AcquireTokenOptions,
409
+ ): Promise<string> {
410
+ if (!process.env.GITHUB_APP_ID || !process.env.GITHUB_PRIVATE_KEY) {
411
+ throw new Error(
412
+ "cannot acquire token via GitHub App: GITHUB_APP_ID and GITHUB_PRIVATE_KEY must be set",
413
+ );
414
+ }
415
+
416
+ const repoContext = parseRepoContext();
417
+
418
+ const config: GitHubAppConfig = {
419
+ appId: process.env.GITHUB_APP_ID,
420
+ privateKey: process.env.GITHUB_PRIVATE_KEY.replace(/\\n/g, "\n"),
421
+ repoOwner: repoContext.owner,
422
+ repoName: repoContext.name,
423
+ };
424
+
425
+ const jwt = generateJWT(config.appId, config.privateKey);
426
+ const installationId = await findInstallationId(
427
+ jwt,
428
+ config.repoOwner,
429
+ config.repoName,
430
+ );
431
+ return await createInstallationToken(jwt, installationId, opts?.permissions);
432
+ }
433
+
434
+ /**
435
+ * ensure a GitHub token is available in the environment.
436
+ *
437
+ * when OIDC is available (CI), always mints a fresh token scoped to
438
+ * GITHUB_REPOSITORY — overriding any inherited GITHUB_TOKEN that may
439
+ * be scoped to the wrong repo.
440
+ *
441
+ * otherwise falls back to GitHub App credentials for local development.
442
+ *
443
+ * only called from dev-run.ts (test/dev path) — the live action calls
444
+ * main() directly and never calls this.
445
+ */
446
+ export async function ensureGitHubToken(): Promise<void> {
447
+ // when OIDC is available, always mint a fresh token scoped to
448
+ // GITHUB_REPOSITORY. the inherited GITHUB_TOKEN may be scoped to a
449
+ // different repo (e.g., runner token for infraweaver/app when tests
450
+ // target infraweaver/test-repo).
451
+ if (isOIDCAvailable()) {
452
+ const token = await acquireNewToken();
453
+ process.env.GITHUB_TOKEN = token;
454
+ return;
455
+ }
456
+
457
+ if (!process.env.GITHUB_TOKEN && !process.env.GH_TOKEN) {
458
+ const token = await acquireNewToken();
459
+ process.env.GITHUB_TOKEN = token;
460
+ }
461
+ }
462
+
463
+ export async function acquireNewToken(
464
+ opts?: AcquireTokenOptions,
465
+ ): Promise<string> {
466
+ // stashed OIDC creds (opts.oidc) take the OIDC path even after the
467
+ // ACTIONS_ID_TOKEN_REQUEST_* env vars are scrubbed — that's what lets a
468
+ // mid-run re-mint work after the scrub. otherwise fall back to the env check.
469
+ if (opts?.oidc || isOIDCAvailable()) {
470
+ return await retry(() => acquireTokenViaOIDC(opts), {
471
+ label: "token exchange",
472
+ shouldRetry: (error) => {
473
+ // 4xx is terminal user state (app not installed, permissions wrong) —
474
+ // retrying just triples our log noise and the user's CI bill (see
475
+ // #693). 5xx/429 are transient (vercel cold start, github outage,
476
+ // rate limit) and should ride the existing backoff.
477
+ if (error instanceof TokenExchangeError)
478
+ return error.status >= 500 || error.status === 429;
479
+ return (
480
+ error instanceof Error &&
481
+ (error.message.includes("timed out") ||
482
+ error.message.includes("fetch failed") ||
483
+ error.message.includes("ECONNRESET") ||
484
+ error.message.includes("ETIMEDOUT"))
485
+ );
486
+ },
487
+ });
488
+ }
489
+ // running inside GitHub Actions but the OIDC env vars are absent — the
490
+ // workflow is missing `permissions: id-token: write`. surface an
491
+ // actionable, customer-facing message; the GitHub-App branch below is
492
+ // local-dev only. see #739.
493
+ if (process.env.GITHUB_ACTIONS === "true") {
494
+ throw new Error(
495
+ `missing \`permissions: id-token: write\` on the ${PRODUCT_NAME} workflow job.\n` +
496
+ "\n" +
497
+ `${PRODUCT_NAME} mints short-lived GitHub App installation tokens via OIDC and\n` +
498
+ "requires `id-token: write` to be granted at the job level. add the\n" +
499
+ "following to your workflow yaml:\n" +
500
+ "\n" +
501
+ " jobs:\n" +
502
+ ` ${PRODUCT_SLUG}:\n` +
503
+ " permissions:\n" +
504
+ ` id-token: write # mint ${PRODUCT_NAME} installation tokens via OIDC\n` +
505
+ " contents: read # for actions/checkout\n" +
506
+ "\n" +
507
+ `see ${DOCS_URL}/headless-action#required-permissions for the full template.`,
508
+ );
509
+ }
510
+ // local development via GitHub App
511
+ return await acquireTokenViaGitHubApp(opts);
512
+ }
513
+
514
+ export interface RepoContext {
515
+ owner: string;
516
+ name: string;
517
+ }
518
+
519
+ /**
520
+ * Parse repository context from GITHUB_REPOSITORY environment variable.
521
+ */
522
+ export function parseRepoContext(): RepoContext {
523
+ const githubRepo = process.env.GITHUB_REPOSITORY;
524
+ if (!githubRepo) {
525
+ throw new Error("GITHUB_REPOSITORY environment variable is required");
526
+ }
527
+
528
+ const [owner, name] = githubRepo.split("/");
529
+ if (!owner || !name) {
530
+ throw new Error(
531
+ `Invalid GITHUB_REPOSITORY format: ${githubRepo}. Expected 'owner/repo'`,
532
+ );
533
+ }
534
+
535
+ return { owner, name };
536
+ }
537
+
538
+ export type OctokitWithPlugins = InstanceType<
539
+ ReturnType<typeof Octokit.plugin<typeof Octokit, [typeof throttling]>>
540
+ >;
541
+
542
+ export interface ResourceUsage {
543
+ requestCount: number;
544
+ rateLimitRemaining: number | null;
545
+ rateLimitResetMs: number | null;
546
+ }
547
+
548
+ function emptyResourceUsage(): ResourceUsage {
549
+ return {
550
+ requestCount: 0,
551
+ rateLimitRemaining: null,
552
+ rateLimitResetMs: null,
553
+ };
554
+ }
555
+
556
+ // `core` and `graphql` are always seeded below, so they're declared as required
557
+ // (the index signature still admits other resources, which are added on demand).
558
+ const usageByResource: Record<string, ResourceUsage> & {
559
+ core: ResourceUsage;
560
+ graphql: ResourceUsage;
561
+ } = {
562
+ core: emptyResourceUsage(),
563
+ graphql: emptyResourceUsage(),
564
+ };
565
+
566
+ export interface UsageSummary {
567
+ version: 1;
568
+ github: {
569
+ core: ResourceUsage;
570
+ graphql: ResourceUsage;
571
+ };
572
+ }
573
+
574
+ function getGitHubUsageSummary(): UsageSummary {
575
+ return {
576
+ version: 1,
577
+ github: {
578
+ core: usageByResource.core,
579
+ graphql: usageByResource.graphql,
580
+ },
581
+ };
582
+ }
583
+
584
+ export async function writeGitHubUsageSummaryToFile(
585
+ path: string,
586
+ ): Promise<void> {
587
+ const summary = getGitHubUsageSummary();
588
+ const tmpPath = join(dirname(path), `.usage-summary-${process.pid}.tmp`);
589
+ await writeFile(tmpPath, JSON.stringify(summary));
590
+ await rename(tmpPath, path);
591
+ }
592
+
593
+ export function createOctokit(
594
+ token: string,
595
+ refreshAuth?: (stale: string) => Promise<string>,
596
+ ): OctokitWithPlugins {
597
+ // `OctokitWithPlugins` initialization based on https://github.com/actions/toolkit/blob/2506e78e82fbd2f9e94d63e75f5309118c8de1b1/packages/github/src/github.ts#L15-L22
598
+ // we can't use it directly because it's stuck on `@octokit/core@v5` and we use the hottest `@octokit/core@v7`
599
+ //
600
+ // Auth is applied in the request hook below rather than via the constructor
601
+ // `auth` option: a 401 can swap in a re-minted installation token mid-run
602
+ // (GitHub can reject a freshly-minted token while it replicates; pullfrog #891
603
+ // re-acquires one), and the hook owning the Authorization header end-to-end
604
+ // means no auth strategy clobbers the refreshed token on the replayed request.
605
+ let currentToken = token;
606
+ const OctokitWithPlugins = Octokit.plugin(throttling);
607
+ const octokit = new OctokitWithPlugins({
608
+ throttle: {
609
+ onRateLimit: (_retryAfter, _options, _octokit, retryCount) => {
610
+ return retryCount <= 2;
611
+ },
612
+ onSecondaryRateLimit: (_retryAfter, _options, _octokit, retryCount) => {
613
+ return retryCount <= 2;
614
+ },
615
+ },
616
+ });
617
+
618
+ const onResponse = (response: OctokitResponseShim) => {
619
+ const resource = response.headers["x-ratelimit-resource"];
620
+ if (!resource) {
621
+ return response;
622
+ }
623
+ usageByResource[resource] ??= emptyResourceUsage();
624
+ const usage = usageByResource[resource];
625
+ usage.requestCount++;
626
+ const remaining = response.headers["x-ratelimit-remaining"];
627
+ const reset = response.headers["x-ratelimit-reset"];
628
+ if (remaining !== undefined) {
629
+ usage.rateLimitRemaining = Number(remaining);
630
+ }
631
+ if (reset !== undefined) {
632
+ usage.rateLimitResetMs = Number(reset) * 1000;
633
+ }
634
+ return response;
635
+ };
636
+
637
+ octokit.hook.wrap("request", async (request, options) => {
638
+ // snapshot the token we're about to use; refreshAuth single-flights on it so
639
+ // concurrent requests that all sent the same stale token coalesce to one mint.
640
+ const sentToken = currentToken;
641
+ options.headers.authorization = `token ${sentToken}`;
642
+ try {
643
+ const response = await request(options);
644
+ onResponse(response);
645
+ return response;
646
+ } catch (error) {
647
+ if (
648
+ isObject(error) &&
649
+ "response" in error &&
650
+ isObject(error.response) &&
651
+ "headers" in error.response &&
652
+ isObject(error.response.headers)
653
+ ) {
654
+ onResponse(error.response as OctokitResponseShim);
655
+ }
656
+ // GitHub rejected the installation token with 401 — re-acquire a fresh one
657
+ // and replay the request once. covers the post-mint replication window
658
+ // where a just-minted token is briefly unrecognised. see pullfrog #891.
659
+ if (
660
+ refreshAuth &&
661
+ isObject(error) &&
662
+ "status" in error &&
663
+ error.status === 401
664
+ ) {
665
+ currentToken = await refreshAuth(sentToken);
666
+ options.headers.authorization = `token ${currentToken}`;
667
+ const response = await request(options);
668
+ onResponse(response);
669
+ return response;
670
+ }
671
+ throw error;
672
+ }
673
+ });
674
+
675
+ return octokit;
676
+ }
@@ -0,0 +1,9 @@
1
+ import { existsSync } from "node:fs";
2
+
3
+ export const isCloudflareSandbox =
4
+ !!process.env.CLOUDFLARE_APPLICATION_ID && !!process.env.SANDBOX_VERSION;
5
+
6
+ export const isGitHubActions = !!process.env.GITHUB_ACTIONS;
7
+
8
+ // detect if running inside Docker container (CI tests run in Docker with host env vars)
9
+ export const isInsideDocker = existsSync("/.dockerenv");