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,551 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { parse as parseYaml } from "yaml";
|
|
4
|
+
import { CONFIG_FILE, CONFIG_FILE_JSON } from "#app/brand";
|
|
5
|
+
import { isPathAllowed } from "#app/mcp/guardrails";
|
|
6
|
+
import { NATIVE_SOURCE } from "#app/mcp/terraform/nativeRules";
|
|
7
|
+
import type { Concern, ConcernSuppression } from "#app/mcp/terraform/types";
|
|
8
|
+
import { neutralizeMarkup } from "#app/mcp/untrustedContent";
|
|
9
|
+
import { readConfigAtBaseRef } from "#app/utils/baseRefConfig";
|
|
10
|
+
import { log } from "#app/utils/cli";
|
|
11
|
+
import { INFRAWEAVER_CONFIG_FILENAMES } from "#app/utils/infraweaverConfig";
|
|
12
|
+
|
|
13
|
+
export type SuppressionSource = ConcernSuppression["source"];
|
|
14
|
+
|
|
15
|
+
export interface Suppression {
|
|
16
|
+
source: SuppressionSource;
|
|
17
|
+
rule: string;
|
|
18
|
+
reason: string;
|
|
19
|
+
expires: string | null;
|
|
20
|
+
paths: string[];
|
|
21
|
+
file: string | null;
|
|
22
|
+
/** Set when this came from a NATIVE scanner skip directive (checkov/tfsec/trivy)
|
|
23
|
+
* rather than a `#infraweaver:ignore`. The owning scanner already honours it; we
|
|
24
|
+
* carry the provenance so the unified audit trail shows where it came from. */
|
|
25
|
+
tool?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ParsedSuppressions {
|
|
29
|
+
suppressions: Suppression[];
|
|
30
|
+
warnings: string[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const NAMESPACES: ReadonlySet<string> = new Set([
|
|
34
|
+
"trivy",
|
|
35
|
+
"checkov",
|
|
36
|
+
"tflint",
|
|
37
|
+
"tfsec",
|
|
38
|
+
"terraform-fmt",
|
|
39
|
+
"terraform-validate",
|
|
40
|
+
// the native rule pack — `#infraweaver:ignore:infraweaver:<rule>: reason`. The bare
|
|
41
|
+
// form (`#infraweaver:ignore:<rule>: reason`) also works via `ruleMatches`.
|
|
42
|
+
NATIVE_SOURCE,
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
46
|
+
const INLINE_DIRECTIVE = /#\s*infraweaver:ignore:(.+)$/i;
|
|
47
|
+
const EXPIRES_TOKEN = /\b(?:expires|until)=(\d{4}-\d{2}-\d{2})\b/i;
|
|
48
|
+
|
|
49
|
+
function splitRuleAndReason(
|
|
50
|
+
rest: string,
|
|
51
|
+
): { rule: string; reason: string } | null {
|
|
52
|
+
const parts = rest.split(":");
|
|
53
|
+
if (parts.length < 2) return null;
|
|
54
|
+
const first = (parts[0] ?? "").trim();
|
|
55
|
+
let rule: string;
|
|
56
|
+
let reasonParts: string[];
|
|
57
|
+
if (NAMESPACES.has(first.toLowerCase()) && parts.length >= 3) {
|
|
58
|
+
rule = `${first}:${(parts[1] ?? "").trim()}`;
|
|
59
|
+
reasonParts = parts.slice(2);
|
|
60
|
+
} else {
|
|
61
|
+
rule = first;
|
|
62
|
+
reasonParts = parts.slice(1);
|
|
63
|
+
}
|
|
64
|
+
const reason = reasonParts.join(":").trim();
|
|
65
|
+
if (!rule || !reason) return null;
|
|
66
|
+
return { rule, reason };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function extractExpiry(reason: string): {
|
|
70
|
+
reason: string;
|
|
71
|
+
expires: string | null;
|
|
72
|
+
} {
|
|
73
|
+
const match = reason.match(EXPIRES_TOKEN);
|
|
74
|
+
if (!match) return { reason, expires: null };
|
|
75
|
+
const cleaned = reason
|
|
76
|
+
.replace(EXPIRES_TOKEN, "")
|
|
77
|
+
.replace(/\s{2,}/g, " ")
|
|
78
|
+
.trim();
|
|
79
|
+
return { reason: cleaned, expires: match[1] ?? null };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function parseInlineSuppressions(
|
|
83
|
+
content: string,
|
|
84
|
+
file: string,
|
|
85
|
+
): ParsedSuppressions {
|
|
86
|
+
const suppressions: Suppression[] = [];
|
|
87
|
+
const warnings: string[] = [];
|
|
88
|
+
const lines = content.split(/\r?\n/);
|
|
89
|
+
for (let i = 0; i < lines.length; i++) {
|
|
90
|
+
const line = lines[i] ?? "";
|
|
91
|
+
const directive = line.match(INLINE_DIRECTIVE);
|
|
92
|
+
if (!directive) continue;
|
|
93
|
+
const split = splitRuleAndReason((directive[1] ?? "").trim());
|
|
94
|
+
if (!split) {
|
|
95
|
+
warnings.push(
|
|
96
|
+
`${file}:${i + 1}: #infraweaver:ignore needs <rule>:<reason> — "${line.trim()}" ignored`,
|
|
97
|
+
);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const { reason: rawReason, expires } = extractExpiry(split.reason);
|
|
101
|
+
// LLM01. The reason is free text written by whoever authored the file under
|
|
102
|
+
// examination, and it travels a long way: into the agent's context via
|
|
103
|
+
// `terraform_scan`'s `suppressed[].suppression`, and outward into the SARIF
|
|
104
|
+
// suppression justification and the PR body. Neutralise the markup here, at
|
|
105
|
+
// the single parse point, rather than at each of those surfaces. The
|
|
106
|
+
// directive is matched per line, so the newline collapse is a no-op and the
|
|
107
|
+
// reason stays readable. A reason that neutralises to nothing was never a
|
|
108
|
+
// reason — it falls into the existing "needs a reason" warning below.
|
|
109
|
+
const reason = neutralizeMarkup(rawReason);
|
|
110
|
+
if (!reason) {
|
|
111
|
+
warnings.push(
|
|
112
|
+
`${file}:${i + 1}: #infraweaver:ignore needs a reason — ignored`,
|
|
113
|
+
);
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
suppressions.push({
|
|
117
|
+
source: "inline",
|
|
118
|
+
rule: split.rule,
|
|
119
|
+
reason,
|
|
120
|
+
expires,
|
|
121
|
+
paths: [],
|
|
122
|
+
file,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
return { suppressions, warnings };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
interface NativePattern {
|
|
129
|
+
tool: string;
|
|
130
|
+
re: RegExp;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Native scanner skip directives. The owning scanner already honours these (so the
|
|
134
|
+
// finding never reaches Infraweaver), but we parse them too so a native skip is
|
|
135
|
+
// VISIBLE in Infraweaver's unified audit trail — carrying the scanner provenance —
|
|
136
|
+
// instead of silently vanishing. `#infraweaver:ignore` (above) remains the portable,
|
|
137
|
+
// reason-mandatory form; these stay honoured by their own scanners (pass-through).
|
|
138
|
+
const NATIVE_PATTERNS: readonly NativePattern[] = [
|
|
139
|
+
// checkov:skip=CKV_AWS_20[:optional reason]
|
|
140
|
+
{
|
|
141
|
+
tool: "checkov",
|
|
142
|
+
re: /#\s*checkov:skip=([A-Za-z0-9_]+)(?::\s*(.*\S))?\s*$/i,
|
|
143
|
+
},
|
|
144
|
+
// tfsec:ignore:rule[:exp:YYYY-MM-DD]
|
|
145
|
+
{
|
|
146
|
+
tool: "tfsec",
|
|
147
|
+
re: /#\s*tfsec:ignore:([A-Za-z0-9._-]+)(?::exp:(\d{4}-\d{2}-\d{2}))?\s*$/i,
|
|
148
|
+
},
|
|
149
|
+
// trivy:ignore:rule [exp:YYYY-MM-DD]
|
|
150
|
+
{
|
|
151
|
+
tool: "trivy",
|
|
152
|
+
re: /#\s*trivy:ignore:([A-Za-z0-9._\-*]+)(?:\s+exp:(\d{4}-\d{2}-\d{2}))?\s*$/i,
|
|
153
|
+
},
|
|
154
|
+
];
|
|
155
|
+
|
|
156
|
+
/** A native scanner-skip directive with its source location — the line-aware shape
|
|
157
|
+
* behind both the suppression pipeline and the orphan-skip audit. */
|
|
158
|
+
export interface NativeSkip {
|
|
159
|
+
tool: string;
|
|
160
|
+
/** namespaced rule, e.g. "checkov:CKV_AWS_20" — matches a concern's `rule_id`. */
|
|
161
|
+
rule: string;
|
|
162
|
+
reason: string;
|
|
163
|
+
expires: string | null;
|
|
164
|
+
file: string;
|
|
165
|
+
/** 1-based line of the directive. */
|
|
166
|
+
line: number;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Collect every native scanner-skip directive in a file, WITH line numbers. The
|
|
170
|
+
* single source of truth for native-skip parsing (used by the suppression pipeline
|
|
171
|
+
* and the orphan-skip audit). At most one directive per line. */
|
|
172
|
+
export function collectNativeSkips(
|
|
173
|
+
content: string,
|
|
174
|
+
file: string,
|
|
175
|
+
): NativeSkip[] {
|
|
176
|
+
const out: NativeSkip[] = [];
|
|
177
|
+
const lines = content.split(/\r?\n/);
|
|
178
|
+
for (let i = 0; i < lines.length; i++) {
|
|
179
|
+
const line = lines[i] ?? "";
|
|
180
|
+
for (const { tool, re } of NATIVE_PATTERNS) {
|
|
181
|
+
const m = line.match(re);
|
|
182
|
+
if (!m) continue;
|
|
183
|
+
const ruleId = (m[1] ?? "").trim();
|
|
184
|
+
if (!ruleId) break;
|
|
185
|
+
// checkov captures a reason in group 2; tfsec/trivy capture an expiry there.
|
|
186
|
+
// The reason is repo-authored free text — neutralised for the same reason
|
|
187
|
+
// as `parseInlineSuppressions` below, and it reaches one channel that form
|
|
188
|
+
// doesn't: `orphan_native_skips[].reason`, which is surfaced precisely
|
|
189
|
+
// because nothing else audits it.
|
|
190
|
+
const reason = tool === "checkov" ? neutralizeMarkup(m[2] ?? "") : "";
|
|
191
|
+
const expires = tool === "checkov" ? null : (m[2] ?? null);
|
|
192
|
+
out.push({
|
|
193
|
+
tool,
|
|
194
|
+
rule: `${tool}:${ruleId}`,
|
|
195
|
+
reason: reason || `Native ${tool} skip directive`,
|
|
196
|
+
expires,
|
|
197
|
+
file,
|
|
198
|
+
line: i + 1,
|
|
199
|
+
});
|
|
200
|
+
break; // at most one directive per line
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return out;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Parse native scanner skip directives (`#checkov:skip=…`, `#tfsec:ignore:…`,
|
|
208
|
+
* `#trivy:ignore:…`) into the unified `Suppression` shape so they can be honoured
|
|
209
|
+
* and audited alongside `#infraweaver:ignore`. Native skips don't mandate a reason
|
|
210
|
+
* (their tools don't), so a synthetic one records the provenance. The rule is
|
|
211
|
+
* namespaced (`checkov:CKV_AWS_20`) so it matches a surviving concern's `rule_id`.
|
|
212
|
+
*/
|
|
213
|
+
export function parseNativeSuppressions(
|
|
214
|
+
content: string,
|
|
215
|
+
file: string,
|
|
216
|
+
): ParsedSuppressions {
|
|
217
|
+
const suppressions: Suppression[] = collectNativeSkips(content, file).map(
|
|
218
|
+
(s) => ({
|
|
219
|
+
source: "inline",
|
|
220
|
+
tool: s.tool,
|
|
221
|
+
rule: s.rule,
|
|
222
|
+
reason: s.reason,
|
|
223
|
+
expires: s.expires,
|
|
224
|
+
paths: [],
|
|
225
|
+
file: s.file,
|
|
226
|
+
}),
|
|
227
|
+
);
|
|
228
|
+
return { suppressions, warnings: [] };
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Native skips that NO concern corresponds to — the owning scanner already dropped
|
|
233
|
+
* the finding (or the rule never fired), so the skip is invisible to Infraweaver's
|
|
234
|
+
* gate and posture. Surfacing these keeps scanner-native suppressions auditable
|
|
235
|
+
* (a `#checkov:skip` can silently hide a real issue forever). A skip "matches" a
|
|
236
|
+
* concern when its rule matches (exact / bare / `:suffix`) AND the file is the same.
|
|
237
|
+
* Canonical cross-rule matching (a trivy skip vs a checkov concern for the *same*
|
|
238
|
+
* issue) is a future taxonomy refinement — see `taxonomy.ts`.
|
|
239
|
+
*/
|
|
240
|
+
export function findOrphanNativeSkips(
|
|
241
|
+
skips: NativeSkip[],
|
|
242
|
+
concerns: Concern[],
|
|
243
|
+
): NativeSkip[] {
|
|
244
|
+
return skips.filter(
|
|
245
|
+
(s) =>
|
|
246
|
+
!concerns.some(
|
|
247
|
+
(c) => c.location.file === s.file && ruleMatches(s.rule, c),
|
|
248
|
+
),
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export interface NativeSkipAudit {
|
|
253
|
+
/** every native skip found in the scanned tree. */
|
|
254
|
+
skips: NativeSkip[];
|
|
255
|
+
/** the subset with no corresponding concern (the audit signal). */
|
|
256
|
+
orphans: NativeSkip[];
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Walk a file list, collect native skips, and partition them against the scan's
|
|
261
|
+
* concern set. `read` returns a file's content or null (missing). Pure given its
|
|
262
|
+
* inputs, so it's unit-testable without a real tree.
|
|
263
|
+
*/
|
|
264
|
+
export function auditNativeSkips(
|
|
265
|
+
files: string[],
|
|
266
|
+
concerns: Concern[],
|
|
267
|
+
read: (relPath: string) => string | null,
|
|
268
|
+
): NativeSkipAudit {
|
|
269
|
+
const skips: NativeSkip[] = [];
|
|
270
|
+
for (const f of files) {
|
|
271
|
+
const content = read(f);
|
|
272
|
+
if (content === null) continue;
|
|
273
|
+
skips.push(...collectNativeSkips(content, f));
|
|
274
|
+
}
|
|
275
|
+
return { skips, orphans: findOrphanNativeSkips(skips, concerns) };
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
interface RawPolicyEntry {
|
|
279
|
+
rule?: unknown;
|
|
280
|
+
reason?: unknown;
|
|
281
|
+
expires?: unknown;
|
|
282
|
+
paths?: unknown;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function normalizePaths(value: unknown): string[] {
|
|
286
|
+
if (typeof value === "string") {
|
|
287
|
+
return value
|
|
288
|
+
.split(/[\n,]/)
|
|
289
|
+
.map((s) => s.trim())
|
|
290
|
+
.filter(Boolean);
|
|
291
|
+
}
|
|
292
|
+
if (Array.isArray(value)) {
|
|
293
|
+
return value
|
|
294
|
+
.filter((v): v is string => typeof v === "string")
|
|
295
|
+
.map((v) => v.trim())
|
|
296
|
+
.filter(Boolean);
|
|
297
|
+
}
|
|
298
|
+
return [];
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export function parseSuppressionPolicy(
|
|
302
|
+
raw: string,
|
|
303
|
+
format: "yaml" | "json",
|
|
304
|
+
): ParsedSuppressions {
|
|
305
|
+
const label = format === "json" ? CONFIG_FILE_JSON : CONFIG_FILE;
|
|
306
|
+
const suppressions: Suppression[] = [];
|
|
307
|
+
const warnings: string[] = [];
|
|
308
|
+
let doc: unknown;
|
|
309
|
+
try {
|
|
310
|
+
if (format === "json") {
|
|
311
|
+
if (raw.trim() === "") return { suppressions, warnings };
|
|
312
|
+
doc = JSON.parse(raw);
|
|
313
|
+
} else {
|
|
314
|
+
doc = parseYaml(raw);
|
|
315
|
+
}
|
|
316
|
+
} catch {
|
|
317
|
+
return { suppressions, warnings };
|
|
318
|
+
}
|
|
319
|
+
if (!doc || typeof doc !== "object" || Array.isArray(doc))
|
|
320
|
+
return { suppressions, warnings };
|
|
321
|
+
const block = (doc as Record<string, unknown>).suppressions;
|
|
322
|
+
if (block === undefined) return { suppressions, warnings };
|
|
323
|
+
if (!Array.isArray(block)) {
|
|
324
|
+
warnings.push(
|
|
325
|
+
`${label}: "suppressions" must be a list of { rule, reason } entries — ignored`,
|
|
326
|
+
);
|
|
327
|
+
return { suppressions, warnings };
|
|
328
|
+
}
|
|
329
|
+
block.forEach((entry, idx) => {
|
|
330
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
331
|
+
warnings.push(
|
|
332
|
+
`${label}: suppressions[${idx}] must be a mapping — ignored`,
|
|
333
|
+
);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
const e = entry as RawPolicyEntry;
|
|
337
|
+
const rule = typeof e.rule === "string" ? e.rule.trim() : "";
|
|
338
|
+
// Neutralised like the two inline forms above, so all three suppression
|
|
339
|
+
// sources are treated identically at their parse point. This one is
|
|
340
|
+
// base-ref-read (a fork PR cannot introduce it), but it is the only form
|
|
341
|
+
// that can carry a multi-line YAML scalar — exactly the shape that renders
|
|
342
|
+
// as its own section in a PR body.
|
|
343
|
+
const reason =
|
|
344
|
+
typeof e.reason === "string" ? neutralizeMarkup(e.reason) : "";
|
|
345
|
+
if (!rule || !reason) {
|
|
346
|
+
warnings.push(
|
|
347
|
+
`${label}: suppressions[${idx}] needs a non-empty "rule" and "reason" — ignored`,
|
|
348
|
+
);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
let expires: string | null = null;
|
|
352
|
+
if (e.expires !== undefined && e.expires !== null) {
|
|
353
|
+
const exp = String(e.expires).trim();
|
|
354
|
+
if (!ISO_DATE.test(exp)) {
|
|
355
|
+
warnings.push(
|
|
356
|
+
`${label}: suppressions[${idx}] "expires" must be YYYY-MM-DD — entry ignored`,
|
|
357
|
+
);
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
expires = exp;
|
|
361
|
+
}
|
|
362
|
+
suppressions.push({
|
|
363
|
+
source: "policy",
|
|
364
|
+
rule,
|
|
365
|
+
reason,
|
|
366
|
+
expires,
|
|
367
|
+
paths: normalizePaths(e.paths),
|
|
368
|
+
file: null,
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
return { suppressions, warnings };
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export function loadSuppressionPolicy(
|
|
375
|
+
cwd: string | undefined,
|
|
376
|
+
): ParsedSuppressions {
|
|
377
|
+
const root = cwd ?? process.cwd();
|
|
378
|
+
for (const name of INFRAWEAVER_CONFIG_FILENAMES) {
|
|
379
|
+
let raw: string;
|
|
380
|
+
try {
|
|
381
|
+
raw = readFileSync(join(root, name), "utf-8");
|
|
382
|
+
} catch {
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
return parseSuppressionPolicy(
|
|
386
|
+
raw,
|
|
387
|
+
name.endsWith(".json") ? "json" : "yaml",
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
return { suppressions: [], warnings: [] };
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* The suppression policy that APPLIES to this run.
|
|
395
|
+
*
|
|
396
|
+
* On a pull-request run the `suppressions:` block is read from the **base ref**,
|
|
397
|
+
* not the PR's head: a waiver is an accepted risk, and accepting it is exactly
|
|
398
|
+
* what the review is for. Letting a PR silence the finding that would otherwise
|
|
399
|
+
* block it is the self-approval hole the two-person SoD on waivers (§5.3) exists
|
|
400
|
+
* to close — this closes the file-shaped version of it. A PR that adds a waiver
|
|
401
|
+
* still sees the finding; the waiver applies from the next run on the merged base.
|
|
402
|
+
*
|
|
403
|
+
* Everything degrades to the head value with a warning when the base ref can't
|
|
404
|
+
* be read (shallow clone) or the run isn't a PR — stated, never silent.
|
|
405
|
+
*/
|
|
406
|
+
export function loadSuppressionPolicyForRun(
|
|
407
|
+
cwd: string | undefined,
|
|
408
|
+
): ParsedSuppressions {
|
|
409
|
+
const root = cwd ?? process.cwd();
|
|
410
|
+
const baseRef = process.env.GITHUB_BASE_REF?.trim() || undefined;
|
|
411
|
+
if (!baseRef) return loadSuppressionPolicy(root);
|
|
412
|
+
|
|
413
|
+
const source = readConfigAtBaseRef(root, baseRef);
|
|
414
|
+
if (source.kind === "unavailable") {
|
|
415
|
+
const head = loadSuppressionPolicy(root);
|
|
416
|
+
if (head.suppressions.length > 0) {
|
|
417
|
+
head.warnings.push(
|
|
418
|
+
`could not read the base ref (${baseRef}) to resolve the suppression policy — applying ` +
|
|
419
|
+
`this ref's ${head.suppressions.length} suppression(s). A shallow clone causes this; ` +
|
|
420
|
+
"`fetch-depth: 0` (or fetching the base branch) restores the check.",
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
return head;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const base =
|
|
427
|
+
source.kind === "file"
|
|
428
|
+
? parseSuppressionPolicy(source.raw, source.format)
|
|
429
|
+
: { suppressions: [], warnings: [] };
|
|
430
|
+
const headCount = loadSuppressionPolicy(root).suppressions.length;
|
|
431
|
+
if (headCount !== base.suppressions.length) {
|
|
432
|
+
base.warnings.push(
|
|
433
|
+
`the suppression policy differs from the base ref (${source.ref}) — applying the BASE ` +
|
|
434
|
+
`policy (${base.suppressions.length} entry/entries, not ${headCount}) so this change ` +
|
|
435
|
+
"cannot waive the findings reviewing it. It takes effect once merged.",
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
return base;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function toIsoDate(d: Date): string {
|
|
442
|
+
return d.toISOString().slice(0, 10);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function isActive(s: Suppression, now: Date): boolean {
|
|
446
|
+
if (!s.expires) return true;
|
|
447
|
+
return s.expires >= toIsoDate(now);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function ruleMatches(rule: string, concern: Concern): boolean {
|
|
451
|
+
const wanted = rule.toLowerCase();
|
|
452
|
+
const ruleId = concern.rule_id.toLowerCase();
|
|
453
|
+
if (ruleId === wanted) return true;
|
|
454
|
+
const prefix = `${concern.source.toLowerCase()}:`;
|
|
455
|
+
const bare = ruleId.startsWith(prefix) ? ruleId.slice(prefix.length) : ruleId;
|
|
456
|
+
if (bare === wanted) return true;
|
|
457
|
+
return ruleId.endsWith(`:${wanted}`);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function scopeMatches(s: Suppression, file: string): boolean {
|
|
461
|
+
if (s.source === "inline") return s.file === file;
|
|
462
|
+
if (s.paths.length === 0) return true;
|
|
463
|
+
return isPathAllowed(file, s.paths);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function matches(s: Suppression, concern: Concern, now: Date): boolean {
|
|
467
|
+
return (
|
|
468
|
+
isActive(s, now) &&
|
|
469
|
+
ruleMatches(s.rule, concern) &&
|
|
470
|
+
scopeMatches(s, concern.location.file)
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export interface ApplySuppressionsOptions {
|
|
475
|
+
policy: Suppression[];
|
|
476
|
+
cwd: string;
|
|
477
|
+
now?: Date;
|
|
478
|
+
readFile?: (relPath: string) => string | null;
|
|
479
|
+
onWarn?: (warning: string) => void;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
export function applySuppressions(
|
|
483
|
+
concerns: Concern[],
|
|
484
|
+
opts: ApplySuppressionsOptions,
|
|
485
|
+
): Concern[] {
|
|
486
|
+
const now = opts.now ?? new Date();
|
|
487
|
+
const read = opts.readFile ?? ((rel) => defaultRead(opts.cwd, rel));
|
|
488
|
+
const inlineByFile = new Map<string, Suppression[]>();
|
|
489
|
+
|
|
490
|
+
const inlineFor = (file: string): Suppression[] => {
|
|
491
|
+
const cached = inlineByFile.get(file);
|
|
492
|
+
if (cached) return cached;
|
|
493
|
+
const content = read(file);
|
|
494
|
+
const parsed =
|
|
495
|
+
content === null ? [] : collectInline(content, file, opts.onWarn);
|
|
496
|
+
inlineByFile.set(file, parsed);
|
|
497
|
+
return parsed;
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
return concerns.map((concern) => {
|
|
501
|
+
const candidates = [...inlineFor(concern.location.file), ...opts.policy];
|
|
502
|
+
const hit = candidates.find((s) => matches(s, concern, now));
|
|
503
|
+
if (!hit) return concern;
|
|
504
|
+
return {
|
|
505
|
+
...concern,
|
|
506
|
+
// A native skip keeps source "inline" (it IS an inline directive) but tags its
|
|
507
|
+
// scanner provenance into the reason so the audit trail shows where it came from.
|
|
508
|
+
suppression: {
|
|
509
|
+
source: hit.source,
|
|
510
|
+
reason: hit.tool ? `${hit.reason} [via ${hit.tool} skip]` : hit.reason,
|
|
511
|
+
expires: hit.expires,
|
|
512
|
+
},
|
|
513
|
+
};
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
function collectInline(
|
|
518
|
+
content: string,
|
|
519
|
+
file: string,
|
|
520
|
+
onWarn: ((warning: string) => void) | undefined,
|
|
521
|
+
): Suppression[] {
|
|
522
|
+
const inline = parseInlineSuppressions(content, file);
|
|
523
|
+
// Also fold in native scanner skips so they're honoured + audited in one pipeline.
|
|
524
|
+
const native = parseNativeSuppressions(content, file);
|
|
525
|
+
if (onWarn)
|
|
526
|
+
for (const w of [...inline.warnings, ...native.warnings]) onWarn(w);
|
|
527
|
+
return [...inline.suppressions, ...native.suppressions];
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
function defaultRead(cwd: string, rel: string): string | null {
|
|
531
|
+
try {
|
|
532
|
+
return readFileSync(join(cwd, rel), "utf-8");
|
|
533
|
+
} catch {
|
|
534
|
+
return null;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
export function suppressConcerns(
|
|
539
|
+
concerns: Concern[],
|
|
540
|
+
cwd: string,
|
|
541
|
+
now?: Date,
|
|
542
|
+
): Concern[] {
|
|
543
|
+
const { suppressions, warnings } = loadSuppressionPolicyForRun(cwd);
|
|
544
|
+
for (const w of warnings) log.warning(`» ${w}`);
|
|
545
|
+
return applySuppressions(concerns, {
|
|
546
|
+
policy: suppressions,
|
|
547
|
+
cwd,
|
|
548
|
+
...(now ? { now } : {}),
|
|
549
|
+
onWarn: (w) => log.warning(`» ${w}`),
|
|
550
|
+
});
|
|
551
|
+
}
|
|
Binary file
|