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.
- package/LICENSE +661 -0
- package/README.md +244 -0
- package/dist/agents/claude.d.ts +113 -0
- package/dist/agents/claudePretoolGate.d.ts +137 -0
- package/dist/agents/dispatchMetrics.d.ts +77 -0
- package/dist/agents/gateServer.d.ts +7 -0
- package/dist/agents/index.d.ts +6 -0
- package/dist/agents/nativeFsDenies.d.ts +46 -0
- package/dist/agents/opencode.d.ts +284 -0
- package/dist/agents/opencodePlugin.d.ts +96 -0
- package/dist/agents/opencodeShared.d.ts +40 -0
- package/dist/agents/postRun.d.ts +126 -0
- package/dist/agents/reviewer.d.ts +41 -0
- package/dist/agents/sessionLabeler.d.ts +97 -0
- package/dist/agents/shared.d.ts +246 -0
- package/dist/agents/subagentModels.d.ts +19 -0
- package/dist/agents/tokenQuota.d.ts +118 -0
- package/dist/agents/writeGateSource.d.ts +22 -0
- package/dist/agents/writePolicy.d.ts +79 -0
- package/dist/brand.d.ts +67 -0
- package/dist/cli.mjs +247846 -0
- package/dist/external.d.ts +227 -0
- package/dist/i18n/scaffolding.d.ts +59 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +247061 -0
- package/dist/internal/index.d.ts +18 -0
- package/dist/internal.js +2398 -0
- package/dist/lifecycle.d.ts +2 -0
- package/dist/main.d.ts +8 -0
- package/dist/mcp/arkConfig.d.ts +1 -0
- package/dist/mcp/assess.d.ts +157 -0
- package/dist/mcp/capabilityContext.d.ts +71 -0
- package/dist/mcp/changeSummary.d.ts +52 -0
- package/dist/mcp/checkSuite.d.ts +27 -0
- package/dist/mcp/checkout.d.ts +92 -0
- package/dist/mcp/comment.d.ts +127 -0
- package/dist/mcp/commitInfo.d.ts +11 -0
- package/dist/mcp/crosswalk.d.ts +178 -0
- package/dist/mcp/crosswalkDigest.d.ts +1 -0
- package/dist/mcp/cyberEssentials.d.ts +24 -0
- package/dist/mcp/dashboard.d.ts +125 -0
- package/dist/mcp/dependencies.d.ts +12 -0
- package/dist/mcp/frameworks.d.ts +74 -0
- package/dist/mcp/geminiSanitizer.d.ts +28 -0
- package/dist/mcp/git.d.ts +60 -0
- package/dist/mcp/guardrails.d.ts +222 -0
- package/dist/mcp/issue.d.ts +20 -0
- package/dist/mcp/issueComments.d.ts +11 -0
- package/dist/mcp/issueEvents.d.ts +11 -0
- package/dist/mcp/issueInfo.d.ts +11 -0
- package/dist/mcp/labels.d.ts +14 -0
- package/dist/mcp/localContext.d.ts +26 -0
- package/dist/mcp/moduleExtraction.d.ts +79 -0
- package/dist/mcp/moduleTests.d.ts +106 -0
- package/dist/mcp/modules.d.ts +198 -0
- package/dist/mcp/output.d.ts +16 -0
- package/dist/mcp/pathSafety.d.ts +14 -0
- package/dist/mcp/policy.d.ts +50 -0
- package/dist/mcp/pr.d.ts +64 -0
- package/dist/mcp/prInfo.d.ts +11 -0
- package/dist/mcp/providerSchema.d.ts +52 -0
- package/dist/mcp/review.d.ts +212 -0
- package/dist/mcp/reviewComments.d.ts +245 -0
- package/dist/mcp/roots.d.ts +60 -0
- package/dist/mcp/scope.d.ts +26 -0
- package/dist/mcp/selectMode.d.ts +20 -0
- package/dist/mcp/server.d.ts +61 -0
- package/dist/mcp/shared.d.ts +62 -0
- package/dist/mcp/shell.d.ts +58 -0
- package/dist/mcp/staleFix.d.ts +138 -0
- package/dist/mcp/terraform/azurePrices.d.ts +8 -0
- package/dist/mcp/terraform/baseline.d.ts +57 -0
- package/dist/mcp/terraform/concernResult.d.ts +38 -0
- package/dist/mcp/terraform/cost.d.ts +55 -0
- package/dist/mcp/terraform/cspm.d.ts +80 -0
- package/dist/mcp/terraform/currency.d.ts +110 -0
- package/dist/mcp/terraform/decisions.d.ts +178 -0
- package/dist/mcp/terraform/eidas.d.ts +100 -0
- package/dist/mcp/terraform/evidence.d.ts +343 -0
- package/dist/mcp/terraform/findings.d.ts +76 -0
- package/dist/mcp/terraform/fixMemory.d.ts +81 -0
- package/dist/mcp/terraform/governance.d.ts +56 -0
- package/dist/mcp/terraform/hcl.d.ts +115 -0
- package/dist/mcp/terraform/iacLanguages.d.ts +120 -0
- package/dist/mcp/terraform/idleFloor.d.ts +78 -0
- package/dist/mcp/terraform/keyless.d.ts +68 -0
- package/dist/mcp/terraform/moduleDocs.d.ts +56 -0
- package/dist/mcp/terraform/nativeRules.d.ts +38 -0
- package/dist/mcp/terraform/nativeScan.d.ts +11 -0
- package/dist/mcp/terraform/noiseProfile.d.ts +100 -0
- package/dist/mcp/terraform/normalization.d.ts +52 -0
- package/dist/mcp/terraform/oscal.d.ts +103 -0
- package/dist/mcp/terraform/packs/azurerm-3-4.d.ts +2 -0
- package/dist/mcp/terraform/packs/cloudflare-4-5.d.ts +2 -0
- package/dist/mcp/terraform/paths.d.ts +28 -0
- package/dist/mcp/terraform/plan.d.ts +157 -0
- package/dist/mcp/terraform/planDrift.d.ts +199 -0
- package/dist/mcp/terraform/policyAuthor.d.ts +191 -0
- package/dist/mcp/terraform/prowlerOcsf.d.ts +136 -0
- package/dist/mcp/terraform/refactor.d.ts +183 -0
- package/dist/mcp/terraform/registry.d.ts +108 -0
- package/dist/mcp/terraform/risk.d.ts +41 -0
- package/dist/mcp/terraform/scanSession.d.ts +116 -0
- package/dist/mcp/terraform/scannerCache.d.ts +15 -0
- package/dist/mcp/terraform/scannerEgress.d.ts +72 -0
- package/dist/mcp/terraform/scannerJson.d.ts +13 -0
- package/dist/mcp/terraform/scanners.d.ts +205 -0
- package/dist/mcp/terraform/signing.d.ts +61 -0
- package/dist/mcp/terraform/stateLocking.d.ts +18 -0
- package/dist/mcp/terraform/subprocess.d.ts +43 -0
- package/dist/mcp/terraform/suppressions.d.ts +90 -0
- package/dist/mcp/terraform/taxonomy.d.ts +39 -0
- package/dist/mcp/terraform/tfquery.d.ts +47 -0
- package/dist/mcp/terraform/toolchainIntegrity.d.ts +82 -0
- package/dist/mcp/terraform/tools/authorPolicy.d.ts +59 -0
- package/dist/mcp/terraform/tools/detectPlanDrift.d.ts +20 -0
- package/dist/mcp/terraform/tools/emitCost.d.ts +11 -0
- package/dist/mcp/terraform/tools/emitSarif.d.ts +14 -0
- package/dist/mcp/terraform/tools/fixMemory.d.ts +19 -0
- package/dist/mcp/terraform/tools/infracostDiff.d.ts +22 -0
- package/dist/mcp/terraform/tools/ingestExternalFindings.d.ts +21 -0
- package/dist/mcp/terraform/tools/moduleLookup.d.ts +14 -0
- package/dist/mcp/terraform/tools/moduleSearch.d.ts +23 -0
- package/dist/mcp/terraform/tools/plan.d.ts +59 -0
- package/dist/mcp/terraform/tools/providerUpgrade.d.ts +55 -0
- package/dist/mcp/terraform/tools/readFindings.d.ts +17 -0
- package/dist/mcp/terraform/tools/scan.d.ts +114 -0
- package/dist/mcp/terraform/tools/validate.d.ts +31 -0
- package/dist/mcp/terraform/tools/verifyRemediation.d.ts +31 -0
- package/dist/mcp/terraform/tools/versionCurrency.d.ts +5 -0
- package/dist/mcp/terraform/tools.d.ts +16 -0
- package/dist/mcp/terraform/transformPacks.d.ts +267 -0
- package/dist/mcp/terraform/types.d.ts +226 -0
- package/dist/mcp/terraform/verification.d.ts +81 -0
- package/dist/mcp/terraform/vex.d.ts +115 -0
- package/dist/mcp/terraform/writeOnly.d.ts +67 -0
- package/dist/mcp/terraform.d.ts +51 -0
- package/dist/mcp/terratest.d.ts +85 -0
- package/dist/mcp/untrustedContent.d.ts +76 -0
- package/dist/mcp/upload.d.ts +8 -0
- package/dist/models.d.ts +181 -0
- package/dist/modes/address-reviews.d.ts +2 -0
- package/dist/modes/assess.d.ts +2 -0
- package/dist/modes/build.d.ts +2 -0
- package/dist/modes/compliance-audit.d.ts +2 -0
- package/dist/modes/cost-optimization.d.ts +2 -0
- package/dist/modes/drift-detect.d.ts +2 -0
- package/dist/modes/fix.d.ts +2 -0
- package/dist/modes/incremental-review.d.ts +2 -0
- package/dist/modes/index.d.ts +24 -0
- package/dist/modes/modernize-deprecated.d.ts +2 -0
- package/dist/modes/plan.d.ts +2 -0
- package/dist/modes/policy-gate.d.ts +2 -0
- package/dist/modes/prFormats.d.ts +3 -0
- package/dist/modes/refactor.d.ts +2 -0
- package/dist/modes/refresh-remediation.d.ts +2 -0
- package/dist/modes/remediate-and-refactor.d.ts +2 -0
- package/dist/modes/remediate.d.ts +2 -0
- package/dist/modes/resolve-conflicts.d.ts +2 -0
- package/dist/modes/review.d.ts +2 -0
- package/dist/modes/summarize-pr.d.ts +2 -0
- package/dist/modes/task.d.ts +2 -0
- package/dist/modes/terraform-code-review.d.ts +2 -0
- package/dist/modes/types.d.ts +9 -0
- package/dist/modes/update-dependencies.d.ts +2 -0
- package/dist/prep/index.d.ts +7 -0
- package/dist/prep/installNodeDependencies.d.ts +2 -0
- package/dist/prep/installPythonDependencies.d.ts +2 -0
- package/dist/prep/types.d.ts +31 -0
- package/dist/reviewQuality.d.ts +107 -0
- package/dist/skills/terraform-best-practices/SKILL.md +379 -0
- package/dist/toolState.d.ts +123 -0
- package/dist/utils/activity.d.ts +40 -0
- package/dist/utils/agent.d.ts +47 -0
- package/dist/utils/agentHangReport.d.ts +38 -0
- package/dist/utils/annotations.d.ts +17 -0
- package/dist/utils/apiFetch.d.ts +11 -0
- package/dist/utils/apiKeys.d.ts +48 -0
- package/dist/utils/apiUrl.d.ts +28 -0
- package/dist/utils/assets.d.ts +8 -0
- package/dist/utils/baseRefConfig.d.ts +121 -0
- package/dist/utils/billingErrors.d.ts +85 -0
- package/dist/utils/body.d.ts +34 -0
- package/dist/utils/buildInfraweaverFooter.d.ts +29 -0
- package/dist/utils/byokFallback.d.ts +85 -0
- package/dist/utils/changeImpact.d.ts +101 -0
- package/dist/utils/claudeSubscription.d.ts +30 -0
- package/dist/utils/cli.d.ts +10 -0
- package/dist/utils/cloudClient.d.ts +33 -0
- package/dist/utils/cloudFetchCore.d.ts +42 -0
- package/dist/utils/cloudReport.d.ts +114 -0
- package/dist/utils/codexHome.d.ts +29 -0
- package/dist/utils/codexOAuth.d.ts +60 -0
- package/dist/utils/diffCoverage.d.ts +63 -0
- package/dist/utils/env.d.ts +46 -0
- package/dist/utils/errorReport.d.ts +17 -0
- package/dist/utils/exitHandler.d.ts +8 -0
- package/dist/utils/fixDoubleEscapedString.d.ts +1 -0
- package/dist/utils/gitAuth.d.ts +84 -0
- package/dist/utils/gitAuthServer.d.ts +24 -0
- package/dist/utils/github.d.ts +104 -0
- package/dist/utils/globals.d.ts +3 -0
- package/dist/utils/infraweaverConfig.d.ts +56 -0
- package/dist/utils/install.d.ts +37 -0
- package/dist/utils/instructions.d.ts +48 -0
- package/dist/utils/keylessOidc.d.ts +28 -0
- package/dist/utils/leapingComment.d.ts +11 -0
- package/dist/utils/learnings.d.ts +62 -0
- package/dist/utils/learningsTruncate.d.ts +25 -0
- package/dist/utils/lifecycle.d.ts +57 -0
- package/dist/utils/log.d.ts +111 -0
- package/dist/utils/modelResolver.d.ts +63 -0
- package/dist/utils/moduleFetch.d.ts +39 -0
- package/dist/utils/normalizeEnv.d.ts +30 -0
- package/dist/utils/openCodeModels.d.ts +11 -0
- package/dist/utils/openaiCompatible.d.ts +26 -0
- package/dist/utils/opentofuMcp.d.ts +50 -0
- package/dist/utils/overrides.d.ts +40 -0
- package/dist/utils/packageManager.d.ts +49 -0
- package/dist/utils/patchWorkflowRunFields.d.ts +29 -0
- package/dist/utils/payload.d.ts +249 -0
- package/dist/utils/prSummary.d.ts +61 -0
- package/dist/utils/presets.d.ts +36 -0
- package/dist/utils/progressComment.d.ts +146 -0
- package/dist/utils/providerErrors.d.ts +31 -0
- package/dist/utils/proxyModel.d.ts +76 -0
- package/dist/utils/rangeDiff.d.ts +51 -0
- package/dist/utils/redact.d.ts +33 -0
- package/dist/utils/registryAuth.d.ts +52 -0
- package/dist/utils/remediationCommand.d.ts +58 -0
- package/dist/utils/retry.d.ts +38 -0
- package/dist/utils/reviewCleanup.d.ts +14 -0
- package/dist/utils/run.d.ts +9 -0
- package/dist/utils/runContext.d.ts +112 -0
- package/dist/utils/runContextData.d.ts +42 -0
- package/dist/utils/runErrorRenderer.d.ts +64 -0
- package/dist/utils/runLifecycle.d.ts +89 -0
- package/dist/utils/runStartupLog.d.ts +15 -0
- package/dist/utils/secrets.d.ts +34 -0
- package/dist/utils/setup.d.ts +90 -0
- package/dist/utils/shell.d.ts +44 -0
- package/dist/utils/skills.d.ts +10 -0
- package/dist/utils/subprocess.d.ts +81 -0
- package/dist/utils/terraformMcp.d.ts +46 -0
- package/dist/utils/time.d.ts +15 -0
- package/dist/utils/timer.d.ts +23 -0
- package/dist/utils/todoTracking.d.ts +16 -0
- package/dist/utils/token.d.ts +52 -0
- package/dist/utils/toolLicensing.d.ts +56 -0
- package/dist/utils/toolSelection.d.ts +73 -0
- package/dist/utils/toon.d.ts +16 -0
- package/dist/utils/version.d.ts +2 -0
- package/dist/utils/versioning.d.ts +7 -0
- package/dist/utils/vertex.d.ts +16 -0
- package/dist/utils/workflow.d.ts +13 -0
- package/package.json +132 -0
- package/src/agents/claude.ts +1588 -0
- package/src/agents/claudePretoolGate.ts +286 -0
- package/src/agents/dispatchMetrics.ts +162 -0
- package/src/agents/gateServer.ts +178 -0
- package/src/agents/index.ts +10 -0
- package/src/agents/nativeFsDenies.ts +164 -0
- package/src/agents/opencode.ts +1600 -0
- package/src/agents/opencodePlugin.ts +304 -0
- package/src/agents/opencodeShared.ts +134 -0
- package/src/agents/postRun.ts +615 -0
- package/src/agents/reviewer.ts +134 -0
- package/src/agents/sessionLabeler.ts +185 -0
- package/src/agents/shared.ts +377 -0
- package/src/agents/subagentModels.ts +40 -0
- package/src/agents/tokenQuota.ts +203 -0
- package/src/agents/writeGateSource.ts +148 -0
- package/src/agents/writePolicy.ts +132 -0
- package/src/brand.ts +84 -0
- package/src/cli.ts +117 -0
- package/src/commands/gha.ts +188 -0
- package/src/commands/mcp.ts +126 -0
- package/src/commands/verifyEvidence.ts +100 -0
- package/src/entry.ts +7 -0
- package/src/entryPost.ts +109 -0
- package/src/external.ts +308 -0
- package/src/i18n/scaffolding.ts +191 -0
- package/src/index.ts +7 -0
- package/src/internal/index.ts +74 -0
- package/src/lifecycle.ts +2 -0
- package/src/main.ts +815 -0
- package/src/mcp/__fixtures__/infraweaver-scratch-pr-49-review-3485940013.json +110 -0
- package/src/mcp/__fixtures__/infraweaver-scratch-pr-64-review-3531000326.json +14 -0
- package/src/mcp/__fixtures__/infraweaver-test-repo-pr-1.diff.json +67 -0
- package/src/mcp/__snapshots__/checkout.test.ts.snap +109 -0
- package/src/mcp/__snapshots__/reviewComments.test.ts.snap +71 -0
- package/src/mcp/arkConfig.ts +7 -0
- package/src/mcp/assess.ts +723 -0
- package/src/mcp/capabilityContext.ts +80 -0
- package/src/mcp/changeSummary.ts +145 -0
- package/src/mcp/checkSuite.ts +261 -0
- package/src/mcp/checkout.ts +1015 -0
- package/src/mcp/comment.ts +683 -0
- package/src/mcp/commitInfo.ts +57 -0
- package/src/mcp/crosswalk.ts +1253 -0
- package/src/mcp/crosswalkDigest.ts +5 -0
- package/src/mcp/cyberEssentials.ts +60 -0
- package/src/mcp/dashboard.ts +232 -0
- package/src/mcp/dependencies.ts +190 -0
- package/src/mcp/frameworks.ts +236 -0
- package/src/mcp/geminiSanitizer.ts +212 -0
- package/src/mcp/git.ts +1116 -0
- package/src/mcp/guardrails.ts +771 -0
- package/src/mcp/issue.ts +74 -0
- package/src/mcp/issueComments.ts +48 -0
- package/src/mcp/issueEvents.ts +100 -0
- package/src/mcp/issueInfo.ts +72 -0
- package/src/mcp/labels.ts +35 -0
- package/src/mcp/localContext.ts +65 -0
- package/src/mcp/localServer.ts +217 -0
- package/src/mcp/moduleExtraction.ts +368 -0
- package/src/mcp/moduleTests.ts +421 -0
- package/src/mcp/modules.ts +752 -0
- package/src/mcp/output.ts +71 -0
- package/src/mcp/pathSafety.ts +28 -0
- package/src/mcp/policy.ts +226 -0
- package/src/mcp/pr.ts +238 -0
- package/src/mcp/prInfo.ts +91 -0
- package/src/mcp/providerSchema.ts +175 -0
- package/src/mcp/review.ts +1081 -0
- package/src/mcp/reviewComments.ts +1137 -0
- package/src/mcp/roots.ts +217 -0
- package/src/mcp/scope.ts +82 -0
- package/src/mcp/selectMode.ts +207 -0
- package/src/mcp/server.ts +498 -0
- package/src/mcp/shared.ts +120 -0
- package/src/mcp/shell.ts +631 -0
- package/src/mcp/staleFix.ts +557 -0
- package/src/mcp/terraform/__snapshots__/moduleDocs.test.ts.snap +40 -0
- package/src/mcp/terraform/azurePrices.ts +38 -0
- package/src/mcp/terraform/baseline.ts +172 -0
- package/src/mcp/terraform/concernResult.ts +111 -0
- package/src/mcp/terraform/cost.ts +175 -0
- package/src/mcp/terraform/cspm.ts +326 -0
- package/src/mcp/terraform/currency.ts +354 -0
- package/src/mcp/terraform/decisions.ts +590 -0
- package/src/mcp/terraform/eidas.ts +134 -0
- package/src/mcp/terraform/evidence.ts +771 -0
- package/src/mcp/terraform/findings.ts +383 -0
- package/src/mcp/terraform/fixMemory.ts +253 -0
- package/src/mcp/terraform/governance.ts +231 -0
- package/src/mcp/terraform/hcl.ts +273 -0
- package/src/mcp/terraform/iacLanguages.ts +431 -0
- package/src/mcp/terraform/idleFloor.ts +304 -0
- package/src/mcp/terraform/keyless.ts +123 -0
- package/src/mcp/terraform/moduleDocs.ts +303 -0
- package/src/mcp/terraform/nativeRules.ts +152 -0
- package/src/mcp/terraform/nativeScan.ts +67 -0
- package/src/mcp/terraform/noiseProfile.ts +183 -0
- package/src/mcp/terraform/normalization.ts +265 -0
- package/src/mcp/terraform/oscal.ts +283 -0
- package/src/mcp/terraform/packs/azurerm-3-4.ts +382 -0
- package/src/mcp/terraform/packs/cloudflare-4-5.ts +114 -0
- package/src/mcp/terraform/paths.ts +59 -0
- package/src/mcp/terraform/plan.ts +377 -0
- package/src/mcp/terraform/planDrift.ts +520 -0
- package/src/mcp/terraform/policyAuthor.ts +886 -0
- package/src/mcp/terraform/prowlerOcsf.ts +380 -0
- package/src/mcp/terraform/refactor.ts +879 -0
- package/src/mcp/terraform/registry.ts +317 -0
- package/src/mcp/terraform/risk.ts +99 -0
- package/src/mcp/terraform/scanSession.ts +242 -0
- package/src/mcp/terraform/scannerCache.ts +86 -0
- package/src/mcp/terraform/scannerEgress.ts +141 -0
- package/src/mcp/terraform/scannerJson.ts +22 -0
- package/src/mcp/terraform/scanners.ts +1134 -0
- package/src/mcp/terraform/signing.ts +151 -0
- package/src/mcp/terraform/stateLocking.ts +106 -0
- package/src/mcp/terraform/subprocess.ts +102 -0
- package/src/mcp/terraform/suppressions.ts +551 -0
- package/src/mcp/terraform/taxonomy.ts +0 -0
- package/src/mcp/terraform/tfquery.ts +159 -0
- package/src/mcp/terraform/toolchainIntegrity.ts +151 -0
- package/src/mcp/terraform/tools/authorPolicy.ts +185 -0
- package/src/mcp/terraform/tools/detectPlanDrift.ts +279 -0
- package/src/mcp/terraform/tools/emitCost.ts +130 -0
- package/src/mcp/terraform/tools/emitSarif.ts +108 -0
- package/src/mcp/terraform/tools/fixMemory.ts +82 -0
- package/src/mcp/terraform/tools/infracostDiff.ts +110 -0
- package/src/mcp/terraform/tools/ingestExternalFindings.ts +259 -0
- package/src/mcp/terraform/tools/moduleLookup.ts +86 -0
- package/src/mcp/terraform/tools/moduleSearch.ts +46 -0
- package/src/mcp/terraform/tools/plan.ts +384 -0
- package/src/mcp/terraform/tools/providerUpgrade.ts +217 -0
- package/src/mcp/terraform/tools/readFindings.ts +138 -0
- package/src/mcp/terraform/tools/scan.ts +303 -0
- package/src/mcp/terraform/tools/validate.ts +160 -0
- package/src/mcp/terraform/tools/verifyRemediation.ts +190 -0
- package/src/mcp/terraform/tools/versionCurrency.ts +64 -0
- package/src/mcp/terraform/tools.ts +62 -0
- package/src/mcp/terraform/transformPacks.ts +594 -0
- package/src/mcp/terraform/types.ts +382 -0
- package/src/mcp/terraform/verification.ts +150 -0
- package/src/mcp/terraform/vex.ts +367 -0
- package/src/mcp/terraform/writeOnly.ts +252 -0
- package/src/mcp/terraform.ts +52 -0
- package/src/mcp/terratest.ts +215 -0
- package/src/mcp/untrustedContent.ts +126 -0
- package/src/mcp/upload.ts +123 -0
- package/src/models.ts +753 -0
- package/src/modes/address-reviews.ts +35 -0
- package/src/modes/assess.ts +27 -0
- package/src/modes/build.ts +86 -0
- package/src/modes/compliance-audit.ts +25 -0
- package/src/modes/cost-optimization.ts +36 -0
- package/src/modes/drift-detect.ts +31 -0
- package/src/modes/fix.ts +29 -0
- package/src/modes/incremental-review.ts +103 -0
- package/src/modes/index.ts +94 -0
- package/src/modes/modernize-deprecated.ts +36 -0
- package/src/modes/plan.ts +21 -0
- package/src/modes/policy-gate.ts +27 -0
- package/src/modes/prFormats.ts +325 -0
- package/src/modes/refactor.ts +74 -0
- package/src/modes/refresh-remediation.ts +40 -0
- package/src/modes/remediate-and-refactor.ts +42 -0
- package/src/modes/remediate.ts +78 -0
- package/src/modes/resolve-conflicts.ts +32 -0
- package/src/modes/review.ts +135 -0
- package/src/modes/summarize-pr.ts +42 -0
- package/src/modes/task.ts +26 -0
- package/src/modes/terraform-code-review.ts +68 -0
- package/src/modes/types.ts +17 -0
- package/src/modes/update-dependencies.ts +44 -0
- package/src/prep/index.ts +96 -0
- package/src/prep/installNodeDependencies.ts +251 -0
- package/src/prep/installPythonDependencies.ts +235 -0
- package/src/prep/types.ts +38 -0
- package/src/reviewQuality.ts +237 -0
- package/src/runCli.ts +335 -0
- package/src/skills/terraform-best-practices/SKILL.md +379 -0
- package/src/toolState.ts +241 -0
- package/src/utils/activity.ts +210 -0
- package/src/utils/agent.ts +245 -0
- package/src/utils/agentHangReport.ts +180 -0
- package/src/utils/annotations.ts +56 -0
- package/src/utils/apiFetch.ts +19 -0
- package/src/utils/apiKeys.ts +305 -0
- package/src/utils/apiUrl.ts +42 -0
- package/src/utils/assets.ts +123 -0
- package/src/utils/baseRefConfig.ts +254 -0
- package/src/utils/billingErrors.ts +210 -0
- package/src/utils/body.ts +168 -0
- package/src/utils/buildInfraweaverFooter.ts +104 -0
- package/src/utils/byokFallback.ts +137 -0
- package/src/utils/changeImpact.ts +330 -0
- package/src/utils/claudeSubscription.ts +93 -0
- package/src/utils/cli.ts +36 -0
- package/src/utils/cloudClient.ts +57 -0
- package/src/utils/cloudFetchCore.ts +139 -0
- package/src/utils/cloudReport.ts +316 -0
- package/src/utils/codexHome.ts +204 -0
- package/src/utils/codexOAuth.ts +154 -0
- package/src/utils/codexRefreshDetect.ts +36 -0
- package/src/utils/diffCoverage.ts +404 -0
- package/src/utils/env.ts +84 -0
- package/src/utils/errorReport.ts +94 -0
- package/src/utils/exitHandler.ts +35 -0
- package/src/utils/fixDoubleEscapedString.ts +9 -0
- package/src/utils/ghaCore.ts +13 -0
- package/src/utils/gitAuth.ts +268 -0
- package/src/utils/gitAuthServer.ts +186 -0
- package/src/utils/github.ts +676 -0
- package/src/utils/globals.ts +9 -0
- package/src/utils/humanEditCapture.ts +198 -0
- package/src/utils/infraweaverConfig.ts +202 -0
- package/src/utils/install.ts +279 -0
- package/src/utils/instructions.ts +640 -0
- package/src/utils/keylessOidc.ts +47 -0
- package/src/utils/leapingComment.ts +20 -0
- package/src/utils/learnings.ts +145 -0
- package/src/utils/learningsTruncate.ts +42 -0
- package/src/utils/lifecycle.ts +198 -0
- package/src/utils/log.ts +452 -0
- package/src/utils/modelResolver.ts +105 -0
- package/src/utils/moduleFetch.ts +138 -0
- package/src/utils/normalizeEnv.ts +106 -0
- package/src/utils/openCodeModels.ts +86 -0
- package/src/utils/openaiCompatible.ts +52 -0
- package/src/utils/opentofuMcp.ts +61 -0
- package/src/utils/overrides.ts +100 -0
- package/src/utils/packageManager.ts +257 -0
- package/src/utils/patchWorkflowRunFields.ts +173 -0
- package/src/utils/payload.ts +1206 -0
- package/src/utils/prSummary.ts +148 -0
- package/src/utils/presets.ts +105 -0
- package/src/utils/progressComment.ts +266 -0
- package/src/utils/providerErrors.ts +189 -0
- package/src/utils/proxyModel.ts +239 -0
- package/src/utils/rangeDiff.ts +182 -0
- package/src/utils/redact.ts +86 -0
- package/src/utils/registryAuth.ts +115 -0
- package/src/utils/remediationCommand.ts +144 -0
- package/src/utils/retry.ts +180 -0
- package/src/utils/reviewCleanup.ts +116 -0
- package/src/utils/run.ts +100 -0
- package/src/utils/runContext.ts +276 -0
- package/src/utils/runContextData.ts +121 -0
- package/src/utils/runErrorRenderer.ts +282 -0
- package/src/utils/runFixture.ts +91 -0
- package/src/utils/runLifecycle.ts +360 -0
- package/src/utils/runStartupLog.ts +67 -0
- package/src/utils/secrets.ts +208 -0
- package/src/utils/setup.ts +368 -0
- package/src/utils/shell.ts +132 -0
- package/src/utils/skills.ts +67 -0
- package/src/utils/subprocess.ts +474 -0
- package/src/utils/terraformMcp.ts +99 -0
- package/src/utils/time.ts +59 -0
- package/src/utils/timer.ts +72 -0
- package/src/utils/todoTracking.ts +168 -0
- package/src/utils/token.ts +294 -0
- package/src/utils/toolLicensing.ts +152 -0
- package/src/utils/toolSelection.ts +239 -0
- package/src/utils/toon.ts +76 -0
- package/src/utils/version.ts +10 -0
- package/src/utils/versioning.ts +44 -0
- package/src/utils/vertex.ts +94 -0
- package/src/utils/workflow.ts +25 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry module intelligence — look up a PUBLISHED module's interface and
|
|
3
|
+
* search the public registry for modules to reuse.
|
|
4
|
+
*
|
|
5
|
+
* Complements `./currency.ts` (which answers "is a newer VERSION available?"):
|
|
6
|
+
* this answers "what does this module EXPECT and EXPOSE?" (root inputs/outputs)
|
|
7
|
+
* and "what published modules exist for this need?". It exists so the agent can
|
|
8
|
+
* wire a `module {}` block against a real, published interface — an organisation's
|
|
9
|
+
* own published modules included — instead of guessing variable names.
|
|
10
|
+
*
|
|
11
|
+
* Read-only, public default registry only (private/TFE hosts are rejected, same
|
|
12
|
+
* scope as the currency check), and degrades green on every failure.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
DEFAULT_REGISTRY_BASE_URL,
|
|
17
|
+
fetchRegistryJson,
|
|
18
|
+
isRecord,
|
|
19
|
+
type LookupStatus,
|
|
20
|
+
} from "#app/mcp/terraform/currency";
|
|
21
|
+
|
|
22
|
+
const SEARCH_LIMIT_DEFAULT = 10;
|
|
23
|
+
const SEARCH_LIMIT_MAX = 25;
|
|
24
|
+
|
|
25
|
+
function asString(value: unknown): string | null {
|
|
26
|
+
return typeof value === "string" ? value : null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function asNumber(value: unknown): number | null {
|
|
30
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// --- module detail (interface lookup) ---------------------------------------
|
|
34
|
+
|
|
35
|
+
export interface ModuleInput {
|
|
36
|
+
name: string;
|
|
37
|
+
type: string | null;
|
|
38
|
+
description: string | null;
|
|
39
|
+
default: string | null;
|
|
40
|
+
required: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface ModuleOutput {
|
|
44
|
+
name: string;
|
|
45
|
+
description: string | null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface ModuleDetail {
|
|
49
|
+
source: string;
|
|
50
|
+
version: string | null;
|
|
51
|
+
description: string | null;
|
|
52
|
+
verified: boolean;
|
|
53
|
+
downloads: number | null;
|
|
54
|
+
published_at: string | null;
|
|
55
|
+
provider_dependencies: string[];
|
|
56
|
+
inputs: ModuleInput[];
|
|
57
|
+
outputs: ModuleOutput[];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function parseInputs(root: unknown): ModuleInput[] {
|
|
61
|
+
if (!isRecord(root) || !Array.isArray(root.inputs)) return [];
|
|
62
|
+
const out: ModuleInput[] = [];
|
|
63
|
+
for (const raw of root.inputs) {
|
|
64
|
+
if (!isRecord(raw) || typeof raw.name !== "string") continue;
|
|
65
|
+
const fallback = asString(raw.default);
|
|
66
|
+
out.push({
|
|
67
|
+
name: raw.name,
|
|
68
|
+
type: asString(raw.type),
|
|
69
|
+
description: asString(raw.description),
|
|
70
|
+
default: fallback,
|
|
71
|
+
// the registry sometimes carries an explicit `required` boolean; when it
|
|
72
|
+
// doesn't, a variable with no default is required.
|
|
73
|
+
required: typeof raw.required === "boolean" ? raw.required : fallback === null,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return out;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function parseOutputs(root: unknown): ModuleOutput[] {
|
|
80
|
+
if (!isRecord(root) || !Array.isArray(root.outputs)) return [];
|
|
81
|
+
const out: ModuleOutput[] = [];
|
|
82
|
+
for (const raw of root.outputs) {
|
|
83
|
+
if (!isRecord(raw) || typeof raw.name !== "string") continue;
|
|
84
|
+
out.push({ name: raw.name, description: asString(raw.description) });
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function parseProviderDependencies(root: unknown): string[] {
|
|
90
|
+
if (!isRecord(root) || !Array.isArray(root.provider_dependencies)) return [];
|
|
91
|
+
const out: string[] = [];
|
|
92
|
+
for (const raw of root.provider_dependencies) {
|
|
93
|
+
if (!isRecord(raw)) continue;
|
|
94
|
+
const name = asString(raw.name);
|
|
95
|
+
if (name === null) continue;
|
|
96
|
+
const namespace = asString(raw.namespace);
|
|
97
|
+
out.push(namespace ? `${namespace}/${name}` : name);
|
|
98
|
+
}
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function parseModuleDetail(body: unknown): ModuleDetail | null {
|
|
103
|
+
if (!isRecord(body)) return null;
|
|
104
|
+
const source = asString(body.source) ?? asString(body.id);
|
|
105
|
+
if (source === null) return null;
|
|
106
|
+
const root = body.root;
|
|
107
|
+
return {
|
|
108
|
+
source,
|
|
109
|
+
version: asString(body.version),
|
|
110
|
+
description: asString(body.description),
|
|
111
|
+
verified: body.verified === true,
|
|
112
|
+
downloads: asNumber(body.downloads),
|
|
113
|
+
published_at: asString(body.published_at),
|
|
114
|
+
provider_dependencies: parseProviderDependencies(root),
|
|
115
|
+
inputs: parseInputs(root),
|
|
116
|
+
outputs: parseOutputs(root),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// --- registry resolution (public vs private host) ---------------------------
|
|
121
|
+
|
|
122
|
+
/** the default public registry host — a bare `namespace/name/provider` (or a
|
|
123
|
+
* `registry.terraform.io/`-prefixed source) resolves here with no auth. */
|
|
124
|
+
export const PUBLIC_REGISTRY_HOST = "registry.terraform.io";
|
|
125
|
+
|
|
126
|
+
/** a module lookup's outcome: the shared `LookupStatus` plus two private-registry
|
|
127
|
+
* policy outcomes the tool surfaces with their own message. */
|
|
128
|
+
export type ModuleLookupStatus = LookupStatus | "host_not_allowed" | "auth_required";
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Split a module source into its optional registry `host` and the
|
|
132
|
+
* `namespace/name/provider` path. A host-prefixed source
|
|
133
|
+
* (`app.terraform.io/acme/vpc/aws`) targets a PRIVATE registry; a bare
|
|
134
|
+
* `namespace/name/provider` targets the public default registry (host === null).
|
|
135
|
+
* `path` is null when the source isn't a valid module address (the detected host,
|
|
136
|
+
* if any, is still returned for the caller's error message).
|
|
137
|
+
*/
|
|
138
|
+
export function splitModuleAddress(source: string): { host: string | null; path: string | null } {
|
|
139
|
+
const segments = source.split("/").filter(Boolean);
|
|
140
|
+
const first = segments[0];
|
|
141
|
+
const host = first?.includes(".") ? first.toLowerCase() : null;
|
|
142
|
+
if (segments.length === 4 && host !== null) {
|
|
143
|
+
return { host, path: segments.slice(1).join("/") };
|
|
144
|
+
}
|
|
145
|
+
if (segments.length === 3) return { host: null, path: segments.join("/") };
|
|
146
|
+
return { host, path: null };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface PrivateRegistryAuth {
|
|
150
|
+
/** the host(s) `token` authorises — a private source's host must be one of them.
|
|
151
|
+
* This is the security boundary: the agent names the source, but we only ever
|
|
152
|
+
* send the token to a host the operator allow-listed via `registry_host`. */
|
|
153
|
+
allowedHosts: string[];
|
|
154
|
+
/** the bearer token, or undefined when the run supplied no `registry_token`. */
|
|
155
|
+
token: string | undefined;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** discovered `modules.v1` API base per private host (a run hits the same registry
|
|
159
|
+
* repeatedly). Successful resolutions only — a transient failure must not poison
|
|
160
|
+
* the run. Cleared between tests via `_clearModuleDiscoveryCache`. */
|
|
161
|
+
const discoveryCache = new Map<string, string>();
|
|
162
|
+
|
|
163
|
+
/** test seam: drop the per-host discovery cache. */
|
|
164
|
+
export function _clearModuleDiscoveryCache(): void {
|
|
165
|
+
discoveryCache.clear();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Resolve a private registry's module API base via the standard service-discovery
|
|
170
|
+
* document (`GET https://<host>/.well-known/terraform.json` → its `modules.v1`
|
|
171
|
+
* entry). This is how Terraform itself finds the API, so it works for HCP Terraform,
|
|
172
|
+
* Terraform Enterprise, and any protocol-compliant registry regardless of the path
|
|
173
|
+
* they mount it at. Returns null when discovery fails or the host advertises no
|
|
174
|
+
* module API.
|
|
175
|
+
*/
|
|
176
|
+
async function discoverModulesV1Base(host: string, token: string): Promise<string | null> {
|
|
177
|
+
const cached = discoveryCache.get(host);
|
|
178
|
+
if (cached !== undefined) return cached;
|
|
179
|
+
const { status, body } = await fetchRegistryJson(`https://${host}/.well-known/terraform.json`, {
|
|
180
|
+
Authorization: `Bearer ${token}`,
|
|
181
|
+
});
|
|
182
|
+
if (status !== "ok" || !isRecord(body) || typeof body["modules.v1"] !== "string") return null;
|
|
183
|
+
const modulesPath = body["modules.v1"].replace(/\/$/, "");
|
|
184
|
+
const base = modulesPath.startsWith("http") ? modulesPath : `https://${host}${modulesPath}`;
|
|
185
|
+
discoveryCache.set(host, base);
|
|
186
|
+
return base;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** fetch + parse a module's detail from an already-resolved API base
|
|
190
|
+
* (`…/v1/modules` for the public registry, the discovered `modules.v1` for a
|
|
191
|
+
* private one). `token`, when present, authenticates the private call. */
|
|
192
|
+
async function fetchModuleDetailFrom(
|
|
193
|
+
base: string,
|
|
194
|
+
path: string,
|
|
195
|
+
opts: { version?: string | undefined; token?: string | undefined },
|
|
196
|
+
): Promise<{ status: LookupStatus; module: ModuleDetail | null }> {
|
|
197
|
+
const suffix = opts.version ? `/${encodeURIComponent(opts.version)}` : "";
|
|
198
|
+
const headers = opts.token ? { Authorization: `Bearer ${opts.token}` } : undefined;
|
|
199
|
+
const { status, body } = await fetchRegistryJson(`${base}/${path}${suffix}`, headers);
|
|
200
|
+
if (status !== "ok") return { status, module: null };
|
|
201
|
+
const module = parseModuleDetail(body);
|
|
202
|
+
if (module === null) return { status: "error", module: null };
|
|
203
|
+
return { status: "ok", module };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Look up a published module's interface. A bare `namespace/name/provider` hits
|
|
208
|
+
* the public default registry (no auth). A host-prefixed `host/namespace/name/
|
|
209
|
+
* provider` targets a PRIVATE registry (HCP Terraform / Terraform Enterprise / any
|
|
210
|
+
* protocol-compliant registry): the host must be in `auth.allowedHosts` AND a token
|
|
211
|
+
* supplied, then the API base is resolved via service discovery and the detail
|
|
212
|
+
* fetched with `Authorization: Bearer …`. Pass `version` to pin the lookup; omit it
|
|
213
|
+
* for the latest.
|
|
214
|
+
*/
|
|
215
|
+
export async function fetchModuleDetail(
|
|
216
|
+
source: string,
|
|
217
|
+
opts: {
|
|
218
|
+
version?: string | undefined;
|
|
219
|
+
auth?: PrivateRegistryAuth | undefined;
|
|
220
|
+
/** public-base override (tests). */
|
|
221
|
+
baseUrl?: string;
|
|
222
|
+
} = {},
|
|
223
|
+
): Promise<{ status: ModuleLookupStatus; module: ModuleDetail | null }> {
|
|
224
|
+
const { host, path } = splitModuleAddress(source);
|
|
225
|
+
if (path === null) return { status: "unsupported_source", module: null };
|
|
226
|
+
|
|
227
|
+
// public default registry — no auth.
|
|
228
|
+
if (host === null || host === PUBLIC_REGISTRY_HOST) {
|
|
229
|
+
const base = `${opts.baseUrl ?? DEFAULT_REGISTRY_BASE_URL}/v1/modules`;
|
|
230
|
+
return fetchModuleDetailFrom(base, path, { version: opts.version });
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// private registry — the host must be operator-authorised AND a token supplied.
|
|
234
|
+
if (!opts.auth?.allowedHosts.includes(host)) {
|
|
235
|
+
return { status: "host_not_allowed", module: null };
|
|
236
|
+
}
|
|
237
|
+
if (!opts.auth.token) return { status: "auth_required", module: null };
|
|
238
|
+
const modulesBase = await discoverModulesV1Base(host, opts.auth.token);
|
|
239
|
+
if (modulesBase === null) return { status: "error", module: null };
|
|
240
|
+
return fetchModuleDetailFrom(modulesBase, path, {
|
|
241
|
+
version: opts.version,
|
|
242
|
+
token: opts.auth.token,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// --- module search (discovery) ----------------------------------------------
|
|
247
|
+
|
|
248
|
+
export interface ModuleSearchResult {
|
|
249
|
+
address: string;
|
|
250
|
+
version: string | null;
|
|
251
|
+
description: string | null;
|
|
252
|
+
downloads: number | null;
|
|
253
|
+
verified: boolean;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export interface ModuleSearchQuery {
|
|
257
|
+
query: string;
|
|
258
|
+
namespace?: string | undefined;
|
|
259
|
+
provider?: string | undefined;
|
|
260
|
+
verified?: boolean | undefined;
|
|
261
|
+
limit?: number | undefined;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** build the `namespace/name/provider` address callers feed back into
|
|
265
|
+
* fetchModuleDetail, falling back to the raw (version-suffixed) id. */
|
|
266
|
+
function searchResultAddress(raw: Record<string, unknown>): string | null {
|
|
267
|
+
const namespace = asString(raw.namespace);
|
|
268
|
+
const name = asString(raw.name);
|
|
269
|
+
const provider = asString(raw.provider);
|
|
270
|
+
if (namespace && name && provider) return `${namespace}/${name}/${provider}`;
|
|
271
|
+
return asString(raw.id);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function parseSearchResults(body: unknown): ModuleSearchResult[] | null {
|
|
275
|
+
if (!isRecord(body) || !Array.isArray(body.modules)) return null;
|
|
276
|
+
const out: ModuleSearchResult[] = [];
|
|
277
|
+
for (const raw of body.modules) {
|
|
278
|
+
if (!isRecord(raw)) continue;
|
|
279
|
+
const address = searchResultAddress(raw);
|
|
280
|
+
if (address === null) continue;
|
|
281
|
+
out.push({
|
|
282
|
+
address,
|
|
283
|
+
version: asString(raw.version),
|
|
284
|
+
description: asString(raw.description),
|
|
285
|
+
downloads: asNumber(raw.downloads),
|
|
286
|
+
verified: raw.verified === true,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
return out;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* GET /v1/modules/search — discover published modules (the organisation's own
|
|
294
|
+
* namespace included) to REUSE instead of writing raw resources. Public default
|
|
295
|
+
* registry only. `limit` is clamped to a small range to keep the result tight.
|
|
296
|
+
*/
|
|
297
|
+
export async function searchRegistryModules(
|
|
298
|
+
params: ModuleSearchQuery,
|
|
299
|
+
opts: { baseUrl?: string } = {},
|
|
300
|
+
): Promise<{ status: LookupStatus; modules: ModuleSearchResult[]; limit: number }> {
|
|
301
|
+
const base = opts.baseUrl ?? DEFAULT_REGISTRY_BASE_URL;
|
|
302
|
+
const limit = Math.min(
|
|
303
|
+
Math.max(1, Math.trunc(params.limit ?? SEARCH_LIMIT_DEFAULT)),
|
|
304
|
+
SEARCH_LIMIT_MAX,
|
|
305
|
+
);
|
|
306
|
+
const url = new URL(`${base}/v1/modules/search`);
|
|
307
|
+
url.searchParams.set("q", params.query);
|
|
308
|
+
url.searchParams.set("limit", String(limit));
|
|
309
|
+
if (params.namespace) url.searchParams.set("namespace", params.namespace);
|
|
310
|
+
if (params.provider) url.searchParams.set("provider", params.provider);
|
|
311
|
+
if (params.verified) url.searchParams.set("verified", "true");
|
|
312
|
+
const { status, body } = await fetchRegistryJson(url.toString());
|
|
313
|
+
if (status !== "ok") return { status, modules: [], limit };
|
|
314
|
+
const modules = parseSearchResults(body);
|
|
315
|
+
if (modules === null) return { status: "error", modules: [], limit };
|
|
316
|
+
return { status: "ok", modules, limit };
|
|
317
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { classifyRefusal } from "#app/mcp/terraform/decisions";
|
|
2
|
+
import {
|
|
3
|
+
applyNoisePenalty,
|
|
4
|
+
EMPTY_NOISE_PROFILE,
|
|
5
|
+
explainNoiseAdjustment,
|
|
6
|
+
type NoiseAdjustment,
|
|
7
|
+
type NoiseProfile,
|
|
8
|
+
noiseAdjustmentFor,
|
|
9
|
+
} from "#app/mcp/terraform/noiseProfile";
|
|
10
|
+
import { type Concern, cvssScoreForSeverity } from "#app/mcp/terraform/types";
|
|
11
|
+
|
|
12
|
+
const EXPOSURE_SIGNAL =
|
|
13
|
+
/(0\.0\.0\.0\/0|::\/0|\bpublic(ly)?\b|\binternet\b|\bingress\b|\bunrestricted\b|world[-\s]?readable|\banonymous\b|\bexposed?\b)/i;
|
|
14
|
+
|
|
15
|
+
export interface RiskFactors {
|
|
16
|
+
severity: number;
|
|
17
|
+
exposure: number;
|
|
18
|
+
fixability: number;
|
|
19
|
+
/** G7: the fleet-noise down-rank applied, as a NEGATIVE contribution. Present
|
|
20
|
+
* only when one applied, so a reader can always reconstruct the score from
|
|
21
|
+
* its parts and see that nothing was adjusted invisibly. */
|
|
22
|
+
noise?: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface RiskScore {
|
|
26
|
+
score: number;
|
|
27
|
+
factors: RiskFactors;
|
|
28
|
+
/** the dismissal history behind `factors.noise`, when there is one. */
|
|
29
|
+
noise?: NoiseAdjustment;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Score a concern for SURFACING order.
|
|
34
|
+
*
|
|
35
|
+
* `profile` is the org's fleet-wide dismissal record (G7). It can only ever
|
|
36
|
+
* lower a score, is bounded and floored, and never applies to critical/high —
|
|
37
|
+
* see `noiseProfile.ts` for why a ranking model in an evidence product is
|
|
38
|
+
* allowed to reorder and nothing else. Defaults to empty, so every existing
|
|
39
|
+
* caller keeps the exact scores it had.
|
|
40
|
+
*/
|
|
41
|
+
export function scoreConcern(concern: Concern, profile: NoiseProfile = EMPTY_NOISE_PROFILE): RiskScore {
|
|
42
|
+
const severity = cvssScoreForSeverity(concern.severity);
|
|
43
|
+
const exposed = EXPOSURE_SIGNAL.test(`${concern.rule_id} ${concern.evidence}`);
|
|
44
|
+
const exposure = concern.category === "security" && exposed ? 1.5 : 0;
|
|
45
|
+
const fixability = classifyRefusal(concern).refuse ? 0 : 0.5;
|
|
46
|
+
const raw = severity + exposure + fixability;
|
|
47
|
+
const base = Math.min(10, Math.round(raw * 10) / 10);
|
|
48
|
+
|
|
49
|
+
const adjustment = noiseAdjustmentFor(concern, profile);
|
|
50
|
+
if (!adjustment) return { score: base, factors: { severity, exposure, fixability } };
|
|
51
|
+
const score = applyNoisePenalty(base, adjustment);
|
|
52
|
+
return {
|
|
53
|
+
score,
|
|
54
|
+
// report the penalty ACTUALLY applied (the floor may have absorbed part of
|
|
55
|
+
// it), so `severity + exposure + fixability + noise` reconstructs `score`.
|
|
56
|
+
factors: { severity, exposure, fixability, noise: Math.round((score - base) * 10) / 10 },
|
|
57
|
+
noise: adjustment,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function riskScore(concern: Concern, profile: NoiseProfile = EMPTY_NOISE_PROFILE): number {
|
|
62
|
+
return scoreConcern(concern, profile).score;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface RankedConcern {
|
|
66
|
+
concern_id: string;
|
|
67
|
+
rule_id: string;
|
|
68
|
+
severity: Concern["severity"];
|
|
69
|
+
category: Concern["category"];
|
|
70
|
+
location: Concern["location"];
|
|
71
|
+
risk_score: number;
|
|
72
|
+
risk_factors: RiskFactors;
|
|
73
|
+
/** G7: why this was ranked lower, in the org's own words. Present only when a
|
|
74
|
+
* down-rank applied — an unexplained demotion is indistinguishable from a bug. */
|
|
75
|
+
noise_reason?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function topRisks(
|
|
79
|
+
concerns: Concern[],
|
|
80
|
+
n = 5,
|
|
81
|
+
profile: NoiseProfile = EMPTY_NOISE_PROFILE,
|
|
82
|
+
): RankedConcern[] {
|
|
83
|
+
return concerns
|
|
84
|
+
.map((c) => ({ concern: c, risk: scoreConcern(c, profile) }))
|
|
85
|
+
.sort((a, b) => b.risk.score - a.risk.score || a.concern.id.localeCompare(b.concern.id))
|
|
86
|
+
.slice(0, n)
|
|
87
|
+
.map(({ concern, risk }) => ({
|
|
88
|
+
concern_id: concern.id,
|
|
89
|
+
rule_id: concern.rule_id,
|
|
90
|
+
severity: concern.severity,
|
|
91
|
+
category: concern.category,
|
|
92
|
+
location: concern.location,
|
|
93
|
+
risk_score: risk.score,
|
|
94
|
+
risk_factors: risk.factors,
|
|
95
|
+
// conditional spread, not `noise_reason: undefined` —
|
|
96
|
+
// `exactOptionalPropertyTypes` treats an explicit undefined as a value.
|
|
97
|
+
...(risk.noise ? { noise_reason: explainNoiseAdjustment(risk.noise) } : {}),
|
|
98
|
+
}));
|
|
99
|
+
}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import type { ProvenFixPattern } from "#app/mcp/terraform/fixMemory";
|
|
2
|
+
import type { IdleFloorReport } from "#app/mcp/terraform/idleFloor";
|
|
3
|
+
import type { NoiseProfile } from "#app/mcp/terraform/noiseProfile";
|
|
4
|
+
import type { DriftEvidenceStatement } from "#app/mcp/terraform/planDrift";
|
|
5
|
+
import {
|
|
6
|
+
buildUpgradeStatement,
|
|
7
|
+
type ProvenTransform,
|
|
8
|
+
type TransformMatch,
|
|
9
|
+
type UpgradeEvidenceStatement,
|
|
10
|
+
type UpgradeIntent,
|
|
11
|
+
} from "#app/mcp/terraform/transformPacks";
|
|
12
|
+
import type { Concern } from "#app/mcp/terraform/types";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The terraform tool-to-tool session: the explicit, typed channel the terraform
|
|
16
|
+
* MCP tools use to hand results to one another (and to end-of-run reporting)
|
|
17
|
+
* across separate, agent-mediated invocations.
|
|
18
|
+
*
|
|
19
|
+
* This used to be ~11 loose fields on the 69-field `ToolState` god-bag, where
|
|
20
|
+
* the coupling was invisible in every signature and the ordering was silently
|
|
21
|
+
* load-bearing. Naming the channel makes the contract greppable and testable:
|
|
22
|
+
*
|
|
23
|
+
* - `terraform_scan` / `terraform_assess` / `read_findings` POPULATE the
|
|
24
|
+
* baseline (`baselineConcernIds` / `baselineConcernKeys` /
|
|
25
|
+
* `baselineFmtDriftFiles`) and the acted-on set (`lastScanConcerns`).
|
|
26
|
+
* - `terraform_plan` POPULATES `plannedDestroy` + the confidence signals
|
|
27
|
+
* (`lastBlastTier`, `lastIdempotent`); `infracost_diff` populates
|
|
28
|
+
* `lastCostDirection`; `terraform_emit_sarif` sets `emittedSarifPath`;
|
|
29
|
+
* the refactor equivalence check sets `refactorEquivalence` and
|
|
30
|
+
* `terraform_emit_evidence` sets `refactorProposedUnproven`.
|
|
31
|
+
* - `terraform_verify_remediation` CONSUMES the baseline + confidence signals;
|
|
32
|
+
* `terraform_validate` consumes `baselineFmtDriftFiles`; the push guardrails
|
|
33
|
+
* consume `plannedDestroy` / `refactorEquivalence`; end-of-run reporting
|
|
34
|
+
* (`runLifecycle`, `cloudReport`) consumes `lastScanConcerns` /
|
|
35
|
+
* `emittedSarifPath` / the refactor markers.
|
|
36
|
+
*
|
|
37
|
+
* Every field is still LITERAL (records a thing that happened) and every
|
|
38
|
+
* consumer degrades gracefully when its producer didn't run this session
|
|
39
|
+
* (`undefined`), so the ordering is documented here rather than assumed.
|
|
40
|
+
* Reach it through {@link scanSessionOf} so a partially-constructed `ToolState`
|
|
41
|
+
* (chiefly in tests) lazily gets a session rather than throwing.
|
|
42
|
+
*/
|
|
43
|
+
export interface ScanSession {
|
|
44
|
+
// full pre-fix scan id set (the deduped union of every scanner's concern ids,
|
|
45
|
+
// unfiltered by severity), captured by terraform_scan. read by
|
|
46
|
+
// terraform_verify_remediation to compute regressions = current −
|
|
47
|
+
// baseline (concern ids the fix INTRODUCED). undefined until the first scan.
|
|
48
|
+
baselineConcernIds?: string[];
|
|
49
|
+
// enterprise-integrity — the LINE-INDEPENDENT keys (concernKeyOf) of the
|
|
50
|
+
// same full pre-fix baseline. terraform_verify_remediation diffs on these, not
|
|
51
|
+
// raw ids, so a fix that SHIFTS lines (almost every fix) can't make an unfixed
|
|
52
|
+
// concern look resolved nor a pre-existing one look like a regression. Set
|
|
53
|
+
// alongside baselineConcernIds by terraform_scan / read_findings.
|
|
54
|
+
baselineConcernKeys?: string[];
|
|
55
|
+
// files that already failed `terraform fmt -check` at the pre-fix baseline
|
|
56
|
+
// scan (before any edit). read by terraform_validate so PRE-EXISTING style
|
|
57
|
+
// drift the run didn't introduce never gates `passed` — a scoped remediation
|
|
58
|
+
// must not reformat unrelated lines just to clear drift the file already had.
|
|
59
|
+
// Set alongside baselineConcernIds by terraform_scan / read_findings;
|
|
60
|
+
// undefined until the first scan (validate then falls back to gating on all
|
|
61
|
+
// drift, preserving pre-change behaviour outside the remediation flow).
|
|
62
|
+
baselineFmtDriftFiles?: string[];
|
|
63
|
+
// the most recent terraform_scan's reported concern set (post scope/severity
|
|
64
|
+
// filtering — what the run acted on). read at end-of-run by
|
|
65
|
+
// finalizeSuccessRun to emit the SARIF artifact + findings-count output, and
|
|
66
|
+
// by cloudReport to build the dashboard report. undefined until a scan ran;
|
|
67
|
+
// [] means the scan came back clean.
|
|
68
|
+
lastScanConcerns?: Concern[];
|
|
69
|
+
// destructive resources the most recent terraform_plan reported, partitioned
|
|
70
|
+
// into stateful (data-bearing, high-risk) and ephemeral. set by
|
|
71
|
+
// terraform_plan; read by the destroy-block guardrail (mcp/guardrails.ts) at
|
|
72
|
+
// push time so a fix that would delete/replace a datastore is blocked on the
|
|
73
|
+
// plan's evidence rather than the agent's self-report.
|
|
74
|
+
plannedDestroy?: {
|
|
75
|
+
stateful: { address: string; action: string; type: string }[];
|
|
76
|
+
ephemeral: { address: string; action: string; type: string }[];
|
|
77
|
+
};
|
|
78
|
+
// verification signals the confidence label aggregates, each recorded
|
|
79
|
+
// by the tool that produced it: terraform_plan sets blastTier + idempotent
|
|
80
|
+
// (undefined when no plan ran), infracost_diff sets costDirection. read by
|
|
81
|
+
// terraform_verify_remediation's computeConfidence so the PR's confidence is
|
|
82
|
+
// computed from real evidence, not the agent's word.
|
|
83
|
+
lastBlastTier?: "low" | "medium" | "high";
|
|
84
|
+
lastIdempotent?: boolean;
|
|
85
|
+
lastCostDirection?: "increase" | "decrease" | "no-change" | "unknown";
|
|
86
|
+
// the credential-free idle-floor report from terraform_emit_cost (§5.19). set
|
|
87
|
+
// by that tool; read by the evidence builder so the signed bundle carries the
|
|
88
|
+
// SAME numbers the cost.md artifact shows, computed once.
|
|
89
|
+
lastIdleFloor?: IdleFloorReport | undefined;
|
|
90
|
+
// the drift statement from the most recent detect_plan_drift (TC-2.1). set by
|
|
91
|
+
// that tool; read by terraform_emit_evidence so drift — including the
|
|
92
|
+
// `forgotten` blind-spot list and every coverage gap — enters the SIGNED
|
|
93
|
+
// bundle instead of dying as a run verdict. undefined until drift ran.
|
|
94
|
+
lastDrift?: DriftEvidenceStatement | undefined;
|
|
95
|
+
// absolute path of a SARIF file the agent wrote via terraform_emit_sarif.
|
|
96
|
+
// set by that tool on a successful write. read by finalizeSuccessRun's
|
|
97
|
+
// findings-output step so the end-of-run safety-net emit does NOT clobber an
|
|
98
|
+
// agent-emitted report (which may use a lower threshold / custom path) — it
|
|
99
|
+
// points findings-sarif-path at this file instead of rewriting.
|
|
100
|
+
emittedSarifPath?: string;
|
|
101
|
+
// the most recent terraform_equivalence_check verdict (the keys-free refactor
|
|
102
|
+
// EQUIVALENCE proof). set by that tool; read by the assertRefactorEquivalence
|
|
103
|
+
// push guardrail (mcp/guardrails.ts) so a refactor whose equivalence couldn't
|
|
104
|
+
// be proven — most dangerously, an UNCOVERED `moved {}` block, which would
|
|
105
|
+
// silently destroy/recreate live resources — is hard-blocked at push time on
|
|
106
|
+
// the proof's evidence, never the agent's self-report. undefined until the
|
|
107
|
+
// equivalence check runs, so it only ever gates an actual refactor flow.
|
|
108
|
+
refactorEquivalence?: {
|
|
109
|
+
equivalent: boolean;
|
|
110
|
+
// the keys-free sub-results, recorded so terraform_emit_evidence can render
|
|
111
|
+
// the equivalence statement with the proof that backs each claim (§8).
|
|
112
|
+
resource_set_equivalent: boolean;
|
|
113
|
+
arg_names_equivalent: boolean;
|
|
114
|
+
moves_exhaustive: boolean;
|
|
115
|
+
moves_detected: number;
|
|
116
|
+
validate_passed: boolean;
|
|
117
|
+
fmt_clean: boolean;
|
|
118
|
+
uncovered_moves: { from: string; to: string }[];
|
|
119
|
+
reasons: string[];
|
|
120
|
+
};
|
|
121
|
+
// set by terraform_emit_evidence when it records a b.4 third-party-module
|
|
122
|
+
// adoption shipped WITHOUT a plan (the `proposed — unproven` marker). read by
|
|
123
|
+
// the Cloud report (cloudReport.ts) so the dashboard shows that unmissable
|
|
124
|
+
// marker rather than implying a proof. An actual equivalence proof
|
|
125
|
+
// (refactorEquivalence) always takes precedence over this flag.
|
|
126
|
+
refactorProposedUnproven?: boolean;
|
|
127
|
+
// §5.12 proven-fix memory — the library of proven-fix patterns loaded at run
|
|
128
|
+
// start (local `.infraweaver.fix-memory.json` ∪ the org's Cloud library), read by
|
|
129
|
+
// the terraform_fix_memory tool to offer the fixer a proven prior for the
|
|
130
|
+
// finding-types in the current scan. undefined until loaded; [] = none known.
|
|
131
|
+
fixMemoryLibrary?: ProvenFixPattern[];
|
|
132
|
+
// G7 the org's fleet-wide dismissal record, coerced at run start from the Cloud
|
|
133
|
+
// run-context. Read by `terraform_scan` to DOWN-RANK finding types this org has
|
|
134
|
+
// repeatedly waived. Surfacing only — it can never suppress a finding, change a
|
|
135
|
+
// severity or verdict, or touch the signed evidence (see `noiseProfile`).
|
|
136
|
+
// undefined until loaded; an empty map = nothing learned.
|
|
137
|
+
noiseProfile?: NoiseProfile;
|
|
138
|
+
// §5.12 — patterns CAPTURED this run: each is a finding-type that went ✗→✓ via
|
|
139
|
+
// terraform_verify_remediation (only on a clean proof — verified, a real
|
|
140
|
+
// regression baseline, no regressions). read at end-of-run by cloudReport, which
|
|
141
|
+
// reports them to the org library (the fleet store). Accumulated across verify
|
|
142
|
+
// calls; deduped on use. (The committed local `.infraweaver.fix-memory.json` is
|
|
143
|
+
// produced out-of-band — it's a READ source here, not written during a run.)
|
|
144
|
+
provenFixCaptures?: ProvenFixPattern[];
|
|
145
|
+
// TC-2.2 — the org's fleet-wide record of which provider-upgrade transforms
|
|
146
|
+
// have already planned cleanly elsewhere, coerced at run start from the Cloud
|
|
147
|
+
// run-context. Read by terraform_provider_upgrade to annotate a transform with
|
|
148
|
+
// its fleet reuse. Counters only: no repo names, no configuration.
|
|
149
|
+
provenTransformLibrary?: ProvenTransform[];
|
|
150
|
+
// TC-2.2 — what terraform_provider_upgrade matched this run. Kept so the
|
|
151
|
+
// end-of-run capture can report the transforms the plan actually proved,
|
|
152
|
+
// rather than every transform the pack knows about.
|
|
153
|
+
transformMatches?: TransformMatch[];
|
|
154
|
+
// TC-2.2 — the detected upgrade, bound at evidence time to the plan that
|
|
155
|
+
// followed it. undefined unless terraform_provider_upgrade ran and a pack
|
|
156
|
+
// applied, so a run that never touched a provider major emits no upgrade block.
|
|
157
|
+
upgradeIntent?: UpgradeIntent;
|
|
158
|
+
// TC-2.2 — the aggregate plan counts, recorded by terraform_plan. The session
|
|
159
|
+
// already carries blast tier, idempotency and the destroy classification; only
|
|
160
|
+
// the raw add/change/destroy totals were missing, and the upgrade evidence
|
|
161
|
+
// statement needs them to state what the plan actually showed.
|
|
162
|
+
lastPlanTotals?: {
|
|
163
|
+
to_add: number;
|
|
164
|
+
to_change: number;
|
|
165
|
+
to_destroy: number;
|
|
166
|
+
destructive: number;
|
|
167
|
+
};
|
|
168
|
+
// TC-2.2 — was the upgrade ALREADY detected when this plan ran? Set by
|
|
169
|
+
// terraform_plan from whether `upgradeIntent` existed at that moment.
|
|
170
|
+
//
|
|
171
|
+
// Without it, a run that planned for some other reason and only later called
|
|
172
|
+
// terraform_provider_upgrade would emit a `plan-proven` verdict off a plan
|
|
173
|
+
// produced BEFORE the upgrade was even considered — a signed claim that a
|
|
174
|
+
// migration planned cleanly, backed by a plan of the pre-migration config.
|
|
175
|
+
// The ordering is the whole proof, so it is recorded rather than assumed.
|
|
176
|
+
planFollowedUpgradeDetection?: boolean;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* The TC-2.2 upgrade statement for this session, or undefined when no provider
|
|
181
|
+
* pack applied.
|
|
182
|
+
*
|
|
183
|
+
* Deliberately computed in ONE place. Two consumers need it — the signed
|
|
184
|
+
* evidence bundle and the fleet report — and if each assembled the plan facts
|
|
185
|
+
* itself they could disagree, which would mean telling an org that a transform
|
|
186
|
+
* planned cleanly while the signed artefact for that same run said otherwise.
|
|
187
|
+
*/
|
|
188
|
+
export function upgradeStatementOf(
|
|
189
|
+
session: ScanSession,
|
|
190
|
+
): UpgradeEvidenceStatement | undefined {
|
|
191
|
+
// Only a plan that ran AFTER the upgrade was detected can back it. A plan from
|
|
192
|
+
// earlier in the run describes the pre-migration configuration, so it is
|
|
193
|
+
// discarded here and the statement degrades to `no-plan` — visibly unproven,
|
|
194
|
+
// which is the honest outcome, rather than silently proven by the wrong plan.
|
|
195
|
+
const totals = session.planFollowedUpgradeDetection
|
|
196
|
+
? session.lastPlanTotals
|
|
197
|
+
: undefined;
|
|
198
|
+
return buildUpgradeStatement(
|
|
199
|
+
session.upgradeIntent,
|
|
200
|
+
totals
|
|
201
|
+
? {
|
|
202
|
+
...totals,
|
|
203
|
+
stateful_destructive: session.plannedDestroy?.stateful.length ?? 0,
|
|
204
|
+
// A plan whose idempotency was never recorded is treated as unstable
|
|
205
|
+
// rather than stable — the conservative direction for a proof.
|
|
206
|
+
idempotent: session.lastIdempotent ?? false,
|
|
207
|
+
}
|
|
208
|
+
: undefined,
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** A fresh, empty terraform session. */
|
|
213
|
+
export function createScanSession(): ScanSession {
|
|
214
|
+
return {};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* The single entry point to the terraform session on a `ToolState`. Lazily
|
|
219
|
+
* initializes it, so a partially-constructed `ToolState` (chiefly test fixtures
|
|
220
|
+
* that cast `{}`) still reads and writes safely rather than dereferencing
|
|
221
|
+
* `undefined`. In production `initToolState` seeds it, so this only ever
|
|
222
|
+
* lazy-creates for such fixtures.
|
|
223
|
+
*/
|
|
224
|
+
export function scanSessionOf(toolState: {
|
|
225
|
+
scanSession?: ScanSession;
|
|
226
|
+
}): ScanSession {
|
|
227
|
+
toolState.scanSession ??= {};
|
|
228
|
+
return toolState.scanSession;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* true once terraform_scan / read_findings captured a pre-fix baseline this
|
|
233
|
+
* session. terraform_verify_remediation key-maps requested ids against the
|
|
234
|
+
* baseline when this holds, and reports regressions on that basis; otherwise it
|
|
235
|
+
* falls back to raw-id matching and marks regressions as unchecked.
|
|
236
|
+
*/
|
|
237
|
+
export function hasBaseline(session: ScanSession): boolean {
|
|
238
|
+
return (
|
|
239
|
+
session.baselineConcernKeys !== undefined ||
|
|
240
|
+
session.baselineConcernIds !== undefined
|
|
241
|
+
);
|
|
242
|
+
}
|