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,723 @@
|
|
|
1
|
+
import { type } from "arktype";
|
|
2
|
+
import { COMMENT_COMMAND, PRODUCT_NAME } from "#app/brand";
|
|
3
|
+
import { buildCrosswalkReport, type CrosswalkReport } from "#app/mcp/crosswalk";
|
|
4
|
+
import {
|
|
5
|
+
cyberEssentialsControlsAtRisk,
|
|
6
|
+
cyberEssentialsScore,
|
|
7
|
+
} from "#app/mcp/cyberEssentials";
|
|
8
|
+
import type { LocalToolContext } from "#app/mcp/localContext";
|
|
9
|
+
import { execute, tool, toolOk } from "#app/mcp/shared";
|
|
10
|
+
import {
|
|
11
|
+
type BaselineDelta,
|
|
12
|
+
baselineDelta,
|
|
13
|
+
loadBaselineWithMeta,
|
|
14
|
+
} from "#app/mcp/terraform/baseline";
|
|
15
|
+
import {
|
|
16
|
+
applyScannerAvailability,
|
|
17
|
+
checkovFrameworksFor,
|
|
18
|
+
detectIacLanguages,
|
|
19
|
+
type IacLanguage,
|
|
20
|
+
inLanguageScope,
|
|
21
|
+
LANGUAGE_LABEL,
|
|
22
|
+
type LanguageScope,
|
|
23
|
+
languageOfConcern,
|
|
24
|
+
resolveLanguageScope,
|
|
25
|
+
} from "#app/mcp/terraform/iacLanguages";
|
|
26
|
+
import { scanSessionOf } from "#app/mcp/terraform/scanSession";
|
|
27
|
+
import { attachSourceSnippets, runScanners } from "#app/mcp/terraform/scanners";
|
|
28
|
+
import { suppressConcerns } from "#app/mcp/terraform/suppressions";
|
|
29
|
+
import {
|
|
30
|
+
type Concern,
|
|
31
|
+
dedupe,
|
|
32
|
+
type ScannerOutcome,
|
|
33
|
+
SEVERITY_RANK,
|
|
34
|
+
type Severity,
|
|
35
|
+
sortConcerns,
|
|
36
|
+
} from "#app/mcp/terraform/types";
|
|
37
|
+
import {
|
|
38
|
+
buildVerificationSummary,
|
|
39
|
+
type VerificationSummary,
|
|
40
|
+
} from "#app/mcp/terraform/verification";
|
|
41
|
+
import { log } from "#app/utils/cli";
|
|
42
|
+
import { resolveModuleCredentialEnv } from "#app/utils/registryAuth";
|
|
43
|
+
import {
|
|
44
|
+
type ResolvedToolSelection,
|
|
45
|
+
resolveToolSelection,
|
|
46
|
+
} from "#app/utils/toolSelection";
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Assess pillar — the read-only product. Infraweaver's scanner
|
|
50
|
+
* engine has two modes off ONE codebase: Remediate = engine + fix loop + verify;
|
|
51
|
+
* **Assess = engine, read-only**. This surfaces that read-only half as a
|
|
52
|
+
* first-class deliverable: run the deterministic scanners, normalise into the
|
|
53
|
+
* findings schema, map to the compliance crosswalk, and produce a
|
|
54
|
+
* **scorecard** + an auditor-facing markdown report — WITHOUT touching the
|
|
55
|
+
* Terraform or opening a PR. No cloud credentials, no writes.
|
|
56
|
+
*
|
|
57
|
+
* The scorecard is deterministic (computed from tool results, never the model's
|
|
58
|
+
* word) so a CI gate can branch on `posture` and an assessor gets a reproducible,
|
|
59
|
+
* framework-mapped report.
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
export type AssessPosture = "clean" | "advisory" | "action-required";
|
|
63
|
+
|
|
64
|
+
export interface AssessTopRisk {
|
|
65
|
+
rule_id: string;
|
|
66
|
+
severity: Severity;
|
|
67
|
+
file: string;
|
|
68
|
+
line: number | null;
|
|
69
|
+
evidence: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** A finding a human explicitly accepted (a suppression with a mandatory reason).
|
|
73
|
+
* Surfaced as the report's audit trail — who waived what, why, and until when. */
|
|
74
|
+
export interface AssessWaiver {
|
|
75
|
+
rule_id: string;
|
|
76
|
+
severity: Severity;
|
|
77
|
+
file: string;
|
|
78
|
+
line: number | null;
|
|
79
|
+
reason: string;
|
|
80
|
+
source: "inline" | "policy";
|
|
81
|
+
expires: string | null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Per-language breadth line for the multi-language Assess scorecard. Honest by
|
|
85
|
+
* construction: a language is either `scanned` (a scanner covered it) or listed
|
|
86
|
+
* in `unsupported` (detected, but no static scanner can assess it — e.g. Pulumi),
|
|
87
|
+
* never silently dropped. `by_language` counts OPEN concerns per scanned language. */
|
|
88
|
+
export interface AssessmentLanguages {
|
|
89
|
+
/** every IaC language detected in the tree (superset of scanned + unsupported). */
|
|
90
|
+
detected: IacLanguage[];
|
|
91
|
+
/** languages this run reported on (scope ∩ what a scanner can read). */
|
|
92
|
+
scanned: IacLanguage[];
|
|
93
|
+
/** file count per detected language — the breadth signal. */
|
|
94
|
+
file_counts: Partial<Record<IacLanguage, number>>;
|
|
95
|
+
/** open-concern count per scanned language (0 for a clean language). */
|
|
96
|
+
by_language: Partial<Record<IacLanguage, number>>;
|
|
97
|
+
/** detected languages NO installed scanner can statically assess — surfaced,
|
|
98
|
+
* never scanned-and-silent (each with the honest reason). */
|
|
99
|
+
unsupported: { language: IacLanguage; reason: string }[];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface AssessmentScorecard {
|
|
103
|
+
/** clean (0 concerns) · advisory (only medium/low/info) · action-required (≥1 critical/high). */
|
|
104
|
+
posture: AssessPosture;
|
|
105
|
+
total: number;
|
|
106
|
+
by_severity: Record<Severity, number>;
|
|
107
|
+
/** multi-language breadth: which IaC languages were detected/scanned/unsupported
|
|
108
|
+
* and the open-concern count per scanned language. Terraform-only trees still
|
|
109
|
+
* report here (just one scanned language). */
|
|
110
|
+
languages: AssessmentLanguages;
|
|
111
|
+
/** highest-severity concerns first, capped — the "what to look at first" list. */
|
|
112
|
+
top_risks: AssessTopRisk[];
|
|
113
|
+
compliance: {
|
|
114
|
+
/** frameworks this scan touched (from the crosswalk's by_framework index). */
|
|
115
|
+
frameworks: string[];
|
|
116
|
+
/** distinct controls touched across all frameworks. */
|
|
117
|
+
controls_touched: number;
|
|
118
|
+
/** concerns that mapped to ≥1 control vs none (honest coverage signal). */
|
|
119
|
+
mapped: number;
|
|
120
|
+
unmapped: number;
|
|
121
|
+
version: string;
|
|
122
|
+
reviewed: string;
|
|
123
|
+
};
|
|
124
|
+
/** Cyber Essentials posture (0–100, indicative) + the distinct CE controls the
|
|
125
|
+
* OPEN concerns leave at risk — the report headline a CISO reads first. */
|
|
126
|
+
cyber_essentials: {
|
|
127
|
+
score: number;
|
|
128
|
+
controls_at_risk: string[];
|
|
129
|
+
};
|
|
130
|
+
/** findings a human explicitly accepted — the report's de-emphasised audit
|
|
131
|
+
* trail (excluded from posture/counts above; an expired waiver auto-resurfaces). */
|
|
132
|
+
waivers: AssessWaiver[];
|
|
133
|
+
/** five-status verification taxonomy: per-concern fail / not-code-verifiable +
|
|
134
|
+
* the scanner coverage (verified vs inconclusive). Keeps a "clean" posture
|
|
135
|
+
* honest — e.g. "clean, but tflint inconclusive (not run)". */
|
|
136
|
+
verification: VerificationSummary;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** posture from the severity distribution: any critical/high ⇒ action-required;
|
|
140
|
+
* any lower-severity concern ⇒ advisory; nothing ⇒ clean. */
|
|
141
|
+
export function assessPosture(
|
|
142
|
+
bySeverity: Record<Severity, number>,
|
|
143
|
+
): AssessPosture {
|
|
144
|
+
if (bySeverity.critical > 0 || bySeverity.high > 0) return "action-required";
|
|
145
|
+
if (bySeverity.medium > 0 || bySeverity.low > 0 || bySeverity.info > 0)
|
|
146
|
+
return "advisory";
|
|
147
|
+
return "clean";
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const TOP_RISK_CAP = 10;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Build the deterministic assessment scorecard from a scan's concerns + their
|
|
154
|
+
* crosswalk report. Pure. `concerns` is the OPEN (non-suppressed) severity-sorted,
|
|
155
|
+
* deduped, Terraform-only set — posture, counts and the CE score reflect only what
|
|
156
|
+
* is unresolved; `suppressed` carries the accepted findings for the audit trail.
|
|
157
|
+
* `crosswalk` is `buildCrosswalkReport(concerns)`.
|
|
158
|
+
*/
|
|
159
|
+
export function buildAssessment(
|
|
160
|
+
concerns: Concern[],
|
|
161
|
+
crosswalk: CrosswalkReport,
|
|
162
|
+
verification: VerificationSummary,
|
|
163
|
+
suppressed: Concern[] = [],
|
|
164
|
+
languageScope?: LanguageScope,
|
|
165
|
+
): AssessmentScorecard {
|
|
166
|
+
const by_severity: Record<Severity, number> = {
|
|
167
|
+
critical: 0,
|
|
168
|
+
high: 0,
|
|
169
|
+
medium: 0,
|
|
170
|
+
low: 0,
|
|
171
|
+
info: 0,
|
|
172
|
+
};
|
|
173
|
+
for (const c of concerns) by_severity[c.severity]++;
|
|
174
|
+
|
|
175
|
+
// Multi-language breadth. Default (no scope supplied) = the historical
|
|
176
|
+
// Terraform-only shape, so every existing caller/test keeps a single scanned
|
|
177
|
+
// language without change.
|
|
178
|
+
const by_language: Partial<Record<IacLanguage, number>> = {};
|
|
179
|
+
for (const c of concerns) {
|
|
180
|
+
const lang = languageOfConcern(c);
|
|
181
|
+
by_language[lang] = (by_language[lang] ?? 0) + 1;
|
|
182
|
+
}
|
|
183
|
+
const languages: AssessmentLanguages = languageScope
|
|
184
|
+
? {
|
|
185
|
+
detected: languageScope.detected,
|
|
186
|
+
scanned: languageScope.scanned,
|
|
187
|
+
file_counts: languageScope.fileCounts,
|
|
188
|
+
by_language,
|
|
189
|
+
unsupported: languageScope.unsupported,
|
|
190
|
+
}
|
|
191
|
+
: {
|
|
192
|
+
detected: ["terraform"],
|
|
193
|
+
scanned: ["terraform"],
|
|
194
|
+
file_counts: {},
|
|
195
|
+
by_language,
|
|
196
|
+
unsupported: [],
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const top_risks = [...concerns]
|
|
200
|
+
.sort((a, b) => SEVERITY_RANK[b.severity] - SEVERITY_RANK[a.severity])
|
|
201
|
+
.slice(0, TOP_RISK_CAP)
|
|
202
|
+
.map((c) => ({
|
|
203
|
+
rule_id: c.rule_id,
|
|
204
|
+
severity: c.severity,
|
|
205
|
+
file: c.location.file,
|
|
206
|
+
line: c.location.line,
|
|
207
|
+
evidence: c.evidence,
|
|
208
|
+
}));
|
|
209
|
+
|
|
210
|
+
const controls_touched = Object.values(crosswalk.by_framework).reduce(
|
|
211
|
+
(n, controls) => n + controls.length,
|
|
212
|
+
0,
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
const waivers: AssessWaiver[] = suppressed
|
|
216
|
+
.filter((c) => c.suppression)
|
|
217
|
+
.map((c) => ({
|
|
218
|
+
rule_id: c.rule_id,
|
|
219
|
+
severity: c.severity,
|
|
220
|
+
file: c.location.file,
|
|
221
|
+
line: c.location.line,
|
|
222
|
+
reason: c.suppression?.reason ?? "",
|
|
223
|
+
source: c.suppression?.source ?? "policy",
|
|
224
|
+
expires: c.suppression?.expires ?? null,
|
|
225
|
+
}));
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
posture: assessPosture(by_severity),
|
|
229
|
+
total: concerns.length,
|
|
230
|
+
by_severity,
|
|
231
|
+
languages,
|
|
232
|
+
top_risks,
|
|
233
|
+
compliance: {
|
|
234
|
+
frameworks: Object.keys(crosswalk.by_framework),
|
|
235
|
+
controls_touched,
|
|
236
|
+
mapped: crosswalk.entries.length,
|
|
237
|
+
unmapped: crosswalk.unmapped_concern_ids.length,
|
|
238
|
+
version: crosswalk.version,
|
|
239
|
+
reviewed: crosswalk.reviewed,
|
|
240
|
+
},
|
|
241
|
+
cyber_essentials: {
|
|
242
|
+
score: cyberEssentialsScore(concerns),
|
|
243
|
+
controls_at_risk: cyberEssentialsControlsAtRisk(concerns),
|
|
244
|
+
},
|
|
245
|
+
waivers,
|
|
246
|
+
verification,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const POSTURE_BANNER: Record<AssessPosture, string> = {
|
|
251
|
+
clean:
|
|
252
|
+
"> [!NOTE]\n> ✅ **Clean** — no best-practice concerns found at the configured threshold.",
|
|
253
|
+
advisory:
|
|
254
|
+
"> [!WARNING]\n> ⚠️ **Advisory** — concerns found, but none critical/high. Plan to address them.",
|
|
255
|
+
"action-required":
|
|
256
|
+
"> [!CAUTION]\n> 🚨 **Action required** — critical/high-severity concerns found. Review before relying on this Terraform.",
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
/** Optional render-time context the scorecard can't hold on its own. `delta` is
|
|
260
|
+
* the run-to-run change vs the committed baseline checkpoint (null when no
|
|
261
|
+
* baseline exists — there's nothing to compare against). */
|
|
262
|
+
export interface AssessRenderContext {
|
|
263
|
+
delta?: { delta: BaselineDelta; since: string | null } | null;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** The Cyber Essentials posture headline — the CISO-facing number the report
|
|
267
|
+
* leads with (mirrors a "Failed (22%)"-style lead, but as a 0–100 score). */
|
|
268
|
+
function renderCyberEssentialsHeadline(s: AssessmentScorecard): string {
|
|
269
|
+
const { score, controls_at_risk } = s.cyber_essentials;
|
|
270
|
+
const atRisk = controls_at_risk.length
|
|
271
|
+
? `${controls_at_risk.length} control(s) at risk: ${controls_at_risk.join(", ")}`
|
|
272
|
+
: "no mapped controls at risk";
|
|
273
|
+
return `> **Cyber Essentials posture: ${score} / 100** (indicative) — ${atRisk}.`;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** The run-to-run delta line — what changed since the baseline checkpoint.
|
|
277
|
+
* Reads "no status changes" when nothing was added or fixed, mirroring the
|
|
278
|
+
* push-to-push signal reviewers expect. */
|
|
279
|
+
function renderDeltaLine(delta: BaselineDelta, since: string | null): string {
|
|
280
|
+
const ref = since ? `baseline (${since})` : "baseline";
|
|
281
|
+
if (delta.added === 0 && delta.fixed === 0) {
|
|
282
|
+
return `**Since ${ref}:** no status changes — ${delta.unchanged} carried.`;
|
|
283
|
+
}
|
|
284
|
+
return (
|
|
285
|
+
`**Since ${ref}:** 🔺 ${delta.added} new · ✅ ${delta.fixed} fixed · ` +
|
|
286
|
+
`${delta.unchanged} unchanged.`
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** The accepted/waived findings audit trail — de-emphasised (collapsed), kept out
|
|
291
|
+
* of the posture above, and honest that an expired waiver resurfaces the finding. */
|
|
292
|
+
function renderWaiverBlock(waivers: AssessWaiver[]): string[] {
|
|
293
|
+
const lines: string[] = [];
|
|
294
|
+
lines.push(
|
|
295
|
+
`<details><summary>🤝 Accepted / waived findings (${waivers.length})</summary>`,
|
|
296
|
+
);
|
|
297
|
+
lines.push("");
|
|
298
|
+
lines.push(
|
|
299
|
+
"Explicitly accepted by a human (a suppression with a mandatory reason). " +
|
|
300
|
+
"These do **not** affect the posture above; an expired waiver auto-resurfaces the finding.",
|
|
301
|
+
);
|
|
302
|
+
lines.push("");
|
|
303
|
+
for (const w of waivers) {
|
|
304
|
+
const loc = w.line !== null ? `\`${w.file}:${w.line}\`` : `\`${w.file}\``;
|
|
305
|
+
const expiry = w.expires ? `expires ${w.expires}` : "no expiry";
|
|
306
|
+
lines.push(
|
|
307
|
+
`- ${severityEmoji(w.severity)} \`${w.rule_id}\` — ${loc} — ${w.reason} ` +
|
|
308
|
+
`(source: ${w.source}, ${expiry})`,
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
lines.push("");
|
|
312
|
+
lines.push("</details>");
|
|
313
|
+
return lines;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/** The in-comment "fix it from here" call-to-action — names the exact
|
|
317
|
+
* `@infraweaver fix …` comment commands a reviewer can post to dispatch a scoped,
|
|
318
|
+
* `✗→✓`-verified remediation PR (the comment-trigger surface; it never merges).
|
|
319
|
+
* Only rendered when there's something open to fix. */
|
|
320
|
+
function renderRemediationCta(): string[] {
|
|
321
|
+
return [
|
|
322
|
+
"> [!TIP]",
|
|
323
|
+
`> **Fix it from here** — comment one of these and ${PRODUCT_NAME} opens a scoped PR that proves ` +
|
|
324
|
+
"each concern cleared (`✗→✓`) for your review (it never merges):",
|
|
325
|
+
">",
|
|
326
|
+
`> - \`${COMMENT_COMMAND} fix all high-severity\` — every concern at/above a severity`,
|
|
327
|
+
`> - \`${COMMENT_COMMAND} fix #<id>\` — a single finding (the id from Top risks)`,
|
|
328
|
+
`> - \`${COMMENT_COMMAND} fix <file>\` — one file's group`,
|
|
329
|
+
`> - \`${COMMENT_COMMAND} fix all\` — everything (bounded by \`max_prs\`)`,
|
|
330
|
+
];
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* The multi-language breadth section. Renders ONLY when there's something worth
|
|
335
|
+
* saying — Assess scanned a non-Terraform language, or a detected language could
|
|
336
|
+
* not be scanned (the honest coverage gap). A pure Terraform tree returns [] so
|
|
337
|
+
* the report is byte-for-byte unchanged. Deterministic; language order matches
|
|
338
|
+
* `scanned` (most files first). Pure.
|
|
339
|
+
*/
|
|
340
|
+
function renderLanguageBlock(langs: AssessmentLanguages): string[] {
|
|
341
|
+
const nonTf = langs.scanned.filter((l) => l !== "terraform");
|
|
342
|
+
if (nonTf.length === 0 && langs.unsupported.length === 0) return [];
|
|
343
|
+
|
|
344
|
+
const lines: string[] = ["### IaC languages scanned", ""];
|
|
345
|
+
const cells = langs.scanned.map((l) => {
|
|
346
|
+
const n = langs.by_language[l] ?? 0;
|
|
347
|
+
return `\`${LANGUAGE_LABEL[l]}: ${n}\``;
|
|
348
|
+
});
|
|
349
|
+
lines.push(
|
|
350
|
+
`Assess is Terraform-first but reads every IaC language your scanners parse. ` +
|
|
351
|
+
`Scanned **${langs.scanned.length}** language(s): ${cells.join(" · ")}.`,
|
|
352
|
+
);
|
|
353
|
+
// Remediate scope caveat — the moat line, stated plainly so a reader never
|
|
354
|
+
// mistakes multi-language Assess for multi-language auto-fix.
|
|
355
|
+
if (nonTf.length > 0) {
|
|
356
|
+
lines.push("");
|
|
357
|
+
lines.push(
|
|
358
|
+
`> Findings outside Terraform are **assessed, not auto-remediated** — the proven \`✗→✓\` fix loop ` +
|
|
359
|
+
`is Terraform-specific. Fix non-Terraform findings by hand using the guidance above.`,
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
if (langs.unsupported.length > 0) {
|
|
363
|
+
lines.push("");
|
|
364
|
+
lines.push("> [!WARNING]");
|
|
365
|
+
lines.push(
|
|
366
|
+
"> **Detected but not assessed** (no static scanner covers these — a coverage gap, not a pass):",
|
|
367
|
+
);
|
|
368
|
+
for (const u of langs.unsupported) {
|
|
369
|
+
lines.push(`> - \`${LANGUAGE_LABEL[u.language]}\` — ${u.reason}`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return lines;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Render the scorecard as a deterministic, auditor-facing markdown report (the
|
|
377
|
+
* Assess deliverable). Built entirely from the scorecard so it's reproducible and
|
|
378
|
+
* model-independent. Pure.
|
|
379
|
+
*/
|
|
380
|
+
export function renderAssessmentMarkdown(
|
|
381
|
+
s: AssessmentScorecard,
|
|
382
|
+
ctx: AssessRenderContext = {},
|
|
383
|
+
): string {
|
|
384
|
+
const lines: string[] = [];
|
|
385
|
+
lines.push(POSTURE_BANNER[s.posture]);
|
|
386
|
+
lines.push("");
|
|
387
|
+
lines.push(renderCyberEssentialsHeadline(s));
|
|
388
|
+
lines.push("");
|
|
389
|
+
// Title reflects the breadth honestly: "Terraform" when that's all that was
|
|
390
|
+
// scanned (the common case), "IaC" when Assess widened to other languages.
|
|
391
|
+
const multiLang = s.languages.scanned.some((l) => l !== "terraform");
|
|
392
|
+
lines.push(`## ${multiLang ? "IaC" : "Terraform"} best-practice assessment`);
|
|
393
|
+
lines.push("");
|
|
394
|
+
const sevOrder: Severity[] = ["critical", "high", "medium", "low", "info"];
|
|
395
|
+
const sevCells = sevOrder
|
|
396
|
+
.filter((sev) => s.by_severity[sev] > 0)
|
|
397
|
+
.map((sev) => `\`${sev}: ${s.by_severity[sev]}\``);
|
|
398
|
+
lines.push(
|
|
399
|
+
`**${s.total} concern${s.total === 1 ? "" : "s"}** — ${
|
|
400
|
+
sevCells.length ? sevCells.join(" · ") : "none"
|
|
401
|
+
}`,
|
|
402
|
+
);
|
|
403
|
+
if (ctx.delta) {
|
|
404
|
+
lines.push("");
|
|
405
|
+
lines.push(renderDeltaLine(ctx.delta.delta, ctx.delta.since));
|
|
406
|
+
}
|
|
407
|
+
lines.push("");
|
|
408
|
+
|
|
409
|
+
// Multi-language breadth — only when Assess widened past Terraform, or when a
|
|
410
|
+
// detected language couldn't be scanned (the honest coverage gap). A pure
|
|
411
|
+
// Terraform tree keeps the report exactly as before.
|
|
412
|
+
const langBlock = renderLanguageBlock(s.languages);
|
|
413
|
+
if (langBlock.length > 0) {
|
|
414
|
+
lines.push(...langBlock);
|
|
415
|
+
lines.push("");
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (s.top_risks.length > 0) {
|
|
419
|
+
lines.push("### Top risks");
|
|
420
|
+
lines.push("");
|
|
421
|
+
for (const r of s.top_risks) {
|
|
422
|
+
const loc = r.line !== null ? `\`${r.file}:${r.line}\`` : `\`${r.file}\``;
|
|
423
|
+
lines.push(
|
|
424
|
+
`- ${severityEmoji(r.severity)} \`${r.rule_id}\` — ${loc} — ${r.evidence}`,
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
lines.push("");
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
lines.push("### Compliance crosswalk");
|
|
431
|
+
lines.push("");
|
|
432
|
+
if (s.compliance.frameworks.length > 0) {
|
|
433
|
+
lines.push(
|
|
434
|
+
`Indicative alignment (crosswalk v${s.compliance.version}, reviewed ${s.compliance.reviewed}) — ` +
|
|
435
|
+
`**not an audit verdict**. Touches ${s.compliance.controls_touched} control(s) across ` +
|
|
436
|
+
`${s.compliance.frameworks.length} framework(s): ${s.compliance.frameworks.join(", ")}.`,
|
|
437
|
+
);
|
|
438
|
+
if (s.compliance.unmapped > 0) {
|
|
439
|
+
lines.push("");
|
|
440
|
+
lines.push(
|
|
441
|
+
`> ${s.compliance.unmapped} concern(s) did not map to a control in the starter rule-pack (honest coverage gap).`,
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
} else {
|
|
445
|
+
lines.push(
|
|
446
|
+
"No concerns mapped to a compliance control in the starter rule-pack.",
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
lines.push("");
|
|
450
|
+
|
|
451
|
+
// five-status verification taxonomy — keep the posture honest about coverage.
|
|
452
|
+
const v = s.verification;
|
|
453
|
+
lines.push("### Verification coverage");
|
|
454
|
+
lines.push("");
|
|
455
|
+
lines.push(
|
|
456
|
+
`Code-verified by: ${v.coverage.verified.length ? v.coverage.verified.join(", ") : "none"}.`,
|
|
457
|
+
);
|
|
458
|
+
if (v.coverage.inconclusive.length > 0) {
|
|
459
|
+
lines.push("");
|
|
460
|
+
lines.push(
|
|
461
|
+
`> [!WARNING]\n> **Inconclusive** (a coverage gap, not a pass) — these checks did not run:`,
|
|
462
|
+
);
|
|
463
|
+
for (const t of v.coverage.inconclusive)
|
|
464
|
+
lines.push(`> - \`${t.source}\` — ${t.reason}`);
|
|
465
|
+
}
|
|
466
|
+
if (v.counts.not_code_verifiable > 0) {
|
|
467
|
+
lines.push("");
|
|
468
|
+
lines.push(
|
|
469
|
+
`> ${v.counts.not_code_verifiable} concern(s) are **not code-verifiable** — they need a human/process decision (e.g. IAM least-privilege, a KMS key policy) the engine can flag but not prove.`,
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
lines.push("");
|
|
473
|
+
lines.push(`_${v.note}_`);
|
|
474
|
+
|
|
475
|
+
if (s.waivers.length > 0) {
|
|
476
|
+
lines.push("");
|
|
477
|
+
lines.push(...renderWaiverBlock(s.waivers));
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// The "@infraweaver fix …" CTA is offered ONLY when there's a Terraform concern
|
|
481
|
+
// to fix — the fix loop is Terraform-only, so inviting a fix in a repo whose
|
|
482
|
+
// open findings are all CloudFormation/Kubernetes/etc. would advertise a no-op
|
|
483
|
+
// (and contradict the "assessed, not auto-remediated" caveat above). A pure
|
|
484
|
+
// Terraform tree is unchanged (every open concern counts under `terraform`).
|
|
485
|
+
if ((s.languages.by_language.terraform ?? 0) > 0) {
|
|
486
|
+
lines.push("");
|
|
487
|
+
lines.push(...renderRemediationCta());
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
lines.push("");
|
|
491
|
+
lines.push(
|
|
492
|
+
"_Read-only assessment — no Terraform was modified and no PR was opened._",
|
|
493
|
+
);
|
|
494
|
+
return lines.join("\n");
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function severityEmoji(sev: Severity): string {
|
|
498
|
+
switch (sev) {
|
|
499
|
+
case "critical":
|
|
500
|
+
return "🚨";
|
|
501
|
+
case "high":
|
|
502
|
+
return "⚠️";
|
|
503
|
+
case "medium":
|
|
504
|
+
return "🔶";
|
|
505
|
+
case "low":
|
|
506
|
+
return "ℹ️";
|
|
507
|
+
default:
|
|
508
|
+
return "·";
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
export const TerraformAssessParams = type({
|
|
513
|
+
"severity_threshold?": type(
|
|
514
|
+
"'critical' | 'high' | 'medium' | 'low' | 'info'",
|
|
515
|
+
).describe(
|
|
516
|
+
"minimum severity to include (default: the run's configured threshold, else low).",
|
|
517
|
+
),
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
/** the full read-only assessment pipeline: scan (honouring the licence gate
|
|
521
|
+
* + module-fetch credential) → crosswalk → verification taxonomy → scorecard.
|
|
522
|
+
* Shared by `terraform_assess` and the evidence-bundle emitter so both report the
|
|
523
|
+
* identical posture from the identical toolchain. Pure-ish (only the scanners do
|
|
524
|
+
* I/O); no writes. */
|
|
525
|
+
export function runAssessmentPipeline(
|
|
526
|
+
ctx: LocalToolContext,
|
|
527
|
+
threshold: Severity,
|
|
528
|
+
): {
|
|
529
|
+
cwd: string;
|
|
530
|
+
selection: ResolvedToolSelection;
|
|
531
|
+
/** the resolved multi-language scope (detected / scanned / unsupported). */
|
|
532
|
+
languageScope: LanguageScope;
|
|
533
|
+
outcomes: ScannerOutcome[];
|
|
534
|
+
/** the full annotated set (suppression metadata attached) — what the Cloud report needs. */
|
|
535
|
+
concerns: Concern[];
|
|
536
|
+
/** the OPEN subset — what posture/score/crosswalk reflect. */
|
|
537
|
+
open: Concern[];
|
|
538
|
+
/** the accepted/waived subset — the audit trail. */
|
|
539
|
+
suppressed: Concern[];
|
|
540
|
+
crosswalk: CrosswalkReport;
|
|
541
|
+
verification: VerificationSummary;
|
|
542
|
+
scorecard: AssessmentScorecard;
|
|
543
|
+
/** run-to-run change vs the committed baseline; null when no baseline exists. */
|
|
544
|
+
delta: { delta: BaselineDelta; since: string | null } | null;
|
|
545
|
+
} {
|
|
546
|
+
const cwd = ctx.payload.cwd ?? process.cwd();
|
|
547
|
+
const minRank = SEVERITY_RANK[threshold];
|
|
548
|
+
|
|
549
|
+
// Multi-language Assess: detect which IaC languages the tree contains and
|
|
550
|
+
// resolve the operator's `iac_languages` scope against it. This is a READ-ONLY
|
|
551
|
+
// surface, so it may widen past Terraform — trivy + checkov already parse
|
|
552
|
+
// CloudFormation / Kubernetes / Helm / Dockerfile / ARM / Bicep, and the fix
|
|
553
|
+
// loop stays Terraform-first regardless. Detected-but-unscannable languages
|
|
554
|
+
// (Pulumi) are surfaced as `unsupported`, never scanned-and-silent.
|
|
555
|
+
const languageScope = resolveLanguageScope(
|
|
556
|
+
ctx.payload.iacLanguages,
|
|
557
|
+
detectIacLanguages(cwd),
|
|
558
|
+
);
|
|
559
|
+
|
|
560
|
+
// same licence gate + module credentials (git-transport + private-registry
|
|
561
|
+
// token) as terraform_scan, so a gated tool (e.g. tflint) shows up as
|
|
562
|
+
// INCONCLUSIVE coverage, not a silent pass, and a private cross-repo/registry
|
|
563
|
+
// module still resolves during the read-only scan's init. The resolved selection
|
|
564
|
+
// is returned so the read-only/auditor surfaces can be as transparent about the
|
|
565
|
+
// toolchain (gated / disabled / mistyped tokens) as terraform_scan is — silence
|
|
566
|
+
// on the assess side would read as "fully covered".
|
|
567
|
+
const selection = resolveToolSelection(ctx.payload);
|
|
568
|
+
const outcomes = runScanners(cwd, {
|
|
569
|
+
selection,
|
|
570
|
+
terraformEnv: resolveModuleCredentialEnv(ctx.payload, {
|
|
571
|
+
sshKeyDir: ctx.tmpdir,
|
|
572
|
+
}),
|
|
573
|
+
// scope checkov to the detected/requested languages (trivy scans every format
|
|
574
|
+
// it finds; the language tag + scope filter below keep both honest).
|
|
575
|
+
checkovFrameworks: checkovFrameworksFor(languageScope.scanned),
|
|
576
|
+
toolsNetwork: ctx.payload.toolsNetwork,
|
|
577
|
+
});
|
|
578
|
+
// Re-check the scope against what ACTUALLY ran: a language whose only covering
|
|
579
|
+
// scanner was skipped/disabled this run must report as a coverage gap, never
|
|
580
|
+
// as scanned-clean-with-zero-findings.
|
|
581
|
+
const effectiveScope = applyScannerAvailability(languageScope, {
|
|
582
|
+
trivy: outcomes.some((o) => o.source === "trivy" && o.ran),
|
|
583
|
+
checkov: outcomes.some((o) => o.source === "checkov" && o.ran),
|
|
584
|
+
});
|
|
585
|
+
const inScope = inLanguageScope(effectiveScope);
|
|
586
|
+
const scanned = attachSourceSnippets(
|
|
587
|
+
sortConcerns(dedupe(outcomes.flatMap((o) => o.concerns)))
|
|
588
|
+
.filter(inScope)
|
|
589
|
+
.filter((c) => SEVERITY_RANK[c.severity] >= minRank),
|
|
590
|
+
cwd,
|
|
591
|
+
);
|
|
592
|
+
// Annotate suppressions once, then split. Posture, counts, score and crosswalk
|
|
593
|
+
// reflect only the OPEN findings (a suppression is an accepted finding — kept
|
|
594
|
+
// out of the posture and surfaced in the waiver audit trail instead); `concerns`
|
|
595
|
+
// stays the full annotated set the Cloud report carries.
|
|
596
|
+
const concerns = suppressConcerns(scanned, cwd);
|
|
597
|
+
const open = concerns.filter((c) => !c.suppression);
|
|
598
|
+
const suppressed = concerns.filter((c) => c.suppression);
|
|
599
|
+
|
|
600
|
+
const crosswalk = buildCrosswalkReport(
|
|
601
|
+
open.map((c) => ({
|
|
602
|
+
id: c.id,
|
|
603
|
+
rule_id: c.rule_id,
|
|
604
|
+
evidence: c.evidence,
|
|
605
|
+
category: c.category,
|
|
606
|
+
severity: c.severity,
|
|
607
|
+
location: c.location,
|
|
608
|
+
})),
|
|
609
|
+
);
|
|
610
|
+
const verification = buildVerificationSummary(open, outcomes);
|
|
611
|
+
const scorecard = buildAssessment(
|
|
612
|
+
open,
|
|
613
|
+
crosswalk,
|
|
614
|
+
verification,
|
|
615
|
+
suppressed,
|
|
616
|
+
effectiveScope,
|
|
617
|
+
);
|
|
618
|
+
|
|
619
|
+
// Run-to-run delta vs the committed baseline checkpoint (the engine's own
|
|
620
|
+
// reference point); null when no baseline exists — nothing to compare against.
|
|
621
|
+
const baseline = loadBaselineWithMeta(cwd);
|
|
622
|
+
const delta = baseline
|
|
623
|
+
? { delta: baselineDelta(open, baseline.keys), since: baseline.created }
|
|
624
|
+
: null;
|
|
625
|
+
|
|
626
|
+
return {
|
|
627
|
+
cwd,
|
|
628
|
+
selection,
|
|
629
|
+
languageScope: effectiveScope,
|
|
630
|
+
outcomes,
|
|
631
|
+
concerns,
|
|
632
|
+
open,
|
|
633
|
+
suppressed,
|
|
634
|
+
crosswalk,
|
|
635
|
+
verification,
|
|
636
|
+
scorecard,
|
|
637
|
+
delta,
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
export function TerraformAssessTool(ctx: LocalToolContext) {
|
|
642
|
+
return tool({
|
|
643
|
+
name: "terraform_assess",
|
|
644
|
+
description:
|
|
645
|
+
"Read-only IaC best-practice ASSESSMENT (the Assess pillar — the scanner engine surfaced as a " +
|
|
646
|
+
"product). Terraform-first, but it also assesses every other IaC language the installed scanners parse " +
|
|
647
|
+
"(CloudFormation, Kubernetes, Helm, Dockerfile, Azure ARM/Bicep, Serverless, Ansible; OpenTofu `.tf`/" +
|
|
648
|
+
"`.tofu`) — scope it with the `iac_languages` input. Runs the deterministic scanners, then returns a " +
|
|
649
|
+
"deterministic `scorecard` (overall `posture` — clean / advisory / action-required, `by_severity` counts, " +
|
|
650
|
+
"a `languages` breadth block, `top_risks`, an indicative compliance-crosswalk summary, and a five-status " +
|
|
651
|
+
"`verification` coverage block) plus a ready-to-post `markdown` report. It NEVER modifies any file or opens " +
|
|
652
|
+
"a PR — use it to report posture (e.g. in a job summary or a CI gate on `posture`). A detected language no " +
|
|
653
|
+
"scanner can read (e.g. Pulumi) is reported under `languages.unsupported`, never silently dropped. Pairs " +
|
|
654
|
+
"with `terraform_emit_sarif` (Security tab), `terraform_emit_evidence` (auditor bundle), and `infracost_diff` " +
|
|
655
|
+
"/ `terraform_version_currency`. For the proven fix loop (Terraform only), use `terraform_scan` + Remediate.",
|
|
656
|
+
parameters: TerraformAssessParams,
|
|
657
|
+
execute: execute(async ({ severity_threshold }) => {
|
|
658
|
+
const configured = ctx.payload.severityThreshold as Severity | undefined;
|
|
659
|
+
const threshold: Severity = severity_threshold ?? configured ?? "low";
|
|
660
|
+
|
|
661
|
+
const {
|
|
662
|
+
cwd,
|
|
663
|
+
selection,
|
|
664
|
+
languageScope,
|
|
665
|
+
outcomes,
|
|
666
|
+
concerns,
|
|
667
|
+
scorecard,
|
|
668
|
+
delta,
|
|
669
|
+
} = runAssessmentPipeline(ctx, threshold);
|
|
670
|
+
// a mistyped iac_languages token is silently ignored otherwise — surface it
|
|
671
|
+
// like a mistyped tools_enabled token so the operator knows their scope
|
|
672
|
+
// narrowing didn't take.
|
|
673
|
+
if (languageScope.unknown_tokens.length > 0) {
|
|
674
|
+
log.warning(
|
|
675
|
+
`» iac_languages: ignoring unrecognised language(s) [${languageScope.unknown_tokens.join(", ")}]`,
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
// Publish the reported concern set (the pipeline already applied suppressions)
|
|
679
|
+
// so finalizeSuccessRun's emitFindingsOutputs + reportToCloud fire — assess IS
|
|
680
|
+
// the report path, but lastScanConcerns was only ever set by terraform_scan
|
|
681
|
+
// (Remediate), so Cloud reporting silently no-opped in Assess.
|
|
682
|
+
scanSessionOf(ctx.toolState).lastScanConcerns = concerns;
|
|
683
|
+
const markdown = renderAssessmentMarkdown(scorecard, { delta });
|
|
684
|
+
|
|
685
|
+
const ran = outcomes.filter((o) => o.ran).map((o) => o.source);
|
|
686
|
+
// a mistyped tools_enabled token is otherwise silently ignored; in a
|
|
687
|
+
// read-only assessment that's a footgun (the operator thinks they configured
|
|
688
|
+
// something they didn't). Surface it the same way terraform_scan does.
|
|
689
|
+
if (selection.unknownTokens.length > 0) {
|
|
690
|
+
log.warning(
|
|
691
|
+
`» tools_enabled: ignoring unrecognised tool(s) [${selection.unknownTokens.join(", ")}]`,
|
|
692
|
+
);
|
|
693
|
+
}
|
|
694
|
+
log.info(
|
|
695
|
+
`» terraform_assess: ${scorecard.posture} — ${scorecard.total} concern(s) ` +
|
|
696
|
+
`(${scorecard.compliance.controls_touched} control(s) across ${scorecard.compliance.frameworks.length} framework(s)) ` +
|
|
697
|
+
`across [${scorecard.languages.scanned.join(", ")}] from [${ran.join(", ")}]`,
|
|
698
|
+
);
|
|
699
|
+
return toolOk({
|
|
700
|
+
scanned_dir: cwd,
|
|
701
|
+
scanners_ran: ran,
|
|
702
|
+
// multi-language breadth: the languages detected/scanned + any detected
|
|
703
|
+
// language no scanner could assess (surfaced, never silently dropped).
|
|
704
|
+
languages: {
|
|
705
|
+
detected: languageScope.detected,
|
|
706
|
+
scanned: languageScope.scanned,
|
|
707
|
+
unsupported: languageScope.unsupported,
|
|
708
|
+
unknown_tokens: languageScope.unknown_tokens,
|
|
709
|
+
},
|
|
710
|
+
// parity with terraform_scan: which tools were licence-gated off, which
|
|
711
|
+
// the operator disabled, and which tokens were unrecognised — so the
|
|
712
|
+
// assessment is honest about its own coverage, not silently partial.
|
|
713
|
+
tool_selection: {
|
|
714
|
+
licence_gated: selection.gated,
|
|
715
|
+
disabled: selection.disabled,
|
|
716
|
+
unknown_tokens: selection.unknownTokens,
|
|
717
|
+
},
|
|
718
|
+
scorecard,
|
|
719
|
+
markdown,
|
|
720
|
+
});
|
|
721
|
+
}),
|
|
722
|
+
});
|
|
723
|
+
}
|