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,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Evidence-backed module documentation (`terraform_module_docs`) — the docs
|
|
3
|
+
* half of the Refactor flow. When a refactor lifts resources behind a module
|
|
4
|
+
* boundary, the same PR writes/refreshes the module's README with EVERY claim
|
|
5
|
+
* grounded in a tool result:
|
|
6
|
+
*
|
|
7
|
+
* - the interface table is parsed from the module's real `variable`/`output`
|
|
8
|
+
* blocks ([[modules]]); HCL `description`s are quoted verbatim or left
|
|
9
|
+
* empty — never invented;
|
|
10
|
+
* - the refactor-provenance section (when supplied) lists the moved
|
|
11
|
+
* addresses and words the verdict exactly as the evidence layer does
|
|
12
|
+
* (`equivalence-proven` / `equivalence-failed` / `proposed-unproven`) —
|
|
13
|
+
* never "behaviour preserved" without a passing equivalence result;
|
|
14
|
+
* - the metadata footer carries the generator, tool version and repo
|
|
15
|
+
* `gitHead`, plus a commented placeholder for a future Infragram-rendered
|
|
16
|
+
* diagram link (the cross-sell seam — no built-in diagram).
|
|
17
|
+
*
|
|
18
|
+
* Deterministic: identical inputs ⇒ byte-identical output (the builder is
|
|
19
|
+
* pure; clock-free). Incremental: when the footer's `git-head` is still the
|
|
20
|
+
* ancestor of HEAD with no change under the module dir (the README itself
|
|
21
|
+
* excluded — the commit that landed it always postdates its recorded head),
|
|
22
|
+
* the tool skips.
|
|
23
|
+
*
|
|
24
|
+
* Writes are additionally fenced at push time by DOCS_ALLOWED_PATHS in
|
|
25
|
+
* guardrails.ts — only `modules/x/README.md` / `docs/infraweaver/**` are
|
|
26
|
+
* pushable, and only when the `docs` input is enabled.
|
|
27
|
+
*/
|
|
28
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
29
|
+
import { join } from "node:path";
|
|
30
|
+
import { type } from "arktype";
|
|
31
|
+
import { PRODUCT_NAME } from "#app/brand";
|
|
32
|
+
import type { LocalToolContext } from "#app/mcp/localContext";
|
|
33
|
+
import { collectModuleInterface, type ModuleInterface } from "#app/mcp/modules";
|
|
34
|
+
import { resolveWithinCwd } from "#app/mcp/pathSafety";
|
|
35
|
+
import { execute, tool, toolOk, toolSkip } from "#app/mcp/shared";
|
|
36
|
+
import { scanSessionOf } from "#app/mcp/terraform/scanSession";
|
|
37
|
+
import { log } from "#app/utils/cli";
|
|
38
|
+
import { $ } from "#app/utils/shell";
|
|
39
|
+
import packageJson from "#package.json" with { type: "json" };
|
|
40
|
+
|
|
41
|
+
export type ModuleDocsVerdict =
|
|
42
|
+
| "equivalence-proven"
|
|
43
|
+
| "equivalence-failed"
|
|
44
|
+
| "proposed-unproven";
|
|
45
|
+
|
|
46
|
+
export interface ModuleDocsRefactorInput {
|
|
47
|
+
/** every relocated address, `from → to` — from terraform_generate_moved. */
|
|
48
|
+
moves: { from: string; to: string }[];
|
|
49
|
+
/** worded exactly as the evidence layer's refactor statement. */
|
|
50
|
+
verdict: ModuleDocsVerdict;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface ModuleDocsInput {
|
|
54
|
+
/** repo-relative module dir, e.g. `modules/logging`. */
|
|
55
|
+
moduleDir: string;
|
|
56
|
+
iface: ModuleInterface;
|
|
57
|
+
/** present only for a refactor run (omits the section entirely otherwise). */
|
|
58
|
+
refactor?: ModuleDocsRefactorInput | undefined;
|
|
59
|
+
version?: string;
|
|
60
|
+
/** the repo HEAD the doc was generated at (footer metadata; drives the
|
|
61
|
+
* incremental refresh). null when git is unavailable. */
|
|
62
|
+
gitHead: string | null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** what each verdict may honestly claim — mirrored from the evidence layer's
|
|
66
|
+
* asserts/does-not-assert discipline. */
|
|
67
|
+
const VERDICT_CLAIM: Record<ModuleDocsVerdict, string> = {
|
|
68
|
+
"equivalence-proven":
|
|
69
|
+
"The relocation was **proven behaviour-preserving** by `terraform_equivalence_check`: same resource set, identical arguments, every relocated address covered by a `moved {}` block, validate + fmt clean.",
|
|
70
|
+
"equivalence-failed":
|
|
71
|
+
"The equivalence proof **did NOT pass** — this change must not be treated as behaviour-preserving. See the run's reasons before relying on it.",
|
|
72
|
+
"proposed-unproven":
|
|
73
|
+
"This module adoption is **proposed — unproven**: it alters behaviour and was not verified against a plan. It asserts nothing about runtime behaviour.",
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
function escapeCell(text: string | null): string {
|
|
77
|
+
if (!text) return "";
|
|
78
|
+
return text
|
|
79
|
+
.replaceAll("|", "\\|")
|
|
80
|
+
.replaceAll(/\s*\n\s*/g, " ")
|
|
81
|
+
.trim();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function moduleName(moduleDir: string): string {
|
|
85
|
+
return (
|
|
86
|
+
moduleDir.replace(/\\/g, "/").replace(/\/+$/, "").split("/").pop() ??
|
|
87
|
+
moduleDir
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Build the README from tool outputs only (pure — same inputs, same bytes).
|
|
93
|
+
* No prose is invented: descriptions come verbatim from the HCL or stay empty.
|
|
94
|
+
*/
|
|
95
|
+
export function buildModuleReadme(input: ModuleDocsInput): string {
|
|
96
|
+
const { iface, refactor } = input;
|
|
97
|
+
const name = moduleName(input.moduleDir);
|
|
98
|
+
const lines: string[] = [];
|
|
99
|
+
|
|
100
|
+
lines.push(`# \`${name}\` module`);
|
|
101
|
+
lines.push("");
|
|
102
|
+
lines.push(
|
|
103
|
+
`Evidence-backed documentation generated by ${PRODUCT_NAME} from the module's parsed interface` +
|
|
104
|
+
(refactor ? " and the refactor's recorded proof" : "") +
|
|
105
|
+
". Descriptions are quoted verbatim from the HCL (empty when the HCL has none).",
|
|
106
|
+
);
|
|
107
|
+
lines.push("");
|
|
108
|
+
|
|
109
|
+
lines.push("## Interface");
|
|
110
|
+
lines.push("");
|
|
111
|
+
if (iface.variables.length > 0) {
|
|
112
|
+
lines.push("### Inputs");
|
|
113
|
+
lines.push("");
|
|
114
|
+
lines.push("| Name | Type | Required | Description |");
|
|
115
|
+
lines.push("| ---- | ---- | :------: | ----------- |");
|
|
116
|
+
for (const v of iface.variables) {
|
|
117
|
+
lines.push(
|
|
118
|
+
`| \`${v.name}\` | ${v.type ? `\`${escapeCell(v.type)}\`` : ""} | ${v.required ? "**yes**" : "no"} | ${escapeCell(v.description)} |`,
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
lines.push("");
|
|
122
|
+
}
|
|
123
|
+
if (iface.outputs.length > 0) {
|
|
124
|
+
lines.push("### Outputs");
|
|
125
|
+
lines.push("");
|
|
126
|
+
lines.push("| Name | Description |");
|
|
127
|
+
lines.push("| ---- | ----------- |");
|
|
128
|
+
for (const o of iface.outputs) {
|
|
129
|
+
lines.push(`| \`${o.name}\` | ${escapeCell(o.description)} |`);
|
|
130
|
+
}
|
|
131
|
+
lines.push("");
|
|
132
|
+
}
|
|
133
|
+
if (iface.variables.length === 0 && iface.outputs.length === 0) {
|
|
134
|
+
lines.push("The module declares no `variable` or `output` blocks.");
|
|
135
|
+
lines.push("");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (refactor) {
|
|
139
|
+
lines.push("## Refactor provenance");
|
|
140
|
+
lines.push("");
|
|
141
|
+
lines.push(`Verdict: \`${refactor.verdict}\``);
|
|
142
|
+
lines.push("");
|
|
143
|
+
lines.push(VERDICT_CLAIM[refactor.verdict]);
|
|
144
|
+
lines.push("");
|
|
145
|
+
if (refactor.moves.length > 0) {
|
|
146
|
+
lines.push("Relocated addresses:");
|
|
147
|
+
lines.push("");
|
|
148
|
+
for (const m of refactor.moves) {
|
|
149
|
+
lines.push(`- \`${m.from}\` → \`${m.to}\``);
|
|
150
|
+
}
|
|
151
|
+
lines.push("");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
lines.push("<!--");
|
|
156
|
+
lines.push("generated-by: infraweaver");
|
|
157
|
+
lines.push(`infraweaver-version: ${input.version ?? packageJson.version}`);
|
|
158
|
+
lines.push(`git-head: ${input.gitHead ?? "unknown"}`);
|
|
159
|
+
lines.push(
|
|
160
|
+
"diagram: placeholder — link a Infragram-rendered architecture diagram of this module here",
|
|
161
|
+
);
|
|
162
|
+
lines.push("-->");
|
|
163
|
+
|
|
164
|
+
return `${lines.join("\n")}\n`;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** the `git-head` recorded in an existing generated README's footer, or null
|
|
168
|
+
* (no README / not infraweaver-generated / no head recorded). */
|
|
169
|
+
export function readFooterGitHead(readme: string | null): string | null {
|
|
170
|
+
if (!readme?.includes("generated-by: infraweaver")) return null;
|
|
171
|
+
const m = readme.match(/^git-head: ([0-9a-f]{7,64})$/m);
|
|
172
|
+
return m?.[1] ?? null;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export const TerraformModuleDocsParams = type({
|
|
176
|
+
module_dir: type.string.describe(
|
|
177
|
+
"the module's repo-relative dir (the one the refactor created/adopted, e.g. 'modules/logging').",
|
|
178
|
+
),
|
|
179
|
+
"moves?": type({ from: "string", to: "string" })
|
|
180
|
+
.array()
|
|
181
|
+
.describe(
|
|
182
|
+
"the relocated addresses (from terraform_generate_moved / the equivalence check) — rendered as the provenance list. Omit for a non-refactor regeneration.",
|
|
183
|
+
),
|
|
184
|
+
"proposed_unproven?": type("boolean").describe(
|
|
185
|
+
"set true when documenting a b.4 third-party adoption shipped WITHOUT a plan, so the README records the `proposed-unproven` verdict. Ignored when an equivalence proof was recorded this run.",
|
|
186
|
+
),
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
export function TerraformModuleDocsTool(ctx: LocalToolContext) {
|
|
190
|
+
return tool({
|
|
191
|
+
name: "terraform_module_docs",
|
|
192
|
+
description:
|
|
193
|
+
"Write/refresh an EVIDENCE-BACKED README for a module the refactor created or adopted (call only " +
|
|
194
|
+
"when the `docs` input is enabled). Do not hand-write module docs: this tool builds the README " +
|
|
195
|
+
"exclusively from tool results — an interface table parsed from the module's real " +
|
|
196
|
+
"`variable`/`output` blocks (HCL descriptions verbatim, never invented), the relocated-address " +
|
|
197
|
+
"list you pass in `moves`, and the equivalence verdict recorded this run (worded exactly as the " +
|
|
198
|
+
"evidence layer: equivalence-proven / equivalence-failed / proposed-unproven — never 'behaviour " +
|
|
199
|
+
"preserved' without a passing proof). Deterministic (same inputs ⇒ identical bytes) and " +
|
|
200
|
+
"incremental: when the existing README's footer git-head shows no change under the module dir, it " +
|
|
201
|
+
"skips instead of rewriting. Writes ONLY `<module_dir>/README.md`; pushes are fenced to " +
|
|
202
|
+
"`modules/**/README.md` + `docs/infraweaver/**/*.md` by the docs allow-list carve-out.",
|
|
203
|
+
parameters: TerraformModuleDocsParams,
|
|
204
|
+
// writes a file that lands in the PR diff — a mutating tool for subagent purposes.
|
|
205
|
+
mutates: true,
|
|
206
|
+
execute: execute(async ({ module_dir, moves, proposed_unproven }) => {
|
|
207
|
+
const cwd = ctx.payload.cwd ?? process.cwd();
|
|
208
|
+
if (ctx.payload.docs !== true) {
|
|
209
|
+
return toolSkip(
|
|
210
|
+
"docs_disabled",
|
|
211
|
+
"the `docs` input is not enabled for this run — module README writes are opt-in (set `docs: true` on the action)",
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
// SECURITY: confine the agent-supplied module dir to the workspace.
|
|
215
|
+
const absDir = resolveWithinCwd(cwd, module_dir);
|
|
216
|
+
const target = join(absDir, "README.md");
|
|
217
|
+
|
|
218
|
+
// current repo HEAD for the footer (and the next run's refresh check).
|
|
219
|
+
let gitHead: string | null = null;
|
|
220
|
+
try {
|
|
221
|
+
gitHead = $("git", ["rev-parse", "HEAD"], { cwd, log: false });
|
|
222
|
+
} catch {
|
|
223
|
+
/* no git → footer records "unknown" and refresh always regenerates */
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// incremental refresh: if the committed footer head is still current for
|
|
227
|
+
// this module dir (empty diff), there is nothing to rewrite. The README
|
|
228
|
+
// itself is excluded from the pathspec — its footer records the HEAD from
|
|
229
|
+
// BEFORE it was committed, so the commit that landed it always postdates
|
|
230
|
+
// the recorded head and would otherwise defeat the skip on every run.
|
|
231
|
+
let existing: string | null = null;
|
|
232
|
+
try {
|
|
233
|
+
existing = readFileSync(target, "utf8");
|
|
234
|
+
} catch {
|
|
235
|
+
/* no README yet */
|
|
236
|
+
}
|
|
237
|
+
const priorHead = readFooterGitHead(existing);
|
|
238
|
+
if (priorHead && gitHead) {
|
|
239
|
+
try {
|
|
240
|
+
const dirSpec = module_dir.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
241
|
+
const changed = $(
|
|
242
|
+
"git",
|
|
243
|
+
[
|
|
244
|
+
"diff",
|
|
245
|
+
"--name-only",
|
|
246
|
+
`${priorHead}..HEAD`,
|
|
247
|
+
"--",
|
|
248
|
+
dirSpec,
|
|
249
|
+
`:(exclude)${dirSpec}/README.md`,
|
|
250
|
+
],
|
|
251
|
+
{ cwd, log: false },
|
|
252
|
+
);
|
|
253
|
+
if (!changed.trim()) {
|
|
254
|
+
log.info(
|
|
255
|
+
`» terraform_module_docs: ${module_dir} unchanged since ${priorHead} — skipped`,
|
|
256
|
+
);
|
|
257
|
+
return toolSkip(
|
|
258
|
+
"module_unchanged",
|
|
259
|
+
`README is current: no change under ${module_dir} since the recorded git-head ${priorHead}`,
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
} catch {
|
|
263
|
+
/* unknown prior sha (rebase/shallow) → regenerate */
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const iface = collectModuleInterface(cwd, module_dir);
|
|
268
|
+
// the refactor verdict comes from the RECORDED proof, never self-report:
|
|
269
|
+
// a proof recorded this run wins; the proposed_unproven flag only applies
|
|
270
|
+
// when no proof ran (the b.4 no-plan path); otherwise no refactor section.
|
|
271
|
+
const equivalence = scanSessionOf(ctx.toolState).refactorEquivalence;
|
|
272
|
+
const verdict: ModuleDocsVerdict | undefined = equivalence
|
|
273
|
+
? equivalence.equivalent
|
|
274
|
+
? "equivalence-proven"
|
|
275
|
+
: "equivalence-failed"
|
|
276
|
+
: proposed_unproven
|
|
277
|
+
? "proposed-unproven"
|
|
278
|
+
: undefined;
|
|
279
|
+
const refactor =
|
|
280
|
+
verdict === undefined ? undefined : { moves: moves ?? [], verdict };
|
|
281
|
+
|
|
282
|
+
const readme = buildModuleReadme({
|
|
283
|
+
moduleDir: module_dir,
|
|
284
|
+
iface,
|
|
285
|
+
refactor,
|
|
286
|
+
gitHead,
|
|
287
|
+
});
|
|
288
|
+
writeFileSync(target, readme);
|
|
289
|
+
log.info(
|
|
290
|
+
`» terraform_module_docs: ${module_dir} — ${iface.variables.length} input(s), ${iface.outputs.length} output(s)` +
|
|
291
|
+
(verdict ? `, verdict ${verdict}` : "") +
|
|
292
|
+
` → ${target}`,
|
|
293
|
+
);
|
|
294
|
+
return toolOk({
|
|
295
|
+
output_path: target,
|
|
296
|
+
inputs_documented: iface.variables.length,
|
|
297
|
+
outputs_documented: iface.outputs.length,
|
|
298
|
+
moves_documented: refactor?.moves.length ?? 0,
|
|
299
|
+
...(verdict ? { verdict } : {}),
|
|
300
|
+
});
|
|
301
|
+
}),
|
|
302
|
+
});
|
|
303
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The NATIVE rule pack — the small set of findings Infraweaver produces itself,
|
|
3
|
+
* rather than normalising out of trivy / checkov / tflint.
|
|
4
|
+
*
|
|
5
|
+
* WHY A NATIVE SOURCE AT ALL. Everything else here is deliberately a
|
|
6
|
+
* normalisation layer over other people's scanners, and that is the right
|
|
7
|
+
* default: re-implementing Checkov would be worse Checkov. These three rules
|
|
8
|
+
* exist because no upstream scanner can produce them:
|
|
9
|
+
*
|
|
10
|
+
* - `secret-persisted-to-state` needs the INSTALLED provider schema to know a
|
|
11
|
+
* write-only (`_wo`) equivalent exists for this provider version. It is a
|
|
12
|
+
* fact about the customer's pinned provider, not about a rule database.
|
|
13
|
+
* - the two governance rules are about IaC *shape* (imperative side-effects,
|
|
14
|
+
* input-bound destroy protection), which config scanners do not model at all.
|
|
15
|
+
*
|
|
16
|
+
* BANDS, AND WHY THEY ARE NOT ALL PASS/FAIL. A finding that says "this is a
|
|
17
|
+
* violation" when it is really "a human should look at this" is the fastest way
|
|
18
|
+
* to lose an assessor. Each rule declares a band, and the band — not the
|
|
19
|
+
* severity — decides what the five-status verdict may claim:
|
|
20
|
+
*
|
|
21
|
+
* - `verified` → `fail`. Code-verified from evidence we hold.
|
|
22
|
+
* - `review-required` → `not-code-verifiable`. Real signal, but whether it is
|
|
23
|
+
* acceptable is a governance decision, not a code fact.
|
|
24
|
+
* - `advisory` → `not-code-verifiable`. Legitimate patterns live here;
|
|
25
|
+
* we surface them and explicitly decline to judge.
|
|
26
|
+
*
|
|
27
|
+
* [[verification]] reads the band, so a rule cannot quietly upgrade itself into a
|
|
28
|
+
* verdict it has no evidence for, and [[crosswalk]] can cite a control without
|
|
29
|
+
* the citation implying a pass/fail the engine never proved.
|
|
30
|
+
*/
|
|
31
|
+
import { TOOL_NAME } from "#app/brand";
|
|
32
|
+
import type { Concern, Severity } from "#app/mcp/terraform/types";
|
|
33
|
+
|
|
34
|
+
/** The `Concern.source` every native rule carries. Equal to the emitted-artifact
|
|
35
|
+
* wordmark, so a SARIF report we produce round-trips back through
|
|
36
|
+
* `read_findings` as native (not `reviewer`) and stays ✗→✓ verifiable. */
|
|
37
|
+
export const NATIVE_SOURCE = TOOL_NAME;
|
|
38
|
+
|
|
39
|
+
/** What a rule's finding is allowed to claim. See the module note. */
|
|
40
|
+
export type NativeBand = "verified" | "review-required" | "advisory";
|
|
41
|
+
|
|
42
|
+
export interface NativeRule {
|
|
43
|
+
/** bare rule id — the `rule_id` is `infraweaver:<id>` and the content hash uses
|
|
44
|
+
* this bare form (see `buildConcern`). */
|
|
45
|
+
id: string;
|
|
46
|
+
title: string;
|
|
47
|
+
band: NativeBand;
|
|
48
|
+
category: Concern["category"];
|
|
49
|
+
/** the precise claim the finding makes. Copied into evidence/docs verbatim so
|
|
50
|
+
* the report and the code can never drift apart. */
|
|
51
|
+
asserts: string;
|
|
52
|
+
/** the claim a reader might infer that this rule explicitly does NOT make. */
|
|
53
|
+
doesNotAssert: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const SECRET_PERSISTED_TO_STATE = "secret-persisted-to-state";
|
|
57
|
+
export const IMPERATIVE_ACTION_TRIGGER = "imperative-action-trigger";
|
|
58
|
+
export const DYNAMIC_DESTROY_PROTECTION = "dynamic-destroy-protection";
|
|
59
|
+
export const DEPRECATED_STATE_LOCKING = "deprecated-state-locking";
|
|
60
|
+
|
|
61
|
+
export const NATIVE_RULES: readonly NativeRule[] = [
|
|
62
|
+
{
|
|
63
|
+
id: SECRET_PERSISTED_TO_STATE,
|
|
64
|
+
title:
|
|
65
|
+
"Secret argument persisted to state where a write-only equivalent exists",
|
|
66
|
+
band: "verified",
|
|
67
|
+
category: "security",
|
|
68
|
+
asserts:
|
|
69
|
+
"the INSTALLED provider's schema declares a write-only counterpart for this argument, and the " +
|
|
70
|
+
"configuration assigns the persisted form — so the value is written to Terraform state in plain text",
|
|
71
|
+
doesNotAssert:
|
|
72
|
+
"that the state file is exposed, or that the value is a real credential — state may be encrypted " +
|
|
73
|
+
"and the value may be a placeholder; the finding is about persistence, not about who can read it",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: IMPERATIVE_ACTION_TRIGGER,
|
|
77
|
+
title:
|
|
78
|
+
"Imperative side-effect invoked from declarative IaC (action / action_trigger)",
|
|
79
|
+
band: "review-required",
|
|
80
|
+
category: "correctness",
|
|
81
|
+
asserts:
|
|
82
|
+
"this configuration invokes a provider action as a side-effect of a resource lifecycle event, so an " +
|
|
83
|
+
"apply performs work that is not described by the resource graph and is not reproducible from state",
|
|
84
|
+
doesNotAssert:
|
|
85
|
+
"that the action is wrong or unsafe — actions are a supported Terraform feature and many uses are " +
|
|
86
|
+
"legitimate; the change-control question of who approved an out-of-graph side-effect is a human one",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: DYNAMIC_DESTROY_PROTECTION,
|
|
90
|
+
title:
|
|
91
|
+
"Destroy protection on a stateful resource is bound to an input variable",
|
|
92
|
+
band: "advisory",
|
|
93
|
+
category: "correctness",
|
|
94
|
+
asserts:
|
|
95
|
+
"`prevent_destroy` is set from an expression rather than a literal, so whether this resource is " +
|
|
96
|
+
"protected depends on the values supplied at plan time and cannot be determined from the code alone",
|
|
97
|
+
doesNotAssert:
|
|
98
|
+
"that protection is absent — the dynamic form is the documented OpenTofu pattern for varying " +
|
|
99
|
+
"protection across environments; this is reported as UNVERIFIABLE, never as a failure",
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: DEPRECATED_STATE_LOCKING,
|
|
103
|
+
title: "S3 backend relies on deprecated DynamoDB state locking",
|
|
104
|
+
band: "advisory",
|
|
105
|
+
category: "correctness",
|
|
106
|
+
asserts:
|
|
107
|
+
'this `backend "s3"` block configures DynamoDB-based locking (`dynamodb_table`) without also ' +
|
|
108
|
+
"setting `use_lockfile`, so the only thing preventing two concurrent applies from corrupting state " +
|
|
109
|
+
"is a mechanism HashiCorp has deprecated and will remove in a future release",
|
|
110
|
+
doesNotAssert:
|
|
111
|
+
"that state is currently unlocked or at risk — DynamoDB locking works today; this is a currency " +
|
|
112
|
+
"finding about a mechanism with an end date, not a security failure, and the backend block cannot " +
|
|
113
|
+
"be changed without an operator running `terraform init -migrate-state`",
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
const BY_ID: ReadonlyMap<string, NativeRule> = new Map(
|
|
118
|
+
NATIVE_RULES.map((r) => [r.id, r]),
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* The native rule a concern belongs to, or null when it isn't one of ours.
|
|
123
|
+
* Accepts both the namespaced `infraweaver:<id>` and the bare `<id>` form so it
|
|
124
|
+
* works on a concern before and after `buildConcern` namespaces it.
|
|
125
|
+
*/
|
|
126
|
+
export function nativeRuleOf(ruleId: string): NativeRule | null {
|
|
127
|
+
const prefix = `${NATIVE_SOURCE}:`;
|
|
128
|
+
const bare = ruleId.startsWith(prefix) ? ruleId.slice(prefix.length) : ruleId;
|
|
129
|
+
return BY_ID.get(bare) ?? null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** The severity floor a band implies. A rule may report HIGHER than its floor for
|
|
133
|
+
* a worse instance (a hardcoded literal secret beats a referenced one), but a
|
|
134
|
+
* non-`verified` band can never present as a critical/high violation — that is
|
|
135
|
+
* the loudness a code-verified `fail` has earned and these have not. */
|
|
136
|
+
export const BAND_SEVERITY: Record<NativeBand, Severity> = {
|
|
137
|
+
verified: "medium",
|
|
138
|
+
"review-required": "medium",
|
|
139
|
+
advisory: "low",
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/** The reason text a non-`verified` band carries into the five-status verdict. */
|
|
143
|
+
export function bandVerdictReason(rule: NativeRule): string | null {
|
|
144
|
+
switch (rule.band) {
|
|
145
|
+
case "verified":
|
|
146
|
+
return null;
|
|
147
|
+
case "review-required":
|
|
148
|
+
return `${rule.doesNotAssert} — reported for review, not as a violation`;
|
|
149
|
+
case "advisory":
|
|
150
|
+
return `${rule.doesNotAssert} — reported as advisory, not as a violation`;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The native rule pack as a scanner — one `ScannerOutcome` alongside trivy /
|
|
3
|
+
* checkov / tflint, so everything downstream (grouping, severity gating,
|
|
4
|
+
* suppressions, SARIF, the evidence bundle, the ✗→✓ verifier) treats our own
|
|
5
|
+
* findings exactly like anyone else's, with no special-casing.
|
|
6
|
+
*
|
|
7
|
+
* It re-derives every finding from the tree on each run, which is what makes the
|
|
8
|
+
* ✗→✓ loop work: fix the code and the finding's content id is simply absent from
|
|
9
|
+
* the re-scan.
|
|
10
|
+
*/
|
|
11
|
+
import { readFileSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import { walkTfFiles } from "#app/mcp/modules";
|
|
14
|
+
import { scanGovernanceFile } from "#app/mcp/terraform/governance";
|
|
15
|
+
import { NATIVE_SOURCE } from "#app/mcp/terraform/nativeRules";
|
|
16
|
+
import {
|
|
17
|
+
deprecatedStateLockingToConcerns,
|
|
18
|
+
findDeprecatedStateLocking,
|
|
19
|
+
} from "#app/mcp/terraform/stateLocking";
|
|
20
|
+
import type { Concern, ScannerOutcome } from "#app/mcp/terraform/types";
|
|
21
|
+
import { scanWriteOnlyFiles } from "#app/mcp/terraform/writeOnly";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Read every `.tf` under `cwd` ONCE, as `[repo-relative POSIX path, contents]`.
|
|
25
|
+
* Both rule families get the same text: re-reading the tree per rule would double
|
|
26
|
+
* the I/O of every scan, on exactly the monorepos where that is felt. An
|
|
27
|
+
* unreadable file is skipped — it makes the scan smaller, never wrong.
|
|
28
|
+
*/
|
|
29
|
+
function readTree(cwd: string): [string, string][] {
|
|
30
|
+
const out: [string, string][] = [];
|
|
31
|
+
for (const rel of walkTfFiles(cwd)) {
|
|
32
|
+
try {
|
|
33
|
+
out.push([rel.replace(/\\/g, "/"), readFileSync(join(cwd, rel), "utf8")]);
|
|
34
|
+
} catch {
|
|
35
|
+
/* skip unreadable file */
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Run the native pack over `cwd`.
|
|
43
|
+
*
|
|
44
|
+
* `ran` is always true: the governance rules need nothing but the source text, so
|
|
45
|
+
* the pack itself never fails to run. When the persisted-secret half could not
|
|
46
|
+
* run (no provider schema) that is reported through `partial` — a coverage gap
|
|
47
|
+
* the verification summary surfaces as INCONCLUSIVE, rather than being folded
|
|
48
|
+
* into a silent "the native pack found nothing".
|
|
49
|
+
*/
|
|
50
|
+
export function scanNative(cwd: string): ScannerOutcome {
|
|
51
|
+
const files = readTree(cwd);
|
|
52
|
+
const writeOnly = scanWriteOnlyFiles(cwd, files);
|
|
53
|
+
const concerns: Concern[] = [...writeOnly.concerns];
|
|
54
|
+
for (const [file, text] of files) {
|
|
55
|
+
concerns.push(...scanGovernanceFile(text, file).concerns);
|
|
56
|
+
concerns.push(...deprecatedStateLockingToConcerns(findDeprecatedStateLocking(text), file));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
source: NATIVE_SOURCE,
|
|
61
|
+
ran: true,
|
|
62
|
+
concerns,
|
|
63
|
+
...(writeOnly.coverageGap
|
|
64
|
+
? { partial: { check: `${NATIVE_SOURCE}:write-only`, reason: writeOnly.coverageGap } }
|
|
65
|
+
: {}),
|
|
66
|
+
};
|
|
67
|
+
}
|