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,383 @@
|
|
|
1
|
+
import { type } from "arktype";
|
|
2
|
+
import { TOOL_NAME } from "#app/brand";
|
|
3
|
+
import { ruleDocUrl } from "#app/mcp/terraform/decisions";
|
|
4
|
+
import { NATIVE_SOURCE, nativeRuleOf } from "#app/mcp/terraform/nativeRules";
|
|
5
|
+
import { toRepoRelative } from "#app/mcp/terraform/paths";
|
|
6
|
+
import { parseScannerJson } from "#app/mcp/terraform/scannerJson";
|
|
7
|
+
import {
|
|
8
|
+
type Concern,
|
|
9
|
+
concernId,
|
|
10
|
+
cvssScoreForSeverity,
|
|
11
|
+
isTerraformFile,
|
|
12
|
+
lowerSeverity,
|
|
13
|
+
type Severity,
|
|
14
|
+
severityFromCvss,
|
|
15
|
+
} from "#app/mcp/terraform/types";
|
|
16
|
+
import { redactSecrets } from "#app/utils/redact";
|
|
17
|
+
|
|
18
|
+
// --- reviewer findings (read_findings) ------------------------------------
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The subset of a terraform-reviewer (Assessor) `findings.json` finding that
|
|
22
|
+
* Infraweaver consumes. The reviewer's contract is a deliberate SUPERSET of the
|
|
23
|
+
* Concern model (same content-id formula, same severity enum) — see
|
|
24
|
+
* ../terraform-reviewer/schemas/findings.schema.json. Extra fields
|
|
25
|
+
* (lens/standard/control_id/confidence/state) are ignored except `state`.
|
|
26
|
+
*/
|
|
27
|
+
const ReviewerFinding = type({
|
|
28
|
+
"category?": "string",
|
|
29
|
+
"source?": "string",
|
|
30
|
+
"rule_id?": "string",
|
|
31
|
+
// verified (deterministic) | evidence (confirm manually) | human_only (out of scope).
|
|
32
|
+
"state?": "string",
|
|
33
|
+
"severity?": "string",
|
|
34
|
+
"evidence?": "string",
|
|
35
|
+
"location?": { "file?": "string", "line?": "number | null" },
|
|
36
|
+
"remediation_hint?": "string | null",
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const ReviewerFindingsReport = type({
|
|
40
|
+
"schema_version?": "string",
|
|
41
|
+
"findings?": ReviewerFinding.array().or("null"),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Map a reviewer `source` to a Concern source. The scanners Infraweaver also runs
|
|
46
|
+
* (checkov / tflint / trivy / terraform-fmt / terraform-validate) keep their
|
|
47
|
+
* name, so re-running them reproduces the identical content id — those concerns
|
|
48
|
+
* are ✗→✓ verifiable. Everything else (tfsec — whose rule ids differ from
|
|
49
|
+
* trivy's — plus infracost, llm, …) collapses to `reviewer`: the original tool
|
|
50
|
+
* stays visible in `rule_id`, but Infraweaver can't reproduce the id, so
|
|
51
|
+
* `terraform_verify_remediation` will honestly report it unresolved.
|
|
52
|
+
*
|
|
53
|
+
* NB: trivy ✗→✓ verifiability assumes the reviewer's trivy `rule_id` equals
|
|
54
|
+
* Infraweaver's (both `trivy:<AVDID>`). That holds today (the reviewer's SARIF
|
|
55
|
+
* `ruleId` is the AVD id); if a future Trivy diverges SARIF ruleId from the
|
|
56
|
+
* JSON AVDID, trivy-source findings would stop matching on re-scan.
|
|
57
|
+
*/
|
|
58
|
+
function mapReviewerSource(source: string | undefined): Concern["source"] {
|
|
59
|
+
switch (source) {
|
|
60
|
+
case "checkov":
|
|
61
|
+
case "tflint":
|
|
62
|
+
case "trivy":
|
|
63
|
+
case "terraform-fmt":
|
|
64
|
+
case "terraform-validate":
|
|
65
|
+
// our own native pack: re-running a scan reproduces the identical id, so a
|
|
66
|
+
// findings.json that carries it back to us stays ✗→✓ verifiable.
|
|
67
|
+
case NATIVE_SOURCE:
|
|
68
|
+
return source;
|
|
69
|
+
default:
|
|
70
|
+
return "reviewer";
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function mapReviewerCategory(
|
|
75
|
+
category: string | undefined,
|
|
76
|
+
): Concern["category"] {
|
|
77
|
+
switch (category) {
|
|
78
|
+
case "security":
|
|
79
|
+
return "security";
|
|
80
|
+
case "style":
|
|
81
|
+
return "style";
|
|
82
|
+
case "cost":
|
|
83
|
+
return "cost";
|
|
84
|
+
default:
|
|
85
|
+
return "correctness";
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Map a reviewer `findings.json` body into Concern[]. Drops `human_only`
|
|
91
|
+
* findings (out of scope — not auto-remediable). Paths are normalized to
|
|
92
|
+
* repo-relative POSIX (same as the scanners) so ids and grouping stay portable.
|
|
93
|
+
*/
|
|
94
|
+
export function parseReviewerFindings(json: string, cwd = ""): Concern[] {
|
|
95
|
+
const parsed = parseScannerJson(
|
|
96
|
+
ReviewerFindingsReport,
|
|
97
|
+
json,
|
|
98
|
+
"reviewer findings",
|
|
99
|
+
);
|
|
100
|
+
const out: Concern[] = [];
|
|
101
|
+
for (const f of parsed.findings ?? []) {
|
|
102
|
+
if (f.state === "human_only") continue;
|
|
103
|
+
const file = toRepoRelative(f.location?.file, cwd);
|
|
104
|
+
// Skip findings that don't point at a Terraform file — they aren't per-file
|
|
105
|
+
// remediable. In particular the reviewer's infracost/cost findings are keyed
|
|
106
|
+
// to a project *directory* (not a `.tf`), so they land here; cost is surfaced
|
|
107
|
+
// during remediation by `infracost_diff` (E1), not by editing a directory.
|
|
108
|
+
if (!isTerraformFile(file)) continue;
|
|
109
|
+
const line = f.location?.line ?? null;
|
|
110
|
+
const source = mapReviewerSource(f.source);
|
|
111
|
+
const ruleId = f.rule_id || "finding";
|
|
112
|
+
// Infraweaver's own parsers store `rule_id` namespaced (`${source}:${rule}`)
|
|
113
|
+
// but hash only the bare rule into the content id. Strip a matching
|
|
114
|
+
// `${source}:` prefix so a checkov/tflint/trivy/fmt finding from the reviewer
|
|
115
|
+
// reproduces the SAME id Infraweaver's own scan would — keeping it ✗→✓
|
|
116
|
+
// verifiable. `reviewer`-source findings keep the full rule_id in the hash
|
|
117
|
+
// (they aren't reproducible anyway). Both namespaced and bare inputs work.
|
|
118
|
+
const bareRule =
|
|
119
|
+
source !== "reviewer" && ruleId.startsWith(`${source}:`)
|
|
120
|
+
? ruleId.slice(source.length + 1)
|
|
121
|
+
: ruleId;
|
|
122
|
+
out.push({
|
|
123
|
+
id: concernId(source, bareRule, file, line),
|
|
124
|
+
source,
|
|
125
|
+
rule_id: ruleId,
|
|
126
|
+
severity: lowerSeverity(f.severity),
|
|
127
|
+
category: mapReviewerCategory(f.category),
|
|
128
|
+
evidence: f.evidence || ruleId,
|
|
129
|
+
location: { file, line },
|
|
130
|
+
remediation_hint: f.remediation_hint ?? null,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// --- SARIF ingestion (read_findings) --------------------------------------
|
|
137
|
+
|
|
138
|
+
const SarifLocation = type({
|
|
139
|
+
"physicalLocation?": {
|
|
140
|
+
"artifactLocation?": { "uri?": "string" },
|
|
141
|
+
"region?": { "startLine?": "number" },
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
const SarifSuppression = type({
|
|
145
|
+
kind: "'inSource' | 'external'",
|
|
146
|
+
"justification?": "string",
|
|
147
|
+
});
|
|
148
|
+
const SarifResult = type({
|
|
149
|
+
"ruleId?": "string",
|
|
150
|
+
"level?": "string",
|
|
151
|
+
"message?": { "text?": "string" },
|
|
152
|
+
"locations?": SarifLocation.array(),
|
|
153
|
+
"properties?": { "security-severity?": "string" },
|
|
154
|
+
"suppressions?": SarifSuppression.array(),
|
|
155
|
+
});
|
|
156
|
+
const SarifRule = type({
|
|
157
|
+
"id?": "string",
|
|
158
|
+
"helpUri?": "string",
|
|
159
|
+
"shortDescription?": { "text?": "string" },
|
|
160
|
+
});
|
|
161
|
+
const SarifRun = type({
|
|
162
|
+
"tool?": { "driver?": { "name?": "string", "rules?": SarifRule.array() } },
|
|
163
|
+
"results?": SarifResult.array(),
|
|
164
|
+
});
|
|
165
|
+
const SarifReport = type({
|
|
166
|
+
"version?": "string",
|
|
167
|
+
"$schema?": "string",
|
|
168
|
+
"runs?": SarifRun.array(),
|
|
169
|
+
});
|
|
170
|
+
// the same shapes serve the emit side (buildSarifReport) as plain types.
|
|
171
|
+
type SarifReport = typeof SarifReport.infer;
|
|
172
|
+
type SarifRule = typeof SarifRule.infer;
|
|
173
|
+
type SarifResult = typeof SarifResult.infer;
|
|
174
|
+
|
|
175
|
+
/** true when a parsed JSON object looks like a SARIF report (the standard
|
|
176
|
+
* scanner-output format) rather than a terraform-reviewer findings.json. */
|
|
177
|
+
export function isSarif(parsed: unknown): boolean {
|
|
178
|
+
if (!parsed || typeof parsed !== "object") return false;
|
|
179
|
+
const o = parsed as Record<string, unknown>;
|
|
180
|
+
const schema = typeof o.$schema === "string" ? o.$schema.toLowerCase() : "";
|
|
181
|
+
return (
|
|
182
|
+
Array.isArray(o.runs) &&
|
|
183
|
+
(schema.includes("sarif") || typeof o.version === "string")
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** map a SARIF driver name to a Concern source (so a re-run reproduces the id
|
|
188
|
+
* for the scanners Infraweaver also runs; everything else → `reviewer`). */
|
|
189
|
+
function mapSarifDriver(name: string | undefined): Concern["source"] {
|
|
190
|
+
switch ((name ?? "").toLowerCase()) {
|
|
191
|
+
case "trivy":
|
|
192
|
+
return "trivy";
|
|
193
|
+
case "checkov":
|
|
194
|
+
return "checkov";
|
|
195
|
+
case "tflint":
|
|
196
|
+
return "tflint";
|
|
197
|
+
// a SARIF report we emitted ourselves — the driver name IS the native source,
|
|
198
|
+
// so it round-trips as native rather than collapsing to `reviewer`.
|
|
199
|
+
case NATIVE_SOURCE:
|
|
200
|
+
return NATIVE_SOURCE;
|
|
201
|
+
default:
|
|
202
|
+
return "reviewer";
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** SARIF `level` → severity (a `security-severity` property refines it). */
|
|
207
|
+
function sarifSeverity(
|
|
208
|
+
level: string | undefined,
|
|
209
|
+
securitySeverity: string | undefined,
|
|
210
|
+
): Severity {
|
|
211
|
+
const score = securitySeverity
|
|
212
|
+
? Number.parseFloat(securitySeverity)
|
|
213
|
+
: Number.NaN;
|
|
214
|
+
if (Number.isFinite(score) && score > 0) return severityFromCvss(score);
|
|
215
|
+
switch ((level ?? "").toLowerCase()) {
|
|
216
|
+
case "error":
|
|
217
|
+
return "high";
|
|
218
|
+
case "warning":
|
|
219
|
+
return "medium";
|
|
220
|
+
case "note":
|
|
221
|
+
return "low";
|
|
222
|
+
default:
|
|
223
|
+
return "info";
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Parse a SARIF 2.1.0 report (the standard scanner-output format Trivy /
|
|
229
|
+
* Checkov / tflint all emit) into Concern[]. The driver name picks the source so
|
|
230
|
+
* a finding from a scanner Infraweaver re-runs reproduces the SAME content id
|
|
231
|
+
* (✗→✓ verifiable); other tools collapse to `reviewer`. Rule docs come from the
|
|
232
|
+
* matching `tool.driver.rules[].helpUri`. Non-Terraform files are dropped.
|
|
233
|
+
*/
|
|
234
|
+
export function parseSarifFindings(json: string, cwd = ""): Concern[] {
|
|
235
|
+
let report: SarifReport;
|
|
236
|
+
try {
|
|
237
|
+
report = parseScannerJson(SarifReport, json, "SARIF");
|
|
238
|
+
} catch {
|
|
239
|
+
return [];
|
|
240
|
+
}
|
|
241
|
+
const out: Concern[] = [];
|
|
242
|
+
for (const run of report.runs ?? []) {
|
|
243
|
+
const source = mapSarifDriver(run.tool?.driver?.name);
|
|
244
|
+
const ruleDocs = new Map<string, string>();
|
|
245
|
+
for (const rule of run.tool?.driver?.rules ?? []) {
|
|
246
|
+
if (rule.id && rule.helpUri) ruleDocs.set(rule.id, rule.helpUri);
|
|
247
|
+
}
|
|
248
|
+
for (const result of run.results ?? []) {
|
|
249
|
+
const loc = result.locations?.[0]?.physicalLocation;
|
|
250
|
+
const file = toRepoRelative(loc?.artifactLocation?.uri, cwd);
|
|
251
|
+
if (!isTerraformFile(file)) continue;
|
|
252
|
+
const start = loc?.region?.startLine;
|
|
253
|
+
const line = typeof start === "number" && start > 0 ? start : null;
|
|
254
|
+
const rawRule = result.ruleId || "finding";
|
|
255
|
+
// strip a `${source}:` prefix if a tool already namespaced it, so the
|
|
256
|
+
// content id matches Infraweaver's own scan of the same rule.
|
|
257
|
+
const bareRule =
|
|
258
|
+
source !== "reviewer" && rawRule.startsWith(`${source}:`)
|
|
259
|
+
? rawRule.slice(source.length + 1)
|
|
260
|
+
: rawRule;
|
|
261
|
+
const ruleId = source === "reviewer" ? rawRule : `${source}:${bareRule}`;
|
|
262
|
+
out.push({
|
|
263
|
+
id: concernId(source, bareRule, file, line),
|
|
264
|
+
source,
|
|
265
|
+
rule_id: ruleId,
|
|
266
|
+
severity: sarifSeverity(
|
|
267
|
+
result.level,
|
|
268
|
+
result.properties?.["security-severity"],
|
|
269
|
+
),
|
|
270
|
+
// a native rule declares its own category (the governance rules are
|
|
271
|
+
// `correctness`, not security) — keep it on the round-trip.
|
|
272
|
+
category:
|
|
273
|
+
source === "tflint"
|
|
274
|
+
? "style"
|
|
275
|
+
: (nativeRuleOf(ruleId)?.category ?? "security"),
|
|
276
|
+
evidence: result.message?.text || ruleId,
|
|
277
|
+
location: { file, line },
|
|
278
|
+
remediation_hint: ruleDocs.get(rawRule) ?? null,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return out;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/** dispatch a findings file to the right parser: SARIF (standard scanner
|
|
286
|
+
* output) or a terraform-reviewer findings.json. */
|
|
287
|
+
export function parseFindingsFile(json: string, cwd = ""): Concern[] {
|
|
288
|
+
let parsed: unknown;
|
|
289
|
+
try {
|
|
290
|
+
parsed = JSON.parse(json || "{}");
|
|
291
|
+
} catch {
|
|
292
|
+
return [];
|
|
293
|
+
}
|
|
294
|
+
return isSarif(parsed)
|
|
295
|
+
? parseSarifFindings(json, cwd)
|
|
296
|
+
: parseReviewerFindings(json, cwd);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// --- SARIF emit (GitHub code-scanning) ------------------------------------
|
|
300
|
+
|
|
301
|
+
/** Concern severity → SARIF `level`. SARIF has only error/warning/note, so
|
|
302
|
+
* critical+high collapse to `error`, medium → `warning`, low+info → `note`. The
|
|
303
|
+
* finer grade survives in the `security-severity` property below. */
|
|
304
|
+
function severityToSarifLevel(s: Severity): "error" | "warning" | "note" {
|
|
305
|
+
switch (s) {
|
|
306
|
+
case "critical":
|
|
307
|
+
case "high":
|
|
308
|
+
return "error";
|
|
309
|
+
case "medium":
|
|
310
|
+
return "warning";
|
|
311
|
+
default:
|
|
312
|
+
return "note";
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/** Concern severity → the numeric `security-severity` GitHub reads to colour the
|
|
317
|
+
* alert (0–10 CVSS-like scale). */
|
|
318
|
+
function securitySeverityScore(s: Severity): string {
|
|
319
|
+
return cvssScoreForSeverity(s).toFixed(1);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Emit a set of concerns as a SARIF 2.1.0 report for GitHub code-scanning (the
|
|
324
|
+
* inverse of `parseSarifFindings` — close the loop so a Infraweaver scan can
|
|
325
|
+
* populate the repo's Security tab via `github/codeql-action/upload-sarif`). One
|
|
326
|
+
* `run` with the `infraweaver` driver, a deduped `rules` array (each rule's
|
|
327
|
+
* `helpUri` from `ruleDocUrl`), and one `result` per concern carrying its
|
|
328
|
+
* `level`, `security-severity`, message, and `file:line`. Pure + deterministic
|
|
329
|
+
* (rules sorted, stable partialFingerprints from the content id) so re-emitting
|
|
330
|
+
* an unchanged scan yields a byte-identical report.
|
|
331
|
+
*/
|
|
332
|
+
export function buildSarifReport(concerns: Concern[]): SarifReport {
|
|
333
|
+
// deduped rule metadata, keyed by the namespaced rule_id (the SARIF ruleId).
|
|
334
|
+
const rulesById = new Map<string, SarifRule>();
|
|
335
|
+
for (const c of concerns) {
|
|
336
|
+
if (rulesById.has(c.rule_id)) continue;
|
|
337
|
+
const helpUri = ruleDocUrl(c);
|
|
338
|
+
rulesById.set(c.rule_id, {
|
|
339
|
+
id: c.rule_id,
|
|
340
|
+
...(helpUri ? { helpUri } : {}),
|
|
341
|
+
// LLM02: evidence is repo-derived and can carry a secret — redact before it
|
|
342
|
+
// reaches SARIF (uploaded to GitHub Code Scanning, a durable artifact).
|
|
343
|
+
shortDescription: { text: redactSecrets(c.evidence).slice(0, 200) },
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
const rules = [...rulesById.values()].sort((a, b) =>
|
|
347
|
+
(a.id ?? "").localeCompare(b.id ?? ""),
|
|
348
|
+
);
|
|
349
|
+
const results: SarifResult[] = concerns.map((c) => ({
|
|
350
|
+
ruleId: c.rule_id,
|
|
351
|
+
level: severityToSarifLevel(c.severity),
|
|
352
|
+
message: { text: redactSecrets(c.evidence) },
|
|
353
|
+
properties: { "security-severity": securitySeverityScore(c.severity) },
|
|
354
|
+
...(c.suppression
|
|
355
|
+
? {
|
|
356
|
+
suppressions: [
|
|
357
|
+
{
|
|
358
|
+
kind:
|
|
359
|
+
c.suppression.source === "inline"
|
|
360
|
+
? ("inSource" as const)
|
|
361
|
+
: ("external" as const),
|
|
362
|
+
justification: redactSecrets(c.suppression.reason),
|
|
363
|
+
},
|
|
364
|
+
],
|
|
365
|
+
}
|
|
366
|
+
: {}),
|
|
367
|
+
locations: [
|
|
368
|
+
{
|
|
369
|
+
physicalLocation: {
|
|
370
|
+
artifactLocation: { uri: c.location.file },
|
|
371
|
+
...(c.location.line
|
|
372
|
+
? { region: { startLine: c.location.line } }
|
|
373
|
+
: {}),
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
],
|
|
377
|
+
}));
|
|
378
|
+
return {
|
|
379
|
+
version: "2.1.0",
|
|
380
|
+
$schema: "https://json.schemastore.org/sarif-2.1.0.json",
|
|
381
|
+
runs: [{ tool: { driver: { name: TOOL_NAME, rules } }, results }],
|
|
382
|
+
};
|
|
383
|
+
}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reusable proven-fix memory (§5.12) — "deterministic where safe, proven every time".
|
|
3
|
+
*
|
|
4
|
+
* When a remediation passes the `✗→✓` proof (`terraform_verify_remediation`), the
|
|
5
|
+
* finding-TYPE that was fixed (its `source|bareRule` shape, plus the cross-scanner
|
|
6
|
+
* `canonical_class`) and the guidance that fixed it are captured as a *pattern*.
|
|
7
|
+
* On a later run — the SAME repo, or any repo in the fleet via Cloud — when a
|
|
8
|
+
* finding of that type appears, the pattern is offered to the fixer as a proven
|
|
9
|
+
* starting point.
|
|
10
|
+
*
|
|
11
|
+
* The moat is untouched: a pattern is a PRIOR, never an action. The fixer still
|
|
12
|
+
* edits this repo's own resources and the run STILL re-scans `✗→✓` per target
|
|
13
|
+
* before any PR — a pattern is never blind-applied. This module is the pure core
|
|
14
|
+
* (identity, capture, merge, match, (de)serialize); the file read lives in
|
|
15
|
+
* `loadFixMemory` and everything else is unit-testable.
|
|
16
|
+
*/
|
|
17
|
+
import { readFileSync } from "node:fs";
|
|
18
|
+
import { join } from "node:path";
|
|
19
|
+
import { FIX_MEMORY_FILE } from "#app/brand";
|
|
20
|
+
import { bareRuleOf, type Concern } from "#app/mcp/terraform/types";
|
|
21
|
+
|
|
22
|
+
export const FIX_MEMORY_FILENAME = FIX_MEMORY_FILE;
|
|
23
|
+
|
|
24
|
+
/** Keep the wire + local file bounded — a pattern is a hint, not the whole file. */
|
|
25
|
+
const MAX_DESCRIPTION = 400;
|
|
26
|
+
const MAX_BEFORE_EXAMPLE = 1200;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* A proven-fix pattern. Freshly CAPTURED patterns carry only the identity +
|
|
30
|
+
* guidance (no stats); LIBRARY entries (loaded from Cloud / a local file) also
|
|
31
|
+
* carry the reuse stats and the operator `disabled` flag. The finding-TYPE key
|
|
32
|
+
* (`finding_type`) is file-independent on purpose — the whole point is to reuse
|
|
33
|
+
* across files and repos.
|
|
34
|
+
*/
|
|
35
|
+
export interface ProvenFixPattern {
|
|
36
|
+
/** the finding-TYPE shape: `source|bareRule` (file-independent). The match key. */
|
|
37
|
+
finding_type: string;
|
|
38
|
+
/** producing scanner, when known (null for reviewer-loaded concerns). */
|
|
39
|
+
source: string | null;
|
|
40
|
+
/** cross-scanner canonical class (e.g. "aws-s3-encryption"), when recognised. */
|
|
41
|
+
canonical_class: string | null;
|
|
42
|
+
category: string;
|
|
43
|
+
/** human label — the namespaced rule id (e.g. "trivy:AVD-AWS-0088"). */
|
|
44
|
+
title: string;
|
|
45
|
+
/** the scanner's "what is wrong" message, trimmed + capped. */
|
|
46
|
+
description: string | null;
|
|
47
|
+
/** the remediation guidance that proved out (trivy Resolution / fmt hint / …). */
|
|
48
|
+
remediation_hint: string | null;
|
|
49
|
+
/** a representative BEFORE snippet from the repo the pattern was proven on —
|
|
50
|
+
* a concrete example for the fixer to adapt, never a patch to apply verbatim. */
|
|
51
|
+
before_example: string | null;
|
|
52
|
+
// ── stats (library entries only; absent on fresh captures) ──
|
|
53
|
+
/** how many times this type went `✗→✓` (across the fleet, from Cloud). */
|
|
54
|
+
times_proven?: number;
|
|
55
|
+
/** distinct repos it's been proven on. */
|
|
56
|
+
repos_count?: number;
|
|
57
|
+
/** ISO timestamp of the most recent proof. */
|
|
58
|
+
last_proven?: string;
|
|
59
|
+
/** operator retired this pattern in the dashboard — never offered to the fixer. */
|
|
60
|
+
disabled?: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** The finding-TYPE identity: `source|bareRule`, file-independent (unlike
|
|
64
|
+
* `concernKeyOf`, which folds in the file). Two instances of the same rule in
|
|
65
|
+
* different files/repos share this key — the reuse unit. */
|
|
66
|
+
export function findingTypeOf(c: Pick<Concern, "source" | "rule_id">): string {
|
|
67
|
+
return `${c.source}|${bareRuleOf(c.source, c.rule_id)}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function cap(text: string | null | undefined, max: number): string | null {
|
|
71
|
+
const trimmed = text?.trim();
|
|
72
|
+
if (!trimmed) return null;
|
|
73
|
+
return trimmed.length > max ? `${trimmed.slice(0, max - 1)}…` : trimmed;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Re-apply the size caps to a pattern from an UNTRUSTED source (a committed
|
|
77
|
+
* local file or the Cloud library blob) — captures are already capped, but a
|
|
78
|
+
* hand-edited/garbage file must not bloat the fixer prompt with an unbounded
|
|
79
|
+
* before-example. Pure. */
|
|
80
|
+
function capPattern(p: ProvenFixPattern): ProvenFixPattern {
|
|
81
|
+
return {
|
|
82
|
+
...p,
|
|
83
|
+
description: cap(p.description, MAX_DESCRIPTION),
|
|
84
|
+
remediation_hint: cap(p.remediation_hint, MAX_DESCRIPTION),
|
|
85
|
+
before_example: cap(p.before_example, MAX_BEFORE_EXAMPLE),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Build a fresh pattern from a concern that just proved out `✗→✓`. Pure. */
|
|
90
|
+
export function captureProvenFix(c: Concern): ProvenFixPattern {
|
|
91
|
+
return {
|
|
92
|
+
finding_type: findingTypeOf(c),
|
|
93
|
+
source: c.source,
|
|
94
|
+
canonical_class: c.canonical_class ?? null,
|
|
95
|
+
category: c.category,
|
|
96
|
+
title: c.rule_id,
|
|
97
|
+
description: cap(c.evidence, MAX_DESCRIPTION),
|
|
98
|
+
remediation_hint: cap(c.remediation_hint, MAX_DESCRIPTION),
|
|
99
|
+
before_example: cap(c.code_snippet, MAX_BEFORE_EXAMPLE),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* De-duplicate a run's captures to one pattern per finding-type. When the same
|
|
105
|
+
* type is proven on several concerns this run, keep the FIRST that carries a
|
|
106
|
+
* before-example (a concrete example beats none), else the first seen — the
|
|
107
|
+
* order is otherwise stable so the wire is deterministic.
|
|
108
|
+
*/
|
|
109
|
+
export function dedupeCaptures(
|
|
110
|
+
captures: ProvenFixPattern[],
|
|
111
|
+
): ProvenFixPattern[] {
|
|
112
|
+
const byType = new Map<string, ProvenFixPattern>();
|
|
113
|
+
for (const p of captures) {
|
|
114
|
+
const existing = byType.get(p.finding_type);
|
|
115
|
+
if (!existing) {
|
|
116
|
+
byType.set(p.finding_type, p);
|
|
117
|
+
} else if (!existing.before_example && p.before_example) {
|
|
118
|
+
byType.set(p.finding_type, p);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return [...byType.values()];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Match a loaded library against the CURRENT scan's concerns: return the patterns
|
|
126
|
+
* whose finding-type is present in this scan (deduped, `disabled` excluded),
|
|
127
|
+
* newest-proven first, capped. This is what the fixer is offered — a proven prior
|
|
128
|
+
* for the exact finding-types it's about to fix. Pure.
|
|
129
|
+
*/
|
|
130
|
+
export function matchPatternsForConcerns(
|
|
131
|
+
library: ProvenFixPattern[],
|
|
132
|
+
concerns: Pick<Concern, "source" | "rule_id">[],
|
|
133
|
+
max = 25,
|
|
134
|
+
): ProvenFixPattern[] {
|
|
135
|
+
const present = new Set(concerns.map(findingTypeOf));
|
|
136
|
+
const seen = new Set<string>();
|
|
137
|
+
const matched = library.filter((p) => {
|
|
138
|
+
if (p.disabled) return false;
|
|
139
|
+
if (!present.has(p.finding_type)) return false;
|
|
140
|
+
if (seen.has(p.finding_type)) return false;
|
|
141
|
+
seen.add(p.finding_type);
|
|
142
|
+
return true;
|
|
143
|
+
});
|
|
144
|
+
matched.sort((a, b) =>
|
|
145
|
+
(b.last_proven ?? "").localeCompare(a.last_proven ?? ""),
|
|
146
|
+
);
|
|
147
|
+
return matched.slice(0, max);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface FixMemoryFile {
|
|
151
|
+
version: 1;
|
|
152
|
+
/** ISO timestamp of the last write (informational). */
|
|
153
|
+
updated?: string;
|
|
154
|
+
patterns: ProvenFixPattern[];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Merge freshly-captured patterns into a local library, keyed by finding-type:
|
|
159
|
+
* bump `times_proven`, advance `last_proven`, and prefer a non-empty
|
|
160
|
+
* before-example/hint over an empty one. The local file is single-repo memory
|
|
161
|
+
* (the fleet count lives in Cloud), so `repos_count` stays 1 here. Pure.
|
|
162
|
+
*/
|
|
163
|
+
export function mergeFixMemory(
|
|
164
|
+
existing: ProvenFixPattern[],
|
|
165
|
+
captured: ProvenFixPattern[],
|
|
166
|
+
provenAt: string,
|
|
167
|
+
): ProvenFixPattern[] {
|
|
168
|
+
const byType = new Map<string, ProvenFixPattern>();
|
|
169
|
+
for (const p of existing) byType.set(p.finding_type, { ...p });
|
|
170
|
+
for (const cap of dedupeCaptures(captured)) {
|
|
171
|
+
const prior = byType.get(cap.finding_type);
|
|
172
|
+
if (!prior) {
|
|
173
|
+
byType.set(cap.finding_type, {
|
|
174
|
+
...cap,
|
|
175
|
+
times_proven: 1,
|
|
176
|
+
repos_count: 1,
|
|
177
|
+
last_proven: provenAt,
|
|
178
|
+
});
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
byType.set(cap.finding_type, {
|
|
182
|
+
...prior,
|
|
183
|
+
// refresh the guidance/example from the newest proof when it has richer content.
|
|
184
|
+
description: cap.description ?? prior.description,
|
|
185
|
+
remediation_hint: cap.remediation_hint ?? prior.remediation_hint,
|
|
186
|
+
before_example: cap.before_example ?? prior.before_example,
|
|
187
|
+
canonical_class: cap.canonical_class ?? prior.canonical_class,
|
|
188
|
+
times_proven: (prior.times_proven ?? 0) + 1,
|
|
189
|
+
repos_count: prior.repos_count ?? 1,
|
|
190
|
+
last_proven: provenAt,
|
|
191
|
+
// a locally-retired pattern stays retired even after a fresh local proof.
|
|
192
|
+
...(prior.disabled ? { disabled: true } : {}),
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
return [...byType.values()].sort((a, b) =>
|
|
196
|
+
(b.last_proven ?? "").localeCompare(a.last_proven ?? ""),
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function serializeFixMemory(
|
|
201
|
+
patterns: ProvenFixPattern[],
|
|
202
|
+
updated: string,
|
|
203
|
+
): FixMemoryFile {
|
|
204
|
+
return { version: 1, updated, patterns };
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Parse fix-memory JSON into a pattern list; tolerant of a malformed/old file (→ null). */
|
|
208
|
+
export function parseFixMemory(raw: string): ProvenFixPattern[] | null {
|
|
209
|
+
let doc: unknown;
|
|
210
|
+
try {
|
|
211
|
+
doc = JSON.parse(raw);
|
|
212
|
+
} catch {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
if (!doc || typeof doc !== "object") return null;
|
|
216
|
+
const patterns = (doc as { patterns?: unknown }).patterns;
|
|
217
|
+
if (!Array.isArray(patterns)) return null;
|
|
218
|
+
return patterns.filter(isProvenFixPattern).map(capPattern);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Structural guard for one untrusted pattern (from a file or the Cloud library). */
|
|
222
|
+
export function isProvenFixPattern(value: unknown): value is ProvenFixPattern {
|
|
223
|
+
if (!value || typeof value !== "object") return false;
|
|
224
|
+
const p = value as Record<string, unknown>;
|
|
225
|
+
return (
|
|
226
|
+
typeof p.finding_type === "string" &&
|
|
227
|
+
p.finding_type.length > 0 &&
|
|
228
|
+
typeof p.title === "string" &&
|
|
229
|
+
typeof p.category === "string"
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** Load `.infraweaver.fix-memory.json` under `cwd`; [] when absent/unreadable/malformed. */
|
|
234
|
+
export function loadFixMemory(cwd: string | undefined): ProvenFixPattern[] {
|
|
235
|
+
const root = cwd ?? process.cwd();
|
|
236
|
+
let raw: string;
|
|
237
|
+
try {
|
|
238
|
+
raw = readFileSync(join(root, FIX_MEMORY_FILENAME), "utf-8");
|
|
239
|
+
} catch {
|
|
240
|
+
return [];
|
|
241
|
+
}
|
|
242
|
+
return parseFixMemory(raw) ?? [];
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Coerce an untrusted library payload (the Cloud run-context `provenFixes` blob)
|
|
247
|
+
* into typed patterns, keeping only structurally-valid, non-disabled entries.
|
|
248
|
+
* Pure — the wire boundary can't be typechecked across repos.
|
|
249
|
+
*/
|
|
250
|
+
export function coerceLibrary(raw: unknown): ProvenFixPattern[] {
|
|
251
|
+
if (!Array.isArray(raw)) return [];
|
|
252
|
+
return raw.filter(isProvenFixPattern).map(capPattern);
|
|
253
|
+
}
|