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,1253 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { type } from "arktype";
|
|
3
|
+
import { EXPECTED_CROSSWALK_DIGEST } from "#app/mcp/crosswalkDigest";
|
|
4
|
+
import { FRAMEWORKS } from "#app/mcp/frameworks";
|
|
5
|
+
import type { LocalToolContext } from "#app/mcp/localContext";
|
|
6
|
+
import { execute, tool, toolOk } from "#app/mcp/shared";
|
|
7
|
+
import type { Concern } from "#app/mcp/terraform/types";
|
|
8
|
+
import {
|
|
9
|
+
type ConcernVerificationStatus,
|
|
10
|
+
concernVerificationStatus,
|
|
11
|
+
} from "#app/mcp/terraform/verification";
|
|
12
|
+
import { log } from "#app/utils/cli";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Compliance crosswalk ("explain like I'm the auditor", the
|
|
16
|
+
* seed of the moat). Maps a best-practice concern → the control families
|
|
17
|
+
* it touches across UK public-sector + general frameworks, so a remediation can
|
|
18
|
+
* be narrated to an assessor in their own language ("this closes NCSC Cloud
|
|
19
|
+
* Principle 2 / Cyber Essentials Secure Configuration") rather than as a raw
|
|
20
|
+
* scanner rule id.
|
|
21
|
+
*
|
|
22
|
+
* SCOPE / HONESTY: this is a deterministic STARTER rule-pack keyed on the
|
|
23
|
+
* defect's THEME (encryption, public exposure, least-privilege, logging, …),
|
|
24
|
+
* not a certified control-by-control mapping. The durable product is a
|
|
25
|
+
* versioned, framework-revision-pinned crosswalk — so every mapping
|
|
26
|
+
* carries the pack version + date and is labelled indicative, never an audit
|
|
27
|
+
* verdict. No open crosswalk to UK frameworks exists; this is the wedge.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
export const CROSSWALK_VERSION = "0.6.0";
|
|
31
|
+
/** the date this rule-pack's framework references were last reviewed (absolute). */
|
|
32
|
+
export const CROSSWALK_REVIEWED = "2026-07-26";
|
|
33
|
+
|
|
34
|
+
export interface ControlRef {
|
|
35
|
+
/** the framework, e.g. "NCSC Cloud Security Principles". */
|
|
36
|
+
framework: string;
|
|
37
|
+
/** the control id within that framework, e.g. "Principle 2". */
|
|
38
|
+
control: string;
|
|
39
|
+
/** the control's short title. */
|
|
40
|
+
title: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** a theme of defect, the signals that identify it, and the controls it maps to. */
|
|
44
|
+
interface CrosswalkRule {
|
|
45
|
+
theme: string;
|
|
46
|
+
/** lowercased substrings that, if any appears in the rule_id/evidence, match. */
|
|
47
|
+
signals: string[];
|
|
48
|
+
controls: ControlRef[];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// The starter rule-pack. Themes are matched against the concern's rule_id +
|
|
52
|
+
// evidence (lowercased). Ordered most-specific first; a concern can match
|
|
53
|
+
// several themes (their controls are unioned). Kept deliberately small and
|
|
54
|
+
// auditable — each control ref is a real, citable control family.
|
|
55
|
+
const CROSSWALK: CrosswalkRule[] = [
|
|
56
|
+
{
|
|
57
|
+
theme: "encryption-at-rest",
|
|
58
|
+
// NB avoid the bare token "sse" — it's a substring of "essential"/"asset"
|
|
59
|
+
// and would false-match; use the explicit phrases instead.
|
|
60
|
+
signals: [
|
|
61
|
+
"encrypt",
|
|
62
|
+
"kms",
|
|
63
|
+
"server-side encryption",
|
|
64
|
+
"server_side_encryption",
|
|
65
|
+
"sse_algorithm",
|
|
66
|
+
"at rest",
|
|
67
|
+
"at-rest",
|
|
68
|
+
"unencrypted",
|
|
69
|
+
],
|
|
70
|
+
controls: [
|
|
71
|
+
{
|
|
72
|
+
framework: "NCSC Cloud Security Principles",
|
|
73
|
+
control: "Principle 1",
|
|
74
|
+
title: "Data in transit protection",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
framework: "Cyber Essentials",
|
|
78
|
+
control: "Secure Configuration",
|
|
79
|
+
title: "Secure configuration",
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
framework: "CIS Controls v8",
|
|
83
|
+
control: "3.11",
|
|
84
|
+
title: "Encrypt sensitive data at rest",
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
framework: "NHS DSPT",
|
|
88
|
+
control: "Standard 1",
|
|
89
|
+
title: "Personal confidential data protected",
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
theme: "encryption-in-transit",
|
|
95
|
+
signals: [
|
|
96
|
+
"tls",
|
|
97
|
+
"ssl",
|
|
98
|
+
"https",
|
|
99
|
+
"in transit",
|
|
100
|
+
"in-transit",
|
|
101
|
+
"insecure protocol",
|
|
102
|
+
"http ",
|
|
103
|
+
],
|
|
104
|
+
controls: [
|
|
105
|
+
{
|
|
106
|
+
framework: "NCSC Cloud Security Principles",
|
|
107
|
+
control: "Principle 1",
|
|
108
|
+
title: "Data in transit protection",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
framework: "CIS Controls v8",
|
|
112
|
+
control: "3.10",
|
|
113
|
+
title: "Encrypt sensitive data in transit",
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
theme: "public-exposure",
|
|
119
|
+
signals: [
|
|
120
|
+
"public",
|
|
121
|
+
"0.0.0.0/0",
|
|
122
|
+
"publicly",
|
|
123
|
+
"anonymous",
|
|
124
|
+
"open to the internet",
|
|
125
|
+
"ingress",
|
|
126
|
+
],
|
|
127
|
+
controls: [
|
|
128
|
+
{
|
|
129
|
+
framework: "NCSC Cloud Security Principles",
|
|
130
|
+
control: "Principle 9",
|
|
131
|
+
title: "Secure user management / network separation",
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
framework: "Cyber Essentials",
|
|
135
|
+
control: "Firewalls",
|
|
136
|
+
title: "Boundary firewalls and internet gateways",
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
framework: "CIS Controls v8",
|
|
140
|
+
control: "4.4",
|
|
141
|
+
title: "Implement and manage a firewall on servers",
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
framework: "Secure by Design",
|
|
145
|
+
control: "SbD-7",
|
|
146
|
+
title: "Protect data in transit and at rest",
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
theme: "least-privilege",
|
|
152
|
+
signals: [
|
|
153
|
+
"iam",
|
|
154
|
+
"wildcard",
|
|
155
|
+
"least privilege",
|
|
156
|
+
"least-privilege",
|
|
157
|
+
"policy",
|
|
158
|
+
"admin",
|
|
159
|
+
"privilege",
|
|
160
|
+
"*:*",
|
|
161
|
+
"role",
|
|
162
|
+
],
|
|
163
|
+
controls: [
|
|
164
|
+
{
|
|
165
|
+
framework: "NCSC Cloud Security Principles",
|
|
166
|
+
control: "Principle 9",
|
|
167
|
+
title: "Secure user management",
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
framework: "Cyber Essentials",
|
|
171
|
+
control: "User Access Control",
|
|
172
|
+
title: "User access control",
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
framework: "CIS Controls v8",
|
|
176
|
+
control: "6.8",
|
|
177
|
+
title: "Define and maintain role-based access control",
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
framework: "NHS DSPT",
|
|
181
|
+
control: "Standard 4",
|
|
182
|
+
title: "Managing access",
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
theme: "logging-audit",
|
|
188
|
+
// NB avoid the bare token "log" — it's a substring of "catalog"/"blog" and
|
|
189
|
+
// would false-match; use the explicit phrases/longer tokens instead.
|
|
190
|
+
signals: [
|
|
191
|
+
"logging",
|
|
192
|
+
"log group",
|
|
193
|
+
"audit",
|
|
194
|
+
"cloudtrail",
|
|
195
|
+
"flow log",
|
|
196
|
+
"access log",
|
|
197
|
+
"monitoring",
|
|
198
|
+
"cloudwatch",
|
|
199
|
+
],
|
|
200
|
+
controls: [
|
|
201
|
+
{
|
|
202
|
+
framework: "NCSC Cloud Security Principles",
|
|
203
|
+
control: "Principle 13",
|
|
204
|
+
title: "Audit information and alerting",
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
framework: "CIS Controls v8",
|
|
208
|
+
control: "8.2",
|
|
209
|
+
title: "Collect audit logs",
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
framework: "NHS DSPT",
|
|
213
|
+
control: "Standard 7",
|
|
214
|
+
title: "Continuity planning / monitoring",
|
|
215
|
+
},
|
|
216
|
+
{ framework: "SOC 2", control: "CC7.2", title: "Security monitoring" },
|
|
217
|
+
],
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
theme: "backup-resilience",
|
|
221
|
+
signals: [
|
|
222
|
+
"versioning",
|
|
223
|
+
"backup",
|
|
224
|
+
"snapshot",
|
|
225
|
+
"retention",
|
|
226
|
+
"deletion protection",
|
|
227
|
+
"multi-az",
|
|
228
|
+
],
|
|
229
|
+
controls: [
|
|
230
|
+
{
|
|
231
|
+
framework: "NCSC Cloud Security Principles",
|
|
232
|
+
control: "Principle 2",
|
|
233
|
+
title: "Asset protection and resilience",
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
framework: "NHS DSPT",
|
|
237
|
+
control: "Standard 7",
|
|
238
|
+
title: "Continuity planning",
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
framework: "CIS Controls v8",
|
|
242
|
+
control: "11.2",
|
|
243
|
+
title: "Perform automated backups",
|
|
244
|
+
},
|
|
245
|
+
],
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
theme: "secrets-management",
|
|
249
|
+
signals: [
|
|
250
|
+
"secret",
|
|
251
|
+
"credential",
|
|
252
|
+
"password",
|
|
253
|
+
"hardcoded",
|
|
254
|
+
"plaintext",
|
|
255
|
+
"access key",
|
|
256
|
+
"token",
|
|
257
|
+
],
|
|
258
|
+
controls: [
|
|
259
|
+
{
|
|
260
|
+
framework: "NCSC Cloud Security Principles",
|
|
261
|
+
control: "Principle 10",
|
|
262
|
+
title: "Identity and authentication",
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
framework: "CIS Controls v8",
|
|
266
|
+
control: "16.4",
|
|
267
|
+
title: "Securely store credentials",
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
framework: "Cyber Essentials",
|
|
271
|
+
control: "Secure Configuration",
|
|
272
|
+
title: "Secure configuration",
|
|
273
|
+
},
|
|
274
|
+
],
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
theme: "network-segmentation",
|
|
278
|
+
// internal segmentation (vs the internet-facing "public-exposure" theme):
|
|
279
|
+
// NB avoid the bare token "tag"/"acl" — use explicit phrases.
|
|
280
|
+
signals: [
|
|
281
|
+
"security group",
|
|
282
|
+
"network acl",
|
|
283
|
+
"nacl",
|
|
284
|
+
"subnet",
|
|
285
|
+
"vpc peering",
|
|
286
|
+
"unrestricted egress",
|
|
287
|
+
"egress to 0.0.0.0/0",
|
|
288
|
+
],
|
|
289
|
+
controls: [
|
|
290
|
+
{
|
|
291
|
+
framework: "NCSC Cloud Security Principles",
|
|
292
|
+
control: "Principle 9",
|
|
293
|
+
title: "Network separation",
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
framework: "CIS Controls v8",
|
|
297
|
+
control: "12.2",
|
|
298
|
+
title: "Establish and maintain a secure network architecture",
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
framework: "Secure by Design",
|
|
302
|
+
control: "SbD-5",
|
|
303
|
+
title: "Segment networks",
|
|
304
|
+
},
|
|
305
|
+
],
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
theme: "mfa-strong-auth",
|
|
309
|
+
signals: [
|
|
310
|
+
"mfa",
|
|
311
|
+
"multi-factor",
|
|
312
|
+
"multi factor",
|
|
313
|
+
"password policy",
|
|
314
|
+
"root account",
|
|
315
|
+
"root user",
|
|
316
|
+
"console access",
|
|
317
|
+
],
|
|
318
|
+
controls: [
|
|
319
|
+
{
|
|
320
|
+
framework: "Cyber Essentials",
|
|
321
|
+
control: "User Access Control",
|
|
322
|
+
title: "User access control",
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
framework: "CIS Controls v8",
|
|
326
|
+
control: "6.5",
|
|
327
|
+
title: "Require MFA for administrative access",
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
framework: "NCSC Cloud Security Principles",
|
|
331
|
+
control: "Principle 10",
|
|
332
|
+
title: "Identity and authentication",
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
framework: "NHS DSPT",
|
|
336
|
+
control: "Standard 4",
|
|
337
|
+
title: "Managing access",
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
theme: "patch-currency",
|
|
343
|
+
signals: [
|
|
344
|
+
"deprecated",
|
|
345
|
+
"outdated",
|
|
346
|
+
"end of life",
|
|
347
|
+
"end-of-life",
|
|
348
|
+
"unsupported",
|
|
349
|
+
"legacy runtime",
|
|
350
|
+
],
|
|
351
|
+
controls: [
|
|
352
|
+
{
|
|
353
|
+
framework: "Cyber Essentials",
|
|
354
|
+
control: "Security Update Management",
|
|
355
|
+
title: "Security update management",
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
framework: "CIS Controls v8",
|
|
359
|
+
control: "7.3",
|
|
360
|
+
title: "Perform automated operating system patch management",
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
framework: "NCSC Cloud Security Principles",
|
|
364
|
+
control: "Principle 5",
|
|
365
|
+
title: "Operational security",
|
|
366
|
+
},
|
|
367
|
+
],
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
theme: "container-hardening",
|
|
371
|
+
// Covers Terraform ECS/EKS AND the multi-language Assess formats — Kubernetes
|
|
372
|
+
// manifests, Helm charts, and Dockerfiles (trivy/checkov emit these prose
|
|
373
|
+
// strings). NB "root user" is deliberately NOT here (it's an AWS-root signal
|
|
374
|
+
// under mfa-strong-auth); dockerfile "runs as root" uses "run as root" /
|
|
375
|
+
// "runasnonroot" instead so the two don't cross-match.
|
|
376
|
+
signals: [
|
|
377
|
+
"privileged",
|
|
378
|
+
"container",
|
|
379
|
+
"ecs task",
|
|
380
|
+
"fargate",
|
|
381
|
+
"kubernetes",
|
|
382
|
+
"pod security",
|
|
383
|
+
"host network",
|
|
384
|
+
"hostpath",
|
|
385
|
+
"runasnonroot",
|
|
386
|
+
"run as root",
|
|
387
|
+
"running as root",
|
|
388
|
+
"allowprivilegeescalation",
|
|
389
|
+
"privilege escalation",
|
|
390
|
+
"readonlyrootfilesystem",
|
|
391
|
+
"securitycontext",
|
|
392
|
+
"security context",
|
|
393
|
+
"linux capabilities",
|
|
394
|
+
"add capabilities",
|
|
395
|
+
"healthcheck",
|
|
396
|
+
"latest tag",
|
|
397
|
+
"image tag",
|
|
398
|
+
"seccomp",
|
|
399
|
+
"apparmor",
|
|
400
|
+
],
|
|
401
|
+
controls: [
|
|
402
|
+
{
|
|
403
|
+
framework: "NCSC Cloud Security Principles",
|
|
404
|
+
control: "Principle 5",
|
|
405
|
+
title: "Operational security",
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
framework: "CIS Controls v8",
|
|
409
|
+
control: "4.1",
|
|
410
|
+
title: "Establish and maintain a secure configuration process",
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
framework: "Secure by Design",
|
|
414
|
+
control: "SbD-3",
|
|
415
|
+
title: "Minimise the attack surface",
|
|
416
|
+
},
|
|
417
|
+
],
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
theme: "resource-governance",
|
|
421
|
+
// governance / asset hygiene (tagging, naming) — matches real scanner prose
|
|
422
|
+
// ("resource is not tagged") without the bare token "tag" (substring of "stage").
|
|
423
|
+
signals: [
|
|
424
|
+
"not tagged",
|
|
425
|
+
"untagged",
|
|
426
|
+
"tagging",
|
|
427
|
+
"missing tag",
|
|
428
|
+
"required tags",
|
|
429
|
+
"naming convention",
|
|
430
|
+
],
|
|
431
|
+
controls: [
|
|
432
|
+
{
|
|
433
|
+
framework: "NCSC Cloud Security Principles",
|
|
434
|
+
control: "Principle 2",
|
|
435
|
+
title: "Asset protection and resilience",
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
framework: "CIS Controls v8",
|
|
439
|
+
control: "1.1",
|
|
440
|
+
title: "Establish and maintain detailed enterprise asset inventory",
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
framework: "GDS Service Standard",
|
|
444
|
+
control: "Point 14",
|
|
445
|
+
title: "Operate a reliable service",
|
|
446
|
+
},
|
|
447
|
+
],
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
// The governance band of the native rule pack ([[nativeRules]]): imperative
|
|
451
|
+
// side-effects and input-bound destroy protection are change-control facts,
|
|
452
|
+
// not misconfigurations. Signals are the exact HCL constructs, so this theme
|
|
453
|
+
// can only fire on a finding that named one — no prose match, no drift into
|
|
454
|
+
// the other eleven themes.
|
|
455
|
+
theme: "change-control",
|
|
456
|
+
signals: [
|
|
457
|
+
"action_trigger",
|
|
458
|
+
"imperative-action-trigger",
|
|
459
|
+
"provider action",
|
|
460
|
+
"prevent_destroy",
|
|
461
|
+
"dynamic-destroy-protection",
|
|
462
|
+
"destroy protection",
|
|
463
|
+
// drift findings ([[planDrift]] `drift-<kind>-<address>` rule tokens): an
|
|
464
|
+
// out-of-band change to live infrastructure is the change-control failure
|
|
465
|
+
// mode itself. Exact rule tokens, same discipline as the rest of this
|
|
466
|
+
// theme — prose like "drift" alone must not match (tflint has fmt-drift
|
|
467
|
+
// rule names that are style, not change control).
|
|
468
|
+
"drift-modified",
|
|
469
|
+
"drift-deleted",
|
|
470
|
+
"drift-recreated",
|
|
471
|
+
"drift-replaced",
|
|
472
|
+
],
|
|
473
|
+
controls: [
|
|
474
|
+
{
|
|
475
|
+
framework: "NCSC Cloud Security Principles",
|
|
476
|
+
control: "Principle 5",
|
|
477
|
+
title: "Operational security (change management)",
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
framework: "CIS Controls v8",
|
|
481
|
+
control: "4.2",
|
|
482
|
+
title:
|
|
483
|
+
"Establish and maintain a secure configuration process for network infrastructure",
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
framework: "GDS Service Standard",
|
|
487
|
+
control: "Point 14",
|
|
488
|
+
title: "Operate a reliable service",
|
|
489
|
+
},
|
|
490
|
+
],
|
|
491
|
+
},
|
|
492
|
+
];
|
|
493
|
+
|
|
494
|
+
// ── §5.14 crosswalk hub: NIST SP 800-53 rev 5 spine + CSF 2.0 pivot ────────────
|
|
495
|
+
// The hub keys THEMES (not findings) to 800-53 — one curated table — after which
|
|
496
|
+
// every further framework layer is scheme-requirement-id → 800-53 → themes: one
|
|
497
|
+
// mechanical, auditable hop. 800-53 is the only candidate whose full text is
|
|
498
|
+
// embeddable forever at zero cost (CC0 OSCAL, usnistgov/oscal-content), and its
|
|
499
|
+
// enhancement granularity (SC-28(1), SC-7(5)) fits IaC findings far better than
|
|
500
|
+
// clause-level frameworks. CSF 2.0 is the EU-facing pivot (CyFun/Ireland are
|
|
501
|
+
// CSF-2.0-shaped); its subcategories attach through their NIST-published 800-53
|
|
502
|
+
// informative references, so both layers stay coherent for free.
|
|
503
|
+
|
|
504
|
+
const NIST_800_53_NAME = "NIST SP 800-53";
|
|
505
|
+
const NIST_CSF_NAME = "NIST CSF 2.0";
|
|
506
|
+
const DORA_RTS_NAME = "DORA RTS (EU) 2024/1774";
|
|
507
|
+
const NCSC_CAF_NAME = "NCSC Cyber Assessment Framework";
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Titles of every 800-53 control the hub references, keyed by display id
|
|
511
|
+
* ("SC-28(1)" — OSCAL id "sc-28.1"). Transcribed from the CC0 OSCAL rev 5.2.0
|
|
512
|
+
* catalog (public domain worldwide), so embedding is unconditionally lawful.
|
|
513
|
+
*/
|
|
514
|
+
const NIST_800_53_TITLES: Record<string, string> = {
|
|
515
|
+
"AC-3": "Access Enforcement",
|
|
516
|
+
"AC-4": "Information Flow Enforcement",
|
|
517
|
+
"AC-6": "Least Privilege",
|
|
518
|
+
"AC-6(1)": "Authorize Access to Security Functions",
|
|
519
|
+
"AC-6(10)":
|
|
520
|
+
"Prohibit Non-privileged Users from Executing Privileged Functions",
|
|
521
|
+
"AC-17(2)": "Protection of Confidentiality and Integrity Using Encryption",
|
|
522
|
+
"AU-2": "Event Logging",
|
|
523
|
+
"AU-11": "Audit Record Retention",
|
|
524
|
+
"AU-12": "Audit Record Generation",
|
|
525
|
+
"CM-2": "Baseline Configuration",
|
|
526
|
+
"CM-3": "Configuration Change Control",
|
|
527
|
+
"CM-4": "Impact Analyses",
|
|
528
|
+
"CM-5": "Access Restrictions for Change",
|
|
529
|
+
"CM-6": "Configuration Settings",
|
|
530
|
+
"CM-7": "Least Functionality",
|
|
531
|
+
"CM-8": "System Component Inventory",
|
|
532
|
+
"CM-12": "Information Location",
|
|
533
|
+
"CP-6": "Alternate Storage Site",
|
|
534
|
+
"CP-9": "System Backup",
|
|
535
|
+
"CP-10": "System Recovery and Reconstitution",
|
|
536
|
+
"IA-2": "Identification and Authentication (Organizational Users)",
|
|
537
|
+
"IA-2(1)": "Multi-factor Authentication to Privileged Accounts",
|
|
538
|
+
"IA-2(2)": "Multi-factor Authentication to Non-privileged Accounts",
|
|
539
|
+
"IA-5": "Authenticator Management",
|
|
540
|
+
"IA-5(1)": "Password-based Authentication",
|
|
541
|
+
"IA-5(7)": "No Embedded Unencrypted Static Authenticators",
|
|
542
|
+
"SA-22": "Unsupported System Components",
|
|
543
|
+
"SC-7": "Boundary Protection",
|
|
544
|
+
"SC-7(3)": "Access Points",
|
|
545
|
+
"SC-7(5)": "Deny by Default — Allow by Exception",
|
|
546
|
+
"SC-8": "Transmission Confidentiality and Integrity",
|
|
547
|
+
"SC-8(1)": "Cryptographic Protection",
|
|
548
|
+
"SC-12": "Cryptographic Key Establishment and Management",
|
|
549
|
+
"SC-13": "Cryptographic Protection",
|
|
550
|
+
"SC-28": "Protection of Information at Rest",
|
|
551
|
+
"SC-28(1)": "Cryptographic Protection",
|
|
552
|
+
"SC-39": "Process Isolation",
|
|
553
|
+
"SI-2": "Flaw Remediation",
|
|
554
|
+
"SI-4": "System Monitoring",
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* THE HUB TABLE (§5.14 step 2): defect theme → the 800-53 rev 5 controls it
|
|
559
|
+
* evidences. Hand-curated to the technically-enforceable band an IaC scan can
|
|
560
|
+
* honestly speak to (crypto, IAM, segmentation, logging, secure-config, backup
|
|
561
|
+
* topology) — never the organisational/process/physical bands. The theme layer
|
|
562
|
+
* insulates every downstream framework from an 800-53 rev 6 restructure.
|
|
563
|
+
*/
|
|
564
|
+
export const THEME_TO_NIST: Record<string, string[]> = {
|
|
565
|
+
"encryption-at-rest": ["SC-28", "SC-28(1)", "SC-12", "SC-13"],
|
|
566
|
+
"encryption-in-transit": ["SC-8", "SC-8(1)", "SC-13", "AC-17(2)"],
|
|
567
|
+
"public-exposure": ["SC-7", "SC-7(3)", "SC-7(5)", "AC-3", "CM-7"],
|
|
568
|
+
"least-privilege": ["AC-3", "AC-6", "AC-6(1)", "AC-6(10)"],
|
|
569
|
+
"logging-audit": ["AU-2", "AU-11", "AU-12", "SI-4"],
|
|
570
|
+
"backup-resilience": ["CP-6", "CP-9", "CP-10"],
|
|
571
|
+
"secrets-management": ["IA-5", "IA-5(7)", "SC-12", "SC-28"],
|
|
572
|
+
"network-segmentation": ["AC-4", "SC-7", "SC-7(5)"],
|
|
573
|
+
"mfa-strong-auth": ["IA-2", "IA-2(1)", "IA-2(2)", "IA-5(1)"],
|
|
574
|
+
"patch-currency": ["SI-2", "SA-22"],
|
|
575
|
+
"container-hardening": ["CM-2", "CM-6", "CM-7", "SC-39"],
|
|
576
|
+
"resource-governance": ["CM-8", "CM-12"],
|
|
577
|
+
"change-control": ["CM-2", "CM-3", "CM-4", "CM-5"],
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
/** One requirement of a hub-anchored framework layer. */
|
|
581
|
+
interface HubRequirement {
|
|
582
|
+
/** The requirement id as the Cloud pack and evidence bundle cite it. */
|
|
583
|
+
id: string;
|
|
584
|
+
/** Short label for `ControlRef.title` (the pack carries the full wording). */
|
|
585
|
+
title: string;
|
|
586
|
+
/** The 800-53 spine ids this requirement is anchored to. A requirement
|
|
587
|
+
* attaches to a theme exactly when one of these appears in that theme's
|
|
588
|
+
* `THEME_TO_NIST` row — the single mechanical, auditable hop. */
|
|
589
|
+
nist: string[];
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/** A framework layer that rides the 800-53 spine rather than being hand-themed. */
|
|
593
|
+
interface HubLayer {
|
|
594
|
+
/** Display name — MUST equal a `FrameworkDef.name` in the registry. */
|
|
595
|
+
framework: string;
|
|
596
|
+
requirements: HubRequirement[];
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* NIST CSF 2.0 — the EU-facing pivot (CyFun and Ireland's baseline are
|
|
601
|
+
* CSF-2.0-shaped). Anchors are NIST's own CSF↔800-53 informative references
|
|
602
|
+
* (OLIR/CPRT), trimmed to the ids the spine carries. References that would
|
|
603
|
+
* create dishonest joins are deliberately omitted (PR.PS-01 keeps CM-2/CM-6 but
|
|
604
|
+
* not CM-7, so a public-exposure finding never claims "configuration
|
|
605
|
+
* management practices").
|
|
606
|
+
*/
|
|
607
|
+
const CSF_2_0_LAYER: HubLayer = {
|
|
608
|
+
framework: NIST_CSF_NAME,
|
|
609
|
+
requirements: [
|
|
610
|
+
{
|
|
611
|
+
id: "PR.DS-01",
|
|
612
|
+
title: "Data-at-rest protected",
|
|
613
|
+
nist: ["SC-28", "SC-28(1)"],
|
|
614
|
+
},
|
|
615
|
+
{
|
|
616
|
+
id: "PR.DS-02",
|
|
617
|
+
title: "Data-in-transit protected",
|
|
618
|
+
nist: ["SC-8", "SC-8(1)"],
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
id: "PR.DS-11",
|
|
622
|
+
title: "Backups created, protected, and tested",
|
|
623
|
+
nist: ["CP-6", "CP-9", "CP-10"],
|
|
624
|
+
},
|
|
625
|
+
{
|
|
626
|
+
id: "PR.AA-01",
|
|
627
|
+
title: "Identities and credentials managed",
|
|
628
|
+
nist: ["IA-5", "IA-5(7)"],
|
|
629
|
+
},
|
|
630
|
+
{
|
|
631
|
+
id: "PR.AA-03",
|
|
632
|
+
title: "Users, services, and hardware authenticated",
|
|
633
|
+
nist: ["IA-2", "IA-2(1)", "IA-2(2)"],
|
|
634
|
+
},
|
|
635
|
+
{
|
|
636
|
+
id: "PR.AA-05",
|
|
637
|
+
title: "Least-privilege access permissions enforced",
|
|
638
|
+
nist: ["AC-3", "AC-6", "AC-6(1)"],
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
id: "PR.PS-01",
|
|
642
|
+
title: "Configuration management practices applied",
|
|
643
|
+
nist: ["CM-2", "CM-6"],
|
|
644
|
+
},
|
|
645
|
+
{
|
|
646
|
+
id: "PR.PS-02",
|
|
647
|
+
title: "Software maintained and replaced by risk",
|
|
648
|
+
nist: ["SI-2", "SA-22"],
|
|
649
|
+
},
|
|
650
|
+
{
|
|
651
|
+
id: "PR.PS-04",
|
|
652
|
+
title: "Log records generated for monitoring",
|
|
653
|
+
nist: ["AU-2", "AU-12"],
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
id: "PR.IR-01",
|
|
657
|
+
title: "Networks protected from unauthorized access",
|
|
658
|
+
nist: ["SC-7", "SC-7(5)", "AC-4"],
|
|
659
|
+
},
|
|
660
|
+
{
|
|
661
|
+
id: "DE.CM-09",
|
|
662
|
+
title: "Computing resources monitored for adverse events",
|
|
663
|
+
nist: ["SI-4"],
|
|
664
|
+
},
|
|
665
|
+
{
|
|
666
|
+
id: "ID.AM-02",
|
|
667
|
+
title: "Software and system inventories maintained",
|
|
668
|
+
nist: ["CM-8"],
|
|
669
|
+
},
|
|
670
|
+
],
|
|
671
|
+
};
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* DORA technical layer (§5.15) — Commission Delegated Regulation (EU) 2024/1774,
|
|
675
|
+
* the RTS on ICT risk-management tools, methods, processes and policies. It is
|
|
676
|
+
* the RTS that gives concrete technical form to DORA (Reg. (EU) 2022/2554)
|
|
677
|
+
* **Art. 9 "Protection and prevention"** and **Art. 10 "Detection"**; the
|
|
678
|
+
* requirement ids below are RTS articles, not DORA Level-1 articles (RTS Art. 9
|
|
679
|
+
* is "Capacity and performance management" and RTS Art. 10 is "Vulnerability and
|
|
680
|
+
* patch management" — different instruments, same numbers, so we cite the RTS
|
|
681
|
+
* explicitly and never write a bare "Article 9").
|
|
682
|
+
*
|
|
683
|
+
* Surface: RTS Section 4 (Encryption and cryptography, Arts 6–7), Section 5 (ICT
|
|
684
|
+
* operations security, Arts 8–12), Section 6 (Network security, Arts 13–14) and
|
|
685
|
+
* Chapter II access control (Arts 20–21) — precisely the config-band articles.
|
|
686
|
+
*
|
|
687
|
+
* HONESTY: this is "evidence toward the DORA technical controls", never "DORA
|
|
688
|
+
* compliant". Roughly half of DORA — governance, business-continuity testing,
|
|
689
|
+
* third-party risk and the Register of Information, TLPT, physical security — is
|
|
690
|
+
* outside anything an IaC scan can observe; the Cloud pack carries those
|
|
691
|
+
* articles as scanner-less rows so the published coverage % states the gap.
|
|
692
|
+
* EUR-Lex text is reusable commercially under Commission Decision 2011/833/EU.
|
|
693
|
+
*/
|
|
694
|
+
const DORA_RTS_LAYER: HubLayer = {
|
|
695
|
+
framework: DORA_RTS_NAME,
|
|
696
|
+
requirements: [
|
|
697
|
+
{
|
|
698
|
+
id: "RTS-6(2)",
|
|
699
|
+
title: "Encryption of data at rest, in transit, and in use",
|
|
700
|
+
nist: ["SC-28", "SC-28(1)", "SC-8", "SC-8(1)", "SC-13"],
|
|
701
|
+
},
|
|
702
|
+
{
|
|
703
|
+
id: "RTS-7(1)",
|
|
704
|
+
title: "Cryptographic key lifecycle management",
|
|
705
|
+
nist: ["SC-12"],
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
id: "RTS-8(2)(b)",
|
|
709
|
+
title: "Backup, restore, and environment separation",
|
|
710
|
+
nist: ["CP-6", "CP-9", "CP-10"],
|
|
711
|
+
},
|
|
712
|
+
{
|
|
713
|
+
id: "RTS-10(4)",
|
|
714
|
+
title: "Patch identification and deployment",
|
|
715
|
+
nist: ["SI-2", "SA-22"],
|
|
716
|
+
},
|
|
717
|
+
{
|
|
718
|
+
id: "RTS-11(2)(a)",
|
|
719
|
+
title: "Access restrictions by data classification",
|
|
720
|
+
nist: ["AC-3"],
|
|
721
|
+
},
|
|
722
|
+
{
|
|
723
|
+
id: "RTS-11(2)(b)",
|
|
724
|
+
title: "Secure configuration baselines minimising exposure",
|
|
725
|
+
nist: ["CM-2", "CM-6"],
|
|
726
|
+
},
|
|
727
|
+
{
|
|
728
|
+
id: "RTS-12(2)(a)",
|
|
729
|
+
title: "Log event scope and retention periods",
|
|
730
|
+
nist: ["AU-11"],
|
|
731
|
+
},
|
|
732
|
+
{
|
|
733
|
+
id: "RTS-12(2)(c)",
|
|
734
|
+
title: "Logging of access, ICT operations, and network traffic",
|
|
735
|
+
nist: ["AU-2", "AU-12"],
|
|
736
|
+
},
|
|
737
|
+
{
|
|
738
|
+
id: "RTS-13(a)",
|
|
739
|
+
title: "Network segregation and segmentation",
|
|
740
|
+
nist: ["AC-4", "SC-7"],
|
|
741
|
+
},
|
|
742
|
+
{
|
|
743
|
+
id: "RTS-13(d)",
|
|
744
|
+
title: "Network access controls on unauthorised connections",
|
|
745
|
+
nist: ["SC-7", "SC-7(5)"],
|
|
746
|
+
},
|
|
747
|
+
{
|
|
748
|
+
id: "RTS-13(e)",
|
|
749
|
+
title: "Encryption of network communications",
|
|
750
|
+
nist: ["SC-8", "SC-8(1)", "AC-17(2)"],
|
|
751
|
+
},
|
|
752
|
+
{
|
|
753
|
+
id: "RTS-13(g)",
|
|
754
|
+
title: "Securing traffic to internet and external connections",
|
|
755
|
+
nist: ["SC-7", "SC-7(3)"],
|
|
756
|
+
},
|
|
757
|
+
{
|
|
758
|
+
id: "RTS-13(h)",
|
|
759
|
+
title: "Firewall rule specification and review",
|
|
760
|
+
nist: ["SC-7(5)"],
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
id: "RTS-14(1)",
|
|
764
|
+
title: "Securing information in transit",
|
|
765
|
+
nist: ["SC-8", "SC-8(1)"],
|
|
766
|
+
},
|
|
767
|
+
{
|
|
768
|
+
id: "RTS-20(2)(a)",
|
|
769
|
+
title: "Unique identity and user account",
|
|
770
|
+
nist: ["IA-2"],
|
|
771
|
+
},
|
|
772
|
+
{
|
|
773
|
+
id: "RTS-21(a)",
|
|
774
|
+
title: "Least-privilege and need-to-know access rights",
|
|
775
|
+
nist: ["AC-6", "AC-6(1)"],
|
|
776
|
+
},
|
|
777
|
+
{
|
|
778
|
+
id: "RTS-21(d)",
|
|
779
|
+
title: "Access restriction controls on ICT assets",
|
|
780
|
+
nist: ["AC-3"],
|
|
781
|
+
},
|
|
782
|
+
{
|
|
783
|
+
id: "RTS-21(f)",
|
|
784
|
+
title: "Strong authentication for privileged and remote access",
|
|
785
|
+
nist: ["IA-2(1)", "IA-2(2)", "IA-5(1)"],
|
|
786
|
+
},
|
|
787
|
+
],
|
|
788
|
+
};
|
|
789
|
+
|
|
790
|
+
/**
|
|
791
|
+
* NCSC Cyber Assessment Framework v4.0 (B.2) — the UK layer that matters for
|
|
792
|
+
* the Cyber Security and Resilience Bill, NIS-regulated operators and the
|
|
793
|
+
* public-sector buyers who assess against GovAssure.
|
|
794
|
+
*
|
|
795
|
+
* ⚠️ READ THIS BEFORE EDITING. The CAF is **not** the framework the legacy
|
|
796
|
+
* `ncsc-caf` slug names — that slug belongs to the NCSC *Cloud Security
|
|
797
|
+
* Principles*, and for a while five product surfaces advertised "NCSC CAF"
|
|
798
|
+
* while mapping to the Principles. This layer is the real thing; its registry
|
|
799
|
+
* slug is `ncsc-caf-v4` precisely so the two can never merge.
|
|
800
|
+
*
|
|
801
|
+
* Authored against the published v4.0 PDF, not from recall — v4.0 restructured
|
|
802
|
+
* the contributing outcomes substantially (A2.b became "Understanding Threat",
|
|
803
|
+
* A4.b "Secure Software Development and Support" is new, C1 lost an outcome to
|
|
804
|
+
* consolidation, C2 collapsed to a single "Threat Hunting"), so a v3.2-shaped
|
|
805
|
+
* mapping would cite outcomes that no longer exist.
|
|
806
|
+
*
|
|
807
|
+
* HONESTY. The CAF is an **outcome-based** framework assessed on Indicators of
|
|
808
|
+
* Good Practice, most of which describe organisational behaviour — governance,
|
|
809
|
+
* risk process, supply chain, staff training, incident response. Of its 37
|
|
810
|
+
* contributing outcomes, the 13 below are the only ones an IaC scan can speak
|
|
811
|
+
* to at all, and even those it evidences *partially*: CAF asks whether a
|
|
812
|
+
* practice is working, and we can only show what the code declares. The Cloud
|
|
813
|
+
* pack carries all 37 rows so the published coverage % states that gap rather
|
|
814
|
+
* than hiding it. This is "evidence toward CAF outcomes", never "CAF achieved"
|
|
815
|
+
* — the CAF's own achievement levels (Not / Partially / Achieved) are an
|
|
816
|
+
* assessor's judgement and nothing here may present as one.
|
|
817
|
+
*/
|
|
818
|
+
const NCSC_CAF_LAYER: HubLayer = {
|
|
819
|
+
framework: NCSC_CAF_NAME,
|
|
820
|
+
requirements: [
|
|
821
|
+
{ id: "A3.a", title: "Asset Management", nist: ["CM-8", "CM-12"] },
|
|
822
|
+
{
|
|
823
|
+
id: "B2.a",
|
|
824
|
+
title: "Identity Verification, Authentication and Authorisation",
|
|
825
|
+
nist: ["IA-2", "IA-2(1)", "IA-2(2)", "IA-5(1)"],
|
|
826
|
+
},
|
|
827
|
+
{
|
|
828
|
+
id: "B2.c",
|
|
829
|
+
title: "Privileged User Management",
|
|
830
|
+
nist: ["AC-6", "AC-6(1)", "AC-6(10)"],
|
|
831
|
+
},
|
|
832
|
+
{
|
|
833
|
+
id: "B2.d",
|
|
834
|
+
title: "Identity and Access Management (IdAM)",
|
|
835
|
+
nist: ["AC-3", "IA-5", "IA-5(7)"],
|
|
836
|
+
},
|
|
837
|
+
{
|
|
838
|
+
id: "B3.b",
|
|
839
|
+
title: "Data in Transit",
|
|
840
|
+
nist: ["SC-8", "SC-8(1)", "AC-17(2)"],
|
|
841
|
+
},
|
|
842
|
+
{
|
|
843
|
+
id: "B3.c",
|
|
844
|
+
title: "Stored Data",
|
|
845
|
+
nist: ["SC-28", "SC-28(1)", "SC-12", "SC-13"],
|
|
846
|
+
},
|
|
847
|
+
// CM-7 (least functionality) is deliberately omitted, exactly as CSF
|
|
848
|
+
// PR.PS-01 omits it: it would make every public-exposure finding claim
|
|
849
|
+
// "Secure Configuration", a join the evidence does not support.
|
|
850
|
+
{ id: "B4.b", title: "Secure Configuration", nist: ["CM-2", "CM-6"] },
|
|
851
|
+
{ id: "B4.c", title: "Secure Management", nist: ["CM-3", "CM-4", "CM-5"] },
|
|
852
|
+
{ id: "B4.d", title: "Vulnerability Management", nist: ["SI-2", "SA-22"] },
|
|
853
|
+
{ id: "B5.a", title: "Resilience Preparation", nist: ["CP-9", "CP-10"] },
|
|
854
|
+
{ id: "B5.b", title: "Design for Resilience", nist: ["CP-6", "AC-4"] },
|
|
855
|
+
{
|
|
856
|
+
id: "C1.a",
|
|
857
|
+
title: "Sources and Tools for Logging and Monitoring",
|
|
858
|
+
nist: ["AU-2", "AU-12", "SI-4"],
|
|
859
|
+
},
|
|
860
|
+
// Retention only (AU-11). The access half of C1.b would need AC-3, which
|
|
861
|
+
// would drag every least-privilege finding into a logging claim.
|
|
862
|
+
{ id: "C1.b", title: "Securing Logs", nist: ["AU-11"] },
|
|
863
|
+
],
|
|
864
|
+
};
|
|
865
|
+
|
|
866
|
+
/**
|
|
867
|
+
* Every hub-anchored layer, in citation order. Adding a framework wave is one
|
|
868
|
+
* more entry here plus the matching Cloud pack rows — no engine logic changes.
|
|
869
|
+
*/
|
|
870
|
+
const HUB_LAYERS: HubLayer[] = [CSF_2_0_LAYER, DORA_RTS_LAYER, NCSC_CAF_LAYER];
|
|
871
|
+
|
|
872
|
+
/**
|
|
873
|
+
* The hub-derived control refs for a set of themes: the 800-53 spine controls
|
|
874
|
+
* (sorted) plus every hub-layer requirement whose anchors intersect those spine
|
|
875
|
+
* ids. Deterministic + pure. Conservative fan-out is by design — an exposure
|
|
876
|
+
* finding lights all boundary controls rather than risk a false pass on a
|
|
877
|
+
* related one.
|
|
878
|
+
*/
|
|
879
|
+
export function hubControlsForThemes(themes: string[]): ControlRef[] {
|
|
880
|
+
const nistIds = new Set<string>();
|
|
881
|
+
for (const theme of themes) {
|
|
882
|
+
for (const id of THEME_TO_NIST[theme] ?? []) nistIds.add(id);
|
|
883
|
+
}
|
|
884
|
+
const refs: ControlRef[] = [];
|
|
885
|
+
for (const id of [...nistIds].sort()) {
|
|
886
|
+
refs.push({
|
|
887
|
+
framework: NIST_800_53_NAME,
|
|
888
|
+
control: id,
|
|
889
|
+
title: NIST_800_53_TITLES[id] ?? id,
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
for (const layer of HUB_LAYERS) {
|
|
893
|
+
for (const req of layer.requirements) {
|
|
894
|
+
if (!req.nist.some((id) => nistIds.has(id))) continue;
|
|
895
|
+
refs.push({
|
|
896
|
+
framework: layer.framework,
|
|
897
|
+
control: req.id,
|
|
898
|
+
title: req.title,
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
return refs;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/**
|
|
906
|
+
* Map a single concern to the indicative control references it touches. Matches
|
|
907
|
+
* the concern's `rule_id` + `evidence` (and an optional `category`) against the
|
|
908
|
+
* crosswalk themes; unions the controls of every theme that fires. Pure.
|
|
909
|
+
* Returns an empty array when nothing matches (honest — better than a forced
|
|
910
|
+
* mapping). De-duplicates identical control refs.
|
|
911
|
+
*/
|
|
912
|
+
export function mapConcernToControls(concern: {
|
|
913
|
+
rule_id: string;
|
|
914
|
+
evidence: string;
|
|
915
|
+
category?: string;
|
|
916
|
+
}): { themes: string[]; controls: ControlRef[] } {
|
|
917
|
+
assertCrosswalkIntegrity();
|
|
918
|
+
const haystack = `${concern.rule_id} ${concern.evidence}`.toLowerCase();
|
|
919
|
+
const themes: string[] = [];
|
|
920
|
+
const controls: ControlRef[] = [];
|
|
921
|
+
const seen = new Set<string>();
|
|
922
|
+
for (const rule of CROSSWALK) {
|
|
923
|
+
if (!rule.signals.some((s) => haystack.includes(s))) continue;
|
|
924
|
+
themes.push(rule.theme);
|
|
925
|
+
for (const c of rule.controls) {
|
|
926
|
+
const key = `${c.framework}|${c.control}`;
|
|
927
|
+
if (seen.has(key)) continue;
|
|
928
|
+
seen.add(key);
|
|
929
|
+
controls.push(c);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
// The §5.14 hub layers ride behind the theme layer: 800-53 spine + CSF pivot.
|
|
933
|
+
for (const c of hubControlsForThemes(themes)) {
|
|
934
|
+
const key = `${c.framework}|${c.control}`;
|
|
935
|
+
if (seen.has(key)) continue;
|
|
936
|
+
seen.add(key);
|
|
937
|
+
controls.push(c);
|
|
938
|
+
}
|
|
939
|
+
return { themes, controls };
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
/**
|
|
943
|
+
* Authored mapping from a defect THEME → the maintained Cloud crosswalk PACK
|
|
944
|
+
* control ids it evidences (infraweaver-ui `src/features/crosswalk/pack.ts`). This
|
|
945
|
+
* is the engine⇄Cloud JOIN KEY: a reported finding carries these ids in its
|
|
946
|
+
* `compliance[]`, so the Cloud `/compliance` verdicts and the required-control
|
|
947
|
+
* violation detection bind to REAL findings (without it they keyed on engine
|
|
948
|
+
* control names and never joined the pack's ids — the C1 divergence).
|
|
949
|
+
*
|
|
950
|
+
* HAND-SYNCED with pack.ts, exactly like the report wire schema — every id here
|
|
951
|
+
* must exist there. The engine themes are coarser than the pack's controls, so a
|
|
952
|
+
* theme fans out to every control it plausibly evidences (conservative: an
|
|
953
|
+
* exposure finding lights all boundary/exposure controls rather than risk a false
|
|
954
|
+
* pass on a related one). A theme with no honest pack control maps to `[]` — we
|
|
955
|
+
* emit NOTHING rather than mis-attribute (vuln-management, key-rotation and
|
|
956
|
+
* malware controls have no code-verifiable theme and stay unmapped).
|
|
957
|
+
*/
|
|
958
|
+
const THEME_TO_PACK_CONTROLS: Record<string, string[]> = {
|
|
959
|
+
// encryption at rest → CE A2.1, ISO A.8.24, NCSC P2.
|
|
960
|
+
"encryption-at-rest": ["A2.1", "A.8.24", "P2"],
|
|
961
|
+
// in-transit has no CE/ISO-pinned control here → NCSC P1 only.
|
|
962
|
+
"encryption-in-transit": ["P1"],
|
|
963
|
+
// boundary + public storage exposure across all three frameworks.
|
|
964
|
+
"public-exposure": ["A1.1", "A1.2", "A2.3", "A.8.20", "A.5.23", "P5"],
|
|
965
|
+
"least-privilege": ["A4.1", "A.5.15", "P9"],
|
|
966
|
+
// secure configuration & logging (CE A2.2 explicitly covers logging).
|
|
967
|
+
"logging-audit": ["A2.2", "A.8.16", "P13"],
|
|
968
|
+
// resilience maps onto NCSC P2 (asset protection & resilience).
|
|
969
|
+
"backup-resilience": ["P2"],
|
|
970
|
+
// hardcoded secrets are a secure-configuration failure (CE A2.2).
|
|
971
|
+
"secrets-management": ["A2.2"],
|
|
972
|
+
// internal segmentation lights the boundary-firewall + network controls.
|
|
973
|
+
"network-segmentation": ["A1.1", "A1.2", "P5"],
|
|
974
|
+
// MFA / strong auth maps onto user-access control + identity.
|
|
975
|
+
"mfa-strong-auth": ["A4.1", "P9"],
|
|
976
|
+
// privileged/over-broad container config is a secure-configuration failure.
|
|
977
|
+
"container-hardening": ["A2.2"],
|
|
978
|
+
// patch-currency + governance/tagging have no honest UK-pack control → no UK
|
|
979
|
+
// ids here. Since the §5.14 hub they DO emit their 800-53/CSF pack ids (SI-2,
|
|
980
|
+
// SA-22, CM-8, … via `packControlsForThemes`) — real homes, not mis-attribution.
|
|
981
|
+
"patch-currency": [],
|
|
982
|
+
"resource-governance": [],
|
|
983
|
+
// change-control is a governance band no UK starter-pack control speaks to
|
|
984
|
+
// honestly (CE and the NCSC principles are technical-configuration frameworks).
|
|
985
|
+
// Its 800-53/CSF/DORA ids still flow through `packControlsForThemes` via the
|
|
986
|
+
// hub, which is where a change-control claim actually belongs.
|
|
987
|
+
"change-control": [],
|
|
988
|
+
};
|
|
989
|
+
|
|
990
|
+
// ── Integrity gate (LLM04) ──────────────────────────────────────────────────────
|
|
991
|
+
// The crosswalk drives compliance verdicts, so a poisoned control mapping would
|
|
992
|
+
// yield a false "compliant" — the worst failure for an attestation product. We pin a
|
|
993
|
+
// sha256 of the reviewed tables and verify it before any verdict is produced; a
|
|
994
|
+
// mismatch fail-closes. Regenerate the pin with `pnpm run gen:crosswalk-digest` after
|
|
995
|
+
// an intended crosswalk edit. The digest also rides in the (Ed25519-signed) evidence
|
|
996
|
+
// bundle, so the exact table that produced each attestation is cryptographically bound.
|
|
997
|
+
|
|
998
|
+
/** Deterministic, key-sorted serialization — the exact bytes the digest covers. */
|
|
999
|
+
function stableStringify(value: unknown): string {
|
|
1000
|
+
if (value === null || typeof value !== "object")
|
|
1001
|
+
return JSON.stringify(value) ?? "null";
|
|
1002
|
+
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
1003
|
+
const obj = value as Record<string, unknown>;
|
|
1004
|
+
return `{${Object.keys(obj)
|
|
1005
|
+
.sort()
|
|
1006
|
+
.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`)
|
|
1007
|
+
.join(",")}}`;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
/** The canonical payload of the curated crosswalk tables + version stamps. Pure. */
|
|
1011
|
+
export function canonicalCrosswalkPayload(): string {
|
|
1012
|
+
return stableStringify({
|
|
1013
|
+
version: CROSSWALK_VERSION,
|
|
1014
|
+
reviewed: CROSSWALK_REVIEWED,
|
|
1015
|
+
crosswalk: CROSSWALK,
|
|
1016
|
+
themeToPackControls: THEME_TO_PACK_CONTROLS,
|
|
1017
|
+
// §5.14 hub layers — a poisoned spine or layer table would mis-verdict every
|
|
1018
|
+
// downstream framework, so the digest covers them (and the registry) too.
|
|
1019
|
+
frameworks: FRAMEWORKS,
|
|
1020
|
+
themeToNist: THEME_TO_NIST,
|
|
1021
|
+
nistTitles: NIST_800_53_TITLES,
|
|
1022
|
+
hubLayers: HUB_LAYERS,
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
/** sha256 (hex) of the canonical crosswalk payload. Pure. */
|
|
1027
|
+
export function crosswalkDigest(): string {
|
|
1028
|
+
return createHash("sha256").update(canonicalCrosswalkPayload()).digest("hex");
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
/** The digest of the crosswalk actually loaded in this build (computed once). */
|
|
1032
|
+
export const CROSSWALK_DIGEST = crosswalkDigest();
|
|
1033
|
+
|
|
1034
|
+
/**
|
|
1035
|
+
* Fail-closed integrity gate. Throws when the loaded crosswalk doesn't match the
|
|
1036
|
+
* pinned, reviewed digest — so no compliance verdict can be produced from a tampered
|
|
1037
|
+
* or poisoned table. Every verdict-producing entry calls this. The args are injectable
|
|
1038
|
+
* so a test can exercise the mismatch path without corrupting the real module.
|
|
1039
|
+
*/
|
|
1040
|
+
export function assertCrosswalkIntegrity(
|
|
1041
|
+
actual: string = CROSSWALK_DIGEST,
|
|
1042
|
+
expected: string = EXPECTED_CROSSWALK_DIGEST,
|
|
1043
|
+
): void {
|
|
1044
|
+
if (actual !== expected) {
|
|
1045
|
+
throw new Error(
|
|
1046
|
+
`crosswalk integrity check failed: loaded digest ${actual} does not match the pinned ${expected}. ` +
|
|
1047
|
+
"The compliance crosswalk was modified without re-pinning — run `pnpm run gen:crosswalk-digest` if the " +
|
|
1048
|
+
"change is intended, otherwise treat this as tampering (LLM04).",
|
|
1049
|
+
);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
/** The maintained-pack control ids a concern's themes evidence (deduped, sorted).
|
|
1054
|
+
* Empty when nothing maps. Pure. See {@link THEME_TO_PACK_CONTROLS}. */
|
|
1055
|
+
export function packControlsForThemes(themes: string[]): string[] {
|
|
1056
|
+
const ids = new Set<string>();
|
|
1057
|
+
for (const theme of themes) {
|
|
1058
|
+
for (const id of THEME_TO_PACK_CONTROLS[theme] ?? []) ids.add(id);
|
|
1059
|
+
}
|
|
1060
|
+
// The hub layers (800-53 + CSF 2.0) exist in the Cloud pack under the SAME
|
|
1061
|
+
// control ids the hub tables carry, so the join needs no second hand-synced
|
|
1062
|
+
// table — one source (THEME_TO_NIST / HUB_LAYERS) feeds both the narrated
|
|
1063
|
+
// crosswalk and the pack join key.
|
|
1064
|
+
for (const ref of hubControlsForThemes(themes)) ids.add(ref.control);
|
|
1065
|
+
return [...ids].sort();
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
/**
|
|
1069
|
+
* The maintained Cloud-pack control ids a single concern maps to — the values
|
|
1070
|
+
* the cloud report puts in each finding's `compliance[]` so the dashboard's
|
|
1071
|
+
* control verdicts and required-control gate join on real findings. Pure.
|
|
1072
|
+
*/
|
|
1073
|
+
export function packControlsForConcern(concern: {
|
|
1074
|
+
rule_id: string;
|
|
1075
|
+
evidence: string;
|
|
1076
|
+
category?: string;
|
|
1077
|
+
}): string[] {
|
|
1078
|
+
return packControlsForThemes(mapConcernToControls(concern).themes);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
export interface ConcernForCrosswalk {
|
|
1082
|
+
id: string;
|
|
1083
|
+
rule_id: string;
|
|
1084
|
+
evidence: string;
|
|
1085
|
+
category?: string;
|
|
1086
|
+
severity?: string;
|
|
1087
|
+
location?: { file: string; line: number | null };
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
export interface CrosswalkEntry {
|
|
1091
|
+
concern_id: string;
|
|
1092
|
+
rule_id: string;
|
|
1093
|
+
themes: string[];
|
|
1094
|
+
controls: ControlRef[];
|
|
1095
|
+
/** the five-status verdict for this control statement: `fail` (code-verified
|
|
1096
|
+
* violation) or `not-code-verifiable` (a human-decision control the engine can
|
|
1097
|
+
* flag but not prove). Lets an assessor read the crosswalk honestly. */
|
|
1098
|
+
status: ConcernVerificationStatus;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
export interface CrosswalkReport {
|
|
1102
|
+
version: string;
|
|
1103
|
+
reviewed: string;
|
|
1104
|
+
/** per-concern control mappings (only concerns that mapped to ≥1 control). */
|
|
1105
|
+
entries: CrosswalkEntry[];
|
|
1106
|
+
/** framework → the distinct controls this scan touched, for an auditor index. */
|
|
1107
|
+
by_framework: Record<string, { control: string; title: string }[]>;
|
|
1108
|
+
/** concerns that did not map to any control (honest coverage signal). */
|
|
1109
|
+
unmapped_concern_ids: string[];
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
/**
|
|
1113
|
+
* Build the auditor crosswalk for a set of concerns: per-concern control refs
|
|
1114
|
+
* plus a `by_framework` index (which controls this scan touched, deduped) and an
|
|
1115
|
+
* honest `unmapped` list. Pure + deterministic. Carries the pack version + date
|
|
1116
|
+
* so the report is reproducible and clearly indicative.
|
|
1117
|
+
*/
|
|
1118
|
+
export function buildCrosswalkReport(
|
|
1119
|
+
concerns: ConcernForCrosswalk[],
|
|
1120
|
+
): CrosswalkReport {
|
|
1121
|
+
assertCrosswalkIntegrity();
|
|
1122
|
+
const entries: CrosswalkEntry[] = [];
|
|
1123
|
+
const unmapped: string[] = [];
|
|
1124
|
+
const byFramework = new Map<string, Map<string, string>>();
|
|
1125
|
+
for (const c of concerns) {
|
|
1126
|
+
const { themes, controls } = mapConcernToControls(c);
|
|
1127
|
+
if (controls.length === 0) {
|
|
1128
|
+
unmapped.push(c.id);
|
|
1129
|
+
continue;
|
|
1130
|
+
}
|
|
1131
|
+
entries.push({
|
|
1132
|
+
concern_id: c.id,
|
|
1133
|
+
rule_id: c.rule_id,
|
|
1134
|
+
themes,
|
|
1135
|
+
controls,
|
|
1136
|
+
status: concernVerificationStatus(c).status,
|
|
1137
|
+
});
|
|
1138
|
+
for (const ctl of controls) {
|
|
1139
|
+
const map = byFramework.get(ctl.framework) ?? new Map<string, string>();
|
|
1140
|
+
if (!map.has(ctl.control)) map.set(ctl.control, ctl.title);
|
|
1141
|
+
byFramework.set(ctl.framework, map);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
const by_framework: Record<string, { control: string; title: string }[]> = {};
|
|
1145
|
+
for (const [framework, controls] of [...byFramework.entries()].sort((a, b) =>
|
|
1146
|
+
a[0].localeCompare(b[0]),
|
|
1147
|
+
)) {
|
|
1148
|
+
by_framework[framework] = [...controls.entries()]
|
|
1149
|
+
.map(([control, title]) => ({ control, title }))
|
|
1150
|
+
.sort((a, b) => a.control.localeCompare(b.control));
|
|
1151
|
+
}
|
|
1152
|
+
return {
|
|
1153
|
+
version: CROSSWALK_VERSION,
|
|
1154
|
+
reviewed: CROSSWALK_REVIEWED,
|
|
1155
|
+
entries,
|
|
1156
|
+
by_framework,
|
|
1157
|
+
unmapped_concern_ids: unmapped,
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
/**
|
|
1162
|
+
* The tokens a `required_controls` policy can match a concern on (lower-cased):
|
|
1163
|
+
* each mapped control's framework, control id, `framework|control` key and title,
|
|
1164
|
+
* the defect themes, AND the maintained-pack control ids the concern evidences.
|
|
1165
|
+
* So a policy entry can require a whole framework ("Cyber Essentials"), a single
|
|
1166
|
+
* control ("Secure Configuration" or "Cyber Essentials|Secure Configuration"), a
|
|
1167
|
+
* theme ("encryption-at-rest"), or a Cloud-pack control id ("A2.1") — the last is
|
|
1168
|
+
* what the Cloud "required controls" policy sends down via run-context. Pure.
|
|
1169
|
+
*/
|
|
1170
|
+
export function controlMatchTokens(concern: {
|
|
1171
|
+
rule_id: string;
|
|
1172
|
+
evidence: string;
|
|
1173
|
+
category?: string;
|
|
1174
|
+
}): string[] {
|
|
1175
|
+
const { themes, controls } = mapConcernToControls(concern);
|
|
1176
|
+
const tokens = new Set<string>();
|
|
1177
|
+
for (const t of themes) tokens.add(t.toLowerCase());
|
|
1178
|
+
for (const c of controls) {
|
|
1179
|
+
tokens.add(c.framework.toLowerCase());
|
|
1180
|
+
tokens.add(c.control.toLowerCase());
|
|
1181
|
+
tokens.add(`${c.framework}|${c.control}`.toLowerCase());
|
|
1182
|
+
tokens.add(c.title.toLowerCase());
|
|
1183
|
+
}
|
|
1184
|
+
// The Cloud pack control ids (e.g. "A2.1") so an org's dashboard required-control
|
|
1185
|
+
// policy, delivered as pack ids over run-context, enforces in the CI gate.
|
|
1186
|
+
for (const id of packControlsForThemes(themes)) tokens.add(id.toLowerCase());
|
|
1187
|
+
return [...tokens];
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
/**
|
|
1191
|
+
* The OPEN concerns that map to at least one REQUIRED compliance control — these
|
|
1192
|
+
* fail the CI gate regardless of severity (the 2g-vi "required control" policy:
|
|
1193
|
+
* a CISO marks the controls that MUST stay clean, e.g. encryption-at-rest for
|
|
1194
|
+
* SOC 2). `required` is matched case-insensitively against each concern's
|
|
1195
|
+
* framework / control / `framework|control` / title / theme (see
|
|
1196
|
+
* `controlMatchTokens`). Suppressed (accepted) concerns never count. Pure.
|
|
1197
|
+
*/
|
|
1198
|
+
export function requiredControlViolations(
|
|
1199
|
+
concerns: Concern[],
|
|
1200
|
+
required: string[],
|
|
1201
|
+
): Concern[] {
|
|
1202
|
+
assertCrosswalkIntegrity();
|
|
1203
|
+
const wanted = new Set(
|
|
1204
|
+
required.map((r) => r.trim().toLowerCase()).filter(Boolean),
|
|
1205
|
+
);
|
|
1206
|
+
if (wanted.size === 0) return [];
|
|
1207
|
+
return concerns.filter(
|
|
1208
|
+
(c) =>
|
|
1209
|
+
!c.suppression &&
|
|
1210
|
+
controlMatchTokens(c).some((token) => wanted.has(token)),
|
|
1211
|
+
);
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
export const ComplianceCrosswalkParams = type({
|
|
1215
|
+
concerns: type({
|
|
1216
|
+
id: type.string,
|
|
1217
|
+
rule_id: type.string,
|
|
1218
|
+
evidence: type.string,
|
|
1219
|
+
"category?": type.string,
|
|
1220
|
+
"severity?": type.string,
|
|
1221
|
+
})
|
|
1222
|
+
.array()
|
|
1223
|
+
.describe(
|
|
1224
|
+
"the concerns to map (pass the `concerns` array from terraform_scan/read_findings).",
|
|
1225
|
+
),
|
|
1226
|
+
});
|
|
1227
|
+
|
|
1228
|
+
export function ComplianceCrosswalkTool(ctx: LocalToolContext) {
|
|
1229
|
+
void ctx;
|
|
1230
|
+
return tool({
|
|
1231
|
+
name: "terraform_compliance_crosswalk",
|
|
1232
|
+
description:
|
|
1233
|
+
"Map a scan's concerns to the UK public-sector + general compliance controls they touch — NCSC " +
|
|
1234
|
+
"Cloud Security Principles, Cyber Essentials, NHS DSPT, Secure by Design, CIS Controls, SOC 2, plus the " +
|
|
1235
|
+
"NIST SP 800-53 rev 5 spine, NIST CSF 2.0 pivot, DORA RTS (EU) 2024/1774 and the NCSC Cyber " +
|
|
1236
|
+
"Assessment Framework v4.0 (§5.14 crosswalk hub) — so a " +
|
|
1237
|
+
"remediation PR can be narrated to an ASSESSOR in their own framework. Pass the `concerns` from " +
|
|
1238
|
+
"terraform_scan/read_findings; returns a per-concern control mapping plus a `by_framework` index and an " +
|
|
1239
|
+
"honest `unmapped_concern_ids` list. The mapping is an INDICATIVE starter rule-pack (version + review " +
|
|
1240
|
+
"date included) keyed on the defect theme — cite it as 'indicative alignment', never an audit verdict.",
|
|
1241
|
+
parameters: ComplianceCrosswalkParams,
|
|
1242
|
+
execute: execute(async ({ concerns }) => {
|
|
1243
|
+
const report = buildCrosswalkReport(concerns as ConcernForCrosswalk[]);
|
|
1244
|
+
log.info(
|
|
1245
|
+
`» terraform_compliance_crosswalk: ${report.entries.length} mapped / ${report.unmapped_concern_ids.length} unmapped across ${Object.keys(report.by_framework).length} framework(s)`,
|
|
1246
|
+
);
|
|
1247
|
+
return toolOk({
|
|
1248
|
+
...report,
|
|
1249
|
+
note: `Indicative crosswalk v${report.version} (reviewed ${report.reviewed}) — alignment guidance, not an audit verdict.`,
|
|
1250
|
+
});
|
|
1251
|
+
}),
|
|
1252
|
+
});
|
|
1253
|
+
}
|