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,138 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { type } from "arktype";
|
|
4
|
+
import { PRODUCT_NAME } from "#app/brand";
|
|
5
|
+
import type { LocalToolContext } from "#app/mcp/localContext";
|
|
6
|
+
import { resolveWithinCwd } from "#app/mcp/pathSafety";
|
|
7
|
+
import { execute, tool, toolOk } from "#app/mcp/shared";
|
|
8
|
+
import { buildConcernResult } from "#app/mcp/terraform/concernResult";
|
|
9
|
+
import { docUrlsForGroup, ruleDocUrl } from "#app/mcp/terraform/decisions";
|
|
10
|
+
import { parseFindingsFile } from "#app/mcp/terraform/findings";
|
|
11
|
+
import {
|
|
12
|
+
type Concern,
|
|
13
|
+
SEVERITY_RANK,
|
|
14
|
+
type Severity,
|
|
15
|
+
skipResult,
|
|
16
|
+
} from "#app/mcp/terraform/types";
|
|
17
|
+
import { UNTRUSTED_DATA_NOTICE } from "#app/mcp/untrustedContent";
|
|
18
|
+
import { log } from "#app/utils/cli";
|
|
19
|
+
|
|
20
|
+
export const ReadFindingsParams = type({
|
|
21
|
+
"path?": type.string.describe(
|
|
22
|
+
"path to the Assessor's findings.json. Defaults to $INFRAWEAVER_FINDINGS_PATH, then ./findings.json in the workspace.",
|
|
23
|
+
),
|
|
24
|
+
"severity_threshold?": type(
|
|
25
|
+
"'critical' | 'high' | 'medium' | 'low' | 'info'",
|
|
26
|
+
).describe(
|
|
27
|
+
"minimum severity to report (default: the run's configured threshold, else low).",
|
|
28
|
+
),
|
|
29
|
+
"group_by?": type("'file' | 'rule'").describe(
|
|
30
|
+
"'file' (default) makes one group per file; 'rule' groups a single rule across all files into one group.",
|
|
31
|
+
),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export function ReadFindingsTool(ctx: LocalToolContext) {
|
|
35
|
+
return tool({
|
|
36
|
+
name: "read_findings",
|
|
37
|
+
description:
|
|
38
|
+
"Load best-practice concerns from a terraform-reviewer (Assessor) findings.json INSTEAD of running " +
|
|
39
|
+
"the scanners. Returns the SAME { concerns, groups, summary } shape as terraform_scan, so Remediate " +
|
|
40
|
+
"consumes it identically. `human_only` findings and non-Terraform files are dropped. Concerns from " +
|
|
41
|
+
"checkov / tflint / terraform-fmt re-verify deterministically (✗→✓); findings exclusive to the reviewer " +
|
|
42
|
+
`(tfsec / infracost / llm) carry source \`reviewer\` and can't be reproduced by ${PRODUCT_NAME}'s scanners, so ` +
|
|
43
|
+
"terraform_verify_remediation will report them unresolved — rely on terraform_validate + your explanation " +
|
|
44
|
+
"for those. Returns `found: false` (never an error) when no findings.json is present.",
|
|
45
|
+
parameters: ReadFindingsParams,
|
|
46
|
+
execute: execute(async ({ path, severity_threshold, group_by }) => {
|
|
47
|
+
const cwd = ctx.payload.cwd ?? process.cwd();
|
|
48
|
+
// SECURITY: confine the agent-supplied `path` to the workspace so it can't
|
|
49
|
+
// be used as an arbitrary file-read primitive. The env-var fallback is
|
|
50
|
+
// operator-controlled (not agent-controlled), so it stays unconfined.
|
|
51
|
+
const findingsPath = path
|
|
52
|
+
? resolveWithinCwd(cwd, path)
|
|
53
|
+
: process.env.INFRAWEAVER_FINDINGS_PATH || join(cwd, "findings.json");
|
|
54
|
+
let raw: string;
|
|
55
|
+
try {
|
|
56
|
+
raw = readFileSync(findingsPath, "utf8");
|
|
57
|
+
} catch {
|
|
58
|
+
return skipResult(
|
|
59
|
+
"findings_not_found",
|
|
60
|
+
`no findings.json at ${findingsPath} (set the path arg or $INFRAWEAVER_FINDINGS_PATH)`,
|
|
61
|
+
{
|
|
62
|
+
key: "found",
|
|
63
|
+
reasonKey: "reason",
|
|
64
|
+
extra: { concerns: [], groups: [] },
|
|
65
|
+
},
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
let parsed: Concern[];
|
|
69
|
+
try {
|
|
70
|
+
// accept BOTH a terraform-reviewer findings.json AND a standard SARIF
|
|
71
|
+
// report (Trivy/Checkov/tflint -o sarif) — the dispatcher detects which.
|
|
72
|
+
parsed = parseFindingsFile(raw, cwd);
|
|
73
|
+
} catch {
|
|
74
|
+
return skipResult(
|
|
75
|
+
"findings_parse_error",
|
|
76
|
+
`could not parse findings file at ${findingsPath}`,
|
|
77
|
+
{
|
|
78
|
+
key: "found",
|
|
79
|
+
reasonKey: "reason",
|
|
80
|
+
extra: { concerns: [], groups: [] },
|
|
81
|
+
},
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const configured = ctx.payload.severityThreshold as Severity | undefined;
|
|
86
|
+
const threshold: Severity = severity_threshold ?? configured ?? "low";
|
|
87
|
+
const minRank = SEVERITY_RANK[threshold];
|
|
88
|
+
|
|
89
|
+
// same concerns→result pipeline as terraform_scan (baseline, filter,
|
|
90
|
+
// suppress, group, batch, tally), so the rest of the Remediate checklist is
|
|
91
|
+
// source-agnostic. No diff-scope filter — a findings.json is already scoped.
|
|
92
|
+
const grouping = group_by ?? ctx.payload.grouping ?? "file";
|
|
93
|
+
const autonomyThreshold =
|
|
94
|
+
(ctx.payload.autonomyThreshold as Severity | undefined) ?? "high";
|
|
95
|
+
const {
|
|
96
|
+
active,
|
|
97
|
+
suppressed,
|
|
98
|
+
groups,
|
|
99
|
+
batchPlan,
|
|
100
|
+
bySeverity: by_severity,
|
|
101
|
+
} = buildConcernResult(ctx, parsed, {
|
|
102
|
+
cwd,
|
|
103
|
+
minRank,
|
|
104
|
+
grouping,
|
|
105
|
+
autonomyThreshold,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
log.info(
|
|
109
|
+
`» read_findings: ${active.length} concern(s) ≥ ${threshold} from ${findingsPath}` +
|
|
110
|
+
(suppressed.length ? ` (${suppressed.length} suppressed)` : "") +
|
|
111
|
+
` (${groups.length} ${grouping}-group(s))`,
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
return toolOk({
|
|
115
|
+
found: true,
|
|
116
|
+
source_file: findingsPath,
|
|
117
|
+
grouping,
|
|
118
|
+
summary: {
|
|
119
|
+
total: active.length,
|
|
120
|
+
suppressed: suppressed.length,
|
|
121
|
+
groups: groups.length,
|
|
122
|
+
by_severity,
|
|
123
|
+
},
|
|
124
|
+
groups: groups.map((g) => ({
|
|
125
|
+
...g,
|
|
126
|
+
doc_urls: docUrlsForGroup(g, active),
|
|
127
|
+
})),
|
|
128
|
+
batch_plan: batchPlan,
|
|
129
|
+
concerns: active.map((c) => ({ ...c, doc_url: ruleDocUrl(c) })),
|
|
130
|
+
// LLM01. These concerns were parsed out of a file in the workspace —
|
|
131
|
+
// a SARIF or findings.json the repo supplied — so every `evidence`
|
|
132
|
+
// string arrives from outside with no provenance at all. Same notice as
|
|
133
|
+
// the other concern-producing tools; see `mcp/untrustedContent.ts`.
|
|
134
|
+
untrusted_data: UNTRUSTED_DATA_NOTICE,
|
|
135
|
+
});
|
|
136
|
+
}),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { type } from "arktype";
|
|
4
|
+
import type { LocalToolContext } from "#app/mcp/localContext";
|
|
5
|
+
import { walkTfFiles } from "#app/mcp/modules";
|
|
6
|
+
import { execute, tool, toolOk } from "#app/mcp/shared";
|
|
7
|
+
import { buildConcernResult } from "#app/mcp/terraform/concernResult";
|
|
8
|
+
import {
|
|
9
|
+
classifyRefusal,
|
|
10
|
+
clusterByLocation,
|
|
11
|
+
docUrlsForGroup,
|
|
12
|
+
type PreventiveControl,
|
|
13
|
+
preventiveControlFor,
|
|
14
|
+
ruleDocUrl,
|
|
15
|
+
} from "#app/mcp/terraform/decisions";
|
|
16
|
+
import {
|
|
17
|
+
EMPTY_NOISE_PROFILE,
|
|
18
|
+
explainNoiseAdjustment,
|
|
19
|
+
} from "#app/mcp/terraform/noiseProfile";
|
|
20
|
+
import { scoreConcern, topRisks } from "#app/mcp/terraform/risk";
|
|
21
|
+
import { runScannersCached } from "#app/mcp/terraform/scannerCache";
|
|
22
|
+
import { changedTerraformFiles } from "#app/mcp/terraform/scanners";
|
|
23
|
+
import { scanSessionOf } from "#app/mcp/terraform/scanSession";
|
|
24
|
+
import { auditNativeSkips } from "#app/mcp/terraform/suppressions";
|
|
25
|
+
import {
|
|
26
|
+
type Concern,
|
|
27
|
+
SEVERITY_RANK,
|
|
28
|
+
type Severity,
|
|
29
|
+
} from "#app/mcp/terraform/types";
|
|
30
|
+
import { UNTRUSTED_DATA_NOTICE } from "#app/mcp/untrustedContent";
|
|
31
|
+
import { log } from "#app/utils/cli";
|
|
32
|
+
import { resolveModuleCredentialEnv } from "#app/utils/registryAuth";
|
|
33
|
+
import { resolveToolSelection } from "#app/utils/toolSelection";
|
|
34
|
+
|
|
35
|
+
export const TerraformScanParams = type({
|
|
36
|
+
"scan_scope?": type("'full' | 'diff'").describe(
|
|
37
|
+
"'full' (default) scans the whole workspace; 'diff' limits concerns to Terraform files changed vs the base branch.",
|
|
38
|
+
),
|
|
39
|
+
"severity_threshold?": type(
|
|
40
|
+
"'critical' | 'high' | 'medium' | 'low' | 'info'",
|
|
41
|
+
).describe(
|
|
42
|
+
"minimum severity to report (default: low). 'info' includes everything.",
|
|
43
|
+
),
|
|
44
|
+
"group_by?": type("'file' | 'rule'").describe(
|
|
45
|
+
"'file' (default) makes one group per file (smaller blast radius per PR). 'rule' groups a single rule's concerns across ALL files into one group — use for sweeping, low-risk rules (e.g. 'add tags everywhere') so they become one PR instead of many.",
|
|
46
|
+
),
|
|
47
|
+
"download_external_modules?": type("boolean").describe(
|
|
48
|
+
"default false. When true, checkov resolves and scans INSIDE registry/git modules — REQUIRED for the refactor b.4 path (adopting a third-party module): scanning with it OFF would stop looking inside the adopted module and silently drop its findings (a false ✗→✓ / 'finding-laundering'). Leave off for normal Terraform-only scans (faster, offline).",
|
|
49
|
+
),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
export interface ScanScanners {
|
|
53
|
+
runScannersCached: typeof runScannersCached;
|
|
54
|
+
changedTerraformFiles: typeof changedTerraformFiles;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const realScanners: ScanScanners = { runScannersCached, changedTerraformFiles };
|
|
58
|
+
|
|
59
|
+
export async function runScan(
|
|
60
|
+
ctx: LocalToolContext,
|
|
61
|
+
{
|
|
62
|
+
scan_scope,
|
|
63
|
+
severity_threshold,
|
|
64
|
+
group_by,
|
|
65
|
+
download_external_modules,
|
|
66
|
+
}: typeof TerraformScanParams.infer,
|
|
67
|
+
scanners: ScanScanners = realScanners,
|
|
68
|
+
) {
|
|
69
|
+
const cwd = ctx.payload.cwd ?? process.cwd();
|
|
70
|
+
// precedence: explicit tool arg > the run's configured severity_threshold > "low"
|
|
71
|
+
const configured = ctx.payload.severityThreshold as Severity | undefined;
|
|
72
|
+
const threshold: Severity = severity_threshold ?? configured ?? "low";
|
|
73
|
+
const minRank = SEVERITY_RANK[threshold];
|
|
74
|
+
const scope = scan_scope ?? ctx.payload.scanScope ?? "full";
|
|
75
|
+
|
|
76
|
+
// the unified tool selection (licence gate + allow/deny) and the optional
|
|
77
|
+
// module credentials (git-transport + private-registry token), both derived
|
|
78
|
+
// from the run payload so the scan and its ✗→✓ verification re-scan see the
|
|
79
|
+
// identical toolchain.
|
|
80
|
+
const selection = resolveToolSelection(ctx.payload);
|
|
81
|
+
const terraformEnv = resolveModuleCredentialEnv(ctx.payload, {
|
|
82
|
+
sshKeyDir: ctx.tmpdir,
|
|
83
|
+
});
|
|
84
|
+
if (selection.unknownTokens.length > 0) {
|
|
85
|
+
log.warning(
|
|
86
|
+
`» tools_enabled: ignoring unrecognised tool(s) [${selection.unknownTokens.join(", ")}]`,
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// read-only scan path: cache by Terraform-tree content hash so a repeated
|
|
91
|
+
// scan on an UNCHANGED tree is instant. Self-invalidating (any edit busts the
|
|
92
|
+
// hash). The ✗→✓ verifier below uses runScanners DIRECTLY — never the cache —
|
|
93
|
+
// so verification always re-scans fresh.
|
|
94
|
+
const outcomes = scanners.runScannersCached(cwd, {
|
|
95
|
+
selection,
|
|
96
|
+
terraformEnv,
|
|
97
|
+
downloadExternalModules: download_external_modules,
|
|
98
|
+
toolsNetwork: ctx.payload.toolsNetwork,
|
|
99
|
+
});
|
|
100
|
+
if (ctx.payload.toolsNetwork?.unknown.length) {
|
|
101
|
+
log.warning(
|
|
102
|
+
`» tools_network: ignoring unrecognised token(s) [${ctx.payload.toolsNetwork.unknown.join(", ")}]`,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// diff scope: keep only concerns in Terraform files changed vs the base.
|
|
107
|
+
let scopeNote: string | undefined;
|
|
108
|
+
let changed: Set<string> | null = null;
|
|
109
|
+
if (scope === "diff") {
|
|
110
|
+
changed = scanners.changedTerraformFiles(cwd);
|
|
111
|
+
if (changed === null) {
|
|
112
|
+
scopeNote =
|
|
113
|
+
"diff scope requested but the base branch could not be determined — scanned full instead";
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const inScope = (c: Concern): boolean =>
|
|
117
|
+
changed === null
|
|
118
|
+
? true
|
|
119
|
+
: changed.has(c.location.file.replace(/\\/g, "/").replace(/^\.\//, ""));
|
|
120
|
+
|
|
121
|
+
// grouping mode: by-file (default, smaller per-PR blast radius) or
|
|
122
|
+
// by-rule (one PR per rule across all files — for sweeping low-risk rules).
|
|
123
|
+
const grouping = group_by ?? ctx.payload.grouping ?? "file";
|
|
124
|
+
const autonomyThreshold =
|
|
125
|
+
(ctx.payload.autonomyThreshold as Severity | undefined) ?? "high";
|
|
126
|
+
// shared concerns→result pipeline (baseline capture, filter, suppress, group,
|
|
127
|
+
// batch, tally) — also backs read_findings so both stay source-agnostic.
|
|
128
|
+
const result = buildConcernResult(
|
|
129
|
+
ctx,
|
|
130
|
+
outcomes.flatMap((o) => o.concerns),
|
|
131
|
+
{
|
|
132
|
+
cwd,
|
|
133
|
+
minRank,
|
|
134
|
+
grouping,
|
|
135
|
+
autonomyThreshold,
|
|
136
|
+
inScope,
|
|
137
|
+
},
|
|
138
|
+
);
|
|
139
|
+
const {
|
|
140
|
+
active,
|
|
141
|
+
suppressed,
|
|
142
|
+
groups,
|
|
143
|
+
batchPlan,
|
|
144
|
+
bySeverity: by_severity,
|
|
145
|
+
} = result;
|
|
146
|
+
// the reported (post-filter) set — read at end-of-run by finalizeSuccessRun
|
|
147
|
+
// to emit the SARIF artifact + findings outputs.
|
|
148
|
+
scanSessionOf(ctx.toolState).lastScanConcerns = result.annotated;
|
|
149
|
+
// G7: the org's fleet-wide dismissal record, seeded at run start. Affects the
|
|
150
|
+
// ORDER of `top_risks` / `risk_score` only — every concern above is already
|
|
151
|
+
// final by this point, and nothing here can remove one.
|
|
152
|
+
const noiseProfile =
|
|
153
|
+
scanSessionOf(ctx.toolState).noiseProfile ?? EMPTY_NOISE_PROFILE;
|
|
154
|
+
|
|
155
|
+
// Native scanner-skip directives (#checkov:skip / #tfsec:ignore / #trivy:ignore)
|
|
156
|
+
// are honoured by their OWN scanner — so the finding never reaches Infraweaver's
|
|
157
|
+
// gate or posture. Surface the ORPHANS (a skip with no corresponding concern)
|
|
158
|
+
// so a directive that silently hides a real issue stays auditable. Matched
|
|
159
|
+
// against the raw scan set (pre-threshold) so a below-threshold concern that
|
|
160
|
+
// DID fire isn't reported as a false orphan.
|
|
161
|
+
const nativeSkipAudit = auditNativeSkips(
|
|
162
|
+
walkTfFiles(cwd),
|
|
163
|
+
outcomes.flatMap((o) => o.concerns),
|
|
164
|
+
(rel) => {
|
|
165
|
+
try {
|
|
166
|
+
return readFileSync(join(cwd, rel), "utf-8");
|
|
167
|
+
} catch {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
// concerns different scanners flagged at the same file:line (one
|
|
174
|
+
// canonical fix); concerns whose fix needs a human decision (prefer
|
|
175
|
+
// a structured refusal); the preventive control per distinct rule.
|
|
176
|
+
const coLocated = clusterByLocation(active);
|
|
177
|
+
const refusalCandidates = active
|
|
178
|
+
.map((c) => ({ id: c.id, ...classifyRefusal(c) }))
|
|
179
|
+
.filter((r) => r.refuse)
|
|
180
|
+
.map((r) => ({ concern_id: r.id, reason: r.reason }));
|
|
181
|
+
const prevention: Record<string, PreventiveControl> = {};
|
|
182
|
+
for (const c of active) {
|
|
183
|
+
if (prevention[c.rule_id]) continue;
|
|
184
|
+
const control = preventiveControlFor(c);
|
|
185
|
+
if (control) prevention[c.rule_id] = control;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const ran = outcomes.filter((o) => o.ran).map((o) => o.source);
|
|
189
|
+
const skippedScanners = outcomes
|
|
190
|
+
.filter((o) => !o.ran)
|
|
191
|
+
.map((o) => ({ source: o.source, reason: o.skipped_reason }));
|
|
192
|
+
const partialScanners = outcomes.flatMap((o) =>
|
|
193
|
+
o.partial ? [o.partial] : [],
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
log.info(
|
|
197
|
+
`» terraform_scan: ${active.length} concern(s) ≥ ${threshold} from [${ran.join(", ")}] ` +
|
|
198
|
+
`(${groups.length} ${grouping}-group(s))` +
|
|
199
|
+
(suppressed.length ? ` (${suppressed.length} suppressed)` : "") +
|
|
200
|
+
(skippedScanners.length
|
|
201
|
+
? ` (skipped: ${skippedScanners.map((s) => s.source).join(", ")})`
|
|
202
|
+
: ""),
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
return toolOk({
|
|
206
|
+
scanned_dir: cwd,
|
|
207
|
+
scope: changed === null ? "full" : "diff",
|
|
208
|
+
...(scopeNote ? { scope_note: scopeNote } : {}),
|
|
209
|
+
grouping,
|
|
210
|
+
scanners_ran: ran,
|
|
211
|
+
scanners_skipped: skippedScanners,
|
|
212
|
+
// A scanner can RUN and still be partially blind (e.g. the native pack's
|
|
213
|
+
// persisted-secret rule without a provider schema). Listing that here keeps
|
|
214
|
+
// `scanners_ran` from implying full coverage; omitted entirely when empty so
|
|
215
|
+
// the common result shape is unchanged.
|
|
216
|
+
...(partialScanners.length ? { scanners_partial: partialScanners } : {}),
|
|
217
|
+
// licence-aware tool posture: which non-permissive tools are off
|
|
218
|
+
// for want of an explicit opt-in, and which were explicitly disabled.
|
|
219
|
+
tool_selection: {
|
|
220
|
+
licence_gated: selection.gated,
|
|
221
|
+
disabled: selection.disabled,
|
|
222
|
+
},
|
|
223
|
+
summary: {
|
|
224
|
+
total: active.length,
|
|
225
|
+
suppressed: suppressed.length,
|
|
226
|
+
groups: groups.length,
|
|
227
|
+
by_severity,
|
|
228
|
+
},
|
|
229
|
+
groups: groups.map((g) => ({
|
|
230
|
+
...g,
|
|
231
|
+
doc_urls: docUrlsForGroup(g, active),
|
|
232
|
+
})),
|
|
233
|
+
batch_plan: batchPlan,
|
|
234
|
+
// cross-tool co-location, refusal candidates, prevention.
|
|
235
|
+
co_located: coLocated,
|
|
236
|
+
refusal_candidates: refusalCandidates,
|
|
237
|
+
prevention,
|
|
238
|
+
top_risks: topRisks(active, 5, noiseProfile),
|
|
239
|
+
concerns: active.map((c) => {
|
|
240
|
+
const risk = scoreConcern(c, noiseProfile);
|
|
241
|
+
return {
|
|
242
|
+
...c,
|
|
243
|
+
doc_url: ruleDocUrl(c),
|
|
244
|
+
risk_score: risk.score,
|
|
245
|
+
// G7: never demote silently — the reason travels with the finding.
|
|
246
|
+
...(risk.noise
|
|
247
|
+
? { noise_reason: explainNoiseAdjustment(risk.noise) }
|
|
248
|
+
: {}),
|
|
249
|
+
};
|
|
250
|
+
}),
|
|
251
|
+
...(nativeSkipAudit.orphans.length
|
|
252
|
+
? {
|
|
253
|
+
orphan_native_skips: nativeSkipAudit.orphans.map((s) => ({
|
|
254
|
+
file: s.file,
|
|
255
|
+
line: s.line,
|
|
256
|
+
tool: s.tool,
|
|
257
|
+
rule: s.rule,
|
|
258
|
+
reason: s.reason,
|
|
259
|
+
...(s.expires ? { expires: s.expires } : {}),
|
|
260
|
+
})),
|
|
261
|
+
}
|
|
262
|
+
: {}),
|
|
263
|
+
...(suppressed.length
|
|
264
|
+
? {
|
|
265
|
+
suppressed: suppressed.map((c) => ({
|
|
266
|
+
id: c.id,
|
|
267
|
+
rule_id: c.rule_id,
|
|
268
|
+
severity: c.severity,
|
|
269
|
+
location: c.location,
|
|
270
|
+
suppression: c.suppression,
|
|
271
|
+
})),
|
|
272
|
+
}
|
|
273
|
+
: {}),
|
|
274
|
+
// LLM01. `evidence`, `remediation_hint` and `code_snippet` are written by
|
|
275
|
+
// third-party scanners over source authored by the party under examination,
|
|
276
|
+
// and `orphan_native_skips[].reason` / `suppression.reason` come straight
|
|
277
|
+
// out of a comment in that source (`# checkov:skip=CKV_X: <anything>`). This
|
|
278
|
+
// result is structurally identical to `ingest_external_findings`, which has
|
|
279
|
+
// carried the notice since it shipped — the asymmetry was the defect, not
|
|
280
|
+
// the presence of the field.
|
|
281
|
+
untrusted_data: UNTRUSTED_DATA_NOTICE,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export function TerraformScanTool(ctx: LocalToolContext) {
|
|
286
|
+
return tool({
|
|
287
|
+
name: "terraform_scan",
|
|
288
|
+
description:
|
|
289
|
+
"Scan the Terraform in the workspace against best practices using the deterministic check tools " +
|
|
290
|
+
"(terraform fmt, terraform validate, tflint, trivy, checkov). Returns a stable, severity-ranked " +
|
|
291
|
+
"list of `concerns` — each is one best-practice issue with a content-derived `id`, the producing " +
|
|
292
|
+
"`source`, `rule_id`, `severity`, the `location` (file + line), and a `remediation_hint`. Concerns " +
|
|
293
|
+
"are also rolled up into `groups` (one per file): different scanners flag the same defect under " +
|
|
294
|
+
"different rule ids, so remediate ONE group per PR (its `id` is the branch/PR key; its `concern_ids` " +
|
|
295
|
+
"are what the ✗→✓ re-scan must confirm cleared) rather than one PR per concern. Scanners that aren't " +
|
|
296
|
+
"installed are reported as skipped (they never fail the scan). Also returns `co_located` (concerns " +
|
|
297
|
+
"different scanners flagged at the same file:line — fix as ONE canonical change), " +
|
|
298
|
+
"`refusal_candidates` (concerns whose fix needs a human decision — prefer a structured refusal over " +
|
|
299
|
+
"guessing), and `prevention` (a CI guardrail per rule that stops it recurring).",
|
|
300
|
+
parameters: TerraformScanParams,
|
|
301
|
+
execute: execute(async (input) => runScan(ctx, input)),
|
|
302
|
+
});
|
|
303
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { type } from "arktype";
|
|
2
|
+
import type { LocalToolContext } from "#app/mcp/localContext";
|
|
3
|
+
import { execute, tool, toolOk } from "#app/mcp/shared";
|
|
4
|
+
import { resolveRoots } from "#app/mcp/terraform/paths";
|
|
5
|
+
import { scanSessionOf } from "#app/mcp/terraform/scanSession";
|
|
6
|
+
import {
|
|
7
|
+
checkArgumentsAgainstSchema,
|
|
8
|
+
collectProviderRequirements,
|
|
9
|
+
scanFmt,
|
|
10
|
+
scanTflint,
|
|
11
|
+
scanValidate,
|
|
12
|
+
} from "#app/mcp/terraform/scanners";
|
|
13
|
+
import { dedupe, skipped, sortConcerns } from "#app/mcp/terraform/types";
|
|
14
|
+
import { UNTRUSTED_DATA_NOTICE } from "#app/mcp/untrustedContent";
|
|
15
|
+
import { resolveModuleCredentialEnv } from "#app/utils/registryAuth";
|
|
16
|
+
import { resolveToolSelection } from "#app/utils/toolSelection";
|
|
17
|
+
|
|
18
|
+
export const TerraformValidateParams = type({
|
|
19
|
+
"paths?": type.string
|
|
20
|
+
.array()
|
|
21
|
+
.describe(
|
|
22
|
+
"optional list of file globs/paths to limit fmt+lint to; omit to check the whole workspace",
|
|
23
|
+
),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export interface ValidateScanners {
|
|
27
|
+
scanFmt: typeof scanFmt;
|
|
28
|
+
scanValidate: typeof scanValidate;
|
|
29
|
+
scanTflint: typeof scanTflint;
|
|
30
|
+
collectProviderRequirements: typeof collectProviderRequirements;
|
|
31
|
+
checkArgumentsAgainstSchema: typeof checkArgumentsAgainstSchema;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const realScanners: ValidateScanners = {
|
|
35
|
+
scanFmt,
|
|
36
|
+
scanValidate,
|
|
37
|
+
scanTflint,
|
|
38
|
+
collectProviderRequirements,
|
|
39
|
+
checkArgumentsAgainstSchema,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export async function runValidate(
|
|
43
|
+
ctx: LocalToolContext,
|
|
44
|
+
scanners: ValidateScanners = realScanners,
|
|
45
|
+
) {
|
|
46
|
+
const cwd = ctx.payload.cwd ?? process.cwd();
|
|
47
|
+
// honour the same licence gate + module-fetch credential as
|
|
48
|
+
// terraform_scan: tflint (MPL-2.0) runs only when opted in; validate's init
|
|
49
|
+
// gets the credential so a private cross-repo module resolves.
|
|
50
|
+
const selection = resolveToolSelection(ctx.payload);
|
|
51
|
+
const terraformEnv = resolveModuleCredentialEnv(ctx.payload, {
|
|
52
|
+
sshKeyDir: ctx.tmpdir,
|
|
53
|
+
});
|
|
54
|
+
// `terraform validate` runs per-root (multi-root aware); fmt + tflint are
|
|
55
|
+
// recursive over the whole tree.
|
|
56
|
+
const fmtOutcome = scanners.scanFmt(cwd);
|
|
57
|
+
const validateOutcome = scanners.scanValidate(cwd, terraformEnv);
|
|
58
|
+
const tflintOutcome = selection.enabled("tflint")
|
|
59
|
+
? scanners.scanTflint(cwd)
|
|
60
|
+
: skipped(
|
|
61
|
+
"tflint",
|
|
62
|
+
selection.offReason("tflint") ?? "disabled by tools_enabled",
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// PRE-EXISTING `terraform fmt` drift (captured by the pre-fix scan, before
|
|
66
|
+
// any edit) is not this run's to fix: forcing a whole-file reformat to
|
|
67
|
+
// clear style drift the file already had is exactly what bloats a scoped
|
|
68
|
+
// remediation diff. Such drift is surfaced as advisory `preexisting_fmt_drift`
|
|
69
|
+
// and kept out of the `passed` gate; only NEW drift (a file the agent's
|
|
70
|
+
// edit left unformatted) gates. With no baseline captured (validate called
|
|
71
|
+
// before any scan), fall back to gating on all drift — pre-change behaviour.
|
|
72
|
+
const baselineDrift = scanSessionOf(ctx.toolState).baselineFmtDriftFiles;
|
|
73
|
+
const isPreexisting = (c: (typeof fmtOutcome.concerns)[number]) =>
|
|
74
|
+
baselineDrift?.includes(c.location.file) ?? false;
|
|
75
|
+
const gatingFmtConcerns = fmtOutcome.concerns.filter((c) => !isPreexisting(c));
|
|
76
|
+
const preexistingFmtDrift = [
|
|
77
|
+
...new Set(
|
|
78
|
+
fmtOutcome.concerns.filter(isPreexisting).map((c) => c.location.file),
|
|
79
|
+
),
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
const remaining = sortConcerns(
|
|
83
|
+
dedupe([
|
|
84
|
+
...gatingFmtConcerns,
|
|
85
|
+
...validateOutcome.concerns,
|
|
86
|
+
...tflintOutcome.concerns,
|
|
87
|
+
]),
|
|
88
|
+
);
|
|
89
|
+
const ran = [fmtOutcome, validateOutcome, tflintOutcome]
|
|
90
|
+
.filter((c) => c.ran)
|
|
91
|
+
.map((c) => c.source);
|
|
92
|
+
// count of roots where terraform ran but `validate -json` couldn't be
|
|
93
|
+
// parsed — a real failure, not a clean tree. We genuinely don't know if
|
|
94
|
+
// those roots are valid, so `passed` must fail closed below rather than
|
|
95
|
+
// silently treating an un-validated root as passing.
|
|
96
|
+
const unvalidatedRoots = validateOutcome.unvalidated ?? 0;
|
|
97
|
+
// surface the pinned provider majors so the fix targets the right
|
|
98
|
+
// argument schema (deterministic, read straight from required_providers).
|
|
99
|
+
const providers = scanners.collectProviderRequirements(cwd);
|
|
100
|
+
const roots = resolveRoots(cwd).map((r) => r.relDir || ".");
|
|
101
|
+
// cross-check the arguments actually written in the workspace
|
|
102
|
+
// against the INSTALLED provider's schema, so an argument that's invalid
|
|
103
|
+
// for the pinned provider major (a "correct" fix for the wrong version) is
|
|
104
|
+
// caught here, before the PR, instead of surfacing as a `plan` failure.
|
|
105
|
+
// Deterministic and degrades green (omitted) when the schema isn't
|
|
106
|
+
// available (terraform not installed / dir not init-ed).
|
|
107
|
+
const schemaCheck = scanners.checkArgumentsAgainstSchema(cwd);
|
|
108
|
+
return toolOk({
|
|
109
|
+
// `passed` stays gated on fmt + validate + tflint only — those are
|
|
110
|
+
// authoritative (fmt counts only NEW drift; see preexisting_fmt_drift).
|
|
111
|
+
// The schema cross-check is a high-signal ADVISORY (a conservative HCL
|
|
112
|
+
// parse), surfaced separately so a parser edge case can never wrongly
|
|
113
|
+
// block a valid fix. Fails closed when a root ran but couldn't be
|
|
114
|
+
// validated: an un-validated root is "unknown", not "clean".
|
|
115
|
+
passed: remaining.length === 0 && unvalidatedRoots === 0,
|
|
116
|
+
checks_ran: ran,
|
|
117
|
+
// true when ≥1 Terraform root could not be validated (terraform ran but
|
|
118
|
+
// its `-json` output was unparseable). When set, `passed` is false even
|
|
119
|
+
// with no remaining_issues — re-run after fixing the root's init/state,
|
|
120
|
+
// or inspect it by hand; do NOT treat the clean issue list as a pass.
|
|
121
|
+
validate_incomplete: unvalidatedRoots > 0,
|
|
122
|
+
remaining_issues: remaining,
|
|
123
|
+
// ADVISORY (does not gate `passed`): files that already failed
|
|
124
|
+
// `terraform fmt` at the pre-fix baseline. Reformatting them would pull
|
|
125
|
+
// unrelated lines into a scoped fix — leave them, or sweep repo-wide
|
|
126
|
+
// formatting in a separate `fix rule terraform-fmt` PR.
|
|
127
|
+
preexisting_fmt_drift: preexistingFmtDrift,
|
|
128
|
+
providers,
|
|
129
|
+
// arguments written in the workspace that are NOT in the
|
|
130
|
+
// installed provider's schema (would break `plan` on the pinned major).
|
|
131
|
+
// `schema_checked` is false when the schema was unavailable (terraform
|
|
132
|
+
// not installed / dir not init-ed) — then `unknown_arguments` is empty
|
|
133
|
+
// and you should rely on `terraform_plan` to catch a bad argument.
|
|
134
|
+
schema_checked: schemaCheck.checked,
|
|
135
|
+
unknown_arguments: schemaCheck.unknown_arguments,
|
|
136
|
+
// the Terraform roots `validate` covered (each was init+validate'd).
|
|
137
|
+
roots_validated: roots,
|
|
138
|
+
// LLM01. `remaining_issues[].evidence` is a `terraform validate` diagnostic
|
|
139
|
+
// or a tflint message, and both quote the workspace's own HCL back — an
|
|
140
|
+
// identifier, a string literal, a heredoc. Same channel as the other
|
|
141
|
+
// concern-producing tools; see `mcp/untrustedContent.ts`.
|
|
142
|
+
untrusted_data: UNTRUSTED_DATA_NOTICE,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function TerraformValidateTool(ctx: LocalToolContext) {
|
|
147
|
+
return tool({
|
|
148
|
+
name: "terraform_validate",
|
|
149
|
+
description:
|
|
150
|
+
"Fast pre-PR gate. Runs `terraform fmt -check`, `terraform validate` (per Terraform root — " +
|
|
151
|
+
"multi-root aware, see `roots_validated`), and `tflint` over the " +
|
|
152
|
+
"workspace and returns whether the Terraform is well-formed and idiomatic. Also reports `providers` " +
|
|
153
|
+
"— the pinned provider requirements (name + source + version constraint + resolved `major`): " +
|
|
154
|
+
"honour the pinned major when writing a fix, because argument names and valid blocks differ across " +
|
|
155
|
+
"provider majors, and a 'correct' fix for the wrong major just breaks `plan`. Call this AFTER " +
|
|
156
|
+
"applying a fix and BEFORE opening a PR — never open a PR whose `terraform_validate` did not pass.",
|
|
157
|
+
parameters: TerraformValidateParams,
|
|
158
|
+
execute: execute(async () => runValidate(ctx)),
|
|
159
|
+
});
|
|
160
|
+
}
|